how to render PNG images without background in django templates? - django

I need to display the png transparent image in the frontend but am unable to format it correctly.
i have tried to change the format to png but it is rendering a black background to it.
class HelpCategories(models.Model):
Name1 = (
('Getting Started','Getting Started'),
('Pricing','Pricing'),
('Integration','Integration'),
('Security','Security'),
('Product Professionals','Product Professionals'),
('About Products','About Products'),
)
Title = models.CharField(max_length=40, default='Getting Started')
image = ImageField(upload_to='help_image', null=True, blank=True)
def __str__(self):
return self.Title
def save(self, *args, **kwargs):
if self.image:
imageTemporary = Image.open(self.image).convert('RGB')
outputIoStream = BytesIO()
imageTemporaryResized = imageTemporary.resize((400,400))
imageTemporaryResized.save(outputIoStream, format='PNG', quality=300)
outputIoStream.seek(0)
self.image = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.png" % self.image.name.split('.')[0], 'image/png', sys.getsizeof(outputIoStream), None)
super(HelpCategories, self).save(*args, **kwargs)
I need to be able to see only the image object in the template.

Related

Django custom save model creating duplicate files

I'm trying to get image uploads to also save as thumbnails, which works. The problem was when I did an update the custom method saved the thumbnail again in a different directory. so I modified my save function to look like this.
models.py
class Photo(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=255)
created = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='photos/%Y%m')
thumbnail = models.ImageField(blank=True, upload_to='thumbnails/%Y%m')
submitter = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
year = models.ForeignKey(Year, blank=True, on_delete=models.CASCADE)
people = TaggableManager(through=TaggedPeople, verbose_name='People')
tags = TaggableManager(through=TaggedGeneric, verbose_name='Tags')
def save(self, *args, **kwargs):
try:
this = Photo.objects.get(id=self.id)
if this.thumbnail != self.thumbnail:
this.thumbnail.delete(save=False)
except:
if self.thumbnail:
img = Image.open(BytesIO(self.thumbnail.read()))
if hasattr(img, '_getexif'):
exif = img._getexif()
if exif:
for tag, label in ExifTags.TAGS.items():
if label == 'Orientation':
orientation = tag
break
if orientation in exif:
if exif[orientation] == 3:
img = img.rotate(180, expand=True)
elif exif[orientation] == 6:
img = img.rotate(270, expand=True)
elif exif[orientation] == 8:
img = img.rotate(90, expand=True)
img.thumbnail((360,360), Image.ANTIALIAS)
output = BytesIO()
img.save(output, format='JPEG', quality=95)
output.seek(0)
self.thumbnail = File(output, self.thumbnail.name)
return super().save(*args, **kwargs)
def __str__(self):
return self.title
and my views
class PhotoCreateView(LoginRequiredMixin, CreateView):
model = Photo
fields = ['image', 'title', 'description', 'year', 'people', 'tags']
template_name = 'photoapp/create.html'
success_url = '/photo/?page=1'
extra_context = {'tags':GenericTag.objects.all().order_by('name'),'people':PeopleTag.objects.all().order_by('name'),}
def form_valid(self, form):
form.instance.thumbnail = self.request.FILES['image']
form.instance.submitter = self.request.user
return super().form_valid(form)
class PhotoUpdateView(LoginRequiredMixin, UpdateView):
template_name = 'photoapp/update.html'
model = Photo
fields = ['title', 'description', 'year', 'people', 'tags']
success_url = '/photo/?page=1'
So the CreateView now works fine, and I have stopped the duplicate thumbnail files, but the UpdateView does not work. How can I fix this?
I figured it out. I just had to add a save to the try section.
def save(self, *args, **kwargs):
try:
this = Photo.objects.get(id=self.id)
if this.thumbnail != self.thumbnail:
this.thumbnail.delete(save=False)
return super().save(*args, **kwargs)
except:
if self.thumbnail:
img = Image.open(BytesIO(self.thumbnail.read()))
if hasattr(img, '_getexif'):
exif = img._getexif()
if exif:
for tag, label in ExifTags.TAGS.items():
if label == 'Orientation':
orientation = tag
break
if orientation in exif:
if exif[orientation] == 3:
img = img.rotate(180, expand=True)
elif exif[orientation] == 6:
img = img.rotate(270, expand=True)
elif exif[orientation] == 8:
img = img.rotate(90, expand=True)
img.thumbnail((360,360), Image.ANTIALIAS)
output = BytesIO()
img.save(output, format='JPEG', quality=95)
output.seek(0)
self.thumbnail = File(output, self.thumbnail.name)
return super().save(*args, **kwargs)
I had a similar complaint in Django-Wagtail, where saving image.save() programmatically duplicated on the file system the imported image. Do get around this I used Python Glob to get the path, and OS to remove the original image after the save function had been loaded. It worked well enough for Wagtail, I wanted to capture the issue for others - as there isn't much on the web about this. It's frustrating, doubles your disk space usage due to this functionality if you aren't careful! I don't like that it renames the files/moves them, but it is what it is.
from django.core.management.base import BaseCommand, CommandError
from wagtail.images.models import Image
from django.core.files.images import ImageFile
import os
from os import path
import glob
#import sqlite3
class Command(BaseCommand):
help = "just a thing to "
def handle(self, *args, **options):
target_path = "/home/inmyth/inmyth/media/images/"
my_images = []
if os.path.exists(target_path):
my_images = glob.glob(target_path + "*.png")
for mj_imgs in my_images:
print(mj_imgs)
image_file = ImageFile(open(mj_imgs, 'rb'), name=mj_imgs[:-4])
img_label = mj_imgs.rfind("/") + 1
image = Image(title=mj_imgs[img_label:-4], file=image_file)
image.save()
os.remove(mj_imgs)
pass

