Blender V2.61 - r43446

tiff.c

Go to the documentation of this file.
00001 /*
00002  * tiff.c
00003  *
00004  * 
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * Contributor(s): Jonathan Merritt.
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00047 #include <string.h>
00048 
00049 #include "imbuf.h"
00050 
00051 #include "BLI_math.h"
00052 #include "BLI_string.h"
00053 #include "BLI_utildefines.h"
00054  
00055 #include "BKE_global.h"
00056 
00057 
00058 #include "IMB_imbuf_types.h"
00059 #include "IMB_imbuf.h"
00060 
00061 #include "IMB_allocimbuf.h"
00062 #include "IMB_filetype.h"
00063 #include "IMB_filter.h"
00064 
00065 #include "tiffio.h"
00066 
00067 
00068 
00069 /***********************
00070  * Local declarations. *
00071  ***********************/
00072 /* Reading and writing of an in-memory TIFF file. */
00073 static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n);
00074 static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n);
00075 static toff_t  imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence);
00076 static int     imb_tiff_CloseProc(thandle_t handle);
00077 static toff_t  imb_tiff_SizeProc(thandle_t handle);
00078 static int     imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize);
00079 static void    imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size);
00080 
00081 
00082 /* Structure for in-memory TIFF file. */
00083 typedef struct ImbTIFFMemFile {
00084     unsigned char *mem; /* Location of first byte of TIFF file. */
00085     toff_t offset;      /* Current offset within the file.      */
00086     tsize_t size;       /* Size of the TIFF file.               */
00087 } ImbTIFFMemFile;
00088 #define IMB_TIFF_GET_MEMFILE(x) ((ImbTIFFMemFile*)(x));
00089 
00090 
00091 
00092 /*****************************
00093  * Function implementations. *
00094  *****************************/
00095 
00096 
00097 static void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
00098 {
00099     (void)fd;
00100     (void)base;
00101     (void)size;
00102 }
00103 
00104 static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) 
00105 {
00106     (void)fd;
00107     (void)pbase;
00108     (void)psize;
00109 
00110     return (0);
00111 }
00112 
00123 static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
00124 {
00125     tsize_t nRemaining, nCopy;
00126     ImbTIFFMemFile* mfile;
00127     void *srcAddr;
00128 
00129     /* get the pointer to the in-memory file */
00130     mfile = IMB_TIFF_GET_MEMFILE(handle);
00131     if(!mfile || !mfile->mem) {
00132         fprintf(stderr, "imb_tiff_ReadProc: !mfile || !mfile->mem!\n");
00133         return 0;
00134     }
00135 
00136     /* find the actual number of bytes to read (copy) */
00137     nCopy = n;
00138     if((tsize_t)mfile->offset >= mfile->size)
00139         nRemaining = 0;
00140     else
00141         nRemaining = mfile->size - mfile->offset;
00142     
00143     if(nCopy > nRemaining)
00144         nCopy = nRemaining;
00145     
00146     /* on EOF, return immediately and read (copy) nothing */
00147     if(nCopy <= 0)
00148         return (0);
00149 
00150     /* all set -> do the read (copy) */
00151     srcAddr = (void*)(&(mfile->mem[mfile->offset]));
00152     memcpy((void*)data, srcAddr, nCopy);
00153     mfile->offset += nCopy;     /* advance file ptr by copied bytes */
00154     return nCopy;
00155 }
00156 
00157 
00158 
00165 static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
00166 {
00167     (void)handle;
00168     (void)data;
00169     (void)n;
00170     
00171     printf("imb_tiff_WriteProc: this function should not be called.\n");
00172     return (-1);
00173 }
00174 
00175 
00176 
00191 static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
00192 {
00193     ImbTIFFMemFile *mfile;
00194     toff_t new_offset;
00195 
00196     /* get the pointer to the in-memory file */
00197     mfile = IMB_TIFF_GET_MEMFILE(handle);
00198     if(!mfile || !mfile->mem) {
00199         fprintf(stderr, "imb_tiff_SeekProc: !mfile || !mfile->mem!\n");
00200         return (-1);
00201     }
00202 
00203     /* find the location we plan to seek to */
00204     switch (whence) {
00205         case SEEK_SET:
00206             new_offset = ofs;
00207             break;
00208         case SEEK_CUR:
00209             new_offset = mfile->offset + ofs;
00210             break;
00211         default:
00212             /* no other types are supported - return an error */
00213             fprintf(stderr, 
00214                 "imb_tiff_SeekProc: "
00215                 "Unsupported TIFF SEEK type.\n");
00216             return (-1);
00217     }
00218 
00219     /* set the new location */
00220     mfile->offset = new_offset;
00221     return mfile->offset;
00222 }
00223 
00224 
00225 
00238 static int imb_tiff_CloseProc(thandle_t handle)
00239 {
00240     ImbTIFFMemFile *mfile;
00241 
00242     /* get the pointer to the in-memory file */
00243     mfile = IMB_TIFF_GET_MEMFILE(handle);
00244     if(!mfile || !mfile->mem) {
00245         fprintf(stderr,"imb_tiff_CloseProc: !mfile || !mfile->mem!\n");
00246         return (0);
00247     }
00248     
00249     /* virtually close the file */
00250     mfile->mem    = NULL;
00251     mfile->offset = 0;
00252     mfile->size   = 0;
00253     
00254     return (0);
00255 }
00256 
00257 
00258 
00264 static toff_t imb_tiff_SizeProc(thandle_t handle)
00265 {
00266     ImbTIFFMemFile* mfile;
00267 
00268     /* get the pointer to the in-memory file */
00269     mfile = IMB_TIFF_GET_MEMFILE(handle);
00270     if(!mfile || !mfile->mem) {
00271         fprintf(stderr,"imb_tiff_SizeProc: !mfile || !mfile->mem!\n");
00272         return (0);
00273     }
00274 
00275     /* return the size */
00276     return (toff_t)(mfile->size);
00277 }
00278 
00279 static TIFF *imb_tiff_client_open(ImbTIFFMemFile *memFile, unsigned char *mem, size_t size)
00280 {
00281     /* open the TIFF client layer interface to the in-memory file */
00282     memFile->mem = mem;
00283     memFile->offset = 0;
00284     memFile->size = size;
00285 
00286     return TIFFClientOpen("(Blender TIFF Interface Layer)", 
00287         "r", (thandle_t)(memFile),
00288         imb_tiff_ReadProc, imb_tiff_WriteProc,
00289         imb_tiff_SeekProc, imb_tiff_CloseProc,
00290         imb_tiff_SizeProc, imb_tiff_DummyMapProc, imb_tiff_DummyUnmapProc);
00291 }
00292 
00308 #define IMB_TIFF_NCB 4      /* number of comparison bytes used */
00309 int imb_is_a_tiff(unsigned char *mem)
00310 {
00311     char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a };
00312     char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 };
00313 
00314     return ( (memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) ||
00315          (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) );
00316 }
00317 
00318 static void scanline_contig_16bit(float *rectf, unsigned short *sbuf, int scanline_w, int spp)
00319 {
00320     int i;
00321     for (i=0; i < scanline_w; i++) {
00322         rectf[i*4 + 0] = sbuf[i*spp + 0] / 65535.0;
00323         rectf[i*4 + 1] = sbuf[i*spp + 1] / 65535.0;
00324         rectf[i*4 + 2] = sbuf[i*spp + 2] / 65535.0;
00325         rectf[i*4 + 3] = (spp==4)?(sbuf[i*spp + 3] / 65535.0):1.0;
00326     }
00327 }
00328 
00329 static void scanline_contig_32bit(float *rectf, float *fbuf, int scanline_w, int spp)
00330 {
00331     int i;
00332     for (i=0; i < scanline_w; i++) {
00333         rectf[i*4 + 0] = fbuf[i*spp + 0];
00334         rectf[i*4 + 1] = fbuf[i*spp + 1];
00335         rectf[i*4 + 2] = fbuf[i*spp + 2];
00336         rectf[i*4 + 3] = (spp==4)?fbuf[i*spp + 3]:1.0f;
00337     }
00338 }
00339 
00340 static void scanline_separate_16bit(float *rectf, unsigned short *sbuf, int scanline_w, int chan)
00341 {
00342     int i;
00343     for (i=0; i < scanline_w; i++)
00344         rectf[i*4 + chan] = sbuf[i] / 65535.0;
00345 }
00346 
00347 static void scanline_separate_32bit(float *rectf, float *fbuf, int scanline_w, int chan)
00348 {
00349     int i;
00350     for (i=0; i < scanline_w; i++)
00351         rectf[i*4 + chan] = fbuf[i];
00352 }
00353 
00354 static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image)
00355 {
00356     uint16 unit;
00357     float xres;
00358     float yres;
00359 
00360     TIFFGetFieldDefaulted(image, TIFFTAG_RESOLUTIONUNIT, &unit);
00361     TIFFGetFieldDefaulted(image, TIFFTAG_XRESOLUTION, &xres);
00362     TIFFGetFieldDefaulted(image, TIFFTAG_YRESOLUTION, &yres);
00363 
00364     if(unit == RESUNIT_CENTIMETER) {
00365         ibuf->ppm[0]= (double)xres * 100.0;
00366         ibuf->ppm[1]= (double)yres * 100.0;
00367     }
00368     else {
00369         ibuf->ppm[0]= (double)xres / 0.0254;
00370         ibuf->ppm[1]= (double)yres / 0.0254;
00371     }
00372 }
00373 
00374 /* 
00375  * Use the libTIFF scanline API to read a TIFF image.
00376  * This method is most flexible and can handle multiple different bit depths 
00377  * and RGB channel orderings.
00378  */
00379 static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
00380 {
00381     ImBuf *tmpibuf;
00382     int success= 0;
00383     short bitspersample, spp, config;
00384     size_t scanline;
00385     int ib_flag=0, row, chan;
00386     float *fbuf=NULL;
00387     unsigned short *sbuf=NULL;
00388 
00389     TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample);
00390     TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp);     /* number of 'channels' */
00391     TIFFGetField(image, TIFFTAG_PLANARCONFIG, &config);
00392 
00393     imb_read_tiff_resolution(ibuf, image);
00394 
00395     scanline = TIFFScanlineSize(image);
00396     
00397     if (bitspersample == 32) {
00398         ib_flag = IB_rectfloat;
00399         fbuf = (float *)_TIFFmalloc(scanline);
00400     } else if (bitspersample == 16) {
00401         ib_flag = IB_rectfloat;
00402         sbuf = (unsigned short *)_TIFFmalloc(scanline);
00403     } else {
00404         ib_flag = IB_rect;
00405     }
00406     
00407     tmpibuf= IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ib_flag);
00408     
00409     /* simple RGBA image */
00410     if (!(bitspersample == 32 || bitspersample == 16)) {
00411         success |= TIFFReadRGBAImage(image, ibuf->x, ibuf->y, tmpibuf->rect, 0);
00412     }
00413     /* contiguous channels: RGBRGBRGB */
00414     else if (config == PLANARCONFIG_CONTIG) {
00415         for (row = 0; row < ibuf->y; row++) {
00416             int ib_offset = ibuf->x*ibuf->y*4 - ibuf->x*4 * (row+1);
00417         
00418             if (bitspersample == 32) {
00419                 success |= TIFFReadScanline(image, fbuf, row, 0);
00420                 scanline_contig_32bit(tmpibuf->rect_float+ib_offset, fbuf, ibuf->x, spp);
00421                 
00422             } else if (bitspersample == 16) {
00423                 success |= TIFFReadScanline(image, sbuf, row, 0);
00424                 scanline_contig_16bit(tmpibuf->rect_float+ib_offset, sbuf, ibuf->x, spp);
00425             }
00426         }
00427     /* separate channels: RRRGGGBBB */
00428     } else if (config == PLANARCONFIG_SEPARATE) {
00429         
00430         /* imbufs always have 4 channels of data, so we iterate over all of them
00431          * but only fill in from the TIFF scanline where necessary. */
00432         for (chan = 0; chan < 4; chan++) {
00433             for (row = 0; row < ibuf->y; row++) {
00434                 int ib_offset = ibuf->x*ibuf->y*4 - ibuf->x*4 * (row+1);
00435                 
00436                 if (bitspersample == 32) {
00437                     if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
00438                         memset(fbuf, 1.0, sizeof(fbuf));
00439                     else
00440                         success |= TIFFReadScanline(image, fbuf, row, chan);
00441                     scanline_separate_32bit(tmpibuf->rect_float+ib_offset, fbuf, ibuf->x, chan);
00442                     
00443                 } else if (bitspersample == 16) {
00444                     if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
00445                         memset(sbuf, 65535, sizeof(sbuf));
00446                     else
00447                         success |= TIFFReadScanline(image, sbuf, row, chan);
00448                     scanline_separate_16bit(tmpibuf->rect_float+ib_offset, sbuf, ibuf->x, chan);
00449                     
00450                 }
00451             }
00452         }
00453     }
00454     
00455     if (bitspersample == 32)
00456         _TIFFfree(fbuf);
00457     else if (bitspersample == 16)
00458         _TIFFfree(sbuf);
00459 
00460     if(success) {
00461         ibuf->profile = (bitspersample==32)?IB_PROFILE_LINEAR_RGB:IB_PROFILE_SRGB;
00462 
00463 //      Code seems to be not needed for 16 bits tif, on PPC G5 OSX (ton)
00464         if(bitspersample < 16)
00465             if(ENDIAN_ORDER == B_ENDIAN)
00466                 IMB_convert_rgba_to_abgr(tmpibuf);
00467         if(premul) {
00468             IMB_premultiply_alpha(tmpibuf);
00469             ibuf->flags |= IB_premul;
00470         }
00471         
00472         /* assign rect last */
00473         if (tmpibuf->rect_float)
00474             ibuf->rect_float= tmpibuf->rect_float;
00475         else    
00476             ibuf->rect= tmpibuf->rect;
00477         ibuf->mall |= ib_flag;
00478         ibuf->flags |= ib_flag;
00479         
00480         tmpibuf->mall &= ~ib_flag;
00481     }
00482 
00483     IMB_freeImBuf(tmpibuf);
00484     
00485     return success;
00486 }
00487 
00488 void imb_inittiff(void)
00489 {
00490     if (!(G.f & G_DEBUG))
00491         TIFFSetErrorHandler(NULL);
00492 }
00493 
00505 ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags)
00506 {
00507     TIFF *image = NULL;
00508     ImBuf *ibuf = NULL, *hbuf;
00509     ImbTIFFMemFile memFile;
00510     uint32 width, height;
00511     char *format = NULL;
00512     int level;
00513     short spp;
00514     int ib_depth;
00515 
00516     /* check whether or not we have a TIFF file */
00517     if(size < IMB_TIFF_NCB) {
00518         fprintf(stderr, "imb_loadtiff: size < IMB_TIFF_NCB\n");
00519         return NULL;
00520     }
00521     if(imb_is_a_tiff(mem) == 0)
00522         return NULL;
00523 
00524     image = imb_tiff_client_open(&memFile, mem, size);
00525 
00526     if(image == NULL) {
00527         printf("imb_loadtiff: could not open TIFF IO layer.\n");
00528         return NULL;
00529     }
00530 
00531     /* allocate the image buffer */
00532     TIFFGetField(image, TIFFTAG_IMAGEWIDTH,  &width);
00533     TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
00534     TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp);
00535     
00536     ib_depth = (spp==3)?24:32;
00537     
00538     ibuf = IMB_allocImBuf(width, height, ib_depth, 0);
00539     if(ibuf) {
00540         ibuf->ftype = TIF;
00541     }
00542     else {
00543         fprintf(stderr, 
00544             "imb_loadtiff: could not allocate memory for TIFF "
00545             "image.\n");
00546         TIFFClose(image);
00547         return NULL;
00548     }
00549 
00550     /* if testing, we're done */
00551     if(flags & IB_test) {
00552         TIFFClose(image);
00553         return ibuf;
00554     }
00555 
00556     /* detect if we are reading a tiled/mipmapped texture, in that case
00557        we don't read pixels but leave it to the cache to load tiles */
00558     if(flags & IB_tilecache) {
00559         format= NULL;
00560         TIFFGetField(image, TIFFTAG_PIXAR_TEXTUREFORMAT, &format);
00561 
00562         if(format && strcmp(format, "Plain Texture")==0 && TIFFIsTiled(image)) {
00563             int numlevel = TIFFNumberOfDirectories(image);
00564 
00565             /* create empty mipmap levels in advance */
00566             for(level=0; level<numlevel; level++) {
00567                 if(!TIFFSetDirectory(image, level))
00568                     break;
00569 
00570                 if(level > 0) {
00571                     width= (width > 1)? width/2: 1;
00572                     height= (height > 1)? height/2: 1;
00573 
00574                     hbuf= IMB_allocImBuf(width, height, 32, 0);
00575                     hbuf->miplevel= level;
00576                     hbuf->ftype= ibuf->ftype;
00577                     ibuf->mipmap[level-1] = hbuf;
00578 
00579                     if(flags & IB_premul)
00580                         hbuf->flags |= IB_premul;
00581                 }
00582                 else
00583                     hbuf= ibuf;
00584 
00585                 hbuf->flags |= IB_tilecache;
00586 
00587                 TIFFGetField(image, TIFFTAG_TILEWIDTH, &hbuf->tilex);
00588                 TIFFGetField(image, TIFFTAG_TILELENGTH, &hbuf->tiley);
00589 
00590                 hbuf->xtiles= ceil(hbuf->x/(float)hbuf->tilex);
00591                 hbuf->ytiles= ceil(hbuf->y/(float)hbuf->tiley);
00592 
00593                 imb_addtilesImBuf(hbuf);
00594 
00595                 ibuf->miptot++;
00596             }
00597         }
00598     }
00599 
00600     /* read pixels */
00601     if(!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image, 0)) {
00602         fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n");
00603         TIFFClose(image);
00604         return NULL;
00605     }
00606 
00607     /* close the client layer interface to the in-memory file */
00608     TIFFClose(image);
00609 
00610     /* return successfully */
00611     return ibuf;
00612 }
00613 
00614 void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect)
00615 {
00616     TIFF *image = NULL;
00617     uint32 width, height;
00618     ImbTIFFMemFile memFile;
00619 
00620     image = imb_tiff_client_open(&memFile, mem, size);
00621 
00622     if(image == NULL) {
00623         printf("imb_loadtiff: could not open TIFF IO layer for loading mipmap level.\n");
00624         return;
00625     }
00626 
00627     if(TIFFSetDirectory(image, ibuf->miplevel)) { /* allocate the image buffer */
00628         TIFFGetField(image, TIFFTAG_IMAGEWIDTH,  &width);
00629         TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
00630 
00631         if(width == ibuf->x && height == ibuf->y) {
00632             if(rect) {
00633                 /* tiff pixels are bottom to top, tiles are top to bottom */
00634                 if(TIFFReadRGBATile(image, tx*ibuf->tilex, (ibuf->ytiles - 1 - ty)*ibuf->tiley, rect) == 1) {
00635                     if(ibuf->tiley > ibuf->y)
00636                         memmove(rect, rect+ibuf->tilex*(ibuf->tiley - ibuf->y), sizeof(int)*ibuf->tilex*ibuf->y);
00637 
00638                     if(ibuf->flags & IB_premul)
00639                         IMB_premultiply_rect(rect, 32, ibuf->tilex, ibuf->tiley);
00640                 }
00641                 else
00642                     printf("imb_loadtiff: failed to read tiff tile at mipmap level %d\n", ibuf->miplevel);
00643             }
00644         }
00645         else
00646             printf("imb_loadtiff: mipmap level %d has unexpected size %ux%u instead of %dx%d\n", ibuf->miplevel, width, height, ibuf->x, ibuf->y);
00647     }
00648     else
00649         printf("imb_loadtiff: could not find mipmap level %d\n", ibuf->miplevel);
00650 
00651     /* close the client layer interface to the in-memory file */
00652     TIFFClose(image);
00653 }
00654 
00671 int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
00672 {
00673     TIFF *image = NULL;
00674     uint16 samplesperpixel, bitspersample;
00675     size_t npixels;
00676     unsigned char *pixels = NULL;
00677     unsigned char *from = NULL, *to = NULL;
00678     unsigned short *pixels16 = NULL, *to16 = NULL;
00679     float *fromf = NULL;
00680     float xres, yres;
00681     int x, y, from_i, to_i, i;
00682     int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA };
00683     
00684 
00685     /* check for a valid number of bytes per pixel.  Like the PNG writer,
00686      * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
00687      * to gray, RGB, RGBA respectively. */
00688     samplesperpixel = (uint16)((ibuf->planes + 7) >> 3);
00689     if((samplesperpixel > 4) || (samplesperpixel == 2)) {
00690         fprintf(stderr,
00691             "imb_savetiff: unsupported number of bytes per " 
00692             "pixel: %d\n", samplesperpixel);
00693         return (0);
00694     }
00695 
00696     if((ibuf->ftype & TIF_16BIT) && ibuf->rect_float)
00697         bitspersample = 16;
00698     else
00699         bitspersample = 8;
00700 
00701     /* open TIFF file for writing */
00702     if(flags & IB_mem) {
00703         /* bork at the creation of a TIFF in memory */
00704         fprintf(stderr,
00705             "imb_savetiff: creation of in-memory TIFF files is " 
00706             "not yet supported.\n");
00707         return (0);
00708     }
00709     else {
00710         /* create image as a file */
00711         image = TIFFOpen(name, "w");
00712     }
00713     if(image == NULL) {
00714         fprintf(stderr,
00715             "imb_savetiff: could not open TIFF for writing.\n");
00716         return (0);
00717     }
00718 
00719     /* allocate array for pixel data */
00720     npixels = ibuf->x * ibuf->y;
00721     if(bitspersample == 16)
00722         pixels16 = (unsigned short*)_TIFFmalloc(npixels *
00723             samplesperpixel * sizeof(unsigned short));
00724     else
00725         pixels = (unsigned char*)_TIFFmalloc(npixels *
00726             samplesperpixel * sizeof(unsigned char));
00727 
00728     if(pixels == NULL && pixels16 == NULL) {
00729         fprintf(stderr,
00730             "imb_savetiff: could not allocate pixels array.\n");
00731         TIFFClose(image);
00732         return (0);
00733     }
00734 
00735     /* setup pointers */
00736     if(bitspersample == 16) {
00737         fromf = ibuf->rect_float;
00738         to16   = pixels16;
00739     }
00740     else {
00741         from = (unsigned char*)ibuf->rect;
00742         to   = pixels;
00743     }
00744 
00745     /* setup samples per pixel */
00746     TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample);
00747     TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
00748 
00749     if(samplesperpixel == 4) {
00750         /* RGBA images */
00751         TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1,
00752                 extraSampleTypes);
00753         TIFFSetField(image, TIFFTAG_PHOTOMETRIC, 
00754                 PHOTOMETRIC_RGB);
00755     }
00756     else if(samplesperpixel == 3) {
00757         /* RGB images */
00758         TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
00759                 PHOTOMETRIC_RGB);
00760     }
00761     else if(samplesperpixel == 1) {
00762         /* greyscale images, 1 channel */
00763         TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
00764                 PHOTOMETRIC_MINISBLACK);
00765     }
00766 
00767     /* copy pixel data.  While copying, we flip the image vertically. */
00768     for(x = 0; x < ibuf->x; x++) {
00769         for(y = 0; y < ibuf->y; y++) {
00770             from_i = 4*(y*ibuf->x+x);
00771             to_i   = samplesperpixel*((ibuf->y-y-1)*ibuf->x+x);
00772 
00773             if(pixels16) {
00774                 /* convert from float source */
00775                 float rgb[3];
00776                 
00777                 if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
00778                     linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
00779                 else
00780                     copy_v3_v3(rgb, &fromf[from_i]);
00781 
00782                 to16[to_i+0] = FTOUSHORT(rgb[0]);
00783                 to16[to_i+1] = FTOUSHORT(rgb[1]);
00784                 to16[to_i+2] = FTOUSHORT(rgb[2]);
00785                 to_i += 3; from_i+=3;
00786                 
00787                 if (samplesperpixel == 4) {
00788                     to16[to_i+3] = FTOUSHORT(fromf[from_i+3]);
00789                     /*to_i++; from_i++;*/ /*unused, set on each loop */
00790                 }
00791             }
00792             else {
00793                 for(i = 0; i < samplesperpixel; i++, to_i++, from_i++)
00794                     to[to_i] = from[from_i];
00795             }
00796         }
00797     }
00798 
00799     /* write the actual TIFF file */
00800     TIFFSetField(image, TIFFTAG_IMAGEWIDTH,      ibuf->x);
00801     TIFFSetField(image, TIFFTAG_IMAGELENGTH,     ibuf->y);
00802     TIFFSetField(image, TIFFTAG_ROWSPERSTRIP,    ibuf->y);
00803     TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
00804     TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
00805     TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00806 
00807 
00808     if(ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
00809         xres= (float)(ibuf->ppm[0] * 0.0254);
00810         yres= (float)(ibuf->ppm[1] * 0.0254);
00811     }
00812     else {
00813         xres= yres= 150.0f;
00814     }
00815 
00816     TIFFSetField(image, TIFFTAG_XRESOLUTION,     xres);
00817     TIFFSetField(image, TIFFTAG_YRESOLUTION,     yres);
00818     TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT,  RESUNIT_INCH);
00819     if(TIFFWriteEncodedStrip(image, 0,
00820             (bitspersample == 16)? (unsigned char*)pixels16: pixels,
00821             ibuf->x*ibuf->y*samplesperpixel*bitspersample/8) == -1) {
00822         fprintf(stderr,
00823             "imb_savetiff: Could not write encoded TIFF.\n");
00824         TIFFClose(image);
00825         if(pixels) _TIFFfree(pixels);
00826         if(pixels16) _TIFFfree(pixels16);
00827         return (1);
00828     }
00829 
00830     /* close the TIFF file */
00831     TIFFClose(image);
00832     if(pixels) _TIFFfree(pixels);
00833     if(pixels16) _TIFFfree(pixels16);
00834     return (1);
00835 }