kabaname
kabaname

Reputation: 265

Batch generating barcodes using ReportLab

Yesterday, I asked a question that was perhaps too broad.

Today, I've acted on my ideas in an effort to implement a solution.

Using ReportLab, pdfquery and PyPDF2, I'm trying to automate the process of generating barcodes on hundreds of pages in a PDF document.

Each page needs to have one barcode. However, if a page has a letter in the top right ('A' through 'E') then it needs to use the same barcode as the previous page. The files with letters on the top right are duplicate forms with similar information.

If there is no letter present, then a unique barcode number (incremented by one is fine) should be used on that page.

My code seems to work, but I'm having two issues:

  1. The barcode moves around ever so slightly (minor issue).
  2. The barcode value will not change (major issue). Only the first barcode number is set on all pages.

I can't seem to tell why the value isn't changing. Does anyone have an a clue?

Code is here:

import pdfquery
import os
from io import BytesIO
from PyPDF2 import PdfFileWriter, PdfFileReader
from reportlab.graphics.barcode import eanbc
from reportlab.graphics.shapes import Drawing 
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
from reportlab.graphics import renderPDF

pdf = pdfquery.PDFQuery("letters-test.pdf")

total_pages = pdf.doc.catalog['Pages'].resolve()['Count']
print("Total pages", total_pages)

barcode_value = 12345670

output = PdfFileWriter()

for i in range(0, total_pages):
    pdf.load(i) # Load page i into memory
    duplicate_letter = pdf.pq('LTTextLineHorizontal:in_bbox("432,720,612,820")').text()

    if duplicate_letter != '':
        print("Page " + str(i+1) + " letter " + str(duplicate_letter))
        print(barcode_value)
        packet = BytesIO()
        c = canvas.Canvas(packet, pagesize=letter)

        # draw the eanbc8 code
        barcode_eanbc8 = eanbc.Ean8BarcodeWidget(str(barcode_value))
        bounds = barcode_eanbc8.getBounds()
        width = bounds[2] - bounds[0]
        height = bounds[3] - bounds[1]
        d = Drawing(50, 10)
        d.add(barcode_eanbc8)
        renderPDF.draw(d, c, 400, 700)
        c.save()

        packet.seek(0)

        new_pdf = PdfFileReader(packet)

        # read existing PDF
        existing_pdf = PdfFileReader(open("letters-test.pdf", "rb"))

        # add the "watermark" (which is the new pdf) on the existing page
        page = existing_pdf.getPage(i)
        page.mergePage(new_pdf.getPage(0))
        output.addPage(page)

    else:
        # increment barcode value
        barcode_value += 1
        print("Page " + str(i+1) + " isn't a duplicate.")
        print(barcode_value)
        packet = BytesIO()
        c = canvas.Canvas(packet, pagesize=letter)

        # draw the eanbc8 code
        barcode_eanbc8 = eanbc.Ean8BarcodeWidget(str(barcode_value))
        bounds = barcode_eanbc8.getBounds()
        width = bounds[2] - bounds[0]
        height = bounds[3] - bounds[1]
        d = Drawing(50, 10)
        d.add(barcode_eanbc8)
        renderPDF.draw(d, c, 420, 710)
        c.save()

        packet.seek(0)

        new_pdf = PdfFileReader(packet)

        # read existing PDF
        existing_pdf = PdfFileReader(open("letters-test.pdf", "rb"))

        # add the "watermark" (which is the new pdf) on the existing page

        page = existing_pdf.getPage(i)
        page.mergePage(new_pdf.getPage(0))
        output.addPage(page)

     # Clear page i from memory and re load.
     # pdf = pdfquery.PDFQuery("letters-test.pdf")


outputStream = open("newpdf.pdf", "wb")
output.write(outputStream)
outputStream.close()

And here is letters-test.pdf

Upvotes: 7

Views: 1498

Answers (2)

georgexsh
georgexsh

Reputation: 16624

as Kamil Nicki's answer pointed out, Ean8BarcodeWidget limiting effective digits to 7:

class Ean8BarcodeWidget(Ean13BarcodeWidget):
    _digits=7
...
self.value=max(self._digits-len(value),0)*'0'+value[:self._digits]

you may change your encoding scheme or use EAN 13 barcode with Ean13BarcodeWidget, which has 12 digits usable.

Upvotes: 3

Kamil Niski
Kamil Niski

Reputation: 4765

The reason why your barcode is not changing is that you provided too long integer into eanbc.Ean8BarcodeWidget.

According to EAN standard EAN-8 barcodes are 8 digits long (7 digits + checkdigit)

Solution:

If you change barcode_value from 12345670 to 1234560 and run your script you will see that barcode value is increased as you want and checkdigit is appended as eighth number.

With that information in hand you should use only 7 digits to encode information in barcode.

Upvotes: 2

Related Questions