如何使用tkinter显示来自字节的PDF文件

huangapple go评论112阅读模式
英文:

How to display PDF files from bytes with tkinter

问题

我正在尝试创建一个应用程序,在其中显示PDF文件。也许制作起来不会太难,但我有一些步骤:

  1. 使用ReportLab创建PDF文件(这很容易)。
  2. 我不想将这个PDF文件保存在硬盘上,所以我将使用BytesIO进行内存存储。
  3. 我找到了一个名为“tkpdfviewer”的包,可以在我的应用程序内显示PDF文件。

我编写了一个简单的代码来展示我的问题。

from tkinter import *
from tkinter import ttk
import tkinter as tk
from io import BytesIO
from tkPDFViewer import tkPDFViewer as pdf
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import mm

main = tk.Tk()

main.title("PDF Viewer Main")

# 主窗口大小
app_height = 350
app_width = 350

# 屏幕尺寸
screen_width = main.winfo_screenwidth()
screen_height = main.winfo_screenheight()

# 左上角坐标
x = (screen_width - app_width) / 2
y = ((screen_height - app_height) - 50) / 2

# 应用参数应用到主窗口的geometry
main.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')

main.resizable(False, False)
main.configure(background="white")

def create_pdf():
    pdf_reader = Toplevel(main)
        
    pdf_reader.title("PDF Viewer")

    # 主窗口大小
    app_height = 700
    app_width = 900

    # 屏幕尺寸
    screen_width = pdf_reader.winfo_screenwidth()
    screen_height = pdf_reader.winfo_screenheight()

    # 左上角坐标
    x = (screen_width - app_width) / 2
    y = ((screen_height - app_height) - 50) / 2

    # 应用参数应用到主窗口的geometry
    pdf_reader.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')

    pdf_reader.resizable(False, False)
    pdf_reader.configure(background="white")
    
    buffer = BytesIO()
    
    c = canvas.Canvas(buffer, pagesize=landscape(A4), bottomup=0)
    c.drawString(400, 300, "Sample PDF file")
    c.save()
    
    buffer.seek(0)
    pdf_path = buffer.getvalue()
    
    # 创建ShowPdf对象来显示PDF文件
    v1 = pdf.ShowPdf()
    
    # 添加PDF位置、宽度和高度
    v2 = v1.pdf_view(pdf_reader, pdf_location=pdf_path, width=50, height=100, bar=True, load="before")
    
    # 将PDF添加到GUI中
    v2.pack()
    
    pdf_reader.mainloop()

create_btn = Button(main, text="Create PDF file", command=create_pdf)
create_btn.pack(pady=135)

main.mainloop()

但也许我的选择是错误的,"tkpdfviewer"不是一个好的选择,因为它不能从字节中显示PDF文件?我遇到了以下问题:

Exception in thread Thread-1 (add_img):
Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
    self.run()
  File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 975, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\site-packages\tkPDFViewer\tkPDFViewer.py", line 43, in add_img
    open_pdf = fitz.open(pdf_location)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\site-packages\fitz\fitz.py", line 3925, in __init__
    raise TypeError(msg)
TypeError: bad filename

"tkpdfviewer"正在运行,但没有显示任何内容。有人能帮我解决这个问题吗?我的想法是创建PDF文件并在不保存到计算机上的情况下显示它。

英文:

I'm trying to make an application to display PDF files inside it. And maybe it wouldn't be so hard to make, but I have a few steps:

  1. Create a PDF file with ReportLab (there is nothing hard to get).
  2. I don't want so save this pdf file on hard disk, so I will use memory storage with BytesIO.
  3. I've found "tkpdfviewer" like package that will show PDF files inside my application.

I wrote a simple code which will show my problem.

