Изменение размера изображения на входе - PullRequest
0 голосов
/ 19 января 2020

У меня определены некоторые модели, и я пытаюсь написать метод create_image(). Я не хочу, чтобы изображения были больше, чем 960x720 (или 720x960). Я пытался следовать этому уроку среди других, но я не совсем понял его правильно. Пожалуйста, посмотрите на мой код и скажите, что я могу сделать по-другому.

models.py

from django.db import models
from home.models import TimestampedModel
from .managers import AlbumManager, ImageManager

class Album(TimestampedModel):
    title = models.CharField(max_length=255)
    objects = AlbumManager()

class Image(TimestampedModel):
    image = models.ImageField(upload_to='img/%Y/%m/%d/')
    album = models.ForeignKey(Album, on_delete=models.CASCADE)
    objects = ImageManager()

Manager.py

from django.db import models

class AlbumManager(models.Manager):
    def create_album(self, request):
        from .models import Image

        # Data collection
        title = request.POST.get('title', '')
        images = request.FILES.getlist('images', [])

        # Validations
        errors = []

        if not title:
            errors.append('Please enter a title.')

        if not images:
            errors.append('Please upload at least one image.')

        # Return failure
        if errors:
            return (False, errors)

        # Album creation
        album = self.create(title=title)

        # Image creation
        for image in images:
            Image.objects.create_image(image=image, album=album)

        # Return success
        len_images = len(images)
        return (True, 'You have successfully uploaded %d image%s to the album \'%s\'.' % (len_images, '' if len_images == 1 else 's', title))

class ImageManager(models.Manager):
    def create_image(self, **kwargs):
        from io import StringIO
        from PIL import Image

        # Validations (raise error)
        if 'image' not in kwargs and 'album' not in kwargs:
            raise TypeError("create_image() missing 2 required keyword arguments 'image' and 'album'")
        elif 'image' not in kwargs:
            raise TypeError("create_image() missing 1 required keyword argument 'image'")
        elif 'album' not in kwargs:
            raise TypeError("create_image() missing 1 required keyword argument 'album'")

        # Downscale image if necessary
        image = Image.open(kwargs['image'])
        imagefile  = StringIO(image)

        width, height = image.size

        if width > height:
            max_width = float(960)
            max_height = float(720)
            ratio = min(max_width / width, max_height / height)

            width, height = (width * ratio, height * ratio)
        elif width < height:
            max_width = float(720)
            max_height = float(960)
            ratio = min(max_width / width, max_height / height)

            width, height = (width * ratio, height * ratio)
        else:
            max_width = float(720)
            ratio = max_width / width

            width, height = (width * ratio, height * ratio)

        # File operations
        imagefile = StringIO()
        resizedImage.save(imagefile, 'JPEG')
        filename = hashlib.md5(imagefile.getvalue()).hexdigest() + '.jpeg'

        imagefile = open(os.path.join('/tmp', filename), 'w')
        resizedImage.save(filename, 'JPEG')
        # imagefile = open(os.path.join('/tmp', filename), 'r')
        # content = django.core.files.File(imagefile)

        # Return image object
        return self.create(image=resizedImage, album=kwargs['album'])

Редактировать 1

Вот последнее полученное сообщение об ошибке:

Internal Server Error: /images/create/
Traceback (most recent call last):
  File "/home/matt/Repositories/mtm/env/lib/python3.5/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/matt/Repositories/mtm/env/lib/python3.5/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/matt/Repositories/mtm/env/lib/python3.5/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/matt/Repositories/mtm/images/views.py", line 16, in create
    valid, response = Album.objects.create_album(request)
  File "/home/matt/Repositories/mtm/images/managers.py", line 29, in create_album
    Image.objects.create_image(image=image, album=album)
  File "/home/matt/Repositories/mtm/images/managers.py", line 51, in create_image
    imagefile  = StringIO(image)
TypeError: initial_value must be str or None, not PngImageFile

Редактировать 2

views.py

from django.shortcuts import render, redirect
from django.http import HttpResponseBadRequest
from django.contrib import messages

from .models import Album

def create(request):
    if request.method != 'POST':
        return HttpResponseBadRequest()

    valid, response = Album.objects.create_album(request)

    if not valid:
        for error in response:
            messages.error(request, error)
    else:
        messages.success(request, response)

    return redirect('users:index')

AlbumManager (Manager.py)

См. Выше.

Ответы [ 2 ]

1 голос
/ 19 января 2020

Я думаю, что это охватывает все ваши дела:

from io import BytesIO
from PIL import Image

class Image(TimestampedModel):
    image = models.ImageField(upload_to='img/%Y/%m/%d/')
    album = models.ForeignKey(Album, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        if self.image:
            self.resize_image()
        super().save(*args, **kwargs)

    def resize_image(self):
        img = Image.open(self.image).convert('RGB')
        width, height = img.size

        # only resize image if the conditions below happen
        if (width >= height and (width > 960 or height > 720)) or (height > width and (height > 960 or width > 720)):
            if width > height:
                if (height * 960/ width) > 720:
                    new_height = 720
                    new_width = int(width * new_height / height)
                else:
                    new_width = 960
                    new_height = int(height * new_width / width)

            else:
                if (width * 960 / height) > 720:
                    new_width = 720
                    new_height = int(height * new_width / width)
                else:
                    new_height = 960
                    new_width = int(width * new_height / height)

            img = img.resize((new_width, new_height), Image.ANTIALIAS)
            img_file = BytesIO()
            img.save(img_file, 'JPEG', quality=85)
            new_name = self.image.name.split('.')[0] + '.jpg'
            self.image.save(new_name, img_file)

0 голосов
/ 19 января 2020
# You can resize your image in your forms.py or in the similar manner to your ImageManager

from PIL import Image

class ImageForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(ImageForm, self).__init__(*args, **kwargs)

    class Meta:
        model = Image
        fields = ('__all__')


    def save(self, request, commit=True):
        instance = super(ImageForm, self).save(commit=False)
        image = Image.open(instance.image)
        resized_image = image.resize((720, 960), Image.ANTIALIAS)
        resized_image.save('project_app/static/img/'+instance.image.name)
        return instance  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...