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