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