Image.thumbnail - can't change size properly - django

I am trying to create model for news. My model contains ImageField where i wont to store thumbnail:
class News(models.Model):
title = models.CharField(verbose_name=u'tytuł', max_length=40)
lead = models.TextField(verbose_name=u'zajawka', blank= False)
body = models.TextField(verbose_name=u'treść ogłosznia', blank=False)
author = models.ForeignKey(User)
active = models.BooleanField(verbose_name=u'aktywność ogłoszenia')
pub_date = models.DateTimeField(verbose_name=u'data publikacji')
slug = models.SlugField(unique=True)
lead_photo= models.ImageField(upload_to="lead_photo/")
objects= NewsManager()
I found on the other site code and i modified it to my needs:
def save(self, force_update=False, force_insert=False, thumb_size=(120,120)):
from PIL import Image
from cStringIO import StringIO
from django.core.files.uploadedfile import SimpleUploadedFile
image = Image.open(self.lead_photo)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
image.thumbnail(thumb_size, Image.ANTIALIAS)
# save the thumbnail to memory
temp_handle = StringIO()
image.save(temp_handle, 'JPEG')
temp_handle.seek(0) # rewind the file
# save to the thumbnail field
suf = SimpleUploadedFile(os.path.split(self.lead_photo.name)[-1],
temp_handle.read(),
content_type='image/jpeg')
self.lead_photo.save(suf.name+'.png', suf, save=False)
# save the image object
super(News, self).save(force_update, force_insert)
the problem is that i cant create thumbnail with different width and height proportion. When for instance a set thumb_size(240,320) i'll get the same proportion as in oryginal but picture is smaller. Thanks for advices.
Edit:
On PIL documentation i found very interesting sentence about that method:
"This method modifies the image to contain a thumbnail version of itself, no larger than the given size." So is there any option to make it exact that size?

You can try resize method.
And as a variant you can create new background image (doc):
newImage = Image.new(resized.mode, resized.size, "black")
and place your main image on it keeping aspect ratio resized by image.thumbnail(thumb_size, Image.ANTIALIAS).

You can use:
http://djangothumbnails.com/
from django.db import models
from thumbs import ImageWithThumbsField
class Person(models.Model):
photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(200,200)))
Do not forget intall pillow
pip install pillow

Related

django.db.models ImageField save Image as Base64

I'm actually new to Django. Let's say I have this model as a class
class UserAccount(AbstractBaseUser, PermissionsMixin):
...
profile_photo = models.ImageField(
upload_to='photos/profile-picture', blank=True)
objects = UserAccountManager()
def __str__(self):
return self.email
I want to save the profile_photo attribute as a base64 file (instead of file path). How do I do that?
Context : In my client side (front-end), I can't render the image by getting its file path. So I want to save the image as base64 string in the DB instead of actual image path so that it will be easier to render in the front end
ImageField has "url" property. It's will combine with MEDIA_URL in the project's setting.

Django Signals - How to save the instance

I am using Django Rest Framework to upload videos. Now I wanted to add thumbnails to my video files. Whenever a Video object is saved, I wanted to create a thumbnail and set its thumbnail field.
My Video model looks like this:
class Video(models.Model):
created = models.DateTimeField(auto_now_add=True)
text = models.CharField(max_length=100, blank=True)
video = models.FileField(upload_to='Videos/',blank=True)
thumbnail = models.ImageField(upload_to = 'Images/', blank = True)
My signal handler looks like this:
from moviepy.video.io.VideoFileClip import VideoFileClip
from posts.models import Video
from django.db.models.signals import post_save
from django.dispatch import receiver
from settingsFolderOfProject.settings import MEDIA_ROOT
import os
# when save() of Video is done, create_thumbnail_from_video() is called
#receiver(post_save, sender=Video)
def create_thumbnail_from_video(sender, instance, created, **kwargs):
if created:
# create the clip using moviepy's VideoFileClip class
clip = VideoFileClip(os.path.join(MEDIA_ROOT, instance.video.name))
# create the frame at 1st second and set it to instance's thumbnail field
instance.thumbnail = clip.save_frame(os.path.join(MEDIA_ROOT, 'Images/thumbnail.jpg'),t='00:00:01')
# save the instance
instance.save() # <--- I think this op does not work properly
What I have to change?
The thumbnail file gets created in the folder as expected but Django does not set the thumbnail field of my Video model instance. The thumbnail field of the created Video instance is still set to null.
clip.save_frame() doesn't return anything.
Instead do
path = os.path.join(MEDIA_ROOT, 'Images/thumbnail.jpg')
clip.save_frame(path,t='00:00:01')
instance.thumbnail = path
instance.save()
Note: Haven't tested yet. Comment if problem still persists. Thnx...

