尝试渲染两个 PDF 文件时遇到的问题

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

我正在尝试编写一个程序,该程序将包含两个文件:试卷和答卷。这两个文件应该在同一个窗口中渲染,并且有一个可以使用的垂直滚动条。

下面是我的代码:

import tkinter as tk
from tkinter import filedialog
from tkinter import ttk
from tkinter import *
from PIL import Image, ImageTk
import os
from pdf2image import convert_from_path

class PDFViewerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF Question Cropper")

        self.frame = ttk.Frame(self.root)
        self.frame.pack(fill="both", expand=True)

        self.question_file = None
        self.answer_file = None

        self.question_label = ttk.Label(self.frame, text="No question file selected.")
        self.question_label.pack()

        self.select_question_button = ttk.Button(self.frame, text="Select Question PDF", command=self.select_question_pdf)
        self.select_question_button.pack()

        self.answer_label = ttk.Label(self.frame, text="No answer file selected.")
        self.answer_label.pack()

        self.select_answer_button = ttk.Button(self.frame, text="Select Answer PDF", command=self.select_answer_pdf)
        self.select_answer_button.pack()

        self.confirm_button = ttk.Button(self.frame, text="Confirm and Process", command=self.process_pdfs)
        self.confirm_button.pack()

        self.new_window = None
        self.pdf_canvas1 = None
        self.pdf_canvas2 = None

    def select_question_pdf(self):
        self.question_file = filedialog.askopenfilename(title="Select Question PDF")
        if self.question_file:
            self.question_label.config(text=f"Question PDF: {os.path.basename(self.question_file)}")

    def select_answer_pdf(self):
        self.answer_file = filedialog.askopenfilename(title="Select Answer PDF")
        if self.answer_file:
            self.answer_label.config(text=f"Answer PDF: {os.path.basename(self.answer_file)}")

    def process_pdfs(self):
        if not self.question_file or not self.answer_file:
            return
        self.open_new_window()

    def open_new_window(self):
        self.new_window = tk.Toplevel(self.root)
        self.new_window.title("Question Cropper")

        self.pdf_viewer_frame = ttk.Frame(self.new_window)
        self.pdf_viewer_frame.pack(fill=tk.BOTH, expand=True)

        self.pdf_canvas1 = tk.Canvas(self.pdf_viewer_frame, xscrollincrement=1)
        self.pdf_canvas2 = tk.Canvas(self.pdf_viewer_frame, xscrollincrement=1)

        self.scrollbar1 = ttk.Scrollbar(self.pdf_viewer_frame, orient="vertical", command=self.pdf_canvas1.yview)
        self.scrollbar2 = ttk.Scrollbar(self.pdf_viewer_frame, orient="vertical", command=self.pdf_canvas2.yview)

        self.scrollbar1.pack(side="right", fill="y")
        self.scrollbar2.pack(side="right", fill="y")

        self.pdf_canvas1.config(yscrollcommand=self.scrollbar1.set)
        self.pdf_canvas2.config(yscrollcommand=self.scrollbar2.set)

        self.pdf_canvas1.pack(side="left", fill="both", expand=True)
        self.pdf_canvas2.pack(side="right", fill="both", expand=True)

        self.file_label = ttk.Label(self.new_window, text="Processing...")
        self.file_label.pack()

        self.display_pdfs()

    def display_pdfs(self):
        if self.question_file and self.answer_file:
            question_pages = convert_from_path(self.question_file)
            answer_pages = convert_from_path(self.answer_file)

            if question_pages and answer_pages:
                max_width = max(page.width for page in question_pages + answer_pages)
                max_height = max(page.height for page in question_pages + answer_pages)

                for page in range(min(len(question_pages), len(answer_pages))):
                    img1 = question_pages[page]
                    img2 = answer_pages[page]

                    img1_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
                    img2_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))

                    img1_blank.paste(img1, (0, 0))
                    img2_blank.paste(img2, (0, 0))

                    photo1 = ImageTk.PhotoImage(master=self.new_window, image=img1_blank)
                    photo2 = ImageTk.PhotoImage(master=self.new_window, image=img2_blank)

                    canvas_width = max_width
                    canvas_height = max_height

                    self.pdf_canvas1.config(scrollregion=(0, 0, canvas_width, canvas_height), width=canvas_width, height=canvas_height)
                    self.pdf_canvas2.config(scrollregion=(0, 0, canvas_width, canvas_height), width=canvas_width, height=canvas_height)

                    self.pdf_canvas1.create_image(0, 0, image=photo1, anchor=tk.NW)
                    self.pdf_canvas2.create_image(0, 0, image=photo2, anchor=tk.NW)

                    self.pdf_canvas1.photo = photo1
                    self.pdf_canvas2.photo = photo2

                    self.file_label.config(text=f"Question File: {os.path.basename(self.question_file)}\nAnswer File: {os.path.basename(self.answer_file)} - Page {page + 1}")

