Recipe: Image transparent background

Sometimes you need to remove a simple background from an image. This is why we created a handy tool for quick transparency restoring or to make images and icons usable. This is a process that works by color selection and tolerance.

The recipe uses ImageMagick to add a transparent background to images by using a color from one corner of the image. The same color around the image will be made transparent up to a given tolerance percentage threshold.
Anti alias will fix rough edges. And lastly the filename tag will be added to the output file and placed next to the source file.

Download the recipe from the extended collection here:
https://magnetron.app/recipes/image-transparent-background

For Windows & macOS

You can run this recipe with a magnetron.app license key.
With magnetron.dev you can also use the source to create your own custom processes.

Take a closer look at the source below

the dialog

(added July 2023)

header={
  "recipe_version": "1.6",
  "title": "Make image background transparent",
  "description": "Convert images to a transparent background by using a color from one corner",
  "tags": "ImageMagick,image,transparent",
  "chef": "BeatRig",
  "dependencies": "identify,convert",
  "instructions": "Drop image files here and run this recipe to select the background detection settings",
  "type": "default",
  "os": "windows,macOS",
  "palette": "Mint Cream",
  "spice": "BQ==:G+Hy36kJcnQQYYavb/JV2Il6eCYr6h4hRJHCF9rRbhX5BcazL6cuTgUMdz0xA50VWA5PmmV0Q7aWkiUtNFtbk991l+t0e8IBXMReMIT1GNjnZZDv7n2YRAo0xcSQbY0ixjG6LLH4wGKnspKAoA/v69iLn6N2IH0XzIZwTGdHSo4=",
  "flavour": "5gnchER9IDp3Qba1ew9cEMnTc+pUXHxXhJg7iMtxZrEmHReJsUclezzYzLSoirkfGsOmvQOGPrV976j4i9uN/04nmzQXjeMYmQOLk2tvuwGSv9ht0tMYtIP+yuWwL6cUA7Qh11eJAIrOO04B7horG/krlUQJ68cMVZu7jB2vvhA=",
  "time": 1694301146,
  "core_version": "0.5.7",
  "magnetron_version": "1.0.261",
  "functions": "main,onAbout",
  "uuid": "7ebe4cd6eee6474c8c1190d380f4c630"
};

//----------------------------------------------------------------------------
// o7 based on https://github.com/hackerb9/mktrans/blob/master/mktrans

