Save 16-bit PGM Image?
I am attempting to convert an image in PNG format to a 16-bit PGM format and save it using Python's PIL library. I'm using Python 3.12.4 in all examples shown.
Using the following test.png image:
Attempting a simple script like this with the Image.save() function:
from PIL import Image
image = Image.open("test.png")
image.save("test.pgm")
Can save resave the image as PGM, however it's always saved as an 8-bit image, as shown by GIMP:
Attempting to specify the amount of pixel bits via the optional bits argument as such:
from PIL import Image
image = Image.open("test.png")
image.save("test.pgm", bits = 16)
Also results in an 8-bit PGM image being saved.
Attempting to manually create a numpy array of the np.uint16 type & then creating an image from it using the Image.fromarray() function as such:
from PIL import Image
import numpy as np
image = Image.open("test.png")
imageData = np.array(image.getdata(), dtype = np.uint16)
newImage = Image.fromarray(imageData)
newImage.save("test.pgm", bits = 16)
Results in:
OSError: cannot write mode I;16 as PPM
I also noticed that this appears to break the image, as saving with np.uint32 saves a blank image with a very narrow horizontal size and a very large vertical size.
What is the proper way to save 16-bit PGM images using the Python PIL library?
Thanks for reading my post, any guidance is appreciated.
Hi. The image that you have provided is an RGBA image. It has 8-bits per channel, so I think it makes perfect sense for it to be saved in 8-bit mode by default.
Converting it to I mode
from PIL import Image
image = Image.open("test.png")
image.convert("I").save("test.pgm")
will save a 16-bit image.
via the optional
bitsargument as such:
Looking at the source code, that isn't a Pillow feature for the PGM format. I'm guessing you saw this used for a PNG image somewhere, and presumed that you could use the same argument when saving a PGM image? That is not the case - Pillow often has format-specific arguments for saving.
I also noticed that this appears to break the image, as saving with
np.uint32saves a blank image with a very narrow horizontal size and a very large vertical size.
im.getdata() returns a "flattened" object, so I expect that's where the size information is being lost. Instead of np.array(image.getdata()), you can pass a Pillow image directly to NumPy with np.array(image)
OSError: cannot write mode I;16 as PPM
I've created https://github.com/python-pillow/Pillow/pull/8231 to fix this.
@SvarunSoda was that answer helpful?