import os from fastapi import HTTPException from fastapi.responses import FileResponse from fastapi import APIRouter, Request, FastAPI from PIL import Image class FileHandler: def __init__(self, category, image_type, filename): self.filename = filename self.category = category self.image_type = image_type @property def src_file(self) -> str: src_path = "data/{category}/images/{filename}" return src_path.format( category = self.category, filename = self.filename ) @property def dest_file(self) -> str: base_url = "/images/{category}/{filename}" return base_url.format( category = self.category, filename = self.filename ) @property def dest_filename(self) -> str: base_url = "static/images/{category}/{image_type}/{filename}" return base_url.format( category = self.category, image_type = self.image_type, filename = self.filename ) @property def dest_path(self) -> str: base_url = "static/images/{category}/{image_type}" return base_url.format( category = self.category, image_type = self.image_type ) def __str__(self): return ( f"FileHandler(\n" f" filename='{self.filename}',\n" f" category='{self.category}',\n" f" image_type='{self.image_type}',\n" f" src_file='{self.src_file}',\n" f" dest_file='{self.dest_file}',\n" f" dest_filename='{self.dest_filename}'\n" f")" ) class ImageService: def __init__(self,app: FastAPI): self.router = APIRouter() self.app = app self.IMAGE_SIZES = self.app.state.IMAGE_SIZES #self._ensure_directories_exist() self._add_routes() def __str__(self): """ Provides a string representation of the class instance. """ base_paths_str = "\n".join( [f"{key}: {value}" for key, value in self.base_paths.items()] ) image_sizes_str = "\n".join( [ f"{key}: width={value['width']}, height={value['height']}" for key, value in self.image_sizes.items() ] ) return f" dict: """ Retrieve the width and height for a given image type from the app state. Args: request (Request): FastAPI request object. image_type (str): The type of the image (e.g., 'thumbnails'). Returns: dict: A dictionary with 'width' and 'height'. """ image_sizes = self.app.state.IMAGE_SIZES if image_type not in image_sizes: raise ValueError( f"Invalid image type: {image_type}. Must be one of {list( image_sizes.keys() )}" ) return image_sizes[image_type] def _add_routes(self): self.router.add_api_route( "/image/{category}/{type}/{filename}", self.get_image, methods=["GET"], response_class=FileResponse, ) async def get_image(self, category: str, type: str, filename: str): """ Retrieve an image file from the specified category and type. """ file_path = self._resolve_path(category, type, filename) return FileResponse(file_path) def validate_image(self, file_path:FileHandler=None, width:int=None, height:int=None, overwrite = True ) -> bool: if not os.path.exists( file_path.dest_filename ): with Image.open( file_path.src_file ) as img: print(file_path.src_file) self._resize_image( img, file_path, width, height ) return True with Image.open( file_path.dest_filename ) as img: if img.width != width or img.height != height: if overwrite: self._resize_image( img, file_path, width, height ) return False return True def _resize_image(self, img: Image.Image, file_path: FileHandler, width: int, height: int): resized_img = img.resize( (width, height), Image.Resampling.LANCZOS ) os.makedirs(file_path.dest_path,exist_ok = True) resized_img.save( file_path.dest_filename ) async def get_image(self, category: str, type: str, filename: str): file_path = self._resolve_path( category, type, filename ) return FileResponse( file_path ) def image_tag(self, category: str, image_type: str, filename: str, alt: str = "", width: int = None, height: int = None) -> str: """ Generate an HTML tag with default sizes if dimensions are not provided. """ # Use default sizes if none are provided default_size = self.get_image_size( image_type) width = width or default_size.get( "width" ) height = height or default_size.get( "height" ) #file_path = self._resolve_path( category, image_type, filename ) file_path = FileHandler(category = category,image_type = image_type,filename = filename) self.validate_image( file_path, width = width,height=height, overwrite = True ) tag = f'