109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
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
|