Search code examples
pythondjangobarcodereportlab

Apply alignments on Reportlab SimpleDocTemplate to append multiple barcodes in number of rows


I am using Reportlab SimpleDocTemplate to create a pdf file. I have to write (draw) multiple images row-wise so that I can adjust many images within the file.

class PrintBarCodes(View):

     def get(self, request, format=None):
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = 'attachment;\
        filename="barcodes.pdf"'

        # Close the PDF object cleanly, and we're done.
        ean = barcode.get('ean13', '123456789102', writer=ImageWriter())
        filename = ean.save('ean13')
        doc = SimpleDocTemplate(response, pagesize=A4)
        parts = []
        parts.append(Image(filename))
        doc.build(parts)
        return response

In the code, I have printed a single barcode to the file. And, the output is showing in the images as can be seen below.

But, I need to draw a number of barcodes. How to reduce the image size before drawing to the pdf file and adjust in row fashion?

enter image description here


Solution

  • As your question suggest that you need flexibility I think the most sensible approach is using Flowable's. The barcode normally isn't one but we can make it one pretty easily. By doing so we can let decide how much space there is in your layout for each barcode.

    So step one the Barcode Flowable which looks like this:

    from reportlab.graphics import renderPDF
    from reportlab.graphics.barcode.eanbc import Ean13BarcodeWidget
    from reportlab.graphics.shapes import Drawing
    from reportlab.platypus import Flowable
    
    class BarCode(Flowable):
        # Based on https://stackoverflow.com/questions/18569682/use-qrcodewidget-or-plotarea-with-platypus
        def __init__(self, value="1234567890", ratio=0.5):
            # init and store rendering value
            Flowable.__init__(self)
            self.value = value
            self.ratio = ratio
    
        def wrap(self, availWidth, availHeight):
            # Make the barcode fill the width while maintaining the ratio
            self.width = availWidth
            self.height = self.ratio * availWidth
            return self.width, self.height
    
        def draw(self):
            # Flowable canvas
            bar_code = Ean13BarcodeWidget(value=self.value)
            bounds = bar_code.getBounds()
            bar_width = bounds[2] - bounds[0]
            bar_height = bounds[3] - bounds[1]
            w = float(self.width)
            h = float(self.height)
            d = Drawing(w, h, transform=[w / bar_width, 0, 0, h / bar_height, 0, 0])
            d.add(bar_code)
            renderPDF.draw(d, self.canv, 0, 0)
    

    Then to answer your question, the easiest way to now put multiple barcodes on one page would be using a Table like so:

    from reportlab.platypus import SimpleDocTemplate, Table
    from reportlab.lib.pagesizes import A4
    
    doc = SimpleDocTemplate("test.pdf", pagesize=A4)
    
    table_data = [[BarCode(value='123'), BarCode(value='456')],
                  [BarCode(value='789'), BarCode(value='012')]]
    
    barcode_table = Table(table_data)
    
    parts = []
    parts.append(barcode_table)
    doc.build(parts)
    

    Which outputs:

    Example of barcode table