How to force a FilerImageField to convert image format

I'm trying to force certain FilerImageFields to be convert to another format on saving.
I've created this model
class SearchImage(FilerImageField):
def convert_to_webp(self):
print("in convert")
extension = ['jpeg', 'png', 'jpg', 'img', 'gif']
if any(ext in self.file.name.lower() for ext in extension):
#try:
img = Image.open(self.file)
correggi_nome = self.file.name.split('.')[0]
img.save(correggi_nome + '.webp','webp')
logger.debug('img.save save another copy of the file not repalced the original!')
#except Exception as ex:
# logger.error(ex)
def save(self, *args, **kwargs):
self.convert_to_webp()
print("Save search image")
super().save()
class Organisation(models.Model):
....
search_image = SearchImage(
related_name='+',
verbose_name=_('Search thumbnail image'),
help_text=_('Search thumbnail image'),
on_delete=models.SET_NULL,
blank=True,
null=True
)
....
def save(*args, **kwargs):
print('saving')
print("just before search thumbnail save")
self.search_image.save()
print("just after search thumbnail save")
super.save()
my SeachImage.save() is never called. When I save an image (or organisation) I see the print statements within the Organisation.save() but not the SearchImage.save(). How to I get this to work?
Okay so I went down a bit of a rabbit hole but it looks like you want to overwrite the Image object's save method, not the FilerImageField, which is a ForeignKey object:
class MyImageModel(Image):
def convert_to_webp(self):
print('in convert')
extension = ['jpeg', 'png', 'jpg', 'img', 'gif']
if any(ext in self.file.name.lower() for ext in extension):
print('Doing the conversion')
def save(self, *args, **kwargs):
self.convert_to_webp()
print('Save search image')
super().save(*args, **kwargs)
class SearchImage(FilerImageField):
default_model_class = MyImageModel
class Organisation(models.Model):
search_image = FilerImageField(
verbose_name='Search thumbnail image',
help_text='Search thumbnail image',
on_delete=models.SET_NULL,
blank=True,
null=True
)
def save(self, *args, **kwargs):
self.search_image.save()
super().save(*args, **kwargs)

How to compress images before uploading them to Amazon s3 using django storages and django rest framework?

