Reportlab 元素未放置在框架中

问题描述 投票:0回答:1

我正在创建一个脚本,该脚本创建一个 PDF,其中包含从 json 中的值创建的值和二维码,以及一些供人们捕获工作完成情况的额外元素。我在使元素在每个相应框架内正确对齐方面遇到问题,并且已经尝试了多种不同的变体和操作顺序,包括使用 ChatGPT 来获取有关如何解决此问题的想法。

这是我当前的代码(在一次仅处理 1 或 2 个元素时,我确实注释掉了一些内容。

import pandas as pd
import argparse
import qrcode
from qrcode.exceptions import DataOverflowError
from reportlab.lib.pagesizes import letter, landscape
from reportlab.platypus import SimpleDocTemplate, PageTemplate, Frame, Image, Table, Paragraph
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from reportlab.platypus.flowables import Flowable
from reportlab.lib.units import inch
from io import BytesIO
from tqdm import tqdm  # Import tqdm for progress bar
from PyPDF2 import PdfWriter, PdfReader


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', help='input file path', required=True)
    parser.add_argument('--StoreId', help='output PDF file path', required=True)
    args = parser.parse_args()
    return args

def Create_Dataframe():
    args = parse_args()
    df = pd.read_json(args.input)
    entityId = df['entityId']
    row = entityId.str.split('.').str[0]
    rack = entityId.str.split('.').str[1]
    row_num = row.str.split('row').str[1]
    rack_num = rack.str.split('rack|case|table|display|endcap|bin|dispenser').str[1]
    rack_label = row_num + '.' + rack_num
    df = pd.DataFrame({'row/rack': rack_label, 'barcode': entityId})
    return df

def create_qr_code(barcode):
    try:
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data(barcode)
        qr.make(fit=True)
        img = qr.make_image(fill_color="black", back_color="white")
        img_buffer = BytesIO()
        img.save(img_buffer)
        return img_buffer

    except DataOverflowError as e:
        print(f"QR code data is too large: {e}")
    except Exception as e:
        print(f"Error generating QR code: {e}")
        return None

class EmptySquare(Flowable):
    def __init__(self, width, height, border_color=colors.black, fill_color=colors.white, border_width=1):
        self.width = width
        self.height = height
        self.border_color = border_color
        self.border_width = border_width
        self.fill_color = fill_color

    def draw(self):
        self.canv.setFillColor(self.fill_color)
        self.canv.setStrokeColor(self.border_color)
        self.canv.setLineWidth(self.border_width)
        self.canv.rect(0, 0, self.width, self.height, stroke=1, fill=1)

# Define the EmptySquare instances and text
styles = getSampleStyleSheet()
style = styles['Normal']
empty_square1 = EmptySquare(60, 60, border_color=colors.black)
text1 = Paragraph('<font size=48>Calibrated</font>', style)
empty_square2 = EmptySquare(60, 60, border_color=colors.black)
text2 = Paragraph('<font size=48>LCV</font>', style)

def create_pdf(df, output_name):
    try:
        total = len(df['barcode'])

        pdf_writer = PdfWriter()

        with tqdm(total=total) as pbar:
            for barcode, row_rack in zip(df['barcode'], df['row/rack']):
                img_buffer = create_qr_code(barcode)
                if img_buffer:
                    doc = SimpleDocTemplate("temp.pdf", pagesize=landscape(letter))

                    # Create frames for each element
                    # row_rack_frame = Frame(
                    #     x1=30, 
                    #     y1=300, 
                    #     width=730,
                    #     height=280,
                    #     showBoundary=1,
                    #     id='row_rack_frame'
                    # )
                    # qr_frame = Frame(
                    #     x1=0,
                    #     y1=-100,
                    #     width=155,
                    #     height=155,
                    #     showBoundary=1,
                    #     id='qr_frame'
                    # )
                    row_rack_frame = Frame(
                        inch/2,
                        inch*4.5,
                        inch*10,
                        inch*3.75,
                        bottomPadding=inch,
                        topPadding=0,
                        showBoundary=1,
                        id='row_rack_frame'
                    )
                    qr_frame = Frame(
                        inch*4.5,
                        inch*1.75,
                        inch*2.5,
                        inch*2.5,
                        showBoundary=1,
                        id='qr_frame'
                    )
                    # calibrate_frame = Frame(
                    #     x1=0,
                    #     y1=0,
                    #     width=250,
                    #     height=80,
                    #     showBoundary=1,
                    #     id='calibrate_frame'
                    # )
                
                    # lcv_frame = Frame(
                    #     x1=0,
                    #     y1=0,
                    #     width=250,
                    #     height=80,
                    #     showBoundary=1,
                    #     id='lcv_frame'
                    # )
                    

                    # Add Frames and Create Template
                    page_template = PageTemplate(id='page', frames=[row_rack_frame,qr_frame])
                    doc.addPageTemplates([page_template])

                    story = []

                    # Add "row/rack" text to row_rack_frame
                    #row_rack_html = '<para><font size=280>{}</font></para>'.format(row_rack)
                    row_rack_style = ParagraphStyle(name='row_rack', alignment=1, leading=50, fontSize=280, spaceAfter=50, spaceBefore=0)
                    row_rack_paragraph = Paragraph(row_rack, style=row_rack_style)

                    
                    # Set QR Code
                    img = Image(img_buffer, width=150, height=150)

                    # Create table for calibrate text and square
                    cal_data = [
                        [text1, empty_square1]
                    ]
                    
                    # Create a table for lcv text and square
                    lcv_data = [
                        [text2, empty_square2]
                    ]


                    # Set Calibrate Table size
                    cal_table = Table(cal_data, colWidths=[250, 60], rowHeights=[60], vAlign=2)

                    # Set LCV Table size
                    lcv_table = Table(lcv_data, colWidths=[150, 60], rowHeights=[60], vAlign=2)

                    # Append data to frames
                    story.append(row_rack_paragraph)
                    story.append(img)
                    story.append(cal_table)
                    story.append(lcv_table)
                    

                    doc.build(story)
                    pdf_writer.add_page(PdfReader(open("temp.pdf", "rb")).pages[0])

                pbar.update(1)

        # Write the merged PDF
        pdf_writer.write(open(output_name, "wb"))

        print(f'PDF file "{output_name}" created successfully.')

    except Exception as e:
        print(f"Error creating the PDF: {str(e)}")

def main():
    args = parse_args()
    df = Create_Dataframe()
    output_name = args.StoreId + '.pdf'  # Use StoreId as the output file name
    create_pdf(df, output_name)


if __name__ == '__main__':
    main()

拉取的 json 输入如下所示

"entityId":"row1.rack1.fv"
段落文字为排/架分割版,二维码为完整版

这就是当前输出的样子

这就是我想要的样子(现在用的是二维码而不是条形码,颜色并不重要)

我还遇到了放置在 cal_table 和 lcv_table 中的“empty_sqaure”的问题,它没有与文本垂直对齐。

任何可以提供的帮助将不胜感激!

python reportlab
1个回答
0
投票

尝试在图像前添加带有负值的间隔符,例如:

story.append(Spacer(0,-50))
story.append(img)
story.append(cal_table)
© www.soinside.com 2019 - 2024. All rights reserved.