diff --git a/libvips/foreign/cgifsave.c b/libvips/foreign/cgifsave.c index 718e24ad..40876e76 100644 --- a/libvips/foreign/cgifsave.c +++ b/libvips/foreign/cgifsave.c @@ -45,7 +45,6 @@ #include #include #include -#include #include @@ -163,7 +162,7 @@ static int vips__cgif_write( void *target, const uint8_t *buffer, */ static gboolean vips_foreign_save_cgif_pixels_are_equal( const VipsPel *cur, const VipsPel *bef, - double maxerror ) + double sq_maxerror ) { if( bef[3] != cur[3] ) /* Alpha channel must be identical. @@ -180,27 +179,7 @@ vips_foreign_save_cgif_pixels_are_equal( const VipsPel *cur, const VipsPel *bef, const int dG = cur[1] - bef[1]; const int dB = cur[2] - bef[2]; - return( sqrt( dR * dR + dG * dG + dB * dB ) <= maxerror ); -} - -/* Check if the alpha channel of the current frame matches the frame before. - * If the current frame has an alpha component which is not identical to the - * frame from before we are forced to use the transparency index for the - * alpha channel instead of for the transparency size optimization (maxerror). - */ -static gboolean -vips_foreign_save_cgif_check_alpha_constraint( const VipsPel *cur, - const VipsPel *bef, int n_pels ) -{ - while( n_pels-- ) { - if( cur[3] == 0 && bef[3] != 0 ) - return TRUE; - - cur += 4; - bef += 4; - } - - return FALSE; + return( dR * dR + dG * dG + dB * dB <= sq_maxerror ); } /* We have a complete frame --- write! @@ -217,8 +196,10 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif ) VipsPel *frame_bytes = VIPS_REGION_ADDR( cgif->frame, 0, frame_rect->top ); - VipsPel * restrict p; int i; + VipsPel * restrict cur; + VipsPel * restrict bef; + gboolean has_alpha_constraint = FALSE; VipsPel *rgb; CGIF_FrameConfig frame_config; @@ -234,21 +215,32 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif ) /* Threshold the alpha channel. It's safe to modify the region since * it's a buffer we made. + * + * Also, check if the alpha channel of the current frame matches the + * frame before. + * If the current frame has an alpha component which is not identical + * to the frame from before we are forced to use the transparency index + * for the alpha channel instead of for the transparency size + * optimization (maxerror). */ - p = frame_bytes; + cur = frame_bytes; + bef = cgif->frame_bytes_head; for( i = 0; i < n_pels; i++ ) { - if( p[3] >= 128 ) - p[3] = 255; + if( cur[3] >= 128 ) + cur[3] = 255; else { /* Helps the quanizer generate a better palette. */ - p[0] = 0; - p[1] = 0; - p[2] = 0; - p[3] = 0; + cur[0] = 0; + cur[1] = 0; + cur[2] = 0; + cur[3] = 0; + + if( bef && bef[i * 4 + 3] != 0 ) + has_alpha_constraint = TRUE; } - p += 4; + cur += 4; } /* Do we need to compute a new palette? Do it if the frame sum @@ -266,14 +258,14 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif ) * to [255, 0, 0] are detected. */ checksum = 0; - p = frame_bytes; + cur = frame_bytes; for( i = 0; i < n_pels; i++ ) { - checksum += p[0] * 1000; - checksum += p[1] * 100; - checksum += p[2] * 10; - checksum += p[3]; + checksum += cur[0] * 1000; + checksum += cur[1] * 100; + checksum += cur[2] * 10; + checksum += cur[3]; - p += 4; + cur += 4; } if( cgif->frame_checksum == 0 || @@ -390,21 +382,15 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif ) * transparent. */ if( cgif->frame_bytes_head ) { - VipsPel *cur, *bef; - gboolean has_alpha_constraint; - cur = frame_bytes; bef = cgif->frame_bytes_head; - has_alpha_constraint = - vips_foreign_save_cgif_check_alpha_constraint( cur, - bef, n_pels ); /* Transparency trick is only possible when no alpha channel * constraint is present. */ if( !has_alpha_constraint ) { - int i; uint8_t trans_index; + double sq_maxerror; trans_index = cgif->lp->count; if( cgif->has_transparency ) { @@ -413,9 +399,11 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif ) ~CGIF_FRAME_ATTR_HAS_ALPHA; } + sq_maxerror = cgif->maxerror * cgif->maxerror; + for( i = 0; i < n_pels; i++ ) { if( vips_foreign_save_cgif_pixels_are_equal( - cur, bef, cgif->maxerror ) ) + cur, bef, sq_maxerror ) ) cgif->index[i] = trans_index; else { bef[0] = cur[0];