I have a web scraper that I want to download an image of the page it's scraping and save it as a "screenshot" ImageField in a Django model. I am using this code:
def save_screenshot(source,screenshot):
box = (0, 0, 1200, 600)
im = Image.open(io.BytesIO(screenshot))
region = im.crop(box)
tempfile_io = io.BytesIO()
region.save(tempfile_io, 'JPEG', optimize=True, quality=70)
source.screenshot.save(source.slug_name+"-screenshot",ContentFile(tempfile_io.getvalue()),save=True)
It saves the screenshot to the /media/news_source_screenshots/ directory but doesn't save it to the model. The model field is defined as:
screenshot = models.ImageField(upload_to='news_source_screenshots',blank=True,null=True)
What am I missing?
So it turns out the above code works great! The issue was that I was calling the above method using a piece of code like this:
source = NewsSource.objects.get(name=name)
html,screenshot = get_url(source.url)
save_screenshot(source,screenshot)
source.save()
So the save_sceenshot method worked but then the work it had done was overwritten by my source.save() call. Go figure!
Related
I'm trying to create a QR Code in my Django model which creates itself whenever a new record is saved. The problem is that when testing in my dev environment everything is fine but in production I get an error on the specified line below saying: ValueError, images do not match.
from django.core.files import File
import qrcode
from io import BytesIO
from PIL import Image
from datetime import date
# this is the save method of the django model class, I just left out the other methods
def save(self, *args, **kwargs):
img = qrcode.make(self.account_id)
canvas = Image.new('RGB', (400, 400), 'white')
canvas.paste(img) # Error occurs on this line
buffer = BytesIO()
canvas.save(buffer, 'PNG')
canvas.close()
fname = f'pdf-qr-code-{self.account_id}.png'
self.menu_qr_code.save(fname, File(buffer), save=False)
super(PDFMenu, self).save(*args, **kwargs)
I don't know if maybe the problem is with my configurations on my ubuntu server since that's the place where the problem takes place but maybe a new way of creating a qr code within this custom save method is necessary.
Thanks in advance for the help.
Here's my save method for model with field image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True):
def save(self, *args, **kwargs):
if self.image:
self.image = compress(self.image)
if self.second_image:
self.second_image = compress(self.second_image)
if self.third_image:
self.third_image = compress(self.third_image)
if self.fourth_image:
self.fourth_image = compress(self.fourth_image)
super().save(*args, **kwargs)
It works fine and compresses all images but changes image's directory every time when I click save in django admin. It makes all images' paths be like:
before edited and saved: products/2020/11/05/img.jpeg
after: products/2020/11/05/products/2020/11/05/img.jpeg
click save one more time: products/2020/11/05/products/2020/11/05/products/2020/11/05/img.jpeg
And then I get this error:
SuspiciousFileOperation at /admin/shop/product/6/change/
Storage can not find an available filename for "products\2020\11\05\products\2020\11\05\products\2020\...... .jpeg".
Please make sure that the corresponding file field allows sufficient "max_length".
How can I fix this problem? I think I need to choose location where saved images would be stored. Django doesn't let me use absolute path in upload_to field so I have no idea.
compress func is:
from io import BytesIO
from PIL import Image
from django.core.files import File
def compress(image):
im = Image.open(image)
if im.mode != 'RGB':
im = im.convert('RGB')
im_io = BytesIO()
im.save(im_io, 'JPEG', quality=70)
compressed_image = File(im_io, name=image.name)
return compressed_image
The problem is that the filename is updated everytime. At each step, you should make sure that the filename is only a filename. Something like this:
import os
if self.image:
self.image = compress(self.image)
self.image.name = os.path.basename(self.image.name)
I don't know exactly what is your compress function, but maybe you could also check that it doesn't do something weird with the filename.
I am trying transfer a file to Stripe from a firebase database using the stripe.File.create() method. Here is the code that I am using:
file_url = storage.child("/path/to/file").get_url(token=None)
response = requests.get(file_url, stream=True)
img = Image.open(BytesIO(response.content))
stripe.File.create(
purpose="identity_document",
file=img
)
But when I run this code I get:
Request req_E7fskNVgpHHlRm: Invalid hash
I believe I am getting the correct image from firebase, since I can run the following line and get the image saved to my local drive:
img.save("test.jpg")
But Stripe doest not seem to like the file format that I am giving it. I believe the file has to be supplied in binary mode, so perhaps I simply need to do edit the line img = Image.open(BytesIO(response.content)) to get the file in binary mode.
Any feedback is appreciated.
I figured it out. img = Image.open(BytesIO(response.content)) creates a JpegImageFile object, which is an image. But Stripe is expecting a file, something like io.BufferedReader object. So Stripe is saying that you are supplying an image, when really it just wants a file. To fix the issue, just change the img = line to:
imgFile = BytesIO(response.content)
I'm trying to get a image from the web and save it to the imageField using the images url.
The below code spits out a error ('JpegImageFile' object has no attribute '_committed').
from PIL import Image
import urllib.request
import io
if form.is_valid():
instance = form.save(commit=False)
URL = 'http://www.image.jpg'
with urllib.request.urlopen(URL) as url:
file = io.BytesIO(url.read())
img = Image.open(file)
instance.image = img
instance.image has to be of type django.core.files.images.ImageFile I am testing my models with this code. Maybe it points you to the correct direction :
# This gets me a temp Image for testing. In your case it would be a real file
def get_test_image_file(tmpdir=None):
file = tempfile.NamedTemporaryFile(suffix='.png', dir=tmpdir)
return ImageFile(file, name=file.name)
and the for the model test I do :
def test_addimage_create(self):
adimage = AdImage.objects.create(advertiser=self.advertiser,
picture=get_test_image_file(tmpdir=MEDIA_ROOT))
self.assertIsInstance(adimage, AdImage)
so in your case instead of instance.image = img. img has to be an Object of Type ImageFile which then can be assigned to the form.instance. Btw. you should assign the values to the instance before save()
I am writing a script which will get an image from a link. Then the image will be resized using the PIL module and the uploaded to Imgur using pyimgur. I dont want to save the image on disk, instead manipulate the image in memory and then upload it from memory to Imgur.
The Script:
from pyimgur import Imgur
import cStringIO
import requests
from PIL import Image
LINK = "http://pngimg.com/upload/cat_PNG106.png"
CLIENT_ID = '29619ae5d125ae6'
im = Imgur(CLIENT_ID)
def _upload_image(img, title):
uploaded_image = im.upload_image(img, title=title)
return uploaded_image.link
def _resize_image(width, height, link):
#Retrieve our source image from a URL
fp = requests.get(link)
#Load the URL data into an image
img = cStringIO.StringIO(fp.content)
im = Image.open(img)
#Resize the image
im2 = im.resize((width, height), Image.NEAREST)
#saving the image into a cStringIO object to avoid writing to disk
out_im2 = cStringIO.StringIO()
im2.save(out_im2, 'png')
return out_im2.getvalue()
When I run this script I get this error: TypeError: file() argument 1 must be encoded string without NULL bytes, not str
Anyone has a solution in mind?
It looks like the same problem as this, and the solution is to use StringIO.
A common tip for searching such issues is to search using the generic part of the error message/string.