Prawn: how to set document's printable dimensions - ruby-on-rails

I'm generating a pdf with prawn. Basically, I generate the document and I fill it with some images.
The problem comes when I download the file and I try to print it. The dimensions are not set to the ones I previously specified.
pdf = Prawn::Document.new(page_size: "A3", margin: PAGE_MARGIN, page_layout: :landscape)
When I try to print it, the default page size is "A4" instead of "A3"
How can I solve this?
I tried to attach some metadata but it didn't work correctly.
Thanks in advance!

In the case where you're generating the document within its own class, this also works to declare the paper size:
class EnvelopePdf < Prawn::Document
def initialize(_item_array, _type_of_item)
super(:page_size => [324, 684], :page_layout => :landscape) # 4.5" by 9.5", which is No 10 envelopes
... application-specific initialization code here ...
print_the_envelopes
end

Using prawn 1.3.0:
require "prawn"
pdf = Prawn::Document.new(:page_size => 'A3')
pdf.text "Hello World!"
pdf.render_file("export.pdf")
in terminal:
pdfinfo export.pdf
outputs:
Creator: Prawn
Producer: Prawn
Tagged: no
Form: none
Pages: 1
Encrypted: no
Page size: 841.89 x 1190.55 pts
Page rot: 0
File size: 842 bytes
Optimized: no
PDF version: 1.3

Related

Encoding problem when adding text to existing PDF with CombinePDF

