1 /* Merge two images top-bottom. dx, dy is the offset needed to get from sec
2  * (secondary image) to ref (reference image).
3  *
4  * Usage:
5  *
6  *   int
7  *   vips_tbmerge( ref, sec, out, dx, dy )
8  *   VipsImage *ref, *sec, *out;
9  *   int dx, dy;
10  *
11  * Returns 0 on success and -1 on error
12  *
13  * Copyright: 1990, 1991 N. Dessipris
14  * Author: N. Dessipris
15  * Written on: 20/09/1990
16  * Updated on: 17/04/1991
17  * 1/6/92: J. Cupitt
18  *      - check for difference bug fixed
19  *      - geometry calculations improved and simplified
20  *      - small speedups
21  * 30/6/93 K.Martinez : coped with IM_CODING_LABQ images
22  * 7/7/93 JC
23  *	- ANSIfied
24  *	- proper freeing on errors, ready for partial
25  * 8/11/93 JC
26  *	- now propagates both input histories
27  *	- adds magic lines for global mosaic optimisation
28  *
29  *
30  *  16/May/1994 Ahmed. Abbood
31  *      - Modified to use partials on all IO
32  *
33  *  June/1995 Ahmed Abbood
34  *
35  *      - Modified to work with different types of images.
36  *
37  *
38  * 16/6/95 JC
39  *	- added to VIPS!
40  * 7/9/95 JC
41  *	- split into two parts: im_tbmerge() and im__tbmerge()
42  *	- latter called by im_tbmosaic()
43  *	- just the same as public im_tbmerge(), but adds no history
44  *	- necessary for im_global_balance()
45  *	- small bugs fixed
46  * 10/10/95 JC
47  *	- better checks that parameters are sensible
48  * 11/10/95 JC
49  *	- Kirk spotted what a load of rubbish Ahmed's code is
50  *	- rewritten - many, many bugs fixed
51  * 28/7/97 JC
52  *	- new non-rectangular im_lrmerge adapted to make this
53  *	- small tidies
54  * 18/2/98 JC
55  *	- im_demand_hint() call added
56  * 19/2/98 JC
57  *	- now works for any dx/dy by calling im_insert() for bizarre cases
58  * 2/2/01 JC
59  *	- added tunable max blend width
60  * 8/3/01 JC
61  *	- switched to integer arithmetic for integer blends
62  * 23/3/01 JC
63  *	- oops, iblend was broken
64  * 7/11/01 JC
65  *	- more sophisticated transparency handling
66  * 15/8/02 JC
67  *	- records Xoffset/Yoffset
68  * 20/6/05
69  *	- now requires all bands == 0 for transparency (used to just check
70  *	  band 0)
71  * 24/1/11
72  * 	- gtk-doc
73  * 	- match formats and bands automatically
74  * 18/6/20 kleisauke
75  * 	- convert to vips8
76  */
77 
78 /*
79 
80     This file is part of VIPS.
81 
82     VIPS is free software; you can redistribute it and/or modify
83     it under the terms of the GNU Lesser General Public License as published by
84     the Free Software Foundation; either version 2 of the License, or
85     (at your option) any later version.
86 
87     This program is distributed in the hope that it will be useful,
88     but WITHOUT ANY WARRANTY; without even the implied warranty of
89     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
90     GNU Lesser General Public License for more details.
91 
92     You should have received a copy of the GNU Lesser General Public License
93     along with this program; if not, write to the Free Software
94     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
95     02110-1301  USA
96 
97  */
98 
99 /*
100 
101     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
102 
103  */
104 
105 #ifdef HAVE_CONFIG_H
106 #include <config.h>
107 #endif /*HAVE_CONFIG_H*/
108 #include <vips/intl.h>
109 
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <math.h>
113 
114 #include <vips/vips.h>
115 #include <vips/thread.h>
116 #include <vips/transform.h>
117 #include <vips/internal.h>
118 
119 #include "pmosaicing.h"
120 
121 /* Return the position of the first non-zero pel from the top.
122  */
123 static int
find_top(VipsRegion * ir,int * pos,int x,int y,int h)124 find_top( VipsRegion *ir, int *pos, int x, int y, int h )
125 {
126 	VipsPel *pr = VIPS_REGION_ADDR( ir, x, y );
127 	VipsImage *im = ir->im;
128 	int ls = VIPS_REGION_LSKIP( ir ) / VIPS_IMAGE_SIZEOF_ELEMENT( im );
129 	int b = im->Bands;
130 	int i, j;
131 
132 	/* Double the number of bands in a complex.
133 	 */
134 	if( vips_band_format_iscomplex( im->BandFmt ) )
135 		b *= 2;
136 
137 /* Search for the first non-zero band element from the top edge of the image.
138  */
139 #define tsearch( TYPE ) { \
140 	TYPE *p = (TYPE *) pr; \
141 	\
142 	for( i = 0; i < h; i++ ) { \
143 		for( j = 0; j < b; j++ ) \
144 			if( p[j] ) \
145 				break; \
146 		if( j < b ) \
147 			break; \
148 		\
149 		p += ls; \
150 	} \
151 }
152 
153 	switch( im->BandFmt ) {
154 	case VIPS_FORMAT_UCHAR:	tsearch( unsigned char ); break;
155 	case VIPS_FORMAT_CHAR:	tsearch( signed char ); break;
156 	case VIPS_FORMAT_USHORT:	tsearch( unsigned short ); break;
157 	case VIPS_FORMAT_SHORT:	tsearch( signed short ); break;
158 	case VIPS_FORMAT_UINT:	tsearch( unsigned int ); break;
159 	case VIPS_FORMAT_INT:	tsearch( signed int );  break;
160 	case VIPS_FORMAT_FLOAT:	tsearch( float ); break;
161 	case VIPS_FORMAT_DOUBLE:	tsearch( double ); break;
162 	case VIPS_FORMAT_COMPLEX:	tsearch( float ); break;
163 	case VIPS_FORMAT_DPCOMPLEX:	tsearch( double ); break;
164 
165 	default:
166 		vips_error( "vips_tbmerge", "%s", _( "internal error" ) );
167 		return( -1 );
168 	}
169 
170 	*pos = y + i;
171 
172 	return( 0 );
173 }
174 
175 /* Return the position of the first non-zero pel from the bottom.
176  */
177 static int
find_bot(VipsRegion * ir,int * pos,int x,int y,int h)178 find_bot( VipsRegion *ir, int *pos, int x, int y, int h )
179 {
180 	VipsPel *pr = VIPS_REGION_ADDR( ir, x, y );
181 	VipsImage *im = ir->im;
182 	int ls = VIPS_REGION_LSKIP( ir ) / VIPS_IMAGE_SIZEOF_ELEMENT( ir->im );
183 	int b = im->Bands;
184 	int i, j;
185 
186 	/* Double the number of bands in a complex.
187 	 */
188 	if( vips_band_format_iscomplex( im->BandFmt ) )
189 		b *= 2;
190 
191 /* Search for the first non-zero band element from the top edge of the image.
192  */
193 #define rsearch( TYPE ) { \
194 	TYPE *p = (TYPE *) pr + (h - 1) * ls; \
195 	\
196 	for( i = h - 1; i >= 0; i-- ) { \
197 		for( j = 0; j < b; j++ ) \
198 			if( p[j] ) \
199 				break; \
200 		if( j < b ) \
201 			break; \
202 		\
203 		p -= ls; \
204 	} \
205 }
206 
207 	switch( im->BandFmt ) {
208 	case VIPS_FORMAT_UCHAR:	rsearch( unsigned char ); break;
209 	case VIPS_FORMAT_CHAR:	rsearch( signed char ); break;
210 	case VIPS_FORMAT_USHORT:	rsearch( unsigned short ); break;
211 	case VIPS_FORMAT_SHORT:	rsearch( signed short ); break;
212 	case VIPS_FORMAT_UINT:	rsearch( unsigned int ); break;
213 	case VIPS_FORMAT_INT:	rsearch( signed int );  break;
214 	case VIPS_FORMAT_FLOAT:	rsearch( float ); break;
215 	case VIPS_FORMAT_DOUBLE:	rsearch( double ); break;
216 	case VIPS_FORMAT_COMPLEX:	rsearch( float ); break;
217 	case VIPS_FORMAT_DPCOMPLEX:	rsearch( double ); break;
218 
219 	default:
220 		vips_error( "vips_tbmerge", "%s", _( "internal error" ) );
221 		return( -1 );
222 	}
223 
224 	*pos = y + i;
225 
226 	return( 0 );
227 }
228 
229 /* Make first/last for oreg.
230  */
231 static int
make_firstlast(MergeInfo * inf,Overlapping * ovlap,VipsRect * oreg)232 make_firstlast( MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
233 {
234 	VipsRegion *rir = inf->rir;
235 	VipsRegion *sir = inf->sir;
236 	VipsRect rr, sr;
237 	int x;
238 	int missing;
239 
240 	/* We're going to build first/last ... lock it from other generate
241 	 * threads. In fact it's harmless if we do get two writers, but we may
242 	 * avoid duplicating work.
243 	 */
244 	g_mutex_lock( ovlap->fl_lock );
245 
246 	/* Do we already have first/last for this area? Bail out if we do.
247 	 */
248 	missing = 0;
249 	for( x = oreg->left; x < VIPS_RECT_RIGHT( oreg ); x++ ) {
250 		const int j = x - ovlap->overlap.left;
251 		const int first = ovlap->first[j];
252 
253 		if( first < 0 ) {
254 			missing = 1;
255 			break;
256 		}
257 	}
258 	if( !missing ) {
259 		/* No work to do!
260 		 */
261 		g_mutex_unlock( ovlap->fl_lock );
262 		return( 0 );
263 	}
264 
265 	/* Entire height of overlap in ref for oreg ... we know oreg is inside
266 	 * overlap.
267 	 */
268 	rr.left = oreg->left;
269 	rr.top = ovlap->overlap.top;
270 	rr.width = oreg->width;
271 	rr.height = ovlap->overlap.height;
272 	rr.left -= ovlap->rarea.left;
273 	rr.top -= ovlap->rarea.top;
274 
275 	/* Same in sec.
276 	 */
277 	sr.left = oreg->left;
278 	sr.top = ovlap->overlap.top;
279 	sr.width = oreg->width;
280 	sr.height = ovlap->overlap.height;
281 	sr.left -= ovlap->sarea.left;
282 	sr.top -= ovlap->sarea.top;
283 
284 	/* Make pixels.
285 	 */
286 	if( vips_region_prepare( rir, &rr ) ||
287 		vips_region_prepare( sir, &sr ) ) {
288 		g_mutex_unlock( ovlap->fl_lock );
289 		return( -1 );
290 	}
291 
292 	/* Make first/last cache.
293 	 */
294 	for( x = 0; x < oreg->width; x++ ) {
295 		const int j = (x + oreg->left) - ovlap->overlap.left;
296 		int *first = &ovlap->first[j];
297 		int *last = &ovlap->last[j];
298 
299 		/* Done this line already?
300 		 */
301 		if( *first < 0 ) {
302 			/* Search for top/bottom of overlap on this scan-line.
303 			 */
304 			if( find_top( sir, first,
305 				x + sr.left, sr.top, sr.height ) ||
306 				find_bot( rir, last,
307 					x + rr.left, rr.top, rr.height ) ) {
308 				g_mutex_unlock( ovlap->fl_lock );
309 				return( -1 );
310 			}
311 
312 			/* Translate to output space.
313 			 */
314 			*first += ovlap->sarea.top;
315 			*last += ovlap->rarea.top;
316 
317 			/* Clip to maximum blend width, if necessary.
318 			 */
319 			if( ovlap->mwidth >= 0 &&
320 				*last - *first > ovlap->mwidth ) {
321 				int shrinkby = (*last - *first) - ovlap->mwidth;
322 
323 				*first += shrinkby / 2;
324 				*last -= shrinkby / 2;
325 			}
326 		}
327 	}
328 
329 	g_mutex_unlock( ovlap->fl_lock );
330 
331 	return( 0 );
332 }
333 
334 /* Test pixel == 0.
335  */
336 #define TEST_ZERO( TYPE, T, RESULT ) { \
337 	TYPE *tt = (T); \
338 	int ii; \
339 	\
340 	for( ii = 0; ii < cb; ii++ ) \
341 		if( tt[i + ii] ) \
342 			break; \
343 	if( ii == cb )  \
344 		(RESULT) = 1; \
345 }
346 
347 /* Blend two integer images ... one scan-line.
348  */
349 #define iblend( TYPE, B, IN1, IN2, OUT ) { \
350 	TYPE *tr = (TYPE *) (IN1); \
351 	TYPE *ts = (TYPE *) (IN2); \
352 	TYPE *tq = (TYPE *) (OUT); \
353 	const int cb = (B); \
354 	int ref_zero; \
355 	int sec_zero; \
356 	int x, b; \
357 	int i; \
358 	\
359 	for( i = 0, x = 0; x < oreg->width; x++ ) { \
360 		ref_zero = 0; \
361 		sec_zero = 0; \
362 		TEST_ZERO( TYPE, tr, ref_zero ); \
363 		TEST_ZERO( TYPE, ts, sec_zero ); \
364 		\
365 		/* Above the bottom image? \
366 		 */ \
367 		if( y < first[x] ) { \
368 			if( !ref_zero ) \
369 				for( b = 0; b < cb; b++, i++ )  \
370 					tq[i] = tr[i]; \
371 			else \
372 				for( b = 0; b < cb; b++, i++ )  \
373 					tq[i] = ts[i]; \
374 		} \
375 		/* To the right? \
376 		 */ \
377 		else if( y >= last[x] ) { \
378 			if( !sec_zero ) \
379 				for( b = 0; b < cb; b++, i++ )  \
380 					tq[i] = ts[i]; \
381 			else \
382 				for( b = 0; b < cb; b++, i++ )  \
383 					tq[i] = tr[i]; \
384 		} \
385 		/* In blend area. \
386 		 */ \
387 		else { \
388 			if( !ref_zero && !sec_zero ) { \
389 				const int bheight = last[x] - first[x]; \
390 				const int inx = ((y - first[x]) << \
391 					BLEND_SHIFT) / bheight; \
392 				int c1 = vips__icoef1[inx];  \
393 				int c2 = vips__icoef2[inx];  \
394 				\
395 				for( b = 0; b < cb; b++, i++ ) \
396 					tq[i] = c1 * tr[i] / BLEND_SCALE + \
397 						c2 * ts[i] / BLEND_SCALE; \
398 			} \
399 			else if( !ref_zero ) \
400 				for( b = 0; b < cb; b++, i++ )  \
401 					tq[i] = tr[i]; \
402 			else \
403 				for( b = 0; b < cb; b++, i++ )  \
404 					tq[i] = ts[i]; \
405 		}  \
406 	} \
407 }
408 
409 /* Blend two float images.
410  */
411 #define fblend( TYPE, B, IN1, IN2, OUT ) { \
412 	TYPE *tr = (TYPE *) (IN1); \
413 	TYPE *ts = (TYPE *) (IN2); \
414 	TYPE *tq = (TYPE *) (OUT); \
415 	int ref_zero; \
416 	int sec_zero; \
417 	const int cb = (B); \
418 	int x, b; \
419 	int i; \
420 	\
421 	for( i = 0, x = 0; x < oreg->width; x++ ) { \
422 		ref_zero = 0; \
423 		sec_zero = 0; \
424 		TEST_ZERO( TYPE, tr, ref_zero ); \
425 		TEST_ZERO( TYPE, ts, sec_zero ); \
426 		\
427 		/* Above the bottom image? \
428 		 */ \
429 		if( y < first[x] )  \
430 			if( !ref_zero ) \
431 				for( b = 0; b < cb; b++, i++ )  \
432 					tq[i] = tr[i]; \
433 			else \
434 				for( b = 0; b < cb; b++, i++ )  \
435 					tq[i] = tr[i]; \
436 		/* To the right? \
437 		 */ \
438 		else if( y >= last[x] )  \
439 			if( !sec_zero ) \
440 				for( b = 0; b < cb; b++, i++ )  \
441 					tq[i] = ts[i]; \
442 			else \
443 				for( b = 0; b < cb; b++, i++ )  \
444 					tq[i] = tr[i]; \
445 		/* In blend area. \
446 		 */ \
447 		else { \
448 			if( !ref_zero && !sec_zero ) { \
449 				const int bheight = last[x] - first[x]; \
450 				const int inx = ((y - first[x]) << \
451 					BLEND_SHIFT) / bheight; \
452 				double c1 = vips__coef1[inx];  \
453 				double c2 = vips__coef2[inx];  \
454 				\
455 				for( b = 0; b < cb; b++, i++ ) \
456 					tq[i] = c1 * tr[i] + c2 * ts[i]; \
457 			} \
458 			else if( !ref_zero ) \
459 				for( b = 0; b < cb; b++, i++ )  \
460 					tq[i] = tr[i]; \
461 			else \
462 				for( b = 0; b < cb; b++, i++ )  \
463 					tq[i] = ts[i]; \
464 		}  \
465 	} \
466 }
467 
468 /* Top-bottom blend function for non-labpack images.
469  */
470 static int
tb_blend(VipsRegion * or,MergeInfo * inf,Overlapping * ovlap,VipsRect * oreg)471 tb_blend( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
472 {
473 	VipsRegion *rir = inf->rir;
474 	VipsRegion *sir = inf->sir;
475 	VipsImage *im = or->im;
476 
477 	VipsRect prr, psr;
478 	int y, yr, ys;
479 
480 	/* Make sure we have a complete first/last set for this area.
481 	 */
482 	if( make_firstlast( inf, ovlap, oreg ) )
483 		return( -1 );
484 
485 	/* Part of rr which we will output.
486 	 */
487 	prr = *oreg;
488 	prr.left -= ovlap->rarea.left;
489 	prr.top -= ovlap->rarea.top;
490 
491 	/* Part of sr which we will output.
492 	 */
493 	psr = *oreg;
494 	psr.left -= ovlap->sarea.left;
495 	psr.top -= ovlap->sarea.top;
496 
497 	/* Make pixels.
498 	 */
499 	if( vips_region_prepare( rir, &prr ) ||
500 		vips_region_prepare( sir, &psr ) )
501 		return( -1 );
502 
503 	/* Loop down overlap area.
504 	 */
505 	for( y = oreg->top, yr = prr.top, ys = psr.top;
506 		y < VIPS_RECT_BOTTOM( oreg ); y++, yr++, ys++ ) {
507 		VipsPel *pr = VIPS_REGION_ADDR( rir, prr.left, yr );
508 		VipsPel *ps = VIPS_REGION_ADDR( sir, psr.left, ys );
509 		VipsPel *q = VIPS_REGION_ADDR( or, oreg->left, y );
510 
511 		const int j = oreg->left - ovlap->overlap.left;
512 		const int *first = ovlap->first + j;
513 		const int *last = ovlap->last + j;
514 
515 		switch( im->BandFmt ) {
516 		case VIPS_FORMAT_UCHAR:
517 			iblend( unsigned char, im->Bands, pr, ps, q ); break;
518 		case VIPS_FORMAT_CHAR:
519 			iblend( signed char, im->Bands, pr, ps, q ); break;
520 		case VIPS_FORMAT_USHORT:
521 			iblend( unsigned short, im->Bands, pr, ps, q ); break;
522 		case VIPS_FORMAT_SHORT:
523 			iblend( signed short, im->Bands, pr, ps, q ); break;
524 		case VIPS_FORMAT_UINT:
525 			iblend( unsigned int, im->Bands, pr, ps, q ); break;
526 		case VIPS_FORMAT_INT:
527 			iblend( signed int, im->Bands, pr, ps, q );  break;
528 		case VIPS_FORMAT_FLOAT:
529 			fblend( float, im->Bands, pr, ps, q ); break;
530 		case VIPS_FORMAT_DOUBLE:
531 			fblend( double, im->Bands, pr, ps, q ); break;
532 		case VIPS_FORMAT_COMPLEX:
533 			fblend( float, im->Bands * 2, pr, ps, q ); break;
534 		case VIPS_FORMAT_DPCOMPLEX:
535 			fblend( double, im->Bands * 2, pr, ps, q ); break;
536 
537 		default:
538 			vips_error( "vips_tbmerge", "%s", _( "internal error" ) );
539 			return( -1 );
540 		}
541 	}
542 
543 	return( 0 );
544 }
545 
546 /* Top-bottom blend function for VIPS_CODING_LABQ images.
547  */
548 static int
tb_blend_labpack(VipsRegion * or,MergeInfo * inf,Overlapping * ovlap,VipsRect * oreg)549 tb_blend_labpack( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
550 {
551 	VipsRegion *rir = inf->rir;
552 	VipsRegion *sir = inf->sir;
553 	VipsRect prr, psr;
554 	int y, yr, ys;
555 
556 	/* Make sure we have a complete first/last set for this area. This
557 	 * will just look at the top 8 bits of L, not all 10, but should be OK.
558 	 */
559 	if( make_firstlast( inf, ovlap, oreg ) )
560 		return( -1 );
561 
562 	/* Part of rr which we will output.
563 	 */
564 	prr = *oreg;
565 	prr.left -= ovlap->rarea.left;
566 	prr.top -= ovlap->rarea.top;
567 
568 	/* Part of sr which we will output.
569 	 */
570 	psr = *oreg;
571 	psr.left -= ovlap->sarea.left;
572 	psr.top -= ovlap->sarea.top;
573 
574 	/* Make pixels.
575 	 */
576 	if( vips_region_prepare( rir, &prr ) ||
577 		vips_region_prepare( sir, &psr ) )
578 		return( -1 );
579 
580 	/* Loop down overlap area.
581 	 */
582 	for( y = oreg->top, yr = prr.top, ys = psr.top;
583 		y < VIPS_RECT_BOTTOM( oreg ); y++, yr++, ys++ ) {
584 		VipsPel *pr = VIPS_REGION_ADDR( rir, prr.left, yr );
585 		VipsPel *ps = VIPS_REGION_ADDR( sir, psr.left, ys );
586 		VipsPel *q = VIPS_REGION_ADDR( or, oreg->left, y );
587 
588 		const int j = oreg->left - ovlap->overlap.left;
589 		const int *first = ovlap->first + j;
590 		const int *last = ovlap->last + j;
591 
592 		float *fq = inf->merge;
593 		float *r = inf->from1;
594 		float *s = inf->from2;
595 
596 		/* Unpack two bits we want.
597 		 */
598 		vips__LabQ2Lab_vec( r, pr, oreg->width );
599 		vips__LabQ2Lab_vec( s, ps, oreg->width );
600 
601 		/* Blend as floats.
602 		 */
603 		fblend( float, 3, r, s, fq );
604 
605 		/* Re-pack to output buffer.
606 		 */
607 		vips__Lab2LabQ_vec( q, inf->merge, oreg->width );
608 	}
609 
610 	return( 0 );
611 }
612 
613 /* Build per-call state.
614  */
615 static Overlapping *
build_tbstate(VipsImage * ref,VipsImage * sec,VipsImage * out,int dx,int dy,int mwidth)616 build_tbstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
617 {
618    	Overlapping *ovlap;
619 
620 	if( !(ovlap = vips__build_mergestate( "vips_tbmerge",
621 		ref, sec, out, dx, dy, mwidth )) )
622 		return( NULL );
623 
624 	/* Select blender.
625 	 */
626 	switch( ovlap->ref->Coding ) {
627 	case VIPS_CODING_LABQ:
628 		ovlap->blend = tb_blend_labpack;
629 		break;
630 
631 	case VIPS_CODING_NONE:
632 		ovlap->blend = tb_blend;
633 		break;
634 
635 	default:
636 		vips_error( "vips_tbmerge", "%s", _( "unknown coding type" ) );
637 		return( NULL );
638 	}
639 
640 	/* Find the parts of output which come just from ref and just from sec.
641 	 */
642 	ovlap->rpart = ovlap->rarea;
643 	ovlap->spart = ovlap->sarea;
644 	ovlap->rpart.height -= ovlap->overlap.height;
645 	ovlap->spart.top += ovlap->overlap.height;
646 	ovlap->spart.height -= ovlap->overlap.height;
647 
648 	/* Is there too much overlap? ie. bottom edge of ref image is greater
649 	 * than bottom edge of sec image, or top edge of ref > top edge of
650 	 * sec.
651 	 */
652 	if( VIPS_RECT_BOTTOM( &ovlap->rarea ) > VIPS_RECT_BOTTOM( &ovlap->sarea ) ||
653 		ovlap->rarea.top > ovlap->sarea.top ) {
654 		vips_error( "vips_tbmerge", "%s", _( "too much overlap" ) );
655 		return( NULL );
656 	}
657 
658 	/* Max number of pixels we may have to blend together.
659 	 */
660 	ovlap->blsize = ovlap->overlap.width;
661 
662 	return( ovlap );
663 }
664 
665 int
vips__tbmerge(VipsImage * ref,VipsImage * sec,VipsImage * out,int dx,int dy,int mwidth)666 vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
667 	int dx, int dy, int mwidth )
668 {
669 	Overlapping *ovlap;
670 
671 	if( dy > 0 || dy < 1 - ref->Ysize ) {
672 		VipsImage *x;
673 
674 #ifdef DEBUG
675 		printf( "vips__tbmerge: no overlap, using insert\n" );
676 #endif
677 
678 		/* No overlap, use insert instead.
679 		 */
680   		if( vips_insert( ref, sec, &x, -dx, -dy,
681 			"expand", TRUE,
682 			NULL ) )
683 			return( -1 );
684 		if( vips_image_write( x, out ) ) {
685 			g_object_unref( x );
686 			return( -1 );
687 		}
688 		g_object_unref( x );
689 
690 		out->Xoffset = -dx;
691 		out->Yoffset = -dy;
692 
693 		return( 0 );
694 	}
695 
696 	if( !(ovlap = build_tbstate( ref, sec, out, dx, dy, mwidth )) )
697 		return( -1 );
698 
699 	if( vips_image_pipelinev( out,
700 		VIPS_DEMAND_STYLE_THINSTRIP, ovlap->ref, ovlap->sec, NULL ) )
701 		return( -1 );
702 
703 	out->Xsize = ovlap->oarea.width;
704 	out->Ysize = ovlap->oarea.height;
705 	out->Xoffset = -dx;
706 	out->Yoffset = -dy;
707 
708 	if( vips_image_generate( out,
709 		vips__start_merge, vips__merge_gen, vips__stop_merge, ovlap, NULL ) )
710 		return( -1 );
711 
712 	return ( 0 );
713 }
714 
715