Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2010-05-07 19:18:04 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2010-05-07 19:18:04 +0400
commit008863daec1249d1f17bc69e1105e336db690d63 (patch)
tree78a4001857b26a287125a3f5fa31496052f6ebdd /source/blender/imbuf/intern/tiff.c
parent1613829e8e821321da99cad4790b7e6a1d90cea8 (diff)
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine. Imbuf module: some small refactoring and removing a lot of unused or old code (about 6.5k lines). * Added a ImFileType struct with callbacks to make adding an file format type, or making changes to the API easier. * Move imbuf init/exit code into IMB_init()/IMB_exit() functions. * Increased mipmap levels from 10 to 20, you run into this limit already with a 2k image. * Removed hamx, amiga, anim5 format support. * Removed colormap saving, only simple colormap code now for reading tga. * Removed gen_dynlibtiff.py, editing this is almost as much work as just editing the code directly. * Functions removed that were only used for sequencer plugin API: IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp, IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace, IMB_dit0, IMB_dit2, IMB_cspace * Write metadata info into OpenEXR images. Can be viewed with the command line utility 'exrheader' For the image tile cache code, see this page: http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
Diffstat (limited to 'source/blender/imbuf/intern/tiff.c')
-rw-r--r--source/blender/imbuf/intern/tiff.c284
1 files changed, 179 insertions, 105 deletions
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index dd18c77c5c6..e7309eefb56 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -43,16 +43,17 @@
#include <string.h>
#include "imbuf.h"
-#include "imbuf_patch.h"
#include "BKE_global.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"
@@ -72,12 +73,12 @@ 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));
@@ -108,28 +109,28 @@ static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
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) */
@@ -171,12 +172,12 @@ 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)
{
- 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);
}
@@ -218,11 +219,11 @@ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
*/
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);
}
@@ -244,11 +245,11 @@ static int imb_tiff_CloseProc(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 +258,23 @@ 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)
+{
+ /* open the TIFF client layer interface to the in-memory file */
+ memFile->mem = mem;
+ memFile->offset = 0;
+ memFile->size = size;
+ return 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);
+}
/**
* 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 +288,7 @@ static 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,7 +297,31 @@ int imb_is_a_tiff(void *mem)
(memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) );
}
+static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
+{
+ ImBuf *tmpibuf;
+ int success;
+
+ tmpibuf= IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect, 0);
+ success= libtiff_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;
+}
/**
* Loads a TIFF file.
@@ -303,52 +337,42 @@ 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;
+ char *format = NULL;
+ int level;
- memFile.mem = mem;
- memFile.offset = 0;
- memFile.size = size;
+ if(!G.have_libtiff)
+ return NULL;
/* 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) {
+ ibuf = IMB_allocImBuf(width, height, 32, 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");
@@ -356,65 +380,109 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
return NULL;
}
- /* read in the image data */
- if (!(flags & IB_test)) {
+ /* if testing, we're done */
+ if(flags & IB_test) {
+ libtiff_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;
+ libtiff_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 && libtiff_TIFFIsTiled(image)) {
+ int numlevel = libtiff_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(!libtiff_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->flags |= IB_tilecache;
+ hbuf->ftype= ibuf->ftype;
+ ibuf->mipmap[level-1] = hbuf;
+
+ if(flags & IB_premul)
+ hbuf->flags |= IB_premul;
+ }
+ else
+ hbuf= ibuf;
+
+ libtiff_TIFFGetField(image, TIFFTAG_TILEWIDTH, &hbuf->tilex);
+ libtiff_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");
+ libtiff_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);
-
/* 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(libtiff_TIFFSetDirectory(image, ibuf->miplevel)) {
+ /* allocate the image buffer */
+ libtiff_TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width);
+ libtiff_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(libtiff_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 */
+ libtiff_TIFFClose(image);
}
/**
@@ -435,7 +503,7 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
#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 +514,17 @@ 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 };
+
+ if(!G.have_libtiff) {
+ fprintf(stderr, "imb_savetiff: no tiff library available.\n");
+ return (0);
+ }
/* 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 +537,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");
}
- if (image == NULL) {
+ if(image == NULL) {
fprintf(stderr,
"imb_savetiff: could not open TIFF for writing.\n");
return (0);
@@ -489,7 +563,7 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
pixels = (unsigned char*)libtiff__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);
@@ -529,17 +603,17 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
}
/* 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++)
+ for(i = 0; i < samplesperpixel; i++, to_i++, from_i++)
to16[to_i] = FTOUSHORT(fromf[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];
}
}
@@ -555,7 +629,7 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
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,
+ if(libtiff_TIFFWriteEncodedStrip(image, 0,
(bitspersample == 16)? (unsigned char*)pixels16: pixels,
ibuf->x*ibuf->y*samplesperpixel*bitspersample/8) == -1) {
fprintf(stderr,