1 /* quantise an image with libimagequant
2  *
3  * 20/6/18
4  * 	  - from vipspng.c
5  */
6 
7 /*
8 
9     This file is part of VIPS.
10 
11     VIPS is free software; you can redistribute it and/or modify
12     it under the terms of the GNU Lesser General Public License as published by
13     the Free Software Foundation; either version 2 of the License, or
14     (at your option) any later version.
15 
16     This program is distributed in the hope that it will be useful,
17     but WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19     GNU Lesser General Public License for more details.
20 
21     You should have received a copy of the GNU Lesser General Public License
22     along with this program; if not, write to the Free Software
23     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24     02110-1301  USA
25 
26  */
27 
28 /*
29 
30     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
31 
32  */
33 
34 /*
35 #define DEBUG
36 #define VIPS_DEBUG
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif /*HAVE_CONFIG_H*/
42 #include <vips/intl.h>
43 
44 #include <vips/vips.h>
45 
46 #ifdef HAVE_IMAGEQUANT
47 
48 #include "pforeign.h"
49 
50 #include <libimagequant.h>
51 
52 /* Track during a quantisation.
53  */
54 typedef struct _Quantise {
55 	VipsImage *in;
56 	VipsImage **index_out;
57 	VipsImage **palette_out;
58 	int colours;
59 	int Q;
60 	double dither;
61 	int effort;
62 
63 	liq_attr *attr;
64 	liq_image *input_image;
65 	liq_result *quantisation_result;
66 	VipsImage *t[5];
67 } Quantise;
68 
69 static void
vips__quantise_free(Quantise * quantise)70 vips__quantise_free( Quantise *quantise )
71 {
72 	int i;
73 
74 	VIPS_FREEF( liq_result_destroy, quantise->quantisation_result );
75 	VIPS_FREEF( liq_image_destroy, quantise->input_image );
76 	VIPS_FREEF( liq_attr_destroy, quantise->attr );
77 
78 	for( i = 0; i < VIPS_NUMBER( quantise->t ); i++ )
79 		VIPS_UNREF( quantise->t[i] );
80 
81 	VIPS_FREE( quantise );
82 }
83 
84 static Quantise *
vips__quantise_new(VipsImage * in,VipsImage ** index_out,VipsImage ** palette_out,int colours,int Q,double dither,int effort)85 vips__quantise_new( VipsImage *in,
86 	VipsImage **index_out, VipsImage **palette_out,
87         int colours, int Q, double dither, int effort )
88 {
89 	Quantise *quantise;
90 	int i;
91 
92 	quantise = VIPS_NEW( NULL, Quantise );
93 	quantise->in = in;
94 	quantise->index_out = index_out;
95 	quantise->palette_out = palette_out;
96 	quantise->colours = colours;
97 	quantise->Q = Q;
98 	quantise->dither = dither;
99 	quantise->effort = effort;
100 	for( i = 0; i < VIPS_NUMBER( quantise->t ); i++ )
101 		quantise->t[i] = NULL;
102 
103 	return( quantise );
104 }
105 
106 int
vips__quantise_image(VipsImage * in,VipsImage ** index_out,VipsImage ** palette_out,int colours,int Q,double dither,int effort,gboolean threshold_alpha)107 vips__quantise_image( VipsImage *in,
108 	VipsImage **index_out, VipsImage **palette_out,
109 	int colours, int Q, double dither, int effort,
110 	gboolean threshold_alpha )
111 {
112 	Quantise *quantise;
113 	VipsImage *index;
114 	VipsImage *palette;
115 	const liq_palette *lp;
116 	gint64 i;
117 	VipsPel * restrict p;
118 	gboolean added_alpha;
119 
120 	quantise = vips__quantise_new( in, index_out, palette_out,
121 		colours, Q, dither, effort );
122 
123 	/* Ensure input is sRGB.
124 	 */
125 	if( in->Type != VIPS_INTERPRETATION_sRGB ) {
126 		if( vips_colourspace( in, &quantise->t[0],
127 			VIPS_INTERPRETATION_sRGB, NULL ) ) {
128 			vips__quantise_free( quantise );
129 			return( -1 );
130 		}
131 		in = quantise->t[0];
132 	}
133 
134 	/* Add alpha channel if missing.
135 	 */
136 	added_alpha = FALSE;
137 	if( !vips_image_hasalpha( in ) ) {
138 		if( vips_bandjoin_const1( in, &quantise->t[1], 255, NULL ) ) {
139 			vips__quantise_free( quantise );
140 			return( -1 );
141 		}
142 		added_alpha = TRUE;
143 		in = quantise->t[1];
144 	}
145 
146 	if( !(quantise->t[2] = vips_image_copy_memory( in )) ) {
147 		vips__quantise_free( quantise );
148 		return( -1 );
149 	}
150 	in = quantise->t[2];
151 
152 	/* Threshold alpha channel.
153 	 */
154 	if( threshold_alpha &&
155 		!added_alpha ) {
156 		const guint64 n_pels = VIPS_IMAGE_N_PELS( in );
157 
158 		p = VIPS_IMAGE_ADDR( in, 0, 0 );
159 		for( i = 0; i < n_pels; i++ ) {
160 			p[3] = p[3] > 128 ? 255 : 0;
161 			p += 4;
162 		}
163 	}
164 
165 	quantise->attr = liq_attr_create();
166 	liq_set_max_colors( quantise->attr, colours );
167 	liq_set_quality( quantise->attr, 0, Q );
168 	liq_set_speed( quantise->attr, 11 - effort );
169 
170 	quantise->input_image = liq_image_create_rgba( quantise->attr,
171 		VIPS_IMAGE_ADDR( in, 0, 0 ), in->Xsize, in->Ysize, 0 );
172 
173 	if( liq_image_quantize( quantise->input_image, quantise->attr,
174 		&quantise->quantisation_result ) ) {
175 		vips_error( "quantise", "%s", _( "quantisation failed" ) );
176 		vips__quantise_free( quantise );
177 		return( -1 );
178 	}
179 
180 	liq_set_dithering_level( quantise->quantisation_result, dither );
181 
182 	index = quantise->t[3] = vips_image_new_memory();
183 	vips_image_init_fields( index,
184 		in->Xsize, in->Ysize, 1, VIPS_FORMAT_UCHAR,
185 		VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
186 
187 	if( vips_image_write_prepare( index ) ) {
188 		vips__quantise_free( quantise );
189 		return( -1 );
190 	}
191 
192 	if( liq_write_remapped_image( quantise->quantisation_result,
193 		quantise->input_image,
194 		VIPS_IMAGE_ADDR( index, 0, 0 ), VIPS_IMAGE_N_PELS( index ) ) ) {
195 		vips_error( "quantise", "%s", _( "quantisation failed" ) );
196 		vips__quantise_free( quantise );
197 		return( -1 );
198 	}
199 
200 	lp = liq_get_palette( quantise->quantisation_result );
201 
202 	palette = quantise->t[4] = vips_image_new_memory();
203 	vips_image_init_fields( palette, lp->count, 1, 4,
204 		VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB,
205 		1.0, 1.0 );
206 
207 	if( vips_image_write_prepare( palette ) ) {
208 		vips__quantise_free( quantise );
209 		return( -1 );
210 	}
211 
212 	p = VIPS_IMAGE_ADDR( palette, 0, 0 );
213 	for( i = 0; i < lp->count; i++ ) {
214 		p[0] = lp->entries[i].r;
215 		p[1] = lp->entries[i].g;
216 		p[2] = lp->entries[i].b;
217 		p[3] = lp->entries[i].a;
218 
219 		p += 4;
220 	}
221 
222 	*index_out = index;
223 	g_object_ref( index );
224 	*palette_out = palette;
225 	g_object_ref( palette );
226 
227 	vips__quantise_free( quantise );
228 
229 	return( 0 );
230 }
231 
232 #else /*!HAVE_IMAGEQUANT*/
233 
234 int
vips__quantise_image(VipsImage * in,VipsImage ** index_out,VipsImage ** palette_out,int colours,int Q,double dither,int effort,gboolean threshold_alpha)235 vips__quantise_image( VipsImage *in,
236 	VipsImage **index_out, VipsImage **palette_out,
237 	int colours, int Q, double dither, int effort,
238 	gboolean threshold_alpha )
239 {
240 	vips_error( "vips__quantise_image",
241 		"%s", _( "libvips not built with quantisation support" ) );
242 
243 	return( -1 );
244 }
245 
246 #endif /*HAVE_IMAGEQUANT*/
247 
248