Convert RGBA PNG to RGB with PIL
Here's a version that's much simpler - not sure how performant it is. Heavily based on some django snippet I found while building RGBA -> JPG + BG
support for sorl thumbnails.
from PIL import Image
png = Image.open(object.logo.path)
png.load() # required for png.split()
background = Image.new("RGB", png.size, (255, 255, 255))
background.paste(png, mask=png.split()[3]) # 3 is the alpha channel
background.save('foo.jpg', 'JPEG', quality=80)
Result @80%
Result @ 50%
Convert RGBA to RGB in Python
You probably want to use an image's convert method:
import PIL.Image
rgba_image = PIL.Image.open(path_to_image)
rgb_image = rgba_image.convert('RGB')
PIL Loading a Transparent PNG as RGB?
The below code is working for me:
from PIL import Image
import requests
import StringIO
url = "https://gis.apfo.usda.gov/arcgis/rest/services/NAIP/Tennessee_2016_60cm/ImageServer/exportImage?bbox=-87.1875,34.3071438563,-84.375,36.5978891331&bboxSR=4326&size=256,256&imageSR=102113&transparent=true&format=png&f=image"
resp = requests.get(url)
content = StringIO.StringIO(resp.content)
image = Image.open(content)
image = image.convert('RGBA')
composite = Image.new("RGBA", image.size, (255,255,255,0))
composite.paste(image )
PIL Image.save() convert doesn't maintain RGB color
You can do something like the following
image_with_detections = np.array(image_with_detections)
image = Image.fromarray(image_with_detections.astype('uint8'), 'RGB')
image = image[:,:,::-1]
image.save(save_path)
Why PIL convert('RGB') makes some transparent into black but some into white?
Both images have transparency in them, it's just that one has white pixels made transparent and the other has black pixels made transparent. Another way of saying the same thing is that the underlying colour of transparent pixels is black in one image and white in the other. You can't see the difference because they are transparent!
Here is lenna1
with the alpha layer removed on the left, then the alpha layer itself on the right:
And here is lenna2
with the alpha layer removed on the left, then the alpha layer itself on the right:
You can make them the same by finding all the transparent pixels, and making them white like this:
# Load the image and make into Numpy array
rgba = np.array(Image.open('lena2.png'))
# Make image transparent white anywhere it is transparent
rgba[rgba[...,-1]==0] = [255,255,255,0]
# Make back into PIL Image and save
Image.fromarray(rgba).save('result.png')
If you want to make the transparent pixels visible blue so you can see them for testing, use:
rgba[rgba[...,-1]==0] = [0,0,255,255]
If you have ImageMagick installed, you can force all transparent pixels to become the colour of your choice, say magenta, in Terminal:
magick lenna1.png -background magenta -alpha background result.png
That often means you can improve PNG compression and decrease PNG file sizes by making all transparent pixels black and, as a result, the image is likely to compress much better than if the transparent pixels are all wildly different colours:
magick image.png -background black -alpha background result.png
Saving png sequence as WebP in pil makes background opaque black
Fixed it - there was literally 1 character wrong with your code!
Inside of gen_frame, it was im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
and it should be im = im.convert('RGBA').convert('P', palette=Image.ADAPTIVE, colors=255)
. As per one of my favorite YouTubers, "The truth hurts.". (Ben Finegold).
Correct:
from PIL import Image, ImageSequence
def gen_frame(im: Image) -> Image:
alpha = im.getchannel('A')
# Convert the image into P mode but only use 255 colors in the palette out of 256
# -------------------------------------------
# THE im.convert('RGB') WAS CHANGED TO "RGBA"
# -------------------------------------------
im = im.convert('RGBA').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.info['transparency'] = 255
return im
im = Image.open("input_gif.gif")
im_list = []
for frame in ImageSequence.Iterator(im):
# perform some functions on the image frames
frame = frame.convert('RGBA').resize((512, 512), Image.ANTIALIAS)
frame = gen_frame(frame)
im_list.append(frame)
img = im_list[0]
imgs = im_list[1:]
img.save("output_gif.gif", save_all=True, append_images=imgs, duration=50, loop=0, optimize=False, disposal=2)
# works correctly, as intended
img.save("output_webp.webp", save_all=True, append_images=imgs, duration=50, loop=0, optimize=False, disposal=2, lossless=True)
# Transparency loss in the webp format
https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
From the docs:
GIF
Pillow reads GIF87a and GIF89a versions of the GIF file format. The library writes run-length encoded files in GIF87a by default, unless GIF89a features are used or GIF89a is already in use.
GIF files are initially read as grayscale (L) or palette mode (P) images, but seeking to later frames in an image will change the mode to either RGB or RGBA, depending on whether the first frame had transparency.
So in essence, when you went to generate a frame for the image, you were not adding the alpha channel to it, despite setting the transparency in the info properties, and when you went to save it, it was lost.
As per the docs:
transparency
Transparency color index. This key is omitted if the image is not transparent.
Related Topics
Naturally Sorting Pandas Dataframe
How to Scroll Frame Using Mouse Wheel & Adding Horizontal Scrollbar
How to Set Class Attributes from Variable Arguments (Kwargs) in Python
Binary Representation of Float in Python (Bits Not Hex)
Coalesce Values from 2 Columns into a Single Column in a Pandas Dataframe
Sorting Text File by Using Python
How to Call a Shell Script from Python Code
How to Filter Rows in Pandas by Regex
How to Pipe a Subprocess Call to a Text File
Importerror: No Module Named _Ssl
Pyinstaller and --Onefile: How to Include an Image in the Exe File
Paramiko Ssh Die/Hang with Big Output
Jupyter Notebook with Python 3.8 - Notimplementederror
How to Determine Whether a Year Is a Leap Year
How to Handle Elements Inside Shadow Dom from Selenium