function main()
{
    CheckInstalled();

    var antialias_items = ["Anti-alias","Anti-alias (fast)","No anti-alias"];
    var corner_items = ["Top-Left","Top-Right","Bottom-Left","Bottom-Right"];
    
    var corner = corner_items[0];
    var fuzz = "20";
    var antialias = antialias_items[0];
    var tag = "-transparent";

    var files = getFiles();
    if (files.length <= 0)
        abort("drop a file to process first");

    for (var i = 0; i < files.length; i++)
    {
        filename = files[i].path;
        pathInfo = getPathInfo(filename);
        
        setMainMessage("processing " + pathInfo.basename);
        setProgress((i+0.5) / files.length * 100.);

        var dialog_width = 500;
        var form = {
            "mainlabel" : {
                "type" : "label",
                "label" : "Add transparancy from a specific background corner color to\n" + pathInfo.basename,
                "bounds" : {
                    "x" : 5,
                    "w" : dialog_width,
                    "h" : 60,
                    "y" : 5,
                }
            },
            "cornerlabel" : {
                "type" : "label",
                "label" : "The sample color corner",
                "bounds" : {
                    "x" : 5,
                    "w" : dialog_width/2,
                }
            },
            "corner" : {
                "type" : "combobox",
                "default" : corner,
                "items" : corner_items,
                "label" : "Sample color corner",
                "bounds" : {
                    "x" : dialog_width/2,
                    "y" : -1,
                    "w" : dialog_width/2,
                }
            },
            "fuzzlabel" : {
                "type" : "label",
                "label" : "Color tolerance",
                "bounds" : {
                    "x" : 5,
                    "w" : dialog_width/2
                }
            },
            "fuzz" : {
                "type" : "slider",
                "value": 30,
                "range" : { 
                    "min" : 0,
                    "max" : 100,
                    "interval" : 1,
                    "decimals": 0
                },
                "label" : "color % tolerance:",
                "bounds" : {
                    "x" : dialog_width/2,
                    "y" : -1,
                    "w" : dialog_width/2
                }
            },
            "antialiaslabel" : {
                "type" : "label",
                "label" : "anti-alias type",
                "bounds" : {
                    "x" : 5,
                    "w" : dialog_width/2
                }
            },
            "antialias" : {
                "type" : "combobox",
                "default" : antialias,
                "items" : antialias_items,
                "label" : "anti-alias types:",
                "bounds" : {
                    "x" : dialog_width/2,
                    "y" : -1,
                    "w" : dialog_width/2
                }
            },
            "tag" : {
                "type" : "textedit",
                "default" : tag,
                "label" : "add file name tag:",
                "bounds" : {
                    "x" : dialog_width/2,
                    "y" : -1,
                    "w" : dialog_width/2
                }
            },
            "okay" : {
                "type" : "button",
                "label" : "okay",
                "returns" : 1
            },
            "cancel" : {
                "type" : "button",
                "label" : "cancel",
                "returns" : 0
            }
        };

        form_out = dialog(form);
        if (form_out.cancel)
            abort("Cancelled");

        corner = form_out.corner;
        fuzz = form_out.fuzz;
        antialias = form_out.antialias;
        tag = form_out.tag;

        outfile = pathInfo.folder + pathInfo.sep + pathInfo.basename + form_out.tag + ".png";

        var wah = cmd("identify", ["-format", "%w,%h", filename]);
        var dimensions = wah.split(",");
        echo("dimensions:" + dimensions[0] + "x" + dimensions[1]);

        var x = 0;
        var y = 0;
        if (form_out.corner == corner_items[1])
            x = dimensions[0];
        if (form_out.corner == corner_items[2])
            y = dimensions[1];
        if (form_out.corner == corner_items[3])
        {
            x = dimensions[0];
            y = dimensions[1];
        }            
        pixelcomma = x + "," + y;
        pixelplus = "+" + x + "+" + y;

        var pflag = false; // false for 1 pixel border

        // Get color of pixel
        var color = cmd("convert", [filename, "-format", "%[pixel:p{" + pixelcomma + "}]", "info:-"]);
        // check if starts with rgba and ends with ,0)
        if (color.substring(0, 4) == "rgba" && color.substring(color.length - 3, color.length) == ",0)")
            color = color.substring(0, color.length - 3) + ",1)"; // if so replace end with ,1)
        if (color == "none")
            abort (filename + " pixel at " + pixelcomma + " completely transparent. Cannot floodfill");
        echo(color);

        var options=[filename];
        if (pflag == false) // Add a 1 pixel border so we'll fill from the bottom and sides as well.
	    {
            options.push("-bordercolor");
            options.push(color);
            options.push("-border");
            options.push("1");
        }

        // In a new stack, make a copy of the image
        options.push("(");
        options.push("+clone");
        
        // [copy] floodfill with transparency ("none") starting at top-left    
        options.push("-fuzz");
        options.push(form_out.fuzz + "%");
        options.push("-fill");
        options.push("none");
        options.push("-floodfill");
        options.push(pixelplus);
        options.push(color);
    
        // [copy] extract just the transparency (alpha channel)
        options.push("-alpha");
        options.push("extract");

        if (form_out.antialias != antialias_items[2])
        {
	        if (form_out.antialias == antialias_items[1])
            {
                // [copy] blow up the alpha channel so we can do sub-pixel morphology
                options.push("-geometry");
                options.push("200%");

                // [copy] blur the alpha channel to make it antialiased
                options.push("-blur");
                options.push("0x0.5");

                // [copy] shrink the region that is opaque by half a pixel.
                options.push("-morphology");
                options.push("erode");
                options.push("square:1");

                // [copy] scale the alpha channel back to normal size.
                options.push("-geometry");
                options.push("50%");
            }
	        else // speedy antialias
            {
                // [copy] blur the alpha channel to make it antialiased
                options.push("-blur");
                options.push("0x1");

                // [copy] only antialias inside the figure (<50% opacity becomes 0%)
                options.push("-level");
                options.push("50%,100%");
            }
        }

        // [copy] end the stack.
        options.push(")");

        // Compose the original image and the copy's alpha channel.
        options.push("-compose");
        options.push("CopyOpacity");
        options.push("-composite");

        if (pflag == false) // Remove the 1 pixel border we added
	    {
            options.push("-shave");
            options.push("1");
        }
        options.push(outfile);

        echo("convert " + objectToString(options));
        echo(cmd("convert", options));

        setProgress((i+1) / files.length * 100.);

        if (isCanceled())
            abort("Canceled");
    }
    setMainMessage("finished");
}

function onAbout()
{
    dialog(header.title, header.description, "i");
}

//----------------------------------------------------------------------------
function CheckInstalled()
{
    var cmds = header.dependencies.split(",");
    for (i = 0; i < cmds.length; i++)
    {
        var install_cmd = cmds[i];//"convert";
        var cmd_path = getAllowedApps(install_cmd);    
        if (cmd_path.length <= 0)
            abort("ImageMagick " + install_cmd + " not installed");
    }
}