Alpha Image Fixing Script

I wrote a quick Python script that corrects images with background colors bleeding through the alpha channel. This problem seems like it can be common to some graphics software, such as sometimes a black halo around antialiased edges. If you are having a similar problem while working with alpha images this script might help. It requires PIL.

fixes color bleeding
#!/usr/bin/python

# Corrects the color of semi-transparent pixels when there is a
# background color bleeding through.

import sys
import Image
import ImageDraw

def help():
	print "USAGE:"
	print "\tfix_img_alpha.py [-o outfile | -b r,g,b | -h] infile"
	print
	print "-o          Out file"
	print "-b x,x,x    Background Color (black by default)"
	print "-h          Display help"
	
if (len(sys.argv) == 1) or (sys.argv.count('-h') > 0):
	help()
	exit()
	
if sys.argv.count('-b') > 0:
	tmp = sys.argv[sys.argv.index('-b') + 1]
	tmp = tmp.split(',')
	back = []
	for i in tmp:
		back.append(float(i))
else:
	back = [0.0, 0.0, 0.0]

infile = sys.argv[len(sys.argv)-1]

if sys.argv.count('-o') > 0:
	outfile = sys.argv[sys.argv.index('-o') + 1]
else:
	tmp = infile.split('.')
	outfile = tmp[0] + '_fixed_alpha' + '.' + tmp[1]

img = Image.open(infile)
outimg = Image.new("RGBA", img.size)

draw = ImageDraw.ImageDraw(outimg)

data = img.getdata()

c = [0,0,0,0]

for y in xrange(img.size[1]):
	for x in xrange(img.size[0]):
		i = y * img.size[0] + x
		# p = (1 - a) * b + a * c
		# c = (p - (1 - a) * b) / a
		p = data[i]
		a = float(p[3]) / 255.0
		if a > 0.0:
			c[0] = min(int((float(p[0]) - (1.0 - a) * back[0]) / a), 255)
			c[1] = min(int((float(p[1]) - (1.0 - a) * back[1]) / a), 255)
			c[2] = min(int((float(p[2]) - (1.0 - a) * back[2]) / a), 255)
			c[3] = p[3]
		else:
			c = [p[0], p[1], p[2], p[3]]
		
		draw.point((x,y), tuple(c))
		
outimg.save(outfile)

(log in to comment)

Comments

Isn't that the usual use of an alpha channel? Transparency or partial transparency? I can see what you've done, but isn't it the same as removing the alpha channel from the image in the first place?
Not exactly. The problem is a little counter-intuitive, so it may be difficult to understand what is actually going wrong. With some graphics applications (in this case Blender) the image is rendered in front of a background color (in the above example it was red). Instead of simply ignoring the background color (since it represents a transparent area) and using the correct object color the colors of the object and the background are blended together -- which taints the coloration of the semi-transparent parts of the image (giving the above bubble a reddish tint). Ideally there should be no trace of the background color in an image with transparency, and this script fixes the color values in the alpha areas.
Another example, I did a very quick search and found this page with PNG files of hawaiian plants. Since they use a black background the antialiased edges have an undesirable dark halo around them. This script would help correct this problem.