Implementation of preview book, by analogy of pillow.Image.show

This commit is contained in:
Oleskii Pyskun
2024-07-02 07:58:08 +03:00
parent c9540e868f
commit 5515fd3660
2 changed files with 104 additions and 1 deletions
+9 -1
View File
@@ -4,6 +4,7 @@ import json
import zipfile
from io import BytesIO
from pathlib import Path
from typing import Union
import xmltodict
@@ -12,6 +13,7 @@ from cbz import utils
from cbz.constants import xml_name
from cbz.models import ComicModel
from cbz.page import PageInfo
from cbz.ui import show_in_tk
class ComicInfo(ComicModel):
@@ -32,6 +34,13 @@ class ComicInfo(ComicModel):
def from_pages(cls, pages: [PageInfo], **kwargs) -> ComicInfo:
return cls(pages, **kwargs)
def show(self):
"""
display cbz for preview, after call open ui with info and pages and wait for close preview windows
:return:
"""
show_in_tk(self.title, self.__pages, utils.dumps(self._get()))
@classmethod
def from_cbz(cls, path: Union[Path, str]) -> ComicInfo:
"""
@@ -104,7 +113,6 @@ class ComicInfo(ComicModel):
xml_name,
xmltodict.unparse({'ComicInfo': self.dumps()}, pretty=True).encode('utf-8')
)
for i, page in enumerate(self.__pages):
zip_file.writestr(f'page-{i + 1:03d}{page.suffix}', page.content)
result = zip_buffer.getvalue()
+95
View File
@@ -0,0 +1,95 @@
from io import BytesIO
from tkinter import (Tk, Button, BOTTOM, TOP, PhotoImage, Scrollbar, X, Y, Canvas, HORIZONTAL, VERTICAL, YES, BOTH,
SUNKEN, RIGHT, LEFT, DISABLED, NORMAL, Label, Frame, ALL)
from PIL import ImageTk, Image
class ScrolledCanvas(Frame):
image_cursor: int = -2
info_text: str = ""
pages = list()
next_btn = None
prev_btn = None
counter = None
image: PhotoImage
def __init__(self, parent=None):
Frame.__init__(self, parent)
self.master.title("Spectrogram Viewer")
self.pack(expand=YES, fill=BOTH)
self.canvas = Canvas(self, relief=SUNKEN)
self.canvas.config(width=400, height=200)
self.canvas.config(highlightthickness=0)
s_bar_v = Scrollbar(self, orient=VERTICAL)
s_bar_h = Scrollbar(self, orient=HORIZONTAL)
s_bar_v.config(command=self.canvas.yview)
s_bar_h.config(command=self.canvas.xview)
self.canvas.config(yscrollcommand=s_bar_v.set)
self.canvas.config(xscrollcommand=s_bar_h.set)
s_bar_v.pack(side=RIGHT, fill=Y)
s_bar_h.pack(side=BOTTOM, fill=X)
self.canvas.pack(side=LEFT, expand=YES, fill=BOTH)
def set_text(self) -> None:
self.canvas.delete('image')
self.canvas.create_text(0, 0, anchor="nw", text=self.info_text, tags="image")
self.canvas.config(scrollregion=self.canvas.bbox(ALL))
def set_image(self, content: bytes) -> None:
self.canvas.delete('image')
with BytesIO(content) as f:
with Image.open(f) as image:
self.image = ImageTk.PhotoImage(image)
self.canvas.create_image(0, 0, anchor="nw", image=self.image, tags='image')
self.canvas.config(scrollregion=self.canvas.bbox(ALL))
def show_image(self, n: int) -> None:
self.image_cursor += n
if self.image_cursor == -1:
self.set_text()
self.prev_btn.config(state=DISABLED)
self.next_btn.config(state=NORMAL if self.pages else DISABLED)
elif self.image_cursor >= 0:
self.set_image(self.pages[self.image_cursor].content)
if self.image_cursor == len(self.pages) - 1:
self.next_btn.config(state=DISABLED)
self.prev_btn.config(state=NORMAL)
else:
self.prev_btn.config(state=NORMAL)
self.next_btn.config(state=NORMAL)
self.counter.config(text=f"{self.image_cursor + 1}/{len(self.pages)}")
self.canvas.yview_moveto(0)
self.canvas.xview_moveto(0)
def show_in_tk(title, pages, info):
root = Tk()
root.geometry("700x700")
frame = ScrolledCanvas(root)
frame.info_text = "\n".join([f"{key}: {value}" for key, value in info.items()])
frame.pages = pages
frame.pack(side=TOP)
button_frame = Frame(root)
button_next = Button(button_frame, text="Next", command=lambda: frame.show_image(1))
button_exit = Button(button_frame, text="Exit", command=root.quit)
counter = Label(button_frame)
button_prev = Button(button_frame, text="Previous", command=lambda: frame.show_image(-1))
counter.grid(row=0, column=1)
button_exit.grid(row=0, column=2)
button_next.grid(row=0, column=3)
button_prev.grid(row=0, column=0)
frame.next_btn = button_next
frame.prev_btn = button_prev
frame.counter = counter
button_frame.pack(side=BOTTOM)
root.bind('<Left>', lambda x: frame.show_image(-1) if button_prev["state"] == NORMAL else True)
root.bind('<Right>', lambda x: frame.show_image(1) if button_next["state"] == NORMAL else True)
root.bind('<Escape>', lambda x: root.quit())
frame.show_image(1)
root.title(title)
root.mainloop()