from tkinter import *
from tkinter import ttk
import tkinter as tk
from io import BytesIO
from tkPDFViewer import tkPDFViewer as pdf
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import mm
main = tk.Tk()
main.title("PDF Viewer Main")
# Main window sizes
app_height = 350
app_width = 350
# Define of screen sizes
screen_width = main.winfo_screenwidth()
screen_height = main.winfo_screenheight()
# Define of left corner coordinates 
x = (screen_width - app_width) / 2
y = ((screen_height - app_height)-50) / 2
# Applying defineded parameters to root.geometry
main.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')
main.resizable(False, False)
main.configure(background="white")
def create_pdf():
pdf_reader = Toplevel(main)
pdf_reader.title("PDF Viewer")
# Main window sizes
app_height = 700
app_width = 900
# Define of screen sizes
screen_width = pdf_reader.winfo_screenwidth()
screen_height = pdf_reader.winfo_screenheight()
# Define of left corner coordinates 
x = (screen_width - app_width) / 2
y = ((screen_height - app_height)-50) / 2
# Applying defineded parameters to root.geometry
pdf_reader.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')
pdf_reader.resizable(False, False)
pdf_reader.configure(background="white")
buffer = BytesIO()
c = canvas.Canvas(buffer, pagesize=landscape(A4), bottomup=0)
c.drawString(400,300,"Sample PDF file")
c.save()
buffer.seek(0)
pdf_path = buffer.getvalue()
#print(pdf_path)
# creating object of ShowPdf from tkPDFViewer.
v1 = pdf.ShowPdf()
# Adding pdf location and width and height.
v2 = v1.pdf_view(pdf_reader, pdf_location = pdf_path, width = 50, height = 100, bar=True, load="before")
# Placing Pdf in my gui.
v2.pack()
pdf_reader.mainloop()
create_btn = Button(main, text="Create PDF file", command=create_pdf)
create_btn.pack(pady=135)
main.mainloop()

But maybe my choice was wrong and "tkpdfviewer" is not a good variant to use, because it can't show PDF files from bytes? I have a following issue:

Exception in thread Thread-1 (add_img):
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
self.run()
File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\site-packages\tkPDFViewer\tkPDFViewer.py", line 43, in add_img
open_pdf = fitz.open(pdf_location)
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\site-packages\fitz\fitz.py", line 3925, in __init__
raise TypeError(msg)
TypeError: bad filename

"tkpdfviewer" is running, but didn't showing anything.

Could someone help me to solve it? My idea is to create PDF file and show it without saving on computer.

答案1

得分: 0

根据@acw1668的回答,我对主要的"tkpdfviewer"库进行了一些更改,现在它正常工作了!

代码中的一些更改:

这一行:

def pdf_view(self, master, width=1200, height=600, pdf_location="", bar=True, load="after"):

更改为:

def pdf_view(self, master, width=1200, height=600, mem_area="", bar=True, load="after"):

在函数中:

def add_img():

我更改了以下代码行:

precentage_dicide = 0
open_pdf = fitz.open(pdf_location)
for page in open_pdf:
pix = page.getPixmap()
pix1 = fitz.Pixmap(pix, 0) if pix.alpha else pix
img = pix1.getImageData("ppm")

更改为:

precentage_dicide = 0
open_pdf = fitz.open("pdf", mem_area)
for page in open_pdf:
pix = page.get_pixmap()
pix1 = fitz.Pixmap(pix, 0) if pix.alpha else pix
img = pix1.tobytes("ppm")
英文:

According to @acw1668 answer I made some changes with main "tkpdfviewer" library and now it works fine!

A few changes in code:

This line:

def pdf_view(self,master,width=1200,height=600,pdf_location="",bar=True,load="after"):

With this line:

def pdf_view(self,master,width=1200,height=600,mem_area="",bar=True,load="after"):

In function:

def add_img():

I have changed these lines of code:

precentage_dicide = 0
open_pdf = fitz.open(pdf_location)
for page in open_pdf:
pix = page.getPixmap()
pix1 = fitz.Pixmap(pix,0) if pix.alpha else pix
img = pix1.getImageData("ppm")

With this:

precentage_dicide = 0
open_pdf = fitz.open("pdf", mem_area)
for page in open_pdf:
pix = page.get_pixmap()
pix1 = fitz.Pixmap(pix,0) if pix.alpha else pix
img = pix1.tobytes("ppm")

huangapple
  • 本文由 发表于 2023年1月9日 17:25:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75055252.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定