Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Get number of pages #27

Open
joselo opened this issue Jun 1, 2021 · 4 comments
Open

Question: Get number of pages #27

joselo opened this issue Jun 1, 2021 · 4 comments

Comments

@joselo
Copy link

joselo commented Jun 1, 2021

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!

@andrewtimberlake
Copy link
Owner

andrewtimberlake commented Jun 2, 2021 via email

@joselo
Copy link
Author

joselo commented Jun 2, 2021

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

@Hermanverschooten
Copy link
Contributor

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

@andrewtimberlake
Copy link
Owner

Thanks @Hermanverschooten I’ll look at how to incorporate something like this into the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants