From 86126dbc3837734c87df0a0579fba0f6b92d1685 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:13:14 -0500 Subject: [PATCH 01/10] Use module aliases --- lib/eqrcode.ex | 62 ++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/eqrcode.ex b/lib/eqrcode.ex index 1d6c755..cd8e935 100644 --- a/lib/eqrcode.ex +++ b/lib/eqrcode.ex @@ -13,28 +13,30 @@ defmodule EQRCode do ``` """ + alias EQRCode.{Encode, ReedSolomon, Matrix} + @doc """ Encode the binary. """ - @spec encode(binary) :: EQRCode.Matrix.t() + @spec encode(binary) :: Matrix.t() def encode(bin) when byte_size(bin) <= 154 do data = - EQRCode.Encode.encode(bin) - |> EQRCode.ReedSolomon.encode() + Encode.encode(bin) + |> ReedSolomon.encode() - EQRCode.Encode.version(bin) - |> EQRCode.Matrix.new() - |> EQRCode.Matrix.draw_finder_patterns() - |> EQRCode.Matrix.draw_seperators() - |> EQRCode.Matrix.draw_alignment_patterns() - |> EQRCode.Matrix.draw_timing_patterns() - |> EQRCode.Matrix.draw_dark_module() - |> EQRCode.Matrix.draw_reserved_format_areas() - |> EQRCode.Matrix.draw_reserved_version_areas() - |> EQRCode.Matrix.draw_data_with_mask(data) - |> EQRCode.Matrix.draw_format_areas() - |> EQRCode.Matrix.draw_version_areas() - |> EQRCode.Matrix.draw_quite_zone() + Encode.version(bin) + |> Matrix.new() + |> Matrix.draw_finder_patterns() + |> Matrix.draw_seperators() + |> Matrix.draw_alignment_patterns() + |> Matrix.draw_timing_patterns() + |> Matrix.draw_dark_module() + |> Matrix.draw_reserved_format_areas() + |> Matrix.draw_reserved_version_areas() + |> Matrix.draw_data_with_mask(data) + |> Matrix.draw_format_areas() + |> Matrix.draw_version_areas() + |> Matrix.draw_quite_zone() end def encode(bin) when is_nil(bin) do @@ -47,22 +49,22 @@ defmodule EQRCode do @doc """ Encode the binary with custom pattern bits. Only supports version 5. """ - @spec encode(binary, bitstring) :: EQRCode.Matrix.t() + @spec encode(binary, bitstring) :: Matrix.t() def encode(bin, bits) when byte_size(bin) <= 106 do data = - EQRCode.Encode.encode(bin, bits) - |> EQRCode.ReedSolomon.encode() + Encode.encode(bin, bits) + |> ReedSolomon.encode() - EQRCode.Matrix.new(5) - |> EQRCode.Matrix.draw_finder_patterns() - |> EQRCode.Matrix.draw_seperators() - |> EQRCode.Matrix.draw_alignment_patterns() - |> EQRCode.Matrix.draw_timing_patterns() - |> EQRCode.Matrix.draw_dark_module() - |> EQRCode.Matrix.draw_reserved_format_areas() - |> EQRCode.Matrix.draw_data_with_mask0(data) - |> EQRCode.Matrix.draw_format_areas() - |> EQRCode.Matrix.draw_quite_zone() + Matrix.new(5) + |> Matrix.draw_finder_patterns() + |> Matrix.draw_seperators() + |> Matrix.draw_alignment_patterns() + |> Matrix.draw_timing_patterns() + |> Matrix.draw_dark_module() + |> Matrix.draw_reserved_format_areas() + |> Matrix.draw_data_with_mask0(data) + |> Matrix.draw_format_areas() + |> Matrix.draw_quite_zone() end def encode(_, _), do: IO.puts("Binary too long.") @@ -82,5 +84,5 @@ defmodule EQRCode do Default options are `%{color: "#000", shape: "square"}`. """ - defdelegate svg(matrix, options \\ %{}), to: EQRCode.Svg + defdelegate svg(matrix, options \\ %{}), to: EQRCode.SVG end From fd8f2129c2373f2b0ccf35e51a27893966c3a023 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:13:24 -0500 Subject: [PATCH 02/10] Svg -> SVG --- lib/eqrcode/svg.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eqrcode/svg.ex b/lib/eqrcode/svg.ex index 7a4ffd2..3c69611 100644 --- a/lib/eqrcode/svg.ex +++ b/lib/eqrcode/svg.ex @@ -1,4 +1,4 @@ -defmodule EQRCode.Svg do +defmodule EQRCode.SVG do @moduledoc """ Render the QR Code matrix in SVG format From 3fda296a17c56516bc605fbd66c8e3af04169dd6 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:15:51 -0500 Subject: [PATCH 03/10] Fixed redefinition warning --- lib/eqrcode/galois_field.ex | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/eqrcode/galois_field.ex b/lib/eqrcode/galois_field.ex index 1089035..75271b4 100644 --- a/lib/eqrcode/galois_field.ex +++ b/lib/eqrcode/galois_field.ex @@ -3,6 +3,20 @@ defmodule EQRCode.GaloisField do import Bitwise + @integers %{} + @alphas %{} + + Stream.iterate(1, fn e -> + n = e <<< 1 + if n >= 256, do: n ^^^ 0b100011101, else: n + end) + |> Stream.take(256) + |> Stream.with_index() + |> Enum.each(fn {e, i} -> + Module.put_attribute(__MODULE__, :alphas, Map.put(@alphas, e, i)) + Module.put_attribute(__MODULE__, :integers, Map.put(@integers, i, e)) + end) + @doc """ Given alpha exponent returns integer. @@ -11,7 +25,9 @@ defmodule EQRCode.GaloisField do 2 """ @spec to_i(integer) :: integer - def to_i(alpha) + def to_i(alpha) do + @integers[alpha] + end @doc """ Given integer returns alpha exponent. @@ -21,16 +37,7 @@ defmodule EQRCode.GaloisField do 1 """ @spec to_a(integer) :: integer - def to_a(integer) - - Stream.iterate(1, fn e -> - n = e <<< 1 - if n >= 256, do: n ^^^ 0b100011101, else: n - end) - |> Stream.take(256) - |> Stream.with_index() - |> Enum.each(fn {e, i} -> - def to_i(unquote(i)), do: unquote(e) - def to_a(unquote(e)), do: unquote(i) - end) + def to_a(integer) do + @alphas[integer] + end end From 450dfc74d142aaefb6f4d11f2d2de7e63f3a80a8 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:28:11 -0500 Subject: [PATCH 04/10] Updated tests --- test/eqrcode_test.exs | 1 - test/galois_field_test.exs | 4 ++++ test/matrix_test.exs | 4 ++++ test/reed_solomon_test.exs | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/galois_field_test.exs create mode 100644 test/matrix_test.exs create mode 100644 test/reed_solomon_test.exs diff --git a/test/eqrcode_test.exs b/test/eqrcode_test.exs index 2116630..9433251 100644 --- a/test/eqrcode_test.exs +++ b/test/eqrcode_test.exs @@ -1,6 +1,5 @@ defmodule EQRCodeTest do use ExUnit.Case - doctest EQRCode describe "encoder" do @sample_matrix {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, diff --git a/test/galois_field_test.exs b/test/galois_field_test.exs new file mode 100644 index 0000000..4138320 --- /dev/null +++ b/test/galois_field_test.exs @@ -0,0 +1,4 @@ +defmodule EQRCode.GaloisFieldTest do + use ExUnit.Case + doctest EQRCode.GaloisField +end diff --git a/test/matrix_test.exs b/test/matrix_test.exs new file mode 100644 index 0000000..437e1a4 --- /dev/null +++ b/test/matrix_test.exs @@ -0,0 +1,4 @@ +defmodule EQRCode.MatrixTest do + use ExUnit.Case + doctest EQRCode.Matrix +end diff --git a/test/reed_solomon_test.exs b/test/reed_solomon_test.exs new file mode 100644 index 0000000..0d6e230 --- /dev/null +++ b/test/reed_solomon_test.exs @@ -0,0 +1,4 @@ +defmodule EQRCode.ReedSolomonTest do + use ExUnit.Case + doctest EQRCode.ReedSolomon +end From 6012ec3bf30bc350d3a78f61689f8755ba7c7d54 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:28:28 -0500 Subject: [PATCH 05/10] Fix documentation --- lib/eqrcode/galois_field.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eqrcode/galois_field.ex b/lib/eqrcode/galois_field.ex index 75271b4..211da2a 100644 --- a/lib/eqrcode/galois_field.ex +++ b/lib/eqrcode/galois_field.ex @@ -21,7 +21,7 @@ defmodule EQRCode.GaloisField do Given alpha exponent returns integer. Example: - iex> QRCode.GaloisField.to_i(1) + iex> EQRCode.GaloisField.to_i(1) 2 """ @spec to_i(integer) :: integer @@ -33,7 +33,7 @@ defmodule EQRCode.GaloisField do Given integer returns alpha exponent. Example: - iex> QRCode.GaloisField.to_a(2) + iex> EQRCode.GaloisField.to_a(2) 1 """ @spec to_a(integer) :: integer From 67ed06b00ac455c4ad5769b072ac1fd699422b3d Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:28:35 -0500 Subject: [PATCH 06/10] Added viewbox option --- lib/eqrcode.ex | 1 + lib/eqrcode/svg.ex | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/eqrcode.ex b/lib/eqrcode.ex index cd8e935..fec1264 100644 --- a/lib/eqrcode.ex +++ b/lib/eqrcode.ex @@ -81,6 +81,7 @@ defmodule EQRCode do * `color`: In hexadecimal format. The default is `#000` * `shape`: Only `square` or `circle`. The default is `square` * `width`: The width of the QR code in pixel. Without the width attribute, the QR code size will be dynamically generated based on the input string. + * `viewbox`: When set to `true`, the SVG element will specify its height and width using `viewBox`, instead of explicit `height` and `width` tags. Default options are `%{color: "#000", shape: "square"}`. """ diff --git a/lib/eqrcode/svg.ex b/lib/eqrcode/svg.ex index 3c69611..37ace87 100644 --- a/lib/eqrcode/svg.ex +++ b/lib/eqrcode/svg.ex @@ -18,20 +18,30 @@ defmodule EQRCode.SVG do """ + alias EQRCode.Matrix + @doc """ Return the SVG format of the QR Code """ - def svg(%EQRCode.Matrix{matrix: matrix}, options) do + def svg(%Matrix{matrix: matrix}, options) do matrix_size = matrix |> Tuple.to_list() |> Enum.count() svg_options = options |> set_svg_options(matrix_size) dimension = matrix_size * svg_options[:module_size] xml_tag = ~s() + dimension_attrs = + if Keyword.get(options, :viewbox, false) do + ~s(width="#{dimension}" height="#{dimension}") + else + ~s(viewBox="0 0 #{dimension} #{dimension}") + end + open_tag = - ~s() + ~s() close_tag = ~s() From f9f5f65aa1b023e95d7fe5d8e3cf45fab747e509 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:32:14 -0500 Subject: [PATCH 07/10] Added default options to SVG module --- lib/eqrcode/svg.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/eqrcode/svg.ex b/lib/eqrcode/svg.ex index 37ace87..e2a14c2 100644 --- a/lib/eqrcode/svg.ex +++ b/lib/eqrcode/svg.ex @@ -23,7 +23,8 @@ defmodule EQRCode.SVG do @doc """ Return the SVG format of the QR Code """ - def svg(%Matrix{matrix: matrix}, options) do + @spec svg(Matrix.t(), Keyword.t()) :: String.t() + def svg(%Matrix{matrix: matrix}, options \\ []) do matrix_size = matrix |> Tuple.to_list() |> Enum.count() svg_options = options |> set_svg_options(matrix_size) dimension = matrix_size * svg_options[:module_size] From cbdb93ecccf0cb24bea35aa4b1d7103ea8eaee48 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:37:10 -0500 Subject: [PATCH 08/10] Options should be a keyword list, not a map --- lib/eqrcode.ex | 4 ++-- lib/eqrcode/svg.ex | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/eqrcode.ex b/lib/eqrcode.ex index fec1264..071e12c 100644 --- a/lib/eqrcode.ex +++ b/lib/eqrcode.ex @@ -73,7 +73,7 @@ defmodule EQRCode do ```elixir qr_code_content |> EQRCode.encode() - |> EQRCode.svg(%{color: "#cc6600", shape: "circle", width: 300}) + |> EQRCode.svg(color: "#cc6600", shape: "circle", width: 300) ``` You can specify the following attributes of the QR code: @@ -85,5 +85,5 @@ defmodule EQRCode do Default options are `%{color: "#000", shape: "square"}`. """ - defdelegate svg(matrix, options \\ %{}), to: EQRCode.SVG + defdelegate svg(matrix, options \\ []), to: EQRCode.SVG end diff --git a/lib/eqrcode/svg.ex b/lib/eqrcode/svg.ex index e2a14c2..1a885d4 100644 --- a/lib/eqrcode/svg.ex +++ b/lib/eqrcode/svg.ex @@ -26,7 +26,7 @@ defmodule EQRCode.SVG do @spec svg(Matrix.t(), Keyword.t()) :: String.t() def svg(%Matrix{matrix: matrix}, options \\ []) do matrix_size = matrix |> Tuple.to_list() |> Enum.count() - svg_options = options |> set_svg_options(matrix_size) + svg_options = options |> Map.new() |> set_svg_options(matrix_size) dimension = matrix_size * svg_options[:module_size] xml_tag = ~s() From 85be49d1b9bed8d397d0710ecb5b7f6aaa5b4882 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Fri, 31 Aug 2018 13:38:42 -0500 Subject: [PATCH 09/10] Logical fix! --- lib/eqrcode/svg.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eqrcode/svg.ex b/lib/eqrcode/svg.ex index 1a885d4..9c62351 100644 --- a/lib/eqrcode/svg.ex +++ b/lib/eqrcode/svg.ex @@ -33,9 +33,9 @@ defmodule EQRCode.SVG do dimension_attrs = if Keyword.get(options, :viewbox, false) do - ~s(width="#{dimension}" height="#{dimension}") - else ~s(viewBox="0 0 #{dimension} #{dimension}") + else + ~s(width="#{dimension}" height="#{dimension}") end open_tag = From b38fe404b2ce86fd96ebb88c832eb794bab1fe26 Mon Sep 17 00:00:00 2001 From: Nick Kezhaya Date: Sun, 2 Sep 2018 21:59:16 -0500 Subject: [PATCH 10/10] Support map() in SVG args --- lib/eqrcode.ex | 2 +- lib/eqrcode/svg.ex | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/eqrcode.ex b/lib/eqrcode.ex index 071e12c..ef65c81 100644 --- a/lib/eqrcode.ex +++ b/lib/eqrcode.ex @@ -83,7 +83,7 @@ defmodule EQRCode do * `width`: The width of the QR code in pixel. Without the width attribute, the QR code size will be dynamically generated based on the input string. * `viewbox`: When set to `true`, the SVG element will specify its height and width using `viewBox`, instead of explicit `height` and `width` tags. - Default options are `%{color: "#000", shape: "square"}`. + Default options are `[color: "#000", shape: "square"]`. """ defdelegate svg(matrix, options \\ []), to: EQRCode.SVG end diff --git a/lib/eqrcode/svg.ex b/lib/eqrcode/svg.ex index 9c62351..6b0bea6 100644 --- a/lib/eqrcode/svg.ex +++ b/lib/eqrcode/svg.ex @@ -5,7 +5,7 @@ defmodule EQRCode.SVG do ```elixir qr_code_content |> EQRCode.encode() - |> EQRCode.svg(%{color: "#cc6600", shape: "circle", width: 300}) + |> EQRCode.svg(color: "#cc6600", shape: "circle", width: 300) ``` You can specify the following attributes of the QR code: @@ -23,8 +23,9 @@ defmodule EQRCode.SVG do @doc """ Return the SVG format of the QR Code """ - @spec svg(Matrix.t(), Keyword.t()) :: String.t() + @spec svg(Matrix.t(), map() | Keyword.t()) :: String.t() def svg(%Matrix{matrix: matrix}, options \\ []) do + options = options |> Enum.map(& &1) matrix_size = matrix |> Tuple.to_list() |> Enum.count() svg_options = options |> Map.new() |> set_svg_options(matrix_size) dimension = matrix_size * svg_options[:module_size]