update reaquirements. removed redundant loading logic
All checks were successful
Python CI / test (push) Successful in 1m26s
Lint / lint (push) Successful in 1m37s
Tests / test (3.10) (push) Successful in 1m17s
Tests / test (3.11) (push) Successful in 1m14s
Tests / test (3.9) (push) Successful in 1m11s

This commit is contained in:
Duncan Tourolle 2025-11-27 20:06:01 +01:00
parent e8d9eaca51
commit 45268cdfe4
3 changed files with 31 additions and 73 deletions

View File

@ -131,20 +131,38 @@ class ImageData(BaseLayoutElement):
self._async_loading = False
self._async_load_requested = False
def resolve_image_path(self) -> Optional[str]:
"""
Resolve the image path to an absolute path.
Returns the absolute path if the image exists, None otherwise.
"""
if not self.image_path:
return None
# Already absolute
if os.path.isabs(self.image_path):
if os.path.exists(self.image_path):
return self.image_path
return None
# Relative path - look in project folder
project_folder, _ = get_asset_search_paths()
if project_folder:
full_path = os.path.join(project_folder, self.image_path)
if os.path.exists(full_path):
return full_path
return None
def _extract_dimensions_metadata(self):
"""
Extract image dimensions without loading the full image.
Uses PIL's lazy loading to just read the header.
"""
try:
# Resolve path
image_path = self.image_path
if not os.path.isabs(self.image_path):
project_folder, search_paths = get_asset_search_paths()
if project_folder and os.path.exists(os.path.join(project_folder, self.image_path)):
image_path = os.path.join(project_folder, self.image_path)
if os.path.exists(image_path):
image_path = self.resolve_image_path()
if image_path:
# Use PIL to just read dimensions (fast, doesn't load pixel data)
with Image.open(image_path) as img:
width, height = img.width, img.height
@ -166,44 +184,14 @@ class ImageData(BaseLayoutElement):
"""Render the image using OpenGL"""
from OpenGL.GL import (glBegin, glEnd, glVertex2f, glColor3f, glColor4f, GL_QUADS, GL_LINE_LOOP,
glEnable, glDisable, GL_TEXTURE_2D, glBindTexture, glTexCoord2f,
glGenTextures, glTexImage2D, GL_RGBA, GL_UNSIGNED_BYTE,
glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_LINEAR,
glDeleteTextures)
from PIL import Image
import os
glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
x, y = self.position
w, h = self.size
# Note: Rotation is now handled at the PIL image level, not visually
# The image data itself is rotated, so we render it without transformation
# Try to load and render the actual image
texture_id = None
# Handle both absolute and relative paths
image_full_path = self.image_path
if self.image_path and not os.path.isabs(self.image_path):
# Relative path - only look in project folder (assets)
# Search paths are only used for healing, not for rendering
project_folder, _ = get_asset_search_paths()
if project_folder:
full_path = os.path.join(project_folder, self.image_path)
if os.path.exists(full_path):
image_full_path = full_path
else:
print(f"ImageData: Could not resolve path: {self.image_path}")
print(f" Expected at: {full_path}")
print(f" Image needs healing - not found in assets folder")
# NOTE: Async loading is now handled by page_layout.py calling request_image_load()
# This sync path should only be reached if async loading is not available
# The actual image will be loaded in the background and the texture created
# via _on_async_image_loaded() callback when ready
# Create texture from pending image if one exists (deferred from async load)
# This ensures texture creation happens when GL context is active
# Texture creation must happen during render when GL context is active
if hasattr(self, '_pending_pil_image') and self._pending_pil_image is not None:
self._create_texture_from_pending_image()

View File

@ -409,37 +409,6 @@ class PDFExporter:
self._render_element(params.canvas, params.element, params.x_offset_mm,
params.page_width_pt, params.page_height_pt, params.page_number)
def _resolve_image_path(self, image_path: str) -> Optional[str]:
"""
Resolve an image path, handling both absolute and relative paths.
Uses the same logic as ImageData.render() for consistency.
Args:
image_path: The image path (absolute or relative)
Returns:
Resolved absolute path if found, None otherwise
"""
if not image_path:
return None
# If already absolute and exists, return it
if os.path.isabs(image_path) and os.path.exists(image_path):
return image_path
# For relative paths, only look in project folder (assets)
# Search paths are only used for healing, not for PDF export
from pyPhotoAlbum.models import get_asset_search_paths
project_folder, _ = get_asset_search_paths()
if project_folder:
full_path = os.path.join(project_folder, image_path)
if os.path.exists(full_path):
return full_path
return None
def _render_image(self, ctx: RenderContext):
"""
Render an image element on the PDF canvas.
@ -447,8 +416,8 @@ class PDFExporter:
Args:
ctx: RenderContext containing all rendering parameters
"""
# Resolve image path (handles both absolute and relative paths)
image_full_path = self._resolve_image_path(ctx.image_element.image_path)
# Resolve image path using ImageData's method
image_full_path = ctx.image_element.resolve_image_path()
# Check if image exists
if not image_full_path:

View File

@ -39,6 +39,7 @@ dev = [
"pytest-qt>=4.2.0",
"pytest-cov>=4.0.0",
"pytest-mock>=3.10.0",
"pdfplumber>=0.10.0",
"flake8>=5.0.0",
"black>=22.0.0",
"mypy>=0.990",