1 /* in-place insert
2 *
3 * Copyright: J. Cupitt
4 * Written: 15/06/1992
5 * 22/7/93 JC
6 * - im_incheck() added
7 * 16/8/94 JC
8 * - im_incheck() changed to im_makerw()
9 * 1/9/04 JC
10 * - checks bands/types/etc match (thanks Matt)
11 * - smarter pixel size calculations
12 * 5/12/06
13 * - im_invalidate() after paint
14 * 24/3/09
15 * - added IM_CODING_RAD support
16 * 21/10/09
17 * - allow sub to be outside main
18 * - gtkdoc
19 * 6/3/10
20 * - don't im_invalidate() after paint, this now needs to be at a higher
21 * level
22 * 25/8/10
23 * - cast and bandalike sub to main
24 * 22/9/10
25 * - rename to im_draw_image()
26 * - gtk-doc
27 * 9/2/14
28 * - redo as a class, based on draw_image
29 * 28/3/14
30 * - add "mode" param
31 */
32
33 /*
34
35 This file is part of VIPS.
36
37 VIPS is free software; you can redistribute it and/or modify
38 it under the terms of the GNU Lesser General Public License as published by
39 the Free Software Foundation; either version 2 of the License, or
40 (at your option) any later version.
41
42 This program is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 GNU Lesser General Public License for more details.
46
47 You should have received a copy of the GNU Lesser General Public License
48 along with this program; if not, write to the Free Software
49 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
50 02110-1301 USA
51
52 */
53
54 /*
55
56 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
57
58 */
59
60 #ifdef HAVE_CONFIG_H
61 #include <config.h>
62 #endif /*HAVE_CONFIG_H*/
63 #include <vips/intl.h>
64
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <limits.h>
69
70 #include <vips/vips.h>
71 #include <vips/internal.h>
72
73 #include "pdraw.h"
74
75 typedef struct _VipsDrawImage {
76 VipsDraw parent_object;
77
78 /* Parameters.
79 */
80 VipsImage *sub;
81 int x;
82 int y;
83 VipsCombineMode mode;
84
85 } VipsDrawImage;
86
87 typedef struct _VipsDrawImageClass {
88 VipsDrawClass parent_class;
89
90 } VipsDrawImageClass;
91
92 G_DEFINE_TYPE( VipsDrawImage, vips_draw_image, VIPS_TYPE_DRAW );
93
94 #define LOOP( TYPE, TEMP, MIN, MAX ) { \
95 TYPE * restrict pt = (TYPE *) p; \
96 TYPE * restrict qt = (TYPE *) q; \
97 \
98 for( x = 0; x < sz; x++ ) { \
99 TEMP v; \
100 \
101 v = pt[x] + qt[x]; \
102 \
103 qt[x] = VIPS_CLIP( MIN, v, MAX ); \
104 } \
105 }
106
107 #define LOOPF( TYPE ) { \
108 TYPE * restrict pt = (TYPE *) p; \
109 TYPE * restrict qt = (TYPE *) q; \
110 \
111 for( x = 0; x < sz; x++ ) \
112 qt[x] += pt[x]; \
113 }
114
115 static void
vips_draw_image_mode_add(VipsDrawImage * draw_image,VipsImage * im,VipsPel * q,VipsPel * p,int n)116 vips_draw_image_mode_add( VipsDrawImage *draw_image, VipsImage *im,
117 VipsPel *q, VipsPel *p, int n )
118 {
119 /* Complex just doubles the size.
120 */
121 const int sz = n * im->Bands *
122 (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1);
123
124 int x;
125
126 switch( im->BandFmt ) {
127 case VIPS_FORMAT_UCHAR:
128 LOOP( unsigned char, int, 0, UCHAR_MAX ); break;
129 case VIPS_FORMAT_CHAR:
130 LOOP( signed char, int, SCHAR_MIN, SCHAR_MAX ); break;
131 case VIPS_FORMAT_USHORT:
132 LOOP( unsigned short, int, 0, USHRT_MAX ); break;
133 case VIPS_FORMAT_SHORT:
134 LOOP( signed short, int, SCHAR_MIN, SCHAR_MAX ); break;
135 case VIPS_FORMAT_UINT:
136 LOOP( unsigned int, gint64, 0, UINT_MAX ); break;
137 case VIPS_FORMAT_INT:
138 LOOP( signed int, gint64, INT_MIN, INT_MAX ); break;
139
140 case VIPS_FORMAT_FLOAT:
141 case VIPS_FORMAT_COMPLEX:
142 LOOPF( float ); break;
143
144 case VIPS_FORMAT_DOUBLE:
145 case VIPS_FORMAT_DPCOMPLEX:
146 LOOPF( double ); break;
147
148 default:
149 g_assert_not_reached();
150 }
151 }
152
153 static int
vips_draw_image_build(VipsObject * object)154 vips_draw_image_build( VipsObject *object )
155 {
156 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
157 VipsDraw *draw = VIPS_DRAW( object );
158 VipsDrawImage *draw_image = (VipsDrawImage *) object;
159 VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 );
160
161 VipsImage *im;
162 VipsRect image_rect;
163 VipsRect sub_rect;
164 VipsRect clip_rect;
165
166 if( VIPS_OBJECT_CLASS( vips_draw_image_parent_class )->build( object ) )
167 return( -1 );
168
169 if( vips_check_coding_known( class->nickname, draw->image ) ||
170 vips_check_coding_same( class->nickname,
171 draw->image, draw_image->sub ) ||
172 vips_check_bands_1orn_unary( class->nickname,
173 draw_image->sub, draw->image->Bands ) )
174 return( -1 );
175
176 /* SET will work for any matching coding, but every other mode needs
177 * uncoded images.
178 */
179 if( draw_image->mode != VIPS_COMBINE_MODE_SET &&
180 vips_check_uncoded( class->nickname, draw->image ) )
181 return( -1 );
182
183 /* Cast sub to match main in bands and format.
184 */
185 im = draw_image->sub;
186 if( im->Coding == VIPS_CODING_NONE ) {
187 if( vips__bandup( class->nickname,
188 im, &t[0], draw->image->Bands ) ||
189 vips_cast( t[0], &t[1], draw->image->BandFmt, NULL ) )
190 return( -1 );
191
192 im = t[1];
193 }
194
195 /* Make rects for main and sub and clip.
196 */
197 image_rect.left = 0;
198 image_rect.top = 0;
199 image_rect.width = draw->image->Xsize;
200 image_rect.height = draw->image->Ysize;
201 sub_rect.left = draw_image->x;
202 sub_rect.top = draw_image->y;
203 sub_rect.width = im->Xsize;
204 sub_rect.height = im->Ysize;
205 vips_rect_intersectrect( &image_rect, &sub_rect, &clip_rect );
206
207 if( !vips_rect_isempty( &clip_rect ) ) {
208 VipsPel *p, *q;
209 int y;
210
211 if( vips_image_wio_input( im ) )
212 return( -1 );
213
214 p = VIPS_IMAGE_ADDR( im,
215 clip_rect.left - draw_image->x,
216 clip_rect.top - draw_image->y );
217 q = VIPS_IMAGE_ADDR( draw->image,
218 clip_rect.left, clip_rect.top );
219
220 for( y = 0; y < clip_rect.height; y++ ) {
221 switch( draw_image->mode ) {
222 case VIPS_COMBINE_MODE_SET:
223 memcpy( (char *) q, (char *) p,
224 clip_rect.width *
225 VIPS_IMAGE_SIZEOF_PEL( im ) );
226 break;
227
228 case VIPS_COMBINE_MODE_ADD:
229 vips_draw_image_mode_add( draw_image,
230 im, q, p, clip_rect.width );
231 break;
232
233 default:
234 g_assert_not_reached();
235 }
236
237 p += VIPS_IMAGE_SIZEOF_LINE( im );
238 q += VIPS_IMAGE_SIZEOF_LINE( draw->image );
239 }
240 }
241
242 return( 0 );
243 }
244
245 static void
vips_draw_image_class_init(VipsDrawImageClass * class)246 vips_draw_image_class_init( VipsDrawImageClass *class )
247 {
248 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
249 VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
250
251 gobject_class->set_property = vips_object_set_property;
252 gobject_class->get_property = vips_object_get_property;
253
254 vobject_class->nickname = "draw_image";
255 vobject_class->description = _( "paint an image into another image" );
256 vobject_class->build = vips_draw_image_build;
257
258 VIPS_ARG_IMAGE( class, "sub", 5,
259 _( "Sub-image" ),
260 _( "Sub-image to insert into main image" ),
261 VIPS_ARGUMENT_REQUIRED_INPUT,
262 G_STRUCT_OFFSET( VipsDrawImage, sub ) );
263
264 VIPS_ARG_INT( class, "x", 6,
265 _( "x" ),
266 _( "Draw image here" ),
267 VIPS_ARGUMENT_REQUIRED_INPUT,
268 G_STRUCT_OFFSET( VipsDrawImage, x ),
269 -1000000000, 1000000000, 0 );
270
271 VIPS_ARG_INT( class, "y", 7,
272 _( "y" ),
273 _( "Draw image here" ),
274 VIPS_ARGUMENT_REQUIRED_INPUT,
275 G_STRUCT_OFFSET( VipsDrawImage, y ),
276 -1000000000, 1000000000, 0 );
277
278 VIPS_ARG_ENUM( class, "mode", 8,
279 _( "Mode" ),
280 _( "Combining mode" ),
281 VIPS_ARGUMENT_OPTIONAL_INPUT,
282 G_STRUCT_OFFSET( VipsDrawImage, mode ),
283 VIPS_TYPE_COMBINE_MODE, VIPS_COMBINE_MODE_SET );
284
285 }
286
287 static void
vips_draw_image_init(VipsDrawImage * draw_image)288 vips_draw_image_init( VipsDrawImage *draw_image )
289 {
290 draw_image->mode = VIPS_COMBINE_MODE_SET;
291 }
292
293 /**
294 * vips_draw_image: (method)
295 * @image: image to draw on
296 * @sub: image to paint
297 * @x: draw @sub here
298 * @y: draw @sub here
299 * @...: %NULL-terminated list of optional named arguments
300 *
301 * Optional arguments:
302 *
303 * * @mode: how to combine pixels
304 *
305 * Draw @sub on top of @image at position @x, @y. The two images must have the
306 * same Coding. If @sub has 1 band, the bands will be duplicated to match the
307 * number of bands in @image. @sub will be converted to @image's format, see
308 * vips_cast().
309 *
310 * Use @mode to set how pixels are combined. If you use
311 * #VIPS_COMBINE_MODE_ADD, both images muct be uncoded.
312 *
313 * See also: vips_draw_mask(), vips_insert().
314 *
315 * Returns: 0 on success, or -1 on error.
316 */
317 int
vips_draw_image(VipsImage * image,VipsImage * sub,int x,int y,...)318 vips_draw_image( VipsImage *image, VipsImage *sub, int x, int y, ... )
319 {
320 va_list ap;
321 int result;
322
323 va_start( ap, y );
324 result = vips_call_split( "draw_image", ap, image, sub, x, y );
325 va_end( ap );
326
327 return( result );
328 }
329