Refactor Thumbrenderer (#168)

* Merge Render methods

* Cleanup comments

* Removed old render methods and replaced with new one

* Fix Formatting

- Change all instances of "os.path.normpath" to pathlib's "Path"
- Remove unused import
- Modify log formatting
- Change "self.tr" to "self.thumb_renderer" to avoid masking internal method
- Restore DecompressionBombError handling from main
- Misc. formatting

* Fix MyPy no-redef

---------

Co-authored-by: Travis Abendshien <lvnvtravis@gmail.com>
This commit is contained in:
Theasacraft
2024-05-19 01:56:45 +02:00
committed by GitHub
parent 02bf15e080
commit e94c4871d7
4 changed files with 167 additions and 360 deletions

View File

@@ -0,0 +1,50 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
from PIL import Image, ImageEnhance, ImageChops
def four_corner_gradient_background(image: Image.Image, adj_size, mask, hl):
if image.size != (adj_size, adj_size):
# Old 1 color method.
# bg_col = image.copy().resize((1, 1)).getpixel((0,0))
# bg = Image.new(mode='RGB',size=(adj_size,adj_size),color=bg_col)
# bg.thumbnail((1, 1))
# bg = bg.resize((adj_size,adj_size), resample=Image.Resampling.NEAREST)
# Small gradient background. Looks decent, and is only a one-liner.
# bg = image.copy().resize((2, 2), resample=Image.Resampling.BILINEAR).resize((adj_size,adj_size),resample=Image.Resampling.BILINEAR)
# Four-Corner Gradient Background.
# Not exactly a one-liner, but it's (subjectively) really cool.
tl = image.getpixel((0, 0))
tr = image.getpixel(((image.size[0] - 1), 0))
bl = image.getpixel((0, (image.size[1] - 1)))
br = image.getpixel(((image.size[0] - 1), (image.size[1] - 1)))
bg = Image.new(mode="RGB", size=(2, 2))
bg.paste(tl, (0, 0, 2, 2))
bg.paste(tr, (1, 0, 2, 2))
bg.paste(bl, (0, 1, 2, 2))
bg.paste(br, (1, 1, 2, 2))
bg = bg.resize((adj_size, adj_size), resample=Image.Resampling.BICUBIC)
bg.paste(
image,
box=(
(adj_size - image.size[0]) // 2,
(adj_size - image.size[1]) // 2,
),
)
bg.putalpha(mask)
final = bg
else:
image.putalpha(mask)
final = image
hl_soft = hl.copy()
hl_soft.putalpha(ImageEnhance.Brightness(hl.getchannel(3)).enhance(0.5))
final.paste(ImageChops.soft_light(final, hl_soft), mask=hl_soft.getchannel(3))
return final

View File

@@ -1174,7 +1174,7 @@ class QtDriver(QObject):
self.thumb_job_queue.put(
(
item_thumb.renderer.render,
(sys.float_info.max, "", base_size, ratio, True),
(sys.float_info.max, "", base_size, ratio, True, True),
)
)
# # Restore Selected Borders
@@ -1272,7 +1272,7 @@ class QtDriver(QObject):
self.thumb_job_queue.put(
(
item_thumb.renderer.render,
(time.time(), filepath, base_size, ratio, False),
(time.time(), filepath, base_size, ratio, False, True),
)
)
else:

View File

@@ -90,9 +90,11 @@ class PreviewPanel(QWidget):
self.preview_img.addAction(self.open_file_action)
self.preview_img.addAction(self.open_explorer_action)
self.tr = ThumbRenderer()
self.tr.updated.connect(lambda ts, i, s: (self.preview_img.setIcon(i)))
self.tr.updated_ratio.connect(
self.thumb_renderer = ThumbRenderer()
self.thumb_renderer.updated.connect(
lambda ts, i, s: (self.preview_img.setIcon(i))
)
self.thumb_renderer.updated_ratio.connect(
lambda ratio: (
self.set_image_ratio(ratio),
self.update_image_size(
@@ -380,7 +382,7 @@ class PreviewPanel(QWidget):
# if self.preview_img.iconSize().toTuple()[0] < self.preview_img.size().toTuple()[0] + 10:
# if type(self.item) == Entry:
# filepath = os.path.normpath(f'{self.lib.library_dir}/{self.item.path}/{self.item.filename}')
# self.tr.render_big(time.time(), filepath, self.preview_img.size().toTuple(), self.devicePixelRatio())
# self.thumb_renderer.render(time.time(), filepath, self.preview_img.size().toTuple(), self.devicePixelRatio(),update_on_ratio_change=True)
# logging.info(f' Img Aspect Ratio: {self.image_ratio}')
# logging.info(f' Max Button Size: {size}')
@@ -443,7 +445,14 @@ class PreviewPanel(QWidget):
self.preview_img.setCursor(Qt.CursorShape.ArrowCursor)
ratio: float = self.devicePixelRatio()
self.tr.render_big(time.time(), "", (512, 512), ratio, True)
self.thumb_renderer.render(
time.time(),
"",
(512, 512),
ratio,
True,
update_on_ratio_change=True,
)
try:
self.preview_img.clicked.disconnect()
except RuntimeError:
@@ -466,8 +475,14 @@ class PreviewPanel(QWidget):
)
self.file_label.setFilePath(filepath)
window_title = filepath
ratio = self.devicePixelRatio()
self.tr.render_big(time.time(), filepath, (512, 512), ratio)
ratio: float = self.devicePixelRatio()
self.thumb_renderer.render(
time.time(),
filepath,
(512, 512),
ratio,
update_on_ratio_change=True,
)
self.file_label.setText("\u200b".join(filepath))
self.file_label.setCursor(Qt.CursorShape.PointingHandCursor)
@@ -575,8 +590,15 @@ class PreviewPanel(QWidget):
)
self.preview_img.setCursor(Qt.CursorShape.ArrowCursor)
ratio = self.devicePixelRatio()
self.tr.render_big(time.time(), "", (512, 512), ratio, True)
ratio: float = self.devicePixelRatio()
self.thumb_renderer.render(
time.time(),
"",
(512, 512),
ratio,
True,
update_on_ratio_change=True,
)
try:
self.preview_img.clicked.disconnect()
except RuntimeError:
@@ -658,7 +680,7 @@ class PreviewPanel(QWidget):
# filepath = os.path.normpath(f'{self.lib.library_dir}/{item.path}/{item.filename}')
# window_title = filepath
# ratio: float = self.devicePixelRatio()
# self.tr.render_big(time.time(), filepath, (512, 512), ratio)
# self.thumb_renderer.render(time.time(), filepath, (512, 512), ratio,update_on_ratio_change=True)
# self.file_label.setText("\u200b".join(filepath))
# # TODO: Deal with this later.

View File

@@ -3,7 +3,6 @@
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
import ctypes
import logging
import math
import os
@@ -12,25 +11,24 @@ from pathlib import Path
import cv2
from PIL import (
Image,
ImageChops,
UnidentifiedImageError,
ImageQt,
ImageDraw,
ImageFont,
ImageEnhance,
ImageOps,
ImageFile,
)
from PIL.Image import DecompressionBombError
from PySide6.QtCore import QObject, Signal, QSize
from PySide6.QtGui import QPixmap
from src.qt.helpers.gradient import four_corner_gradient_background
from src.core.constants import PLAINTEXT_TYPES, VIDEO_TYPES, IMAGE_TYPES
ImageFile.LOAD_TRUNCATED_IMAGES = True
ERROR = f"[ERROR]"
WARNING = f"[WARNING]"
INFO = f"[INFO]"
ERROR = "[ERROR]"
WARNING = "[WARNING]"
INFO = "[INFO]"
logging.basicConfig(format="%(message)s", level=logging.INFO)
@@ -44,50 +42,40 @@ class ThumbRenderer(QObject):
# updatedSize = Signal(QSize)
thumb_mask_512: Image.Image = Image.open(
os.path.normpath(
f"{Path(__file__).parents[3]}/resources/qt/images/thumb_mask_512.png"
)
Path(f"{Path(__file__).parents[3]}/resources/qt/images/thumb_mask_512.png")
)
thumb_mask_512.load()
thumb_mask_hl_512: Image.Image = Image.open(
os.path.normpath(
f"{Path(__file__).parents[3]}/resources/qt/images/thumb_mask_hl_512.png"
)
Path(f"{Path(__file__).parents[3]}/resources/qt/images/thumb_mask_hl_512.png")
)
thumb_mask_hl_512.load()
thumb_loading_512: Image.Image = Image.open(
os.path.normpath(
f"{Path(__file__).parents[3]}/resources/qt/images/thumb_loading_512.png"
)
Path(f"{Path(__file__).parents[3]}/resources/qt/images/thumb_loading_512.png")
)
thumb_loading_512.load()
thumb_broken_512: Image.Image = Image.open(
os.path.normpath(
f"{Path(__file__).parents[3]}/resources/qt/images/thumb_broken_512.png"
)
Path(f"{Path(__file__).parents[3]}/resources/qt/images/thumb_broken_512.png")
)
thumb_broken_512.load()
thumb_file_default_512: Image.Image = Image.open(
os.path.normpath(
Path(
f"{Path(__file__).parents[3]}/resources/qt/images/thumb_file_default_512.png"
)
)
thumb_file_default_512.load()
# thumb_debug: Image.Image = Image.open(os.path.normpath(
# thumb_debug: Image.Image = Image.open(Path(
# f'{Path(__file__).parents[2]}/resources/qt/images/temp.jpg'))
# thumb_debug.load()
# TODO: Make dynamic font sized given different pixel ratios
font_pixel_ratio: float = 1
ext_font = ImageFont.truetype(
os.path.normpath(
f"{Path(__file__).parents[3]}/resources/qt/fonts/Oxanium-Bold.ttf"
),
Path(f"{Path(__file__).parents[3]}/resources/qt/fonts/Oxanium-Bold.ttf"),
math.floor(12 * font_pixel_ratio),
)
@@ -96,42 +84,37 @@ class ThumbRenderer(QObject):
timestamp: float,
filepath,
base_size: tuple[int, int],
pixelRatio: float,
isLoading=False,
pixel_ratio: float,
is_loading=False,
gradient=False,
update_on_ratio_change=False,
):
"""Renders an entry/element thumbnail for the GUI."""
adj_size: int = 1
image = None
pixmap = None
"""Internal renderer. Renders an entry/element thumbnail for the GUI."""
image: Image.Image = None
pixmap: QPixmap = None
final: Image.Image = None
extension: str = None
# adj_font_size = math.floor(12 * pixelRatio)
if ThumbRenderer.font_pixel_ratio != pixelRatio:
ThumbRenderer.font_pixel_ratio = pixelRatio
resampling_method = Image.Resampling.BILINEAR
if ThumbRenderer.font_pixel_ratio != pixel_ratio:
ThumbRenderer.font_pixel_ratio = pixel_ratio
ThumbRenderer.ext_font = ImageFont.truetype(
os.path.normpath(
Path(
f"{Path(__file__).parents[3]}/resources/qt/fonts/Oxanium-Bold.ttf"
),
math.floor(12 * ThumbRenderer.font_pixel_ratio),
)
if isLoading or filepath:
adj_size = math.ceil(base_size[0] * pixelRatio)
if isLoading:
li: Image.Image = ThumbRenderer.thumb_loading_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
adj_size = math.ceil(max(base_size[0], base_size[1]) * pixel_ratio)
if is_loading:
final = ThumbRenderer.thumb_loading_512.resize(
(adj_size, adj_size), resample=resampling_method
)
qim = ImageQt.ImageQt(li)
qim = ImageQt.ImageQt(final)
pixmap = QPixmap.fromImage(qim)
pixmap.setDevicePixelRatio(pixelRatio)
pixmap.setDevicePixelRatio(pixel_ratio)
if update_on_ratio_change:
self.updated_ratio.emit(1)
elif filepath:
mask: Image.Image = ThumbRenderer.thumb_mask_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
).getchannel(3)
hl: Image.Image = ThumbRenderer.thumb_mask_hl_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
)
extension = os.path.splitext(filepath)[1][1:].lower()
try:
@@ -151,7 +134,7 @@ class ThumbRenderer(QObject):
image = ImageOps.exif_transpose(image)
except DecompressionBombError as e:
logging.info(
f"[ThumbRenderer][ERROR] Couldn't Render thumbnail for {filepath} (because of {e})"
f"[ThumbRenderer]{WARNING} Couldn't Render thumbnail for {filepath} (because of {e})"
)
# Videos =======================================================
@@ -173,22 +156,16 @@ class ThumbRenderer(QObject):
# Plain Text ===================================================
elif extension in PLAINTEXT_TYPES:
try:
text: str = extension
with open(filepath, "r", encoding="utf-8") as text_file:
text = text_file.read(256)
bg = Image.new("RGB", (256, 256), color="#1e1e1e")
draw = ImageDraw.Draw(bg)
draw.text((16, 16), text, file=(255, 255, 255))
image = bg
except:
logging.info(
f"[ThumbRenderer][ERROR]: Coulnd't render thumbnail for {filepath}"
)
with open(filepath, "r", encoding="utf-8") as text_file:
text = text_file.read(256)
bg = Image.new("RGB", (256, 256), color="#1e1e1e")
draw = ImageDraw.Draw(bg)
draw.text((16, 16), text, file=(255, 255, 255))
image = bg
# No Rendered Thumbnail ========================================
else:
image = ThumbRenderer.thumb_file_default_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
(adj_size, adj_size), resample=resampling_method
)
if not image:
@@ -204,307 +181,65 @@ class ThumbRenderer(QObject):
new_y = adj_size
new_x = math.ceil(adj_size * (orig_x / orig_y))
# img_ratio = new_x / new_y
image = image.resize((new_x, new_y), resample=Image.Resampling.BILINEAR)
if image.size != (adj_size, adj_size):
# Old 1 color method.
# bg_col = image.copy().resize((1, 1)).getpixel((0,0))
# bg = Image.new(mode='RGB',size=(adj_size,adj_size),color=bg_col)
# bg.thumbnail((1, 1))
# bg = bg.resize((adj_size,adj_size), resample=Image.Resampling.NEAREST)
# Small gradient background. Looks decent, and is only a one-liner.
# bg = image.copy().resize((2, 2), resample=Image.Resampling.BILINEAR).resize((adj_size,adj_size),resample=Image.Resampling.BILINEAR)
# Four-Corner Gradient Background.
# Not exactly a one-liner, but it's (subjectively) really cool.
tl = image.getpixel((0, 0))
tr = image.getpixel(((image.size[0] - 1), 0))
bl = image.getpixel((0, (image.size[1] - 1)))
br = image.getpixel(((image.size[0] - 1), (image.size[1] - 1)))
bg = Image.new(mode="RGB", size=(2, 2))
bg.paste(tl, (0, 0, 2, 2))
bg.paste(tr, (1, 0, 2, 2))
bg.paste(bl, (0, 1, 2, 2))
bg.paste(br, (1, 1, 2, 2))
bg = bg.resize(
(adj_size, adj_size), resample=Image.Resampling.BICUBIC
)
bg.paste(
image,
box=(
(adj_size - image.size[0]) // 2,
(adj_size - image.size[1]) // 2,
),
)
bg.putalpha(mask)
final = bg
else:
image.putalpha(mask)
final = image
hl_soft = hl.copy()
hl_soft.putalpha(ImageEnhance.Brightness(hl.getchannel(3)).enhance(0.5))
final.paste(
ImageChops.soft_light(final, hl_soft), mask=hl_soft.getchannel(3)
)
# hl_add = hl.copy()
# hl_add.putalpha(ImageEnhance.Brightness(hl.getchannel(3)).enhance(.25))
# final.paste(hl_add, mask=hl_add.getchannel(3))
except (UnidentifiedImageError, FileNotFoundError, cv2.error):
broken_thumb = True
final = ThumbRenderer.thumb_broken_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
)
qim = ImageQt.ImageQt(final)
if image:
image.close()
pixmap = QPixmap.fromImage(qim)
pixmap.setDevicePixelRatio(pixelRatio)
if pixmap:
self.updated.emit(timestamp, pixmap, QSize(*base_size), extension)
else:
self.updated.emit(timestamp, QPixmap(), QSize(*base_size), extension)
def render_big(
self,
timestamp: float,
filepath,
base_size: tuple[int, int],
pixelRatio: float,
isLoading: bool = False,
):
"""Renders a large, non-square entry/element thumbnail for the GUI."""
adj_size: int = 1
image: Image.Image = None
pixmap: QPixmap = None
final: Image.Image = None
extension: str = None
# adj_font_size = math.floor(12 * pixelRatio)
if ThumbRenderer.font_pixel_ratio != pixelRatio:
ThumbRenderer.font_pixel_ratio = pixelRatio
ThumbRenderer.ext_font = ImageFont.truetype(
os.path.normpath(
f"{Path(__file__).parents[3]}/resources/qt/fonts/Oxanium-Bold.ttf"
),
math.floor(12 * ThumbRenderer.font_pixel_ratio),
)
if isLoading or filepath:
adj_size = math.ceil(max(base_size[0], base_size[1]) * pixelRatio)
if isLoading:
adj_size = math.ceil((512 * pixelRatio))
final = ThumbRenderer.thumb_loading_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
)
qim = ImageQt.ImageQt(final)
pixmap = QPixmap.fromImage(qim)
pixmap.setDevicePixelRatio(pixelRatio)
self.updated_ratio.emit(1)
elif filepath:
# mask: Image.Image = ThumbRenderer.thumb_mask_512.resize(
# (adj_size, adj_size), resample=Image.Resampling.BILINEAR).getchannel(3)
# hl: Image.Image = ThumbRenderer.thumb_mask_hl_512.resize(
# (adj_size, adj_size), resample=Image.Resampling.BILINEAR)
extension = os.path.splitext(filepath)[1][1:].lower()
try:
# Images =======================================================
if extension in IMAGE_TYPES:
try:
image = Image.open(filepath)
# image = self.thumb_debug
if image.mode == "RGBA":
# logging.info(image.getchannel(3).tobytes())
new_bg = Image.new("RGB", image.size, color="#1e1e1e")
new_bg.paste(image, mask=image.getchannel(3))
image = new_bg
if image.mode != "RGB":
image = image.convert(mode="RGB")
image = ImageOps.exif_transpose(image)
except DecompressionBombError as e:
logging.info(
f"[ThumbRenderer][ERROR] Couldn't Render thumbnail for {filepath} (because of {e})"
)
# Videos =======================================================
elif extension in VIDEO_TYPES:
video = cv2.VideoCapture(filepath)
video.set(
cv2.CAP_PROP_POS_FRAMES,
(video.get(cv2.CAP_PROP_FRAME_COUNT) // 2),
)
success, frame = video.read()
if not success:
# Depending on the video format, compression, and frame
# count, seeking halfway does not work and the thumb
# must be pulled from the earliest available frame.
video.set(cv2.CAP_PROP_POS_FRAMES, 0)
success, frame = video.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
image = Image.fromarray(frame)
# Plain Text ===================================================
elif extension in PLAINTEXT_TYPES:
try:
text: str = extension
with open(filepath, "r", encoding="utf-8") as text_file:
text = text_file.read(256)
bg = Image.new("RGB", (256, 256), color="#1e1e1e")
draw = ImageDraw.Draw(bg)
draw.text((16, 16), text, file=(255, 255, 255))
image = bg
except:
logging.info(
f"[ThumbRenderer][ERROR]: Coulnd't render thumbnail for {filepath}"
)
# No Rendered Thumbnail ========================================
else:
image = ThumbRenderer.thumb_file_default_512.resize(
if update_on_ratio_change:
self.updated_ratio.emit(new_x / new_y)
image = image.resize((new_x, new_y), resample=resampling_method)
if gradient:
mask: Image.Image = ThumbRenderer.thumb_mask_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
).getchannel(3)
hl: Image.Image = ThumbRenderer.thumb_mask_hl_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
)
if not image:
raise UnidentifiedImageError
orig_x, orig_y = image.size
if orig_x < adj_size and orig_y < adj_size:
new_x, new_y = (adj_size, adj_size)
if orig_x > orig_y:
new_x = adj_size
new_y = math.ceil(adj_size * (orig_y / orig_x))
elif orig_y > orig_x:
new_y = adj_size
new_x = math.ceil(adj_size * (orig_x / orig_y))
final = four_corner_gradient_background(image, adj_size, mask, hl)
else:
new_x, new_y = (adj_size, adj_size)
if orig_x > orig_y:
new_x = adj_size
new_y = math.ceil(adj_size * (orig_y / orig_x))
elif orig_y > orig_x:
new_y = adj_size
new_x = math.ceil(adj_size * (orig_x / orig_y))
self.updated_ratio.emit(new_x / new_y)
image = image.resize((new_x, new_y), resample=Image.Resampling.BILINEAR)
# image = image.resize(
# (new_x, new_y), resample=Image.Resampling.BILINEAR)
# if image.size != (adj_size, adj_size):
# # Old 1 color method.
# # bg_col = image.copy().resize((1, 1)).getpixel((0,0))
# # bg = Image.new(mode='RGB',size=(adj_size,adj_size),color=bg_col)
# # bg.thumbnail((1, 1))
# # bg = bg.resize((adj_size,adj_size), resample=Image.Resampling.NEAREST)
# # Small gradient background. Looks decent, and is only a one-liner.
# # bg = image.copy().resize((2, 2), resample=Image.Resampling.BILINEAR).resize((adj_size,adj_size),resample=Image.Resampling.BILINEAR)
# # Four-Corner Gradient Background.
# # Not exactly a one-liner, but it's (subjectively) really cool.
# tl = image.getpixel((0, 0))
# tr = image.getpixel(((image.size[0]-1), 0))
# bl = image.getpixel((0, (image.size[1]-1)))
# br = image.getpixel(((image.size[0]-1), (image.size[1]-1)))
# bg = Image.new(mode='RGB', size=(2, 2))
# bg.paste(tl, (0, 0, 2, 2))
# bg.paste(tr, (1, 0, 2, 2))
# bg.paste(bl, (0, 1, 2, 2))
# bg.paste(br, (1, 1, 2, 2))
# bg = bg.resize((adj_size, adj_size),
# resample=Image.Resampling.BICUBIC)
# bg.paste(image, box=(
# (adj_size-image.size[0])//2, (adj_size-image.size[1])//2))
# bg.putalpha(mask)
# final = bg
# else:
# image.putalpha(mask)
# final = image
# hl_soft = hl.copy()
# hl_soft.putalpha(ImageEnhance.Brightness(
# hl.getchannel(3)).enhance(.5))
# final.paste(ImageChops.soft_light(final, hl_soft),
# mask=hl_soft.getchannel(3))
# hl_add = hl.copy()
# hl_add.putalpha(ImageEnhance.Brightness(hl.getchannel(3)).enhance(.25))
# final.paste(hl_add, mask=hl_add.getchannel(3))
scalar = 4
rec: Image.Image = Image.new(
"RGB",
tuple([d * scalar for d in image.size]), # type: ignore
"black",
)
draw = ImageDraw.Draw(rec)
draw.rounded_rectangle(
(0, 0) + rec.size,
(base_size[0] // 32) * scalar * pixelRatio,
fill="red",
)
rec = rec.resize(
tuple([d // scalar for d in rec.size]),
resample=Image.Resampling.BILINEAR,
)
# final = image
final = Image.new("RGBA", image.size, (0, 0, 0, 0))
# logging.info(rec.size)
# logging.info(image.size)
final.paste(image, mask=rec.getchannel(0))
except (UnidentifiedImageError, FileNotFoundError, cv2.error):
broken_thumb = True
self.updated_ratio.emit(1)
scalar = 4
rec: Image.Image = Image.new(
"RGB",
tuple([d * scalar for d in image.size]), # type: ignore
"black",
)
draw = ImageDraw.Draw(rec)
draw.rounded_rectangle(
(0, 0) + rec.size,
(base_size[0] // 32) * scalar * pixel_ratio,
fill="red",
)
rec = rec.resize(
tuple([d // scalar for d in rec.size]),
resample=Image.Resampling.BILINEAR,
)
final = Image.new("RGBA", image.size, (0, 0, 0, 0))
final.paste(image, mask=rec.getchannel(0))
except (
UnidentifiedImageError,
FileNotFoundError,
cv2.error,
DecompressionBombError,
UnicodeDecodeError,
) as e:
if e is not UnicodeDecodeError:
logging.info(
f"[ThumbRenderer]{ERROR}: Couldn't render thumbnail for {filepath} ({e})"
)
if update_on_ratio_change:
self.updated_ratio.emit(1)
final = ThumbRenderer.thumb_broken_512.resize(
(adj_size, adj_size), resample=Image.Resampling.BILINEAR
(adj_size, adj_size), resample=resampling_method
)
# if extension in VIDEO_TYPES + ['gif', 'apng'] or broken_thumb:
# idk = ImageDraw.Draw(final)
# # idk.textlength(file_type)
# ext_offset_x = idk.textlength(
# text=extension.upper(), font=ThumbRenderer.ext_font) / 2
# ext_offset_x = math.floor(ext_offset_x * (1/pixelRatio))
# x_margin = math.floor(
# (adj_size-((base_size[0]//6)+ext_offset_x) * pixelRatio))
# y_margin = math.floor(
# (adj_size-((base_size[0]//8)) * pixelRatio))
# stroke_width = round(2 * pixelRatio)
# fill = 'white' if not broken_thumb else '#E32B41'
# idk.text((x_margin, y_margin), extension.upper(
# ), fill=fill, font=ThumbRenderer.ext_font, stroke_width=stroke_width, stroke_fill=(0, 0, 0))
qim = ImageQt.ImageQt(final)
if image:
image.close()
pixmap = QPixmap.fromImage(qim)
pixmap.setDevicePixelRatio(pixelRatio)
pixmap.setDevicePixelRatio(pixel_ratio)
if pixmap:
# logging.info(final.size)
# self.updated.emit(pixmap, QSize(*final.size))
self.updated.emit(
timestamp,
pixmap,
QSize(
math.ceil(adj_size * 1 / pixelRatio),
math.ceil(final.size[1] * 1 / pixelRatio),
math.ceil(adj_size / pixel_ratio),
math.ceil(final.size[1] / pixel_ratio),
),
extension,
)