Search code examples
node.jsimagemagickimage-manipulationgraphicsmagickimagefilter

How do I trim transparent borders from my image in an efficient way?


I want to automatate the process of trimming transparent edges from PNG images with Node.js, but rather with either with a CLI tool (called by child_process) or a Node module with native bindings than a pure JavaScript implementation for performance reasons.

This sounds like a fairly simple task, but I am searching for weeks without any results that fit my needs.

  • The trimming routine should search for transparent pixels, no matter what the input image looks like. Most implementations check the color of the top left pixel.
  • The trimming routine should be configurable with a tolerance value, so anything with 20% or less opacity gets removed rather than strictly checking for 0% opacity.

I currently use Sharp and GraphicsMagick for a complex chain of image manipulations, but because I didn't find a tool for transparency trimming, I wrote a custom Jimp plugin that handles the trimming jobs in a rather inefficient way, but it's still working.

Here is an example input image:

And an expected output image:

I want to get rid of Jimp though.


Solution

  • libvips, the image processing library used by sharp, has find_trim.

    In your case you only want to test the alpha channel (band 3), so extract that and search for the bounding box of values more than 200 from 0 (ie. near solid)::

    $ vips extract_band test-transparency.png x.png 3
    $ vips find_trim x.png --background 0 --threshold 200
    0
    0
    445
    475
    

    And that's left/top/width/height of the area you want. You can crop that out of your original image with:

    $ vips crop test-transparency.png y.png 0 0 445 475
    

    To make:

    enter image description here

    You can do it as a one-liner with:

    $ vips crop test-transparency.png y.png $(vips extract_band test-transparency.png x.png 3; vips find_trim x.png --background 0 --threshold 200)
    

    You can make it a little more efficient in Python:

    #!/usr/bin/python3
    
    import sys
    import pyvips
    
    image = pyvips.Image.new_from_file(sys.argv[1])
    left, top, width, height = image[3].find_trim(background=0, threshold=200)
    image = image.crop(left, top, width, height)
    image.write_to_file(sys.argv[2])
    

    And shell out to that. Of course, you might not want to add py as a dependency.