37 #define ERR_NO_ERROR 0
41 #define ERR_UNSUPPORTED 4
43 #define ERR_OPEN_WRITE 6
53 strncpy(buffer,
"TIFF loader: Error opening file", buflen);
56 strncpy(buffer,
"TIFF loader: Out of memory error", buflen);
59 strncpy(buffer,
"TIFF loader: Unsupported image type", buflen);
62 strncpy(buffer,
"TIFF loader: Illegal tiff file", buflen);
65 strncpy(buffer,
"TIFF saver: Error opening file", buflen);
68 strncpy(buffer,
"TIFF loader: Error writing file", buflen);
76 tiff_error(
const char* module,
const char* fmt, va_list list)
82 tiff_warn(
const char * module,
const char * fmt, va_list list)
88 checkcmap(
int n, uint16* r, uint16* g, uint16* b)
91 if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
98 invert_row(
unsigned char *ptr,
unsigned char *data,
int n,
int invert)
101 if (invert) *ptr++ = 255 - *data++;
102 else *ptr++ = *data++;
108 remap_row(
unsigned char *ptr,
unsigned char *data,
int n,
109 unsigned short *rmap,
unsigned short *gmap,
unsigned short *bmap,
unsigned char *amap)
114 *ptr++ = (
unsigned char) rmap[ix];
115 *ptr++ = (
unsigned char) gmap[ix];
116 *ptr++ = (
unsigned char) bmap[ix];
117 if (amap) *ptr++ = (
unsigned char) amap[ix];
122 copy_row(
unsigned char *ptr,
unsigned char *data,
int n,
int numcomponents)
124 memcpy(ptr, data, (
size_t)n*numcomponents);
128 interleave_row(
unsigned char *ptr,
131 unsigned char *green,
132 unsigned char *alpha,
139 if (alpha) *ptr++ = *alpha++;
144 tiff_try_read_rgba(TIFF *in,
int w,
int h,
int format,
145 unsigned char * buffer)
147 unsigned char * newbuffer = NULL;
149 newbuffer = (
unsigned char*) malloc((
size_t)w*h*4);
154 if (!TIFFReadRGBAImage(in, w, h,
155 (
unsigned int*) newbuffer, 1)) {
160 unsigned char * src = newbuffer;
161 unsigned char * dst = buffer;
163 for (i = 0; i < n; i++) {
192 const unsigned char *header,
195 static unsigned char tifcmp[] = {0x4d, 0x4d, 0x0, 0x2a};
196 static unsigned char tifcmp2[] = {0x49, 0x49, 0x2a, 0};
198 if (headerlen < 4)
return 0;
199 if (memcmp((
const void*)header, (
const void*)tifcmp, 4) == 0)
return 1;
200 if (memcmp((
const void*)header, (
const void*)tifcmp2, 4) == 0)
return 1;
205 #define CVT(x) (((x) * 255L) / ((1L<<16)-1))
206 #define pack(a,b) ((a)<<8 | (b))
212 int *numComponents_ret)
215 uint16 samplesperpixel;
216 uint16 bitspersample;
223 unsigned char *inbuf = NULL;
227 unsigned char *buffer;
230 unsigned char *currPtr;
233 TIFFSetErrorHandler(tiff_error);
234 TIFFSetWarningHandler(tiff_warn);
236 in = TIFFOpen(filename,
"r");
241 if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1) {
242 if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE &&
243 photometric != PHOTOMETRIC_MINISWHITE &&
244 photometric != PHOTOMETRIC_MINISBLACK) {
257 if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1) {
258 if (samplesperpixel < 1 || samplesperpixel > 4) {
271 if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1) {
272 if (bitspersample != 8) {
285 if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 ||
286 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 ||
287 TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1) {
293 if (photometric == PHOTOMETRIC_MINISWHITE ||
294 photometric == PHOTOMETRIC_MINISBLACK)
297 if (photometric == PHOTOMETRIC_PALETTE) format = 3;
298 else format = samplesperpixel;
300 buffer = (
unsigned char*)malloc((
size_t)w*h*format);
311 currPtr = buffer + (h-1)*w*format;
315 switch (pack(photometric, config)) {
316 case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG):
317 case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG):
318 case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE):
319 case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE):
321 inbuf = (unsigned char *)malloc(TIFFScanlineSize(in));
322 for (row = 0; row < h; row++) {
323 if (TIFFReadScanline(in, inbuf, row, 0) < 0) {
327 invert_row(currPtr, inbuf, w, photometric == PHOTOMETRIC_MINISWHITE);
331 tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
336 case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
337 case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
338 if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1)
344 if (!tifferror && checkcmap(1<<bitspersample, red, green, blue) == 16) {
346 for (i = (1<<bitspersample)-1; i >= 0; i--) {
347 red[i] = CVT(red[i]);
348 green[i] = CVT(green[i]);
349 blue[i] = CVT(blue[i]);
353 inbuf = (
unsigned char *)malloc(TIFFScanlineSize(in));
354 for (row = 0; row < h; row++) {
355 if (TIFFReadScanline(in, inbuf, row, 0) < 0) {
359 remap_row(currPtr, inbuf, w, red, green, blue, NULL);
363 tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
368 case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
369 inbuf = (unsigned char *)malloc(TIFFScanlineSize(in));
370 for (row = 0; row < h; row++) {
371 if (TIFFReadScanline(in, inbuf, row, 0) < 0) {
375 copy_row(currPtr, inbuf, w, format);
379 tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
384 case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
385 rowsize = TIFFScanlineSize(in);
386 inbuf = (
unsigned char *)malloc(format*rowsize);
387 for (row = 0; !tifferror && row < h; row++) {
389 for (s = 0; s < format; s++) {
390 if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0) {
395 interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize,
396 format == 4 ? inbuf+3*rowsize : NULL, w);
401 tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
410 if (inbuf) free(inbuf);
414 if (buffer) free(buffer);
418 *height_ret = height;
419 *numComponents_ret = format;
425 const unsigned char * bytes,
433 short config = PLANARCONFIG_CONTIG;
434 int16 compression = COMPRESSION_PACKBITS;
436 out = TIFFOpen(filename,
"w");
442 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) width);
443 TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) height);
444 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
445 TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
446 if (numcomponents <= 2)
447 photometric = PHOTOMETRIC_MINISBLACK;
449 photometric = PHOTOMETRIC_RGB;
450 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
452 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
453 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, numcomponents);
454 if (numcomponents == 2 || numcomponents == 4) {
456 v[0] = EXTRASAMPLE_UNASSALPHA;
457 TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
459 TIFFSetField(out, TIFFTAG_MINSAMPLEVALUE, (uint16) 0);
460 TIFFSetField(out, TIFFTAG_MAXSAMPLEVALUE, (uint16) 255);
461 TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
463 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 1L);
464 TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, filename);
466 bytesperrow = width * numcomponents;
468 for (y = 0; y < height; y++) {
469 if (TIFFWriteScanline(out, (tdata_t) (bytes + bytesperrow * (height-y-1)), y, 0) < 0) {
482 uint16 samplesperpixel;
483 uint16 bitspersample;
492 unsigned char * inbuf;
493 } simage_tiff_opendata;
502 simage_tiff_opendata * od;
506 TIFFSetErrorHandler(tiff_error);
507 TIFFSetWarningHandler(tiff_warn);
509 in = TIFFOpen(filename,
"r");
514 od = (simage_tiff_opendata*) malloc(
sizeof(simage_tiff_opendata));
518 if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &od->photometric) == 1) {
519 if (od->photometric != PHOTOMETRIC_RGB &&
521 od->photometric != PHOTOMETRIC_MINISWHITE &&
522 od->photometric != PHOTOMETRIC_MINISBLACK) {
537 if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &od->samplesperpixel) == 1) {
538 if (od->samplesperpixel < 1 || od->samplesperpixel > 4) {
553 if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &od->bitspersample) == 1) {
554 if (od->bitspersample != 8) {
569 if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &od->w) != 1 ||
570 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &od->h) != 1 ||
571 TIFFGetField(in, TIFFTAG_PLANARCONFIG, &od->config) != 1) {
578 if (od->photometric == PHOTOMETRIC_MINISWHITE ||
579 od->photometric == PHOTOMETRIC_MINISBLACK)
582 if (od->photometric == PHOTOMETRIC_PALETTE) od->format = 3;
583 else od->format = od->samplesperpixel;
585 switch (pack(od->photometric, od->config)) {
588 case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
589 case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
590 if (TIFFGetField(in, TIFFTAG_COLORMAP, &od->red, &od->green, &od->blue) != 1)
596 if (!tifferror && checkcmap(1<<od->bitspersample, od->red, od->green, od->blue) == 16) {
598 for (i = (1<<od->bitspersample)-1; i >= 0; i--) {
599 od->red[i] = CVT(od->red[i]);
600 od->green[i] = CVT(od->green[i]);
601 od->blue[i] = CVT(od->blue[i]);
605 od->rowsize = (int) TIFFScanlineSize(in);
606 od->inbuf = (
unsigned char *) malloc(od->rowsize * 4);
610 *numcomponents = od->format;
619 simage_tiff_opendata * od = (simage_tiff_opendata*) opendata;
629 simage_tiff_opendata * od;
632 od = (simage_tiff_opendata*) opendata;
635 switch (pack(od->photometric, od->config)) {
636 case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG):
637 case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG):
638 case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE):
639 case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE):
640 if (TIFFReadScanline(od->in, od->inbuf, row, 0) < 0) {
644 invert_row(buf, od->inbuf, od->w, od->photometric == PHOTOMETRIC_MINISWHITE);
647 case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
648 case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
649 if (TIFFReadScanline(od->in, od->inbuf, row, 0) < 0) {
653 remap_row(buf, od->inbuf, od->w, od->red, od->green, od->blue, NULL);
656 case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
657 if (TIFFReadScanline(od->in, od->inbuf, row, 0) < 0) {
661 copy_row(buf, od->inbuf, od->w, od->format);
664 case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
665 for (s = 0; s < od->format; s++) {
666 if (TIFFReadScanline(od->in, (tdata_t)(od->inbuf+s*od->rowsize),
667 (uint32)row, (tsample_t)s) < 0) {
672 interleave_row(buf, od->inbuf, od->inbuf+od->rowsize, od->inbuf + 2*od->rowsize,
673 od->format == 4 ? od->inbuf + 3*od->rowsize: NULL, od->w);
void * simage_tiff_open(const char *filename, int *width, int *height, int *numcomponents)
int simage_tiff_error(char *buffer, int bufferlen)
int simage_tiff_save(const char *filename, const unsigned char *bytes, int width, int height, int numcomponents)
void simage_tiff_close(void *opendata)
unsigned char * simage_tiff_load(const char *filename, int *width, int *height, int *numComponents)
int simage_tiff_read_line(void *opendata, int y, unsigned char *buf)
int simage_tiff_identify(const char *filename, const unsigned char *header, int headerlen)