Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://coin3d.github.io
https://www.kongsberg.com/en/kogt/
simage_tiff.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Kongsberg Oil & Gas Technologies
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * based on example code found in libtiff
19  *
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif /* HAVE_CONFIG_H */
25 
26 #ifdef HAVE_TIFFLIB
27 
28 #include <simage_tiff.h>
29 #include <stdio.h>
30 
31 #include <tiffio.h>
32 
33 #include <string.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 
37 #define ERR_NO_ERROR 0
38 #define ERR_OPEN 1
39 #define ERR_READ 2
40 #define ERR_MEM 3
41 #define ERR_UNSUPPORTED 4
42 #define ERR_TIFFLIB 5
43 #define ERR_OPEN_WRITE 6
44 #define ERR_WRITE 7
45 
46 static int tifferror = ERR_NO_ERROR;
47 
48 int
49 simage_tiff_error(char * buffer, int buflen)
50 {
51  switch (tifferror) {
52  case ERR_OPEN:
53  strncpy(buffer, "TIFF loader: Error opening file", buflen);
54  break;
55  case ERR_MEM:
56  strncpy(buffer, "TIFF loader: Out of memory error", buflen);
57  break;
58  case ERR_UNSUPPORTED:
59  strncpy(buffer, "TIFF loader: Unsupported image type", buflen);
60  break;
61  case ERR_TIFFLIB:
62  strncpy(buffer, "TIFF loader: Illegal tiff file", buflen);
63  break;
64  case ERR_OPEN_WRITE:
65  strncpy(buffer, "TIFF saver: Error opening file", buflen);
66  break;
67  case ERR_WRITE:
68  strncpy(buffer, "TIFF loader: Error writing file", buflen);
69  break;
70  }
71  return tifferror;
72 }
73 
74 
75 static void
76 tiff_error(const char* module, const char* fmt, va_list list)
77 {
78  /* FIXME: store error message ? */
79 }
80 
81 static void
82 tiff_warn(const char * module, const char * fmt, va_list list)
83 {
84  /* FIXME: notify? */
85 }
86 
87 static int
88 checkcmap(int n, uint16* r, uint16* g, uint16* b)
89 {
90  while (n-- > 0)
91  if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
92  return (16);
93  /* Assuming 8-bit colormap */
94  return (8);
95 }
96 
97 static void
98 invert_row(unsigned char *ptr, unsigned char *data, int n, int invert)
99 {
100  while (n--) {
101  if (invert) *ptr++ = 255 - *data++;
102  else *ptr++ = *data++;
103  }
104 }
105 
106 
107 static void
108 remap_row(unsigned char *ptr, unsigned char *data, int n,
109  unsigned short *rmap, unsigned short *gmap, unsigned short *bmap,unsigned char *amap)
110 {
111  unsigned int ix;
112  while (n--) {
113  ix = *data++;
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];
118  }
119 }
120 
121 static void
122 copy_row(unsigned char *ptr, unsigned char *data, int n, int numcomponents)
123 {
124  memcpy(ptr, data, (size_t)n*numcomponents);
125 }
126 
127 static void
128 interleave_row(unsigned char *ptr,
129  unsigned char *red,
130  unsigned char *blue,
131  unsigned char *green,
132  unsigned char *alpha,
133  int n)
134 {
135  while (n--) {
136  *ptr++ = *red++;
137  *ptr++ = *green++;
138  *ptr++ = *blue++;
139  if (alpha) *ptr++ = *alpha++;
140  }
141 }
142 
143 static int
144 tiff_try_read_rgba(TIFF *in, int w, int h, int format,
145  unsigned char * buffer)
146 {
147  unsigned char * newbuffer = NULL;
148  if (format != 4) {
149  newbuffer = (unsigned char*) malloc((size_t)w*h*4);
150  }
151  else {
152  newbuffer = buffer;
153  }
154  if (!TIFFReadRGBAImage(in, w, h,
155  (unsigned int*) newbuffer, 1)) {
156  free(newbuffer);
157  return ERR_READ;
158  }
159  if (format != 4) {
160  unsigned char * src = newbuffer;
161  unsigned char * dst = buffer;
162  int i, n = w*h;
163  for (i = 0; i < n; i++) {
164  switch (format) {
165  case 1:
166  *dst++ = src[0];
167  break;
168  case 2:
169  *dst++ = src[0];
170  *dst++ = src[3];
171  break;
172  case 3:
173  *dst++ = src[0];
174  *dst++ = src[1];
175  *dst++ = src[2];
176  break;
177  default:
178  break;
179 
180  }
181  src += 4;
182  }
183  free(newbuffer);
184  }
185 
186  return ERR_NO_ERROR;
187 }
188 
189 
190 int
191 simage_tiff_identify(const char *ptr,
192  const unsigned char *header,
193  int headerlen)
194 {
195  static unsigned char tifcmp[] = {0x4d, 0x4d, 0x0, 0x2a};
196  static unsigned char tifcmp2[] = {0x49, 0x49, 0x2a, 0};
197 
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;
201  return 0;
202 }
203 
204 /* useful defines (undef'ed below) */
205 #define CVT(x) (((x) * 255L) / ((1L<<16)-1))
206 #define pack(a,b) ((a)<<8 | (b))
207 
208 unsigned char *
209 simage_tiff_load(const char *filename,
210  int *width_ret,
211  int *height_ret,
212  int *numComponents_ret)
213 {
214  TIFF *in;
215  uint16 samplesperpixel;
216  uint16 bitspersample;
217  uint16 photometric;
218  uint32 w, h;
219  uint16 config;
220  uint16* red;
221  uint16* green;
222  uint16* blue;
223  unsigned char *inbuf = NULL;
224  tsize_t rowsize;
225  uint32 row;
226  int format;
227  unsigned char *buffer;
228  int width;
229  int height;
230  unsigned char *currPtr;
231 
232 
233  TIFFSetErrorHandler(tiff_error);
234  TIFFSetWarningHandler(tiff_warn);
235 
236  in = TIFFOpen(filename, "r");
237  if (in == NULL) {
238  tifferror = ERR_OPEN;
239  return NULL;
240  }
241  if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1) {
242  if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE &&
243  photometric != PHOTOMETRIC_MINISWHITE &&
244  photometric != PHOTOMETRIC_MINISBLACK) {
245  /*Bad photometric; can only handle Grayscale, RGB and Palette images :-( */
246  TIFFClose(in);
247  tifferror = ERR_UNSUPPORTED;
248  return NULL;
249  }
250  }
251  else {
252  tifferror = ERR_READ;
253  TIFFClose(in);
254  return NULL;
255  }
256 
257  if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1) {
258  if (samplesperpixel < 1 || samplesperpixel > 4) {
259  /* Bad samples/pixel */
260  tifferror = ERR_UNSUPPORTED;
261  TIFFClose(in);
262  return NULL;
263  }
264  }
265  else {
266  tifferror = ERR_READ;
267  TIFFClose(in);
268  return NULL;
269  }
270 
271  if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1) {
272  if (bitspersample != 8) {
273  /* can only handle 8-bit samples. */
274  TIFFClose(in);
275  tifferror = ERR_UNSUPPORTED;
276  return NULL;
277  }
278  }
279  else {
280  tifferror = ERR_READ;
281  TIFFClose(in);
282  return NULL;
283  }
284 
285  if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 ||
286  TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 ||
287  TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1) {
288  TIFFClose(in);
289  tifferror = ERR_READ;
290  return NULL;
291  }
292 
293  if (photometric == PHOTOMETRIC_MINISWHITE ||
294  photometric == PHOTOMETRIC_MINISBLACK)
295  format = 1;
296  else {
297  if (photometric == PHOTOMETRIC_PALETTE) format = 3;
298  else format = samplesperpixel;
299  }
300  buffer = (unsigned char*)malloc((size_t)w*h*format);
301 
302  if (!buffer) {
303  tifferror = ERR_MEM;
304  TIFFClose(in);
305  return NULL;
306  }
307 
308  width = w;
309  height = h;
310 
311  currPtr = buffer + (h-1)*w*format;
312 
313  tifferror = ERR_NO_ERROR;
314 
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):
320 
321  inbuf = (unsigned char *)malloc(TIFFScanlineSize(in));
322  for (row = 0; row < h; row++) {
323  if (TIFFReadScanline(in, inbuf, row, 0) < 0) {
324  tifferror = ERR_READ;
325  break;
326  }
327  invert_row(currPtr, inbuf, w, photometric == PHOTOMETRIC_MINISWHITE);
328  currPtr -= format*w;
329  }
330  if (tifferror == ERR_READ) {
331  tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
332  }
333 
334  break;
335 
336  case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
337  case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
338  if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1)
339  tifferror = ERR_READ;
340  /* */
341  /* Convert 16-bit colormap to 8-bit (unless it looks */
342  /* like an old-style 8-bit colormap). */
343  /* */
344  if (!tifferror && checkcmap(1<<bitspersample, red, green, blue) == 16) {
345  int i;
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]);
350  }
351  }
352 
353  inbuf = (unsigned char *)malloc(TIFFScanlineSize(in));
354  for (row = 0; row < h; row++) {
355  if (TIFFReadScanline(in, inbuf, row, 0) < 0) {
356  tifferror = ERR_READ;
357  break;
358  }
359  remap_row(currPtr, inbuf, w, red, green, blue, NULL);
360  currPtr -= format*w;
361  }
362  if (tifferror == ERR_READ) {
363  tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
364  }
365 
366  break;
367 
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) {
372  tifferror = ERR_READ;
373  break;
374  }
375  copy_row(currPtr, inbuf, w, format);
376  currPtr -= format*w;
377  }
378  if (tifferror == ERR_READ) {
379  tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
380  }
381 
382  break;
383 
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++) {
388  int s;
389  for (s = 0; s < format; s++) {
390  if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0) {
391  tifferror = ERR_READ; break;
392  }
393  }
394  if (tifferror != ERR_READ) {
395  interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize,
396  format == 4 ? inbuf+3*rowsize : NULL, w);
397  currPtr -= format*w;
398  }
399  }
400  if (tifferror == ERR_READ) {
401  tifferror = tiff_try_read_rgba(in, w, h, format, buffer);
402  }
403 
404  break;
405  default:
406  tifferror = ERR_UNSUPPORTED;
407  break;
408  }
409 
410  if (inbuf) free(inbuf);
411  TIFFClose(in);
412 
413  if (tifferror) {
414  if (buffer) free(buffer);
415  return NULL;
416  }
417  *width_ret = width;
418  *height_ret = height;
419  *numComponents_ret = format;
420  return buffer;
421 }
422 
423 int
424 simage_tiff_save(const char *filename,
425  const unsigned char * bytes,
426  int width,
427  int height,
428  int numcomponents)
429 {
430  uint16 photometric;
431  TIFF * out;
432  int y, bytesperrow;
433  short config = PLANARCONFIG_CONTIG;
434  int16 compression = COMPRESSION_PACKBITS; /* RLE */
435 
436  out = TIFFOpen(filename, "w");
437  if (out == NULL) {
438  tifferror = ERR_OPEN_WRITE;
439  return 0;
440  }
441 
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;
448  else
449  photometric = PHOTOMETRIC_RGB;
450  TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
451 
452  TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
453  TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, numcomponents);
454  if (numcomponents == 2 || numcomponents == 4) {
455  uint16 v[1];
456  v[0] = EXTRASAMPLE_UNASSALPHA;
457  TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
458  }
459  TIFFSetField(out, TIFFTAG_MINSAMPLEVALUE, (uint16) 0);
460  TIFFSetField(out, TIFFTAG_MAXSAMPLEVALUE, (uint16) 255);
461  TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
462  /* force 1 row/strip for library limitation */
463  TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 1L);
464  TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, filename);
465 
466  bytesperrow = width * numcomponents;
467 
468  for (y = 0; y < height; y++) {
469  if (TIFFWriteScanline(out, (tdata_t) (bytes + bytesperrow * (height-y-1)), y, 0) < 0) {
470  TIFFClose(out);
471  tifferror = ERR_WRITE;
472  return 0;
473  }
474  }
475 
476  TIFFClose(out);
477  return 1;
478 }
479 
480 typedef struct {
481  TIFF * in;
482  uint16 samplesperpixel;
483  uint16 bitspersample;
484  uint16 photometric;
485  uint32 w, h;
486  uint16 config;
487  uint16 * red;
488  uint16 * green;
489  uint16 * blue;
490  int format;
491  int rowsize;
492  unsigned char * inbuf;
493 } simage_tiff_opendata;
494 
495 void *
496 simage_tiff_open(const char * filename,
497  int * width,
498  int * height,
499  int * numcomponents)
500 {
501  TIFF * in;
502  simage_tiff_opendata * od;
503 
504  tifferror = ERR_NO_ERROR;
505 
506  TIFFSetErrorHandler(tiff_error);
507  TIFFSetWarningHandler(tiff_warn);
508 
509  in = TIFFOpen(filename, "r");
510  if (in == NULL) {
511  tifferror = ERR_OPEN;
512  return NULL;
513  }
514  od = (simage_tiff_opendata*) malloc(sizeof(simage_tiff_opendata));
515  od->in = in;
516 
517  /* random access of lines is not be supported for palette images */
518  if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &od->photometric) == 1) {
519  if (od->photometric != PHOTOMETRIC_RGB &&
520  /* od->photometric != PHOTOMETRIC_PALETTE && */
521  od->photometric != PHOTOMETRIC_MINISWHITE &&
522  od->photometric != PHOTOMETRIC_MINISBLACK) {
523  /* Bad photometric; can only handle Grayscale and RGB images */
524  TIFFClose(in);
525  tifferror = ERR_UNSUPPORTED;
526  free(od);
527  return NULL;
528  }
529  }
530  else {
531  tifferror = ERR_READ;
532  free(od);
533  TIFFClose(in);
534  return NULL;
535  }
536 
537  if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &od->samplesperpixel) == 1) {
538  if (od->samplesperpixel < 1 || od->samplesperpixel > 4) {
539  /* Bad samples/pixel */
540  tifferror = ERR_UNSUPPORTED;
541  free(od);
542  TIFFClose(in);
543  return NULL;
544  }
545  }
546  else {
547  tifferror = ERR_READ;
548  free(od);
549  TIFFClose(in);
550  return NULL;
551  }
552 
553  if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &od->bitspersample) == 1) {
554  if (od->bitspersample != 8) {
555  /* can only handle 8-bit samples. */
556  TIFFClose(in);
557  tifferror = ERR_UNSUPPORTED;
558  free(od);
559  return NULL;
560  }
561  }
562  else {
563  tifferror = ERR_READ;
564  TIFFClose(in);
565  free(od);
566  return NULL;
567  }
568 
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) {
572  TIFFClose(in);
573  tifferror = ERR_READ;
574  free(od);
575  return NULL;
576  }
577 
578  if (od->photometric == PHOTOMETRIC_MINISWHITE ||
579  od->photometric == PHOTOMETRIC_MINISBLACK)
580  od->format = 1;
581  else {
582  if (od->photometric == PHOTOMETRIC_PALETTE) od->format = 3;
583  else od->format = od->samplesperpixel;
584  }
585  switch (pack(od->photometric, od->config)) {
586  default:
587  break;
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)
591  tifferror = ERR_READ;
592  /* */
593  /* Convert 16-bit colormap to 8-bit (unless it looks */
594  /* like an old-style 8-bit colormap). */
595  /* */
596  if (!tifferror && checkcmap(1<<od->bitspersample, od->red, od->green, od->blue) == 16) {
597  int i;
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]);
602  }
603  }
604  }
605  od->rowsize = (int) TIFFScanlineSize(in);
606  od->inbuf = (unsigned char *) malloc(od->rowsize * 4); /* *4 to support all formats */
607 
608  *width = od->w;
609  *height = od->h;
610  *numcomponents = od->format;
611 
612  return (void*) od;
613 }
614 
615 
616 void
617 simage_tiff_close(void * opendata)
618 {
619  simage_tiff_opendata * od = (simage_tiff_opendata*) opendata;
620  TIFFClose(od->in);
621  free(od->inbuf);
622  free(od);
623 }
624 
625 int
626 simage_tiff_read_line(void * opendata, int y, unsigned char * buf)
627 {
628  int s, row;
629  simage_tiff_opendata * od;
630  tifferror = ERR_NO_ERROR;
631 
632  od = (simage_tiff_opendata*) opendata;
633  row = (od->h-1)-y;
634 
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) {
641  tifferror = ERR_READ;
642  break;
643  }
644  invert_row(buf, od->inbuf, od->w, od->photometric == PHOTOMETRIC_MINISWHITE);
645  break;
646 
647  case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
648  case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
649  if (TIFFReadScanline(od->in, od->inbuf, row, 0) < 0) {
650  tifferror = ERR_READ;
651  break;
652  }
653  remap_row(buf, od->inbuf, od->w, od->red, od->green, od->blue, NULL);
654  break;
655 
656  case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
657  if (TIFFReadScanline(od->in, od->inbuf, row, 0) < 0) {
658  tifferror = ERR_READ;
659  break;
660  }
661  copy_row(buf, od->inbuf, od->w, od->format);
662  break;
663 
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) {
668  tifferror = ERR_READ; break;
669  }
670  }
671  if (!tifferror) {
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);
674  }
675  break;
676  default:
677  tifferror = ERR_UNSUPPORTED;
678  break;
679  }
680  return tifferror == ERR_NO_ERROR;
681 }
682 
683 #undef CVT
684 #undef pack
685 
686 #endif /* HAVE_TIFFLIB */
void * simage_tiff_open(const char *filename, int *width, int *height, int *numcomponents)
int simage_tiff_error(char *buffer, int bufferlen)
#define ERR_WRITE
int simage_tiff_save(const char *filename, const unsigned char *bytes, int width, int height, int numcomponents)
#define ERR_OPEN
void simage_tiff_close(void *opendata)
unsigned char * simage_tiff_load(const char *filename, int *width, int *height, int *numComponents)
#define ERR_MEM
int simage_tiff_read_line(void *opendata, int y, unsigned char *buf)
#define ERR_UNSUPPORTED
#define ERR_NO_ERROR
int simage_tiff_identify(const char *filename, const unsigned char *header, int headerlen)