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