新しい画像の高さと幅を800pxに変更して、保存したいと思います。また、アプリは実際の画像を保存してはなりません。何か助けはありますか?
これは私のコードです。元の画像を保存し、サイズ変更された写真は保存しません。
models.py:
class Photo(models.Model):
photo = models.ImageField(upload_to='photos/default/')
def save(self):
if not self.id and not self.photo:
return
super(Photo, self).save()
image = Image.open(self.photo)
(width, height) = image.size
"Max width and height 800"
if (800 / width < 800 / height):
factor = 800 / height
else:
factor = 800 / width
size = ( width / factor, height / factor)
image.resize(size, Image.ANTIALIAS)
image.save(self.photo.path)
image = image.resize(size, Image.ANTIALIAS)
サイズ変更は非破壊的であり、新しい画像を返します。
私は自分のプロジェクトに Django-resized を使用しています。
保存する前にアップロードした写真のサイズを変更する解決策を探しました。 (StackOverflowの)あちこちにたくさんの情報があります。しかし、完全な解決策はありません。これが私の最終的な解決策であり、それを望んでいる人々に役立つと思います。
開発ハイライト
枕をインストールします
$ Sudo apt-get install libjpeg-dev
$ Sudo apt-get install zlib1g-dev
$ pip install -I Pillow
myapp/models.py
from Django.db import models
class Post(models.Model):
caption = models.CharField(max_length=100, default=None, blank=True)
image_w = models.PositiveIntegerField(default=0)
image_h = models.PositiveIntegerField(default=0)
image = models.ImageField(upload_to='images/%Y/%m/%d/', default=None,
blank=True, width_field='image_w', height_field='image_h')
thumbnail = models.ImageField(upload_to='images/%Y/%m/%d/', default=None,
blank=True)
このモデルは、サムネイルとオプションのキャプション付きの写真を保存します。これは、実際のユースケースに似ているはずです。
私たちの目標は、写真のサイズを640x640に変更し、150x150のサムネイルを生成することです。また、WebAPIで写真のサイズを返す必要があります。 image_w
およびimage_h
は、テーブルにキャッシュされたディメンションです。 ImageFieldを宣言するときに、クォータを追加する必要があることに注意してください。ただし、thumbnail
には幅と高さのフィールドは必要ありません(異なることがわかります)。
それがモデルです。モデルをオーバーライドしたり、モデルに関数を追加したりする必要はありません。
myapp/serializers.py
ModelSerializer
を使用して、HTTPPOSTからの受信データを処理します。
from rest_framework import serializers
from myapp.models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('caption',)
アップロードされた写真をシリアライザーが処理することは望ましくありません。自分で処理します。したがって、フィールドに「image」を含める必要はありません。
myapp/views.py
@api_view(['POST'])
@parser_classes((MultiPartParser,))
def handle_uploaded_image(request):
# process images first. if error, quit.
if not 'uploaded_media' in request.FILES:
return Response({'msg': 'Photo missing.'}, status.HTTP_400_BAD_REQUEST)
try:
im = Image.open(StringIO(request.FILES['uploaded_media'].read()))
except IOError:
return Response({'msg': 'Bad image.'}, status.HTTP_400_BAD_REQUEST)
serializer = PostSerializer(data=request.DATA, files=request.FILES)
if not serializer.is_valid():
return Response({'msg': serializer.errors}, status.HTTP_400_BAD_REQUEST)
post = Post.create()
if serializer.data['caption'] is not None:
post.caption = serializer.data['caption']
filename = uuid.uuid4()
name = '%s_0.jpg' % (filename)
post.image.save(name=name, content=resize_image(im, 640))
name = '%s_1.jpg' % (filename)
post.thumbnail.save(name=name, content=resize_image(im, 150))
post.save()
return Response({'msg': 'success',
'caption': post.caption,
'image': {
'url': request.build_absolute_uri(post.image.url),
'width': post.image_w,
'height': post.image_h,
}
'thumbnail': request.build_absolute_uri(post.thumbnail.url),
}, status.HTTP_201_CREATED)
共有pyのヘルパー関数
def resize_image(im, Edge):
(width, height) = im.size
(width, height) = scale_dimension(w, h, long_Edge=edge)
content = StringIO()
im.resize((width, height), Image.ANTIALIAS).save(fp=content, format='JPEG', dpi=[72, 72])
return ContentFile(content.getvalue())
def scale_dimension(width, height, long_Edge):
if width > height:
ratio = long_Edge * 1. / width
else:
ratio = long_Edge * 1. / height
return int(width * ratio), int(height * ratio)
ここでは、元の画像が変更されるため、Image.thumbnailは使用しません。このコードは、複数の解像度(さまざまな目的のための低解像度と高解像度など)を保存する場合に適しています。受信メッセージのサイズを2回変更すると、品質が低下することがわかりました。
また、画像を直接ディスクに保存することもありません。 ContentFile(メモリ内のコンテンツのFileオブジェクト)を介して画像をImageFieldにプッシュし、ImageFieldにその仕事をさせます。画像の複数のコピーに同じファイル名と異なる接尾辞を付ける必要があります。
クレジット
このソリューションを構築するために参照したコードのリンクは次のとおりです。
イメージも検証する場合は、次を参照してください: https://stackoverflow.com/a/20762344/3731039
これが私のために働いたもので、Djangoサイズから少しインスピレーションを得ました
@receiver(pre_save, sender=MyUser)
@receiver(pre_save, sender=Gruppo)
def ridimensiona_immagine(sender, instance=None, created=False, **kwargs):
foto = instance.foto
foto.file.seek(0)
thumb = PIL.Image.open(foto.file)
thumb.thumbnail((
200,
200
), PIL.Image.ANTIALIAS)
buffer = StringIO.StringIO()
thumb.save(buffer, "PNG")
image_file = InMemoryUploadedFile(buffer, None, 'test.png', 'image/png', buffer.len, None)
instance.foto.file = image_file
python <3を使用している場合は、:の使用を検討する必要があります。
from __future__ import division
この場合、部門の結果番号は浮動小数点数になります。
私はまだこの解決策をテストしていませんが、それは役立つかもしれません!!
#subidas.py
import PIL
from PIL import Image
def achichar_tamanho(path):
img = Image.open(path)
img = img.resize((230,230), PIL.Image.ANTIALIAS)
img.save(path)
あなたのmodels.py
、次の変更を加えます。
from subidas import achicar_tamanho
class Productos(models.Model):
imagen = models.ImageField(default="emg_bol/productos/interrogacion.png", upload_to='emg_bol/productos/', blank=True, null=True, help_text="Image of the product")
tiempo_ultima_actualizacion = models.DateTimeField( help_text="Cuando fue la ultima vez, que se modificaron los datos de este producto", auto_now=True)
prioridad = models.IntegerField(max_length=4, default=99, help_text="Frecuencia (medida en unidad), con que el producto es despachado para la venta")
proveedor = models.ForeignKey(Proveedores, help_text="El que provello del producto'")
def save(self, *args, **kwargs):
super(Productos,self).save(*args, **kwargs)
pcod = "%s_%s" % ( re.sub('\s+', '', self.descripcion)[:3], self.id)
self.producto_cod = pcod
achichar_tamanho(self.imagen.path)
super(Productos,self).save(*args, **kwargs)
これらの変更を実装する前後の違いは何でしたか、私は本当に知りません。