I'm trying to compress the images before uploading them to the amazon s3 server, but I couldn't do it, I used 'PIL', to do it, but it didn't work
This is the code I used with the library 'PIL':
from io import BytesIO
from PIL import Image
from django.core.files import File
def compress(image):
im = Image.open(image)
im_io = BytesIO()
im.save(im_io,'PNG', quality=70)
new_image = File(im_io, name=image.name)
return new_image
class MyModel(models.Model):
file = models.FileField(blank=True, null=True, validators=[validateFileSize])
def save(self, *args, **kwargs):
new_image = compress(self.file)
self.file = new_image
super().save(*args, **kwargs)
I solved it using the following code
def compress(image):
im = Image.open(image)
# create a BytesIO object
im_io = BytesIO()
# save image to BytesIO object
#im = im.resize([500,500])
im = im.convert("RGB")
im = im.save(im_io,'JPEG', quality=70)
# create a django-friendly Files object
new_image = File(im_io, name=image.name)
return new_image
class Media(models.Model):
file = models.FileField(blank=True, null=True, validators=[validateFileSize])
def __str__(self):
return str(self.id)
def save(self, *args, **kwargs):
if self.file:
if self.file.size > (300 * 1024):
# call the compress function
new_image = compress(self.file)
# set self.image to new_image
self.file = new_image
# save
super().save(*args, **kwargs)

django-resized // When upload png file, it's extension changed to .apng

I am using the django-resized package to resize the image.
When I upload a PNG file using this package, the extension is changed to apng.
I don't want this extension to change..
Other image files are normally uploaded.
What should I fix it?
Background
- django==2.1.5
- django-resized==0.3.9
When use Django's default model.ImageField, the extension of png does not change.
# models.py
def upload_to(instance, filename):
return 'vip/{username}/{filename}'.format(
username=instance.whose.whose.username, filename=filename)
class VipIndex(models.Model):
whose = models.OneToOneField(Profile, on_delete=models.CASCADE, related_name='vipindex')
main_big_image = ResizedImageField(crop=['middle', 'center'], size=[500, 300], quality=50, blank=True, upload_to=upload_to)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
# forms.py
class VipMainForm(forms.ModelForm):
class Meta:
model = VipIndex
fields = (
'main_big_image',
)
def __init__(self, *args, **kwargs):
super(VipMainForm, self).__init__(*args, **kwargs)
self.fields['main_big_image'].widget.attrs = {'autocomplete': 'off', 'class': 'form-control'}
# views.py
#login_required
def profile_2(request):
if request.method == 'POST':
form_main = VipMainForm(request.POST, request.FILES)
if form_main.is_valid():
nav = form_main.save(commit=False)
nav.whose = request.user.profiles
nav.save()
return redirect('profile_2')
else:
form_main = VipMainForm()
return render(request, 'accounts/profile_2.html', {
'form_main':form_main,
})
Are there specific settings to keep the extension of the png file?
Add the following to settings.py
DJANGORESIZED_DEFAULT_FORMAT_EXTENSIONS = {'PNG': ".png"}
and it will override saving the file as .apng

What is 'get_source_filename()' used for in Django?

I am getting the following error:
'MyProfile' object has no attribute 'get_source_filename'
The following code is from a previously answered SO question, so I'm not sure what get_source_filename() is or does. A google search turned up nothing.
class MyProfile(UserenaBaseProfile):
coverpic = models.ImageField(upload_to="site_media/media/covers/", null=True, blank=True)
def save(self, *args, **kwargs):
# Did we have to resize the image?
# We pop it to remove from kwargs when we pass these along
image_resized = kwargs.pop('image_resized',False)
super(MyProfile, self).save(*args, **kwargs)
if self.coverpic:
print "yes"
basewidth = 300
filename = self.get_source_filename()
image = Image.open(filename)
wpercent = (basewidth/float(image.size[0]))
hsize = int((float(image.size[1])*float(wpercent)))
img = image.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
self.coverpic = img
self.coverpic.save