diff --git a/pyPhotoAlbum/async_backend.py b/pyPhotoAlbum/async_backend.py index d081982..331a40b 100644 --- a/pyPhotoAlbum/async_backend.py +++ b/pyPhotoAlbum/async_backend.py @@ -745,18 +745,26 @@ class AsyncPDFGenerator(QObject): # Patch Image.open to use cache def cached_open(path, *args, **kwargs): - # Try cache first - # Note: We cache the unrotated image so rotation can be applied per-element - cached_img = self.image_cache.get(Path(path)) - if cached_img: - logger.debug(f"PDF using cached image: {path}") - return cached_img + # Only use cache for file paths, not BytesIO or other file-like objects + is_file_path = isinstance(path, (str, Path)) - # Load and cache (unrotated - rotation is applied per-element) - img = original_open(path, *args, **kwargs) - img = convert_to_rgba(img) - self.image_cache.put(Path(path), img) - return img + if is_file_path: + # Try cache first + # Note: We cache the unrotated image so rotation can be applied per-element + path_obj = Path(path) if isinstance(path, str) else path + cached_img = self.image_cache.get(path_obj) + if cached_img: + logger.debug(f"PDF using cached image: {path}") + return cached_img + + # Load and cache (unrotated - rotation is applied per-element) + img = original_open(path, *args, **kwargs) + img = convert_to_rgba(img) + self.image_cache.put(path_obj, img) + return img + else: + # For BytesIO and other file-like objects, just use original open + return original_open(path, *args, **kwargs) # Temporarily patch Image.open try: diff --git a/pyPhotoAlbum/frame_manager.py b/pyPhotoAlbum/frame_manager.py index e187e1f..54befdc 100644 --- a/pyPhotoAlbum/frame_manager.py +++ b/pyPhotoAlbum/frame_manager.py @@ -303,8 +303,14 @@ class FrameManager: output_height=target_size, ) - # Load as PIL Image - img = Image.open(io.BytesIO(png_data)) + # Validate png_data type + if not isinstance(png_data, bytes): + print(f"Warning: cairosvg returned {type(png_data)} instead of bytes") + return None + + # Load as PIL Image from bytes buffer + buffer = io.BytesIO(png_data) + img = Image.open(buffer) if img.mode != "RGBA": img = img.convert("RGBA") @@ -314,7 +320,9 @@ class FrameManager: return img except Exception as e: + import traceback print(f"Error loading SVG {svg_path}: {e}") + traceback.print_exc() return None def _recolor_svg(self, svg_content: str, color: Tuple[int, int, int]) -> str: @@ -388,11 +396,17 @@ class FrameManager: return frame._image_cache[cache_key] if frame.asset_path: - svg_path = self._frames_dir / frame.asset_path - img = self._load_svg_as_image(svg_path, corner_size, color) - if img: - frame._image_cache[cache_key] = img - return img + try: + svg_path = self._frames_dir / frame.asset_path + img = self._load_svg_as_image(svg_path, corner_size, color) + if img: + frame._image_cache[cache_key] = img + return img + except Exception as e: + import traceback + print(f"Error getting corner image for {frame.name}: {e}") + traceback.print_exc() + return None return None diff --git a/pyPhotoAlbum/pdf_exporter.py b/pyPhotoAlbum/pdf_exporter.py index f2f9d55..b5ca275 100644 --- a/pyPhotoAlbum/pdf_exporter.py +++ b/pyPhotoAlbum/pdf_exporter.py @@ -62,20 +62,28 @@ def _process_image_task(task: ImageTask) -> Tuple[str, Optional[bytes], Optional if not isinstance(task.image_path, str): return (task.task_id, None, f"Invalid image_path type: {type(task.image_path).__name__}, expected str") - # Import here to ensure fresh imports in worker process + # Import PIL first with basic load from PIL import Image - # Load image first (before other imports that might cause issues) - img = Image.open(task.image_path) + # Try to open the image - this is the most likely failure point + try: + img = Image.open(task.image_path) + except Exception as open_err: + import traceback + return (task.task_id, None, f"Image.open failed: {open_err}\n{traceback.format_exc()}") # Now import the rest - from pyPhotoAlbum.image_utils import ( - apply_pil_rotation, - convert_to_rgba, - calculate_center_crop_coords, - crop_image_to_coords, - apply_rounded_corners, - ) + try: + from pyPhotoAlbum.image_utils import ( + apply_pil_rotation, + convert_to_rgba, + calculate_center_crop_coords, + crop_image_to_coords, + apply_rounded_corners, + ) + except Exception as import_err: + import traceback + return (task.task_id, None, f"Import image_utils failed: {import_err}\n{traceback.format_exc()}") # Convert to RGBA img = convert_to_rgba(img)