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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <vips/vips.h>
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
@ -163,7 +162,7 @@ static int vips__cgif_write( void *target, const uint8_t *buffer,
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
vips_foreign_save_cgif_pixels_are_equal( const VipsPel *cur, const VipsPel *bef,
|
vips_foreign_save_cgif_pixels_are_equal( const VipsPel *cur, const VipsPel *bef,
|
||||||
double maxerror )
|
double sq_maxerror )
|
||||||
{
|
{
|
||||||
if( bef[3] != cur[3] )
|
if( bef[3] != cur[3] )
|
||||||
/* Alpha channel must be identical.
|
/* 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 dG = cur[1] - bef[1];
|
||||||
const int dB = cur[2] - bef[2];
|
const int dB = cur[2] - bef[2];
|
||||||
|
|
||||||
return( sqrt( dR * dR + dG * dG + dB * dB ) <= maxerror );
|
return( dR * dR + dG * dG + dB * dB <= sq_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have a complete frame --- write!
|
/* We have a complete frame --- write!
|
||||||
|
@ -217,8 +196,10 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
|
||||||
VipsPel *frame_bytes =
|
VipsPel *frame_bytes =
|
||||||
VIPS_REGION_ADDR( cgif->frame, 0, frame_rect->top );
|
VIPS_REGION_ADDR( cgif->frame, 0, frame_rect->top );
|
||||||
|
|
||||||
VipsPel * restrict p;
|
|
||||||
int i;
|
int i;
|
||||||
|
VipsPel * restrict cur;
|
||||||
|
VipsPel * restrict bef;
|
||||||
|
gboolean has_alpha_constraint = FALSE;
|
||||||
VipsPel *rgb;
|
VipsPel *rgb;
|
||||||
CGIF_FrameConfig frame_config;
|
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
|
/* Threshold the alpha channel. It's safe to modify the region since
|
||||||
* it's a buffer we made.
|
* 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++ ) {
|
for( i = 0; i < n_pels; i++ ) {
|
||||||
if( p[3] >= 128 )
|
if( cur[3] >= 128 )
|
||||||
p[3] = 255;
|
cur[3] = 255;
|
||||||
else {
|
else {
|
||||||
/* Helps the quanizer generate a better palette.
|
/* Helps the quanizer generate a better palette.
|
||||||
*/
|
*/
|
||||||
p[0] = 0;
|
cur[0] = 0;
|
||||||
p[1] = 0;
|
cur[1] = 0;
|
||||||
p[2] = 0;
|
cur[2] = 0;
|
||||||
p[3] = 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
|
/* 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.
|
* to [255, 0, 0] are detected.
|
||||||
*/
|
*/
|
||||||
checksum = 0;
|
checksum = 0;
|
||||||
p = frame_bytes;
|
cur = frame_bytes;
|
||||||
for( i = 0; i < n_pels; i++ ) {
|
for( i = 0; i < n_pels; i++ ) {
|
||||||
checksum += p[0] * 1000;
|
checksum += cur[0] * 1000;
|
||||||
checksum += p[1] * 100;
|
checksum += cur[1] * 100;
|
||||||
checksum += p[2] * 10;
|
checksum += cur[2] * 10;
|
||||||
checksum += p[3];
|
checksum += cur[3];
|
||||||
|
|
||||||
p += 4;
|
cur += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cgif->frame_checksum == 0 ||
|
if( cgif->frame_checksum == 0 ||
|
||||||
|
@ -390,21 +382,15 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
|
||||||
* transparent.
|
* transparent.
|
||||||
*/
|
*/
|
||||||
if( cgif->frame_bytes_head ) {
|
if( cgif->frame_bytes_head ) {
|
||||||
VipsPel *cur, *bef;
|
|
||||||
gboolean has_alpha_constraint;
|
|
||||||
|
|
||||||
cur = frame_bytes;
|
cur = frame_bytes;
|
||||||
bef = cgif->frame_bytes_head;
|
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
|
/* Transparency trick is only possible when no alpha channel
|
||||||
* constraint is present.
|
* constraint is present.
|
||||||
*/
|
*/
|
||||||
if( !has_alpha_constraint ) {
|
if( !has_alpha_constraint ) {
|
||||||
int i;
|
|
||||||
uint8_t trans_index;
|
uint8_t trans_index;
|
||||||
|
double sq_maxerror;
|
||||||
|
|
||||||
trans_index = cgif->lp->count;
|
trans_index = cgif->lp->count;
|
||||||
if( cgif->has_transparency ) {
|
if( cgif->has_transparency ) {
|
||||||
|
@ -413,9 +399,11 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
|
||||||
~CGIF_FRAME_ATTR_HAS_ALPHA;
|
~CGIF_FRAME_ATTR_HAS_ALPHA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sq_maxerror = cgif->maxerror * cgif->maxerror;
|
||||||
|
|
||||||
for( i = 0; i < n_pels; i++ ) {
|
for( i = 0; i < n_pels; i++ ) {
|
||||||
if( vips_foreign_save_cgif_pixels_are_equal(
|
if( vips_foreign_save_cgif_pixels_are_equal(
|
||||||
cur, bef, cgif->maxerror ) )
|
cur, bef, sq_maxerror ) )
|
||||||
cgif->index[i] = trans_index;
|
cgif->index[i] = trans_index;
|
||||||
else {
|
else {
|
||||||
bef[0] = cur[0];
|
bef[0] = cur[0];
|
||||||
|
|
Loading…
Reference in New Issue