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 = α
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