Python PIL | RGB values are wrong - python

I am making a steganography program. I got it to work without PIL but it only works with bitmaps, so I did some research and I found and learned general PIL. I converted my algorithm to be compatible with PIL and it looks like it works, but when I go to decode it seems like it pulls numbers out of nowhere. After some debugging I believe there to be a pattern of sorts because it is only a few values off.
To further debug I've created a similar program that makes the image completely red, then reopens it and reads its pixel values, however, I seem to be encountering the same error. The weird thing is that my computer science teacher, who uses Python 2, isn't encountering this error. I was wondering if any more experienced PIL users know why this is and any fixes. I am using Python 3 on Windows 10.
Here is my code (This is the program I made for debugging):
from PIL import Image
def redify(file_name): #Function that turns the whole image red
image = Image.open(file_name)
image = image.convert("RGB")
pixels = list(image.getdata())
fileTypeIndex = 0
for i in range(0,len(file_name)):
if file_name[-i] == ".":
fileTypeIndex = i
break
for x in range(0,len(pixels)):
pixels[x] = 255,0,0
final = Image.new(image.mode,image.size)
final.putdata(pixels)
final.save(file_name[:-fileTypeIndex] + "_redified" + file_name[-fileTypeIndex:])
def readImage(file_name): #Fucntion that opens an image and reads its data
image = Image.open(file_name)
image = image.convert("RGB")
rgbList = list(image.getdata())
print(rgbList) # This returns every pixel as (254,0,0)
# When I set each pixel to 0,255,0 it returns (0,255,1)
# When I set each pixel to 0,0,255 it returns (0,0,254)
# All of these shouldn't be occuring
redify("moon.jpg")
readImage("moon_redified.jpg")

Related

RGB Values Being Returned by PIL don't match RGB color

I'm attempting to make a reasonably simple code that will be able to read the size of an image and return all the RGB values. I'm using PIL on Python 2.7, and my code goes like this:
import os, sys
from PIL import Image
img = Image.open('C:/image.png')
pixels = img.load()
print(pixels[0, 1])
now this code was actually gotten off of this site as a way to read a gif file. I'm trying to get the code to print out an RGB tuple (in this case (55, 55, 55)) but all it gives me is a small sequence of unrelated numbers, usually containing 34.
I have tried many other examples of code, whether from here or not, but it doesn't seem to work. Is it something wrong with the .png format? Do I need to further code in the rgb part? I'm happy for any help.
My guess is that your image file is using pre-multiplied alpha values. The 8 values you see are pretty close to 55*34/255 (where 34 is the alpha channel value).
PIL uses the mode "RGBa" (with a little a) to indicate when it's using premultiplied alpha. You may be able to tell PIL to covert the to normal "RGBA", where the pixels will have roughly the values you expect:
img = Image.open('C:/image.png').convert("RGBA")
Note that if your image isn't supposed to be partly transparent at all, you may have larger issues going on. We can't help you with that without knowing more about your image.

Freeimage plugin mirrors RGB arrays if saving in 16-bit

I am working with 2D floating-point numpy arrays and saving them as .png files with high precision (see this question for how I came to this point). To do this I use the freeimage plugin, as in that linked question.
This creates a weird behaviour where the images are flipped (both left-right and up-down) if saved to 16-bit. This behaviour happens only for RGB or RGBA images, not for greyscale images. Here is some example code:
from skimage import io, img_as_uint, img_as_ubyte
im = np.random.uniform(size=(256, 256))
im[:128, :128] = 1
im = img_as_ubyte(im)
io.use_plugin('freeimage')
io.imsave('test_1.png', im)
creates the following picture:
when I try to save this in 16 bit, I get the same result (albeit taking 99kb instead of 50, so I know the bitdepth is working).
Now do the same as an RGB image:
im = np.random.uniform(size=(256, 256, 3))
im[:128, :128] = 1
im = img_as_ubyte(im)
io.use_plugin('freeimage')
io.imsave('test_1.png', im)
The 8-bit result is:
but doing the following
im = img_as_uint(im)
io.use_plugin('freeimage')
io.imsave('test_1.png', im)
gives me
This happens if the array contains an alpha level too.
It can be fixed by including
im = np.fliplr(np.flipud(im))
before saving. However, it seems to me this is pretty weird behaviour and not very desirable. Any idea why this is happening or whether it is intended? As far as I could see it's not documented.

Python PIL: Convert RGBA->P - ValueError: image has wrong mode [duplicate]

I would like to convert a PNG32 image (with transparency) to PNG8 with Python Image Library.
So far I have succeeded converting to PNG8 with a solid background.
Below is what I am doing:
from PIL import Image
im = Image.open("logo_256.png")
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
im.save("logo_py.png", colors=255)
After much searching on the net, here is the code to accomplish what I asked for:
from PIL import Image
im = Image.open("logo_256.png")
# PIL complains if you don't load explicitly
im.load()
# Get the alpha band
alpha = im.split()[-1]
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
# Set all pixel values below 128 to 255,
# and the rest to 0
mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0)
# Paste the color of index 255 and use alpha as a mask
im.paste(255, mask)
# The transparency index is 255
im.save("logo_py.png", transparency=255)
Source: http://nadiana.com/pil-tips-converting-png-gif
Although the code there does not call im.load(), and thus crashes on my version of os/python/pil. (It looks like that is the bug in PIL).
As mentioned by Mark Ransom, your paletized image will only have one transparency level.
When saving your paletized image, you'll have to specify which color index you want to be the transparent color like this :
im.save("logo_py.png", transparency=0)
to save the image as a paletized colors and using the first color as a transparent color.
This is an old question so perhaps older answers are tuned to older version of PIL?
But for anyone coming to this with Pillow>=6.0.0 then the following answer is many magnitudes faster and simpler.
im = Image.open('png32_or_png64_with_alpha.png')
im = im.quantize()
im.save('png8_with_alpha_channel_preserved.png')
Don't use PIL to generate the palette, as it can't handle RGBA properly and has quite limited quantization algorithm.
Use pngquant instead.

python PIL - Convert [animated] gif frames to JPG but artifacts

Edit: The problem with my original search for information was that I did not distinguish between gifs and "animated gifs". Hence there are a lot of resources on SO to deal with this question.
Resources:
Link 3
Evidently PIL itself is poorly equipped to deal with animated gifs.
I'm trying to convert gif frames to jpg. For some gifs (mostly black and white) this works out fine, but for others (mostly color) not so much. I've looked at a few of the posts on SO, and tried them, to no avail. In particular I tried out: Link1 , Link2.
Performance is a mild consideration, but for now I'd just like a working solution. A consistent pattern is that the first image of the gif will always come out perfect. Interestingly enough, I have even tried out Zamzar and it also produces the same noise data. I was doing some research and it seems that this might be an issue with the LZW compression algorithm, though on SO, I've seen posts that suggest PIL takes care of LZW decompression. On the other hand I've heard that LZW decompression is propitiatory.
Note that I've also tried converting to PNG without success there either. Are the white dots layered on top of the image or something?
Here is a sample gif that produces this error.
Edit: I just came across images2gif.py. I will update this post if it works for this problem.
Here is the code I'm using:
from PIL import Image
import sys
import os
def processImage(infile):
try:
im = Image.open(infile)
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
mypalette = im.getpalette()
try:
while 1:
im.putpalette(mypalette)
new_im = Image.new("RGB", im.size)
#new_im = Image.new("RGB", im.size)
new_im.paste(im)
new_im.save('foo'+str(i)+'.png')
#if(os.stat('foo' + str(i)+'.png')):
# os.remove('foo' + str(i) + '.jpg')
i += 1
mypalette = im.getpalette()
im.seek(im.tell() + 1)
except EOFError:
pass # end of sequence

Transparent PNG in PIL turns out not to be transparent

I have been hitting my head against the wall for a while with this, so maybe someone out there can help.
I'm using PIL to open a PNG with transparent background and some random black scribbles, and trying to put it on top of another PNG (with no transparency), then save it to a third file.
It comes out all black at the end, which is irritating, because I didn't tell it to be black.
I've tested this with multiple proposed fixes from other posts. The image opens in RGBA format, and it's still messed up.
Also, this program is supposed to deal with all sorts of file formats, which is why I'm using PIL. Ironic that the first format I tried is all screwy.
Any help would be appreciated. Here's the code:
from PIL import Image
img = Image.open(basefile)
layer = Image.open(layerfile) # this file is the transparent one
print layer.mode # RGBA
img.paste(layer, (xoff, yoff)) # xoff and yoff are 0 in my tests
img.save(outfile)
I think what you want to use is the paste mask argument.
see the docs, (scroll down to paste)
from PIL import Image
img = Image.open(basefile)
layer = Image.open(layerfile) # this file is the transparent one
print layer.mode # RGBA
img.paste(layer, (xoff, yoff), mask=layer)
# the transparancy layer will be used as the mask
img.save(outfile)

Categories

Resources