lib/pdf417/high_level_encoder.ex

defmodule PDF417.HighLevelEncoder do
  @moduledoc """
  This encoder takes the input String and converts it to an array of numbers 0-917.
  Currently supported are two modes, text (ASCII), and numeric. 
  """

  alias PDF417.{CompactionManager, ErrorCorrection}

  @pad_codeword 900

  def encode(barcode = %{message: message, columns: columns, security_level: security_level}) do
    codewords =
      CompactionManager.compact(message)
      |> padding(security_level, columns)
      |> add_length_descriptor()
      |> error_correction(security_level)

    Map.put(barcode, :codewords, codewords)
  end

  defp padding(codewords, security_level, columns) do
    sum_codewords = 1 + length(codewords) + correction_codeword_length(security_level)

    rows = :math.ceil(sum_codewords / columns)

    pad_count =
      (rows * columns - sum_codewords)
      |> trunc()

    codewords ++ List.duplicate(@pad_codeword, pad_count)
  end

  defp correction_codeword_length(security_level), do: :math.pow(2, security_level + 1)

  defp add_length_descriptor(codewords) do
    [1 + length(codewords) | codewords]
  end

  defp error_correction(codewords, security_level) do
    codewords ++ ErrorCorrection.correction_codewords(codewords, security_level)
  end
end