Nathaniel M. Beaver
Nathaniel M. Beaver

Reputation: 755

Replace only background color of PNG

Here is my code:

#! /usr/bin/env sh
# Generate test image.
convert -size 100x60 xc:blue -fill blue -stroke black -draw "circle 50,30 55,55" in.png

# Make background transparent.
convert in.png -fill none -draw 'matte 0,0 floodfill' -flop  -draw 'matte 0,0 floodfill' -flop out.png
# Replace transparent background with green.
mogrify -background green -flatten out.png

# The wrong way.
convert in.png -transparent blue oops.png
mogrify -background green -flatten oops.png

It is based on this snippet: https://snippets.aktagon.com/snippets/558-how-to-remove-a-background-with-imagemagick

Starting with this:

Black circle filled with blue, blue background

I want to get this:

Black circle filled with blue, green background

Not this:

Black circle filled with green, green background

Can I achieve this with a single convert command instead of a convert followed by a mogrify?

I am using ImageMagick 6.8.9-9.

Upvotes: 3

Views: 2151

Answers (1)

Mark Setchell
Mark Setchell

Reputation: 207853

Essentially, you are seeking a "floodfill", like this:

convert in.png -fill green  -draw 'color 0,0 floodfill' result.png

enter image description here

That will look at the top-left pixel (0,0) and fill all similarly coloured pixels which are connected to it with green. If your background has slight variations in it, e.g. it's a JPEG, add some fuzz factor

convert in.jpg -fuzz 25% ...

Note that if your circle had touched the top and bottom edges, it would prevent the fill from flooding around to the right side of the diagram. So, let's say you had created your circle like this:

convert -size 100x60 xc:blue -fill blue -stroke black -draw "circle 50,30 50,0" in.png

enter image description here

And then you run the above command, you will get:

enter image description here

If that happens, you can add a single pixel wide border all the way around for the colour to "flow" through first, then flood-fill, and finally remove it later:

convert in.png -bordercolor blue -border 1 -fill green  -draw 'color 0,0 floodfill' -shave 1x1 result.png

Upvotes: 5

Related Questions