import os from io import BytesIO from reportlab.graphics.barcode import code128 from reportlab.lib.pagesizes import mm from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak from constants import APP_PATH class PDFGenerator: def __init__(self): ASSETS_FOLDER = os.path.join(APP_PATH, 'assets') FONTS_FOLDER = os.path.join(ASSETS_FOLDER, 'fonts') FONT_FILE_PATH = os.path.join(FONTS_FOLDER, 'DejaVuSans.ttf') self.page_width = 58 * mm self.page_height = 40 * mm pdfmetrics.registerFont(TTFont('DejaVuSans', FONT_FILE_PATH)) # Get standard styles and create a new style with a smaller font size styles = getSampleStyleSheet() self.small_style = ParagraphStyle( 'Small', parent=styles['Normal'], fontName='DejaVuSans', # Specify the new font fontSize=6, leading=7, spaceAfter=2, leftIndent=2, rightIndent=2 ) def generate_small_text(self, barcode_value, text, num_duplicates=1): buffer = BytesIO() # Create document with specified page size doc = SimpleDocTemplate(buffer, pagesize=(self.page_width, self.page_height), rightMargin=1 * mm, leftMargin=1 * mm, topMargin=1 * mm, bottomMargin=1 * mm) # Create paragraph with new style paragraph = Paragraph(text, self.small_style) # Get the width and height of the paragraph paragraph_width, paragraph_height = paragraph.wrap(self.page_width - 2 * mm, self.page_height) # Create barcode barcode_height = (self.page_height - paragraph_height * mm) available_width = self.page_width - 2 * mm # Adjust for margins # Approximate number of elements in a Code 128 barcode for average length num_elements = 11 * len(barcode_value) # Rough estimate: 11 elements per character # Calculate barWidth bar_width = available_width / num_elements barcode = code128.Code128(barcode_value, barWidth=bar_width, barHeight=barcode_height, humanReadable=True) # Function to draw barcode on canvas def add_barcode(canvas, doc): barcode_width = barcode.width barcode_x = (self.page_width - barcode_width) / 2 # Center the barcode barcode.drawOn(canvas, barcode_x, self.page_height - barcode.height - 5) # Create list of elements to add to the document elements = [] for _ in range(num_duplicates): elements.append(Spacer(1, barcode_height + 2 * mm)) elements.append(paragraph) elements.append(PageBreak()) # Build document doc.build(elements[:-1], onFirstPage=add_barcode, onLaterPages=add_barcode) # Remove the last PageBreak buffer.seek(0) return buffer def generate_large_text(self, barcode_value, text, num_duplicates=1): buffer = BytesIO() # Create document with specified page size doc = SimpleDocTemplate(buffer, pagesize=(self.page_width, self.page_height), rightMargin=1 * mm, leftMargin=1 * mm, topMargin=1 * mm, bottomMargin=1 * mm) # Create paragraph with new style paragraph = Paragraph(text, self.small_style) # Create barcode barcode = code128.Code128(barcode_value, humanReadable=True) # Function to draw barcode on canvas def add_barcode(canvas, doc): barcode_width = barcode.width barcode_x = (self.page_width - barcode_width) / 2 # Center the barcode barcode.drawOn(canvas, barcode_x, self.page_height - barcode.height - 5) # Create list of elements to add to the document elements = [] for _ in range(num_duplicates): elements.append(Spacer(1, 8 * mm)) elements.append(paragraph) elements.append(PageBreak()) # Build document doc.build(elements[:-1], onFirstPage=add_barcode, onLaterPages=add_barcode) # Remove the last PageBreak buffer.seek(0) return buffer def generate(self, barcode_value, text, num_duplicates=1): paragraph = Paragraph(text, self.small_style) # Get the width and height of the paragraph paragraph_width, paragraph_height = paragraph.wrap(self.page_width - 2 * mm, self.page_height) if paragraph_height > 30: return self.generate_large_text(barcode_value, text, num_duplicates) return self.generate_small_text(barcode_value, text, num_duplicates)