1 
2 // Modify transparency channel to indicate distance from image area
3 // 255 = in image; distance = 255-alpha
4 
5 #ifdef SET_TO_EDGE
6 #undef SET_TO_EDGE
7 #endif
8 #ifdef SET_TO_DISTANCE
9 #undef SET_TO_DISTANCE
10 #endif
11 
12 #define SET_TO_EDGE( a )		{ ch = a; if( *(PIXEL_TYPE*)ch == 1 ) *(PIXEL_TYPE*)ch = (PIXEL_TYPE)254;}
13 #define SET_TO_DISTANCE( a )	{ ch = a; if( *(PIXEL_TYPE*)ch && *(PIXEL_TYPE*)ch < setdist ) *(PIXEL_TYPE*)ch = (PIXEL_TYPE)setdist;}
14 
15 
16 #ifdef BYTES_PER_CHANNEL
17 #undef BYTES_PER_CHANNEL
18 #endif
19 
20 #define BYTES_PER_CHANNEL	sizeof(PIXEL_TYPE)
21 
_SetDistance(Image * im,Image * pano,PTRect * theRect,int showprogress)22 void _SetDistance ( Image* im, Image* pano, PTRect *theRect, int showprogress )
23 {
24 	int 					x,y,bpp,bppa, bpl, bpla, skip=0,setdist,dist;
25 	unsigned char			*data = *(im->data), *alpha = *(pano->data), *idata, *adata;
26 	register unsigned char 	*ch;
27 	char 					*progressMessage, percent[24];
28 	PTRect 					OLRect;
29 
30 	bpp 	= im->bitsPerPixel/8;
31 	bppa	= pano->bitsPerPixel/8;
32 	bpl 	= im->bytesPerLine;
33 	bpla	= pano->bytesPerLine;
34 
35 	OLRect.left 	= theRect->right;
36 	OLRect.right 	= theRect->left;
37 	OLRect.top 		= theRect->bottom;
38 	OLRect.bottom 	= theRect->top;
39 
40 	if( showprogress )
41 	{
42 		progressMessage = "Merging Images";
43 		Progress( _initProgress, progressMessage );
44 	}
45 
46 
47 	// First, set alpha channel in overlap region to 1, find minimum overlap rectangle
48 
49 	for(y=theRect->top; y<theRect->bottom; y++)
50 	{
51 		idata = data  + bpl  * y + theRect->left * bpp;
52 		adata = alpha + bpla * y + theRect->left * bppa;
53 		for(x=theRect->left; x<theRect->right; x++, idata+=bpp, adata+=bppa)
54 		{
55 			if( *(PIXEL_TYPE*)idata == PIXEL_MAX && *(PIXEL_TYPE*)adata == PIXEL_MAX ) // Point in  overlap
56 			{
57 				*(PIXEL_TYPE*)idata = 1; *(PIXEL_TYPE*)adata = 1;
58 				if(x>OLRect.right) 	OLRect.right = x;
59 				if(x<OLRect.left ) 	OLRect.left = x;
60 				if(y>OLRect.bottom) OLRect.bottom = y;
61 				if(y<OLRect.top ) 	OLRect.top = y;
62 			}
63 		}
64 	}
65 	OLRect.right++;  OLRect.bottom++;
66 	// Set frame
67 
68 	for(y=theRect->top; y<theRect->bottom; y++)
69 	{
70 		idata = data  + bpl  * y + theRect->left * bpp;
71 		adata = alpha + bpla * y + theRect->left * bppa;
72 		for(x=theRect->left; x<theRect->right; x++, idata+=bpp, adata+=bppa)
73 		{
74 			if( *(PIXEL_TYPE*)idata  && !*(PIXEL_TYPE*)adata )
75 			{
76 				if	( x > theRect->left 	&& *(PIXEL_TYPE*)(adata - bppa)) 	SET_TO_EDGE( idata - bpp );
77 				if	( x < theRect->right-1 	&& *(PIXEL_TYPE*)(adata + bppa)) 	SET_TO_EDGE( idata + bpp );
78 				if	( y > theRect->top 		&& *(PIXEL_TYPE*)(adata - bpla)) 	SET_TO_EDGE( idata - bpl );
79 				if	( y < theRect->bottom-1 && *(PIXEL_TYPE*)(adata + bpla)) 	SET_TO_EDGE( idata + bpl );
80 			}
81 
82 			if(!*(PIXEL_TYPE*)idata  &&  *(PIXEL_TYPE*)adata )
83 			{
84 				if	( x > theRect->left 	&& *(PIXEL_TYPE*)(idata - bpp)) 	SET_TO_EDGE( adata - bppa );
85 				if	( x < theRect->right-1 	&& *(PIXEL_TYPE*)(idata + bpp)) 	SET_TO_EDGE( adata + bppa );
86 				if	( y > theRect->top 		&& *(PIXEL_TYPE*)(idata - bpl)) 	SET_TO_EDGE( adata - bpla );
87 				if	( y < theRect->bottom-1 && *(PIXEL_TYPE*)(idata + bpl)) 	SET_TO_EDGE( adata + bpla );
88 			}
89 		}
90 	}
91 
92 
93 
94 	// Set distances
95 
96 	for( dist = 2; dist<255; dist++)
97 	{
98 			// Update Progress report and check for cancel every 5 lines.
99 		skip++;
100 		if( showprogress && skip == 5 )
101 		{
102 
103 			sprintf( percent, "%d", (int) (dist* 100)/255) ;
104 			if( ! Progress( _setProgress, percent ) )
105 						return;
106 			skip = 0;
107 		}
108 		setdist = 255-dist;
109 
110 		for(y=OLRect.top; y<OLRect.bottom; y++)
111 		{
112 			idata = data  + bpl  * y + OLRect.left * bpp;
113 			adata = alpha + bpla * y + OLRect.left * bppa;
114 			for(x=OLRect.left; x<OLRect.right; x++, idata+=bpp, adata+=bppa)
115 			{
116 				if( *(PIXEL_TYPE*)idata 	== setdist + 1 )
117 				{
118 					if	( x > OLRect.left 		&& *(PIXEL_TYPE*)(adata - bppa)) 	SET_TO_DISTANCE( idata - bpp );
119 					if	( x < OLRect.right-1 	&& *(PIXEL_TYPE*)(adata + bppa)) 	SET_TO_DISTANCE( idata + bpp );
120 					if	( y > OLRect.top 		&& *(PIXEL_TYPE*)(adata - bpla)) 	SET_TO_DISTANCE( idata - bpl );
121 					if	( y < OLRect.bottom-1 	&& *(PIXEL_TYPE*)(adata + bpla)) 	SET_TO_DISTANCE( idata + bpl );
122 				}
123 				if( *(PIXEL_TYPE*)adata 	== setdist + 1 )
124 				{
125 					if	( x > OLRect.left 		&& *(PIXEL_TYPE*)(idata - bpp)) 	SET_TO_DISTANCE( adata - bppa );
126 					if	( x < OLRect.right-1 	&& *(PIXEL_TYPE*)(idata + bpp)) 	SET_TO_DISTANCE( adata + bppa );
127 					if	( y > OLRect.top 		&& *(PIXEL_TYPE*)(idata - bpl)) 	SET_TO_DISTANCE( adata - bpla );
128 					if	( y < OLRect.bottom-1 	&& *(PIXEL_TYPE*)(idata + bpl)) 	SET_TO_DISTANCE( adata + bpla );
129 				}
130 			}
131 		}
132 	}
133 
134 	if( showprogress )
135 		Progress( _disposeProgress, percent );
136 }
137 
_SetDistanceImage(Image * im,Image * pano,PTRect * theRect,int showprogress,int feather)138 void _SetDistanceImage ( Image* im, Image* pano, PTRect *theRect, int showprogress, int feather )
139 {
140 	int 					x,y,bpp,bppa, bpl, bpla, skip=0,setdist,dist;
141 	unsigned char			*data = *(im->data), *alpha = *(pano->data), *idata, *adata;
142 	register unsigned char 	*ch;
143 	char 					*progressMessage, percent[24];
144 	PTRect 					OLRect;
145 
146 	bpp 	= im->bitsPerPixel/8;
147 	bppa	= pano->bitsPerPixel/8;
148 	bpl 	= im->bytesPerLine;
149 	bpla	= pano->bytesPerLine;
150 
151 	OLRect.left 	= theRect->right;
152 	OLRect.right 	= theRect->left;
153 	OLRect.top 		= theRect->bottom;
154 	OLRect.bottom 	= theRect->top;
155 
156 	if( showprogress )
157 	{
158 		progressMessage = "Merging Images";
159 		Progress( _initProgress, progressMessage );
160 	}
161 
162 
163 	// First, set alpha channel in overlap region to 1, find minimum overlap rectangle
164 
165 	for(y=theRect->top; y<theRect->bottom; y++)
166 	{
167 		idata = data  + bpl  * y + theRect->left * bpp;
168 		adata = alpha + bpla * y + theRect->left * bppa;
169 		for(x=theRect->left; x<theRect->right; x++, idata+=bpp, adata+=bppa)
170 		{
171 			if( *(PIXEL_TYPE*)idata == PIXEL_MAX && *(PIXEL_TYPE*)adata == PIXEL_MAX ) // Point in  overlap
172 			{
173 				*(PIXEL_TYPE*)adata = 1;
174 				if(x>OLRect.right) 	OLRect.right = x;
175 				if(x<OLRect.left ) 	OLRect.left = x;
176 				if(y>OLRect.bottom) OLRect.bottom = y;
177 				if(y<OLRect.top ) 	OLRect.top = y;
178 			}
179 		}
180 	}
181 	OLRect.right++;  OLRect.bottom++;
182 	// Set frame
183 
184 	for(y=theRect->top; y<theRect->bottom; y++)
185 	{
186 		idata = data  + bpl  * y + theRect->left * bpp;
187 		adata = alpha + bpla * y + theRect->left * bppa;
188 		for(x=theRect->left; x<theRect->right; x++, idata+=bpp, adata+=bppa)
189 		{
190 			if(!*(PIXEL_TYPE*)idata  &&  *(PIXEL_TYPE*)adata )
191 			{
192 				if	( x > theRect->left 	&& *(PIXEL_TYPE*)(idata - bpp)) 		SET_TO_EDGE( adata - bppa );
193 				if	( x < theRect->right-1 	&& *(PIXEL_TYPE*)(idata + bpp)) 		SET_TO_EDGE( adata + bppa );
194 				if	( y > theRect->top 		&& *(PIXEL_TYPE*)(idata - bpl)) 		SET_TO_EDGE( adata - bpla );
195 				if	( y < theRect->bottom-1 && *(PIXEL_TYPE*)(idata + bpl)) 		SET_TO_EDGE( adata + bpla );
196 			}
197 		}
198 	}
199 
200 
201 
202 	// Set distances
203 
204 	feather+=2;
205 	if(feather > 255) feather = 255;
206 	for( dist = 2; dist<feather; dist++)
207 	{
208 			// Update Progress report and check for cancel every 5 lines.
209 		skip++;
210 		if( showprogress && skip == 5 )
211 		{
212 
213 			sprintf( percent, "%d", (int) (dist* 100)/255) ;
214 			if( ! Progress( _setProgress, percent ) )
215 						return;
216 			skip = 0;
217 		}
218 		setdist = 255-dist;
219 
220 		for(y=OLRect.top; y<OLRect.bottom; y++)
221 		{
222 			idata = data  + bpl  * y + OLRect.left * bpp;
223 			adata = alpha + bpla * y + OLRect.left * bppa;
224 			for(x=OLRect.left; x<OLRect.right; x++, idata+=bpp, adata+=bppa)
225 			{
226 				if( *(PIXEL_TYPE*)adata 	== setdist + 1 )
227 				{
228 					if	( x > OLRect.left 		&& *(PIXEL_TYPE*)(idata - bpp)) 		SET_TO_DISTANCE( adata - bppa );
229 					if	( x < OLRect.right-1 	&& *(PIXEL_TYPE*)(idata + bpp)) 		SET_TO_DISTANCE( adata + bppa );
230 					if	( y > OLRect.top 		&& *(PIXEL_TYPE*)(idata - bpl)) 		SET_TO_DISTANCE( adata - bpla );
231 					if	( y < OLRect.bottom-1 	&& *(PIXEL_TYPE*)(idata + bpl)) 		SET_TO_DISTANCE( adata + bpla );
232 				}
233 			}
234 		}
235 	}
236 
237 	if( showprogress )
238 		Progress( _disposeProgress, percent );
239 }
240 
241 
242 // Add image src to dst; use alpha channel
243 // seam is placed in the middle between edges of valid
244 // image portions.
245 // feather specifies width of soft edge (in pixels)
246 // showprogress = 1: Progressbar is displayed
247 // return 0 on success, -1 on failure
248 
_merge(Image * dst,Image * src,int feather,int showprogress,int seam)249 int _merge (  Image *dst, Image *src,  int feather, int showprogress, int seam )
250 {
251 	register int 			x,y, i;
252 	register unsigned char *dest, *source;	// Pointer to rgb-data
253     double 					sfactor = 1.0;
254 	register double 		result;
255 	PTRect					theRect;
256 	int 					bps,bpd;
257 
258 
259 	// Do all sorts of checks (size, etc)
260 
261 	if( (dst->bytesPerLine != src->bytesPerLine) ||
262 		(dst->width        != src->width)		 ||
263 		(dst->height       != src->height)       ||
264 	    (dst->dataSize     != src->dataSize)     ||
265 		(dst->bitsPerPixel != src->bitsPerPixel) ||
266 		(dst->bitsPerPixel != (BYTES_PER_CHANNEL*32)) 	||
267 		(dst->data 		   == NULL)				 ||
268 		(src->data         == NULL))
269 	{
270 		return -1;
271 	}
272 
273 	theRect.left 	= 0;
274 	theRect.right 	= dst->width;
275 	theRect.top 	= 0;
276 	theRect.bottom 	= dst->height;
277 
278 	bps = src->bitsPerPixel/8;
279 	bpd = dst->bitsPerPixel/8;
280 
281 	if( seam == _middle ){
282 		_SetDistance ( src, dst, &theRect, showprogress );
283 
284 		for(y=0; y<dst->height; y++){
285 			dest 	= *(dst->data) + y*dst->bytesPerLine;
286 			source 	= *(src->data) + y*src->bytesPerLine;
287 			for(x=0; x<dst->width; x++, dest+=bpd, source+=bps){
288 				if( *(PIXEL_TYPE*)source ) {// alpha channel set
289 					if( !*(PIXEL_TYPE*)dest ) {// No data in dest, so copy source to dest
290 						*(PIXEL_TYPE*)dest = 1;
291 						*(PIXEL_TYPE*)(dest+BYTES_PER_CHANNEL) 		= *(PIXEL_TYPE*)(source+BYTES_PER_CHANNEL);
292 						*(PIXEL_TYPE*)(dest+2*BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+2*BYTES_PER_CHANNEL);
293 						*(PIXEL_TYPE*)(dest+3*BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+3*BYTES_PER_CHANNEL);
294 					}
295 					else{
296 						int d = 255 - (int)*(PIXEL_TYPE*)source, s = 255 - (int)*(PIXEL_TYPE*)dest;
297 
298 						if( d==254 || d > s + feather )
299 						; // Use dest
300 						else if( s > d + feather ) // Use just source
301 						{
302 							*(PIXEL_TYPE*)(dest+BYTES_PER_CHANNEL) 		= *(PIXEL_TYPE*)(source+BYTES_PER_CHANNEL);
303 							*(PIXEL_TYPE*)(dest+2*BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+2*BYTES_PER_CHANNEL);
304 							*(PIXEL_TYPE*)(dest+3*BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+3*BYTES_PER_CHANNEL);
305 						}
306 						else
307 						{
308 							sfactor = GetBlendfactor( d, s, feather );
309 							for( i=1; i<=3; i++)
310 							{
311 								result = sfactor * *(PIXEL_TYPE*)(source+ i*BYTES_PER_CHANNEL)  +
312 										( 1.0 - sfactor ) * *(PIXEL_TYPE*)(dest+i*BYTES_PER_CHANNEL);
313 								DBL_TO_PIX( *(PIXEL_TYPE*)(dest+i*BYTES_PER_CHANNEL) , result );
314 							}
315 						}
316 					}
317 				}
318 			}
319 		}
320 	}
321 	else if( seam == _dest ){
322 		_SetDistanceImage ( dst, src, &theRect, showprogress, feather );
323 		for(y=0; y<dst->height; y++){
324 			dest 	= *(dst->data) + y*dst->bytesPerLine;
325 			source 	= *(src->data) + y*src->bytesPerLine;
326 			for(x=0; x<dst->width; x++, dest+=bpd, source+=bps){
327 				if( *(PIXEL_TYPE*)source ) {// alpha channel set
328 					if( !*(PIXEL_TYPE*)dest ) {// No data in dest, so copy source to dest
329 						*(PIXEL_TYPE*)dest = 1;
330 						*(PIXEL_TYPE*)(dest+BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+BYTES_PER_CHANNEL);
331 						*(PIXEL_TYPE*)(dest+2*BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+2*BYTES_PER_CHANNEL);
332 						*(PIXEL_TYPE*)(dest+3*BYTES_PER_CHANNEL) 	= *(PIXEL_TYPE*)(source+3*BYTES_PER_CHANNEL);
333 					}
334 					else{
335 						int d = 255 - (int)*(PIXEL_TYPE*)source;
336 
337 						if( d > feather )
338 						; // Use dest
339 						else{ // blend
340 							sfactor = ((double) d / (double) feather) * ( 1.0 - BLEND_RANDOMIZE * rand() / (double)RAND_MAX );
341 							for( i=1; i<=3; i++){
342 								result = sfactor * *(PIXEL_TYPE*)(dest+ i*BYTES_PER_CHANNEL)  +
343 										( 1.0 - sfactor ) * *(PIXEL_TYPE*)(source+i*BYTES_PER_CHANNEL);
344 								DBL_TO_PIX( *(PIXEL_TYPE*)(dest+i*BYTES_PER_CHANNEL) , result );
345 							}
346 						}
347 					}
348 				}
349 			}
350 		}
351 
352 	}
353 	else
354 	{
355 		PrintError("Error in function merge");
356 		return -1;
357 	}
358 
359 	// Set alpha channel
360 
361 	LOOP_IMAGE( dst, {if( *(PIXEL_TYPE*)idata ) *(PIXEL_TYPE*)idata = PIXEL_MAX;} );
362 
363 	return 0;
364 }
365 
366 
367 
368 
369 
370 
371 
372 
373 
374 
375 
_mergeAlpha(Image * im,unsigned char * alpha,int feather,PTRect * theRect)376 void _mergeAlpha ( Image *im, unsigned char *alpha, int feather, PTRect *theRect )
377 {
378 	register int 			x,y;
379 	double 				sfactor;
380 	unsigned char			*data = *(im->data), *idata, *adata;
381 	int				BitsPerChannel,bpp;
382 	Image				aImage;	 // Dummy for transfering alpha data
383 
384 
385 	GetBitsPerChannel( im, BitsPerChannel );
386 	bpp = im->bitsPerPixel/8;
387 
388 	memcpy( &aImage, im, sizeof( Image ));
389 	aImage.bitsPerPixel = BitsPerChannel;
390 	aImage.bytesPerLine = im->width*BYTES_PER_CHANNEL;
391 	aImage.data = &alpha;
392 
393 
394 	_SetDistance ( im, &aImage, theRect, 1 );
395 
396 	for(y=theRect->top; y<theRect->bottom; y++){
397 		idata = data + im->bytesPerLine * y + theRect->left * bpp;
398 		adata = alpha + im->width * y * BYTES_PER_CHANNEL + theRect->left * BYTES_PER_CHANNEL;
399 		for(x=theRect->left; x<theRect->right; x++, idata+=bpp, adata+=BYTES_PER_CHANNEL){
400 			if( *(PIXEL_TYPE*)idata ){ // alpha channel of image set
401 				if( !*(PIXEL_TYPE*)adata ) {// No data in pano, so copy source to dest
402 					*(PIXEL_TYPE*)idata = PIXEL_MAX;
403 					}
404 				else{
405 					int d = 255 - (int)*(PIXEL_TYPE*)idata, s = 255 - (int)*(PIXEL_TYPE*)adata;
406 
407 					if( d==254 || d > s + feather ){
408 							*(PIXEL_TYPE*)idata = 0;
409 					}
410 					else if( s > d + feather ){ // Use just source
411 							*(PIXEL_TYPE*)idata = PIXEL_MAX;
412 					}
413 					else{
414 						sfactor = 255.0 * GetBlendfactor( d, s, feather );
415 						DBL_TO_PIX( *(PIXEL_TYPE*)idata , sfactor );
416 					}
417 				}
418 			}
419 		}
420 	}
421 }
422 
423 
424 
425 
426 
427