Barcode PDFs with Ruby on Rails
For a project, I was researching methods to generate individual PDFs with imprinted EAN barcodes. Some of the how-tos and blog articles I found were quite old, and it was not always immediately obvious if the solution still works and could be recommended in 2023. The following represents my short notes of a working way to do this. There may be other or better ways, but this one worked for me.
Barby is a barcode generator library for Ruby. It generates a barcode as an image or as a PDF. For creating the actual PDF with background image I am using the Prawn PDF generation library for Ruby. It produces PDFs from scratch and annotates existing PDFs with text, images, and barcodes.
I am using two model classes, one for the voucher with the code property (which shall be printed as a barcode), and one for the PDF generation. The PDF generation class is a subclass of Prawn::Document. It takes a path and a code as arguments and generates a PDF with the barcode imprinted. The voucher class creates a temporary file, calls the PDF generation class, and returns the path to the temporary file. As we are using Rails Tempfile, the temporary file is deleted automatically when the Rails process exits.
The resulting PDF should be 100mm x 133mm with a png as the background image. At first, I experimented with the background option of Prawn::Document, but this did not work as expected. The background image didn’t scale to the page size. Instead, I am using the image method to draw the background image. The fit option scales the image to the page size.
Prawn’s measurement_extensions allow the use of mm as a unit for the page size instead of the default 1/72 inch.
require "barby/barcode/code_128"
require "barby/outputter/prawn_outputter"
require "prawn/measurement_extensions"
class CodePdf < Prawn::Document
def initialize path, code, background
super({
page_size: [100.mm, 177.mm],
margin: 0
})
image background, fit: [100.mm, 177.mm]
barcode code
render_file path
end
def barcode code
barcode = Barby::Code128.new code
barcode.annotate_pdf self, height: 18.mm, x: 17.mm, y: 3.mm
end
end
In the code class, we create a temporary file and call the PDF generation class. The background image is found in the app/assets/images/{language} directory. The name of the background image is stored in the voucher property of the price object (where the code belongs_to). The voucher property is a string like voucher.png. The I18n.locale method returns the current locale, e.g. de or fr which is used to find the correct background image.
def voucher
# Create temporary file e.g. tmp/voucher20230805-66997-kozjms.pdf
tmpfile = Tempfile.new "voucher", Rails.root.join("tmp")
path = tmpfile.path + ".pdf"
bg_path = Rails.root.join "app", "assets", "images", I18n.locale.to_s, price.voucher
CodePdf.new path, code, bg_path
path
end
Here is an example of the resulting voucher PDF with the barcode: