- use %u rather tham %d for unsigned ints in string formatting funcs.
[blender.git] / source / blender / imbuf / intern / tiff.c
index 99f74fea640399ca007918161bb2f65e31fb5e4e..7beb853fe62ba0fc58cef0809766f22d2d3ed86a 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/imbuf/intern/tiff.c
+ *  \ingroup imbuf
+ */
+
+
 /**
  * Provides TIFF file loading and saving for Blender, via libtiff.
  *
 #include <string.h>
 
 #include "imbuf.h"
-#include "BKE_global.h"
-#include "BKE_utildefines.h"
 
 #include "BLI_math.h"
 #include "BLI_string.h"
+#include "BLI_utildefines.h"
+#include "BKE_global.h"
+
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
@@ -93,11 +99,18 @@ typedef struct ImbTIFFMemFile {
 
 static void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
 {
+       (void)fd;
+       (void)base;
+       (void)size;
 }
 
 static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) 
 {
-                       return (0);
+       (void)fd;
+       (void)pbase;
+       (void)psize;
+
+       return (0);
 }
 
 /**
@@ -154,6 +167,10 @@ 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)
 {
+       (void)handle;
+       (void)data;
+       (void)n;
+       
        printf("imb_tiff_WriteProc: this function should not be called.\n");
        return (-1);
 }
@@ -262,7 +279,7 @@ static 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)
+static TIFF *imb_tiff_client_open(ImbTIFFMemFile *memFile, unsigned char *mem, size_t size)
 {
        /* open the TIFF client layer interface to the in-memory file */
        memFile->mem = mem;
@@ -301,17 +318,6 @@ int imb_is_a_tiff(unsigned char *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;
@@ -330,17 +336,10 @@ static void scanline_contig_32bit(float *rectf, float *fbuf, int scanline_w, int
                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;
+               rectf[i*4 + 3] = (spp==4)?fbuf[i*spp + 3]:1.0f;
        }
 }
 
-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;
@@ -355,40 +354,25 @@ static void scanline_separate_32bit(float *rectf, float *fbuf, int 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)
+static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image)
 {
-       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;
-       }
+       uint16 unit;
+       float xres;
+       float yres;
 
-       /* assign rect last */
-       ibuf->rect= tmpibuf->rect;
-       ibuf->mall |= IB_rect;
-       ibuf->flags |= IB_rect;
+       TIFFGetFieldDefaulted(image, TIFFTAG_RESOLUTIONUNIT, &unit);
+       TIFFGetFieldDefaulted(image, TIFFTAG_XRESOLUTION, &xres);
+       TIFFGetFieldDefaulted(image, TIFFTAG_YRESOLUTION, &yres);
 
-       tmpibuf->mall &= ~IB_rect;
-       IMB_freeImBuf(tmpibuf);
-
-       return success;
+       if(unit == RESUNIT_CENTIMETER) {
+               ibuf->ppm[0]= (double)xres * 100.0;
+               ibuf->ppm[1]= (double)yres * 100.0;
+       }
+       else {
+               ibuf->ppm[0]= (double)xres / 0.0254;
+               ibuf->ppm[1]= (double)yres / 0.0254;
+       }
 }
-#endif
 
 /* 
  * Use the libTIFF scanline API to read a TIFF image.
@@ -398,17 +382,19 @@ static int imb_read_tiff_pixels_rgba(ImBuf *ibuf, TIFF *image, int premul)
 static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
 {
        ImBuf *tmpibuf;
-       int success;
+       int success= 0;
        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);
+
+       imb_read_tiff_resolution(ibuf, image);
+
        scanline = TIFFScanlineSize(image);
        
        if (bitspersample == 32) {
@@ -417,30 +403,28 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
        } else if (bitspersample == 16) {
                ib_flag = IB_rectfloat;
                sbuf = (unsigned short *)_TIFFmalloc(scanline);
-       } else if (bitspersample == 8) {
+       } else {
                ib_flag = IB_rect;
-               cbuf = (unsigned char *)_TIFFmalloc(scanline);
        }
        
-       tmpibuf= IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->depth, ib_flag, 0);
+       tmpibuf= IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->depth, ib_flag);
        
+       /* simple RGBA image */
+       if (!(bitspersample == 32 || bitspersample == 16)) {
+               success |= TIFFReadRGBAImage(image, ibuf->x, ibuf->y, tmpibuf->rect, 0);
+       }
        /* contiguous channels: RGBRGBRGB */
-       if (config == PLANARCONFIG_CONTIG) {
+       else 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);
+                               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);
+                               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 */
@@ -456,53 +440,49 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
                                        if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
                                                memset(fbuf, 1.0, sizeof(fbuf));
                                        else
