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