1 /*
2  *  ptstitch.c
3  *
4  *  Routines related to stitching and creation of alpha channels
5  *
6  *  Copyright Helmut Dersch and Daniel M. German
7  *
8  *  Aug 2006
9  *
10  *  This program is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2 of the License, or (at your option) any later version.
14  *
15  *  This software is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this software; see the file COPYING.  If not, a copy
22  *  can be downloaded from http://www.gnu.org/licenses/gpl.html, or
23  *  obtained by writing to the Free Software Foundation, Inc.,
24  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  *
27  *  Author: Daniel M German dmgerman at uvic doooot ca
28  *
29  */
30 
31 #include <assert.h>
32 
33 #include "filter.h"
34 #include "pttiff.h"
35 #include "file.h"
36 #include "ptstitch.h"
37 #include "PTcommon.h"
38 #include "ptfeather.h"
39 #include "metadata.h"
40 
41 // Get the value of a channel in the  pixel pointed by ptr
panoStitchPixelChannelGet(unsigned char * ptr,int bytesPerChannel,int channel)42 unsigned int panoStitchPixelChannelGet(unsigned char *ptr, int bytesPerChannel, int channel)
43 {
44     uint16_t *pixel16;
45     assert(ptr != NULL);
46 
47     assert(channel >= 0 && channel <=3);
48     assert(bytesPerChannel == 1 || bytesPerChannel ==2);
49 
50     if (bytesPerChannel == 1) {
51         return *(ptr + channel);
52     }
53     else if (bytesPerChannel == 2) {
54         pixel16  = (uint16_t *) ptr;
55         return *(pixel16+channel);
56     }
57     else {
58         assert(0);
59         return 0;// fix warning.
60     }
61 
62 }
63 
64 // Get the value of a channel in the  pixel pointed by ptr
panoStitchPixelChannelSet(unsigned char * ptr,int bytesPerChannel,int channel,unsigned int value)65 void panoStitchPixelChannelSet(unsigned char *ptr, int bytesPerChannel, int channel, unsigned int value)
66 {
67     uint16_t *pixel16;
68     assert(ptr != NULL);
69 
70     assert(channel >= 0 && channel <=3);
71     assert(bytesPerChannel == 4 || bytesPerChannel ==8);
72 
73     if (bytesPerChannel == 4) {
74         *(ptr + channel) = value;
75     }
76     else if (bytesPerChannel == 8) {
77         pixel16  = (uint16_t *) ptr;
78         *(pixel16+channel) = value;
79     }
80     else {
81         assert(0);
82     }
83 
84 }
85 
panoStitchPixelMapGet(unsigned char * ptr,int bytesPerPixel)86 static unsigned int panoStitchPixelMapGet(unsigned char *ptr, int bytesPerPixel)
87 {
88     uint16_t *pixel16;
89     unsigned char *temp;
90     assert(ptr != NULL);
91 
92     assert(bytesPerPixel == 4 || bytesPerPixel ==8);
93 
94     // We use 2 channel (Green in 16 bit) and (Green and Blue in 8 bit images) to store the map
95 
96     // Make sure this happens in char *
97     temp = ptr + bytesPerPixel /2;
98     pixel16 = (uint16_t *) temp;
99 
100     return *pixel16;
101 }
102 
103 // Set the value of a given channel in the pixel pointed by ptr
panoStitchPixelMapSet(unsigned char * ptr,int bytesPerPixel,unsigned int value)104 static void panoStitchPixelMapSet(unsigned char *ptr, int bytesPerPixel, unsigned int value)
105 {
106     uint16_t *ptr16;
107     unsigned char *temp;
108 
109     // We use 2 channel (Green in 16 bit) and (Green and Blue in 8 bit images) to store the map
110 
111     assert(bytesPerPixel == 4 || bytesPerPixel ==8);
112     assert(ptr != NULL);
113 
114     assert(value >= 0);
115     assert(value <= 0xffff);
116 
117     temp = ptr + bytesPerPixel /2;
118     ptr16 = (uint16_t *) temp;
119 
120     *ptr16 = value;
121 }
122 
123 // Set the map of a pixel only if it is necessary
panoStitchPixelDetermineMap(unsigned char * pixel,int bytesPerPixel,unsigned int * count)124 static void panoStitchPixelDetermineMap(unsigned char *pixel, int bytesPerPixel,  unsigned int *count)
125 {
126 
127     int alphaChannel;
128     unsigned int value = 0;
129 
130     assert(bytesPerPixel == 4 || bytesPerPixel ==8);
131     assert(pixel != NULL);
132 
133     alphaChannel = panoStitchPixelChannelGet(pixel, bytesPerPixel/4, 0);
134 
135     if (alphaChannel == 0) {
136         *count = 0;
137     }
138     else {
139         (*count)++;
140     }
141     value = panoStitchPixelMapGet(pixel, bytesPerPixel);
142 
143     if (value < *count) {
144         *count = value;
145     }
146     else
147         panoStitchPixelMapSet(pixel, bytesPerPixel, *count);
148 
149 }
150 
151 
152 
153 /*
154  * This routine creates the stitching mask map
155  *
156  * Stitching maps contain the same alpha channel than the original image, but instead of pixel data they contiain
157  * an "index" of how good that pixel is. Pixels at the center of the image have better indexes than
158  * those at the edge
159  *
160  */
panoStitchComputeMaskMap(Image * image)161 void panoStitchComputeMaskMap(Image * image)
162 {
163 
164     int column;
165     int row;
166     unsigned char *ptr;
167     unsigned char *pixel = NULL;
168     unsigned int count;
169     int bytesPerPixel = 0;
170     unsigned int alphaChannel;
171 
172 
173     // determine the type of image
174     bytesPerPixel = panoImageBytesPerPixel(image);
175 
176     // Use the GreenBlue pixel area is used to keep a counter of the
177     // minimum distance (in pixels) away we are from the edges of the
178     // mask (horizontal or vertical)
179 
180     // The algorithm is fairly simple:
181 
182     // For each column
183     //   Process each row from top to down
184     //     Set each pixel counter to the number of pixels from edge of the mask (from the left)
185     //   Process each row from bottom to top
186     // Set each pixel counter to the minimum between current counter and number of pixels
187     // from edge (from the right)
188 
189     // for each row
190     //   repeat the same algorithm (done per column)
191 
192     for (column = 0; column < panoImageWidth(image); column++) {
193         count = 0;
194         // Point to the given column in row 0
195 
196         ptr = panoImageData(image) + column * bytesPerPixel;
197 
198         //    fprintf(stderr, "St1.1 Column[%d]\n", column);
199 
200 
201         // From top to bottom
202         for (row = 0; row < panoImageHeight(image); row++) {
203 
204             // Get alpha channel for this point
205 	    pixel = ptr +  row * panoImageBytesPerLine(image);
206 
207             alphaChannel = panoStitchPixelChannelGet(pixel, bytesPerPixel/4, 0);
208 
209             if (alphaChannel == 0) {
210                 count = 0;
211             }
212             else {
213                 count++;
214             }
215             // In the first pass we ALWAYS set the map because it is uninitialized
216             panoStitchPixelMapSet(pixel, bytesPerPixel, count);
217         }
218 
219         count = 0;
220         row = image->height;
221 
222         // From bottom to top
223         while (--row >= 0) {
224             pixel = ptr + row * image->bytesPerLine;
225 
226             panoStitchPixelDetermineMap(pixel, bytesPerPixel, &count);
227 
228         }                       //while
229 
230         //    fprintf(stderr, "St1.5 Column[%d]\n", column);
231 
232     }                           //
233 
234     ///////////// row by row
235 
236     //  fprintf(stderr, "St2\n");
237 
238     for (row = 0; row < image->height; row++) {
239         count = 0;
240         ptr = row * image->bytesPerLine + *(image->data);
241 
242         // process from left to right
243         for (column = 0; column < image->width; column++) {
244             pixel = ptr + panoImageBytesPerPixel(image) * column;
245 
246             panoStitchPixelDetermineMap(pixel, bytesPerPixel, &count);
247         }                       // for column
248 
249         //-----------------------------;;
250 
251 
252         //  fprintf(stderr, "St3\n");
253 
254         count = 0;
255         column = image->width;
256 
257         while (--column >= 0) {
258             pixel = ptr + panoImageBytesPerPixel(image) * column;
259 
260             panoStitchPixelDetermineMap(pixel, bytesPerPixel, &count);
261         }
262     }                           // end of for row
263 
264 }
265 
266 
267 //
268 // Compute the map of the stitching mask and create a file with it.
269 // The stitching mask will be contained in the GB channels (this is,
270 // the 16 bits corresponding to the G and B channel will contain a uint16_t that
271 // contains, for that particular point, the stitching mask.
272 //
panoStitchCreateMaskMapFiles(fullPath * inputFiles,fullPath * maskFiles,int numberImages)273 int panoStitchCreateMaskMapFiles(fullPath * inputFiles, fullPath * maskFiles,
274                                     int numberImages)
275 {
276     int index;
277     char tempString[512];
278     Image image;
279 
280     if (ptQuietFlag == 0)
281         Progress(_initProgress, "Preparing Stitching Masks");
282 
283     // for each image, create merging mask and save to temporal file
284     for (index = 0; index < numberImages; index++) {
285 
286         sprintf(tempString, "%d", index * 100 / numberImages);
287 
288         // Do progress
289         if (ptQuietFlag == 0) {
290             if (Progress(_setProgress, tempString) == 0) {
291                 return 0;
292             }
293         }
294 
295         if (panoTiffRead(&image, inputFiles[index].name) == 0) {
296             PrintError("Could not read TIFF-file");
297             return 0;
298         }
299 
300         // Compute the stitching mask in-situ
301         panoStitchComputeMaskMap(&image);
302 
303         strcpy(maskFiles[index].name, inputFiles[0].name);
304 
305         if (panoFileMakeTemp(&maskFiles[index]) == 0) {
306             PrintError("Could not make Tempfile");
307             return -1;
308         }
309 
310 	if (panoTiffWrite(&image, maskFiles[index].name) == 0) {
311 	    PrintError("Could not write TIFF-file [%s]", maskFiles[index].name);
312 	    return -1;
313 	}
314 
315         //    fprintf(stderr, "Written to file %s\n", maskFiles[index].name);
316 
317 	panoImageDispose(&image);
318 
319     }                           // for (index...
320 
321     // Do progress
322 
323     if (!ptQuietFlag)
324 
325         Progress(_setProgress, "100");
326     Progress(_disposeProgress, tempString);
327 
328     return 1;
329 }
330 
331 /*
332  * This routine takes one given row from numberImages images and tries
333  * to set their alpha channel to show the one with the 'best' pixel
334  *
335  * TODO: unify this and the 8 bits version
336  */
panoStitchSetBestAlphaChannel16bits(unsigned char * imagesBuffer,int numberImages,pano_ImageMetadata * imageParms)337 static void panoStitchSetBestAlphaChannel16bits(unsigned char *imagesBuffer,
338                                                    int numberImages,
339                                                    pano_ImageMetadata * imageParms)
340 {
341     //  fprintf(stderr, "SetBestAlphaChannel16bits not supported yet\n");
342     //assert(0); // it should not be here... yet
343 
344     unsigned char *pixel;
345     uint16_t *ptrCount;
346     uint16_t best;
347     uint16_t maskValue;
348     int column;
349     int j;
350     int bytesPerLine;
351 
352     assert(imageParms->bytesPerPixel == 8);
353 
354     bytesPerLine = imageParms->cropInfo.fullWidth * imageParms->bytesPerPixel;
355 
356     for (column = 0, pixel = imagesBuffer;
357          column < imageParms->cropInfo.fullWidth; column++, pixel += imageParms->bytesPerPixel) {
358 
359         best = 0;
360         ptrCount = (uint16_t *) (pixel + 2);
361         maskValue = *ptrCount;
362 
363         // find the image with the highest value
364 
365         for (j = 1; j < numberImages; j++) {
366 
367             ptrCount = (uint16_t *) (pixel + bytesPerLine * j + 2);
368 
369             if (*ptrCount > maskValue) {
370 
371                 best = j;
372                 maskValue = *ptrCount;
373 
374             }
375         }                       // for j
376 
377         if (maskValue != 0) {
378 
379             // set the mask of the ones above, but not below... interesting...
380 
381             for (j = best + 1; j < numberImages; j++) {
382                 uint16_t *pixel2;
383 
384                 pixel2 = (uint16_t *) (pixel + bytesPerLine * j);
385 
386                 if (0 != *pixel2) {
387                     *pixel2 = 1;
388                 }
389             }
390         }
391     }                           // for i
392 
393 
394 }
395 
396 /*
397  * This routine takes one given row from numberImages images and tries
398  * to set their alpha channel to show the one with the 'best' pixel
399  *
400  * TODO: unify this and the 16 bits version
401  */
panoStitchSetBestAlphaChannel8bits(unsigned char * imagesBuffer,int numberImages,pano_ImageMetadata * imageParms)402 static void panoStitchSetBestAlphaChannel8bits(unsigned char *imagesBuffer,
403                                                   int numberImages,
404                                                   pano_ImageMetadata * imageParms)
405 {
406     unsigned char *pixel;
407     uint16_t *ptrCount;
408     uint16_t best;
409     uint16_t maskValue;
410     int column;
411     int j;
412 
413     int bytesPerLine;
414 
415     assert(imageParms->bytesPerPixel == 4);
416 
417     bytesPerLine = imageParms->cropInfo.fullWidth * imageParms->bytesPerPixel;
418 
419     for (column = 0, pixel = imagesBuffer;
420          column < imageParms->cropInfo.fullWidth;
421 	 column++, pixel += 4) {
422 
423         best = 0;
424         ptrCount = (uint16_t *) (pixel + 2);
425         maskValue = *ptrCount;
426 
427         // find the image with the highest value
428 
429         for (j = 1; j < numberImages; j++) {
430 	    unsigned char *temp;
431 
432             temp = (pixel + bytesPerLine * j + 2);
433 
434             ptrCount = (uint16_t *) temp;
435 
436             if (*ptrCount > maskValue) {
437 
438                 best = j;
439                 maskValue = *ptrCount;
440 
441             }
442         }                       // for j
443 
444         if (maskValue != 0) {
445 
446             // set the mask of the ones above, but not below... interesting...
447 
448             for (j = best + 1; j < numberImages; j++) {
449                 unsigned char *pixel2;
450 
451                 pixel2 = pixel + bytesPerLine * j;
452 
453                 if (0 != *pixel2) {
454                     *pixel2 = 1;
455                 }
456             }
457         }
458     }                           // for i
459 
460 }
461 
462 
463 
464 
465 /*
466  * Creates an image with RBG from input but alpha channel from mask
467  *
468  */
panoStitchReplaceAlphaChannel(fullPath * inputImage,fullPath * mask,fullPath * output)469 static int panoStitchReplaceAlphaChannel(fullPath * inputImage, fullPath * mask,
470                                          fullPath * output)
471 {
472     unsigned char *imageRowBuffer = NULL;
473     unsigned char *maskRowBuffer = NULL;
474     int row;
475     int j;
476 
477     int returnValue = 0;
478     int numberBytesToCopy;
479     unsigned char *source;
480     unsigned char *destination;
481 
482     pano_Tiff *imageFile  = NULL;
483     pano_Tiff *outputFile = NULL;
484     pano_Tiff *maskFile   = NULL;
485 
486     int jumpBytes;
487     int alphaChannelOffset;
488 
489     //   For each row
490     //     Read row of image
491     //     Read row of mask
492     //     Replace alpha channel in image with masks alpha channel
493     //     Write row
494     //
495     //Note that all three images involved here (input image, mask image and
496     //resulting image) have the same dimensions, and we don't care what the
497     //dimensions are the for the final output image
498 
499     // FIRST PREPARE THE FILES
500 
501     // Open input image
502     if ((imageFile = panoTiffOpen(inputImage->name)) == NULL) {
503         PrintError("Could not open TIFF-file");
504         returnValue = 0;
505         goto end;
506     }
507 
508     //Allocate line buffers for image and mask
509     if ((imageRowBuffer = calloc(panoTiffBytesPerLine(imageFile), 1)) == NULL
510         || (maskRowBuffer =
511             calloc(panoTiffBytesPerLine(imageFile), 1)) == NULL) {
512         PrintError("Not enough memory");
513         returnValue = 0;
514         goto end;
515     }
516 
517     // Open mask file
518     if ((maskFile = panoTiffOpen(mask->name)) == NULL) {
519         PrintError("Could not open mask file");
520         returnValue = 0;
521         goto end;
522     }
523 
524     // Create output file
525     if ((outputFile =
526          panoTiffCreate(output->name, &maskFile->metadata)) == NULL) {
527         PrintError("Could not create TIFF-file");
528         returnValue = 0;
529         goto end;
530     }
531 
532     // Processing one row at a time
533     if (panoTiffBitsPerPixel(imageFile) == 32) {
534         jumpBytes = 4;
535         alphaChannelOffset = 3;
536         numberBytesToCopy = 1;
537     }
538     else {
539         jumpBytes = 8;
540         alphaChannelOffset = 6;
541         numberBytesToCopy = 2;
542     }
543 
544     // Process one line at a time.
545 
546     for (row = 0; row < panoTiffImageHeight(imageFile); row++) {
547 
548         TIFFReadScanline(imageFile->tiff, imageRowBuffer, row, 0);
549         TIFFReadScanline(maskFile->tiff, maskRowBuffer, row, 0);
550 
551         destination = imageRowBuffer + alphaChannelOffset;
552         source = maskRowBuffer + alphaChannelOffset;
553 
554         // Copy alpha channel...
555         for (j = 0; j < panoTiffImageWidth(imageFile); j++) {
556             int k;
557             // Copy the mask
558             // TODO: use memcpy
559             for (k = 0; k < numberBytesToCopy; k++) {
560                 *(destination + k) = *(source + k);
561             }
562 
563             destination += jumpBytes;
564             source += jumpBytes;
565         }
566 
567         // Write row to output
568         if (TIFFWriteScanline(outputFile->tiff, imageRowBuffer, row, 0) != 1) {
569             PrintError
570                 ("Unable to write data to output file (ReplaceAlphaChannel)\n");
571             returnValue = 0;
572             goto end;
573         }
574 
575     }
576 
577     returnValue = 1;
578   end:
579 
580     if(imageFile)
581       panoTiffClose(imageFile);
582 
583     if(maskFile)
584       panoTiffClose(maskFile);
585 
586     if(outputFile)
587       panoTiffClose(outputFile);
588 
589     free(imageRowBuffer);
590     free(maskRowBuffer);
591 
592     return returnValue;
593 }
594 
595 
panoStitchCalculateAlphaChannel(unsigned char * imagesBuffer,int numberImages,pano_ImageMetadata * imageMetadata)596 static void panoStitchCalculateAlphaChannel(unsigned char *imagesBuffer,
597                                                int numberImages,
598                                                pano_ImageMetadata * imageMetadata)
599 {
600 
601     switch (imageMetadata->bitsPerSample) {
602     case 8:
603         panoStitchSetBestAlphaChannel8bits(imagesBuffer, numberImages, imageMetadata);
604         break;
605     case 16:
606         panoStitchSetBestAlphaChannel16bits(imagesBuffer, numberImages, imageMetadata);
607         break;
608     default:
609         fprintf(stderr,
610                 "CalculateAlphaChannel not supported for this image type (%d bitsPerPixel)\n",
611                 imageMetadata->bitsPerPixel);
612         exit(1);
613     }
614 }
615 
616 
617 /*
618  * Create the alpha channels for the output images
619  *
620  */
panoStitchCreateAlphaChannels(fullPath * masksNames,fullPath * alphaChannelNames,int numberImages)621 int panoStitchCreateAlphaChannels(fullPath * masksNames,
622                                   fullPath * alphaChannelNames, int numberImages)
623 {
624     pano_Tiff **tiffMasks;
625     pano_Tiff **tiffAlphaChannels;
626     unsigned char *imagesBuffer = NULL;
627     unsigned char *ptrBuffer;
628     int index;
629     char tempString[24];
630 
631     int returnValue = 0;
632     int fullSizeRowIndex;
633 
634     int fullImageWidth;
635     int fullImageHeight;
636     int bytesPerLine;
637     int bitsPerPixel;
638 
639     assert(numberImages > 0);
640     assert(masksNames != NULL);
641     assert(alphaChannelNames != NULL);
642 
643     //printf("CreateAlpha %d\n", numberImages);
644 
645     // Allocate arrays of TIFF* for the input and output
646     // images. process is one row at a time, with all images
647     // processed at the same time
648     tiffMasks = calloc(numberImages, sizeof(pano_Tiff));
649     tiffAlphaChannels = calloc(numberImages, sizeof(pano_Tiff));
650 
651     if (tiffAlphaChannels == NULL || tiffMasks == NULL) {
652         PrintError("Not enough memory");
653         return 0;
654     }
655 
656     if (ptQuietFlag == 0)
657         Progress(_initProgress, "Calculating Alpha Channel");
658 
659     // Alpha Channel calculation
660     // Open for read
661     //       mask files
662     //  and  input files
663     // Open for write  alpha channel files
664 
665     // Open up an input image, then create a corresponding output image...repeat for all images
666     for (index = 0; index < numberImages; index++) {
667 
668         if ((tiffMasks[index] = panoTiffOpen(masksNames[index].name)) == 0) {
669             PrintError("Could not open TIFF-file");
670             return 0;
671         }
672 
673         strcpy(alphaChannelNames[index].name, masksNames[0].name);
674 
675         if (panoFileMakeTemp(&alphaChannelNames[index]) == 0) {
676             PrintError("Could not make Tempfile");
677             goto end;
678         }
679 
680         tiffAlphaChannels[index] =
681             panoTiffCreate(alphaChannelNames[index].name,
682                            panoTiffImageMetadata(tiffMasks[index]));
683 
684         if (tiffAlphaChannels[index] == NULL) {
685             PrintError("Could not create TIFF-file");
686             goto end;
687         }
688 
689     }                           // finished opening up output files
690 
691     // Get sizes of the entire image
692     fullImageWidth = panoTiffFullImageWidth(tiffMasks[0]);
693     fullImageHeight = panoTiffFullImageHeight(tiffMasks[0]);
694     bitsPerPixel = panoTiffBitsPerPixel(tiffMasks[0]);
695     bytesPerLine = fullImageWidth * panoTiffBytesPerPixel(tiffMasks[0]);
696 
697     for (index = 0; index < numberImages; index++) {
698 	assert(fullImageWidth == panoTiffFullImageWidth(tiffMasks[index]));
699 	assert(fullImageHeight == panoTiffFullImageHeight(tiffMasks[index]));
700 	assert(bitsPerPixel == panoTiffBitsPerPixel(tiffMasks[index]));
701 	assert(bytesPerLine == fullImageWidth * panoTiffBytesPerPixel(tiffMasks[index]));
702     }
703 
704     // just for the sake of it
705 
706     // The imagesBuffer contains as many rows as we have input images, and
707     // each row is as wide as the final output image
708 
709         //      printf("Fulls ize %d %d bytesPerLine %d bitsPerPixel %d\n", numberImages,
710         //                 bytesPerLine,
711         //                 bytesPerLine, bitsPerPixel);
712 
713     imagesBuffer = calloc(numberImages, bytesPerLine);
714     if (imagesBuffer == NULL) {
715         PrintError("Not enough memory");
716         goto end;
717     }
718 
719     assert(fullImageWidth > 0 && fullImageHeight > 0 && bytesPerLine > 0
720            && bitsPerPixel > 0);
721     //  fprintf(stderr, "Files have been created, process each row\n");
722 
723     //iterate one row at a time, and for each row process all images
724 
725     for (fullSizeRowIndex = 0; fullSizeRowIndex < fullImageHeight;
726          fullSizeRowIndex++) {
727 
728         // Update progress
729         if (ptQuietFlag == 0) {
730             if (fullSizeRowIndex == (fullSizeRowIndex / 20) * 20) {
731                 sprintf(tempString, "%lu",
732                         (long unsigned) fullSizeRowIndex * 100 /
733                         fullImageHeight);
734                 if (Progress(_setProgress, tempString) == 0) {
735                     // If user aborts, end
736                     returnValue = 0;
737                     goto end;
738                 }
739             }
740         }
741 
742 
743         // process the current row for all images
744         for (ptrBuffer = imagesBuffer, index = 0; index < numberImages;
745              index++, ptrBuffer += bytesPerLine) {
746 
747             if (!panoTiffReadScanLineFullSize
748                 (tiffMasks[index], ptrBuffer, fullSizeRowIndex)) {
749                 PrintError("Error reading temporary TIFF data");
750                 returnValue = 0;
751                 goto end;
752             }
753 	    RGBAtoARGB(ptrBuffer, fullImageWidth, bitsPerPixel);
754 
755         }
756 
757 
758 
759         //calculate the alpha channel for this row in all images
760 
761 	panoStitchCalculateAlphaChannel(imagesBuffer, numberImages,
762 					panoTiffImageMetadata(tiffMasks[0]));
763 
764 
765 
766         //write out the alpha channel data for this row to all output images
767         for (index = 0, ptrBuffer = imagesBuffer; index < numberImages;
768              index++, ptrBuffer += bytesPerLine) {
769 
770 
771 	    ARGBtoRGBA(ptrBuffer, fullImageWidth, bitsPerPixel);
772             if (!panoTiffWriteScanLineFullSize
773                 (tiffAlphaChannels[index], ptrBuffer, fullSizeRowIndex)) {
774                 PrintError
775                     ("Unable to write data to output file (CreateAlphaChannel)\n");
776                 returnValue = 0;
777                 goto end;
778             }
779         }
780 
781 
782     }                           //for fullSizeRowIndex
783     returnValue = 1;
784 
785   end:
786 
787     if (!ptQuietFlag) {
788         Progress(_setProgress, "100");
789         Progress(_disposeProgress, "");
790     }
791 
792     for (index = 0; index < numberImages; index++) {
793         if (tiffMasks[index] != NULL)
794             panoTiffClose(tiffMasks[index]);
795         if (tiffAlphaChannels[index] != NULL)
796             panoTiffClose(tiffAlphaChannels[index]);
797     }                           // for index.
798 
799     free(imagesBuffer);
800     free(tiffAlphaChannels);
801     free(tiffMasks);
802 
803     return returnValue;
804 }
805 
806 
807 
808 /**
809  * Replaces the alpha channel in each image in inputFiles with a generated
810  * mask.  The mask is calculated so as to route the seam between overlapping
811  * images through the center of the overlap region...
812  */
panoStitchReplaceMasks(fullPath * inputFiles,fullPath * outputFiles,int numberImages,int featherSize)813 int panoStitchReplaceMasks(fullPath * inputFiles, fullPath * outputFiles,
814                                   int numberImages, int featherSize)
815 {
816     int returnValue = -1; // default to fail
817     fullPath *alphaChannelFiles = NULL;
818     fullPath *maskFiles         = NULL;
819     int i;
820     Image image;
821     char tempString[512];
822 
823     if (numberImages == 0) {
824         return 0;
825     }
826 
827 
828     SetImageDefaults(&image);
829 
830     maskFiles = calloc(numberImages, sizeof(fullPath));
831     alphaChannelFiles = calloc(numberImages, sizeof(fullPath));
832 
833 
834     if (maskFiles == NULL || alphaChannelFiles == NULL) {
835         PrintError("Not enough memory");
836         goto end;
837     }
838 
839     // CREATE stitching maps
840     if (!panoStitchCreateMaskMapFiles(inputFiles, maskFiles, numberImages)) {
841         PrintError("Could not create the stitching masks");
842         goto end;
843     }
844 
845     if (!panoStitchCreateAlphaChannels(maskFiles, alphaChannelFiles, numberImages)) {
846         PrintError("Could not create alpha channels");
847         goto end;
848     }
849 
850     // From this point on we do not need to process all files at once. This will save temporary disk space
851 
852     for (i = 0; i < numberImages; i++) {
853         fullPath withAlphaChannel;
854 
855         sprintf(tempString, "%d", 100 * i / numberImages);
856 
857         if (ptQuietFlag == 0) {
858             if (Progress(_setProgress, tempString) == 0) {
859                 // We have to delete any temp file
860                 goto end;
861             }
862         }
863 
864         // We no longer need the mask files
865         remove(maskFiles[i].name);
866 
867         // Reuse the temporary name
868         memcpy(&withAlphaChannel, &maskFiles[i], sizeof(fullPath));
869 
870         // Replace the alpha channel of the input image
871         if (!panoStitchReplaceAlphaChannel
872             (&inputFiles[i], &alphaChannelFiles[i], &withAlphaChannel)) {
873             PrintError("Unable to replace alpha channel in image %d", i);
874             goto end;
875         }
876         // we no longer need the alpha channel
877         remove(alphaChannelFiles[i].name);
878 
879 
880         // Do feathering
881         if (featherSize > 0) {
882 
883             fullPath feathered;
884 
885             memcpy(&feathered, &maskFiles[i], sizeof(fullPath));
886 
887             if (!panoFeatherFile(&withAlphaChannel, &feathered, featherSize)) {
888                 PrintError("Unable to apply feather to image %d", i);
889                 goto end;
890             }
891 
892 	    if (strcmp(withAlphaChannel.name, feathered.name) != 0) {
893 	      remove(withAlphaChannel.name);
894 	    }
895             rename(feathered.name, outputFiles[i].name);
896         }
897         else {
898 	  rename(withAlphaChannel.name, outputFiles[i].name);
899 
900         }
901     }
902     returnValue = 0; //success
903 
904 end:
905     free(maskFiles);
906     free(alphaChannelFiles);
907 
908     return returnValue;
909 
910 }
911 
912 /// BLENDING ROUTINES
913 
panoStitchBlendLayers8Bit(unsigned char ** imageDataBuffers,int counterImageFiles,unsigned char * resultBuffer,int lines,int imageWidth,int scanLineSize)914 static void panoStitchBlendLayers8Bit(unsigned char **imageDataBuffers, int counterImageFiles,
915                                       unsigned char *resultBuffer, int lines, int imageWidth,
916                                       int scanLineSize)
917 {
918 
919     // 0x8(%ebp)    imageDataBuffers
920     // 0xc(%ebp)    counterImageFiles
921     // 0x10(%ebp)   resultBuffer
922     // 0x14(%ebp)   lines
923     // 0x18(%ebp)   imageWidth
924     // 0x1c(%ebp)   scanLineSize
925 
926     // 0xffffffdc(%ebp)  imageIndex
927     // 0xffffffe0(%ebp)  alphaChannel
928     // 0xffffffe4(%ebp)  blue
929     // 0xffffffe8(%ebp)  green
930     // 0xffffffec(%ebp)  red
931     // 0xfffffff0(%ebp)  rowOffset
932     // 0xfffffff4(%ebp)  pixelOffset
933     // 0xfffffff8(%ebp)  currentLine
934     // 0xfffffffc(%ebp)  currentColumn
935 
936     int imageIndex = 0;
937     unsigned int colours[3];
938     unsigned int alphaChannel;
939     unsigned int currentLine;
940     unsigned int currentColumn;
941     unsigned int rowOffset;
942 
943     currentLine = 0;
944 
945     for (currentLine = 0; (int)currentLine < lines; currentLine++) {
946 
947         //printf("Currnet line %d\n", currentLine);
948 
949         rowOffset = scanLineSize * currentLine;
950 
951         for (currentColumn = 0; (int) currentColumn < imageWidth; currentColumn++) {
952 
953             unsigned int pixelOffset;
954             unsigned int i;
955 
956             //      printf("Currnet column %d\n", currentColumn);
957 
958             pixelOffset = rowOffset + currentColumn * 4;
959 
960 
961             // Initialize colours for this pixel
962             alphaChannel = 0;
963             for (i = 0; i < 3; i++)
964                 colours[i] = 0;
965 
966 
967             // Do alpha blending, from top to bottom. Bail out when alpha channel is equal to maximum
968 
969             for (imageIndex = counterImageFiles - 1; imageIndex >= 0;
970                  imageIndex--) {
971 
972                 unsigned int alphaContribution;
973                 unsigned char *ptrPixel;
974                 unsigned int bottomAlpha;
975                 unsigned int index;
976 
977 
978                 // printf("Currnet image %d\n", imageIndex);
979 
980 
981                 // The alpha blending algorithm is (for premultiplied values)
982 
983                 // C_result = C_above + C_below * (1 - alpha_above)
984                 // A_result = Alpha_above + alpha_below * (1 - alpha_above)
985 
986                 // Find pixel in this layer
987                 ptrPixel = imageDataBuffers[imageIndex] + pixelOffset;
988 
989 
990                 // printf("TO read pixel\n");
991 
992                 bottomAlpha = *(ptrPixel + 3);  // this should be the value of the mask for this particular pixel
993 
994                 // printf("After read pixel\n");
995 
996                 alphaContribution =
997                     ((0xff - alphaChannel) * bottomAlpha) / 0xff;
998 
999                 // I don't really think this step is necessary, but due to innestability of the calculation
1000                 // alphaContribution it might overflow the byte valuex
1001 
1002                 if (alphaChannel + alphaContribution > 0xff) {
1003                     alphaContribution = 0xff - alphaChannel;
1004                 }
1005 
1006                 alphaChannel += alphaContribution;
1007 
1008                 // Makek sure the alpha channel is within range
1009                 assert(alphaChannel >= 0 && alphaChannel <= 0xff);
1010 
1011                 // now do the colours
1012 
1013                 // printf("TO set pixel\n");
1014 
1015                 for (index = 0; index < 3; index++) {
1016                     colours[index] += (*(ptrPixel + index) * alphaContribution) / 0xff; //
1017 
1018                     if (!(colours[index] >= 0 && colours[index] <= 0xff)) {
1019                         printf("PPPPPPPPPPPPPPPPPanic %d index [%d]\n",
1020                                colours[index], index);
1021                     }
1022                     assert(colours[index] >= 0 && colours[index] <= 0xff);
1023                 }
1024 
1025                 // We don't need to continue if the alpha channel is at the max
1026                 if (alphaChannel >= 0xff)
1027                     break;
1028 
1029             }                   // for (imageIndex =counterImageFiles-1; imageIndex >= 0; imageIndex--) {
1030 
1031             // Is it really necessary to check the values of the colours and alphachannel to make
1032             // sure they are not overflowing a byte?
1033 
1034             // Set the value of the pixel
1035             for (i = 0; i < 3; i++) {
1036                 assert(colours[i] <= 0xff && colours[i] >= 0);
1037                 *(resultBuffer + pixelOffset + i) = colours[i];
1038             }
1039 
1040             *(resultBuffer + pixelOffset + 3) = alphaChannel;
1041 
1042 
1043         }                       //(currentColumn < imageWidth)
1044 
1045     }                           //for currentLine < lines
1046 
1047 }
1048 
panoStitchBlendLayers16Bit(unsigned char ** imageDataBuffers,int counterImageFiles,unsigned char * resultBuffer,int lines,int imageWidth,int scanLineSize)1049 static void panoStitchBlendLayers16Bit(unsigned char **imageDataBuffers, int counterImageFiles,
1050                                 unsigned char *resultBuffer, int lines, int imageWidth,
1051                                 int scanLineSize)
1052 {
1053 
1054     int imageIndex = 0;
1055     unsigned long long colours[3];
1056     unsigned long long alphaChannel;
1057     unsigned int currentLine;
1058     unsigned int currentColumn;
1059     unsigned int rowOffset;
1060 
1061     uint16_t *u16ResultBuffer = (uint16_t *) resultBuffer;
1062     uint16_t **u16ImageDataBuffers = (uint16 **) imageDataBuffers;
1063 
1064     currentLine = 0;
1065 
1066 
1067     for (currentLine = 0; (int) currentLine < lines; currentLine++) {
1068 
1069         //  printf("Lines %d\n", lines);
1070         //  printf("Width %d\n", imageWidth);
1071         //  printf("length %d\n", scanLineSize);
1072 
1073 
1074         //printf("Currnet line %d\n", currentLine);
1075 
1076         // scanLineSize is in bytes, but we need the length in 16bit units
1077         rowOffset = (scanLineSize / 2) * currentLine;
1078 
1079         for (currentColumn = 0; (int) currentColumn < imageWidth; currentColumn++) {
1080 
1081             unsigned int pixelOffset;
1082             unsigned int i;
1083 
1084             //      printf("Currnet column %d\n", currentColumn);
1085 
1086             pixelOffset = rowOffset + currentColumn * 4;
1087 
1088             //      printf("Currnet offset %d\n", pixelOffset);
1089 
1090             // Initialize colours for this pixel
1091             alphaChannel = 0;
1092             for (i = 0; i < 3; i++)
1093                 colours[i] = 0;
1094 
1095 
1096             // Do alpha blending, from top to bottom. Bail out when alpha channel is equal to maximum
1097 
1098             for (imageIndex = counterImageFiles - 1; imageIndex >= 0;
1099                  imageIndex--) {
1100 
1101                 unsigned long long alphaContribution;
1102                 uint16_t *ptrPixel;
1103                 unsigned long long bottomAlpha;
1104                 unsigned int index;
1105 
1106 
1107                 // printf("Currnet image %d\n", imageIndex);
1108 
1109 
1110                 // The alpha blending algorithm is (for premultiplied values)
1111 
1112                 // C_result = C_above + C_below * (1 - alpha_above)
1113                 // A_result = Alpha_above + alpha_below * (1 - alpha_above)
1114 
1115                 // Find pixel in this layer
1116                 ptrPixel = u16ImageDataBuffers[imageIndex] + pixelOffset;
1117 
1118 
1119                 // printf("TO read pixel\n");
1120 
1121                 bottomAlpha = *(ptrPixel + 3);  // this should be the value of the mask for this particular pixel
1122 
1123                 //printf("After read pixel\n");
1124 
1125                 alphaContribution =
1126                     ((0xffff - alphaChannel) * bottomAlpha) / 0xffff;
1127 
1128                 // I don't really think this step is necessary, but due to innestability of the calculation
1129                 // alphaContribution it might overflow the byte valuex
1130 
1131                 if (alphaChannel + alphaContribution > 0xffff) {
1132                     alphaContribution = 0xffff - alphaChannel;
1133                 }
1134 
1135                 alphaChannel += alphaContribution;
1136 
1137                 // Makek sure the alpha channel is within range
1138                 assert(alphaChannel >= 0 && alphaChannel <= 0xffff);
1139 
1140                 // now do the colours
1141 
1142                 //printf("TO set pixel\n");
1143 
1144                 for (index = 0; index < 3; index++) {
1145                     colours[index] += (*(ptrPixel + index) * alphaContribution) / 0xffff;       //
1146                     if (!(colours[index] >= 0 && colours[index] <= 0xffff)) {
1147                         printf("PPPPPPPPPPPPPPPPPanic %lld index [%d]\n",
1148                                colours[index], index);
1149                     }
1150                     assert(colours[index] >= 0 && colours[index] <= 0xffff);
1151                 }
1152 
1153                 // We don't need to continue if the alpha channel is at the max
1154                 if (alphaChannel >= 0xffff)
1155                     break;
1156 
1157             }                   // for (imageIndex =counterImageFiles-1; imageIndex >= 0; imageIndex--) {
1158 
1159             // Is it really necessary to check the values of the colours and alphachannel to make
1160             // sure they are not overflowing a byte?
1161             //      printf("Done loop\n");
1162             // Set the value of the pixel
1163             for (i = 0; i < 3; i++) {
1164                 assert(colours[i] <= 0xffff && colours[i] >= 0);
1165                 *(u16ResultBuffer + pixelOffset + i) = (uint16_t)(colours[i]);
1166             }
1167             //      printf("Done loop 2\n");
1168             *(u16ResultBuffer + pixelOffset + 3) = (uint16_t)(alphaChannel);
1169 
1170 
1171         }                       //(currentColumn < imageWidth)
1172 
1173     }                           //for currentLine < lines
1174 
1175 }
1176 
1177 /*
1178  * TODO: BLend 8 and 16 versions into one
1179  * Blend all the images into one
1180  */
panoStitchBlendLayers(unsigned char ** imageDataBuffers,unsigned int counterImageFiles,unsigned char * resultBuffer,unsigned int linesToRead,int imageWidth,unsigned int bitsPerPixel,unsigned int scanLineSize)1181 void panoStitchBlendLayers(unsigned char **imageDataBuffers,
1182                            unsigned int counterImageFiles,
1183                            unsigned char *resultBuffer,
1184                            unsigned int linesToRead,
1185                            int imageWidth,
1186                            unsigned int bitsPerPixel,
1187                            unsigned int scanLineSize)
1188 {
1189 
1190     if (bitsPerPixel == 32) {
1191         panoStitchBlendLayers8Bit(imageDataBuffers, counterImageFiles, resultBuffer,
1192                         linesToRead, imageWidth, scanLineSize);
1193     }
1194     else if (bitsPerPixel == 64) {
1195         panoStitchBlendLayers16Bit(imageDataBuffers, counterImageFiles, resultBuffer,
1196                                    linesToRead, imageWidth, scanLineSize);
1197     }
1198 }
1199