1 /* Panorama_Tools       -       Generate, Edit and Convert Panoramic Images
2    Copyright (C) 1998,1999 - Helmut Dersch  der@fh-furtwangen.de
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this software; see the file COPYING.  If not, a copy
16    can be downloaded from http://www.gnu.org/licenses/gpl.html, or
17    obtained by writing to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19 
20 /*------------------------------------------------------------*/
21 
22 // Functions to read tiff format
23 
24 
25 #include <stdio.h>
26 #include <assert.h>
27 
28 #include "panorama.h"
29 #include "filter.h"
30 
31 #include "tiffio.h"
32 
33 #include "ZComb.h"
34 
35 
36 #include "pttiff.h"
37 #include "metadata.h"
38 #include "ptstitch.h"
39 
40 
41 int readplanarTIFF(Image * im, TIFF * tif);
42 void RGBAtoARGB(uint8_t * buf, int width, int bitsPerPixel);
43 void ARGBtoRGBA(uint8_t * buf, int width, int bitsPerPixel);
44 int readtif(Image * im, TIFF * tif);
45 
46 
readplanarTIFF(Image * im,TIFF * tif)47 int readplanarTIFF(Image * im, TIFF * tif)
48 {
49     uint8_t *buf;
50     int32_t y;
51     short SamplesPerPixel;
52 
53     TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplesPerPixel);
54     if (SamplesPerPixel > 4)
55         return -1;
56     if (SamplesPerPixel == 3)
57     {
58         im->bitsPerPixel = im->bitsPerPixel * 3 / 4;
59         im->bytesPerLine = im->bytesPerLine * 3 / 4;
60     }
61 
62     buf = (uint8_t *) malloc((size_t) TIFFScanlineSize(tif));
63     if (buf == NULL)
64     {
65         PrintError("Not enough memory");
66         return -1;
67     }
68 
69     for (y = 0; y < im->height; y++)
70     {
71         TIFFReadScanline(tif, buf, (uint32) y, 0);
72         RGBAtoARGB(buf, im->width, im->bitsPerPixel);
73         memcpy(*(im->data) + y * im->bytesPerLine, buf,
74                (size_t) (im->bytesPerLine));
75     }
76     free(buf);
77     ThreeToFourBPP(im);
78     return 0;
79 
80 }
81 
82 
83 
84 // image is allocated, but not image data
85 
readtif(Image * im,TIFF * tif)86 int readtif(Image * im, TIFF * tif)
87 {
88     short BitsPerSample, tPhotoMetric, config;
89     uint32_t w, h;
90     unsigned long **hdl_raster;
91 
92     if (tif == NULL || im == NULL)
93         return -1;
94 
95     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
96     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
97     TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
98     TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &tPhotoMetric);
99     TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
100 
101     SetImageDefaults(im);
102     im->width = w;
103     im->height = h;
104     im->bitsPerPixel = 32 * BitsPerSample / 8;
105     im->bytesPerLine = im->width * im->bitsPerPixel / 8;
106     im->dataSize = im->bytesPerLine * im->height;
107 
108 
109     hdl_raster = (unsigned long **) mymalloc((size_t) im->dataSize);
110     if (hdl_raster == NULL)
111     {
112         PrintError("Not enough memory");
113         return -1;
114     }
115 
116     im->data = (uint8_t **) hdl_raster;
117 
118     if (tPhotoMetric == PHOTOMETRIC_RGB && config == PLANARCONFIG_CONTIG)
119     {
120         return readplanarTIFF(im, tif);
121     }
122 
123     if (TIFFReadRGBAImage
124         (tif, (uint32) w, (uint32) h, (uint32 *) * (im->data), 0))
125     {
126         // Convert agbr to argb; flip image vertically
127         unsigned char *cline, *ct, *cb;
128         int h2 = im->height / 2, y;
129         // Only do the conversion once
130         size_t localBytesPerLine = im->bytesPerLine;
131 
132         cline = (unsigned char *) malloc(localBytesPerLine);
133         if (cline == NULL)
134         {
135             PrintError("Not enough memory");
136             return -1;
137         }
138 
139         ct = *im->data;
140         cb = *im->data + (im->height - 1) * im->bytesPerLine;
141 
142         for (y = 0; y < h2;
143              y++, ct += im->bytesPerLine, cb -= im->bytesPerLine)
144         {
145             RGBAtoARGB(ct, im->width, im->bitsPerPixel);
146             RGBAtoARGB(cb, im->width, im->bitsPerPixel);
147             memcpy(cline, ct, localBytesPerLine);
148             memcpy(ct, cb, localBytesPerLine);
149             memcpy(cb, cline, localBytesPerLine);
150         }
151         if (im->height != 2 * h2)
152         {                       // odd number of scanlines
153             RGBAtoARGB(*im->data + y * im->bytesPerLine, im->width,
154                        im->bitsPerPixel);
155         }
156         if (cline)
157             free(cline);
158     }
159     else
160     {
161         PrintError("Could not read tiff-data");
162         return -1;
163     }
164     return 0;
165 }
166 
167 /**
168  * Populates the CropInfo struct with data about cropping of
169  * the TIFF file specified by filename
170  */
getCropInformationFromTiff(TIFF * tif,CropInfo * c)171 void getCropInformationFromTiff(TIFF * tif, CropInfo * c)
172 {
173     float x_position, x_resolution, y_position, y_resolution;
174 
175     //these are the actual, physical dimensions of the TIFF file
176     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &(c->cropped_width));
177     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &(c->cropped_height));
178 
179     //If nothing is stored in these tags, then this must be an "uncropped" TIFF
180     //file, in which case, the "full size" width/height is the same as the
181     //"cropped" width and height
182     if (TIFFGetField(tif, TIFFTAG_PIXAR_IMAGEFULLWIDTH, &(c->full_width)) ==
183         0)
184         (c->full_width = c->cropped_width);
185     if (TIFFGetField(tif, TIFFTAG_PIXAR_IMAGEFULLLENGTH, &(c->full_height)) ==
186         0)
187         (c->full_height = c->cropped_height);
188 
189     if (TIFFGetField(tif, TIFFTAG_XPOSITION, &x_position) == 0)
190         x_position = 0;
191     if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &x_resolution) == 0)
192         x_resolution = 0;
193     if (TIFFGetField(tif, TIFFTAG_YPOSITION, &y_position) == 0)
194         y_position = 0;
195     if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &y_resolution) == 0)
196         y_resolution = 0;
197 
198     //offset in pixels of "cropped" image from top left corner of
199     //full image (rounded to nearest integer)
200     c->x_offset = (uint32) ((x_position * x_resolution) + 0.49);
201     c->y_offset = (uint32) ((y_position * y_resolution) + 0.49);
202 
203     //printf("%s: %dx%d  @ %d,%d", filename, c->cropped_width, c->cropped_height, c->x_offset, c->y_offset);
204 }
205 
206 
setCropInformationInTiff(TIFF * tiffFile,CropInfo * crop_info)207 void setCropInformationInTiff(TIFF * tiffFile, CropInfo * crop_info)
208 {
209     char *errMsg = "Could not set TIFF tag";
210     float pixels_per_resolution_unit = 150.0;
211 
212     //If crop_info==NULL then this isn't a "cropped TIFF", so don't include
213     //cropped TIFF tags
214     if (crop_info == NULL)
215         return;
216 
217     //The X offset in ResolutionUnits of the left side of the image, with
218     //respect to the left side of the page.
219     if (TIFFSetField
220         (tiffFile, TIFFTAG_XPOSITION,
221          (float) crop_info->x_offset / pixels_per_resolution_unit) == 0)
222         dieWithError(errMsg);
223     //The Y offset in ResolutionUnits of the top of the image, with
224     //respect to the top of the page.
225     if (TIFFSetField
226         (tiffFile, TIFFTAG_YPOSITION,
227          (float) crop_info->y_offset / pixels_per_resolution_unit) == 0)
228         dieWithError(errMsg);
229 
230     //The number of pixels per ResolutionUnit in the ImageWidth
231     if (TIFFSetField
232         (tiffFile, TIFFTAG_XRESOLUTION,
233          (float) pixels_per_resolution_unit) == 0)
234         dieWithError(errMsg);
235     //The number of pixels per ResolutionUnit in the ImageLength (height)
236     if (TIFFSetField
237         (tiffFile, TIFFTAG_YRESOLUTION,
238          (float) pixels_per_resolution_unit) == 0)
239         dieWithError(errMsg);
240 
241     //The size of the picture represented by an image.  Note: 2 = Inches.  This
242     //is required so that the computation of pixel offset using XPOSITION/YPOSITION and
243     //XRESOLUTION/YRESOLUTION is valid (See tag description for XPOSITION/YPOSITION).
244     if (TIFFSetField(tiffFile, TIFFTAG_RESOLUTIONUNIT, (uint16_t) 2) == 0)
245         dieWithError(errMsg);
246 
247     // TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH
248     // are set when an image has been cropped out of a larger image.
249     // They reflect the size of the original uncropped image.
250     // The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used
251     // to determine the position of the smaller image in the larger one.
252     if (TIFFSetField
253         (tiffFile, TIFFTAG_PIXAR_IMAGEFULLWIDTH, crop_info->full_width) == 0)
254         dieWithError(errMsg);
255     if (TIFFSetField
256         (tiffFile, TIFFTAG_PIXAR_IMAGEFULLLENGTH,
257          crop_info->full_height) == 0)
258         dieWithError(errMsg);
259 }
260 
261 
262 
readTIFF(Image * im,fullPath * sfile)263 int readTIFF(Image * im, fullPath * sfile)
264 {
265     char filename[512];
266     TIFF *tif;
267     int result = 0;
268 
269 
270 
271 #ifdef __Mac__
272     unsigned char the_pcUnixFilePath[512];      //added by Kekus Digital
273     Str255 the_cString;
274     Boolean the_bReturnValue;
275     CFStringRef the_FilePath;
276     CFURLRef the_Url;           //till here
277 #endif
278 
279     if (FullPathtoString(sfile, filename))
280     {
281         PrintError("Could not get filename");
282         return -1;
283     }
284 
285 #ifdef __Mac__
286     CopyCStringToPascal(filename, the_cString); //Added by Kekus Digital
287     the_FilePath =
288         CFStringCreateWithPascalString(kCFAllocatorDefault, the_cString,
289                                        kCFStringEncodingUTF8);
290     the_Url =
291         CFURLCreateWithFileSystemPath(kCFAllocatorDefault, the_FilePath,
292                                       kCFURLHFSPathStyle, false);
293     the_bReturnValue =
294         CFURLGetFileSystemRepresentation(the_Url, true, the_pcUnixFilePath,
295                                          512);
296 
297     strcpy(filename, the_pcUnixFilePath);       //till here
298 #endif
299 
300     tif = TIFFOpen(filename, "r");
301 
302     if (!tif)
303     {
304         PrintError("Could not open tiff-file");
305         return -1;
306     }
307     result = readtif(im, tif);
308 
309     //Store name of TIFF file
310     strncpy(im->name, filename, 255);
311 
312     getCropInformationFromTiff(tif, &(im->cropInformation));
313 
314     TIFFClose(tif);
315     return result;
316 }
317 
writeCroppedTIFF(Image * im,fullPath * sfile,CropInfo * crop_info)318 int writeCroppedTIFF(Image * im, fullPath * sfile, CropInfo * crop_info)
319 {
320     char string[512];
321     TIFF *tif;
322     uint8_t *buf;
323     unsigned int y;
324     size_t bufsize;
325 
326 #ifdef __Mac__
327     unsigned char the_pcUnixFilePath[512];      //added by Kekus Digital
328     Str255 the_cString;
329     Boolean the_bReturnValue;
330     CFStringRef the_FilePath;
331     CFURLRef the_Url;           //till here
332 #endif
333 
334     if (FullPathtoString(sfile, string))
335     {
336         PrintError("Could not get filename");
337         return -1;
338     }
339 
340 #ifdef __Mac__
341     CopyCStringToPascal(string, the_cString);   //added by Kekus Digital
342     the_FilePath =
343         CFStringCreateWithPascalString(kCFAllocatorDefault, the_cString,
344                                        kCFStringEncodingUTF8);
345     the_Url =
346         CFURLCreateWithFileSystemPath(kCFAllocatorDefault, the_FilePath,
347                                       kCFURLHFSPathStyle, false);
348     the_bReturnValue =
349         CFURLGetFileSystemRepresentation(the_Url, true, the_pcUnixFilePath,
350                                          512);
351 
352     strcpy(string, the_pcUnixFilePath); //till here
353 #endif
354 
355     tif = TIFFOpen(string, "w");
356     if (!tif)
357     {
358         PrintError("Could not create TIFF-file");
359         return -1;
360     }
361 
362     // Rik's mask-from-focus hacking
363     if (ZCombSeeImage(im, string))
364     {
365         PrintError("failed ZCombSeeImage");
366     }
367     // end Rik's mask-from-focus hacking (for the moment...)
368 
369     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, im->width);
370     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, im->height);
371     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
372     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
373 
374     // Thomas Rauscher, Add for 32 bit (float) support
375     //
376     //      TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, im->bitsPerPixel < 48 ? 8 : 16 );
377     //  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, im->bitsPerPixel == 24 || im->bitsPerPixel == 48 ? 3 : 4);
378 
379     switch (im->bitsPerPixel)
380     {
381     case 24:
382         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
383         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
384         break;
385     case 32:
386         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
387         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
388         break;
389     case 48:
390         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
391         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
392         break;
393     case 64:
394         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
395         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
396         break;
397     case 96:
398         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
399         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
400         TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
401         break;
402     case 128:
403         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
404         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
405         TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
406         break;
407     }
408     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
409 
410 
411     //"1" indicates that The 0th row represents the visual top of the image,
412     //and the 0th column represents the visual left-hand side.
413     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
414 
415 
416     //TIFFTAG_ROWSPERSTRIP indicates the number of rows per "strip" of TIFF data.  The original PTStitcher
417     //set this value to the panorama height whch meant that the entire image
418     //was contained in one strip.  This is not only explicitly discouraged by the
419     //TIFF specification ("Use of a single strip is not recommended. Choose RowsPerStrip
420     //such that each strip is about 8K bytes, even if the data is not compressed,
421     //since it makes buffering simpler for readers. The 8K value is fairly
422     //arbitrary, but seems to work well."), but is also makes it impossible
423     //for programs to read the output from Pano Tools to perform random
424     //access on the data which leads to unnecessarily inefficient approaches to
425     //manipulating these images).
426     //
427     //In practice, most panoramas generated these days (Feb 2006) contain more than
428     //2000 pixels per row (equal to 8KB mentioned above), so it is easiest to
429     //hard-code this value to one, which also enables complete random access to
430     //the output files by subsequent blending/processing applications
431 
432 
433     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
434 
435     if (crop_info != NULL)
436         setCropInformationInTiff(tif, crop_info);
437 
438     bufsize = TIFFScanlineSize(tif);
439     if ((uint32_t)bufsize < im->bytesPerLine)
440         bufsize = im->bytesPerLine;
441     buf = (uint8_t *) malloc(bufsize);
442     if (buf == NULL)
443     {
444         PrintError("Not enough memory");
445         return -1;
446     }
447 
448     for (y = 0; (uint32_t) y < im->height; y++)
449     {
450         memcpy(buf, *(im->data) + y * im->bytesPerLine,
451                (size_t) im->bytesPerLine);
452         ARGBtoRGBA(buf, im->width, im->bitsPerPixel);
453         TIFFWriteScanline(tif, buf, y, 1);
454     }
455     TIFFClose(tif);
456     free(buf);
457     return 0;
458 
459 }
460 
461 
writeTIFF(Image * im,fullPath * sfile)462 int writeTIFF(Image * im, fullPath * sfile)
463 {
464     return writeCroppedTIFF(im, sfile, &(im->cropInformation));
465 }
466 
467 
468 
RGBAtoARGB(uint8_t * buf,int width,int bitsPerPixel)469 void RGBAtoARGB(uint8_t * buf, int width, int bitsPerPixel)
470 {
471     int x;
472     switch (bitsPerPixel)
473     {
474     case 32:
475         {
476             uint8_t pix;
477             for (x = 0; x < width; x++, buf += 4)
478             {
479                 pix = buf[3];
480                 buf[3] = buf[2];
481                 buf[2] = buf[1];
482                 buf[1] = buf[0];
483                 buf[0] = pix;
484             }
485         }
486         break;
487     case 64:
488         {
489             uint16_t *bufs = (uint16_t *) buf, pix;
490             for (x = 0; x < width; x++, bufs += 4)
491             {
492                 pix = bufs[3];
493                 bufs[3] = bufs[2];
494                 bufs[2] = bufs[1];
495                 bufs[1] = bufs[0];
496                 bufs[0] = pix;
497             }
498         }
499         break;
500     case 128:
501         {
502             float *bufs = (float *) buf, pix;
503             for (x = 0; x < width; x++, bufs += 4)
504             {
505                 pix = bufs[3];
506                 bufs[3] = bufs[2];
507                 bufs[2] = bufs[1];
508                 bufs[1] = bufs[0];
509                 bufs[0] = pix;
510             }
511         }
512         break;
513     }
514 }
515 
ARGBtoRGBA(uint8_t * buf,int width,int bitsPerPixel)516 void ARGBtoRGBA(uint8_t * buf, int width, int bitsPerPixel)
517 {
518     int x;
519     switch (bitsPerPixel)
520     {
521     case 32:
522         {
523             uint8_t pix;
524             for (x = 0; x < width; x++, buf += 4)
525             {
526                 pix = buf[0];
527                 buf[0] = buf[1];
528                 buf[1] = buf[2];
529                 buf[2] = buf[3];
530                 buf[3] = pix;
531             }
532         }
533         break;
534     case 64:
535         {
536             uint16_t *bufs = (uint16_t *) buf, pix;
537             for (x = 0; x < width; x++, bufs += 4)
538             {
539                 pix = bufs[0];
540                 bufs[0] = bufs[1];
541                 bufs[1] = bufs[2];
542                 bufs[2] = bufs[3];
543                 bufs[3] = pix;
544             }
545         }
546         break;
547     case 128:
548         {
549             float *bufs = (float *) buf, pix;
550             for (x = 0; x < width; x++, bufs += 4)
551             {
552                 pix = bufs[0];
553                 bufs[0] = bufs[1];
554                 bufs[1] = bufs[2];
555                 bufs[2] = bufs[3];
556                 bufs[3] = pix;
557             }
558         }
559         break;
560     }
561 }
562 
563 
564 //////////////////////////////////////////////////////////////////////
565 // NEW tiff routines
566 //////////////////////////////////////////////////////////////////////
567 
568 
569 
panoTiffGetCropInformation(pano_Tiff * file)570 int panoTiffGetCropInformation(pano_Tiff * file)
571 {
572 /*
573   Read the crop information of a TIFF file
574 
575   Cropped TIFFs have the following properties:
576 
577   * Their image width and length is the size of the cropped region
578   * The full size of the image is in PIXAR_IMAGEFULLWIDTH and PIXAR_IMAGEFULLHEIGHT
579   * If these 2 records do not exist then assume it is uncropped
580 
581 
582  */
583 
584     float x_position, x_resolution, y_position, y_resolution;
585     pano_CropInfo *c;
586 
587     assert(file != NULL);
588     assert(file->tiff != NULL);
589 
590     c = &(file->metadata.cropInfo);
591     c->croppedWidth = 0;
592 
593     file->metadata.isCropped = FALSE;
594 
595     if (TIFFGetField(file->tiff, TIFFTAG_IMAGEWIDTH, &(c->croppedWidth)) == 0
596         || TIFFGetField(file->tiff, TIFFTAG_IMAGELENGTH,
597                         &(c->croppedHeight)) == 0) {
598         PrintError("Error reading file size from TIFF");
599         return FALSE;
600     }
601 
602 
603 
604     if (TIFFGetField(file->tiff, TIFFTAG_XPOSITION, &x_position) != 0) {
605 	// This means this is a cropped image
606 
607 	file->metadata.isCropped = TRUE;
608 
609 
610 
611 	// we should get a x resoltion, y position and yresolution, if not,
612 	// we will issue an error, as it can be cropped on just "one dimension"
613 
614 	if (TIFFGetField(file->tiff, TIFFTAG_XRESOLUTION, &x_resolution) == 0) {
615 	    PrintError("Cropped Image contains XPosition but not XResoulion tag. "
616 		       "Report to developers if you think this is a bug");
617 	    return FALSE;
618 	}
619 	if (TIFFGetField(file->tiff, TIFFTAG_YRESOLUTION, &y_resolution) == 0) {
620 	    PrintError("Cropped image contains XPosition and YPosition, but it does not contain Y Resolution. "
621 		       "Report to developers you think this is a bug");
622 	    return FALSE;
623 	}
624 
625 	if (TIFFGetField(file->tiff, TIFFTAG_YPOSITION, &y_position) == 0) {
626 	    PrintError("Cropped image contains XPosition but not YPosition. "
627 		       "Report to developers you think this is a bug");
628 	    return FALSE;
629 	}
630 
631 	//offset in pixels of "cropped" image from top left corner of
632 	//full image (rounded to nearest integer)
633 	// The position of the file is given in "real" dimensions, we have to rescale them
634 
635 	c->xOffset = (uint32) ((x_position * x_resolution) + 0.49);
636 	c->yOffset = (uint32) ((y_position * y_resolution) + 0.49);
637 
638 	// One problem is that some images do not contain FULL size. if they don't have
639 	// then assume it
640 
641 	if (TIFFGetField(file->tiff, TIFFTAG_PIXAR_IMAGEFULLWIDTH, &(c->fullWidth)) == 0)
642 	    c->fullWidth = c->xOffset  + c->croppedWidth;
643 
644 	if (TIFFGetField(file->tiff, TIFFTAG_PIXAR_IMAGEFULLLENGTH, &(c->fullHeight)) == 0)
645 	    c->fullHeight = c->yOffset + c->croppedHeight;
646     } else {
647 
648 	// Not cropped, then initilize fields accordingly
649 
650         x_position = 0;
651         x_resolution = 0;
652         y_position = 0;
653         y_resolution = 0;
654 	c->xOffset = 0;
655 	c->yOffset = 0;
656         c->fullHeight = c->croppedHeight;
657 	c->fullWidth = c->croppedWidth;
658 
659     }
660 
661 
662 #if 0
663     // used for debugging
664     printf("%dx%d  @ %d,%d", c->croppedWidth, c->croppedHeight, c->xOffset, c->yOffset);
665 
666     printf("get 3 width %d length %d\n", (int) c->croppedWidth,
667     (int) c->croppedHeight);
668     printf("get 3 full %d length %d\n", (int) c->fullWidth,
669                (int) c->fullHeight);
670     printf("cropped %d\n", (int) file->metadata.isCropped);
671 #endif
672 
673     return TRUE;
674 
675 }
676 
677 // checks if an "absolute" row is inside the ROI
panoTiffRowInsideROI(pano_Tiff * image,int row)678 int panoTiffRowInsideROI(pano_Tiff * image, int row)
679 {
680     // We are in the ROI if the row is bigger than the yoffset
681     // and the row is less or equal to the offset + height
682 
683 
684     assert(image != NULL);
685     assert(row >= 0);
686 
687     return panoROIRowInside(&(image->metadata.cropInfo), row);
688 
689 
690 }
691 
692 
693 
panoTiffIsCropped(pano_Tiff * file)694 int panoTiffIsCropped(pano_Tiff * file)
695 {
696     return file->metadata.isCropped;
697 }
698 
panoTiffBytesPerLine(pano_Tiff * file)699 int panoTiffBytesPerLine(pano_Tiff * file)
700 {
701     return file->metadata.bytesPerLine;
702 }
703 
panoTiffSamplesPerPixel(pano_Tiff * file)704 int panoTiffSamplesPerPixel(pano_Tiff * file)
705 {
706     return file->metadata.samplesPerPixel;
707 }
708 
709 
710 
panoTiffBitsPerPixel(pano_Tiff * file)711 int panoTiffBitsPerPixel(pano_Tiff * file)
712 {
713     return file->metadata.bitsPerPixel;
714 }
715 
panoTiffBytesPerPixel(pano_Tiff * file)716 int panoTiffBytesPerPixel(pano_Tiff * file)
717 {
718     return file->metadata.bytesPerPixel;
719 }
720 
panoTiffImageHeight(pano_Tiff * file)721 int panoTiffImageHeight(pano_Tiff * file)
722 {
723     return file->metadata.imageHeight;
724 }
725 
panoTiffImageWidth(pano_Tiff * file)726 int panoTiffImageWidth(pano_Tiff * file)
727 {
728     return file->metadata.imageWidth;
729 }
730 
panoTiffXOffset(pano_Tiff * file)731 int panoTiffXOffset(pano_Tiff * file)
732 {
733     return file->metadata.cropInfo.xOffset;
734 }
735 
panoTiffYOffset(pano_Tiff * file)736 int panoTiffYOffset(pano_Tiff * file)
737 {
738     return file->metadata.cropInfo.yOffset;
739 }
740 
panoTiffImageMetadata(pano_Tiff * file)741 pano_ImageMetadata *panoTiffImageMetadata(pano_Tiff * file)
742 {
743     return &file->metadata;
744 }
745 
panoTiffFullImageWidth(pano_Tiff * file)746 int panoTiffFullImageWidth(pano_Tiff * file)
747 {
748     return file->metadata.cropInfo.fullWidth;
749 }
750 
panoTiffFullImageHeight(pano_Tiff * file)751 int panoTiffFullImageHeight(pano_Tiff * file)
752 {
753     return file->metadata.cropInfo.fullHeight;
754 }
755 
756 
757 
758 
759 
760 // Read an "absolute" row relative to the cropped area of the TIFF
panoTiffReadScanLineFullSize(pano_Tiff * file,void * buffer,int row)761 int panoTiffReadScanLineFullSize(pano_Tiff * file, void *buffer, int row)
762 {
763     // Reads a scan line only if inside ROI, otherwise it only "zeroes" data
764     int bytesPerLine;
765     int bytesPerPixel;
766 
767     assert(file != NULL);
768 
769     if (row > panoTiffFullImageHeight(file)) {
770         PrintError("Trying to read row %d beyond end of file", row);
771         return FALSE;
772     }
773     bytesPerPixel = panoTiffBytesPerPixel(file);
774 
775     bytesPerLine = panoTiffFullImageWidth(file) * bytesPerPixel;
776 
777 	//printf("Bytes per line %d %d\n", bytesPerLine, panoTiffFullImageWidth(file));
778 
779     assert(panoTiffIsCropped(file) ||
780            panoTiffFullImageWidth(file) == panoTiffImageWidth(file));
781 
782 
783     bzero(buffer, bytesPerLine);
784 
785     if (panoTiffRowInsideROI(file, row)) {
786         if (TIFFReadScanline
787             (file->tiff, (uint8_t *)(buffer) + panoTiffXOffset(file) * bytesPerPixel,
788              row - panoTiffYOffset(file), 0) != 1) {
789             PrintError("Error reading row %d in tiff file", row);
790             return FALSE;
791         }
792     }
793     return TRUE;
794 }
795 
panoTiffWriteScanLineFullSize(pano_Tiff * file,void * buffer,int row)796 int panoTiffWriteScanLineFullSize(pano_Tiff * file, void *buffer, int row)
797 {
798     // Reads a scan line only if inside ROI, otherwise it only "zeroes" data
799     int bytesPerPixel;
800 
801     assert(file != NULL);
802 
803     if (row > panoTiffFullImageHeight(file)) {
804         PrintError("Trying to read row %d beyond end of file", row);
805         return FALSE;
806     }
807     bytesPerPixel = panoTiffBytesPerPixel(file);
808 
809     assert(panoTiffIsCropped(file) ||
810            panoTiffFullImageWidth(file) == panoTiffImageWidth(file));
811 
812 
813     if (panoTiffRowInsideROI(file, row)) {
814         if (TIFFWriteScanline
815             (file->tiff, (uint8_t *)(buffer) + panoTiffXOffset(file) * bytesPerPixel,
816              row - panoTiffYOffset(file), 0) != 1) {
817             PrintError("Error writing row %d in tiff file", row);
818             return FALSE;
819         }
820     }
821     return TRUE;
822 }
823 
824 
825 
panoTiffSetCropInformation(pano_Tiff * file)826 int panoTiffSetCropInformation(pano_Tiff * file)
827 {
828     pano_CropInfo *cropInfo;
829     pano_ImageMetadata *metadata;
830     TIFF *tiffFile;
831     int result;
832 
833     assert(file != NULL);
834 
835     tiffFile = file->tiff;
836     assert(tiffFile != NULL);
837     metadata = &(file->metadata);
838     cropInfo = &(metadata->cropInfo);
839 
840 
841     if (!panoTiffIsCropped(file))
842         return TRUE;
843 	//MRDL: Photoshop sometimes writes out files with a TIFFTAG_XRESOLUTION of 0.
844 	//If input files are from Photoshop, this values propogates from input
845 	//file to metadata, and can mess up setting of XPOSITION here...
846 	if (metadata->xPixelsPerResolution == 0 || metadata->yPixelsPerResolution == 0)
847 	{
848 		metadata->xPixelsPerResolution = PANO_DEFAULT_PIXELS_PER_RESOLUTION;
849 		metadata->yPixelsPerResolution = PANO_DEFAULT_PIXELS_PER_RESOLUTION;
850 	}
851 
852     //The X offset in ResolutionUnits of the left side of the image, with
853     //respect to the left side of the page.
854     //The Y offset in ResolutionUnits of the top of the image, with
855     //respect to the top of the page.
856 
857     result =
858         TIFFSetField(tiffFile, TIFFTAG_XPOSITION,
859                      (float) cropInfo->xOffset /
860                      metadata->xPixelsPerResolution)
861         && TIFFSetField(tiffFile, TIFFTAG_YPOSITION,
862                         (float) cropInfo->yOffset /
863                         metadata->yPixelsPerResolution);
864 
865     //The number of pixels per ResolutionUnit in the ImageWidth
866     //The number of pixels per ResolutionUnit in the ImageLength (height)
867     result = result &&
868         TIFFSetField(tiffFile, TIFFTAG_XRESOLUTION,
869                      metadata->xPixelsPerResolution)
870         && TIFFSetField(tiffFile, TIFFTAG_YRESOLUTION,
871                         metadata->yPixelsPerResolution);
872 
873     //The size of the picture represented by an image.  This
874     //is required so that the computation of pixel offset using XPOSITION/YPOSITION and
875     //XRESOLUTION/YRESOLUTION is valid (See tag description for XPOSITION/YPOSITION).
876     result = result &&
877         TIFFSetField(tiffFile, TIFFTAG_RESOLUTIONUNIT,
878                      metadata->resolutionUnits);
879 
880     // TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH
881     // are set when an image has been cropped out of a larger image.
882     // They reflect the size of the original uncropped image.
883     // The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used
884     // to determine the position of the smaller image in the larger one.
885     result = result &&
886         TIFFSetField(tiffFile, TIFFTAG_PIXAR_IMAGEFULLWIDTH,
887                      cropInfo->fullWidth)
888         && TIFFSetField(tiffFile, TIFFTAG_PIXAR_IMAGEFULLLENGTH,
889                         cropInfo->fullHeight);
890     if (!result) {
891         PrintError("Unable to set metadata of output tiff file");
892         return FALSE;
893     }
894     return result;
895 }
896 
panoTiffGetString(pano_Tiff * tiffFile,ttag_t tiffTag)897 char *panoTiffGetString(pano_Tiff *tiffFile, ttag_t tiffTag)
898 {
899     char *temp;
900     char *returnValue;
901     if (TIFFGetField(tiffFile->tiff, tiffTag, &temp) == 0) {
902     // If the tag does not exist just return
903         return NULL;
904     }
905     else {
906     // Allocate its memory
907     returnValue = calloc(strlen(temp) + 1, 1);
908 
909     if (returnValue == NULL)
910         return NULL;
911     // copy to the new location and return
912     strcpy(returnValue, temp);
913     return returnValue;
914     }
915 }
916 
panoTiffGetImageProperties(pano_Tiff * tiff)917 int panoTiffGetImageProperties(pano_Tiff * tiff)
918 {
919 /*
920   Retrieve the properties of the image that we need to keep
921  */
922 
923 
924     TIFF *tiffFile;
925     pano_ImageMetadata *metadata;
926     int result;
927     void *ptr;
928 
929     assert(tiff != NULL);
930 
931     tiffFile = tiff->tiff;
932 
933     metadata = &tiff->metadata;
934 
935     assert(tiffFile != NULL);
936 
937     //printf("get\n");
938 
939     if (!panoTiffGetCropInformation(tiff)) {
940         goto error;
941     }
942 
943 
944     // These are tags that are expected to be present
945 
946     result = TIFFGetField(tiffFile, TIFFTAG_IMAGEWIDTH, &metadata->imageWidth)
947         && TIFFGetField(tiffFile, TIFFTAG_IMAGELENGTH, &metadata->imageHeight)
948         && TIFFGetField(tiffFile, TIFFTAG_BITSPERSAMPLE,
949                         &metadata->bitsPerSample)
950         && TIFFGetField(tiffFile, TIFFTAG_SAMPLESPERPIXEL,
951                         &metadata->samplesPerPixel)
952         && TIFFGetField(tiffFile, TIFFTAG_COMPRESSION,
953                         &metadata->compression.type)
954         && TIFFGetField(tiffFile, TIFFTAG_ROWSPERSTRIP,
955                         &metadata->rowsPerStrip);
956 
957 
958     if (!result)
959         goto error;
960 
961     if (metadata->compression.type == COMPRESSION_LZW) {
962 
963 	// set default compression predictor
964 	metadata->compression.predictor = 2; //horizontal differencing
965 
966 	// unleess it comes in the file
967 	TIFFGetField(tiffFile, TIFFTAG_PREDICTOR,
968 		     &(metadata->compression.predictor));
969     }
970 
971     metadata->bytesPerLine = TIFFScanlineSize(tiffFile);
972     if (metadata->bytesPerLine <= 0) {
973         PrintError("File did not include proper bytes per line information.");
974         return 0;
975     }
976 
977     // These are optional tags
978 
979 
980 
981     if (TIFFGetField(tiffFile, TIFFTAG_ICCPROFILE, &(metadata->iccProfile.size),
982              &ptr)) {
983 
984         if ((metadata->iccProfile.data = calloc(metadata->iccProfile.size, 1)) == NULL) {
985             PrintError("Not enough memory");
986             return 0;
987         }
988         memcpy(metadata->iccProfile.data, ptr, metadata->iccProfile.size);
989     }
990 
991     tiff->metadata.copyright = panoTiffGetString(tiff, TIFFTAG_COPYRIGHT);
992     tiff->metadata.datetime = panoTiffGetString(tiff, TIFFTAG_DATETIME);
993     tiff->metadata.imageDescription = panoTiffGetString(tiff, TIFFTAG_IMAGEDESCRIPTION);
994     tiff->metadata.artist = panoTiffGetString(tiff, TIFFTAG_ARTIST);
995 
996     TIFFGetField(tiffFile, TIFFTAG_PAGENUMBER, &metadata->imageNumber, &metadata->imageTotalNumber);
997 
998     //printf("...........................REad and allocate ICC Profile %d %x\n",
999     //(int)(metadata->iccProfile.size), (int)(metadata->iccProfile.data));
1000 
1001     if (TIFFGetField
1002         (tiffFile, TIFFTAG_RESOLUTIONUNIT, &(metadata->resolutionUnits)) == 0)
1003         metadata->resolutionUnits = PANO_DEFAULT_TIFF_RESOLUTION_UNITS;
1004 
1005     if (TIFFGetField
1006         (tiffFile, TIFFTAG_XRESOLUTION,
1007          &(metadata->xPixelsPerResolution)) == 0)
1008         metadata->xPixelsPerResolution =
1009             PANO_DEFAULT_PIXELS_PER_RESOLUTION;
1010 
1011     if (TIFFGetField
1012         (tiffFile, TIFFTAG_YRESOLUTION,
1013          &(metadata->yPixelsPerResolution)) == 0)
1014         metadata->yPixelsPerResolution =
1015             PANO_DEFAULT_PIXELS_PER_RESOLUTION;
1016 
1017     // Compute rest of the fields
1018 
1019     // let us truly hope the size of a byte never changes :)
1020     metadata->bytesPerPixel =
1021         (metadata->samplesPerPixel * metadata->bitsPerSample) / 8;
1022     metadata->bitsPerPixel = metadata->bytesPerPixel * 8;
1023 
1024     //printf("get2 bits per sample %d\n", metadata->bitsPerSample);
1025     //    printf("get2 bits per pixel  %d\n", metadata->bitsPerPixel);
1026     //printf("get2 bytes per pixel %d\n", metadata->bytesPerPixel);
1027 
1028     return 1;
1029 
1030   error:
1031     PrintError("Error retrieving metadata from TIFF file");
1032     return 0;
1033 
1034 }
1035 
panoTiffSetImageProperties(pano_Tiff * file)1036 int panoTiffSetImageProperties(pano_Tiff * file)
1037 {
1038     int returnValue = 1;
1039     TIFF *tiffFile;
1040     pano_ImageMetadata *metadata;
1041 
1042     assert(file != NULL);
1043 
1044     tiffFile = file->tiff;
1045     assert(tiffFile != NULL);
1046 
1047     metadata = &(file->metadata);
1048 
1049     assert(metadata != NULL);
1050 
1051     // Each of the invocations below returns 1 if ok, 0 if error.
1052 
1053     //printf("samples per pixel %d\n", (int) metadata->samplesPerPixel);
1054     //printf("samples width %d\n", (int) metadata->imageWidth);
1055     //printf("compression %d\n", (int) metadata->compression.type);
1056     returnValue =
1057         TIFFSetField(tiffFile, TIFFTAG_IMAGEWIDTH, metadata->imageWidth)
1058         && TIFFSetField(tiffFile, TIFFTAG_IMAGELENGTH, metadata->imageHeight)
1059         && TIFFSetField(tiffFile, TIFFTAG_BITSPERSAMPLE,
1060                         metadata->bitsPerSample)
1061         && TIFFSetField(tiffFile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
1062         && TIFFSetField(tiffFile, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
1063         && TIFFSetField(tiffFile, TIFFTAG_SAMPLESPERPIXEL,
1064                         metadata->samplesPerPixel)
1065         && TIFFSetField(tiffFile, TIFFTAG_COMPRESSION,
1066                         metadata->compression.type)
1067         && TIFFSetField(tiffFile, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)
1068         && TIFFSetField(tiffFile, TIFFTAG_ROWSPERSTRIP,
1069                         metadata->rowsPerStrip)
1070         && TIFFSetField(tiffFile, TIFFTAG_RESOLUTIONUNIT,
1071                         metadata->resolutionUnits)
1072         && TIFFSetField(tiffFile, TIFFTAG_XRESOLUTION,
1073                         metadata->xPixelsPerResolution)
1074         && TIFFSetField(tiffFile, TIFFTAG_YRESOLUTION,
1075                         metadata->yPixelsPerResolution)
1076 	&& TIFFSetField(tiffFile, TIFFTAG_PAGENUMBER,  metadata->imageNumber,
1077 			metadata->imageTotalNumber);
1078 
1079 
1080 
1081 
1082     if (returnValue && metadata->bitsPerSample == 32)
1083     {
1084     // If it is 96 or 128 it is  floatint point
1085         returnValue = TIFFSetField(tiffFile, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
1086     }
1087     // Take care of special cases
1088 
1089     if (returnValue) {
1090 
1091 
1092     }
1093 
1094     // Only set ICCprofile if size > 0
1095 
1096     if (returnValue && metadata->iccProfile.size > 0) {
1097         returnValue =
1098             TIFFSetField(tiffFile, TIFFTAG_ICCPROFILE,
1099              (uint32)metadata->iccProfile.size,
1100              (void*)(metadata->iccProfile.data));
1101              //100, data);
1102     }
1103 
1104     if (returnValue && metadata->compression.type == COMPRESSION_LZW) {
1105         returnValue =
1106             TIFFSetField(tiffFile, TIFFTAG_PREDICTOR,
1107                          metadata->compression.predictor);
1108     }
1109 
1110     // String fields
1111     //printf("TO set tricky fields\n");
1112 
1113     if (returnValue && metadata->copyright != NULL)
1114         returnValue = TIFFSetField(tiffFile, TIFFTAG_COPYRIGHT, metadata->copyright);
1115 
1116     if (returnValue && metadata->artist != NULL)
1117         returnValue = TIFFSetField(tiffFile, TIFFTAG_ARTIST, metadata->artist);
1118 
1119     if (returnValue && metadata->datetime!=NULL)
1120         returnValue = TIFFSetField(tiffFile, TIFFTAG_DATETIME, metadata->datetime);
1121 
1122     if (returnValue && metadata->imageDescription != NULL)
1123         returnValue = TIFFSetField(tiffFile, TIFFTAG_IMAGEDESCRIPTION, metadata->imageDescription);
1124 
1125 
1126     returnValue = returnValue &&
1127         TIFFSetField(tiffFile, TIFFTAG_SOFTWARE, "Created by Panotools version " VERSION);
1128 
1129     //    printf("TO set crop\n");
1130     if (returnValue && panoTiffIsCropped(file)) {
1131       //printf("TO set crop 2\n");
1132         returnValue = panoTiffSetCropInformation(file);
1133     }
1134 
1135     return returnValue;
1136 
1137 }
1138 
1139 
1140 
panoTiffReadPlannar(Image * im,pano_Tiff * tif)1141 int panoTiffReadPlannar(Image * im, pano_Tiff * tif)
1142 {
1143     uint8_t *buf;
1144     uint32 row;
1145     short samplesPerPixel;
1146     int bytesRead;
1147     int bitsPerPixel;
1148 
1149     samplesPerPixel = panoTiffSamplesPerPixel(tif);
1150 
1151 
1152     // We can't read more than 4 samples per pixel
1153     if (samplesPerPixel > 4 || samplesPerPixel < 3) {
1154         PrintError("We only support 3 or 4 samples per pixel in TIFF");
1155         return 0;
1156     }
1157     // REmember, we need the values of the TIFF,
1158     // not the values in the image struct
1159     // (which will might not be the same
1160     bytesRead = panoTiffBytesPerLine(tif);
1161     bitsPerPixel = panoTiffBitsPerPixel(tif);
1162 
1163     //    printf("9 Bytes per line %d (im %d) %d %d\n", panoTiffBytesPerLine(tif),
1164     //     im->bytesPerLine, im->bitsPerPixel, panoTiffBitsPerPixel(tif));
1165     buf = calloc(bytesRead, 1);
1166     if (buf == NULL) {
1167         PrintError("Not enough memory");
1168         return 0;
1169     }
1170 
1171     for (row = 0; row < im->height; row++) {
1172         if (TIFFReadScanline(tif->tiff, buf, row, 0) != 1) {
1173             PrintError("Error reading TIFF file");
1174             goto error;
1175         }
1176 
1177         RGBAtoARGB(buf, im->width, bitsPerPixel);
1178 
1179         memcpy(*(im->data) + row * im->bytesPerLine, buf,
1180                (size_t) bytesRead);
1181     }
1182 
1183     // If we don't have an alpha channel we need to rebuild it
1184     if (samplesPerPixel == 3) {
1185         ThreeToFourBPP(im);
1186     }
1187     return 1;
1188 
1189  error:
1190     free(buf);
1191     return 0;
1192 }
1193 
1194 
1195 
1196 
1197 
1198 
1199 
panoTiffClose(pano_Tiff * file)1200 void panoTiffClose(pano_Tiff * file)
1201 {
1202     panoMetadataFree(&file->metadata);
1203     TIFFClose(file->tiff);
1204     free(file);
1205 }
1206 
1207 
1208 // create the tiff according to most of the needed data
panoTiffCreateGeneral(char * fileName,pano_ImageMetadata * metadata,int uncropped)1209 pano_Tiff *panoTiffCreateGeneral(char *fileName,
1210                                  pano_ImageMetadata * metadata, int uncropped)
1211 {
1212     pano_Tiff *panoTiff;
1213 
1214     // Allocate the struct's memory
1215     if ((panoTiff = calloc(sizeof(pano_Tiff), 1)) == NULL) {
1216         PrintError("Not enough memory");
1217         return NULL;
1218     }
1219 
1220     // Open file and retrieve metadata
1221     panoTiff->tiff = TIFFOpen(fileName, "w");
1222     if (panoTiff->tiff == NULL) {
1223         PrintError("Unable to create output file [%s]", fileName);
1224         free(panoTiff);
1225         return NULL;
1226     }
1227 
1228     //printf("Copy metadata from %d\n", (int) metadata->cropInfo.fullWidth);
1229     if (!panoMetadataCopy(&panoTiff->metadata, metadata)) {
1230         panoTiffClose(panoTiff);
1231         return NULL;
1232     }
1233 
1234     if (uncropped) {
1235         panoUnCropMetadata(&panoTiff->metadata);
1236     }
1237 
1238     //printf("Copy metadata %d\n", (int) panoTiff->metadata.cropInfo.fullWidth);
1239     if (!panoTiffSetImageProperties(panoTiff)) {
1240         panoTiffClose(panoTiff);
1241         return NULL;
1242     }
1243     //printf("After set image properties\n");
1244 
1245     // return value
1246     return panoTiff;
1247 }
1248 
panoTiffCreateUnCropped(char * fileName,pano_ImageMetadata * metadata)1249 pano_Tiff *panoTiffCreateUnCropped(char *fileName,
1250                                    pano_ImageMetadata * metadata)
1251 {
1252     // If the file is uncropped it creates a cropped version
1253     return panoTiffCreateGeneral(fileName, metadata, TRUE);
1254 }
1255 
1256 
panoTiffCreate(char * fileName,pano_ImageMetadata * metadata)1257 pano_Tiff *panoTiffCreate(char *fileName, pano_ImageMetadata * metadata)
1258 {
1259     return panoTiffCreateGeneral(fileName, metadata, FALSE);
1260 }
1261 
panoTiffOpen(char * fileName)1262 pano_Tiff *panoTiffOpen(char *fileName)
1263 {
1264     pano_Tiff *panoTiff;
1265 
1266 
1267     // Allocate the struct's memory
1268     if ((panoTiff = calloc(sizeof(*panoTiff), 1)) == NULL) {
1269         PrintError("Not enough memory");
1270         return NULL;
1271     }
1272 
1273     // Open file and retrieve metadata
1274     panoTiff->tiff = TIFFOpen(fileName, "r");
1275 
1276     if (panoTiff->tiff == NULL) {
1277 	PrintError("Unable to open file %s", fileName);
1278 	goto error;
1279     }
1280 
1281     if (!panoTiffGetImageProperties(panoTiff)) {
1282 	TIFFClose(panoTiff->tiff);
1283 	PrintError("Unable to get properties of tiff file %s", fileName);
1284 	goto error;
1285     }
1286     // return value
1287     return panoTiff;
1288 
1289  error:
1290     free(panoTiff);
1291     return NULL;
1292 
1293 }
1294 
1295 
1296 // image is allocated, but not image data
1297 
panoTiffReadData(Image * im,pano_Tiff * tif)1298 int panoTiffReadData(Image * im, pano_Tiff * tif)
1299 {
1300     short tPhotoMetric, config;
1301 
1302     assert(im != NULL);
1303     // Assume that it is unallocated
1304     assert(im->data == NULL);
1305 
1306     assert(tif != NULL);
1307 
1308     TIFFGetField(tif->tiff, TIFFTAG_PHOTOMETRIC, &tPhotoMetric);
1309     TIFFGetField(tif->tiff, TIFFTAG_PLANARCONFIG, &config);
1310 
1311 
1312     // Set general parameters. The width and height are of the data
1313 
1314     if ((im->data = (unsigned char **) mymalloc( im->dataSize) ) == NULL) {
1315         PrintError("Not enough memory");
1316         return 0;
1317     }
1318 
1319     if (tPhotoMetric == PHOTOMETRIC_RGB && config == PLANARCONFIG_CONTIG) {
1320         if (!panoTiffReadPlannar(im, tif))
1321             goto error;
1322     return TRUE;
1323     }
1324 
1325     // I changed the stopOnError to 1 so the function reports an error
1326     // as soon as it happens
1327 
1328     if (TIFFReadRGBAImage(tif->tiff, (uint32) panoTiffImageWidth(tif),
1329                           (uint32) panoTiffImageHeight(tif),
1330                           (uint32 *) * (im->data), 1)) {
1331         // Convert agbr to argb; flip image vertically
1332 
1333         unsigned char *cline, *ct, *cb;
1334         int h2 = im->height / 2, y;
1335         // Only do the conversion once
1336         size_t localBytesPerLine = im->bytesPerLine;
1337 
1338         cline = (unsigned char *) calloc(localBytesPerLine, 1);
1339         if (cline == NULL)
1340         {
1341             PrintError("Not enough memory");
1342             goto error;
1343         }
1344 
1345         ct = *im->data;
1346         cb = *im->data + (im->height - 1) * im->bytesPerLine;
1347 
1348         for (y = 0; y < h2;
1349              y++, ct += im->bytesPerLine, cb -= im->bytesPerLine) {
1350             RGBAtoARGB(ct, im->width, im->bitsPerPixel);
1351             RGBAtoARGB(cb, im->width, im->bitsPerPixel);
1352             memcpy(cline, ct, localBytesPerLine);
1353             memcpy(ct, cb, localBytesPerLine);
1354             memcpy(cb, cline, localBytesPerLine);
1355         }
1356         if (im->height != 2 * h2) {                       // odd number of scanlines
1357             RGBAtoARGB(*im->data + y * im->bytesPerLine, im->width,
1358                        im->bitsPerPixel);
1359         }
1360         free(cline);
1361     }
1362     else {
1363         PrintError("Could not read tiff-data");
1364         goto error;
1365     }
1366     return 1;
1367 
1368  error:
1369     myfree((void**)im->data);
1370     im->data = NULL;
1371     return 0;
1372 }
1373 
1374 
1375 
1376 
1377 // Output an image to a file
panoTiffWrite(Image * im,char * fileName)1378 int panoTiffWrite(Image * im, char *fileName)
1379 {
1380     pano_Tiff *tif = NULL;
1381     void *buf = 0;
1382     unsigned int y;
1383     size_t bufsize;
1384 
1385     // Make sure that the metadata is there...
1386     assert(im->metadata.imageWidth != 0 &&
1387        im->metadata.imageHeight != 0);
1388 
1389 
1390     // first verify the value of some of the metadata fields
1391 
1392     assert(im->bitsPerPixel != 0);
1393 
1394     switch (im->bitsPerPixel) {
1395     case 96:
1396     case 24:
1397     case 48:
1398         im->metadata.samplesPerPixel = 3;
1399         break;
1400     case 32:
1401     case 64:
1402     case 128:
1403         im->metadata.samplesPerPixel = 4;
1404         break;
1405     default:
1406         PrintError("Illegal value for bits per pixel in TIFF image to write %s", fileName);
1407         return FALSE;
1408     }
1409     im->metadata.bitsPerSample = (uint16_t)im->bitsPerPixel/im->metadata.samplesPerPixel;
1410 
1411 
1412     tif = panoTiffCreate(fileName, &im->metadata);
1413 
1414 
1415     if (!tif) {
1416         PrintError("Could not create TIFF-file");
1417         return 0;
1418     }
1419 
1420     // Rik's mask-from-focus hacking
1421     if (ZCombSeeImage(im, fileName)) {
1422         PrintError("failed ZCombSeeImage");
1423     }
1424     // end Rik's mask-from-focus hacking (for the moment...)
1425 
1426     bufsize = TIFFScanlineSize(tif->tiff);
1427 
1428     if ((uint32_t)bufsize < im->bytesPerLine)
1429         bufsize = im->bytesPerLine;
1430 
1431     buf = calloc(bufsize, 1);
1432     if (buf == NULL) {
1433         PrintError("Not enough memory");
1434         goto error;
1435     }
1436 
1437     for (y = 0; (uint32_t) y < im->height; y++) {
1438 	//	printf("Here 1 buffsize %d bytesperline %d width %d\n", bufsize, im->bytesPerLine, im->width);
1439         memcpy(buf, *(im->data) + y * im->bytesPerLine,
1440                (size_t) im->bytesPerLine);
1441         ARGBtoRGBA(buf, im->width, im->bitsPerPixel);
1442         if (TIFFWriteScanline(tif->tiff, buf, y, 0) != 1) {
1443             PrintError("Unable to write to TIFF");
1444             goto error;
1445         }
1446     }
1447     panoTiffClose(tif);
1448     free(buf);
1449     return 1;
1450 
1451  error:
1452     if (buf != NULL)
1453         free(buf);
1454 
1455     if (tif != NULL)
1456         panoTiffClose(tif);
1457 
1458     return 0;
1459 }
1460 
1461 
panoUpdateMetadataFromTiff(Image * im,pano_Tiff * tiff)1462 int panoUpdateMetadataFromTiff(Image *im, pano_Tiff *tiff)
1463 {
1464     int bytesPerLine;
1465 
1466     if (!panoMetadataCopy(&im->metadata, &tiff->metadata)) {
1467         return FALSE;
1468     }
1469     //    printf("IMage width %d %d\n",im->width, panoTiffImageWidth(tiff));
1470     //printf("Bites per pixel %d\n",(int)im->bitsPerPixel);
1471 
1472     im->width = panoTiffImageWidth(tiff);
1473     im->height = panoTiffImageHeight(tiff);
1474 
1475     // We will allocate enough memory for the 3 samples + Alpha Channel
1476     // Regardless of the actual number of samples in the image
1477 
1478     im->bytesPerLine = panoTiffBytesPerLine(tiff);
1479     im->bitsPerPixel = panoTiffBitsPerPixel(tiff);
1480 
1481     // Even if we only find 3 samples we will end with 4
1482     switch (panoTiffSamplesPerPixel(tiff))
1483     {
1484     case 3:
1485         bytesPerLine = panoTiffBytesPerLine(tiff) * 4 / 3;
1486 
1487         im->metadata.bytesPerLine = bytesPerLine;
1488 
1489         im->metadata.bitsPerPixel = im->bitsPerPixel * 4/ 3;
1490         im->metadata.samplesPerPixel = 4;
1491         im->metadata.bytesPerPixel =
1492             (4 * im->metadata.bitsPerSample) / 8;
1493         break;
1494     case 4:
1495         bytesPerLine = panoTiffBytesPerLine(tiff);
1496         break;
1497     default:
1498         PrintError("We only support 3 or 4 samples per pixel");
1499         return 0;
1500     }
1501 
1502     im->dataSize = bytesPerLine * im->height;
1503 
1504     // compute how much space we need
1505     //printf("Data size %d bytesperline %d width %d height %d\n",
1506     //(int)im->dataSize,
1507     //       (int)im->bytesPerLine, (int)im->width,(int)im->height
1508     //);
1509 
1510     return TRUE;
1511 }
1512 
1513 
1514 /*
1515   Read a TIFF file and place it in a Image data structure
1516   Read also the metadata including crop information
1517 */
1518 
panoTiffRead(Image * im,char * fileName)1519 int panoTiffRead(Image * im, char *fileName)
1520 {
1521     pano_Tiff *tiff = NULL;
1522     int result = FALSE;
1523 
1524     SetImageDefaults(im);
1525 
1526     //printf("Reading tiff\n");
1527     if ((tiff = panoTiffOpen(fileName)) == NULL) {
1528         PrintError("Could not open tiff-file %s", fileName);
1529         goto end;
1530     }
1531     //printf("to update metadata tiff\n");
1532 
1533     // Update metadata in the image
1534     if (!panoUpdateMetadataFromTiff(im, tiff)) {
1535         goto end;
1536     }
1537 
1538     //printf("to read data\n");
1539 
1540     if (!panoTiffReadData(im, tiff)) {
1541         PrintError("Unable to read data from TIFF file %s", fileName);
1542         goto end;
1543     }
1544 
1545     //Store name of TIFF file
1546     snprintf(im->name, MAX_PATH_LENGTH, "%s", fileName);
1547 
1548     //printf("after update metadata tiff\n");
1549     result = TRUE;
1550 
1551  end:
1552 
1553     //printf("ENd of Reading tiff\n");
1554 
1555     //panoDumpMetadata(&im->metadata,"Read metadata");
1556 
1557     if (tiff != NULL)
1558 	panoTiffClose(tiff);
1559     return result;
1560 }
1561 
1562 
1563 // THis functions clens any memory currently used by the Image
1564 // data structure
panoImageDispose(Image * im)1565 void panoImageDispose(Image *im)
1566 {
1567     if (im != NULL) {
1568 
1569 	// Release metadata
1570 	panoMetadataFree(&(im->metadata));
1571 
1572 	// Release image data
1573 	if (im->data != NULL) {
1574 	    myfree((void **) im->data);
1575 	    im->data = NULL;
1576 	}
1577     }
1578 }
1579 
1580 
panoTiffErrorHandler(const char * module,const char * fmt,va_list ap)1581 void panoTiffErrorHandler(const char *module, const char *fmt, va_list ap)
1582 {
1583     PrintError("Error in TIFF file (%s) ", module);
1584     PrintError((char *) fmt, ap);
1585 }
1586 
panoTiffSetErrorHandler(void)1587 void panoTiffSetErrorHandler(void)
1588 {
1589   // TODO
1590   // This routines need to be properly implemented. Currently it does nothing
1591 
1592     //MRDL: Reluctantly commented these out...the calls to TIFFSetWarningHandler and
1593     //TIFFSetErrorHandler cause to GCC to abort, with a series of errors like this:
1594     //../../../LibTiff/tiff-v3.6.1/libtiff/libtiff.a(tif_unix.o)(.text+0x11a): In function `TIFFOpen':
1595     //../../../libtiff/tiff-v3.6.1/libtiff/../libtiff/tif_unix.c:144: multiple definition of `TIFFOpen'
1596     //../libpano12.a(dyces00121.o)(.text+0x0): first defined here
1597     // Make sure we have a tiff error handler
1598 
1599   // Disable warnings in TIFF library
1600 
1601     TIFFSetWarningHandler(NULL);
1602 
1603 #ifdef TOBEIMPLEMENTED
1604     TIFFSetWarningHandler(panoTiffErrorHandler);
1605     TIFFSetErrorHandler(panoTiffErrorHandler);
1606 
1607 #endif
1608 }
1609 
1610 
1611 /* panotools is only able to operate on images that have the same size and same depth.
1612    if the colour profiles exist they should be the same too
1613 
1614    Some checksk are optional
1615 
1616 */
panoTiffVerifyAreCompatible(fullPath * tiffFiles,int numberImages,int optionalCheck)1617 int panoTiffVerifyAreCompatible(fullPath * tiffFiles, int numberImages,
1618                                  int optionalCheck)
1619 {
1620     int currentImage;
1621     pano_Tiff *firstFile;
1622     pano_Tiff *otherFile;
1623 
1624     pano_CropInfo *firstCropInfo = NULL;
1625     pano_CropInfo *otherCropInfo = NULL;
1626 
1627     assert(tiffFiles != NULL);
1628 
1629     assert(numberImages > 1);
1630 
1631 
1632     panoTiffSetErrorHandler();
1633 
1634     // Open TIFFs
1635 
1636     firstFile = panoTiffOpen(tiffFiles[0].name);
1637 
1638     if (firstFile == NULL) {
1639         PrintError("Unable to read tiff file %s", tiffFiles[0].name);
1640         return FALSE;
1641     }
1642 
1643     firstCropInfo = &firstFile->metadata.cropInfo;
1644 
1645     // Compare the metadata of the current file with each of the other ones
1646     for (currentImage = 1; currentImage < numberImages; currentImage++) {
1647 
1648         otherFile = panoTiffOpen(tiffFiles[currentImage].name);
1649 	otherCropInfo = &otherFile->metadata.cropInfo;
1650 
1651         if (otherFile == NULL) {
1652             PrintError("Unable to read tiff file %s",
1653                        tiffFiles[currentImage].name);
1654             return FALSE;
1655         }
1656 
1657 
1658         // THey should have the same width
1659         if (panoTiffFullImageWidth(firstFile) !=
1660             panoTiffFullImageWidth(otherFile)) {
1661             PrintError
1662                 ("Image 0 and %d do not have the same width: %d vs %d\n",
1663                  currentImage, (int) firstCropInfo->fullWidth,
1664                  (int) otherCropInfo->fullWidth);
1665             return FALSE;
1666         }
1667 
1668         // THey should have the same height
1669         if (panoTiffFullImageHeight(firstFile) !=
1670             panoTiffFullImageHeight(otherFile)) {
1671             PrintError
1672                 ("Image 0 and %d do not have the same length: %d vs %d\n",
1673                  currentImage, (int) firstCropInfo->fullHeight,
1674                  (int) otherCropInfo->fullHeight);
1675             return FALSE;
1676         }
1677 
1678         // THey should have the same colour depth
1679         if (panoTiffBytesPerPixel(firstFile) !=
1680             panoTiffBytesPerPixel(otherFile)) {
1681             PrintError("Image 0 and %d do not have the same colour depth\n",
1682                        currentImage);
1683             return FALSE;
1684         }
1685         //printf("compatible 1\n");
1686         // THey should have the same number of channels per pixel
1687         if (panoTiffSamplesPerPixel(firstFile) !=
1688             panoTiffSamplesPerPixel(otherFile)) {
1689             PrintError
1690                 ("Image 0 and %d do not have the same number of channels per pixel\n",
1691                  currentImage);
1692             return FALSE;
1693         }
1694 
1695         if (optionalCheck) {
1696 
1697             // Compare profiles
1698 
1699             if (firstFile->metadata.iccProfile.size > 0) {
1700 
1701                 //  They should be the same size and have the same contents
1702                 if (firstFile->metadata.iccProfile.size !=
1703                     otherFile->metadata.iccProfile.size
1704                     || memcmp(firstFile->metadata.iccProfile.data,
1705                               otherFile->metadata.iccProfile.data,
1706                               firstFile->metadata.iccProfile.size) != 0) {
1707                     PrintError
1708                         ("Image 0 and %d have different colour profiles\n",
1709                          currentImage);
1710                     return FALSE;
1711                 }
1712             }
1713         }
1714         panoTiffClose(otherFile);
1715 
1716     }                           // for loop
1717 
1718     panoTiffClose(firstFile);
1719     //printf("THe files are compatible\n");
1720 
1721     return TRUE;
1722 
1723 }
1724 
1725 /**
1726  * Reads inputFile and "uncrops" the image by adding black space to pad
1727  * image to its full size, saving the result as outputFile.  If an error
1728  * is encountered messageBuffer is filled with the message, and a non-zero
1729  * value is returned.  If success, zero is returned
1730  */
panoTiffUnCrop(char * inputFile,char * outputFile,pano_cropping_parms * croppingParms)1731 int panoTiffUnCrop(char *inputFile, char *outputFile, pano_cropping_parms *croppingParms)
1732 {
1733 
1734     pano_CropInfo *inputCropInfo = NULL;
1735     char *buffer = NULL;
1736     char *offsetInBuffer;
1737     int inputRow, outputRow;
1738     pano_Tiff *tiffInput = NULL;
1739     pano_Tiff *tiffOutput = NULL;
1740     pano_ImageMetadata *metadata = NULL;
1741 
1742     if ((tiffInput = panoTiffOpen(inputFile)) == NULL) {
1743         PrintError("Unable to open input file");
1744         goto error;
1745     }
1746 
1747     if (!panoTiffIsCropped(tiffInput)) {
1748         PrintError("Source image is not a cropped tiff");
1749 	if (!croppingParms->forceProcessing)
1750 	    goto error;
1751         PrintError("Forced processing... continuing");
1752     }
1753 
1754     inputCropInfo = &tiffInput->metadata.cropInfo;
1755 
1756     if ((tiffOutput =
1757          panoTiffCreateUnCropped(outputFile, &tiffInput->metadata)) == NULL) {
1758         PrintError("Unable to create output file [%s]", outputFile);
1759         goto error;
1760     }
1761 
1762     metadata = &tiffOutput->metadata;
1763     //printf("***Size of line %d\n", metadata->bytesPerLine);
1764 
1765     // Allocate buffer for line
1766     buffer = calloc(metadata->bytesPerLine, 1);
1767 
1768     if (buffer == NULL) {
1769         PrintError("Unable to allocate memory for IO buffer");
1770         goto error;
1771     }
1772 
1773     inputRow = 0;
1774     // The crop data has to be placed inside the buffer according to the
1775     // cropinfo offset
1776 
1777     offsetInBuffer =
1778         buffer + inputCropInfo->xOffset * metadata->bytesPerPixel;
1779 
1780     assert(metadata->imageHeight > 0);
1781     // Read one line at a time and transfer to output file
1782     for (outputRow = 0; outputRow < (int) metadata->imageHeight; outputRow++) {
1783 
1784         //fill empty buffer with empty space (zeros)
1785         bzero(buffer, metadata->bytesPerLine);
1786 
1787         //if inside ROI then read from input file
1788         if (panoROIRowInside(inputCropInfo, outputRow)) {
1789 
1790             if (TIFFReadScanline(tiffInput->tiff, offsetInBuffer, inputRow, 0)
1791                 != 1) {
1792                 PrintError("Unable to read scanline %d", inputRow);
1793                 goto error;
1794             }
1795             inputRow++;
1796         }
1797 
1798         //write buffer to outputfile
1799         if (TIFFWriteScanline(tiffOutput->tiff, buffer, outputRow, 0) != 1) {
1800             PrintError("Unable to write scanline %d", outputRow);
1801             goto error;
1802         }
1803 
1804     }
1805 
1806     //printf("Finished\n");
1807 
1808     free(buffer);
1809     panoTiffClose(tiffInput);
1810     panoTiffClose(tiffOutput);
1811 
1812     return 1;
1813 
1814   error:
1815     // Error handler
1816     // Make sure we release any resources we have
1817 
1818     if (buffer != NULL)
1819         free(buffer);
1820 
1821     if (tiffOutput != NULL)
1822         panoTiffClose(tiffOutput);
1823 
1824     if (tiffInput != NULL)
1825         panoTiffClose(tiffInput);
1826 
1827 
1828     return 0;
1829 }
1830 
1831 
1832 
panoImageBoundingRectangleCompute(unsigned char * data,int width,int height,int bytesPerPixel,pano_CropInfo * cropInfo)1833 int panoImageBoundingRectangleCompute(unsigned char *data, int width, int height, int bytesPerPixel, pano_CropInfo *cropInfo)
1834 {
1835     unsigned char *pixel;
1836     int xLeft, xRight, yTop, yBottom;
1837     int row; int column;
1838     int alphaChannel;
1839 
1840     xLeft = width;
1841     yTop = 0;
1842 
1843     xRight = 0;
1844     yBottom = 0;
1845 
1846     // We can do it all in one pass over the data
1847 
1848     pixel = data;
1849     for (row = 0; row < height; row++) {
1850 
1851 	for (column = 0; column < width; column++) {
1852 
1853 	    alphaChannel = panoStitchPixelChannelGet(pixel, bytesPerPixel/4, 0);
1854 
1855 	    if (alphaChannel != 0) {
1856 		// Only set the row the first time
1857 		if (yTop == 0)
1858 		    yTop = row;
1859 		// Keep setting it until we find no more data
1860 		yBottom = row;
1861 
1862 		// Columns are trickier...
1863 		// We are scanning row by row, so we need to
1864 		if (xLeft > column) {
1865 		    xLeft = column;
1866 		}
1867 		if (xRight < column) {
1868 		    xRight = column;
1869 		}
1870 	    }
1871 	    pixel += bytesPerPixel;
1872 	}
1873     }
1874 
1875     assert(xRight > xLeft);
1876     assert(yBottom > yTop);
1877 
1878 
1879     // Fill return struct
1880 
1881     cropInfo->fullWidth = width;
1882     cropInfo->fullHeight = height;
1883     cropInfo->xOffset = xLeft;
1884     cropInfo->yOffset = yTop;
1885     cropInfo->croppedWidth = 1 + xRight - xLeft ;
1886     cropInfo->croppedHeight = 1+ yBottom - yTop;
1887 
1888     // it should be at most equal to the original size
1889     assert(width >= cropInfo->croppedWidth);
1890     assert(height >= cropInfo->croppedHeight);
1891 
1892 
1893 
1894     //    fprintf(stderr, "Finding boudinging box: x %d y %d width %d height %d\n", (int)cropInfo->xOffset, (int)cropInfo->yOffset,
1895     //	    (int)cropInfo->croppedWidth, (int)cropInfo->croppedHeight);
1896 
1897     return 1;
1898 }
1899 
1900 /**
1901  * Reads inputFile and crops image
1902  */
panoTiffCrop(char * inputFile,char * outputFile,pano_cropping_parms * croppingParms)1903 int panoTiffCrop(char *inputFile, char *outputFile, pano_cropping_parms *croppingParms)
1904 {
1905 
1906     pano_Tiff *tiffOutput = NULL;
1907     pano_ImageMetadata metadata;
1908     pano_CropInfo cropInfo;
1909     Image im;
1910     unsigned char *data = NULL;
1911     int i;
1912     fullPath tempFile;
1913 
1914     strcpy(tempFile.name, "");
1915     // Let us do the processing in a different file
1916     if (panoFileMakeTemp(&tempFile) == 0) {
1917 	PrintError("Could not make Tempfile");
1918 	return -1;
1919     }
1920 
1921     if (panoTiffRead(&im, inputFile) ==0 ) {
1922         PrintError("Unable to open input file %s", inputFile);
1923         goto error;
1924     }
1925 
1926     // Compute inner rectangle
1927 
1928     panoImageBoundingRectangleCompute(*im.data, im.width, im.height, im.bitsPerPixel/8, &cropInfo);
1929 
1930     // Cropinfo is with respect to the data of the read image, not with respet to the "uncropped" image
1931     if (cropInfo.croppedWidth == 0 || cropInfo.croppedHeight == 0) {
1932 	PrintError("Image is empty, unable to crop. ");
1933 	goto error;
1934     }
1935 
1936     if (!panoMetadataCopy(&metadata, &(im.metadata))) {
1937 	goto error;
1938     }
1939 
1940     panoMetadataCropSizeUpdate(&metadata, &cropInfo);
1941 
1942     if ((tiffOutput =
1943          panoTiffCreate(tempFile.name, &metadata)) == NULL) {
1944         PrintError("Unable to create output file [%s]", outputFile);
1945         goto error;
1946     }
1947 
1948     // Now we need to copy the data.
1949 
1950     data = *(im.data);
1951 
1952     // We need to advance data the number of lines that this file has more of ofset
1953     data += im.bytesPerLine * cropInfo.yOffset;
1954     for (i =0;i < (int) metadata.imageHeight; i++) {
1955 	unsigned char *ptr;
1956 
1957 	// skip the necessary bytes
1958 
1959 	ptr = data + im.metadata.bytesPerPixel * cropInfo.xOffset;
1960 
1961 	// write
1962 	ARGBtoRGBA(ptr, metadata.imageWidth, metadata.bitsPerPixel);
1963         if (TIFFWriteScanline(tiffOutput->tiff, ptr, i, 1) != 1) {
1964 	    PrintError("Error writing to output file");
1965 	    goto error;
1966 	}
1967 
1968 	data += im.bytesPerLine;
1969 
1970     }
1971 
1972     //printf("Finished\n");
1973 
1974     panoTiffClose(tiffOutput);
1975     remove(outputFile);
1976     if (rename(tempFile.name, outputFile) != 0) {
1977 	PrintError("Unable to create output file %s", outputFile);
1978 	goto error;
1979     }
1980 
1981 
1982     return 1;
1983 
1984   error:
1985     // Error handler
1986     // Make sure we release any resources we have
1987 
1988     if (tiffOutput != NULL) {
1989         panoTiffClose(tiffOutput);
1990 	remove(tempFile.name);
1991     }
1992 
1993     return 0;
1994 }
1995 
1996 
panoTiffDisplayInfo(char * fileName)1997 int panoTiffDisplayInfo(char *fileName)
1998 {
1999     pano_Tiff *imageFile;
2000     pano_ImageMetadata *meta;
2001 
2002     char *line = NULL;
2003 
2004     if ((imageFile = panoTiffOpen(fileName)) == NULL) {
2005         PrintError("Could not open TIFF-file %s", fileName);
2006         return 0;
2007     }
2008     meta = &(imageFile->metadata);
2009     printf("Dimensions: %d,%d\n", meta->imageWidth, meta->imageHeight);
2010     if (meta->isCropped) {
2011 	printf("Cropped tiff. Full size: %d,%d Offset: %d,%d\n",
2012 	       (int)meta->cropInfo.fullWidth, (int)meta->cropInfo.fullHeight,
2013 	       (int)meta->cropInfo.xOffset, (int)meta->cropInfo.yOffset);
2014     }
2015     printf("Samples per pixel: %d\n", meta->samplesPerPixel);
2016     printf("Bits per sample: %d\n", meta->bitsPerSample);
2017 
2018     if (meta->iccProfile.size == 0) {
2019 	printf("Contains ICC profile\n");
2020     }
2021     if (meta->copyright != NULL){
2022 	printf("Copyright: %s\n", meta->copyright);
2023     }
2024     if (meta->datetime != NULL){
2025 	printf("Date created: %s\n", meta->datetime);
2026     }
2027     if (meta->artist != NULL){
2028 	printf("Photographer: %s\n", meta->artist);
2029     }
2030     printf("Image: %d out of %d\n", meta->imageNumber, meta->imageTotalNumber);
2031 
2032     line = panoParserFindOLine(meta->imageDescription, meta->imageNumber);
2033     if (line != NULL) {
2034 	printf("Image Spec: %s\n", line);
2035 	free(line);
2036 	if (meta->imageDescription) {
2037 	    printf("Script that created it:\n%s\n", meta->imageDescription);
2038 	}
2039     }
2040 
2041     return 1;
2042 }
2043