Packages

Library that enables programs to write Data Matrix barcodes of the modern ECC200 variety.

Current section

Files

Jump to
data_matrix lib datamatrix matrix.ex
Raw

lib/datamatrix/matrix.ex

defmodule DataMatrix.Matrix do
@moduledoc false
alias DataMatrix.{MappingMatrix, SymbolAttribute}
defstruct [:matrix, :version, :nrow, :ncol]
def new(version) when version in 0..29 do
{nrow, ncol} = SymbolAttribute.size(version)
%__MODULE__{
matrix: empty_matrix(nrow, ncol),
version: version,
nrow: nrow,
ncol: ncol
}
end
def draw_patterns(%__MODULE__{matrix: matrix, nrow: nrow, ncol: ncol, version: version} = m) do
{region_nrow, region_ncol} = SymbolAttribute.data_region_size(version)
horizontal_patterns =
get_positions(region_nrow, nrow)
|> Stream.zip(Stream.cycle([:dotted, :solid]))
|> Stream.map(fn {row, type} ->
for col <- 0..(ncol - 1),
into: %{},
do: {{row, col}, if(type == :dotted, do: 1 - rem(col, 2), else: 1)}
end)
vertical_patterns =
get_positions(region_ncol, ncol)
|> Stream.zip(Stream.cycle([:solid, :dotted]))
|> Stream.map(fn {col, type} ->
for row <- 0..(nrow - 1),
into: %{},
do: {{row, col}, if(type == :dotted, do: rem(row, 2), else: 1)}
end)
patterns =
horizontal_patterns
|> Stream.concat(vertical_patterns)
|> Enum.reduce(%{}, &Map.merge/2)
%{m | matrix: Map.merge(matrix, patterns)}
end
defp get_positions(gap, length) do
positions =
[gap + 1, 1]
|> Stream.cycle()
|> Stream.scan(&(&1 + &2))
|> Enum.take_while(&(&1 < length))
[0 | positions]
end
def draw_data(%__MODULE__{matrix: matrix, version: version} = m, bits) do
{nrow, ncol} = SymbolAttribute.mapping_matrix_size(version)
{mapping, mapping_matrix} = MappingMatrix.get_mapping_matrix(nrow, ncol)
data_matrix =
mapping
|> subdivide_into_data_regions(SymbolAttribute.data_region_size(version))
|> Stream.zip(bits)
|> Map.new()
data_matrix =
mapping_matrix
|> Map.merge(data_matrix)
|> translate(1, 1)
%{m | matrix: Map.merge(matrix, data_matrix)}
end
defp subdivide_into_data_regions(points, {nrow, ncol}) do
Stream.map(points, fn {row, col} ->
{
div(row, nrow) * (nrow + 2) + rem(row, nrow),
div(col, ncol) * (ncol + 2) + rem(col, ncol)
}
end)
end
defp translate(matrix, drow, dcol) do
for {{row, col}, value} <- matrix,
into: %{},
do: {{row + drow, col + dcol}, value}
end
def draw_quiet_zone(%__MODULE__{matrix: matrix, nrow: nrow, ncol: ncol} = m, width \\ 1) do
new_nrow = nrow + 2 * width
new_ncol = ncol + 2 * width
empty = empty_matrix(new_nrow, new_ncol)
centered_matrix = translate(matrix, width, width)
%__MODULE__{m | matrix: Map.merge(empty, centered_matrix), nrow: new_nrow, ncol: new_ncol}
end
def export(%__MODULE__{matrix: matrix, nrow: nrow, ncol: ncol, version: version}) do
flatten =
for row <- 0..(nrow - 1),
col <- 0..(ncol - 1),
do: Map.get(matrix, {row, col})
%{
version: version,
nrow: nrow,
ncol: ncol,
matrix: flatten |> Enum.chunk_every(ncol)
}
end
defp empty_matrix(nrow, ncol) do
for row <- 0..(nrow - 1),
col <- 0..(ncol - 1),
into: %{},
do: {{row, col}, 0}
end
end