I'm trying to generate a preview for an "overlay" config stored in a django model than will be applied later to other model. I have not much experience manipulating files with python... =(
Here is my code:
import io
from django.conf import settings
from django.db import models
from wand.image import Image
from PIL.ImageFile import ImageFile, Parser, Image as PilImage
class Overlay(models.Model):
RELATIVE_POSITIONS = (...)
SIZE_MODES = (...)
name = models.CharField(max_length=50)
source = models.FileField(upload_to='overlays/%Y/%m/%d')
sample = models.ImageField(upload_to='overlay_samples/%Y/%m/%d', blank=True)
px = models.SmallIntegerField(default=0)
py = models.SmallIntegerField(default=0)
position = models.CharField(max_length=2, choices=RELATIVE_POSITIONS)
width = models.SmallIntegerField(default=0)
height = models.SmallIntegerField(default=0)
size_mode = models.CharField(max_length=1, choices=SIZE_MODES, default='B')
last_edit = models.DateTimeField(auto_now=True)
def generate_sample(self):
"""
Generates the sample image and saves it in the "sample" field model
:return: void
"""
base_pic = Image(filename=os.path.join(settings.BASE_DIR, 'girl.jpg'))
overlay_pic = Image(file=self.source)
result_pic = io.BytesIO()
pil_parser = Parser()
if self.width or self.height:
resize_args = {}
if self.width:
resize_args['width'] = self.width
if self.height:
resize_args['height'] = self.height
overlay_pic.resize(**resize_args)
base_pic.composite(overlay_pic, self.px, self.py)
base_pic.save(file=result_pic)
result_pic.seek(0)
while True:
s = result_pic.read(1024)
if not s:
break
pil_parser.feed(s)
pil_result_pic = pil_parser.close()
self.sample.save(self.name, pil_result_pic, False)
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
self.generate_sample()
super(Overlay, self).save(force_insert, force_update, using, update_fields)
But i'm getting AttributeError read here is part on my django debug data:
/usr/local/lib/python2.7/dist-packages/django/core/files/utils.py in <lambda>
"""
encoding = property(lambda self: self.file.encoding)
fileno = property(lambda self: self.file.fileno)
flush = property(lambda self: self.file.flush)
isatty = property(lambda self: self.file.isatty)
newlines = property(lambda self: self.file.newlines)
read = property(lambda self: self.file.read)
readinto = property(lambda self: self.file.readinto)
readline = property(lambda self: self.file.readline)
readlines = property(lambda self: self.file.readlines)
seek = property(lambda self: self.file.seek)
softspace = property(lambda self: self.file.softspace)
tell = property(lambda self: self.file.tell)
▼ Local vars Variable Value
self <File: None>
/usr/local/lib/python2.7/dist-packages/PIL/Image.py in __getattr__
# numpy array interface support
new = {}
shape, typestr = _conv_type_shape(self)
new['shape'] = shape
new['typestr'] = typestr
new['data'] = self.tobytes()
return new
raise AttributeError(name)
def __getstate__(self):
return [
self.info,
self.mode,
self.size,
▼ Local vars Variable Value
self <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1080x1618 at 0x7F1429291248>
name 'read'
What's wrong?
Solved!
Such as @Alexey Kuleshevich was saying django FileField
need a Fileobjeto
, but what was missing is that we must first save the image to a file on disk or in memory, as will guess it's better memory... so here is the final solution. I think it could be improved to not use two step "conversion"
from django.core.files.base import ContentFile
and within the method:
result_pic = io.BytesIO()
pil_parser = Parser()
...
overlay_pic.resize(**resize_args)
base_pic.composite(overlay_pic, self.px, self.py)
base_pic.save(file=result_pic)
result_pic.seek(0)
while True:
s = result_pic.read(1024)
if not s:
break
pil_parser.feed(s)
result_pic = io.BytesIO()
pil_result_pic = pil_parser.close()
pil_result_pic.save(result_pic, format='JPEG')
django_file = ContentFile(result_pic.getvalue())
self.sample.save(self.name, django_file, False)
Thanks to this answer:
How do you convert a PIL Image
to a Django File
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With