first commit
This commit is contained in:
108
image/serializers.py
Normal file
108
image/serializers.py
Normal file
@@ -0,0 +1,108 @@
|
||||
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
|
||||
Reference in New Issue
Block a user