Using reportlab in Python to create Form fields with mulitilines and line breaks

82 Views Asked by At

i am Stuck and i hope that someone here can help me :)

i am writeing a python code that creates a pdf with form fields using reportlab.

every thing is working as expected Screenshot of pdf form

but there is a issue. my multiline fields are not showing the text on multible lines when i press the field i can see all the text.

Screenshot of field when pressed

if i make a change to the field all the text remains and displays correctly

Screenshot of form after text change

I really dont understand why? do any of you have a solution ? i have pasted some of my code below.

def insert_line_breaks(text, max_chars):
    words = text.split()
    processed_text = ""
    current_line = ""

    for word in words:
        if len(current_line) + len(word) <= max_chars:
            current_line += word + " "
        else:
            if current_line:
                # Add the current line to the processed text with the correct newline character
                processed_text += current_line.rstrip() + "\n"
            current_line = word + " "  # Start a new line with the current word

    # Add the last line if it's not empty
    if current_line:
        processed_text += current_line

    return processed_text
def create_pdf_with_form_fields_from_json(json_data_path):
    try:
        # Read and parse the JSON data
        with open(json_data_path, 'r') as file:
            form_fields = json.load(file)

        # Function to draw images on the page
        def draw_images(image_paths_list, start_height, page_width):
            print("Drawing images...")
            margin = 0.5 * inch
            lower_pictures_by = 1.2 * inch
            reduce_box_height_by = 0.48 * inch
            box_size = (page_width - 3 * margin) / 2
            box_height = box_size - reduce_box_height_by
            x_start = margin
            y_start = start_height - lower_pictures_by - box_height
            gap_between_boxes = 0.25 * inch

            for i, path in enumerate(image_paths_list):
                if i >= 4:  # Limit to 4 images
                    break

                x_position = x_start + (i % 2) * (box_size + gap_between_boxes)
                y_position = y_start - (i // 2) * (box_height + gap_between_boxes)
                c.setStrokeColor(colors.lightgrey)
                c.rect(x_position, y_position, box_size, box_height)
                c.drawImage(path, x_position, y_position, width=box_size, height=box_height, preserveAspectRatio=True, mask='auto')
            print("Images drawn.")

        # Sanitize kunde_entry to remove special characters
        kunde_name = re.sub(r'[^A-Za-z0-9 ]+', '', kunde_entry.get())

        # Extracting Kundenummer and Leveringsadresse
        kunde_info = kunde_entry.get().split(',')
        if len(kunde_info) >= 2:
            kundenummer = kunde_info[0].strip()  # Kundenummer
            kundenavn = kunde_info[1].strip()    # Kundenavn
        else:
            messagebox.showerror("Error", "Invalid Kundenummer and name format.")
            return
        print("Starting PDF generation...")

        leveringsadresse = leveringsadresse_entry.get().strip()

        # Constructing the PDF file name
        base_filename = f"{kundenummer}_{leveringsadresse}"
        # Slice the filename to ensure it does not exceed 30 characters
        sliced_filename = base_filename[:30] if len(base_filename) > 30 else base_filename
        pdf_filename = f"F://1. NYT FÆLLES SCANPIPE//ScanPipe_Logistik//Leveringsbeskrivelser//{sliced_filename}.pdf"

        # Set up the canvas
        c = canvas.Canvas(pdf_filename, pagesize=letter)
        page_width, page_height = letter

       # Process text with automatic line breaks
        max_line_length = 80  # Adjust this number based on your PDF layout
        leveringsbeskrivelse = insert_line_breaks(leveringsbeskrivelse_entry.get("1.0", "end-1c"), max_line_length)
        srv_leveringsbeskrivelse = insert_line_breaks(srv_leveringsbeskrivelse_entry.get("1.0", "end-1c"), max_line_length)
        alarm = insert_line_breaks(alarm_entry.get("1.0", "end-1c"), max_line_length)

        print("Generating PDF for:", kundenummer, kundenavn)

        # Initialize the current page
        current_page = 1

        formfieldsheigth = 600
        draw_images(image_paths, formfieldsheigth, page_width)

        # Add form fields and text boxes based on JSON data
        for field in form_fields:
            field_name = field.get('title', 'Untitled')  # Default to 'Untitled' if title is not present
            field_content = field.get('content', '')  # Default to empty string if content is not present
            x, y, width, height = field['x0'], field['y0'], field['width'], field['height']
            subtype = field.get('Subtype', 'Formfield')  # Default to 'Formfield' if Subtype is not present
            field_page = field.get('page')

            if field_name in ["Kundenavn og nummer", "Kundenavn og nummer_SVR"]:
                field_content = kunde_name
            elif field_name in ["By", "By_SVR"]:
                field_content = by_entry.get()
            elif field_name in ["Leveringsadresse", "Leveringsadresse_SVR"]:
                field_content = leveringsadresse
            elif field_name in ["Postnummer", "Postnummer_SVR"]:
                field_content = postnr_entry.get()
            elif field_name in ["Kontaktperson", "Kontaktperson_SVR"]:
                field_content = kontaktperson_entry.get()
            elif field_name in ["Tlf", "Tlf_SVR"]:
                field_content = telefon_entry.get()
            elif field_name in ["Alarm", "Alarm_SVR"]:
                field_content = alarm
            elif field_name == "Leveringsbeskrivelse":
                field_content = leveringsbeskrivelse
            elif field_name == "Leveringsbeskrivelse_SVR":
                field_content = srv_leveringsbeskrivelse

            # Check if the field's page is different from the current page
            if field_page != current_page:
                # Add a new page and update current_page
                c.showPage()
                current_page = field['page']

            if subtype == 'Formfield':
                # Create a form field
                c.acroForm.textfield(name=field_name, tooltip=field_name,
                                     x=x, y=y, width=width, height=height, 
                                     borderColor=colors.black, fillColor=colors.white,
                                     textColor=colors.black, forceBorder=True, maxlen=500,
                                     fieldFlags='multiline', value=field_content)
                
            elif subtype == 'Textbox':
                # Set the fill color to pale yellow and the stroke color to black
                c.setFillColor(colors.cornflower)
                c.setStrokeColor(colors.black)

                # Draw a rectangle with a black border and filled with pale yellow
                c.rect(x, y, width, height, stroke=1, fill=1)

                # Set the text color to black
                c.setFillColorRGB(0, 0, 0)

                # Draw the text inside the box
                c.drawString(x + 2, y + height / 2, field_content)  # Adjusted x to account for the border


        draw_images(srv_image_paths, formfieldsheigth, page_width)

        # Finalize PDF
        c.save()
        print("PDF generated successfully:", pdf_filename)
    except Exception as e:
        print("An error occurred while generating the PDF:", e)

i have tried to write a script that open the pdf after creation and then make a change to the field (add a .). but that dident work...

Edit!!

i found a solution. if i open the pdf after i have saved it using pdfrw and useing this code:

def update_pdf_need_appearances_flag(pdf_path):
try:
    pdf = pdfrw.PdfReader(pdf_path)
    if "/AcroForm" in pdf.Root:
        pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
    else:
        print("No AcroForm found in PDF. This PDF might not contain form fields.")

    pdfrw.PdfWriter().write(pdf_path, pdf)
    print("Updated NeedAppearances flag in PDF:", pdf_path)
except Exception as e:
    print("An error occurred while updating the PDF:", e)

The fields are updated and display the text correctly

1

There are 1 best solutions below

0
Jeppe Silas Nygaard On

i found a solution. if i open the pdf after i have saved it using pdfrw and useing this code:

def update_pdf_need_appearances_flag(pdf_path):
try:
    pdf = pdfrw.PdfReader(pdf_path)
    if "/AcroForm" in pdf.Root:
        pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
    else:
        print("No AcroForm found in PDF. This PDF might not contain form fields.")

    pdfrw.PdfWriter().write(pdf_path, pdf)
    print("Updated NeedAppearances flag in PDF:", pdf_path)
except Exception as e:
    print("An error occurred while updating the PDF:", e)

The fields are updated and display the text correctly