django-imagekit
django-imagekit copied to clipboard
How to get my custom processor with parameters from saved Django model?
Hello and thanks for awesome package!
Django 1.11.7
I use custom processor for text overlay. This is my code:
# ./example/processors.py
from django.conf import settings
from imagekit import ImageSpec, register
from PIL import Image, ImageDraw, ImageFont
_default_font = ImageFont.truetype(settings.TEXT_OVERLAY_FONT, 24)
def add_text_overlay(image, text, font=_default_font):
rgba_image = image.convert('RGBA')
text_overlay = Image.new('RGBA', rgba_image.size, (255, 255, 255, 0))
image_draw = ImageDraw.Draw(text_overlay)
text_size_x, text_size_y = image_draw.textsize(text, font=font)
text_xy = ((rgba_image.size[0] / 2) - (text_size_x / 2), (rgba_image.size[1] / 2) - (text_size_y / 2))
image_draw.text(text_xy, text, font=font, fill=(255, 255, 255, 255))
image_with_text_overlay = Image.alpha_composite(rgba_image, text_overlay)
return image_with_text_overlay
class TextOverlayProcessor(object):
def __init__(self, text=None):
"""
:param text: The overlay text, string.
"""
self.text = text
def process(self, img):
return add_text_overlay(image=img, text=self.text)
And add him to Django model:
# ./example/models.py
from django.db import models
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
from .processors import TextOverlayProcessor
class ExampleModel(models.Model):
title = models.CharField('Image title', max_length=25, default=None, blank=False)
image = models.ImageField('Image source', default=None)
image_800x800 = ImageSpecField(
source='image',
processors=[ResizeToFill(800, 800), TextOverlayProcessor(text='Test text')],
format='JPEG',
options={'quality': 100}
)
Everything ok. After save this model, I have image with overlayed text on center Test text
.
But how to get value of title
field fromExampleModel
model and save this image after save model?
Help me please.
You want instead of hardcoded text to use the value of the title field right?
@vstoykov yep. I'll explain a little why this is necessary.
The moderators of this site create a new entry in which they write a description (text
field) of the photo (for display on the photo as overlay text) and attach a photo (which is cropped in size 800 to 800).
Next, this photo is being posted to Twitter (but that's another story) ^_^
By default Processors are not intended to know anything about Specs and for that reason you can't tell that info.
As a workaround I'm thinking of property that will return the new image by using modified snipped from the README (https://github.com/matthewwithanm/django-imagekit#defining-specs-outside-of-models).
from django.db import models
from imagekit import ImageSpec
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
from .processors import TextOverlayProcessor
class ExampleModel(models.Model):
title = models.CharField('Image title', max_length=25, default=None, blank=False)
image = models.ImageField('Image source', default=None)
@property
def image_800x800(self):
class Thumbnail(ImageSpec):
processors = [ResizeToFill(800, 800), TextOverlayProcessor(text=self.title)]
format = 'JPEG'
options = {'quality': 60}
image_generator = Thumbnail(source=source_file)
result = image_generator.generate()
return result
Probably this code will not work exactly as you want (if it works at all, I have not tested it). But I think that it can give you an idea.
You can also look at the code for ImageSpec
and ImageSpecField
to see if you can pass the needed information somehow and create your own subclass of ImageSpecField
that will pass current instance or only some fields of it to processors (or some of them).
There is currently no such functionality built in because it's not so trivial.
@vstoykov oh, great! Thanks for fast feedback, btw 👍 I'll test this code later and write if it's worked fine.
Would be nice to have included class/method, like ImageSpecField()
, but for overlay and watermark elements (and hide all magic for users — use only dummy parameters). For example:
class ExampleModel(models.Model):
image = models.ImageField('Image source', default=None)
overlay_text = models.CharField('Image for overlay text', max_length=25, default=None, blank=False)
watermark_image = models.ImageField('Image for watermark', default=None)
image_text_overlay = ImageTextOverlayField(
source_image='image'
source_text='overlay_text',
processors=[TextOverlayProcessor(placed='center', font='...', font_size=24, opacity=0.6, ...)]
)
image_watermark = ImageWatermarkField(
source_image='image'
source_watermark='watermark_image',
processors=[WatermarkProcessor(placed='center', opacity=0.6, ...)]
)
And next in templates and/or views (as usual):
{{ example.image_text_overlay.url }}
{{ example.image_watermark.url }}