cgifsave: theshold alpha and check alpha constraint in one pass (#2827)
* cgifsave: theshold alpha and check alpha constraint in one pass * cgifsave: get rid of sqrt()
This commit is contained in:
parent
cb1927e1b7
commit
4fab8beae9
@ -45,7 +45,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user