Quantizr support (#2542)

This commit is contained in:
Sergey Alexandrovich 2021-11-21 16:11:28 +06:00 committed by GitHub
parent 8c9d899acd
commit d71a3c2fc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 317 additions and 58 deletions

View File

@ -1362,6 +1362,8 @@ VIPS_CFLAGS="$VIPS_CFLAGS $PNG_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $PNG_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $PNG_LIBS"
with_quantization=no
# look for libimagequant with pkg-config (only if libpng is enabled)
AC_ARG_WITH([imagequant],
AS_HELP_STRING([--without-imagequant], [build without imagequant (default: test)]))
@ -1370,11 +1372,10 @@ if test x"$with_imagequant" != x"no"; then
PKG_CHECK_MODULES(IMAGEQUANT, imagequant,
[AC_DEFINE(HAVE_IMAGEQUANT,1,[define if you have imagequant installed.])
with_imagequant=yes
with_quantization=yes
PACKAGES_USED="$PACKAGES_USED imagequant"
],
[AC_MSG_WARN([libimagequant not found; disabling 8bpp PNG support])
with_imagequant=no
]
[with_imagequant=no]
)
else
with_imagequant=no
@ -1383,6 +1384,30 @@ fi
VIPS_CFLAGS="$VIPS_CFLAGS $IMAGEQUANT_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $IMAGEQUANT_LIBS"
# look for quantizr with pkg-config (only if libpng is enabled)
AC_ARG_WITH([quantizr],
AS_HELP_STRING([--without-quantizr], [build without quantizr (default: test)]))
if test x"$with_quantizr" != x"no"; then
PKG_CHECK_MODULES(QUANTIZR, quantizr,
[AC_DEFINE(HAVE_QUANTIZR,1,[define if you have quantizr installed.])
with_quantizr=yes
with_quantization=yes
PACKAGES_USED="$PACKAGES_USED quantizr"
],
[with_quantizr=no]
)
else
with_quantizr=no
fi
VIPS_CFLAGS="$VIPS_CFLAGS $QUANTIZR_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $QUANTIZR_LIBS"
if test x"$with_quantization" == x"no"; then
AC_MSG_WARN([quantizr not found; disabling 8bpp PNG support])
fi
# look for libjpeg with pkg-config ... fall back to our tester
AC_ARG_WITH([jpeg],
AS_HELP_STRING([--without-jpeg], [build without libjpeg (default: test)]))
@ -1458,7 +1483,7 @@ VIPS_LIBS="$VIPS_LIBS $EXIF_LIBS"
AC_ARG_WITH([cgif],
AS_HELP_STRING([--without-cgif], [build without cgif (default: test)]))
if test x"$with_imagequant" == x"yes" && test x"$with_cgif" != x"no"; then
if test x"$with_quantization" == x"yes" && test x"$with_cgif" != x"no"; then
PKG_CHECK_MODULES(CGIF, cgif,
[AC_DEFINE(HAVE_CGIF,1,[define if you have cgif installed.])
with_cgif=yes
@ -1617,8 +1642,8 @@ PNG load with libspng: $with_libspng
(requires libspng-0.6 or later)
PNG load/save with libpng: $with_png
(requires libpng-1.2.9 or later)
quantisation to 8 bit: $with_imagequant
(requires libimagequant)
quantisation to 8 bit: $with_quantization
(requires libimagequant or quantizr)
TIFF load/save with libtiff: $with_tiff
image pyramid save: $with_gsf
(requires libgsf-1 1.14.26 or later)
@ -1637,7 +1662,7 @@ Matlab load with matio: $with_matio
NIfTI load/save with niftiio: $with_nifti
FITS load/save with cfitsio: $with_cfitsio
GIF save with cgif: $with_cgif
(requires cgif, libimagequant)
(requires cgif, libimagequant or quantizr)
Magick package: $with_magickpackage (dynamic module: $with_magick_module)
Magick major API version: $magick_version
load with libMagickCore: $enable_magickload

View File

@ -47,10 +47,10 @@
#include <vips/vips.h>
#include "pforeign.h"
#include "quantise.h"
#if defined(HAVE_CGIF) && defined(HAVE_IMAGEQUANT)
#if defined(HAVE_CGIF) && defined(HAVE_QUANTIZATION)
#include <libimagequant.h>
#include <cgif.h>
typedef struct _VipsForeignSaveCgif {
@ -81,10 +81,10 @@ typedef struct _VipsForeignSaveCgif {
/* The frame as seen by libimagequant.
*/
liq_attr *attr;
liq_image *input_image;
liq_result *quantisation_result;
const liq_palette *lp;
VipsQuantiseAttr *attr;
VipsQuantiseImage *input_image;
VipsQuantiseResult *quantisation_result;
const VipsQuantisePalette *lp;
/* The current colourmap, updated on a significant frame change.
*
@ -130,9 +130,9 @@ vips_foreign_save_cgif_dispose( GObject *gobject )
VIPS_UNREF( cgif->target );
VIPS_UNREF( cgif->frame );
VIPS_FREEF( liq_result_destroy, cgif->quantisation_result );
VIPS_FREEF( liq_image_destroy, cgif->input_image );
VIPS_FREEF( liq_attr_destroy, cgif->attr );
VIPS_FREEF( vips__quantise_result_destroy, cgif->quantisation_result );
VIPS_FREEF( vips__quantise_image_destroy, cgif->input_image );
VIPS_FREEF( vips__quantise_attr_destroy, cgif->attr );
VIPS_FREE( cgif->palette_rgb );
VIPS_FREE( cgif->index );
@ -179,8 +179,8 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
/* Set up new frame for libimagequant.
*/
VIPS_FREEF( liq_image_destroy, cgif->input_image );
cgif->input_image = liq_image_create_rgba( cgif->attr,
VIPS_FREEF( vips__quantise_image_destroy, cgif->input_image );
cgif->input_image = vips__quantise_image_create_rgba( cgif->attr,
frame_bytes, frame_rect->width, frame_rect->height, 0 );
/* Threshold the alpha channel. It's safe to modify the region since
@ -215,8 +215,8 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
if( cgif->quantisation_result )
cgif->cgif_config.attrFlags |= CGIF_ATTR_NO_GLOBAL_TABLE;
VIPS_FREEF( liq_result_destroy, cgif->quantisation_result );
if( liq_image_quantize( cgif->input_image, cgif->attr,
VIPS_FREEF( vips__quantise_result_destroy, cgif->quantisation_result );
if( vips__quantise_image_quantize( cgif->input_image, cgif->attr,
&cgif->quantisation_result ) ) {
vips_error( class->nickname,
"%s", _( "quantisation failed" ) );
@ -230,17 +230,17 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
/* Dither frame.
*/
liq_set_dithering_level( cgif->quantisation_result, cgif->dither );
if( liq_write_remapped_image( cgif->quantisation_result,
vips__quantise_set_dithering_level( cgif->quantisation_result, cgif->dither );
if( vips__quantise_write_remapped_image( cgif->quantisation_result,
cgif->input_image, cgif->index, n_pels ) ) {
vips_error( class->nickname, "%s", _( "dither failed" ) );
return( -1 );
}
/* Call liq_get_palette() after liq_write_remapped_image(),
/* Call vips__quantise_get_palette() after vips__quantise_write_remapped_image(),
* as palette is improved during remapping.
*/
cgif->lp = liq_get_palette( cgif->quantisation_result );
cgif->lp = vips__quantise_get_palette( cgif->quantisation_result );
rgb = cgif->palette_rgb;
g_assert( cgif->lp->count <= 256 );
for( i = 0; i < cgif->lp->count; i++ ) {
@ -458,10 +458,10 @@ vips_foreign_save_cgif_build( VipsObject *object )
/* Set up libimagequant.
*/
cgif->attr = liq_attr_create();
liq_set_max_colors( cgif->attr, (1 << cgif->bitdepth) - 1 );
liq_set_quality( cgif->attr, 0, 100 );
liq_set_speed( cgif->attr, 11 - cgif->effort );
cgif->attr = vips__quantise_attr_create();
vips__quantise_set_max_colors( cgif->attr, (1 << cgif->bitdepth) - 1 );
vips__quantise_set_quality( cgif->attr, 0, 100 );
vips__quantise_set_speed( cgif->attr, 11 - cgif->effort );
/* Set up cgif on first use.
*/

View File

@ -217,11 +217,6 @@ int vips__webp_write_target( VipsImage *image, VipsTarget *target,
gboolean min_size, int kmin, int kmax,
gboolean strip, const char *profile );
int vips__quantise_image( VipsImage *in,
VipsImage **index_out, VipsImage **palette_out,
int colours, int Q, double dither, int effort,
gboolean threshold_alpha );
extern const char *vips_foreign_nifti_suffs[];
VipsBandFormat vips__foreign_nifti_datatype2BandFmt( int datatype );

View File

@ -1,4 +1,4 @@
/* quantise an image with libimagequant
/* quantise an image
*
* 20/6/18
* - from vipspng.c
@ -43,11 +43,164 @@
#include <vips/vips.h>
#ifdef HAVE_IMAGEQUANT
#include "quantise.h"
#ifdef HAVE_QUANTIZATION
#include "pforeign.h"
#include <libimagequant.h>
#if defined(HAVE_IMAGEQUANT)
VipsQuantiseAttr*
vips__quantise_attr_create()
{
return liq_attr_create();
}
VipsQuantiseError
vips__quantise_set_max_colors(VipsQuantiseAttr* attr, int colors)
{
return liq_set_max_colors(attr, colors);
}
VipsQuantiseError
vips__quantise_set_quality(VipsQuantiseAttr* attr, int minimum, int maximum)
{
return liq_set_quality(attr, minimum, maximum);
}
VipsQuantiseError
vips__quantise_set_speed(VipsQuantiseAttr* attr, int speed)
{
return liq_set_speed(attr, speed);
}
VipsQuantiseImage*
vips__quantise_image_create_rgba(const VipsQuantiseAttr *attr, const void *bitmap, int width, int height, double gamma)
{
return liq_image_create_rgba(attr, bitmap, width, height, gamma);
}
VipsQuantiseError
vips__quantise_image_quantize(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output)
{
return liq_image_quantize(input_image, options, result_output);
}
VipsQuantiseError
vips__quantise_set_dithering_level(VipsQuantiseResult *res, float dither_level)
{
return liq_set_dithering_level(res, dither_level);
}
const VipsQuantisePalette*
vips__quantise_get_palette(VipsQuantiseResult *result)
{
return liq_get_palette(result);
}
VipsQuantiseError
vips__quantise_write_remapped_image(VipsQuantiseResult *result, VipsQuantiseImage *input_image, void *buffer, size_t buffer_size)
{
return liq_write_remapped_image(result, input_image, buffer, buffer_size);
}
void
vips__quantise_result_destroy(VipsQuantiseResult *result)
{
liq_result_destroy(result);
}
void
vips__quantise_image_destroy(VipsQuantiseImage *img)
{
liq_image_destroy(img);
}
void
vips__quantise_attr_destroy(VipsQuantiseAttr *attr)
{
liq_attr_destroy(attr);
}
#elif defined(HAVE_QUANTIZR) /*HAVE_IMAGEQUANT*/
VipsQuantiseAttr*
vips__quantise_attr_create()
{
return quantizr_new_options();
}
VipsQuantiseError
vips__quantise_set_max_colors(VipsQuantiseAttr* attr, int colors)
{
return quantizr_set_max_colors(attr, colors);
}
VipsQuantiseError
vips__quantise_set_quality(VipsQuantiseAttr* attr, int minimum, int maximum)
{
// Not supported by quantizr
return 0;
}
VipsQuantiseError
vips__quantise_set_speed(VipsQuantiseAttr* attr, int speed)
{
// Not supported by quantizr
return 0;
}
VipsQuantiseImage*
vips__quantise_image_create_rgba(const VipsQuantiseAttr *attr, const void *bitmap, int width, int height, double gamma)
{
return quantizr_create_image_rgba((unsigned char*)bitmap, width, height);
}
VipsQuantiseError
vips__quantise_image_quantize(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output)
{
*result_output = quantizr_quantize(input_image, options);
return 0;
}
VipsQuantiseError
vips__quantise_set_dithering_level(VipsQuantiseResult *res, float dither_level)
{
return quantizr_set_dithering_level(res, dither_level);
}
const VipsQuantisePalette*
vips__quantise_get_palette(VipsQuantiseResult *result)
{
return quantizr_get_palette(result);
}
VipsQuantiseError
vips__quantise_write_remapped_image(VipsQuantiseResult *result, VipsQuantiseImage *input_image, void *buffer, size_t buffer_size)
{
return quantizr_remap(result, input_image, buffer, buffer_size);
}
void
vips__quantise_result_destroy(VipsQuantiseResult *result)
{
quantizr_free_result(result);
}
void
vips__quantise_image_destroy(VipsQuantiseImage *img)
{
quantizr_free_image(img);
}
void
vips__quantise_attr_destroy(VipsQuantiseAttr *attr)
{
quantizr_free_options(attr);
}
#endif /*HAVE_QUANTIZR*/
/* Track during a quantisation.
*/
@ -60,9 +213,9 @@ typedef struct _Quantise {
double dither;
int effort;
liq_attr *attr;
liq_image *input_image;
liq_result *quantisation_result;
VipsQuantiseAttr *attr;
VipsQuantiseImage *input_image;
VipsQuantiseResult *quantisation_result;
VipsImage *t[5];
} Quantise;
@ -71,9 +224,9 @@ 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 );
VIPS_FREEF( vips__quantise_result_destroy, quantise->quantisation_result );
VIPS_FREEF( vips__quantise_image_destroy, quantise->input_image );
VIPS_FREEF( vips__quantise_attr_destroy, quantise->attr );
for( i = 0; i < VIPS_NUMBER( quantise->t ); i++ )
VIPS_UNREF( quantise->t[i] );
@ -112,7 +265,7 @@ vips__quantise_image( VipsImage *in,
Quantise *quantise;
VipsImage *index;
VipsImage *palette;
const liq_palette *lp;
const VipsQuantisePalette *lp;
gint64 i;
VipsPel * restrict p;
gboolean added_alpha;
@ -162,22 +315,22 @@ vips__quantise_image( VipsImage *in,
}
}
quantise->attr = liq_attr_create();
liq_set_max_colors( quantise->attr, colours );
liq_set_quality( quantise->attr, 0, Q );
liq_set_speed( quantise->attr, 11 - effort );
quantise->attr = vips__quantise_attr_create();
vips__quantise_set_max_colors( quantise->attr, colours );
vips__quantise_set_quality( quantise->attr, 0, Q );
vips__quantise_set_speed( quantise->attr, 11 - effort );
quantise->input_image = liq_image_create_rgba( quantise->attr,
quantise->input_image = vips__quantise_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,
if( vips__quantise_image_quantize( quantise->input_image, quantise->attr,
&quantise->quantisation_result ) ) {
vips_error( "quantise", "%s", _( "quantisation failed" ) );
vips__quantise_free( quantise );
return( -1 );
}
liq_set_dithering_level( quantise->quantisation_result, dither );
vips__quantise_set_dithering_level( quantise->quantisation_result, dither );
index = quantise->t[3] = vips_image_new_memory();
vips_image_init_fields( index,
@ -189,7 +342,7 @@ vips__quantise_image( VipsImage *in,
return( -1 );
}
if( liq_write_remapped_image( quantise->quantisation_result,
if( vips__quantise_write_remapped_image( quantise->quantisation_result,
quantise->input_image,
VIPS_IMAGE_ADDR( index, 0, 0 ), VIPS_IMAGE_N_PELS( index ) ) ) {
vips_error( "quantise", "%s", _( "quantisation failed" ) );
@ -197,7 +350,7 @@ vips__quantise_image( VipsImage *in,
return( -1 );
}
lp = liq_get_palette( quantise->quantisation_result );
lp = vips__quantise_get_palette( quantise->quantisation_result );
palette = quantise->t[4] = vips_image_new_memory();
vips_image_init_fields( palette, lp->count, 1, 4,
@ -229,7 +382,7 @@ vips__quantise_image( VipsImage *in,
return( 0 );
}
#else /*!HAVE_IMAGEQUANT*/
#else /*!HAVE_QUANTIZATION*/
int
vips__quantise_image( VipsImage *in,
@ -243,5 +396,5 @@ vips__quantise_image( VipsImage *in,
return( -1 );
}
#endif /*HAVE_IMAGEQUANT*/
#endif /*HAVE_QUANTIZATION*/

View File

@ -0,0 +1,85 @@
/* common defs for image quantisation
*/
/*
Copyright (C) 1991-2005 The National Gallery
This library 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.1 of the License, or (at your option) any later version.
This library 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 library; 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
*/
#ifndef VIPS_QUANTISE_H
#define VIPS_QUANTISE_H
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
#if defined(HAVE_IMAGEQUANT)
#define HAVE_QUANTIZATION
#include <libimagequant.h>
#define VipsQuantiseAttr liq_attr
#define VipsQuantiseImage liq_image
#define VipsQuantiseResult liq_result
#define VipsQuantisePalette liq_palette
#define VipsQuantiseError liq_error
#elif defined(HAVE_QUANTIZR)
#define HAVE_QUANTIZATION
#include <quantizr.h>
#define VipsQuantiseAttr QuantizrOptions
#define VipsQuantiseImage QuantizrImage
#define VipsQuantiseResult QuantizrResult
#define VipsQuantisePalette QuantizrPalette
#define VipsQuantiseError QuantizrError
#endif
#ifdef HAVE_QUANTIZATION
VipsQuantiseAttr* vips__quantise_attr_create();
VipsQuantiseError vips__quantise_set_max_colors(VipsQuantiseAttr* attr, int colors);
VipsQuantiseError vips__quantise_set_quality(VipsQuantiseAttr* attr, int minimum, int maximum);
VipsQuantiseError vips__quantise_set_speed(VipsQuantiseAttr* attr, int speed);
VipsQuantiseImage* vips__quantise_image_create_rgba(const VipsQuantiseAttr *attr, const void *bitmap, int width, int height, double gamma);
VipsQuantiseError vips__quantise_image_quantize(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output);
VipsQuantiseError vips__quantise_set_dithering_level(VipsQuantiseResult *res, float dither_level);
const VipsQuantisePalette* vips__quantise_get_palette(VipsQuantiseResult *result);
VipsQuantiseError vips__quantise_write_remapped_image(VipsQuantiseResult *result, VipsQuantiseImage *input_image, void *buffer, size_t buffer_size);
void vips__quantise_result_destroy(VipsQuantiseResult *result);
void vips__quantise_image_destroy(VipsQuantiseImage *img);
void vips__quantise_attr_destroy(VipsQuantiseAttr *attr);
#endif /*HAVE_QUANTIZATION*/
int vips__quantise_image( VipsImage *in,
VipsImage **index_out, VipsImage **palette_out,
int colours, int Q, double dither, int effort,
gboolean threshold_alpha );
#ifdef __cplusplus
}
#endif /*__cplusplus*/
#endif /*VIPS_QUANTISE_H*/

View File

@ -133,6 +133,7 @@
#include <vips/debug.h>
#include "pforeign.h"
#include "quantise.h"
#include <png.h>
@ -1072,7 +1073,7 @@ write_vips( Write *write,
return( -1 );
}
#ifdef HAVE_IMAGEQUANT
#ifdef HAVE_QUANTIZATION
/* Enable image quantisation to paletted 8bpp PNG if colours is set.
*/
if( palette )
@ -1081,7 +1082,7 @@ write_vips( Write *write,
if( palette )
g_warning( "%s",
_( "ignoring palette (no quantisation support)" ) );
#endif /*HAVE_IMAGEQUANT*/
#endif /*HAVE_QUANTIZATION*/
interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
@ -1181,7 +1182,7 @@ write_vips( Write *write,
return( -1 );
}
#ifdef HAVE_IMAGEQUANT
#ifdef HAVE_QUANTIZATION
if( palette ) {
VipsImage *im_index;
VipsImage *im_palette;
@ -1244,7 +1245,7 @@ write_vips( Write *write,
write->memory = im_index;
in = write->memory;
}
#endif /*HAVE_IMAGEQUANT*/
#endif /*HAVE_QUANTIZATION*/
png_write_info( write->pPng, write->pInfo );