Reputation: 548
I am working Crop Images in a Django Application
using this tutorial Crop Images in Django
Myform:
class UploadImageForm(forms.ModelForm):
x = forms.FloatField(widget=forms.HiddenInput())
y = forms.FloatField(widget=forms.HiddenInput())
width = forms.FloatField(widget=forms.HiddenInput())
height = forms.FloatField(widget=forms.HiddenInput())
primaryphoto = forms.ImageField(required=False,
error_messages={'invalid': _("Image files only")}, widget=forms.FileInput)
class Meta:
model = User
fields = ['primaryphoto', 'x', 'y', 'width', 'height',]
def save(self):
user = super(UploadImageForm, self).save()
x = self.cleaned_data.get('x')
y = self.cleaned_data.get('y')
w = self.cleaned_data.get('width')
h = self.cleaned_data.get('height')
image = Image.open(user.primaryphoto)
cropped_image = image.crop((x, y, w + x, h + y))
resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
resized_image.save(user.primaryphoto.path)
return user
myview:
def upload_image(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
form.save()
return redirect('/profile')
else:
form = UploadImageForm(instance=request.user)
return render(request, 'student/uploadimageform.html', {'form': form})
storage_backend.py:
from storages.backends.s3boto3 import S3Boto3Storage
class MediaStorage(S3Boto3Storage):
location = 'media'
file_overwrite = False
However, when I uploaded it to run on AWS, I got the error message that the backend does not support absolute paths (in reference to primaryphoto.path in the form where the photo is cropped)
. I was wondering what I have to change to get it working with S3. I've found some resources that say change primaryphoto.path to primaryphoto.name, but that hasn't worked for me. I was wondering if you had any recommendations to solve this problem?
Here Image is uploaded to S3 Bucket but issue is throwing above error. Please help me anyone. Thanks in advance ...
Edit answer:
def save(self):
user = super(UploadImageForm, self).save()
x = self.cleaned_data.get('x')
y = self.cleaned_data.get('y')
w = self.cleaned_data.get('width')
h = self.cleaned_data.get('height')
try:
image = Image.open(user.primaryphoto)
cropped_image = image.crop((x, y, w + x, h + y))
resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
resized_image.save(user.primaryphoto.path)
except:
pass
return user
Here issue is throwing error but image is uploading locally and S3 bucket properly ... for handling path error i am using try, except block
Upvotes: 5
Views: 15084
Reputation: 41
For me default.storage.write() did not work, image.save() did not work, this one worked. See this code if anyone is still interested. I apologize for the indentation. My project was using Cloudinary and Django small project.
from io import BytesIO
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage as storage
def save(self, *args, **kargs):
super(User, self).save(*args, **kargs)
# After save, read the file
image_read = storage.open(self.profile_image.name, "r")
image = Image.open(image_read)
if image.height > 200 or image.width > 200:
size = 200, 200
# Create a buffer to hold the bytes
imageBuffer = BytesIO()
# Resize
image.thumbnail(size, Image.ANTIALIAS)
# Save the image as jpeg to the buffer
image.save(imageBuffer, image.format)
# Check whether it is resized
image.show()
# Save the modified image
user = User.objects.get(pk=self.pk)
user.profile_image.save(self.profile_image.name, ContentFile(imageBuffer.getvalue()))
image_read = storage.open(user.profile_image.name, "r")
image = Image.open(image_read)
image.show()
image_read.close()
Upvotes: 2
Reputation: 123
For those redirected here from google, here's code tested and working on aws based on answers from @Alexandar Dimitro and other comments on this page.
from django.core.files.storage import default_storage as storage
def save(self):
user = super(UploadImageForm, self).save()
x = self.cleaned_data.get('x')
y = self.cleaned_data.get('y')
w = self.cleaned_data.get('width')
h = self.cleaned_data.get('height')
image = Image.open(user.primaryphoto)
cropped_image = image.crop((x, y, w + x, h + y))
resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
fh = storage.open(user.primaryphoto.name, "wb")
picture_format = 'png'
resized_image.save(fh, picture_format)
fh.close()
return user
Upvotes: 1
Reputation: 11
This one worked for me. Just replace the save() method in your form.
from django.core.files.storage import default_storage as storage
def save(self):
user = super(UploadImageForm, self).save()
x = self.cleaned_data.get('x')
y = self.cleaned_data.get('y')
w = self.cleaned_data.get('width')
h = self.cleaned_data.get('height')
image = Image.open(user.primaryphoto)
cropped_image = image.crop((x, y, w + x, h + y))
resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
fh = storage.open(user.primaryphoto.name, "w")
picture_format = 'png'
resized_image.save(fh, picture_format)
fh.close()
resized_image.save(user.primaryphoto.path)
return user
Upvotes: 1
Reputation: 8525
Try the following instead.
I don't test it, but some explanations will be good: We convert the image into string buffer in order to create a Django InMemoryUploadedFile
with the cropped image. In this case, we don't use path
. Try it and let me know you face any other errors.
import os
from io import BytesIO as StringIO # python3
from django.core.files.uploadedfile import InMemoryUploadedFile
def save(self):
user = super(UploadImageForm, self).save()
x = self.cleaned_data.get('x')
y = self.cleaned_data.get('y')
w = self.cleaned_data.get('width')
h = self.cleaned_data.get('height')
image = Image.open(user.primaryphoto)
cropped_image = image.crop((x, y, w + x, h + y))
resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
filename = os.path.splitext(resized_image.name)[0]
output = StringIO()
resized_image.save(output, format='JPEG', quality=95)
output.seek(0) #Change the stream position to the given byte offset.
new_image = InMemoryUploadedFile(output,'ImageField',\
"%s.jpg" % filename , 'image/jpeg', output.__sizeof__(), None)
user.primaryphoto = new_image
user.save()
return user
Upvotes: 1