How to convert Base64 string to pdf file using prawn gem

Viewed 5921

I want to generate pdf file from DB record. Encode it to Base64 string and store it to DB. Which works fine. Now I want reverse action, How can I decode Base64 string and generate pdf file again?

here is what I tried so far.

def data_pdf_base64
  begin
    # Create Prawn Object
    my_pdf = Prawn::Document.new
    # write text to pdf
    my_pdf.text("Hello Gagan, How are you?")
    # Save at tmp folder as pdf file
    my_pdf.render_file("#{Rails.root}/tmp/pdf/gagan.pdf")
    # Read pdf file and encode to Base64
    encoded_string = Base64.encode64(File.open("#{Rails.root}/tmp/pdf/gagan.pdf"){|i| i.read})
    # Delete generated pdf file from tmp folder
    File.delete("#{Rails.root}/tmp/pdf/gagan.pdf") if File.exist?("#{Rails.root}/tmp/pdf/gagan.pdf")
    # Now converting Base64 to pdf again
    pdf = Prawn::Document.new
    # I have used ttf font because it was giving me below error
    # Your document includes text that's not compatible with the Windows-1252 character set. If you need full UTF-8 support, use TTF fonts instead of PDF's built-in fonts.
    pdf.font Rails.root.join("app/assets/fonts/fontawesome-webfont.ttf")
    pdf.text Base64.decode64 encoded_string
    pdf.render_file("#{Rails.root}/tmp/pdf/gagan2.pdf")
  rescue => e
    return render :text => "Error: #{e}"
  end
end

Now I am getting below error:

Encoding ASCII-8BIT can not be transparently converted to UTF-8. Please ensure the encoding of the string you are attempting to use is set correctly

I have tried How to convert base64 string to PNG using Prawn without saving on server in Rails but it gives me error:

"\xFF" from ASCII-8BIT to UTF-8

Can anyone point me what I am missing?

1 Answers

The answer is to decode the Base64 encoded string and either send it directly or save it directly to disk (naming it as a PDF file, but without using prawn).

The decoded string is a binary representation of the PDF file data, so there's no need to use Prawn or to re-calculate the content of the PDF data.

i.e.

 raw_pdf_str = Base64.decode64 encoded_string
 render :text, raw_pdf_str # <= this isn't the correct rendering pattern, but it's good enough as an example.

EDIT

To clarify some of the information given in the comments:

  1. It's possible to send the string as an attachment without saving it to disk, either using render text: raw_pdf_str or the #send_data method (these are 4.x API versions, I don't remember the 5.x API style).

  2. It's possible to encode the string (from the Prawn object) without saving the rendered PDF data to a file (save it to a String object instead). i.e.:

    encoded_string = Base64.encode64(my_pdf.render)
    
  3. The String data could be used directly as an email attachment, similarly to the pattern provided here only using the String directly instead of reading any data from a file. i.e.:

    # inside a method in the Mailer class
    attachments['my_pdf.pdf'] = { :mime_type => 'application/pdf',
                                  :content => raw_pdf_str } 
    
Related