rubylabelpngbarcodeprawn

How to put an image on a label using Prawn/labels?


I'm using Ruby for scripting, and Prawn-labels to print ISBN labels for books, using Barby to generate the EAN-13 bar codes.

The ISBNs come out of MySQL. That works fine. I can create a PDF of 30-up labels containing the titles of the books, using Prawn/labels. That works fine.

However, I am not having much joy putting a Barby-generated PNG image of the proper EAN-13 barcode on the label.

Here's getting the info out of the database and generating EAN-13, pretty straightforward:

query = "SELECT ISBN13, Title FROM s_library WHERE Has_barcode != 'y'"
result = client.query(query, symbolize_keys: true)
tags = []
result.each do |row|
    tags << [row[:ISBN13], row[:Title], Barby::EAN13.new(row[:ISBN13].chop)]
end
tags.sort! {|a, b| a[1] <=> b[1]} # Sort by book title

So now I have a two-dimensional Array, with each row containing an ISBN String, a Title String, and a Barby holding the EAN-13 coding for the ISBN (#<Barby::EAN13:0x00007fc6da13ce98 @data="978140006215"> ).

Now I'm following the example for Prawn::Labels, and if I leave out trying to #embed_image the PNG data, I can successfully generate 30-up labels with the title of each book:

Prawn::Labels.generate('EAN_tags.pdf', tags, :type => 'Avery5160') do |pdf, tag|
    pdf.font '/Library/Fonts/Erasdemi.TTF'
    pdf.text(tag[1], :align => :center)
    png = Barby::PngOutputter.new(tag[2]).to_png
#   pdf.embed_image(png, Prawn::Images::PNG.new(png), {})
end
`open EAN_tags.pdf`

When I un-comment the image embedding, I get a cryptic traceback that I don't quite understand:

    25: from /Users/jan/bin/Print_ISBN13.rb:73:in `<main>'
    24: from /usr/local/lib/ruby/gems/2.7.0/gems/prawn-labels-1.2.6/lib/prawn/labels.rb:18:in `generate'
    23: from /usr/local/lib/ruby/gems/2.7.0/gems/prawn-2.3.0/lib/prawn/document.rb:408:in `render_file'
    22: from /usr/local/lib/ruby/gems/2.7.0/gems/prawn-2.3.0/lib/prawn/document.rb:408:in `open'
    21: from /usr/local/lib/ruby/gems/2.7.0/gems/prawn-2.3.0/lib/prawn/document.rb:408:in `block in render_file'
    20: from /usr/local/lib/ruby/gems/2.7.0/gems/prawn-2.3.0/lib/prawn/document.rb:400:in `render'
    19: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/renderer.rb:167:in `render'
    18: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/renderer.rb:202:in `render_body'
    17: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/document_state.rb:72:in `render_body'
    16: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/object_store.rb:70:in `each'
    15: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/object_store.rb:70:in `each'
    14: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/object_store.rb:71:in `block in each'
    13: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/document_state.rb:78:in `block in render_body'
    12: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/reference.rb:26:in `object'
    11: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:87:in `pdf_object'
    10: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:87:in `each'
     9: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:93:in `block in pdf_object'
     8: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:87:in `pdf_object'
     7: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:87:in `each'
     6: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:93:in `block in pdf_object'
     5: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:87:in `pdf_object'
     4: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:87:in `each'
     3: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:93:in `block in pdf_object'
     2: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:75:in `pdf_object'
     1: from /usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:25:in `utf8_to_utf16'
/usr/local/lib/ruby/gems/2.7.0/gems/pdf-core-0.8.1/lib/pdf/core/pdf_object.rb:25:in `encode': "\\x89" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to UTF-16BE (Encoding::UndefinedConversionError)

I can dump the png variable to a file and see the barcode.

From the stack, it looks like it's trying to interpret the PNG data as a UTF-16 String. Ugh. Wasn't expecting that.

Any clues as to what I'm doing wrong?


Solution

  • The answer appears to be to use something called StringIO, which apparently provides a File interface to an in-memory (blob) image.

    So, I added the middle line, below:

        png = Barby::PngOutputter.new(tag[2]).to_png
        str_png = StringIO.new(png)
        pdf.image(str_png)
    
    

    instead of trying to pass binary data via embed_image, and I am now getting the barcode in the final PDF output. (It still needs some tweaking, but the basic concept is now working.)

    I had searched here many ways — really! But the word "blob" is what got the answer on this site.