diff options
Diffstat (limited to 'source/blender/imbuf/intern/tiff.c')
-rw-r--r-- | source/blender/imbuf/intern/tiff.c | 593 |
1 files changed, 434 insertions, 159 deletions
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 7ee31ff7d9a..99f74fea640 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -40,21 +40,26 @@ * used to compress images. */ +#ifdef WITH_TIFF + #include <string.h> #include "imbuf.h" -#include "imbuf_patch.h" - + #include "BKE_global.h" +#include "BKE_utildefines.h" + +#include "BLI_math.h" +#include "BLI_string.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_allocimbuf.h" -#include "IMB_cmap.h" -#include "IMB_tiff.h" +#include "IMB_filetype.h" +#include "IMB_filter.h" -#include "dynlibtiff.h" +#include "tiffio.h" @@ -62,22 +67,22 @@ * Local declarations. * ***********************/ /* Reading and writing of an in-memory TIFF file. */ -tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n); -tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n); -toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence); -int imb_tiff_CloseProc(thandle_t handle); -toff_t imb_tiff_SizeProc(thandle_t handle); -int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize); -void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size); +static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n); +static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n); +static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence); +static int imb_tiff_CloseProc(thandle_t handle); +static toff_t imb_tiff_SizeProc(thandle_t handle); +static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize); +static void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size); /* Structure for in-memory TIFF file. */ -struct ImbTIFFMemFile { +typedef struct ImbTIFFMemFile { unsigned char *mem; /* Location of first byte of TIFF file. */ toff_t offset; /* Current offset within the file. */ tsize_t size; /* Size of the TIFF file. */ -}; -#define IMB_TIFF_GET_MEMFILE(x) ((struct ImbTIFFMemFile*)(x)); +} ImbTIFFMemFile; +#define IMB_TIFF_GET_MEMFILE(x) ((ImbTIFFMemFile*)(x)); @@ -86,13 +91,13 @@ struct ImbTIFFMemFile { *****************************/ -void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) +static void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) { } -int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) { - return (0); + return (0); } /** @@ -105,31 +110,31 @@ int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) * @return: Number of bytes actually read. * 0 = EOF. */ -tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) +static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) { tsize_t nRemaining, nCopy; - struct ImbTIFFMemFile* mfile; + ImbTIFFMemFile* mfile; void *srcAddr; /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - if (!mfile || !mfile->mem) { + if(!mfile || !mfile->mem) { fprintf(stderr, "imb_tiff_ReadProc: !mfile || !mfile->mem!\n"); return 0; } /* find the actual number of bytes to read (copy) */ nCopy = n; - if ((tsize_t)mfile->offset >= mfile->size) + if((tsize_t)mfile->offset >= mfile->size) nRemaining = 0; else nRemaining = mfile->size - mfile->offset; - if (nCopy > nRemaining) + if(nCopy > nRemaining) nCopy = nRemaining; /* on EOF, return immediately and read (copy) nothing */ - if (nCopy <= 0) + if(nCopy <= 0) return (0); /* all set -> do the read (copy) */ @@ -147,7 +152,7 @@ tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) * NOTE: The current Blender implementation should not need this function. It * is simply a stub. */ -tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n) +static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n) { printf("imb_tiff_WriteProc: this function should not be called.\n"); return (-1); @@ -169,14 +174,14 @@ tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n) * @return: Resulting offset location within the file, measured in bytes from * the beginning of the file. (-1) indicates an error. */ -toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) +static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) { - struct ImbTIFFMemFile *mfile; + ImbTIFFMemFile *mfile; toff_t new_offset; /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - if (!mfile || !mfile->mem) { + if(!mfile || !mfile->mem) { fprintf(stderr, "imb_tiff_SeekProc: !mfile || !mfile->mem!\n"); return (-1); } @@ -216,13 +221,13 @@ toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) * * @return: 0 */ -int imb_tiff_CloseProc(thandle_t handle) +static int imb_tiff_CloseProc(thandle_t handle) { - struct ImbTIFFMemFile *mfile; + ImbTIFFMemFile *mfile; /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - if (!mfile || !mfile->mem) { + if(!mfile || !mfile->mem) { fprintf(stderr,"imb_tiff_CloseProc: !mfile || !mfile->mem!\n"); return (0); } @@ -242,13 +247,13 @@ int imb_tiff_CloseProc(thandle_t handle) * * @return: Size of file (in bytes). */ -toff_t imb_tiff_SizeProc(thandle_t handle) +static toff_t imb_tiff_SizeProc(thandle_t handle) { - struct ImbTIFFMemFile* mfile; + ImbTIFFMemFile* mfile; /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - if (!mfile || !mfile->mem) { + if(!mfile || !mfile->mem) { fprintf(stderr,"imb_tiff_SizeProc: !mfile || !mfile->mem!\n"); return (0); } @@ -257,14 +262,23 @@ toff_t imb_tiff_SizeProc(thandle_t handle) return (toff_t)(mfile->size); } +static TIFF *imb_tiff_client_open(ImbTIFFMemFile *memFile, unsigned char *mem, int size) +{ + /* open the TIFF client layer interface to the in-memory file */ + memFile->mem = mem; + memFile->offset = 0; + memFile->size = size; + return TIFFClientOpen("(Blender TIFF Interface Layer)", + "r", (thandle_t)(memFile), + imb_tiff_ReadProc, imb_tiff_WriteProc, + imb_tiff_SeekProc, imb_tiff_CloseProc, + imb_tiff_SizeProc, imb_tiff_DummyMapProc, imb_tiff_DummyUnmapProc); +} /** * Checks whether a given memory buffer contains a TIFF file. * - * FIXME: Possible memory leak if mem is less than IMB_TIFF_NCB bytes long. - * However, changing this will require up-stream modifications. - * * This method uses the format identifiers from: * http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-9.html * The first four bytes of big-endian and little-endian TIFF files @@ -278,7 +292,7 @@ toff_t imb_tiff_SizeProc(thandle_t handle) * hence my manual comparison. - Jonathan Merritt (lancelet) 4th Sept 2005. */ #define IMB_TIFF_NCB 4 /* number of comparison bytes used */ -int imb_is_a_tiff(void *mem) +int imb_is_a_tiff(unsigned char *mem) { char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a }; char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 }; @@ -287,14 +301,222 @@ int imb_is_a_tiff(void *mem) (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) ); } +static void scanline_contig_8bit(unsigned char *rect, unsigned char *cbuf, int scanline_w, int spp) +{ + int i; + for (i=0; i < scanline_w; i++) { + rect[i*4 + 0] = cbuf[i*spp + 0]; + rect[i*4 + 1] = cbuf[i*spp + 1]; + rect[i*4 + 2] = cbuf[i*spp + 2]; + rect[i*4 + 3] = (spp==4)?cbuf[i*spp + 3]:255; + } +} +static void scanline_contig_16bit(float *rectf, unsigned short *sbuf, int scanline_w, int spp) +{ + int i; + for (i=0; i < scanline_w; i++) { + rectf[i*4 + 0] = sbuf[i*spp + 0] / 65535.0; + rectf[i*4 + 1] = sbuf[i*spp + 1] / 65535.0; + rectf[i*4 + 2] = sbuf[i*spp + 2] / 65535.0; + rectf[i*4 + 3] = (spp==4)?(sbuf[i*spp + 3] / 65535.0):1.0; + } +} -/** - * Loads a TIFF file. - * +static void scanline_contig_32bit(float *rectf, float *fbuf, int scanline_w, int spp) +{ + int i; + for (i=0; i < scanline_w; i++) { + rectf[i*4 + 0] = fbuf[i*spp + 0]; + rectf[i*4 + 1] = fbuf[i*spp + 1]; + rectf[i*4 + 2] = fbuf[i*spp + 2]; + rectf[i*4 + 3] = (spp==4)?fbuf[i*spp + 3]:1.0; + } +} + +static void scanline_separate_8bit(unsigned char *rect, unsigned char *cbuf, int scanline_w, int chan) +{ + int i; + for (i=0; i < scanline_w; i++) + rect[i*4 + chan] = cbuf[i]; +} + +static void scanline_separate_16bit(float *rectf, unsigned short *sbuf, int scanline_w, int chan) +{ + int i; + for (i=0; i < scanline_w; i++) + rectf[i*4 + chan] = sbuf[i] / 65535.0; +} + +static void scanline_separate_32bit(float *rectf, float *fbuf, int scanline_w, int chan) +{ + int i; + for (i=0; i < scanline_w; i++) + rectf[i*4 + chan] = fbuf[i]; +} + + +#if 0 +/* + * Use the libTIFF RGBAImage API to read a TIFF image. * This function uses the "RGBA Image" support from libtiff, which enables * it to load most commonly-encountered TIFF formats. libtiff handles format * conversion, color depth conversion, etc. + */ +static int imb_read_tiff_pixels_rgba(ImBuf *ibuf, TIFF *image, int premul) +{ + ImBuf *tmpibuf; + int success; + + tmpibuf= IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect, 0); + success= TIFFReadRGBAImage(image, ibuf->x, ibuf->y, tmpibuf->rect, 0); + + if(ENDIAN_ORDER == B_ENDIAN) + IMB_convert_rgba_to_abgr(tmpibuf); + if(premul) { + IMB_premultiply_alpha(tmpibuf); + ibuf->flags |= IB_premul; + } + + /* assign rect last */ + ibuf->rect= tmpibuf->rect; + ibuf->mall |= IB_rect; + ibuf->flags |= IB_rect; + + tmpibuf->mall &= ~IB_rect; + IMB_freeImBuf(tmpibuf); + + return success; +} +#endif + +/* + * Use the libTIFF scanline API to read a TIFF image. + * This method is most flexible and can handle multiple different bit depths + * and RGB channel orderings. + */ +static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) +{ + ImBuf *tmpibuf; + int success; + short bitspersample, spp, config; + size_t scanline; + int ib_flag=0, row, chan; + float *fbuf=NULL; + unsigned short *sbuf=NULL; + unsigned char *cbuf=NULL; + + TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); /* number of 'channels' */ + TIFFGetField(image, TIFFTAG_PLANARCONFIG, &config); + scanline = TIFFScanlineSize(image); + + if (bitspersample == 32) { + ib_flag = IB_rectfloat; + fbuf = (float *)_TIFFmalloc(scanline); + } else if (bitspersample == 16) { + ib_flag = IB_rectfloat; + sbuf = (unsigned short *)_TIFFmalloc(scanline); + } else if (bitspersample == 8) { + ib_flag = IB_rect; + cbuf = (unsigned char *)_TIFFmalloc(scanline); + } + + tmpibuf= IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->depth, ib_flag, 0); + + /* contiguous channels: RGBRGBRGB */ + if (config == PLANARCONFIG_CONTIG) { + for (row = 0; row < ibuf->y; row++) { + int ib_offset = ibuf->x*ibuf->y*4 - ibuf->x*4 * (row+1); + + if (bitspersample == 32) { + success = TIFFReadScanline(image, fbuf, row, 0); + scanline_contig_32bit(tmpibuf->rect_float+ib_offset, fbuf, ibuf->x, spp); + + } else if (bitspersample == 16) { + success = TIFFReadScanline(image, sbuf, row, 0); + scanline_contig_16bit(tmpibuf->rect_float+ib_offset, sbuf, ibuf->x, spp); + + } else if (bitspersample == 8) { + unsigned char *crect = (unsigned char*)tmpibuf->rect; + success = TIFFReadScanline(image, cbuf, row, 0); + scanline_contig_8bit(crect+ib_offset, cbuf, ibuf->x, spp); + } + } + /* separate channels: RRRGGGBBB */ + } else if (config == PLANARCONFIG_SEPARATE) { + + /* imbufs always have 4 channels of data, so we iterate over all of them + * but only fill in from the TIFF scanline where necessary. */ + for (chan = 0; chan < 4; chan++) { + for (row = 0; row < ibuf->y; row++) { + int ib_offset = ibuf->x*ibuf->y*4 - ibuf->x*4 * (row+1); + + if (bitspersample == 32) { + if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */ + memset(fbuf, 1.0, sizeof(fbuf)); + else + success = TIFFReadScanline(image, fbuf, row, chan); + scanline_separate_32bit(tmpibuf->rect_float+ib_offset, fbuf, ibuf->x, chan); + + } else if (bitspersample == 16) { + if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */ + memset(sbuf, 65535, sizeof(sbuf)); + else + success = TIFFReadScanline(image, sbuf, row, chan); + scanline_separate_16bit(tmpibuf->rect_float+ib_offset, sbuf, ibuf->x, chan); + + } else if (bitspersample == 8) { + unsigned char *crect = (unsigned char*)tmpibuf->rect; + if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */ + memset(cbuf, 255, sizeof(cbuf)); + else + success = TIFFReadScanline(image, cbuf, row, chan); + scanline_separate_8bit(crect+ib_offset, cbuf, ibuf->x, chan); + } + } + } + } + + ibuf->profile = (bitspersample==32)?IB_PROFILE_LINEAR_RGB:IB_PROFILE_SRGB; + + if (bitspersample == 32) + _TIFFfree(fbuf); + else if (bitspersample == 16) + _TIFFfree(sbuf); + else if (bitspersample == 8) + _TIFFfree(cbuf); + + if(ENDIAN_ORDER == B_ENDIAN) + IMB_convert_rgba_to_abgr(tmpibuf); + if(premul) { + IMB_premultiply_alpha(tmpibuf); + ibuf->flags |= IB_premul; + } + + /* assign rect last */ + if (tmpibuf->rect_float) + ibuf->rect_float= tmpibuf->rect_float; + else + ibuf->rect= tmpibuf->rect; + ibuf->mall |= ib_flag; + ibuf->flags |= ib_flag; + + tmpibuf->mall &= ~ib_flag; + IMB_freeImBuf(tmpibuf); + + return success; +} + +void imb_inittiff(void) +{ + if (!(G.f & G_DEBUG)) + TIFFSetErrorHandler(NULL); +} + +/** + * Loads a TIFF file. + * * * @param mem: Memory containing the TIFF file. * @param size: Size of the mem buffer. @@ -303,118 +525,155 @@ int imb_is_a_tiff(void *mem) * * @return: A newly allocated ImBuf structure if successful, otherwise NULL. */ -struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) +ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) { TIFF *image = NULL; - struct ImBuf *ibuf = NULL; - struct ImbTIFFMemFile memFile; + ImBuf *ibuf = NULL, *hbuf; + ImbTIFFMemFile memFile; uint32 width, height; - int bytesperpixel, bitspersample; - int success; - unsigned int pixel_i, byte_i; - uint32 *raster = NULL; - uint32 pixel; - unsigned char *to = NULL; - - memFile.mem = mem; - memFile.offset = 0; - memFile.size = size; + char *format = NULL; + int level; + short spp; + int ib_depth; /* check whether or not we have a TIFF file */ - if (size < IMB_TIFF_NCB) { + if(size < IMB_TIFF_NCB) { fprintf(stderr, "imb_loadtiff: size < IMB_TIFF_NCB\n"); return NULL; } - if (imb_is_a_tiff(mem) == 0) + if(imb_is_a_tiff(mem) == 0) return NULL; - /* open the TIFF client layer interface to the in-memory file */ - image = libtiff_TIFFClientOpen("(Blender TIFF Interface Layer)", - "r", (thandle_t)(&memFile), - imb_tiff_ReadProc, imb_tiff_WriteProc, - imb_tiff_SeekProc, imb_tiff_CloseProc, - imb_tiff_SizeProc, imb_tiff_DummyMapProc, imb_tiff_DummyUnmapProc); - if (image == NULL) { + image = imb_tiff_client_open(&memFile, mem, size); + + if(image == NULL) { printf("imb_loadtiff: could not open TIFF IO layer.\n"); return NULL; } /* allocate the image buffer */ - bytesperpixel = 4; /* 1 byte per channel, 4 channels */ - libtiff_TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); - libtiff_TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); - libtiff_TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample); - ibuf = IMB_allocImBuf(width, height, 8*bytesperpixel, 0, 0); - if (ibuf) { + TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); + TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); + + ib_depth = (spp==3)?24:32; + + ibuf = IMB_allocImBuf(width, height, ib_depth, 0, 0); + if(ibuf) { ibuf->ftype = TIF; - ibuf->profile = IB_PROFILE_SRGB; - } else { + } + else { fprintf(stderr, "imb_loadtiff: could not allocate memory for TIFF " \ "image.\n"); - libtiff_TIFFClose(image); + TIFFClose(image); return NULL; } - /* read in the image data */ - if (!(flags & IB_test)) { + /* if testing, we're done */ + if(flags & IB_test) { + TIFFClose(image); + return ibuf; + } - /* allocate memory for the ibuf->rect */ - imb_addrectImBuf(ibuf); + /* detect if we are reading a tiled/mipmapped texture, in that case + we don't read pixels but leave it to the cache to load tiles */ + if(flags & IB_tilecache) { + format= NULL; + TIFFGetField(image, TIFFTAG_PIXAR_TEXTUREFORMAT, &format); - /* perform actual read */ - raster = (uint32*)libtiff__TIFFmalloc( - width*height * sizeof(uint32)); - if (raster == NULL) { - libtiff_TIFFClose(image); - return NULL; - } - success = libtiff_TIFFReadRGBAImage( - image, width, height, raster, 0); - if (!success) { - fprintf(stderr, - "imb_loadtiff: This TIFF format is not " - "currently supported by Blender.\n"); - libtiff__TIFFfree(raster); - libtiff_TIFFClose(image); - return NULL; - } + if(format && strcmp(format, "Plain Texture")==0 && TIFFIsTiled(image)) { + int numlevel = TIFFNumberOfDirectories(image); - /* copy raster to ibuf->rect; we do a fast copy if possible, - * otherwise revert to a slower component-wise copy */ - if (sizeof(unsigned int) == sizeof(uint32)) { - memcpy(ibuf->rect, raster, - width*height*sizeof(uint32)); - } else { - /* this may not be entirely necessary, but is put here - * in case sizeof(unsigned int) is not a 32-bit - * quantity */ - fprintf(stderr, - "imb_loadtiff: using (slower) component-wise " - "buffer copy.\n"); - to = (unsigned char*)ibuf->rect; - for (pixel_i=0; pixel_i < width*height; pixel_i++) - { - byte_i = sizeof(unsigned int)*pixel_i; - pixel = raster[pixel_i]; - - to[byte_i++] = (unsigned char)TIFFGetR(pixel); - to[byte_i++] = (unsigned char)TIFFGetG(pixel); - to[byte_i++] = (unsigned char)TIFFGetB(pixel); - to[byte_i++] = (unsigned char)TIFFGetA(pixel); + /* create empty mipmap levels in advance */ + for(level=0; level<numlevel; level++) { + if(!TIFFSetDirectory(image, level)) + break; + + if(level > 0) { + width= (width > 1)? width/2: 1; + height= (height > 1)? height/2: 1; + + hbuf= IMB_allocImBuf(width, height, 32, 0, 0); + hbuf->miplevel= level; + hbuf->ftype= ibuf->ftype; + ibuf->mipmap[level-1] = hbuf; + + if(flags & IB_premul) + hbuf->flags |= IB_premul; + } + else + hbuf= ibuf; + + hbuf->flags |= IB_tilecache; + + TIFFGetField(image, TIFFTAG_TILEWIDTH, &hbuf->tilex); + TIFFGetField(image, TIFFTAG_TILELENGTH, &hbuf->tiley); + + hbuf->xtiles= ceil(hbuf->x/(float)hbuf->tilex); + hbuf->ytiles= ceil(hbuf->y/(float)hbuf->tiley); + + imb_addtilesImBuf(hbuf); + + ibuf->miptot++; } } + } - libtiff__TIFFfree(raster); + /* read pixels */ + if(!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image, 0)) { + fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n"); + TIFFClose(image); + return NULL; } /* close the client layer interface to the in-memory file */ - libtiff_TIFFClose(image); - - if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); + TIFFClose(image); /* return successfully */ - return (ibuf); + return ibuf; +} + +void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, int size, int tx, int ty, unsigned int *rect) +{ + TIFF *image = NULL; + uint32 width, height; + ImbTIFFMemFile memFile; + + image = imb_tiff_client_open(&memFile, mem, size); + + if(image == NULL) { + printf("imb_loadtiff: could not open TIFF IO layer for loading mipmap level.\n"); + return; + } + + if(TIFFSetDirectory(image, ibuf->miplevel)) { + /* allocate the image buffer */ + TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); + + if(width == ibuf->x && height == ibuf->y) { + if(rect) { + /* tiff pixels are bottom to top, tiles are top to bottom */ + if(TIFFReadRGBATile(image, tx*ibuf->tilex, (ibuf->ytiles - 1 - ty)*ibuf->tiley, rect) == 1) { + if(ibuf->tiley > ibuf->y) + memmove(rect, rect+ibuf->tilex*(ibuf->tiley - ibuf->y), sizeof(int)*ibuf->tilex*ibuf->y); + + if(ibuf->flags & IB_premul) + IMB_premultiply_rect(rect, 32, ibuf->tilex, ibuf->tiley); + } + else + printf("imb_loadtiff: failed to read tiff tile at mipmap level %d\n", ibuf->miplevel); + } + } + else + printf("imb_loadtiff: mipmap level %d has unexpected size %dx%d instead of %dx%d\n", ibuf->miplevel, width, height, ibuf->x, ibuf->y); + } + else + printf("imb_loadtiff: could not find mipmap level %d\n", ibuf->miplevel); + + /* close the client layer interface to the in-memory file */ + TIFFClose(image); } /** @@ -433,9 +692,7 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) * @return: 1 if the function is successful, 0 on failure. */ -#define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f)) - -short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) +int imb_savetiff(ImBuf *ibuf, char *name, int flags) { TIFF *image = NULL; uint16 samplesperpixel, bitspersample; @@ -446,12 +703,13 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) float *fromf = NULL; int x, y, from_i, to_i, i; int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA }; + /* check for a valid number of bytes per pixel. Like the PNG writer, * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding * to gray, RGB, RGBA respectively. */ samplesperpixel = (uint16)((ibuf->depth + 7) >> 3); - if ((samplesperpixel > 4) || (samplesperpixel == 2)) { + if((samplesperpixel > 4) || (samplesperpixel == 2)) { fprintf(stderr, "imb_savetiff: unsupported number of bytes per " "pixel: %d\n", samplesperpixel); @@ -464,17 +722,18 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) bitspersample = 8; /* open TIFF file for writing */ - if (flags & IB_mem) { + if(flags & IB_mem) { /* bork at the creation of a TIFF in memory */ fprintf(stderr, "imb_savetiff: creation of in-memory TIFF files is " "not yet supported.\n"); return (0); - } else { + } + else { /* create image as a file */ - image = libtiff_TIFFOpen(name, "w"); + image = TIFFOpen(name, "w"); } - if (image == NULL) { + if(image == NULL) { fprintf(stderr, "imb_savetiff: could not open TIFF for writing.\n"); return (0); @@ -483,16 +742,16 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) /* allocate array for pixel data */ npixels = ibuf->x * ibuf->y; if(bitspersample == 16) - pixels16 = (unsigned short*)libtiff__TIFFmalloc(npixels * + pixels16 = (unsigned short*)_TIFFmalloc(npixels * samplesperpixel * sizeof(unsigned short)); else - pixels = (unsigned char*)libtiff__TIFFmalloc(npixels * + pixels = (unsigned char*)_TIFFmalloc(npixels * samplesperpixel * sizeof(unsigned char)); - if (pixels == NULL && pixels16 == NULL) { + if(pixels == NULL && pixels16 == NULL) { fprintf(stderr, "imb_savetiff: could not allocate pixels array.\n"); - libtiff_TIFFClose(image); + TIFFClose(image); return (0); } @@ -507,69 +766,85 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) } /* setup samples per pixel */ - libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample); - libtiff_TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); + TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample); + TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); if(samplesperpixel == 4) { /* RGBA images */ - libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, + TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); - libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } else if(samplesperpixel == 3) { /* RGB images */ - libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } else if(samplesperpixel == 1) { /* greyscale images, 1 channel */ - libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); } /* copy pixel data. While copying, we flip the image vertically. */ - for (x = 0; x < ibuf->x; x++) { - for (y = 0; y < ibuf->y; y++) { + for(x = 0; x < ibuf->x; x++) { + for(y = 0; y < ibuf->y; y++) { from_i = 4*(y*ibuf->x+x); to_i = samplesperpixel*((ibuf->y-y-1)*ibuf->x+x); if(pixels16) { - for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) - to16[to_i] = FTOUSHORT(fromf[from_i]); + /* convert from float source */ + float rgb[3]; + + if (ibuf->profile == IB_PROFILE_LINEAR_RGB) + linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]); + else + copy_v3_v3(rgb, &fromf[from_i]); + + to16[to_i+0] = FTOUSHORT(rgb[0]); + to16[to_i+1] = FTOUSHORT(rgb[1]); + to16[to_i+2] = FTOUSHORT(rgb[2]); + to_i += 3; from_i+=3; + + if (samplesperpixel == 4) { + to16[to_i+3] = FTOUSHORT(fromf[from_i+3]); + to_i++; from_i++; + } } else { - for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) + for(i = 0; i < samplesperpixel; i++, to_i++, from_i++) to[to_i] = from[from_i]; } } } /* write the actual TIFF file */ - libtiff_TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x); - libtiff_TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y); - libtiff_TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y); - libtiff_TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); - libtiff_TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); - libtiff_TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - libtiff_TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0); - libtiff_TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0); - libtiff_TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - if (libtiff_TIFFWriteEncodedStrip(image, 0, + TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x); + TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y); + TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y); + TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); + TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); + TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0); + TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0); + TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); + if(TIFFWriteEncodedStrip(image, 0, (bitspersample == 16)? (unsigned char*)pixels16: pixels, ibuf->x*ibuf->y*samplesperpixel*bitspersample/8) == -1) { fprintf(stderr, "imb_savetiff: Could not write encoded TIFF.\n"); - libtiff_TIFFClose(image); - if(pixels) libtiff__TIFFfree(pixels); - if(pixels16) libtiff__TIFFfree(pixels16); + TIFFClose(image); + if(pixels) _TIFFfree(pixels); + if(pixels16) _TIFFfree(pixels16); return (1); } /* close the TIFF file */ - libtiff_TIFFClose(image); - if(pixels) libtiff__TIFFfree(pixels); - if(pixels16) libtiff__TIFFfree(pixels16); + TIFFClose(image); + if(pixels) _TIFFfree(pixels); + if(pixels16) _TIFFfree(pixels16); return (1); } +#endif /* WITH_TIFF */
\ No newline at end of file |