import os import uuid from io import BytesIO from PIL import Image, ImageOps from django.conf import settings from django.core.files.base import ContentFile from rest_framework import serializers from .models import PostImages class PostImagesSerializer(serializers.ModelSerializer): class Meta: model = PostImages fields = '__all__' class PostImageCreateSerializer(serializers.Serializer): """ Serializer for uploading and processing an image. """ image = serializers.ImageField(write_only=True, help_text="Yüklenecek resim dosyası.") title = serializers.CharField(max_length=254, help_text="Resim için bir başlık.") width = serializers.IntegerField(help_text="Resmin yeni genişliği (pixel).") height = serializers.IntegerField(help_text="Resmin yeni yüksekliği (pixel).") quality = serializers.IntegerField(default=85, min_value=1, max_value=100, help_text="JPG/WebP için kalite (1-100).") format = serializers.ChoiceField( choices=['png', 'webp', 'jpg', 'avif'], default='avif', help_text="Çıktı resim formatı." ) def create(self, validated_data): image_file = validated_data.pop('image') title = validated_data.pop('title') new_width = validated_data.pop('width') new_height = validated_data.pop('height') quality = validated_data.pop('quality') output_format = validated_data.pop('format') # Open the image with Pillow img = Image.open(image_file) # Preserve original metadata for the model original_filename = image_file.name original_size = image_file.size # Process the image: Resize and crop to fill target dimensions (Center Crop). # This ensures the image fills the dimensions without distortion or padding. # ImageOps.fit resizes and crops the image to the requested size. img = ImageOps.fit(img, (new_width, new_height), method=Image.Resampling.LANCZOS, centering=(0.5, 0.5)) # If output format does not support transparency (like JPG), convert to RGB. # This also ensures compatibility for formats like JPEG that don't support P or RGBA. if output_format != 'png' and img.mode != 'RGB': img = img.convert('RGB') # Save the processed image to an in-memory buffer buffer = BytesIO() # Pillow expects 'JPEG' format identifier, not 'jpg' save_format = output_format.upper() if save_format == 'JPG': save_format = 'JPEG' save_kwargs = {'format': save_format} if output_format in ['jpg', 'webp']: save_kwargs['quality'] = quality img.save(buffer, **save_kwargs) buffer.seek(0) # Generate a unique filename and path new_filename = f"processed/{uuid.uuid4()}.{output_format}" file_path = os.path.join(settings.MEDIA_ROOT, new_filename) # Ensure the directory exists os.makedirs(os.path.dirname(file_path), exist_ok=True) # Save the new file to the media directory with open(file_path, 'wb') as f: f.write(buffer.getvalue()) # Get the size of the new file new_size = os.path.getsize(file_path) # Get user from validated_data if provided (serializer.save(user=...)) user = validated_data.pop('user', None) # Create the PostImages model instance instance = PostImages.objects.create( title=title, user=user, path=new_filename, # Store the relative path processed_path=original_filename, # Let's use this field for original name for now original_filename=original_filename, format=output_format, width=new_width, # Use the target width height=new_height, # Use the target height size=new_size, quality=quality, ) return instance def to_representation(self, instance): # Use the PostImagesSerializer to represent the created object return PostImagesSerializer(instance).data