Cannot open jpg images with PIL or open() - python

I am testing to save ImageField in Django, but for some reason all the *.jpg files I've tried don't work while the one png I had works.
Using django shell in WSL VCode terminal.
python 3.7
django 3.0
pillow 7.1.2
If I do with open():
# this has no error
f = open('loko.jpg', 'rb')
#if I do
f.read() # it shows only b'', like its empty
# this saves the field but the image is 0 bytes and cannot be open
object.image.save('name', File(f))
If I do with PIL:
from PIL import Image
# this shows error
# PIL.UnidentifiedImageError: cannot identify image file 'loko.jpg'
img = Image.open('loko.jpg')
With the .png image I've tried, both methods work great.
What could be the problem?

Solution was to update the python-pillow package.
Now it works.

Related

Is there a way of attaching an image on a python code in such a way that it becomes part of the soure code?

I'm a beginner in python and I'm trying to send someone my small python program together with a picture that'll display when the code is run.
I tried to first convert the image to a binary file thinking that I'd be able to paste it in the source code but I'm not sure if that's even possible as I failed to successfully do it.
You can base64-encode your JPEG/PNG image which will make it into a regular (non-binary string) like this:
base64 -w0 IMAGE.JPG
Then you want to get the result into a Python variable, so repeat the command but copy the output to your clipboard:
base64 -w0 IMAGE.JPG | xclip -selection clipboard # Linux
base64 -w0 IMAGE.JPG | pbcopy # macOS
Now start Python and make a variable called img and paste the clipboard into it:
img = 'PASTE'
It will look like this:
img = '/9j/4AAQSk...' # if your image was JPEG
img = 'iVBORw0KGg...' # if your image was PNG
Now do some imports:
from PIL import Image
import base64
import io
# Make PIL Image from base64 string
pilImage = Image.open(io.BytesIO(base64.b64decode(img)))
Now you can do what you like with your image:
# Print its description and size
print(pilImage)
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=200x100>
# Save it to local disk
pilImage.save('result.jpg')
You can save a picture in byte format inside a variable in your program. You can then convert the bytes back into a file-like object using the BytesIO function of the io module and plot that object using the Image module from the Pillow library.
import io
import PIL.Image
with open("filename.png", "rb") as file:
img_binary = file.read()
img = PIL.Image.open(io.BytesIO(img_binary))
img.show()
To save the binary data inside your program without having to read from the source file you need to encode it with something like base64, use print() and then simply copy the output into a new variable and remove the file reading operation from your code.
That would look like this:
img_encoded = base64.encodebytes(img_binary)
print(img_binary)
img_encoded = " " # paste the output from the console into the variable
the output will be very long, especially if you are using a big image. I only used a very small png for testing.
This is how the program should look like at the end:
import io
import base64
import PIL.Image
# with open("filename.png", "rb") as file:
# img_binary = file.read()
# img_encoded = base64.encodebytes(img_binary)
img_encoded = b'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABX[...]'
img = PIL.Image.open(io.BytesIO(base64.decodebytes(img_encoded)))
img.show()
You could perhaps have your Python program download the image from a site where you upload files such as Google Drive, Mega, or Imgur. That way, you can always access and view the image easily without the need of running the program or for example converting the binary back into the image in the method you mentioned.
Otherwise, you could always store the image as bytes in a variable and have your program read this variable. I'm assuming that you really wish to do it this way as it would be easier to distribute as there is only one file that needs to be downloaded and run.
Or you could take a look at pyinstaller which is made for python programs to be easily distributed across machines without the need to install Python by packaging it as an executable (.exe) file! That way you can include the image file together by embedding it into the program. There are plenty of tutorials for pyinstaller you could google up. Note: Include the '--onefile' in your parameters when running pyinstaller as this will package the executable into a single file that the person you're sending it to can easily open whoever it may be-- granted the executable file can run on the user's operating system. :)

Python 3 - How can I open an image in pillow that I already opened using open('image','r')