How can I thumbnail images in serialization of Django REST Framework?

I recently jumped into Django REST Framework. Before using it, I thumbnailed images using django-imagekit. Like you see the models below, it worked well, so I used original size images from image and thumbnailed size images from image_thumbnail.
models.py
class Image(models.Model):
...
image = ProcessedImageField(null=True, blank=True, upload_to=image_path,
processors=[Thumbnail(1000, 1400)], format='JPEG')
image_thumbnail = ImageSpecField(
source='image', format='JPEG', options={'quality': 40})
...
The problem is I can't use image_thumbnail in my serializers. I can use image, but image_thumbnail throws an error message A server error occurred. Please contact the administrator.
serializers.py
class ImageRandomSerializer(ModelSerializer):
class Meta:
model = Image
fields = ('image', 'image_thumbnail', )
Can I not thumbnailed images from models.py in serializers.py? Should I thumbnail them with some Django REST Framework thumbnail tool?
UPDATE
After setting DEBUG=True, it throws the error 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte.
I just found the answer from here.
Added image_thumbnail = ImageField(read_only=True), and now it's working well.
from rest_framework.serializers import ImageField
class ImageRandomSerializer(ModelSerializer):
store = StoreDomainKeySerializer()
image_thumbnail = ImageField(read_only=True)
class Meta:
model = Image
fields = ('store', 'image', 'image_thumbnail',)

Django Model store image file size

I am using Django 1.6. I have a model for uploading image files that looks like this.
class Image(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
url = models.ImageField(upload_to=get_image_path,
null=True,
blank=True,
height_field = 'height',
width_field = 'width',
verbose_name='Image')
height = models.IntegerField(blank=True)
width = models.IntegerField(blank=True)
size = models.IntegerField(blank=True)
format = models.CharField(max_length=50)
caption = models.CharField(max_length=255)
def clean(self):
self.size = self.url.size
class Meta:
db_table = 'image'
As you can see, I am storing the size of the image when the clean() method is called. This works for what I want to do, but is this best practise? Is there a better way to automatically save the image's file size when saving?
The second part of my question is how can I get the content type as well?
Thanks,
Mark
Model.clean() should be used for validation - do not use it to update/save the data, but rather use it to correct any invalid data (or throw an exception/error message).
You may want to consider not even storing the size of the image in the database, given that you can access it from the ImageField - it eliminates the possibility of the data becoming inconsistent as it changes over time.
I believe this question/answer should address your second question.
For the first question
Check out the Python Imaging Library PIL on this thread.
from PIL import Image
im=Image.open(filepath)
im.size # (width,height) tuple
For the second question
HttpRequest.META, more specifically HttpRequest.META.get('CONTENT_TYPE')
from this thread

Getting IOError when using pre_save signal to store a thumbnail

I have a model that has an option photo field. When a photo is added, I want a thumbnail to be automatically created and stored. However, when I do this with a pre_save signal, I keep getting an IOError, and if I try to do it with a post_save signal I can't save the thumbnails path to my model without creating and infinite post_save loop.
Here's the code
# using PIL
from PIL import Image
import os
...
# my model
class Course(models.Model):
...
photo = models.ImageField(upload_to='course_images/', blank=True, null=True)
thumbnail = models.ImageField(upload_to='course_images/thumbnails/', blank=True, null=True, editable=False)
...
# my pre_save signal
def resize_image(sender, instance, *args, **kwargs):
'''Creates a 125x125 thumbnail for the photo in instance.photo'''
if instance.photo:
image = Image.open(instance.photo.path)
image.thumbnail((125, 125), Image.ANTIALIAS)
(head, tail) = os.path.split(instance.photo.path)
(a, b) = os.path.split(instance.photo.name)
image.save(head + '/thumbnails/' + tail)
instance.thumbnail = a + '/thumbnails/' + b
models.signals.pre_save.connect(resize_image, sender=Course)
I figured it out. The problem I was having was trying to save the thumbnail field, and I was trying to do that within a signal. So to fix that I save the thumbnail field in the models save() function instead, and leave the signal to create the thumbnail.
Just took me awhile to figure out :/