defprotocol Pdf.Export do
@moduledoc false
def to_iolist(object)
end
defimpl Pdf.Export, for: List do
def to_iolist([]), do: []
def to_iolist(list), do: Enum.map(list, &Pdf.Export.to_iolist/1)
end
defimpl Pdf.Export, for: BitString do
def to_iolist(string), do: string
end
defimpl Pdf.Export, for: Integer do
def to_iolist(number), do: Pdf.Export.to_iolist(Integer.to_string(number))
end
defimpl Pdf.Export, for: Float do
def to_iolist(number),
do: Pdf.Export.to_iolist(:erlang.float_to_binary(number, [:compact, decimals: 4]))
end
defimpl Pdf.Export, for: Date do
def to_iolist(date) do
[
"(D:",
to_string(date.year),
pad_datepart(date.month),
pad_datepart(date.day),
")"
]
end
defp pad_datepart(part), do: part |> to_string |> String.pad_leading(2, "0")
end
defimpl Pdf.Export, for: DateTime do
def to_iolist(date) do
[
"(D:",
to_string(date.year),
pad_datepart(date.month),
pad_datepart(date.day),
pad_datepart(date.hour),
pad_datepart(date.minute),
pad_datepart(date.second),
timezone_info(date),
")"
]
end
defp pad_datepart(part), do: part |> to_string |> String.pad_leading(2, "0")
defp timezone_info(%{utc_offset: 0}), do: "Z"
defp timezone_info(%{utc_offset: offset}) when offset > 0, do: ["+", format_offset(offset)]
defp timezone_info(%{utc_offset: offset}) when offset < 0, do: ["-", format_offset(abs(offset))]
defp format_offset(offset) do
minutes = round(offset / 60)
hours = round(minutes / 60)
[pad_datepart(hours), "'", pad_datepart(rem(minutes, 60))]
end
end
defimpl Pdf.Export, for: Tuple do
def to_iolist({:string, string}), do: ["(", string, ")"]
def to_iolist({:name, name}), do: ["/", name]
def to_iolist({:object, number, generation}),
do: [Integer.to_string(number), " ", Integer.to_string(generation), " R"]
def to_iolist({:command, []}), do: []
def to_iolist({:command, [head | tail]}),
do: [Pdf.Export.to_iolist(head), Enum.map(tail, &[" ", Pdf.Export.to_iolist(&1)])]
def to_iolist({:command, command}), do: command
end