How can I open an image in pillow that I already opened using open('image','r')
I have an image that I opened using the open() function, but i want to use the image in pillow.
Actually, I encoded it using base64, then the program decodes it,then gives you a variable that is in the same format as the open() function has. Then I just want to show the image, if there is another way to show the image without saving it, please let me know.
Here is the code that I use to decode it, just so you know:
import base64
image_64_encode = 'this-string-is-big-so'
image_64_decode = base64.decodebytes(image_64_encode)
I just want to show the image.
Like this:
from base64 import b64decode
from PIL import Image
import io
# Load useful-looking base64 string of a PNG
b64 = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABAEAIAAAB1mzrKAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0T///////8JWPfcAAAAB3RJTUUH5QsDDgY2fEahewAAANhJREFUeNrt3LENg0AQRcFFOue4/yIhN9K5jAl4UwHS02flAB977z1h1sxzr1M/xnsVAFszz7W++jHeqwVgBcAKgHUDsBaAFQArANYNwFoAVgCsAFg3AFszv/tz6sd4r15BWAGwbgDWArACYAXACoB1hLEWgBUAKwDWDcBaAFYArADYmvldn24A0wKwAmAFwPodgLUArABYAbBuANYCsAJgBcAKgHWEsRaAFQDr+wCsG4D1CsIKgBUA6wZgLQArAFYArBuAtQCsAFgBsG4A1gKwY++Z/sDe+QP/bITzNFwkpgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMS0xMS0wM1QxNDowNjo1NCswMDowMGz+3A4AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjEtMTEtMDNUMTQ6MDY6NTQrMDA6MDAdo2SyAAAAAElFTkSuQmCC'
# Open it with PIL - no disk access required
im = Image.open(io.BytesIO(b64decode(b64)))
print(im)
# prints: <PIL.PngImagePlugin.PngImageFile image mode=RGB size=64x64 at 0x7FF3B90251C0>
The clue is here in the Pillow documentation where it says:
fp – A filename (string), pathlib.Path object or a file object.

Unable to convert imgkit image to PIL image

I am trying to convert an imgkit image into a PIL image to modify it. imgkit successfully converted the html to image when I tried to use a file. When I use BytesIO and try to convert to a PIL image, im getting an error.
Here is my code:
img = imgkit.from_string(template.render(a=elements, r=range(len(elements))), False, config=config)
bytesImg = BytesIO(img)
bytesImg.seek(0)
image = Image.open(bytesImg) #error here
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x102082680>
I already saw this and this.
Am I incorrectly converting the imgkit image to bytes or is there some other error?
Using Pillow 8.1 Python 3.9 and imgkit 1.0.2
Am I incorrectly converting the imgkit image to bytes or is there some other error?
I would start from checking if your bytes represents image understand by your Pillow. Built-in module imghdr should suffice if you are excepting one of format known by it (see table in docs). Usage in this case:
import imghdr
...
print(imghdr.what(None, h=img))
If it does identify format then check if it is supported by your Pillow, else you would need to manually check file signature (few starting bytes).
imgkit was converting the html to pdf because the config variable was messed up.
use
which wkhtmltoimage
to find path to wkhtmltoimage and set
config = imgkit.config(wkhtmltoimage="path found")

Read/Open image from instance of Python io.BufferedReader class

I'm struggling to properly open a TIFF image from an instance of Python's io.BufferedReader class. I download the image from a GCS path using the below lib, but I can't open seem to open the image with traditional tools.
# returns the <_io.BufferedReader>
file = beam.io.gcp.gcsio.GcsIO().open("<GCS_PATH>", 'r')
from PIL import Image
img = Image.open(file.read()) <---- Fails with "TypeError: embedded NUL character"
img = Image.open(file.raw) <--- Fails when any operations are performed with "IOError(err)"
I am open to other libraries besides PIL.
UPDATE
The following also fails:
img = Image.open(file)
It fails with an IOError, stating tempfile.tif: Cannot read TIFF header.
Make sure you wrap both in a ContextManager so they both get closed properly.
with beam.io.gcp.gcsio.GcsIO().open(file_path, 'r') as file, Image.open(io.BytesIO(file.read())) as multi_page_tiff:
do_stuff()

Python PIL Paste

I want to paste a bunch of images together with PIL. For some reason, when I run the line blank.paste(img,(i*128,j*128)) I get the following error: ValueError: cannot determine region size; use 4-item box
I tried messing with it and using a tuple with 4 elements like it said (ex. (128,128,128,128)) but it gives me this error: SystemError: new style getargs format but argument is not a tuple
Each image is 128x and has a naming style of "x_y.png" where x and y are from 0 to 39. My code is below.
from PIL import Image
loc = 'top right/'
blank = Image.new("RGB", (6000,6000), "white")
for x in range(40):
for y in reversed(range(40)):
file = str(x)+'_'+str(y)+'.png'
img = open(loc+file)
blank.paste(img,(x*128,y*128))
blank.save('top right.png')
How can I get this to work?
This worked for me, I'm using Odoo v9 and I have pillow 4.0.
I did it steps in my server with ubuntu:
# pip uninstall pillow
# pip install Pillow==3.4.2
# /etc/init.d/odoo restart
You're not loading the image correctly. The built-in function open just opens a new file descriptor. To load an image with PIL, use Image.open instead:
from PIL import Image
im = Image.open("bride.jpg") # open the file and "load" the image in one statement
If you have a reason to use the built-in open, then do something like this:
fin = open("bride.jpg") # open the file
img = Image.open(fin) # "load" the image from the opened file
With PIL, "loading" an image means reading the image header. PIL is lazy, so it doesn't load the actual image data until it needs to.
Also, consider using os.path.join instead of string concatenation.
For me the methods above didn't work.
After checking image.py I found that image.paste(color) needs one more argument like image.paste(color, mask=original). It worked well for me by changing it to this:
image.paste(color, box=(0, 0) + original.size)

Categories