-                                               success = TIFFReadScanline(image, fbuf, row, chan);
+                                               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);
+                                               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(success) {
+               ibuf->profile = (bitspersample==32)?IB_PROFILE_LINEAR_RGB:IB_PROFILE_SRGB;
+
+//             Code seems to be not needed for 16 bits tif, on PPC G5 OSX (ton)
+               if(bitspersample < 16)
+                       if(ENDIAN_ORDER == B_ENDIAN)
+                               IMB_convert_rgba_to_abgr(tmpibuf);
+               if(premul) {
+                       IMB_premultiply_alpha(tmpibuf);
+                       ibuf->flags |= IB_premul;
+               }
                
-       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;
        }
-       
-       /* 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;
@@ -525,7 +505,7 @@ void imb_inittiff(void)
  *
  * @return: A newly allocated ImBuf structure if successful, otherwise NULL.
  */
-ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
+ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags)
 {
        TIFF *image = NULL;
        ImBuf *ibuf = NULL, *hbuf;
@@ -558,7 +538,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
        
        ib_depth = (spp==3)?24:32;
        
-       ibuf = IMB_allocImBuf(width, height, ib_depth, 0, 0);
+       ibuf = IMB_allocImBuf(width, height, ib_depth, 0);
        if(ibuf) {
                ibuf->ftype = TIF;
        }
@@ -594,7 +574,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
                                        width= (width > 1)? width/2: 1;
                                        height= (height > 1)? height/2: 1;
 
-                                       hbuf= IMB_allocImBuf(width, height, 32, 0, 0);
+                                       hbuf= IMB_allocImBuf(width, height, 32, 0);
                                        hbuf->miplevel= level;
                                        hbuf->ftype= ibuf->ftype;
                                        ibuf->mipmap[level-1] = hbuf;
@@ -634,7 +614,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
        return ibuf;
 }
 
-void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, int size, int tx, int ty, unsigned int *rect)
+void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect)
 {
        TIFF *image = NULL;
        uint32 width, height;
@@ -647,8 +627,7 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, int size, int tx, int ty,
                return;
        }
 
-       if(TIFFSetDirectory(image, ibuf->miplevel)) {
-               /* allocate the image buffer */
+       if(TIFFSetDirectory(image, ibuf->miplevel)) { /* allocate the image buffer */
                TIFFGetField(image, TIFFTAG_IMAGEWIDTH,  &width);
                TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
 
@@ -667,7 +646,7 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, int size, int tx, int ty,
                        }
                }
                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);
+                       printf("imb_loadtiff: mipmap level %d has unexpected size %ux%u 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);
@@ -692,7 +671,7 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, int size, int tx, int ty,
  * @return: 1 if the function is successful, 0 on failure.
  */
 
-int imb_savetiff(ImBuf *ibuf, char *name, int flags)
+int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
 {
        TIFF *image = NULL;
        uint16 samplesperpixel, bitspersample;
@@ -701,6 +680,7 @@ int imb_savetiff(ImBuf *ibuf, char *name, int flags)
        unsigned char *from = NULL, *to = NULL;
        unsigned short *pixels16 = NULL, *to16 = NULL;
        float *fromf = NULL;
+       float xres, yres;
        int x, y, from_i, to_i, i;
        int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA };
        
@@ -809,7 +789,7 @@ int imb_savetiff(ImBuf *ibuf, char *name, int flags)
                                
                                if (samplesperpixel == 4) {
                                        to16[to_i+3] = FTOUSHORT(fromf[from_i+3]);
-                                       to_i++; from_i++;
+                                       /*to_i++; from_i++;*/ /*unused, set on each loop */
                                }
                        }
                        else {
@@ -826,8 +806,18 @@ int imb_savetiff(ImBuf *ibuf, char *name, int flags)
        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);
+
+
+       if(ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
+               xres= (float)(ibuf->ppm[0] * 0.0254);
+               yres= (float)(ibuf->ppm[1] * 0.0254);
+       }
+       else {
+               xres= yres= 150.0f;
+       }
+
+       TIFFSetField(image, TIFFTAG_XRESOLUTION,     xres);
+       TIFFSetField(image, TIFFTAG_YRESOLUTION,     yres);
        TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT,  RESUNIT_INCH);
        if(TIFFWriteEncodedStrip(image, 0,
                        (bitspersample == 16)? (unsigned char*)pixels16: pixels,
@@ -847,4 +837,4 @@ int imb_savetiff(ImBuf *ibuf, char *name, int flags)
        return (1);
 }
 
-#endif /* WITH_TIFF */
\ No newline at end of file
+#endif /* WITH_TIFF */