diff --git a/src/graphql_schema/entities/photo.py b/src/graphql_schema/entities/photo.py index 8808553..518f902 100644 --- a/src/graphql_schema/entities/photo.py +++ b/src/graphql_schema/entities/photo.py @@ -1,3 +1,4 @@ +import asyncio from typing import List, Optional, Annotated, TYPE_CHECKING import strawberry from sqlalchemy import select, update @@ -10,7 +11,7 @@ from graphql_schema.dataloaders.poi import poi_dataloader from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type from graphql_schema.types import ComboboxInput from upload_utils import ( - get_public_url, handle_file_upload, delete_file, parse_exif_info, generate_thumbnail, file_exists, resize_image + get_public_url, handle_file_upload, delete_file, parse_exif_info, generate_thumbnail, file_exists, resize_image, rotate_image ) from .helpers.flight import handle_combobox_save @@ -149,6 +150,31 @@ class EditPhotoMutation: updated_model = await models.Photo.update(db, obj=photo, data=data) return Photo(**updated_model.as_dict()) + @strawberry.mutation() + @authenticated_user_only() + async def rotate_photo(self, info, id: int, angle: int) -> Photo: + + async with get_session() as db: + query = get_base_query(info.context.user_id) + photo = (await db.scalars(query.filter(models.Photo.id == id))).one() + + await asyncio.gather( + rotate_image( + path=get_photo_basepath(photo.flight_id), + filename=photo.filename, + angle=angle, + ), + rotate_image( + path=get_photo_basepath(photo.flight_id)+"/thumbs", + filename=photo.filename, + angle=angle, + ), + ) + + return Photo(**photo.as_dict()) + + + @strawberry.type class DeletePhotoMutation: diff --git a/src/upload_utils.py b/src/upload_utils.py index 91f9698..2c139b5 100644 --- a/src/upload_utils.py +++ b/src/upload_utils.py @@ -63,7 +63,9 @@ async def parse_exif_info(path: str, filename: str) -> dict: async def resize_image( - path: str, filename: str, new_width: int, quality: int = 90, dest_path: str = None, dest_filename: str = None + path: str, filename: str, new_width: int, quality: int = 90, + dest_path: Optional[str] = None, + dest_filename: Optional[str] = None ): if not dest_path: dest_path = path @@ -84,6 +86,25 @@ async def resize_image( pass +async def rotate_image( + path: str, + filename: str, + angle: int, + dest_path: Optional[str] = None, + dest_filename: Optional[str] = None +): + if not dest_path: + dest_path = path + + if not dest_filename: + dest_filename = filename + + img = Image.open(f"{path}/{filename}") + img = img.rotate(angle, Image.LANCZOS, expand=True) + check_directories(dest_path) + img.save(f"{dest_path}/{dest_filename}", 'JPEG', quality=100) + + async def generate_thumbnail(path: str, filename: str, quality: int = 90): return await resize_image( path, filename,