Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any high-quality, programmatic solutions for converting a jpeg with an opaque background to a png with a transparent background?

The common use case here is a user uploading a jpeg logo with a white/color background. It's (fairly) simple to switch the white pixels to transparent ones, but this leaves aliasing artifacts. An ideal solution would essentially "undo" the aliasing (given a known background color). At a minimum, the solution must beat the bg_removal script for ImageMagick (http://imagemagick.org/Usage/scripts/bg_removal).

like image 423
Jeremy Lewis Avatar asked Feb 17 '11 03:02

Jeremy Lewis


2 Answers

The "Color to Alpha" algorithm in GIMP looks like it does a pretty good job. The source is GPL and can be found here. A demonstration of what the GIMP algorithm does with something like a logo is here, and the GIMP manual page for Color-to-Alpha is here.

It looks like the most straightforward way to do this programmatically would be to use GIMP batch mode.

like image 79
Brent Bradburn Avatar answered Nov 08 '22 16:11

Brent Bradburn


As promised, here's a working solution for the common white --> alpha use case. This is running on an Ubuntu 10.04.1 LTS server with the standard GIMP installation (2.6.8).

from gimpfu import *

def run(input_filepath):
    image = pdb.gimp_file_load(input_filepath, input_filepath)
    image.disable_undo()
    layer = image.active_layer
    if not layer.is_rgb:
        pdb.gimp_image_convert_rgb(image)

    white = gimpcolor.RGB(1.0, 1.0, 1.0, 1.0)
    bg_color = pdb.gimp_image_pick_color(image, layer, 0, 0, True, False, 0)
    if bg_color == white:
        pdb.plug_in_colortoalpha(image, layer, bg_color)
        layer_copy = layer.copy()
        image.add_layer(layer_copy)
        image.merge_visible_layers(CLIP_TO_IMAGE)

    pdb.file_png_save_defaults(image, image.active_layer, input_filepath, input_filepath)

run('%(input_filepath)s')

I execute this code from Python (within Django) using the subprocess module (code_as_string is the above code as a string, with input_filepath inserted:

gimp_args = (settings.PATH_TO_GIMP, 
    '-i', 
    '--batch-interpreter=python-fu-eval', 
    '-b', code_as_string,
    '-b', 'from gimpfu import pdb; pdb.gimp_quit(True)')

environ = os.environ.copy()
environ['GIMP2_DIRECTORY'] = settings.PATH_TO_GIMP_DIR
p = subprocess.Popen(gimp_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=environ)
rc = p.wait()
if rc:
    logging.error(p.stdout.read())
like image 40
Jeremy Lewis Avatar answered Nov 08 '22 16:11

Jeremy Lewis