[Python] Python-docx: How to force a new page when adding tables with images?

Discussão em 'Python' iniciado por Stack, Março 11, 2025.

  1. Stack

    Stack Membro Participativo

    I'm generating a Word document using python-docx that contains images arranged in a table format. The document should:


    • Fit multiple images per page (e.g., 4x4 for word cards).


    • Ensure proper page breaks and margins when a new page starts.


    • Adjust margins slightly for even vs. odd pages (to align double-sided printing).


    • Insert images inside table cells, ensuring they are properly aligned.

    However, I'm facing an issue where:


    1. New sections (page breaks) don't always behave as expected—sometimes images get misaligned, or pages don't break where intended.


    2. Margins might not be applied correctly after inserting a new section.


    3. The layout shifts slightly when using create_section(doc, shift_x, shift_y), causing unintended spacing issues.

    Below is a simplified version of the key parts of my code:

    from docx import Document
    from docx.shared import Inches
    from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
    from docx.enum.table import WD_ALIGN_VERTICAL, WD_ROW_HEIGHT
    from docx.enum.section import WD_SECTION
    from pathlib import Path
    import tempfile
    import random
    from PIL import Image

    def create_doc():
    doc = Document()
    section = doc.sections[0]
    section.page_width = Inches(8.27) # A4 width
    section.page_height = Inches(11.69) # A4 height
    section.top_margin = Inches(0.5) # narrow margins
    section.bottom_margin = Inches(0.5)
    section.left_margin = Inches(0.5)
    section.right_margin = Inches(0.5)
    return doc

    def create_section(doc, shift_x=0, shift_y=0):
    """Creates a new section with optional margin shifts"""
    section = doc.add_section(WD_SECTION.NEW_PAGE)
    section.top_margin = int((0.5 - shift_y) * 1440)
    section.bottom_margin = int((0.5 + shift_y) * 1440)
    section.left_margin = int((0.5 + shift_x) * 1440)
    section.right_margin = int((0.5 - shift_x) * 1440)

    def insert_aligned_image(cell, img_path, width, height):
    """ Inserts an image into a table cell and aligns it """
    cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
    para = cell.paragraphs[0]
    run = para.add_run()
    run.add_picture(img_path, width=width, height=height)
    para.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

    def align_word_cards():
    CARD_WIDTH = Inches(1.617)
    CARD_HEIGHT = Inches(2.517)
    CARDS_PER_ROW = 4
    CARDS_PER_PAGE = 16 # 4x4 layout
    images = list(Path("./Cards").glob("*.png"))
    random.shuffle(images)
    doc = create_doc()
    temp_files = []

    for index, img_path in enumerate(images):
    if index % CARDS_PER_PAGE == 0 and index > 0:
    if (index // CARDS_PER_PAGE) % 2 == 1:
    create_section(doc, shift_x=Inches(0.11), shift_y=Inches(0.16))
    else:
    create_section(doc)

    table = doc.add_table(rows=4, cols=CARDS_PER_ROW)
    table.autofit = False
    for row in table.rows:
    row.height = CARD_HEIGHT
    row.height_rule = WD_ROW_HEIGHT.EXACTLY

    row = (index % CARDS_PER_PAGE) // CARDS_PER_ROW
    col = (index % CARDS_PER_PAGE) % CARDS_PER_ROW

    with Image.open(img_path) as img:
    img = img.rotate(90, expand=True).resize((485, 755), Image.LANCZOS)
    with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_img:
    img.save(temp_img, format="PNG")
    temp_files.append(temp_img.name)
    insert_aligned_image(table.cell(row, col), temp_img.name, CARD_WIDTH, CARD_HEIGHT)

    doc.save("output.docx")
    print("Word document created!")

    for temp_file in temp_files:
    Path(temp_file).unlink(missing_ok=True)
    print("Temporary files cleaned up.")

    align_word_cards()

    Questions:


    1. Is create_section(doc, shift_x, shift_y) correctly applying the margin shifts for even/odd pages?


    2. Could table.autofit = False or row.height_rule = WD_ROW_HEIGHT.EXACTLY be affecting the layout unexpectedly?


    3. Is there a better way to force a clean page break that ensures the next table starts on a new page without affecting margins?

    Any insights would be greatly appreciated!

    Continue reading...

Compartilhe esta Página