update reaquirements. removed redundant loading logic
This commit is contained in:
parent
e8d9eaca51
commit
45268cdfe4
@ -131,20 +131,38 @@ class ImageData(BaseLayoutElement):
|
|||||||
self._async_loading = False
|
self._async_loading = False
|
||||||
self._async_load_requested = 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):
|
def _extract_dimensions_metadata(self):
|
||||||
"""
|
"""
|
||||||
Extract image dimensions without loading the full image.
|
Extract image dimensions without loading the full image.
|
||||||
Uses PIL's lazy loading to just read the header.
|
Uses PIL's lazy loading to just read the header.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Resolve path
|
image_path = self.resolve_image_path()
|
||||||
image_path = self.image_path
|
if 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):
|
|
||||||
# Use PIL to just read dimensions (fast, doesn't load pixel data)
|
# Use PIL to just read dimensions (fast, doesn't load pixel data)
|
||||||
with Image.open(image_path) as img:
|
with Image.open(image_path) as img:
|
||||||
width, height = img.width, img.height
|
width, height = img.width, img.height
|
||||||
@ -166,44 +184,14 @@ class ImageData(BaseLayoutElement):
|
|||||||
"""Render the image using OpenGL"""
|
"""Render the image using OpenGL"""
|
||||||
from OpenGL.GL import (glBegin, glEnd, glVertex2f, glColor3f, glColor4f, GL_QUADS, GL_LINE_LOOP,
|
from OpenGL.GL import (glBegin, glEnd, glVertex2f, glColor3f, glColor4f, GL_QUADS, GL_LINE_LOOP,
|
||||||
glEnable, glDisable, GL_TEXTURE_2D, glBindTexture, glTexCoord2f,
|
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)
|
||||||
glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_LINEAR,
|
|
||||||
glDeleteTextures)
|
|
||||||
from PIL import Image
|
|
||||||
import os
|
|
||||||
|
|
||||||
x, y = self.position
|
x, y = self.position
|
||||||
w, h = self.size
|
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
|
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)
|
# 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:
|
if hasattr(self, '_pending_pil_image') and self._pending_pil_image is not None:
|
||||||
self._create_texture_from_pending_image()
|
self._create_texture_from_pending_image()
|
||||||
|
|
||||||
|
|||||||
@ -409,37 +409,6 @@ class PDFExporter:
|
|||||||
self._render_element(params.canvas, params.element, params.x_offset_mm,
|
self._render_element(params.canvas, params.element, params.x_offset_mm,
|
||||||
params.page_width_pt, params.page_height_pt, params.page_number)
|
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):
|
def _render_image(self, ctx: RenderContext):
|
||||||
"""
|
"""
|
||||||
Render an image element on the PDF canvas.
|
Render an image element on the PDF canvas.
|
||||||
@ -447,8 +416,8 @@ class PDFExporter:
|
|||||||
Args:
|
Args:
|
||||||
ctx: RenderContext containing all rendering parameters
|
ctx: RenderContext containing all rendering parameters
|
||||||
"""
|
"""
|
||||||
# Resolve image path (handles both absolute and relative paths)
|
# Resolve image path using ImageData's method
|
||||||
image_full_path = self._resolve_image_path(ctx.image_element.image_path)
|
image_full_path = ctx.image_element.resolve_image_path()
|
||||||
|
|
||||||
# Check if image exists
|
# Check if image exists
|
||||||
if not image_full_path:
|
if not image_full_path:
|
||||||
|
|||||||
@ -39,6 +39,7 @@ dev = [
|
|||||||
"pytest-qt>=4.2.0",
|
"pytest-qt>=4.2.0",
|
||||||
"pytest-cov>=4.0.0",
|
"pytest-cov>=4.0.0",
|
||||||
"pytest-mock>=3.10.0",
|
"pytest-mock>=3.10.0",
|
||||||
|
"pdfplumber>=0.10.0",
|
||||||
"flake8>=5.0.0",
|
"flake8>=5.0.0",
|
||||||
"black>=22.0.0",
|
"black>=22.0.0",
|
||||||
"mypy>=0.990",
|
"mypy>=0.990",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user