Skip to content

Commit

Permalink
Merge pull request #2 from whitepaperclip/master
Browse files Browse the repository at this point in the history
No warnings, added tests, added viewBox option
  • Loading branch information
siliconavengers authored Sep 3, 2018
2 parents 5c5bf00 + b38fe40 commit 8128cf6
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 55 deletions.
67 changes: 35 additions & 32 deletions lib/eqrcode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.")
Expand All @@ -71,16 +73,17 @@ 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:
* `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"}`.
Default options are `[color: "#000", shape: "square"]`.
"""
defdelegate svg(matrix, options \\ %{}), to: EQRCode.Svg
defdelegate svg(matrix, options \\ []), to: EQRCode.SVG
end
37 changes: 22 additions & 15 deletions lib/eqrcode/galois_field.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,41 @@ 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.
Example:
iex> QRCode.GaloisField.to_i(1)
iex> EQRCode.GaloisField.to_i(1)
2
"""
@spec to_i(integer) :: integer
def to_i(alpha)
def to_i(alpha) do
@integers[alpha]
end

@doc """
Given integer returns alpha exponent.
Example:
iex> QRCode.GaloisField.to_a(2)
iex> EQRCode.GaloisField.to_a(2)
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
26 changes: 19 additions & 7 deletions lib/eqrcode/svg.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
defmodule EQRCode.Svg do
defmodule EQRCode.SVG do
@moduledoc """
Render the QR Code matrix in SVG format
```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:
Expand All @@ -18,20 +18,32 @@ defmodule EQRCode.Svg do
"""

alias EQRCode.Matrix

@doc """
Return the SVG format of the QR Code
"""
def svg(%EQRCode.Matrix{matrix: matrix}, options) do
@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 |> 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(<?xml version="1.0" standalone="yes"?>)

dimension_attrs =
if Keyword.get(options, :viewbox, false) do
~s(viewBox="0 0 #{dimension} #{dimension}")
else
~s(width="#{dimension}" height="#{dimension}")
end

open_tag =
~s(<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" width="#{
dimension
}" height="#{dimension}" shape-rendering="crispEdges">)
~s(<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" #{
dimension_attrs
}
shape-rendering="crispEdges">)

close_tag = ~s(</svg>)

Expand Down
1 change: 0 additions & 1 deletion test/eqrcode_test.exs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down
4 changes: 4 additions & 0 deletions test/galois_field_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule EQRCode.GaloisFieldTest do
use ExUnit.Case
doctest EQRCode.GaloisField
end
4 changes: 4 additions & 0 deletions test/matrix_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule EQRCode.MatrixTest do
use ExUnit.Case
doctest EQRCode.Matrix
end
4 changes: 4 additions & 0 deletions test/reed_solomon_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule EQRCode.ReedSolomonTest do
use ExUnit.Case
doctest EQRCode.ReedSolomon
end

0 comments on commit 8128cf6

Please sign in to comment.