Как отображать файлы PDF из байтов с помощью tkinter

Я пытаюсь создать приложение для отображения файлов PDF внутри него. И, может быть, это было бы не так сложно сделать, но у меня есть несколько шагов:

  1. Создайте PDF-файл с помощью ReportLab (в этом нет ничего сложного).
  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")

# 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()

Но, может быть, мой выбор был неправильным, и «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 и показать его без сохранения на компьютере.

Вы не можете передать файловый объект в pdf_location опцию .pdf_view(). Вам нужно изменить tkPDFViewer, чтобы удовлетворить его. Также tkPDFViewer больше не совместим с последней версией PyMuPDF.

acw1668 09.01.2023 11:45

@ acw1668 acw1668, так что бы вы могли мне посоветовать использовать только для отображения PDF-файлов из памяти с помощью BytesIO?

Vitaliy 09.01.2023 12:52

Я бы посоветовал вам скопировать файл tkPDFViewer.py из модуля в каталог вашего проекта и удалить модуль. Затем исправьте проблему, отредактировав файл напрямую.

acw1668 09.01.2023 13:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Согласно ответу @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")

Я бы предложил заменить open_pdf = fitz.open(pdf_location) на open_pdf = fitz.open(filename=pdf_location) if type(pdf_location) is str else fitz.open(stream=pdf_location). Тогда вы все равно можете передать имя файла через аргумент pdf_location.

acw1668 10.01.2023 11:25

Другие вопросы по теме