django-imagekit icon indicating copy to clipboard operation
django-imagekit copied to clipboard

How to add watermark and create thumbnail without watermark?

Open artamoshin opened this issue 8 years ago • 5 comments

I need to fit user uploaded image to 1000px and put a watermark. Also I need to create thumbnail (without watermark).

class Photo(models.Model):
    image = ProcessedImageField(upload_to='photo',
                                processors=[
                                    ResizeToFit(1000, 1000, upscale=False),
                                    Watermark(),
                                ],
                                format='JPEG')
    thumbnail = ImageSpecField(source='image',
                               processors=[
                                   ResizeToFill(200, 200),
                               ],
                               format='JPEG')

The trouble is that the thumbnail is created from the already processed image. How to create a thumbnail from the original image, given that the original image should not be saved?

When i trying

    def save(self, *args, **kwargs):
        self.thumbnail.generate()
        super(Photo, self).save(*args, **kwargs)

it raises exception "I/O operation on closed file".

artamoshin avatar Feb 24 '16 07:02 artamoshin

In order to generate thumbnails without watermark with ImageSpecField you need to have somewhere the original image. If your reason to not want the original image be saved is for security (someone not to guess the path to original image) you can use different storage and save originals outside MEDIA_ROOT.

If you do not want to store the original to save space then probably will be better to create the watermark in the form directly with pilkit (django-imagekit is using it under the hood) and assign it to the normal ImageField (You don't want ImageSpecField, because this is not a real field and you need the orignal to be available all the time because cached thumbnails can be deleted and django-imagekit need to recreate them on request). I know that it is not ideal but you can try.

vstoykov avatar Feb 24 '16 14:02 vstoykov

so did you actually solve it (the whole thing?) Because I actually need the exact same thing

goranmaxim avatar Aug 12 '16 07:08 goranmaxim

Unfortuanly I have no find solution with django-imagekit or easy_thumbnails, so I wrote model save handler using pilkit:

from pilkit.processors import ProcessorPipeline, Transpose, ResizeToFit, ResizeToFill

class Photo(models.Model):
    item = models.ForeignKey(Item)
    image = RestrictedImageField(upload_to=get_image_filename)
    preview = models.ImageField(upload_to=get_preview_filename, blank=True)
    thumbnail = models.ImageField(upload_to=get_thumbnail_filename, blank=True)

    def _img_to_field(self, im, quality=80):
        """
        Saves Pillow image to model field as JPEG.
        """
        buffer = BytesIO()
        im.save(buffer, format='JPEG', quality=quality)
        return InMemoryUploadedFile(buffer, None, self.image.name, 'image/jpeg', buffer.getbuffer().nbytes, None, None)

    def save(self, *args, **kwargs):
        # New file uploaded
        if isinstance(self.image.file, UploadedFile):
            with Image.open(self.image.file) as uploaded_image:
                # White background for semi-transparent images
                if uploaded_image.mode == 'RGBA':
                    background = Image.new('RGB', uploaded_image.size, (255, 255, 255))
                    background.paste(uploaded_image, mask=uploaded_image.split()[3])
                    uploaded_image = background

                if uploaded_image.mode != 'RGB':
                    uploaded_image = uploaded_image.convert('RGB')

                logo_path = os.path.join(settings.BASE_DIR, 'classifieds/watermark.png')
                logo = Image.open(logo_path)

                image = ProcessorPipeline([
                    Transpose(),  # EXIF rotate
                    ResizeToFit(1200, 1200, upscale=False),
                ]).process(uploaded_image)
                image = watermark(image, logo, (image.width - logo.width - 20,
                                                image.height - logo.height - 20), opacity=0.5)
                self.image = self._img_to_field(image)

                thumbnail = ProcessorPipeline([
                    Transpose(),
                    ResizeToFill(240, 180),
                ]).process(uploaded_image)
                self.thumbnail = self._img_to_field(thumbnail)

                preview = ProcessorPipeline([
                    Transpose(),
                    ResizeToFill(500, 375),
                ]).process(uploaded_image)
                preview = watermark(preview, logo, (preview.width - logo.width - 20,
                                                    preview.height - logo.height - 20), opacity=0.5)
                self.preview = self._img_to_field(preview)

        super(Photo, self).save(*args, **kwargs)

RestrictedImageField is models.ImageField with size and formats validating, watermark module - http://code.activestate.com/recipes/362879-watermark-with-pil/

artamoshin avatar Aug 12 '16 09:08 artamoshin

Fields: original image & watemark & thumbnail without watermark

class Photo(models.Model):
    original_img = ProcessedImageField(upload_to='photo',
                                processors=[
                                    ResizeToFit(1000, 1000, upscale=False),
                                ],
                                format='JPEG')

    image = ImageSpecField(source='original_img',
                                processors=[
                                    ResizeToFit(1000, 1000, upscale=False),
                                    Watermark(),
                                ],
                                format='JPEG')

    thumbnail = ImageSpecField(source='original_img',
                               processors=[
                                   ResizeToFill(200, 200),
                               ],
                               format='JPEG')

leotop avatar Feb 08 '18 11:02 leotop

class Watermark(object): def process(self, image): # Code for adding the watermark goes here. return image

class Photo(models.Model): original_image = models.ImageField(upload_to='photos') watermarked_image = ImageSpec([Watermark()], image_field='original_image', format='JPEG', options={'quality': 90})_

anubhavkulshresthagit avatar Jul 06 '20 11:07 anubhavkulshresthagit