if __name__ == "__main__":
    root = tk.Tk()
    app = PDFViewerApp(root)
    root.mainloop()

如果有人能提供帮助,那就太好了。

目前我面临三个主要问题:

  1. 这两个文件在窗口中占用的空间量不同;位于左侧的试卷显得更大。

  2. 两个滚动条被挤压到右侧,而不是位于每个显示文件的相对右侧。

  3. 这两个文件无法完全渲染。在我对当前文件的测试中,似乎只显示第三页。

python tkinter pdf-generation rendering
1个回答
0
投票

对于问题#1,我无法重现该问题,因为您已经使用相同尺寸的空白图像来显示 PDF 页面图像:

img1_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
img2_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))

对于问题#2,您需要按正确的顺序打包画布和滚动条:

self.pdf_canvas1.pack(side="left", fill="both", expand=True)
self.scrollbar1.pack(side="left", fill="y")
self.pdf_canvas2.pack(side="left", fill="both", expand=True)
self.scrollbar2.pack(side="left", fill="y")

对于问题 #3,您使用了相同的一组变量来存储图像引用并将图像放在相同的位置 (0, 0),因此只会显示两个 PDF 文件的最后一个图像。您需要使用两个列表来存储两个 PDF 文件中的图像并将它们放在正确的位置。另外,将图像放入画布后,您还需要更新两个画布的

scrollregion
选项:

def display_pdfs(self):
    if self.question_file and self.answer_file:
        question_pages = convert_from_path(self.question_file)
        answer_pages = convert_from_path(self.answer_file)

        if question_pages and answer_pages:
            max_width = max(page.width for page in question_pages + answer_pages)
            max_height = max(page.height for page in question_pages + answer_pages)

            # offset y for showing page images
            dy = max_height + 5
            # set the size of the canvases
            self.pdf_canvas1.config(width=max_width, height=max_height)
            self.pdf_canvas2.config(width=max_width, height=max_height)

            # lists to store the page images
            self.pdf_canvas1.imagelist = []
            self.pdf_canvas2.imagelist = []

            for page in range(min(len(question_pages), len(answer_pages))):
                img1 = question_pages[page]
                img2 = answer_pages[page]

                img1_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
                img2_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))

                img1_blank.paste(img1, (0, 0))
                img2_blank.paste(img2, (0, 0))

                photo1 = ImageTk.PhotoImage(master=self.new_window, image=img1_blank)
                photo2 = ImageTk.PhotoImage(master=self.new_window, image=img2_blank)

                # calculate correct y position of current page image
                self.pdf_canvas1.create_image(0, page*dy, image=photo1, anchor=tk.NW)
                self.pdf_canvas2.create_image(0, page*dy, image=photo2, anchor=tk.NW)

                # save the references of the page images
                self.pdf_canvas1.imagelist.append(photo1)
                self.pdf_canvas2.imagelist.append(photo2)

            self.file_label.config(text=f"Question File: {os.path.basename(self.question_file)}\nAnswer File: {os.path.basename(self.answer_file)} - Page {page + 1}")

            # update scrollregion option of the two canvases
            self.pdf_canvas1.config(scrollregion=self.pdf_canvas1.bbox("all"))
            self.pdf_canvas2.config(scrollregion=self.pdf_canvas2.bbox("all"))
© www.soinside.com 2019 - 2024. All rights reserved.