Question: Get number of pages
Opened this issue · 4 comments
First of all thanks for this amazing library. I chooed it over html based solutions. It's has everything for my purposes but I wonder if is there any way to get the total number of pages?. I'm rendering an invoice with items. so I have a kind of recursive methods to know when I have to add a new page (:continue.. remaining etc.) however I'm not sure how I could calculate the total of pages that I will add, before render the table. I'm thinking to calculate the total using the size of the data. If do you have any Idea I really appreciate another approach. thanks!
Hey @andrewtimberlake thanks for the quick answer, basically I render the header and the footer in each page, for example if the invoice is too long It could have many pages, so I'm showing the header/fotter in whole pages and I would like to show in the footer something like page 1 from 3
, page 2 from 3
, etc.
So when I render the invoice items I have two functions with pattern matching; one for :complete
and the other one for the remaining
. Something like these:
defp add_table({pdf, :complete}, _invoice), do: pdf
defp add_table({pdf, {:continue, _} = remaining}, invoice) do
{pdf, grid} =
pdf
|> Pdf.add_page(:a4)
|> add_header(invoice)
|> Pdf.table({50, 560}, {500, 300}, remaining, @table_opts)
pdf = add_footer(pdf, invoice)
add_table({pdf, grid}, invoice)
end
defp add_header(pdf, invoice) do
# ...
end
defp add_footer(pdf, invoice) do
%{width: width, height: _height} = Pdf.size(pdf)
page_number = "#{Pdf.page_number(pdf)}"k
total_pages = 3 # How calculate this?
|> Pdf.text_wrap!({20, 100}, {width - 40, 20}, "Page #{page_number} of #{total_pages}", align: :center)
end
I know it is hacky, but I have this function in my pdf_helpers module.
It will traverse the list of pages and execute the given function with arity 3, the pdf, current page number and the total number of pages. I execute this at the end of the PDF generation.
example
add_page_numbers(pdf, fn pdf, page, pages ->
Pdf.text_at(pdf, {100,100}, "#{page} of {pages}")
end)
code:
defp add_page_numbers(pdf, render_fn) when is_function(render_fn, 3) do
document = :sys.get_state(pdf)
pages = length(document.pages) + 1
current_page = document.current
new_pages =
document.pages
|> Enum.reverse()
|> Enum.with_index(1)
|> Enum.map(fn {page, pageno} ->
:sys.replace_state(pdf, fn state -> Map.put(state, :current, page) end)
render_fn.(pdf, pageno, pages)
:sys.get_state(pdf).current
end)
|> Enum.reverse()
:sys.replace_state(pdf, fn state ->
%{state | current: current_page, pages: new_pages}
end)
render_fn.(pdf, pages, pages)
end
defp add_page_numbers(pdf, render_fn) when is_function(render_fn) do
raise ArgumentError, "add_page_numbers takes a render function with arity 3!"
end
defp add_page_numbers(pdf, coords) do
add_page_numbers(pdf, fn pdf, page, pages ->
Pdf.text_at(pdf, coords, "#{page}/#{pages}")
end)
end
Thanks @Hermanverschooten I’ll look at how to incorporate something like this into the library.