1 /* VipsBandjoin -- bandwise join of a set of images
2  *
3  * Copyright: 1991, N. Dessipris, modification of im_bandjoin()
4  *
5  * Author: N. Dessipris
6  * Written on: 17/04/1991
7  * Modified on :
8  * 16/3/94 JC
9  *	- rewritten for partials
10  *	- now in ANSI C
11  *	- now works for any number of input images, except zero
12  * 7/10/94 JC
13  *	- new IM_NEW()
14  * 16/4/07
15  * 	- fall back to im_copy() for 1 input image
16  * 17/1/09
17  * 	- cleanups
18  * 	- gtk-doc
19  * 	- im_bandjoin() just calls this
20  * 	- works for RAD coding too
21  * 27/1/10
22  * 	- formatalike inputs
23  * 17/5/11
24  * 	- sizealike inputs
25  * 27/10/11
26  * 	- rewrite as a class
27  * 7/11/15
28  * 	- added bandjoin_const
29  */
30 
31 /*
32 
33     This file is part of VIPS.
34 
35     VIPS is free software; you can redistribute it and/or modify
36     it under the terms of the GNU Lesser General Public License as published by
37     the Free Software Foundation; either version 2 of the License, or
38     (at your option) any later version.
39 
40     This program is distributed in the hope that it will be useful,
41     but WITHOUT ANY WARRANTY; without even the implied warranty of
42     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43     GNU Lesser General Public License for more details.
44 
45     You should have received a copy of the GNU Lesser General Public License
46     along with this program; if not, write to the Free Software
47     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
48     02110-1301  USA
49 
50  */
51 
52 /*
53 
54     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
55 
56  */
57 
58 /*
59 #define VIPS_DEBUG
60  */
61 
62 #ifdef HAVE_CONFIG_H
63 #include <config.h>
64 #endif /*HAVE_CONFIG_H*/
65 #include <vips/intl.h>
66 
67 #include <stdio.h>
68 #include <string.h>
69 #include <stdlib.h>
70 #include <math.h>
71 
72 #include <vips/vips.h>
73 #include <vips/internal.h>
74 #include <vips/debug.h>
75 
76 #include "bandary.h"
77 
78 typedef struct _VipsBandjoin {
79 	VipsBandary parent_instance;
80 
81 	/* The input images.
82 	 */
83 	VipsArrayImage *in;
84 } VipsBandjoin;
85 
86 typedef VipsBandaryClass VipsBandjoinClass;
87 
88 G_DEFINE_TYPE( VipsBandjoin, vips_bandjoin, VIPS_TYPE_BANDARY );
89 
90 static void
vips_bandjoin_buffer(VipsBandarySequence * seq,VipsPel * q,VipsPel ** p,int width)91 vips_bandjoin_buffer( VipsBandarySequence *seq,
92 	VipsPel *q, VipsPel **p, int width )
93 {
94 	VipsBandary *bandary = seq->bandary;
95 	VipsConversion *conversion = (VipsConversion *) bandary;
96 	VipsImage **in = bandary->ready;
97 
98 	/* Output pel size.
99 	 */
100 	const int ops = VIPS_IMAGE_SIZEOF_PEL( conversion->out );
101 
102 	int i;
103 
104 	/* Loop for each input image. Scattered write is faster than
105 	 * scattered read.
106 	 */
107 	for( i = 0; i < bandary->n; i++ ) {
108 		/* Input pel size.
109 		 */
110 		int ips = VIPS_IMAGE_SIZEOF_PEL( in[i] );
111 
112 		VipsPel * restrict p1;
113 		VipsPel * restrict q1;
114 		int x, z;
115 
116 		q1 = q;
117 		p1 = p[i];
118 
119 		for( x = 0; x < width; x++ ) {
120 			for( z = 0; z < ips; z++ )
121 				q1[z] = p1[z];
122 
123 			p1 += ips;
124 			q1 += ops;
125 		}
126 
127 		q += ips;
128 	}
129 }
130 
131 static int
vips_bandjoin_build(VipsObject * object)132 vips_bandjoin_build( VipsObject *object )
133 {
134 	VipsBandary *bandary = (VipsBandary *) object;
135 	VipsBandjoin *bandjoin = (VipsBandjoin *) object;
136 
137 	if( bandjoin->in ) {
138 		bandary->in = vips_array_image_get( bandjoin->in, &bandary->n );
139 
140 		if( bandary->n == 1 )
141 			return( vips_bandary_copy( bandary ) );
142 		else {
143 			int i;
144 
145 			bandary->out_bands = 0;
146 			for( i = 0; i < bandary->n; i++ )
147 				if( bandary->in[i] )
148 					bandary->out_bands +=
149 						bandary->in[i]->Bands;
150 		}
151 	}
152 
153 	if( VIPS_OBJECT_CLASS( vips_bandjoin_parent_class )->build( object ) )
154 		return( -1 );
155 
156 	return( 0 );
157 }
158 
159 static void
vips_bandjoin_class_init(VipsBandjoinClass * class)160 vips_bandjoin_class_init( VipsBandjoinClass *class )
161 {
162 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
163 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
164 	VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS( class );
165 
166 	VIPS_DEBUG_MSG( "vips_bandjoin_class_init\n" );
167 
168 	gobject_class->set_property = vips_object_set_property;
169 	gobject_class->get_property = vips_object_get_property;
170 
171 	vobject_class->nickname = "bandjoin";
172 	vobject_class->description = _( "bandwise join a set of images" );
173 	vobject_class->build = vips_bandjoin_build;
174 
175 	bandary_class->process_line = vips_bandjoin_buffer;
176 
177 	VIPS_ARG_BOXED( class, "in", 0,
178 		_( "Input" ),
179 		_( "Array of input images" ),
180 		VIPS_ARGUMENT_REQUIRED_INPUT,
181 		G_STRUCT_OFFSET( VipsBandjoin, in ),
182 		VIPS_TYPE_ARRAY_IMAGE );
183 
184 }
185 
186 static void
vips_bandjoin_init(VipsBandjoin * bandjoin)187 vips_bandjoin_init( VipsBandjoin *bandjoin )
188 {
189 	/* Init our instance fields.
190 	 */
191 }
192 
193 static int
vips_bandjoinv(VipsImage ** in,VipsImage ** out,int n,va_list ap)194 vips_bandjoinv( VipsImage **in, VipsImage **out, int n, va_list ap )
195 {
196 	VipsArrayImage *array;
197 	int result;
198 
199 	array = vips_array_image_new( in, n );
200 	result = vips_call_split( "bandjoin", ap, array, out );
201 	vips_area_unref( VIPS_AREA( array ) );
202 
203 	return( result );
204 }
205 
206 /**
207  * vips_bandjoin:
208  * @in: (array length=n) (transfer none): array of input images
209  * @out: (out): output image
210  * @n: number of input images
211  * @...: %NULL-terminated list of optional named arguments
212  *
213  * Join a set of images together, bandwise.
214  *
215  * If the images
216  * have n and m bands, then the output image will have n + m
217  * bands, with the first n coming from the first image and the last m
218  * from the second.
219  *
220  * If the images differ in size, the smaller images are enlarged to match the
221  * larger by adding zero pixels along the bottom and right.
222  *
223  * The input images are cast up to the smallest common type (see table
224  * Smallest common format in
225  * <link linkend="libvips-arithmetic">arithmetic</link>).
226  *
227  * See also: vips_insert().
228  *
229  * Returns: 0 on success, -1 on error
230  */
231 int
vips_bandjoin(VipsImage ** in,VipsImage ** out,int n,...)232 vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... )
233 {
234 	va_list ap;
235 	int result;
236 
237 	va_start( ap, n );
238 	result = vips_bandjoinv( in, out, n, ap );
239 	va_end( ap );
240 
241 	return( result );
242 }
243 
244 /**
245  * vips_bandjoin2:
246  * @in1: first input image
247  * @in2: second input image
248  * @out: (out): output image
249  * @...: %NULL-terminated list of optional named arguments
250  *
251  * Join a pair of images together, bandwise. See vips_bandjoin().
252  *
253  * Returns: 0 on success, -1 on error
254  */
255 int
vips_bandjoin2(VipsImage * in1,VipsImage * in2,VipsImage ** out,...)256 vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... )
257 {
258 	va_list ap;
259 	int result;
260 	VipsImage *in[2];
261 
262 	in[0] = in1;
263 	in[1] = in2;
264 
265 	va_start( ap, out );
266 	result = vips_bandjoinv( in, out, 2, ap );
267 	va_end( ap );
268 
269 	return( result );
270 }
271 
272 typedef struct _VipsBandjoinConst {
273 	VipsBandary parent_instance;
274 
275 	VipsImage *in;
276 	VipsArrayDouble *c;
277 
278 	/* The constant expanded to in's format, ready to be appended to each
279 	 * pixel.
280 	 */
281 	int n;
282 	VipsPel *c_ready;
283 
284 } VipsBandjoinConst;
285 
286 typedef VipsBandaryClass VipsBandjoinConstClass;
287 
288 G_DEFINE_TYPE( VipsBandjoinConst, vips_bandjoin_const, VIPS_TYPE_BANDARY );
289 
290 static void
vips_bandjoin_const_finalize(GObject * object)291 vips_bandjoin_const_finalize( GObject *object )
292 {
293 	VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) object;
294 
295 	VIPS_FREE( bandjoin->c_ready );
296 
297 	G_OBJECT_CLASS( vips_bandjoin_const_parent_class )->finalize( object );
298 }
299 
300 static void
vips_bandjoin_const_buffer(VipsBandarySequence * seq,VipsPel * q,VipsPel ** p,int width)301 vips_bandjoin_const_buffer( VipsBandarySequence *seq,
302 	VipsPel *q, VipsPel **p, int width )
303 {
304 	VipsBandary *bandary = seq->bandary;
305 	VipsConversion *conversion = (VipsConversion *) bandary;
306 	VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) bandary;
307 	VipsImage *in = bandary->ready[0];
308 
309 	/* Output pel size.
310 	 */
311 	const int ops = VIPS_IMAGE_SIZEOF_PEL( conversion->out );
312 
313 	/* Input pel size.
314 	 */
315 	const int ips = VIPS_IMAGE_SIZEOF_PEL( in );
316 
317 	/* Extra bands size.
318 	 */
319 	const int ebs = ops - ips;
320 
321 	VipsPel * restrict p1;
322 	VipsPel * restrict q1;
323 	int x, z;
324 
325 	q1 = q;
326 	p1 = p[0];
327 
328 	/* Special path for 8-bit RGB -> RGBA ... it's a common case.
329 	 */
330 	if( ips == 3 &&
331 		ebs == 1 ) {
332 		int c = bandjoin->c_ready[0];
333 
334 		for( x = 0; x < width; x++ ) {
335 			q1[0] = p1[0];
336 			q1[1] = p1[1];
337 			q1[2] = p1[2];
338 			q1[3] = c;
339 
340 			p1 += 3;
341 			q1 += 4;
342 		}
343 	}
344 	else {
345 		for( x = 0; x < width; x++ ) {
346 			for( z = 0; z < ips; z++ )
347 				q1[z] = p1[z];
348 
349 			p1 += ips;
350 			q1 += ips;
351 
352 			for( z = 0; z < ebs; z++ )
353 				q1[z] = bandjoin->c_ready[z];
354 
355 			q1 += ebs;
356 		}
357 	}
358 }
359 
360 static int
vips_bandjoin_const_build(VipsObject * object)361 vips_bandjoin_const_build( VipsObject *object )
362 {
363 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
364 	VipsBandary *bandary = (VipsBandary *) object;
365 	VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) object;
366 
367 	if( bandjoin->c &&
368 		bandjoin->in ) {
369 		double *c;
370 		int n;
371 
372 		c = vips_array_double_get( bandjoin->c, &n );
373 
374 		if( n == 0 )
375 			return( vips_bandary_copy( bandary ) );
376 		else
377 			bandary->out_bands = bandjoin->in->Bands + n;
378 
379 		bandary->n = 1;
380 		bandary->in = &bandjoin->in;
381 
382 		if( !(bandjoin->c_ready = vips__vector_to_pels( class->nickname,
383 			n, bandjoin->in->BandFmt, bandjoin->in->Coding,
384 			c, NULL, n )) )
385 			return( -1 );
386 
387 	}
388 
389 	if( VIPS_OBJECT_CLASS( vips_bandjoin_const_parent_class )->
390 		build( object ) )
391 		return( -1 );
392 
393 	return( 0 );
394 }
395 
396 static void
vips_bandjoin_const_class_init(VipsBandjoinConstClass * class)397 vips_bandjoin_const_class_init( VipsBandjoinConstClass *class )
398 {
399 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
400 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
401 	VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS( class );
402 
403 	VIPS_DEBUG_MSG( "vips_bandjoin_const_class_init\n" );
404 
405 	gobject_class->finalize = vips_bandjoin_const_finalize;
406 	gobject_class->set_property = vips_object_set_property;
407 	gobject_class->get_property = vips_object_get_property;
408 
409 	vobject_class->nickname = "bandjoin_const";
410 	vobject_class->description = _( "append a constant band to an image" );
411 	vobject_class->build = vips_bandjoin_const_build;
412 
413 	bandary_class->process_line = vips_bandjoin_const_buffer;
414 
415 	VIPS_ARG_IMAGE( class, "in", 0,
416 		_( "Input" ),
417 		_( "Input image" ),
418 		VIPS_ARGUMENT_REQUIRED_INPUT,
419 		G_STRUCT_OFFSET( VipsBandjoinConst, in ) );
420 
421 	VIPS_ARG_BOXED( class, "c", 12,
422 		_( "Constants" ),
423 		_( "Array of constants to add" ),
424 		VIPS_ARGUMENT_REQUIRED_INPUT,
425 		G_STRUCT_OFFSET( VipsBandjoinConst, c ),
426 		VIPS_TYPE_ARRAY_DOUBLE );
427 
428 }
429 
430 static void
vips_bandjoin_const_init(VipsBandjoinConst * bandjoin)431 vips_bandjoin_const_init( VipsBandjoinConst *bandjoin )
432 {
433 	/* Init our instance fields.
434 	 */
435 }
436 
437 static int
vips_bandjoin_constv(VipsImage * in,VipsImage ** out,double * c,int n,va_list ap)438 vips_bandjoin_constv( VipsImage *in, VipsImage **out,
439 	double *c, int n, va_list ap )
440 {
441 	VipsArrayDouble *array;
442 	int result;
443 
444 	array = vips_array_double_new( c, n );
445 	result = vips_call_split( "bandjoin_const", ap, in, out, array );
446 	vips_area_unref( VIPS_AREA( array ) );
447 
448 	return( result );
449 }
450 
451 /**
452  * vips_bandjoin_const: (method)
453  * @in: input image
454  * @out: (out): output image
455  * @c: (array length=n): array of constants to append
456  * @n: number of constants
457  * @...: %NULL-terminated list of optional named arguments
458  *
459  * Append a set of constant bands to an image.
460  *
461  * See also: vips_bandjoin().
462  *
463  * Returns: 0 on success, -1 on error
464  */
465 int
vips_bandjoin_const(VipsImage * in,VipsImage ** out,double * c,int n,...)466 vips_bandjoin_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
467 {
468 	va_list ap;
469 	int result;
470 
471 	va_start( ap, n );
472 	result = vips_bandjoin_constv( in, out, c, n, ap );
473 	va_end( ap );
474 
475 	return( result );
476 }
477 
478 /**
479  * vips_bandjoin_const1: (method)
480  * @in: input image
481  * @out: (out): output image
482  * @c: constant to append
483  * @...: %NULL-terminated list of optional named arguments
484  *
485  * Append a single constant band to an image.
486  *
487  * Returns: 0 on success, -1 on error
488  */
489 int
vips_bandjoin_const1(VipsImage * in,VipsImage ** out,double c,...)490 vips_bandjoin_const1( VipsImage *in, VipsImage **out, double c, ... )
491 {
492 	va_list ap;
493 	int result;
494 
495 	va_start( ap, c );
496 	result = vips_bandjoin_constv( in, out, &c, 1, ap );
497 	va_end( ap );
498 
499 	return( result );
500 }
501 
502 /**
503  * vips_addalpha: (method)
504  * @in: input image
505  * @out: (out): output image
506  * @...: %NULL-terminated list of optional named arguments
507  *
508  * Append an alpha channel.
509  *
510  * See also: vips_image_hasalpha().
511  *
512  * Returns: 0 on success, -1 on error
513  */
514 int
vips_addalpha(VipsImage * in,VipsImage ** out,...)515 vips_addalpha( VipsImage *in, VipsImage **out, ... )
516 {
517 	double max_alpha;
518 
519 	max_alpha = 255.0;
520 	if( in->Type == VIPS_INTERPRETATION_GREY16 ||
521 		in->Type == VIPS_INTERPRETATION_RGB16 )
522 		max_alpha = 65535;
523 
524 	if( vips_bandjoin_const1( in, out, max_alpha, NULL ) )
525 		return( -1 );
526 
527 	return( 0 );
528 }
529