break quantise out to a separate file
slightly simpler reference and memory handling too
This commit is contained in:
parent
35b4a1a3b5
commit
cb76ffb0bd
@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libforeign.la
|
||||
|
||||
libforeign_la_SOURCES = \
|
||||
pforeign.h \
|
||||
quantise.c \
|
||||
exif.c \
|
||||
gifload.c \
|
||||
cairo.c \
|
||||
|
@ -252,6 +252,10 @@ int vips__openslide_read_associated( const char *filename, VipsImage *out,
|
||||
gboolean vips_foreign_load_pdf_is_a_buffer( const void *buf, size_t len );
|
||||
gboolean vips_foreign_load_pdf_is_a( const char *filename );
|
||||
|
||||
int vips__quantise_image( VipsImage *in,
|
||||
VipsImage **index_out, VipsImage **palette_out,
|
||||
int colours, int Q, double dither );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
224
libvips/foreign/quantise.c
Normal file
224
libvips/foreign/quantise.c
Normal file
@ -0,0 +1,224 @@
|
||||
/* quantise an image with libimagequant
|
||||
*
|
||||
* 20/6/18
|
||||
* - from vipspng.c
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG
|
||||
#define VIPS_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#ifdef HAVE_IMAGEQUANT
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "pforeign.h"
|
||||
|
||||
#include <libimagequant.h>
|
||||
|
||||
/* Track during a quantisation.
|
||||
*/
|
||||
typedef struct _Quantise {
|
||||
VipsImage *in;
|
||||
VipsImage **index_out;
|
||||
VipsImage **palette_out;
|
||||
int colours;
|
||||
int Q;
|
||||
double dither;
|
||||
|
||||
liq_attr *attr;
|
||||
liq_image *input_image;
|
||||
liq_result *quantisation_result;
|
||||
VipsImage *t[5];
|
||||
} Quantise;
|
||||
|
||||
static void
|
||||
vips__quantise_free( Quantise *quantise )
|
||||
{
|
||||
int i;
|
||||
|
||||
VIPS_FREEF( liq_result_destroy, quantise->quantisation_result );
|
||||
VIPS_FREEF( liq_image_destroy, quantise->input_image );
|
||||
VIPS_FREEF( liq_attr_destroy, quantise->attr );
|
||||
|
||||
for( i = 0; i < VIPS_NUMBER( quantise->t ); i++ )
|
||||
VIPS_UNREF( quantise->t[i] );
|
||||
|
||||
VIPS_FREE( quantise );
|
||||
}
|
||||
|
||||
static Quantise *
|
||||
vips__quantise_new( VipsImage *in,
|
||||
VipsImage **index_out, VipsImage **palette_out,
|
||||
int colours, int Q, double dither )
|
||||
{
|
||||
Quantise *quantise;
|
||||
int i;
|
||||
|
||||
quantise = VIPS_NEW( NULL, Quantise );
|
||||
quantise->in = in;
|
||||
quantise->index_out = index_out;
|
||||
quantise->palette_out = palette_out;
|
||||
quantise->colours = colours;
|
||||
quantise->Q = Q;
|
||||
quantise->dither = dither;
|
||||
for( i = 0; i < VIPS_NUMBER( quantise->t ); i++ )
|
||||
quantise->t[i] = NULL;
|
||||
|
||||
return( quantise );
|
||||
}
|
||||
|
||||
int
|
||||
vips__quantise_image( VipsImage *in,
|
||||
VipsImage **index_out, VipsImage **palette_out,
|
||||
int colours, int Q, double dither )
|
||||
{
|
||||
Quantise *quantise;
|
||||
VipsImage *index;
|
||||
VipsImage *palette;
|
||||
const liq_palette *lp;
|
||||
int i;
|
||||
|
||||
quantise = vips__quantise_new( in, index_out, palette_out,
|
||||
colours, Q, dither );
|
||||
|
||||
/* Ensure input is sRGB.
|
||||
*/
|
||||
if( in->Type != VIPS_INTERPRETATION_sRGB ) {
|
||||
if( vips_colourspace( in, &quantise->t[0],
|
||||
VIPS_INTERPRETATION_sRGB, NULL ) ) {
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
in = quantise->t[0];
|
||||
}
|
||||
|
||||
/* Add alpha channel if missing.
|
||||
*/
|
||||
if( !vips_image_hasalpha( in ) ) {
|
||||
if( vips_bandjoin_const1( in, &quantise->t[1], 255, NULL ) ) {
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
in = quantise->t[1];
|
||||
}
|
||||
|
||||
if( !(quantise->t[2] = vips_image_copy_memory( in )) ) {
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
in = quantise->t[2];
|
||||
|
||||
quantise->attr = liq_attr_create();
|
||||
liq_set_max_colors( quantise->attr, colours );
|
||||
liq_set_quality( quantise->attr, 0, Q );
|
||||
|
||||
quantise->input_image = liq_image_create_rgba( quantise->attr,
|
||||
VIPS_IMAGE_ADDR( in, 0, 0 ), in->Xsize, in->Ysize, 0 );
|
||||
|
||||
if( liq_image_quantize( quantise->input_image, quantise->attr,
|
||||
&quantise->quantisation_result ) ) {
|
||||
vips_error( "vips2png", "%s", _( "quantisation failed" ) );
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
liq_set_dithering_level( quantise->quantisation_result, dither );
|
||||
|
||||
index = quantise->t[3] = vips_image_new_memory();
|
||||
vips_image_init_fields( index,
|
||||
in->Xsize, in->Ysize, 1, VIPS_FORMAT_UCHAR,
|
||||
VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
|
||||
|
||||
if( vips_image_write_prepare( index ) ) {
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( liq_write_remapped_image( quantise->quantisation_result,
|
||||
quantise->input_image,
|
||||
VIPS_IMAGE_ADDR( index, 0, 0 ), VIPS_IMAGE_N_PELS( index ) ) ) {
|
||||
vips_error( "vips2png", "%s", _( "quantisation failed" ) );
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
lp = liq_get_palette( quantise->quantisation_result );
|
||||
|
||||
palette = quantise->t[4] = vips_image_new_memory();
|
||||
vips_image_init_fields( palette, lp->count, 1, 4,
|
||||
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB,
|
||||
1.0, 1.0 );
|
||||
|
||||
if( vips_image_write_prepare( palette ) ) {
|
||||
vips__quantise_free( quantise );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
for( i = 0; i < lp->count; i++ ) {
|
||||
unsigned char *p = VIPS_IMAGE_ADDR( palette, i, 0 );
|
||||
|
||||
p[0] = lp->entries[i].r;
|
||||
p[1] = lp->entries[i].g;
|
||||
p[2] = lp->entries[i].b;
|
||||
p[3] = lp->entries[i].a;
|
||||
}
|
||||
|
||||
*index_out = index;
|
||||
g_object_ref( index );
|
||||
*palette_out = palette;
|
||||
g_object_ref( palette );
|
||||
|
||||
vips__quantise_free( quantise );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#else /*!HAVE_IMAGEQUANT*/
|
||||
|
||||
int
|
||||
vips__quantise_image( VipsImage *in,
|
||||
VipsImage **index_out, VipsImage **palette_out,
|
||||
int colours, int Q, double dither )
|
||||
{
|
||||
vips_error( "vips__quantise_image",
|
||||
"%s", _( "libvips not built with quantisation support" ) );
|
||||
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#endif /*HAVE_IMAGEQUANT*/
|
||||
|
@ -126,10 +126,6 @@
|
||||
#error "PNG library too old."
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMAGEQUANT
|
||||
#include <libimagequant.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
user_error_function( png_structp png_ptr, png_const_charp error_msg )
|
||||
{
|
||||
@ -883,113 +879,6 @@ write_png_block( VipsRegion *region, VipsRect *area, void *a )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#ifdef HAVE_IMAGEQUANT
|
||||
static int
|
||||
quantise_image( VipsImage *in, VipsImage *out, VipsImage *palette_out,
|
||||
int colours, int Q, double dither )
|
||||
{
|
||||
VipsImage *memory;
|
||||
liq_attr *attr;
|
||||
liq_image *input_image;
|
||||
liq_result *quantisation_result;
|
||||
int i;
|
||||
|
||||
/* Ensure input is sRGB.
|
||||
*/
|
||||
if( in->Type != VIPS_INTERPRETATION_sRGB) {
|
||||
VipsImage *srgb;
|
||||
|
||||
if( vips_colourspace( in, &srgb, VIPS_INTERPRETATION_sRGB,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
in = srgb;
|
||||
VIPS_UNREF( srgb );
|
||||
}
|
||||
|
||||
/* Add alpha channel if missing.
|
||||
*/
|
||||
if( !vips_image_hasalpha( in ) ) {
|
||||
VipsImage *srgba;
|
||||
|
||||
if( vips_bandjoin_const1( in, &srgba, 255, NULL ) )
|
||||
return( -1 );
|
||||
in = srgba;
|
||||
VIPS_UNREF( srgba );
|
||||
}
|
||||
|
||||
if( !(memory = vips_image_copy_memory( in )) )
|
||||
return( -1 );
|
||||
in = memory;
|
||||
|
||||
attr = liq_attr_create();
|
||||
liq_set_max_colors( attr, colours );
|
||||
liq_set_quality( attr, 0, Q );
|
||||
|
||||
input_image = liq_image_create_rgba( attr,
|
||||
VIPS_IMAGE_ADDR( in, 0, 0 ), in->Xsize, in->Ysize, 0 );
|
||||
|
||||
if ( liq_image_quantize( input_image, attr, &quantisation_result ) ) {
|
||||
liq_result_destroy( quantisation_result );
|
||||
liq_image_destroy( input_image );
|
||||
liq_attr_destroy( attr );
|
||||
VIPS_UNREF( memory );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
liq_set_dithering_level( quantisation_result, (float) dither );
|
||||
|
||||
vips_image_init_fields( out, in->Xsize, in->Ysize, 1, VIPS_FORMAT_UCHAR,
|
||||
VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
|
||||
|
||||
if( vips_image_write_prepare( out ) ) {
|
||||
liq_result_destroy( quantisation_result );
|
||||
liq_image_destroy( input_image );
|
||||
liq_attr_destroy( attr );
|
||||
VIPS_UNREF( memory );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( liq_write_remapped_image( quantisation_result, input_image,
|
||||
VIPS_IMAGE_ADDR( out, 0, 0 ), VIPS_IMAGE_N_PELS( out ) ) ) {
|
||||
liq_result_destroy( quantisation_result );
|
||||
liq_image_destroy( input_image );
|
||||
liq_attr_destroy( attr );
|
||||
VIPS_UNREF( memory );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
const liq_palette *palette = liq_get_palette( quantisation_result );
|
||||
|
||||
vips_image_init_fields( palette_out, palette->count, 1, 4,
|
||||
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB,
|
||||
1.0, 1.0 );
|
||||
|
||||
if( vips_image_write_prepare( palette_out ) ) {
|
||||
liq_result_destroy( quantisation_result );
|
||||
liq_image_destroy( input_image );
|
||||
liq_attr_destroy( attr );
|
||||
VIPS_UNREF( memory );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
for( i = 0; i < palette->count; i++ ) {
|
||||
unsigned char *p = VIPS_IMAGE_ADDR( palette_out, i, 0 );
|
||||
|
||||
p[0] = palette->entries[i].r;
|
||||
p[1] = palette->entries[i].g;
|
||||
p[2] = palette->entries[i].b;
|
||||
p[3] = palette->entries[i].a;
|
||||
}
|
||||
|
||||
liq_result_destroy( quantisation_result );
|
||||
liq_image_destroy( input_image );
|
||||
liq_attr_destroy( attr );
|
||||
VIPS_UNREF( memory );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
#endif /*HAVE_IMAGEQUANT*/
|
||||
|
||||
/* Write a VIPS image to PNG.
|
||||
*/
|
||||
static int
|
||||
@ -1125,23 +1014,16 @@ write_vips( Write *write,
|
||||
|
||||
#ifdef HAVE_IMAGEQUANT
|
||||
if( palette ) {
|
||||
VipsImage *im_quantised;
|
||||
VipsImage *im_index;
|
||||
VipsImage *im_palette;
|
||||
int palette_count;
|
||||
png_color *png_palette;
|
||||
png_byte *png_trans;
|
||||
int trans_count;
|
||||
|
||||
im_quantised = vips_image_new_memory();
|
||||
im_palette = vips_image_new_memory();
|
||||
if( quantise_image( in, im_quantised, im_palette, colours, Q,
|
||||
dither ) ) {
|
||||
vips_error( "vips2png",
|
||||
"%s", _( "quantisation failed" ) );
|
||||
VIPS_UNREF( im_quantised );
|
||||
VIPS_UNREF( im_palette );
|
||||
if( vips__quantise_image( in, &im_index, &im_palette,
|
||||
colours, Q, dither ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
palette_count = im_palette->Xsize;
|
||||
|
||||
@ -1153,8 +1035,8 @@ write_vips( Write *write,
|
||||
palette_count * sizeof( png_byte ) );
|
||||
trans_count = 0;
|
||||
for( i = 0; i < palette_count; i++ ) {
|
||||
png_byte *p = (png_byte *) VIPS_IMAGE_ADDR( im_palette,
|
||||
i, 0 );
|
||||
VipsPel *p = (VipsPel *)
|
||||
VIPS_IMAGE_ADDR( im_palette, i, 0 );
|
||||
png_color *col = &png_palette[i];
|
||||
|
||||
col->red = p[0];
|
||||
@ -1186,10 +1068,11 @@ write_vips( Write *write,
|
||||
|
||||
png_free( write->pPng, (void *) png_palette );
|
||||
png_free( write->pPng, (void *) png_trans );
|
||||
VIPS_UNREF( im_palette );
|
||||
VIPS_UNREF( write->memory );
|
||||
|
||||
write->memory = im_quantised;
|
||||
VIPS_UNREF( im_palette );
|
||||
|
||||
VIPS_UNREF( write->memory );
|
||||
write->memory = im_index;
|
||||
in = write->memory;
|
||||
}
|
||||
#endif /*HAVE_IMAGEQUANT*/
|
||||
|
Loading…
Reference in New Issue
Block a user