Skip to content

Commit 34e34ab

Browse files
committed
add vips_dither
compiles!
1 parent b811381 commit 34e34ab

File tree

3 files changed

+284
-0
lines changed

3 files changed

+284
-0
lines changed

libvips/conversion/conversion.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ vips_conversion_operation_init( void )
376376
extern GType vips_composite_get_type( void );
377377
extern GType vips_copy_get_type( void );
378378
extern GType vips_crop_get_type( void );
379+
extern GType vips_dither_get_type( void );
379380
extern GType vips_embed_get_type( void );
380381
extern GType vips_extract_area_get_type( void );
381382
extern GType vips_extract_band_get_type( void );
@@ -426,6 +427,7 @@ vips_conversion_operation_init( void )
426427
vips_composite_get_type();
427428
vips_copy_get_type();
428429
vips_crop_get_type();
430+
vips_dither_get_type();
429431
vips_embed_get_type();
430432
vips_extract_area_get_type();
431433
vips_extract_band_get_type();

libvips/conversion/dither.c

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
/* find a dither
2+
*
3+
* 25/9/22
4+
* - from cgifsave.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+
#ifdef HAVE_CONFIG_H
35+
#include <config.h>
36+
#endif /*HAVE_CONFIG_H*/
37+
#include <glib/gi18n-lib.h>
38+
39+
#include <stdio.h>
40+
#include <stdlib.h>
41+
42+
#include <vips/vips.h>
43+
#include <vips/internal.h>
44+
45+
#include "pconversion.h"
46+
#include "../foreign/quantise.h"
47+
48+
typedef struct _VipsDither {
49+
VipsConversion parent_instance;
50+
51+
VipsImage *in;
52+
VipsImage *palette;
53+
double dither;
54+
55+
VipsQuantiseAttr *attr;
56+
VipsQuantiseImage *image;
57+
VipsQuantiseResult *result;
58+
59+
} VipsDither;
60+
61+
typedef VipsConversionClass VipsDitherClass;
62+
63+
G_DEFINE_TYPE( VipsDither, vips_dither, VIPS_TYPE_CONVERSION );
64+
65+
static void
66+
vips_dither_dispose( GObject *gobject )
67+
{
68+
VipsDither *dither = (VipsDither *) gobject;
69+
70+
VIPS_FREEF( vips__quantise_result_destroy, dither->result );
71+
VIPS_FREEF( vips__quantise_image_destroy, dither->image );
72+
VIPS_FREEF( vips__quantise_attr_destroy, dither->attr );
73+
74+
G_OBJECT_CLASS( vips_dither_parent_class )->dispose( gobject );
75+
}
76+
77+
static int
78+
vips_dither_to_rgba( VipsDither *dither, VipsImage *in, VipsImage **out )
79+
{
80+
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dither );
81+
VipsImage **t = (VipsImage **)
82+
vips_object_local_array( VIPS_OBJECT( dither ), 1 );
83+
84+
VipsImage *rgba;
85+
86+
rgba = in;
87+
g_object_ref( rgba );
88+
if( vips_check_uncoded( class->nickname, rgba ) ||
89+
vips_check_format( class->nickname, rgba, VIPS_FORMAT_UCHAR ) ||
90+
vips_check_bands_atleast( class->nickname, rgba, 3 ) ) {
91+
VIPS_UNREF( rgba );
92+
return( -1 );
93+
}
94+
95+
if( rgba->Bands == 3 ) {
96+
if( vips_addalpha( rgba, &t[0], NULL ) ) {
97+
VIPS_UNREF( rgba );
98+
return( -1 );
99+
}
100+
rgba = t[0];
101+
}
102+
else if( rgba->Bands > 4 ) {
103+
if( vips_extract_band( rgba, &t[0], 0, "n", 4, NULL ) ) {
104+
VIPS_UNREF( rgba );
105+
return( -1 );
106+
}
107+
rgba = t[0];
108+
}
109+
110+
*out = rgba;
111+
112+
return( 0 );
113+
}
114+
115+
static int
116+
vips_dither_build( VipsObject *object )
117+
{
118+
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
119+
VipsConversion *conversion = VIPS_CONVERSION( object );
120+
VipsDither *dither = (VipsDither *) object;
121+
VipsImage **t = (VipsImage **) vips_object_local_array( object, 5 );
122+
123+
VipsImage *in;
124+
VipsImage *palette;
125+
guint32 fake_image[257];
126+
int n_colours;
127+
128+
if( VIPS_OBJECT_CLASS( vips_dither_parent_class )->build( object ) )
129+
return( -1 );
130+
131+
in = dither->in;
132+
palette = dither->palette;
133+
134+
/* The palette can't have more than 256 entries.
135+
*/
136+
if( palette->Xsize != 1 &&
137+
palette->Ysize != 1 ) {
138+
vips_error( class->nickname, "%s",
139+
_( "palettes must have width or height 1" ) );
140+
return( -1 );
141+
}
142+
if( VIPS_IMAGE_N_PELS( palette ) > 256 ) {
143+
vips_error( class->nickname, "%s",
144+
_( "palettes must have not have more than "
145+
"256 elements" ) );
146+
return( -1 );
147+
}
148+
n_colours = palette->Xsize * palette->Ysize;
149+
150+
/* We only work for 8-bit RGBA images.
151+
*/
152+
if( vips_dither_to_rgba( dither, in, &t[0] ) ||
153+
vips_dither_to_rgba( dither, palette, &t[1] ) )
154+
return( -1 );
155+
in = t[0];
156+
palette = t[1];
157+
158+
/* We need the whole thing in memory.
159+
*/
160+
if( vips_image_wio_input( in ) ||
161+
vips_image_wio_input( palette ) )
162+
return( -1 );
163+
164+
dither->attr = vips__quantise_attr_create();
165+
vips__quantise_set_max_colors( dither->attr, n_colours );
166+
vips__quantise_set_quality( dither->attr, 0, 100 );
167+
168+
/* Make a fake image from the input palette and quantise that to get
169+
* the context we use for dithering.
170+
*/
171+
memcpy( fake_image, VIPS_IMAGE_ADDR( palette, 0, 0 ),
172+
n_colours * sizeof( int ) );
173+
dither->image = vips__quantise_image_create_rgba( dither->attr,
174+
fake_image, n_colours, 1, 0.0 );
175+
if( vips__quantise_image_quantize_fixed( dither->image,
176+
dither->attr, &dither->result ) ) {
177+
vips_error( class->nickname,
178+
"%s", _( "quantisation failed" ) );
179+
return( -1 );
180+
}
181+
VIPS_FREEF( vips__quantise_image_destroy, dither->image );
182+
183+
/* The frame index buffer.
184+
*/
185+
vips_image_init_fields( conversion->out,
186+
in->Xsize, in->Ysize, 1,
187+
VIPS_FORMAT_UCHAR,
188+
VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
189+
if( vips_image_write_prepare( conversion->out ) )
190+
return( -1 );
191+
dither->image = vips__quantise_image_create_rgba( dither->attr,
192+
VIPS_IMAGE_ADDR( conversion->out, 0, 0 ),
193+
conversion->out->Xsize, conversion->out->Ysize, 0.0 );
194+
195+
/* Now dither!
196+
*/
197+
vips__quantise_set_dithering_level( dither->result, dither->dither );
198+
if( vips__quantise_write_remapped_image( dither->result, dither->image,
199+
VIPS_IMAGE_ADDR( conversion->out, 0, 0 ),
200+
VIPS_IMAGE_N_PELS( conversion->out ) ) ) {
201+
vips_error( class->nickname, "%s", _( "dither failed" ) );
202+
return( -1 );
203+
}
204+
205+
return( 0 );
206+
}
207+
208+
static void
209+
vips_dither_class_init( VipsDitherClass *class )
210+
{
211+
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
212+
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
213+
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
214+
215+
gobject_class->dispose = vips_dither_dispose;
216+
gobject_class->set_property = vips_object_set_property;
217+
gobject_class->get_property = vips_object_get_property;
218+
219+
vobject_class->nickname = "dither";
220+
vobject_class->description = _( "dither image into palette" );
221+
vobject_class->build = vips_dither_build;
222+
223+
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
224+
225+
VIPS_ARG_IMAGE( class, "in", 0,
226+
_( "Input" ),
227+
_( "Input image" ),
228+
VIPS_ARGUMENT_REQUIRED_INPUT,
229+
G_STRUCT_OFFSET( VipsDither, in ) );
230+
231+
VIPS_ARG_IMAGE( class, "palette", 0,
232+
_( "Palette" ),
233+
_( "Palette image" ),
234+
VIPS_ARGUMENT_REQUIRED_INPUT,
235+
G_STRUCT_OFFSET( VipsDither, palette ) );
236+
237+
VIPS_ARG_DOUBLE( class, "dither", 10,
238+
_( "Dithering" ),
239+
_( "Amount of dithering" ),
240+
VIPS_ARGUMENT_OPTIONAL_INPUT,
241+
G_STRUCT_OFFSET( VipsDither, dither ),
242+
0.0, 1.0, 1.0 );
243+
244+
}
245+
246+
static void
247+
vips_dither_init( VipsDither *dither )
248+
{
249+
}
250+
251+
/**
252+
* vips_dither: (method)
253+
* @in: input image
254+
* @out: (out): output image
255+
* @palette: (in): palette image
256+
* @...: %NULL-terminated list of optional named arguments
257+
*
258+
* Optional arguments:
259+
*
260+
* * @dither: %gdouble, dithering level
261+
*
262+
* Dither @in using @palette.
263+
*
264+
* Use @dither to set the degree of Floyd-Steinberg dithering.
265+
*
266+
* See also: vips_palette().
267+
*
268+
* Returns: 0 on success, -1 on error
269+
*/
270+
int
271+
vips_dither( VipsImage *in, VipsImage **out, VipsImage *palette, ... )
272+
{
273+
va_list ap;
274+
int result;
275+
276+
va_start( ap, palette );
277+
result = vips_call_split( "dither", ap, in, out, palette );
278+
va_end( ap );
279+
280+
return( result );
281+
}

libvips/conversion/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ conversion_sources = files(
1414
'composite.cpp',
1515
'conversion.c',
1616
'copy.c',
17+
'dither.c',
1718
'embed.c',
1819
'extract.c',
1920
'falsecolour.c',

0 commit comments

Comments
 (0)