diff --git a/libvips/conversion/composite.c b/libvips/conversion/composite.c index 193e6f82..f4660be0 100644 --- a/libvips/conversion/composite.c +++ b/libvips/conversion/composite.c @@ -61,7 +61,12 @@ /** * VipsBlendMode: + * VIPS_BLEND_MODE_CLEAR: + * VIPS_BLEND_MODE_SOURCE: * VIPS_BLEND_MODE_OVER: + * VIPS_BLEND_MODE_IN: + * VIPS_BLEND_MODE_OUT: + * VIPS_BLEND_MODE_ATOP: * * The various Porter-Duff blend modes. See vips_composite(), for example. */ @@ -72,6 +77,8 @@ * * https://en.wikipedia.org/wiki/Alpha_compositing * + * https://www.cairographics.org/operators/ + * * Benchmark: * * vips replicate PNG_transparency_demonstration_1.png x.png 15 15 @@ -127,8 +134,8 @@ G_DEFINE_TYPE( VipsComposite, vips_composite, VIPS_TYPE_CONVERSION ); /* Cairo naming conventions: * * aR alpha of result - * aA alpha of source A - * aB alpha of source B + * aA alpha of source A (the new pixel) + * aB alpha of source B (the thing we accumulate) * xR colour channel of result * xA colour channel of source A * xB colour channel of source B @@ -136,10 +143,30 @@ G_DEFINE_TYPE( VipsComposite, vips_composite, VIPS_TYPE_CONVERSION ); #define ALPHA( MODE, aR, aA, aB ) { \ switch( MODE ) { \ + case VIPS_BLEND_MODE_CLEAR: \ + aR = 1 - aA; \ + break; \ + \ + case VIPS_BLEND_MODE_SOURCE: \ + aR = aA; \ + break; \ + \ case VIPS_BLEND_MODE_OVER: \ aR = aA + aB * (1.0 - aA); \ break; \ \ + case VIPS_BLEND_MODE_IN: \ + aR = aA * aB; \ + break; \ + \ + case VIPS_BLEND_MODE_OUT: \ + aR = aA * (1 - aB); \ + break; \ + \ + case VIPS_BLEND_MODE_ATOP: \ + aR = aB; \ + break; \ + \ default: \ aR = 0; \ g_assert_not_reached(); \ @@ -148,10 +175,30 @@ G_DEFINE_TYPE( VipsComposite, vips_composite, VIPS_TYPE_CONVERSION ); #define BLEND_PREMULTIPLIED( MODE, xR, xA, aA, xB, aB ) { \ switch( MODE ) { \ + case VIPS_BLEND_MODE_CLEAR: \ + xR = 1 - aA; \ + break; \ + \ + case VIPS_BLEND_MODE_SOURCE: \ + aR = xA; \ + break; \ + \ case VIPS_BLEND_MODE_OVER: \ xR = xA + xB * (1 - aA); \ break; \ \ + case VIPS_BLEND_MODE_IN: \ + xR = xA; \ + break; \ + \ + case VIPS_BLEND_MODE_OUT: \ + xR = xA; \ + break; \ + \ + case VIPS_BLEND_MODE_ATOP: \ + xR = xA + xB * (1 - aA); \ + break; \ + \ default: \ xR = 0; \ g_assert_not_reached(); \ @@ -160,10 +207,30 @@ G_DEFINE_TYPE( VipsComposite, vips_composite, VIPS_TYPE_CONVERSION ); #define BLEND_MULTIPLY( MODE, xR, aR, xA, aA, xB, aB ) { \ switch( MODE ) { \ + case VIPS_BLEND_MODE_CLEAR: \ + xR = 1 - aA; \ + break; \ + \ + case VIPS_BLEND_MODE_SOURCE: \ + aR = xA; \ + break; \ + \ case VIPS_BLEND_MODE_OVER: \ xR = (aA * xA + aB * xB * (1 - aA)) / aR; \ break; \ \ + case VIPS_BLEND_MODE_IN: \ + xR = xA; \ + break; \ + \ + case VIPS_BLEND_MODE_OUT: \ + xR = xA; \ + break; \ + \ + case VIPS_BLEND_MODE_ATOP: \ + xR = aA * xA + xB * (1 - aA); \ + break; \ + \ default: \ xR = 0; \ g_assert_not_reached(); \ diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index fd22ba0b..5eeb10fd 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -90,7 +90,12 @@ typedef enum { } VipsInteresting; typedef enum { + VIPS_BLEND_MODE_CLEAR, + VIPS_BLEND_MODE_SOURCE, VIPS_BLEND_MODE_OVER, + VIPS_BLEND_MODE_IN, + VIPS_BLEND_MODE_OUT, + VIPS_BLEND_MODE_ATOP, VIPS_BLEND_MODE_LAST } VipsBlendMode; diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index a1081dd1..ed60d8cd 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -355,7 +355,12 @@ vips_blend_mode_get_type( void ) if( etype == 0 ) { static const GEnumValue values[] = { + {VIPS_BLEND_MODE_CLEAR, "VIPS_BLEND_MODE_CLEAR", "clear"}, + {VIPS_BLEND_MODE_SOURCE, "VIPS_BLEND_MODE_SOURCE", "source"}, {VIPS_BLEND_MODE_OVER, "VIPS_BLEND_MODE_OVER", "over"}, + {VIPS_BLEND_MODE_IN, "VIPS_BLEND_MODE_IN", "in"}, + {VIPS_BLEND_MODE_OUT, "VIPS_BLEND_MODE_OUT", "out"}, + {VIPS_BLEND_MODE_ATOP, "VIPS_BLEND_MODE_ATOP", "atop"}, {VIPS_BLEND_MODE_LAST, "VIPS_BLEND_MODE_LAST", "last"}, {0, NULL, NULL} };