Fredrik Anfinsen
Fredrik Anfinsen

Reputation: 97

Check for transparency, GraphicsMagick node.js

I am making a code where users can upload a image. The image is converted with GraphicsMagick and uploaded to our cloud. But it will be best if non-transparent images was converted to JPG instead of PNG for transparent images. How can I check if the image contain a alpha channel in GraphicsMagick?

Upvotes: 1

Views: 3139

Answers (2)

Andi F.
Andi F.

Reputation: 776

You may also give imagemagick a try

Snippet is in TypeScript and makes use of BPromise.promisify for better readability.

Note that this works for PNG, JPEG the expected way (returning string true/false), but for GIFs it will give you a concatenated 'true'|'false' string (e.g. 'truetruefalse', and apply the alpha check per frame).

I also recommend applying .trim() to the result to get rid of potential useless whitespace returned by imagemagick v0.x. every now and then.

import * as imagemagick from 'imagemagick';
import * as BPromise from 'bluebird';

...
const opaqueAsync: any = BPromise.promisify(imagemagick.identify, {context: imagemagick});
const isOpaqueReturnValue: string = await opaqueAsync(['-format', '%[opaque]', picturePath]);
const isPicTransparent: boolean = 'false' === isOpaqueReturnValue.trim();

Upvotes: 0

Oles Savluk
Oles Savluk

Reputation: 4345

I am not sure you can achieve that using only GraphicsMagick, but it is possible in several other ways. For example with pngjs:

You can check PNG metadata:

const gm = require('gm');
const PNG = require('pngjs').PNG;

gm('/path/to/image')
  .stream('png')
  .pipe(new PNG({}))
  .on('metadata', meta => {
    if (meta.alpha) {
      // image is transparent
    } else {
      // image is not transparent
    }
  });

Or iterate over pixels and decide if it's transparency valuable to you, or you can omit it:

...
.on('parsed', function() {
  let isAlphaValuable = false;

  for (var y = 0; y < this.height; y++) {
    for (var x = 0; x < this.width; x++) {
      var idx = (this.width * y + x) << 2;

      // this.data[idx]     - red channel
      // this.data[idx + 1] - green channel
      // this.data[idx + 2] - blue channel

      // this.data[idx + 3] - alpha channel

      // if there is at least one pixel 
      // which transparent for more than 30%             
      // then transparency valuable to us
      isAlphaValuable |= (1 - this.data[idx + 3] / 255) > 0.3;      
    }
  }

  if (isAlphaValuable) {
    // keep transparency
  } else {
    // ignore transparency
  }
});

Upvotes: 3

Related Questions