17

I'm prototyping an image processor in Python 2.7 using PIL1.1.7 and I would like all images to end up in JPG. Input file types will include tiff,gif,png both with transparency and without. I've been trying to combine two scripts that I found that 1. convert other file types to JPG and 2. removing transparency by creating a blank white image and pasting the original image over the white background. My searches are being spammed with people seeking to generate or preserve transparency rather than the opposite.

I'm currently working with this:

#!/usr/bin/python
import os, glob
import Image

images = glob.glob("*.png")+glob.glob("*.gif")

for infile in images:
    f, e = os.path.splitext(infile)
    outfile = f + ".jpg"
    if infile != outfile:
        #try:
        im = Image.open(infile)
        # Create a new image with a solid color
        background = Image.new('RGBA', im.size, (255, 255, 255))
        # Paste the image on top of the background
        background.paste(im, im)
        #I suspect that the problem is the line below
        im = background.convert('RGB').convert('P', palette=Image.ADAPTIVE)
        im.save(outfile)
        #except IOError:
           # print "cannot convert", infile

Both scripts work in isolation, but as I have combined them I get a ValueError: Bad Transparency Mask.

Traceback (most recent call last):
File "pilhello.py", line 17, in <module>
background.paste(im, im)
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 1101, in paste
self.im.paste(im, box, mask.im)
ValueError: bad transparency mask

I suspect that if I were to save a PNG without transparency I could then open that new file, and re-save it as a JPG, and delete the PNG that was written to disk, but I'm hoping that there is an elegant solution that I haven't found yet.

  • Why would you expect the problem is the "line below" when the code is barfing on the `.paste()` and not even getting to that line? – kindall Oct 27 '11 at 04:06
  • This question here came later, but has all the answers: https://stackoverflow.com/a/33507138/2628864 – Vinícius M Jun 16 '20 at 17:24

4 Answers4

34

Make your background RGB, not RGBA. And remove the later conversion of the background to RGB, of course, since it's already in that mode. This worked for me with a test image I created:

from PIL import Image
im = Image.open(r"C:\jk.png")
bg = Image.new("RGB", im.size, (255,255,255))
bg.paste(im,im)
bg.save(r"C:\jk2.jpg")
kindall
  • 178,883
  • 35
  • 278
  • 309
8
image=Image.open('file.png')
non_transparent=Image.new('RGBA',image.size,(255,255,255,255))
non_transparent.paste(image,(0,0),image)

The key is to make the mask (for the paste) the image itself.

This should work on those images that have "soft edges" (where the alpha transparency is set to not be 0 or 255)

Chander
  • 81
  • 1
  • 1
5

The following works for me on this image

f, e = os.path.splitext(infile)
print infile
outfile = f + ".jpg"
if infile != outfile:
    im = Image.open(infile)
    im.convert('RGB').save(outfile, 'JPEG')
uncreative
  • 1,436
  • 9
  • 14
  • I tried this approach at first. Just converting directly to RGB mode works with a hard-edged mask, but can fail pretty nastily with a soft-edged mask. – kindall Oct 27 '11 at 04:20
  • Can you provide a link to an image where it fails? I can see if I can get it to work – uncreative Oct 27 '11 at 04:21
  • [Here's the one](http://mac.jerrykindall.com:81/pil/jk.png) I made to play with this. And [here's the result](http://mac.jerrykindall.com:81/pil/jk_bad.png) of just stripping off the alpha channel. – kindall Oct 27 '11 at 04:28
1
from PIL import Image


def png2jpg(file_name:str, trans_color: tuple):
    """
    convert png file to jpg file
    :param file_name: png file name
    :param trans_color: set transparent color in jpg image
    :return:
    """
    with Image.open(file_name) as im:
        image = im.convert("RGBA")
        datas = image.getdata()
        newData = []
        for item in datas:
            if item[3] == 0:  # if transparent
                newData.append(trans_color)  # set transparent color in jpg
            else:
                newData.append(tuple(item[:3]))
        image = Image.new("RGB", im.size)
        image.getdata()
        image.putdata(newData)
        image.save('{}.jpg'.format(file_name))

To convert png to jpg run png2jpg("try.png", (255,255,255))

Result:

enter image description here

apoptosis
  • 61
  • 5