(Rails 6.0.2.2, ruby 2.7.1, combine_pdf 1.0.18)
I'm currently trying to write some text to an existing PDF with the CombinePDF gem. Unfortunately I'm running in some encoding problems.
I'm loading the existing PDF:
pdf = CombinePDF.load "#{Rails.root}/public/pdf/base.pdf"
Then I'm adding text to it:
pdf.pages[0].textbox "Straße", height: 20, width: 160, y: 527, x: 215, font_size: 12, box_color: nil, text_align: :left, text_padding: 0
When generating a new pdf out of it:
send_data pdf.to_pdf, filename: "output.pdf", type: "application/pdf"
the string gets displayed as StraˆŸe, so the ß isn't displayed correctly.
I also tried to replace it with unicode literals (\xc3\x9f) without any effect.
Anybody has an idea what else to try?
If you use HexaPDF you could do something like this:
require 'hexapdf'
require 'stringio'
doc = HexaPDF::Document.open("#{Rails.root}/public/pdf/base.pdf")
doc.pages[0].canvas.font("Helvetica", size: 12).text("Straße", at: [215, 527])
outio = StringIO.new(''.b)
doc.write(outio)
Just make sure that you use a font that contains glyphs for all characters you want to use. So better use a TrueType font instead of the builtin Helvetica (you can just provide the path to a TrueType font to the #font method).

How can I merge all PDF in one file with wickedpdf?

The way I'm working right now is I'm generating multiple pdf files and sending them all one at a time for the user to download, but the problem is sometimes they end up with too many files.
How can I merge all pdfs in a single file before sending them to the user?
I use combine_pdf gem.
To combine PDF files:
pdf = CombinePDF.new
pdf << CombinePDF.load("file1.pdf") # one way to combine, very fast.
pdf << CombinePDF.load("file2.pdf")
pdf.save "combined.pdf"
You can also parse PDF files from memory. Loading from the memory is
especially effective for importing PDF data recieved through the
internet or from a different authoring library such as Prawn:
pdf_data = prawn_pdf_document.render # Import PDF data from Prawn
pdf = CombinePDF.parse(pdf_data)
If you want to use some tool like PDFTk or CombinePDF, all you should need to do is prerender your individual PDFs by using something like:
pdf1 = render_to_string(pdf: 'pdf1', template: 'pdf1')
pdf2 = render_to_string(pdf: 'pdf2', template: 'pdf2')
or
pdf1 = WickedPdf.new.pdf_from_string(some_html_string)
pdf2 = WickedPdf.new.pdf_from_string(another_html_string)
If those tools won't take a PDF as a string, you may need to write them to tempfiles first.
If you don't want to introduce another dependency to merge things, wkhtmltopdf can take multiple pdf files (or urls), and render them all as one pdf with a command similar to this:
wkhtmltopdf tmp/tempfile1.html tmp/tempfile2.html tmp/output.pdf
Knowing this, you could prerender your templates, with layouts and everything, out to HTML strings, then pass them into wkhtmltopdf something like this:
# app/models/concerns/multipage_pdf_renderer.rb
require 'open3'
class MultipagePdfRenderer
def self.combine(documents)
outfile = WickedPdfTempfile.new('multipage_pdf_renderer.pdf')
tempfiles = documents.each_with_index.map do |doc, index|
file = WickedPdfTempfile.new("multipage_pdf_doc_#{index}.html")
file.binmode
file.write(doc)
file.rewind
file
end
filepaths = tempfiles.map{ |tf| tf.path.to_s }
binary = WickedPdf.new.send(:find_wkhtmltopdf_binary_path)
command = [binary, '-q']
filepaths.each { |fp| command << fp }
command << outfile.path.to_s
err = Open3.popen3(*command) do |stdin, stdout, stderr|
stderr.read
end
raise "Problem generating multipage pdf: #{err}" if err.present?
return outfile.read
ensure
tempfiles.each(&:close!)
end
end
And call in your controller something like this:
def fancy_report
respond_to do |format|
format.pdf do
doc1 = render_to_string(template: 'pages/_page1')
doc2 = render_to_string(template: 'pages/_page2')
pdf_file = MultipagePdfRenderer.combine([doc1, doc2])
send_data pdf_file, type: 'application/pdf', disposition: 'inline'
end
end
end
However, this only covers the simplest of cases, you'll have to do the work of rendering the headers and footers if you need them, parsing (or adding) any options you might need.
This solution originally came from https://github.com/mileszs/wicked_pdf/issues/339 so it may be helpful to look there for more details on this strategy.
Try PDFtk. In my opinon, it is the best library for editing PDF files, and there are some gems that wraps it for access from Ruby.

Prawn - How can i allow unlimited height

On ruby when you create pdf using Prawn you can use:
pdf = Prawn::Document.new(:page_size => [200, 900])
But I want to create a pdf with a fixed width (200) and unlimited maximum height with a minimum.
Something like this:
pdf = Prawn::Document.new(:page_size => [200, {min: 400, max: :unlimited}])
The pdf in question is a ticket so I want to know if this is possible.
Thank you.

Rails 3 and PDFKit. How to specify page size?

I have been looking in the documentation but can't find the answer. How can I specify the page size of my pdf document and what are the available page sizes? I keep on looking and looking but I can't find good documentation. Please point me to a URL or let me know how can I code some page size into my PDF document.
Oh and I don't want to do that on any config file because I need to generate PDf documents of different sizes.
NOT in config file...
PDFKit.configure do |config|
config.wkhtmltopdf = `which wkhtmltopdf`.to_s.strip
config.default_options = {
:encoding=>"UTF-8",
:page_size=>"A4", #or "Letter" or whatever needed
:margin_top=>"0.25in",
:margin_right=>"1in",
:margin_bottom=>"0.25in",
:margin_left=>"1in",
:disable_smart_shrinking=>false
}
end
You can set the page size when creating a new PDF like this:
kit = PDFKit.new(source, :page_size => "Legal")
PDFKit uses WKHTMLTOPDF which in turn uses QPrinter. You can find the available sizes in the QPrinter documentation (there's a bunch), but its pretty safe to say that any size paper you want is available. Also, you can set a custom size if you can't find what you need.
NB: If you don't set a default option for page_size in a config somewhere AND don't supply one in your method call, PDFKit will use its internal default (Letter). See line 10 of lib/pdfkit/configuration.rb
Pdkit accepts custom sizes:
PDFKit.configure do |config|
config.wkhtmltopdf = `which wkhtmltopdf`.strip
config.default_options = {
:page_width => '1682',
:page_height => '2378'
}
end
The sizes must be in milimeters (wkthmltopdf documentation).
Since it's using wkhtmltopdf to generate the PDFs I'm assuming you can use the same options that it supports. In a wkhtmltopdf manual I found, it mentions the following site for a list of sizes:
http://doc.trolltech.com/4.6/qprinter.html#PaperSize-enum
To set the page size, you can use the :page_size option like so:
PDFKit.new(html, :page_size => 'Letter')

Converting PDFs to PNGs with Dragonfly

I have a Dragonfly processor which should take a given PDF and return a PNG of the first page of the document.
When I run this processor via the console, I get back the PNG as expected, however, when in the context of Rails, I'm getting it as a PDF.
My code is roughly similar to this:
def to_pdf_thumbnail(temp_object)
tempfile = new_tempfile('png')
args = "'#{temp_object.path}[0]' '#{tempfile.path}'"
full_command = "convert #{args}"
result = `#{full_command}`
tempfile
end
def new_tempfile(ext=nil)
tempfile = ext ? Tempfile.new(['dragonfly', ".#{ext}"]) : Tempfile.new('dragonfly')
tempfile.binmode
tempfile.close
tempfile
end
Now, tempfile is definitely creating a .png file, but the convert is generating a PDF (when run from within Rails 3).
Any ideas as to what the issue might be here? Is something getting confused about the content type?
I should add that both this and a standard conversion (asset.png.url) both yield a PDF with the PDF content as a small block in the middle of the (A4) image.
An approach I’m using for this is to generate the thumbnail PNG on the fly via the thumb method from Dragonfly’s ImageMagick plugin:
<%= image_tag rails_model.file.thumb('100x100#', format: 'png', frame: 0).url %>
So long as Ghostscript is installed, ImageMagick/Dragonfly will honour the format / frame (i.e. page of the PDF) settings. If file is an image rather than a PDF, it will be converted to a PNG, and the frame number ignored (unless it’s a GIF).
Try this
def to_pdf_thumbnail(temp_object)
ret = ''
tempfile = new_tempfile('png')
system("convert",tmp_object.path[0],tmpfile.path)
tempfile.open {|f| ret = f.read }
ret
end
The problem is you are likely handing convert ONE argument not two
Doesn't convert rely on the extension to determine the type? Are you sure the tempfiles have the proper extensions?

Resources