class PDFMiner: def __init__(self, filepath): # creating the file path self.filepath = filepath # opening the pdf document self.pdf = fitz.open(self.filepath) # loading the first page of the pdf document self.first_page = self.pdf.load_page(0) # getting the height and width of the first page self.width, self.height = self.first_page.rect.width, self.first_page.rect.height # initializing the zoom values of the page zoomdict = {800: 1.0, 700: 1.1, 600: 1.2, 500: 1.3, 1500: 0.9} # getting the width value self.change_width = int(math.floor(self.width / 100.0) * 100) # zooming the page try: self.zoom = zoomdict[self.change_width] except Exception as e: text1.insert(ttk.END, "页面缩放比例获取失败,将同比例展示.... " + e.__str__() + "\n") text1.see(ttk.END) finally: self.zoom = 1 # this will get the metadata from the document like # author, name of document, number of pages def get_metadata(self): # getting metadata from the open PDF document metadata = self.pdf.metadata # getting number of pages from the open PDF document numPages = self.pdf.page_count # returning the metadata and the numPages return metadata, numPages # the function for getting the page def get_page(self, page_num): # loading the page page = self.pdf.load_page(page_num) # checking if zoom is True if self.zoom: # creating a Matrix whose zoom factor is self.zoom mat = fitz.Matrix(self.zoom, self.zoom) # gets the image of the page pix = page.get_pixmap(matrix=mat) # returns the image of the page else: pix = page.get_pixmap() # a variable that holds a transparent image px1 = fitz.Pixmap(pix, 0) if pix.alpha else pix # converting the image to bytes imgdata = px1.tobytes("ppm") # returning the image data return PhotoImage(data=imgdata) # function to get text from the current page def get_text(self, page_num): # loading the page page = self.pdf.load_page(page_num) # getting text from the loaded page text = page.getText('text') # returning text return text # creating a class called PDFViewer class PDFViewer: # initializing the __init__ / special method def __init__(self, master): # path for the pdf doc self.path = None # state of the pdf doc, open or closed self.fileisopen = None self.filekind = None # author of the pdf doc self.author = None # name for the pdf doc self.name = None # the current page for the pdf self.current_page = 0 # total number of pages for the pdf doc self.numPages = None self.canvas_image = None self.canvas_pdf = None # 图片的大小 self.img_width = None self.img_height = None # creating the window self.master = master # creating the top frame self.top_frame = Frame(self.master) # creating the bottom frame self.bottom_frame = Frame(self.top_frame) # creating the canvas for display the PDF pages self.output = ScrolledCanvas(self.top_frame, bg="white", highlightthickness=0, takefocus=1) self.output.frame.pack(expand=True, fill=BOTH, side=TOP) # loading the button icons self.page_frame = Frame(self.bottom_frame) self.uparrow_icon = PhotoImage(data=Arrow_Down_png) self.downarrow_icon = PhotoImage(data=Arrow_Down_png) # resizing the icons to fit on buttons self.uparrow = self.uparrow_icon.subsample(1, 1) self.downarrow = self.downarrow_icon.subsample(1, 1) # creating an up button with an icon self.upbutton = Button(self.page_frame,bd=0, bg="white", highlightthickness=0, image=self.uparrow, command=self.previous_page) self.upbutton.config(background="white", disabledforeground="white", foreground="white", activebackground="white") # adding the button self.upbutton.pack(anchor=CENTER, side=LEFT, padx=1, pady=5) # creating a down button with an icon self.downbutton = Button(self.page_frame, bg="white", highlightthickness=0, image=self.downarrow, command=self.next_page) self.downbutton.config(background="white", disabledforeground="white", foreground="white", activebackground="white") # adding the button self.downbutton.pack(anchor=CENTER, side=LEFT, padx=1, pady=5) # label for displaying page numbers self.page_label = Label(self.page_frame, text='page') # adding the label self.page_label.pack(anchor=CENTER, side=LEFT, padx=3, pady=5) self.page_frame.pack(expand=True, anchor=CENTER, side=LEFT, padx=3, pady=5) # loading the button icons self.zoom_frame = Frame(self.bottom_frame) self.zoomin_icon = PhotoImage(data=Zoom_In_png) self.zoomout_icon = PhotoImage(data=Zoom_Out_png) # resizing the icons to fit on buttons self.zoomin = self.zoomin_icon.subsample(1, 1) self.zoomout = self.zoomout_icon.subsample(1, 1) # creating an up button with an icon self.zoominbutton = Button(self.zoom_frame, bd=0, bg="white", highlightthickness=0, image=self.zoomin, command=self.zoomin_page) self.zoominbutton.config(background="white", disabledforeground="white", foreground="white", activebackground="white") # adding the button self.zoominbutton.pack(anchor=CENTER, side=LEFT, padx=3, pady=5) # creating a down button with an icon self.zoomoutbutton = Button(self.zoom_frame, bg="white", highlightthickness=0, image=self.zoomout, command=self.zoomout_page) self.zoomoutbutton.config(background="white", disabledforeground="white", foreground="white", activebackground="white") # adding the button self.zoomoutbutton.pack(anchor=CENTER, side=LEFT, padx=3, pady=5) # label for displaying page numbers self.zoom_label = Label(self.zoom_frame, text='Zoom') # adding the label self.zoom_label.pack(anchor=CENTER, side=LEFT, padx=3, pady=5) self.zoom_value = StringVar() # 45--200 每次 5 zooms = [zoom for zoom in range(45, 200, 5)] self.zoom_combobox = Combobox(self.zoom_frame, textvariable=self.zoom_value, width=6,state=READONLY, value=[(value).__str__() + "%" for value in zooms]) self.zoom_combobox.pack(anchor=CENTER, side=LEFT, padx=3, pady=5) self.zoom_value.set("100%") self.zoom_combobox.bind("<<ComboboxSelected>>", self.zoom_combobox_change) self.zoom_frame.pack(expand=True, anchor=CENTER, side=LEFT, padx=3, pady=5) # placing the frame using inside main window using grid() self.bottom_frame.pack(side=BOTTOM, fill=X) # placing the frame using inside main window using grid() self.top_frame.pack(side=TOP, fill=BOTH, expand=True) def zoom_combobox_change(self, event): if self.fileisopen and 'pdf' in self.filekind.mime.__str__(): # 更改缩略比例 self.miner.zoom = int(self.zoom_combobox.get()[:-2]) / 10 if self.miner.zoom <= 0.45 or self.miner.zoom >= 2: self.miner.zoom = 1 self.display_page() elif self.fileisopen and 'image' in self.filekind.mime.__str__(): # 更改缩略比例 zoom = int(self.zoom_combobox.get()[:-2]) / 10 if zoom <= 0.45 or zoom >= 2: zoom = 1 self.output.canvas.delete(self.canvas_image) self.output.canvas.img_avatar = ImageTk.PhotoImage( image=self.pil_avatar.resize((int(self.img_width * zoom), int(self.img_height * zoom)))) self.canvas_image = self.output.canvas.create_image(0, 0, anchor=NW, image=self.output.canvas.img_avatar) # function for opening pdf files def open_file(self, filepath): if filepath: # declaring the path self.path = filepath self.filekind = filetype.guess(self.path) # extracting the pdf file from the path filename = os.path.basename(self.path) if self.canvas_pdf: self.output.canvas.delete("all") if self.canvas_image: self.output.canvas.delete("all") self.output.canvas.update() if self.filekind: if('pdf' in self.filekind.mime.__str__()): # passing the path to PDFMiner self.miner = PDFMiner(self.path) # getting data and numPages data, numPages = self.miner.get_metadata() # setting the current page to 0 self.current_page = 0 # checking if numPages exists if numPages: # getting the title self.name = data.get('title', filename[:-4]) # getting the author self.author = data.get('author', None) self.numPages = numPages # setting fileopen to True self.fileisopen = True # calling the display_page() function self.display_page() # replacing the window title with the PDF document name self.zoom_value.set(int(self.miner.zoom * 100).__str__() + "%") elif 'image' in self.filekind.mime.__str__(): self.fileisopen = True # calling the display_page() function self.display_image(self.path) # replacing the window title with the PDF document name self.zoom_value.set("100%") def display_image(self, img_file): # checking if numPages is less than current_page and if current_page is less than self.pil_avatar = PILImage.open(img_file) # inserting the page image inside the Canvas self.img_width, self.img_height = self.pil_avatar.width, self.pil_avatar.height self.output.canvas.img_avatar = ImageTk.PhotoImage(image=self.pil_avatar.resize((self.img_width, self.img_height))) # self.output.canvas.itemconfig(main_image, self.output.canvas.img_avatar) self.canvas_image = self.output.canvas.create_image(0, 0, anchor=NW, image=self.output.canvas.img_avatar) # creating a region for inserting the page inside the Canvas region = self.output.canvas.bbox(ALL) # making the region to be scrollable self.output.canvas.configure(scrollregion=region) def zoomin_page(self): if self.fileisopen and 'pdf' in self.filekind.mime.__str__(): # checking if current_page is less than or equal to numPages-1 self.miner.zoom = self.miner.zoom - 0.05 if self.miner.zoom <= 0.45: self.miner.zoom = 0.45 self.zoom_value.set(int(self.miner.zoom * 100).__str__() + "%") self.display_page() elif self.fileisopen and 'image' in self.filekind.mime.__str__(): self.output.canvas.delete(self.canvas_image) zoom = int(self.zoom_value.get()[:-1]) / 100 zoom = zoom - 0.05 if zoom <= 0.45: zoom = 0.45 self.output.canvas.img_avatar = ImageTk.PhotoImage( image=self.pil_avatar.resize((int(self.img_width * zoom), int(self.img_height * zoom)))) self.canvas_image = self.output.canvas.create_image(0, 0, anchor=NW, image=self.output.canvas.img_avatar) self.zoom_value.set(int(zoom * 100).__str__() + "%") def zoomout_page(self): if self.fileisopen and 'pdf' in self.filekind.mime.__str__(): # checking if current_page is less than or equal to numPages-1 self.miner.zoom = self.miner.zoom + 0.05 if self.miner.zoom >= 2: self.miner.zoom = 2 self.zoom_value.set(int(self.miner.zoom * 100).__str__() + "%") self.display_page() elif self.fileisopen and 'image' in self.filekind.mime.__str__(): self.output.canvas.delete(self.canvas_image) zoom = int(self.zoom_value.get()[:-1]) / 100 zoom = zoom + 0.05 if zoom >= 2: zoom = 2 self.output.canvas.img_avatar = ImageTk.PhotoImage( image=self.pil_avatar.resize((int(self.img_width * zoom), int(self.img_height * zoom)))) self.canvas_image = self.output.canvas.create_image(0, 0, anchor=NW, image=self.output.canvas.img_avatar) self.zoom_value.set(int(zoom * 100).__str__() + "%") # the function to display the page def display_page(self): # checking if numPages is less than current_page and if current_page is less than # or equal to 0 if 0 <= self.current_page < self.numPages: # getting the page using get_page() function from miner self.img_file = self.miner.get_page(self.current_page) # inserting the page image inside the Canvas self.canvas_pdf = self.output.canvas.create_image(0, 0, anchor=CENTER, image=self.img_file) # the variable to be stringified self.stringified_current_page = self.current_page + 1 # updating the page label with number of pages self.page_label['text'] = str(self.stringified_current_page) + ' of ' + str(self.numPages) # creating a region for inserting the page inside the Canvas region = self.output.canvas.bbox(ALL) # making the region to be scrollable self.output.canvas.configure(scrollregion=region) # function for displaying next page def next_page(self): # checking if file is open if self.fileisopen and 'pdf' in self.filekind.mime.__str__(): # checking if current_page is less than or equal to numPages-1 if self.current_page <= self.numPages - 1: # updating the page with value 1 self.current_page += 1 # displaying the new page self.display_page() # function for displaying the previous page def previous_page(self): # checking if fileisopen if self.fileisopen and 'pdf' in self.filekind.mime.__str__(): # checking if current_page is greater than 0 if self.current_page > 0: # decrementing the current_page by 1 self.current_page -= 1 # displaying the previous page self.display_page() pdfview = PDFViewer(master=labFrame_canvas) labFrame_canvas.pack(fill=BOTH, expand=True, side=BOTTOM)
双击预览pdf
下一页
放大 缩小
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
· 全程使用 AI 从 0 到 1 写了个小工具