9

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?

Gagan Gami
  • 10,121
  • 1
  • 29
  • 55
  • @Med : ok let me try will update you soon – Gagan Gami Sep 13 '17 at 13:43
  • @Med : getting this error : `invalid byte sequence in UTF-8` – Gagan Gami Sep 13 '17 at 13:45
  • Your question is unclear. First you say that you store a PDF file in the DB. Then you ask how you can generate a PDF file from the data in the DB. But you just said that the data *is* a PDF file! So, which is it? – Jörg W Mittag Sep 13 '17 at 18:43
  • @JörgWMittag : I am generating pdf file, convert it to Base64 encoded string, store encoded string to DB, now from DB (Base64 encoded string) I want to generate pdf file again, I hope now it's clear – Gagan Gami Sep 21 '17 at 07:31
  • 1
    But you already *have* generated the PDF file! Why do you want to generate it *again*, when you can just retrieve it from the database? – Jörg W Mittag Sep 21 '17 at 07:33
  • @JörgWMittag : yes I have generated pdf file and can send it to user, but for security reason I can not store pdf file to db, instead i store encoded string, now in some method I need to generate pdf file from stored encoded string – Gagan Gami Sep 21 '17 at 07:35
  • But *why* do you have to re-generate the PDF? Why don't you just get the PDF file *that you stored in the database*? – Jörg W Mittag Sep 21 '17 at 07:36
  • forget about generated pdf, it is generated to convert in Base64, once i get encoded string, it will be deleted, my problem is "How can I convert Base64 encoded string to pdf ?" – Gagan Gami Sep 21 '17 at 07:37
  • @JörgWMittag: here is encoded string https://codepaste.net/8hyb1r now if I paste this to https://www.base64decode.org/ it generate pdf file, but I am not aware how can I generate this in Ruby using prawn gem – Gagan Gami Sep 21 '17 at 07:40
  • I *still* don't understand what this has to do with Prawn. Prawn is for generating PDFs. You already have a PDF. Why do you need Prawn? Why do you need to generate a PDF, when you already *have* a PDF in your DB? – Jörg W Mittag Sep 21 '17 at 07:44
  • @JörgWMittag : I have pdf in db as encoded string. now I want to decode it and get back as original pdf file – Gagan Gami Sep 21 '17 at 07:46
  • Yes, then you decode it, but why do you want to generate it, and what do you need Prawn for? – Jörg W Mittag Sep 21 '17 at 07:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154960/discussion-between-gagan-gami-and-jorg-w-mittag). – Gagan Gami Sep 21 '17 at 07:53
  • @JörgWMittag : I got the solution bro. – Gagan Gami Sep 21 '17 at 12:34

1 Answers1

12

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 } 
    
Myst
  • 18,516
  • 2
  • 45
  • 67
  • thank you for the answer, can I send as attachment without saving as physical file in my system? – Gagan Gami Sep 21 '17 at 13:05
  • @GaganGami - Yap, you can send the string as an attachment without saving it to disk. I don't remember the "Rails way" off the cuff. You can also render the Prawn data to a string (before encoding it) instead of rendering it to a file (use `#render` instead of `#render_file`). No need for temporary files. – Myst Sep 21 '17 at 13:08
  • `render` worked fine, I have converted encoded string to physical pdf file, but I don't want to save that file anywhere, instead want some file object which I can attached to the mail without saving to the disk as temporary file – Gagan Gami Sep 21 '17 at 13:14
  • @GaganGami , I'm not sure I understand your requirements... the String object **is** (as far as email attachments are concerned) an object you can attach to the email (as if it were a PDF file) without saving anything to the disk. – Myst Sep 21 '17 at 13:48
  • no worry bro, thanks for your help regarding, `render` it helps me, I have attached file without saving as physical, reference https://stackoverflow.com/questions/5145870/rails-actionmailer-how-to-send-an-attachment-that-you-create – Gagan Gami Sep 21 '17 at 13:52
  • will post my full answer so it can help in future to anyone else – Gagan Gami Sep 21 '17 at 13:52
  • @GaganGami - I added more information to my answer, I hope this helps. – Myst Sep 21 '17 at 14:06
  • Thanks for your kind help, really helps me a lot – Gagan Gami Sep 21 '17 at 14:41