Skip to content

Instantly share code, notes, and snippets.

@jcupitt
Created May 29, 2016 09:18
Show Gist options
  • Save jcupitt/15324d7cec7ece0c63439c518b191baa to your computer and use it in GitHub Desktop.
Save jcupitt/15324d7cec7ece0c63439c518b191baa to your computer and use it in GitHub Desktop.
combine two alpha channels with vips
/* compile with
*
* g++ trans.cpp `pkg-config vips-cpp --cflags --libs`
*/
#include <vips/vips8>
using namespace vips;
/* Return the image alpha maximum. Useful for combining alpha bands. scRGB
* images are 0 - 1 for image data, but the alpha is 0 - 255.
*/
int
image_alpha_max( VipsInterpretation interpretation )
{
if( interpretation == VIPS_INTERPRETATION_RGB16 ||
interpretation == VIPS_INTERPRETATION_GREY16 )
return( 65535 );
else
return( 255 );
}
/* Split an image to pixels plus an optional alpha. An image can be mono, rgb
* or cmyk, each with an optional alpha as the final band.
*/
VImage
image_split( VImage in, VImage &alpha, bool &has_alpha )
{
VImage image;
if( in.bands() == 2 ||
(in.bands() == 4 &&
in.interpretation() != VIPS_INTERPRETATION_CMYK ) ||
(in.bands() == 5 &&
in.interpretation() == VIPS_INTERPRETATION_CMYK ) ) {
has_alpha = TRUE;
image = in.extract_band( 0,
VImage::option()->set( "n", in.bands() - 1 ) );
alpha = in.extract_band( in.bands() - 1,
VImage::option()->set( "n", 1 ) );
}
else {
has_alpha = FALSE;
image = in;
}
return( image );
}
int
main( int argc, char **argv )
{
if( VIPS_INIT( argv[0] ) )
vips_error_exit( NULL );
// load the main image ... it can optionally have an alpha
VImage in = VImage::new_from_file( argv[1] );
VImage image_alpha;
bool image_has_alpha;
VImage image = image_split( in, image_alpha, image_has_alpha );
// load the mask image
VImage in2 = VImage::new_from_file( argv[2] );
VImage mask_alpha;
bool mask_has_alpha;
VImage mask = image_split( in2, mask_alpha, mask_has_alpha );
// we use the mask alpha, or if the mask only has one band, use that
if( mask_has_alpha )
mask = mask_alpha;
else if( mask.bands() > 1 )
vips_error_exit( "mask has no alpha or more than one band" );
// the range of the mask and the image need to match .. one could be
// 16-bit, one 8-bit
int image_max = image_alpha_max( image.interpretation() );
int mask_max = image_alpha_max( mask.interpretation() );
if( image_has_alpha )
// combine the new mask and the existing alpha ... there are
// many ways of doing this, mult is the simplest
mask = image_max *
((mask / mask_max) * (image_alpha / image_max));
else if( image_max != mask_max )
// adjust the range of the mask to match the image
mask = image_max * (mask / mask_max);
// append the mask to the image data ... the mask might be float now,
// we must cast the format down to match the image data
VImage out = image.bandjoin( mask.cast( image.format() ) );
out.write_to_file( argv[3] );
return( 0 );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment