Leptonica  1.77.0
Image processing and image analysis suite
tiffio.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
99 #ifdef HAVE_CONFIG_H
100 #include "config_auto.h"
101 #endif /* HAVE_CONFIG_H */
102 
103 #include <string.h>
104 #include <math.h> /* for isnan */
105 #include <sys/types.h>
106 #ifndef _MSC_VER
107 #include <unistd.h>
108 #else /* _MSC_VER */
109 #include <io.h>
110 #endif /* _MSC_VER */
111 #include <fcntl.h>
112 #include "allheaders.h"
113 
114 /* --------------------------------------------*/
115 #if HAVE_LIBTIFF /* defined in environ.h */
116 /* --------------------------------------------*/
117 
118 #include "tiff.h"
119 #include "tiffio.h"
120 
121 static const l_int32 DEFAULT_RESOLUTION = 300; /* ppi */
122 static const l_int32 MANY_PAGES_IN_TIFF_FILE = 3000; /* warn if big */
123 
124 
125  /* All functions with TIFF interfaces are static. */
126 static PIX *pixReadFromTiffStream(TIFF *tif);
127 static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
128  l_int32 *pyres);
129 static l_int32 tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
130  l_int32 *pheight, l_int32 *pbps,
131  l_int32 *pspp, l_int32 *pres,
132  l_int32 *pcmap, l_int32 *pformat);
133 static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags,
134  SARRAY *savals, SARRAY *satypes,
135  NUMA *nasizes);
136 static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
137  NUMA *natags, SARRAY *savals,
138  SARRAY *satypes, NUMA *nasizes);
139 static TIFF *fopenTiff(FILE *fp, const char *modestring);
140 static TIFF *openTiff(const char *filename, const char *modestring);
141 
142  /* Static helper for tiff compression type */
143 static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp);
144 
145  /* Static function for memory I/O */
146 static TIFF *fopenTiffMemstream(const char *filename, const char *operation,
147  l_uint8 **pdata, size_t *pdatasize);
148 
149  /* This structure defines a transform to be performed on a TIFF image
150  * (note that the same transformation can be represented in
151  * several different ways using this structure since
152  * vflip + hflip + counterclockwise == clockwise). */
154  int vflip; /* if non-zero, image needs a vertical fip */
155  int hflip; /* if non-zero, image needs a horizontal flip */
156  int rotate; /* -1 -> counterclockwise 90-degree rotation,
157  0 -> no rotation
158  1 -> clockwise 90-degree rotation */
159 };
160 
161  /* This describes the transformations needed for a given orientation
162  * tag. The tag values start at 1, so you need to subtract 1 to get a
163  * valid index into this array. It is only valid when not using
164  * TIFFReadRGBAImageOriented(). */
165 static struct tiff_transform tiff_orientation_transforms[] = {
166  {0, 0, 0},
167  {0, 1, 0},
168  {1, 1, 0},
169  {1, 0, 0},
170  {0, 1, -1},
171  {0, 0, 1},
172  {0, 1, 1},
173  {0, 0, -1}
174 };
175 
176  /* Same as above, except that test transformations are only valid
177  * when using TIFFReadRGBAImageOriented(). Transformations
178  * were determined empirically. See the libtiff mailing list for
179  * more discussion: http://www.asmail.be/msg0054683875.html */
180 static struct tiff_transform tiff_partial_orientation_transforms[] = {
181  {0, 0, 0},
182  {0, 0, 0},
183  {0, 0, 0},
184  {0, 0, 0},
185  {0, 1, -1},
186  {0, 1, 1},
187  {1, 0, 1},
188  {0, 1, -1}
189 };
190 
191 
192 /*-----------------------------------------------------------------------*
193  * TIFFClientOpen() wrappers for FILE* *
194  * Provided by Jürgen Buchmüller *
195  * *
196  * We previously used TIFFFdOpen(), which used low-level file *
197  * descriptors. It had portability issues with Windows, along *
198  * with other limitations from lack of stream control operations. *
199  * These callbacks to TIFFClientOpen() avoid the problems. *
200  * *
201  * Jürgen made the functions use 64 bit file operations where possible *
202  * or required, namely for seek and size. On Windows there are specific *
203  * _fseeki64() and _ftelli64() functions, whereas on unix it is *
204  * common to look for a macro _LARGEFILE_SOURCE being defined and *
205  * use fseeko() and ftello() in this case. *
206  *-----------------------------------------------------------------------*/
207 static tsize_t
208 lept_read_proc(thandle_t cookie,
209  tdata_t buff,
210  tsize_t size)
211 {
212  FILE* fp = (FILE *)cookie;
213  tsize_t done;
214  if (!buff || !cookie || !fp)
215  return (tsize_t)-1;
216  done = fread(buff, 1, size, fp);
217  return done;
218 }
219 
220 static tsize_t
221 lept_write_proc(thandle_t cookie,
222  tdata_t buff,
223  tsize_t size)
224 {
225  FILE* fp = (FILE *)cookie;
226  tsize_t done;
227  if (!buff || !cookie || !fp)
228  return (tsize_t)-1;
229  done = fwrite(buff, 1, size, fp);
230  return done;
231 }
232 
233 static toff_t
234 lept_seek_proc(thandle_t cookie,
235  toff_t offs,
236  int whence)
237 {
238  FILE* fp = (FILE *)cookie;
239 #if defined(_MSC_VER)
240  __int64 pos = 0;
241  if (!cookie || !fp)
242  return (tsize_t)-1;
243  switch (whence) {
244  case SEEK_SET:
245  pos = 0;
246  break;
247  case SEEK_CUR:
248  pos = ftell(fp);
249  break;
250  case SEEK_END:
251  _fseeki64(fp, 0, SEEK_END);
252  pos = _ftelli64(fp);
253  break;
254  }
255  pos = (__int64)(pos + offs);
256  _fseeki64(fp, pos, SEEK_SET);
257  if (pos == _ftelli64(fp))
258  return (tsize_t)pos;
259 #elif defined(_LARGEFILE_SOURCE)
260  off64_t pos = 0;
261  if (!cookie || !fp)
262  return (tsize_t)-1;
263  switch (whence) {
264  case SEEK_SET:
265  pos = 0;
266  break;
267  case SEEK_CUR:
268  pos = ftello(fp);
269  break;
270  case SEEK_END:
271  fseeko(fp, 0, SEEK_END);
272  pos = ftello(fp);
273  break;
274  }
275  pos = (off64_t)(pos + offs);
276  fseeko(fp, pos, SEEK_SET);
277  if (pos == ftello(fp))
278  return (tsize_t)pos;
279 #else
280  off_t pos = 0;
281  if (!cookie || !fp)
282  return (tsize_t)-1;
283  switch (whence) {
284  case SEEK_SET:
285  pos = 0;
286  break;
287  case SEEK_CUR:
288  pos = ftell(fp);
289  break;
290  case SEEK_END:
291  fseek(fp, 0, SEEK_END);
292  pos = ftell(fp);
293  break;
294  }
295  pos = (off_t)(pos + offs);
296  fseek(fp, pos, SEEK_SET);
297  if (pos == ftell(fp))
298  return (tsize_t)pos;
299 #endif
300  return (tsize_t)-1;
301 }
302 
303 static int
304 lept_close_proc(thandle_t cookie)
305 {
306  FILE* fp = (FILE *)cookie;
307  if (!cookie || !fp)
308  return 0;
309  fseek(fp, 0, SEEK_SET);
310  return 0;
311 }
312 
313 static toff_t
314 lept_size_proc(thandle_t cookie)
315 {
316  FILE* fp = (FILE *)cookie;
317 #if defined(_MSC_VER)
318  __int64 pos;
319  __int64 size;
320  if (!cookie || !fp)
321  return (tsize_t)-1;
322  pos = _ftelli64(fp);
323  _fseeki64(fp, 0, SEEK_END);
324  size = _ftelli64(fp);
325  _fseeki64(fp, pos, SEEK_SET);
326 #elif defined(_LARGEFILE_SOURCE)
327  off64_t pos;
328  off64_t size;
329  if (!fp)
330  return (tsize_t)-1;
331  pos = ftello(fp);
332  fseeko(fp, 0, SEEK_END);
333  size = ftello(fp);
334  fseeko(fp, pos, SEEK_SET);
335 #else
336  off_t pos;
337  off_t size;
338  if (!cookie || !fp)
339  return (tsize_t)-1;
340  pos = ftell(fp);
341  fseek(fp, 0, SEEK_END);
342  size = ftell(fp);
343  fseek(fp, pos, SEEK_SET);
344 #endif
345  return (toff_t)size;
346 }
347 
348 
349 /*--------------------------------------------------------------*
350  * Reading from file *
351  *--------------------------------------------------------------*/
368 PIX *
369 pixReadTiff(const char *filename,
370  l_int32 n)
371 {
372 FILE *fp;
373 PIX *pix;
374 
375  PROCNAME("pixReadTiff");
376 
377  if (!filename)
378  return (PIX *)ERROR_PTR("filename not defined", procName, NULL);
379 
380  if ((fp = fopenReadStream(filename)) == NULL)
381  return (PIX *)ERROR_PTR("image file not found", procName, NULL);
382  pix = pixReadStreamTiff(fp, n);
383  fclose(fp);
384  return pix;
385 }
386 
387 
388 /*--------------------------------------------------------------*
389  * Reading from stream *
390  *--------------------------------------------------------------*/
405 PIX *
407  l_int32 n)
408 {
409 PIX *pix;
410 TIFF *tif;
411 
412  PROCNAME("pixReadStreamTiff");
413 
414  if (!fp)
415  return (PIX *)ERROR_PTR("stream not defined", procName, NULL);
416 
417  if ((tif = fopenTiff(fp, "r")) == NULL)
418  return (PIX *)ERROR_PTR("tif not opened", procName, NULL);
419 
420  if (TIFFSetDirectory(tif, n) == 0) {
421  TIFFCleanup(tif);
422  return NULL;
423  }
424  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
425  TIFFCleanup(tif);
426  return NULL;
427  }
428  TIFFCleanup(tif);
429  return pix;
430 }
431 
432 
466 static PIX *
468 {
469 char *text;
470 l_uint8 *linebuf, *data;
471 l_uint16 spp, bps, bpp, photometry, tiffcomp, orientation;
472 l_uint16 *redmap, *greenmap, *bluemap;
473 l_int32 d, wpl, bpl, comptype, i, j, ncolors, rval, gval, bval;
474 l_int32 xres, yres;
475 l_uint32 w, h, tiffbpl, tiffword, read_oriented;
476 l_uint32 *line, *ppixel, *tiffdata, *pixdata;
477 PIX *pix;
478 PIXCMAP *cmap;
479 
480  PROCNAME("pixReadFromTiffStream");
481 
482  if (!tif)
483  return (PIX *)ERROR_PTR("tif not defined", procName, NULL);
484 
485  read_oriented = 0;
486 
487  /* Use default fields for bps and spp */
488  TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
489  TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
490  if (bps != 1 && bps != 2 && bps != 4 && bps != 8 && bps != 16) {
491  L_ERROR("invalid bps = %d\n", procName, bps);
492  return NULL;
493  }
494  if (spp == 1)
495  d = bps;
496  else if (spp == 3 || spp == 4)
497  d = 32;
498  else
499  return (PIX *)ERROR_PTR("spp not in set {1,3,4}", procName, NULL);
500  bpp = bps * spp;
501  if (bpp > 32) { /* for rgb or rgba only */
502  L_WARNING("bpp = %d; stripping 16 bit rgb samples down to 8\n",
503  procName, bpp);
504  bps = 8;
505  }
506 
507  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
508  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
509  tiffbpl = TIFFScanlineSize(tif);
510 
511  if ((pix = pixCreate(w, h, d)) == NULL)
512  return (PIX *)ERROR_PTR("pix not made", procName, NULL);
513  pixSetInputFormat(pix, IFF_TIFF);
514  data = (l_uint8 *)pixGetData(pix);
515  wpl = pixGetWpl(pix);
516  bpl = 4 * wpl;
517 
518  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
519 
520  /* Thanks to Jeff Breidenbach, we now support reading 8 bpp
521  * images encoded in the long-deprecated old jpeg format,
522  * COMPRESSION_OJPEG. TIFFReadScanline() fails on this format,
523  * so we use RGBA reading, which generates a 4 spp image, and
524  * pull out the red component. */
525  if (spp == 1 && tiffcomp != COMPRESSION_OJPEG) {
526  linebuf = (l_uint8 *)LEPT_CALLOC(tiffbpl + 1, sizeof(l_uint8));
527  for (i = 0 ; i < h ; i++) {
528  if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
529  LEPT_FREE(linebuf);
530  pixDestroy(&pix);
531  return (PIX *)ERROR_PTR("line read fail", procName, NULL);
532  }
533  memcpy(data, linebuf, tiffbpl);
534  data += bpl;
535  }
536  if (bps <= 8)
537  pixEndianByteSwap(pix);
538  else /* bps == 16 */
540  LEPT_FREE(linebuf);
541  }
542  else { /* rgb or old jpeg */
543  if ((tiffdata = (l_uint32 *)LEPT_CALLOC((size_t)w * h,
544  sizeof(l_uint32))) == NULL) {
545  pixDestroy(&pix);
546  return (PIX *)ERROR_PTR("calloc fail for tiffdata", procName, NULL);
547  }
548  /* TIFFReadRGBAImageOriented() converts to 8 bps */
549  if (!TIFFReadRGBAImageOriented(tif, w, h, (uint32 *)tiffdata,
550  ORIENTATION_TOPLEFT, 0)) {
551  LEPT_FREE(tiffdata);
552  pixDestroy(&pix);
553  return (PIX *)ERROR_PTR("failed to read tiffdata", procName, NULL);
554  } else {
555  read_oriented = 1;
556  }
557 
558  if (spp == 1) { /* 8 bpp, old jpeg format */
559  pixdata = pixGetData(pix);
560  for (i = 0; i < h; i++) {
561  line = pixdata + i * wpl;
562  for (j = 0; j < w; j++) {
563  tiffword = tiffdata[i * w + j];
564  rval = TIFFGetR(tiffword);
565  SET_DATA_BYTE(line, j, rval);
566  }
567  }
568  } else { /* standard rgb */
569  line = pixGetData(pix);
570  for (i = 0; i < h; i++, line += wpl) {
571  for (j = 0, ppixel = line; j < w; j++) {
572  /* TIFFGet* are macros */
573  tiffword = tiffdata[i * w + j];
574  rval = TIFFGetR(tiffword);
575  gval = TIFFGetG(tiffword);
576  bval = TIFFGetB(tiffword);
577  composeRGBPixel(rval, gval, bval, ppixel);
578  ppixel++;
579  }
580  }
581  }
582  LEPT_FREE(tiffdata);
583  }
584 
585  if (getTiffStreamResolution(tif, &xres, &yres) == 0) {
586  pixSetXRes(pix, xres);
587  pixSetYRes(pix, yres);
588  }
589 
590  /* Find and save the compression type */
591  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
592  comptype = getTiffCompressedFormat(tiffcomp);
593  pixSetInputFormat(pix, comptype);
594 
595  if (TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap)) {
596  /* Save the colormap as a pix cmap. Because the
597  * tiff colormap components are 16 bit unsigned,
598  * and go from black (0) to white (0xffff), the
599  * the pix cmap takes the most significant byte. */
600  if (bps > 8) {
601  pixDestroy(&pix);
602  return (PIX *)ERROR_PTR("invalid bps; > 8", procName, NULL);
603  }
604  if ((cmap = pixcmapCreate(bps)) == NULL) {
605  pixDestroy(&pix);
606  return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
607  }
608  ncolors = 1 << bps;
609  for (i = 0; i < ncolors; i++)
610  pixcmapAddColor(cmap, redmap[i] >> 8, greenmap[i] >> 8,
611  bluemap[i] >> 8);
612  pixSetColormap(pix, cmap);
613  } else { /* No colormap: check photometry and invert if necessary */
614  if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometry)) {
615  /* Guess default photometry setting. Assume min_is_white
616  * if compressed 1 bpp; min_is_black otherwise. */
617  if (tiffcomp == COMPRESSION_CCITTFAX3 ||
618  tiffcomp == COMPRESSION_CCITTFAX4 ||
619  tiffcomp == COMPRESSION_CCITTRLE ||
620  tiffcomp == COMPRESSION_CCITTRLEW) {
621  photometry = PHOTOMETRIC_MINISWHITE;
622  } else {
623  photometry = PHOTOMETRIC_MINISBLACK;
624  }
625  }
626  if ((d == 1 && photometry == PHOTOMETRIC_MINISBLACK) ||
627  (d == 8 && photometry == PHOTOMETRIC_MINISWHITE))
628  pixInvert(pix, pix);
629  }
630 
631  if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
632  if (orientation >= 1 && orientation <= 8) {
633  struct tiff_transform *transform = (read_oriented) ?
634  &tiff_partial_orientation_transforms[orientation - 1] :
635  &tiff_orientation_transforms[orientation - 1];
636  if (transform->vflip) pixFlipTB(pix, pix);
637  if (transform->hflip) pixFlipLR(pix, pix);
638  if (transform->rotate) {
639  PIX *oldpix = pix;
640  pix = pixRotate90(oldpix, transform->rotate);
641  pixDestroy(&oldpix);
642  }
643  }
644  }
645 
646  text = NULL;
647  TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &text);
648  if (text) pixSetText(pix, text);
649  return pix;
650 }
651 
652 
653 
654 /*--------------------------------------------------------------*
655  * Writing to file *
656  *--------------------------------------------------------------*/
678 l_ok
679 pixWriteTiff(const char *filename,
680  PIX *pix,
681  l_int32 comptype,
682  const char *modestr)
683 {
684  return pixWriteTiffCustom(filename, pix, comptype, modestr,
685  NULL, NULL, NULL, NULL);
686 }
687 
688 
735 l_ok
736 pixWriteTiffCustom(const char *filename,
737  PIX *pix,
738  l_int32 comptype,
739  const char *modestr,
740  NUMA *natags,
741  SARRAY *savals,
742  SARRAY *satypes,
743  NUMA *nasizes)
744 {
745 l_int32 ret;
746 PIX *pix1;
747 TIFF *tif;
748 
749  PROCNAME("pixWriteTiffCustom");
750 
751  if (!filename)
752  return ERROR_INT("filename not defined", procName, 1);
753  if (!pix)
754  return ERROR_INT("pix not defined", procName, 1);
755  if (pixGetColormap(pix))
757  else
758  pix1 = pixClone(pix);
759 
760  if ((tif = openTiff(filename, modestr)) == NULL) {
761  pixDestroy(&pix1);
762  return ERROR_INT("tif not opened", procName, 1);
763  }
764  ret = pixWriteToTiffStream(tif, pix1, comptype, natags, savals,
765  satypes, nasizes);
766  TIFFClose(tif);
767  pixDestroy(&pix1);
768  return ret;
769 }
770 
771 
772 /*--------------------------------------------------------------*
773  * Writing to stream *
774  *--------------------------------------------------------------*/
802 l_ok
804  PIX *pix,
805  l_int32 comptype)
806 {
807  return pixWriteStreamTiffWA(fp, pix, comptype, "w");
808 }
809 
810 
822 l_ok
824  PIX *pix,
825  l_int32 comptype,
826  const char *modestr)
827 {
828 PIX *pix1;
829 TIFF *tif;
830 
831  PROCNAME("pixWriteStreamTiffWA");
832 
833  if (!fp)
834  return ERROR_INT("stream not defined", procName, 1 );
835  if (!pix)
836  return ERROR_INT("pix not defined", procName, 1 );
837  if (strcmp(modestr, "w") && strcmp(modestr, "a"))
838  return ERROR_INT("modestr not 'w' or 'a'", procName, 1 );
839 
840  if (pixGetColormap(pix))
842  else
843  pix1 = pixClone(pix);
844  if (pixGetDepth(pix1) != 1 && comptype != IFF_TIFF &&
845  comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
846  comptype != IFF_TIFF_JPEG) {
847  L_WARNING("invalid compression type for bpp > 1\n", procName);
848  comptype = IFF_TIFF_ZIP;
849  }
850 
851  if ((tif = fopenTiff(fp, modestr)) == NULL) {
852  pixDestroy(&pix1);
853  return ERROR_INT("tif not opened", procName, 1);
854  }
855 
856  if (pixWriteToTiffStream(tif, pix1, comptype, NULL, NULL, NULL, NULL)) {
857  pixDestroy(&pix1);
858  TIFFCleanup(tif);
859  return ERROR_INT("tif write error", procName, 1);
860  }
861 
862  TIFFCleanup(tif);
863  pixDestroy(&pix1);
864  return 0;
865 }
866 
867 
903 static l_int32
905  PIX *pix,
906  l_int32 comptype,
907  NUMA *natags,
908  SARRAY *savals,
909  SARRAY *satypes,
910  NUMA *nasizes)
911 {
912 l_uint8 *linebuf, *data;
913 l_uint16 redmap[256], greenmap[256], bluemap[256];
914 l_int32 w, h, d, i, j, k, wpl, bpl, tiffbpl, ncolors, cmapsize;
915 l_int32 *rmap, *gmap, *bmap;
916 l_int32 xres, yres;
917 l_uint32 *line, *ppixel;
918 PIX *pixt;
919 PIXCMAP *cmap;
920 char *text;
921 
922  PROCNAME("pixWriteToTiffStream");
923 
924  if (!tif)
925  return ERROR_INT("tif stream not defined", procName, 1);
926  if (!pix)
927  return ERROR_INT( "pix not defined", procName, 1 );
928 
929  pixSetPadBits(pix, 0);
930  pixGetDimensions(pix, &w, &h, &d);
931  xres = pixGetXRes(pix);
932  yres = pixGetYRes(pix);
933  if (xres == 0) xres = DEFAULT_RESOLUTION;
934  if (yres == 0) yres = DEFAULT_RESOLUTION;
935 
936  /* ------------------ Write out the header ------------- */
937  TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (l_uint32)RESUNIT_INCH);
938  TIFFSetField(tif, TIFFTAG_XRESOLUTION, (l_float64)xres);
939  TIFFSetField(tif, TIFFTAG_YRESOLUTION, (l_float64)yres);
940 
941  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (l_uint32)w);
942  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (l_uint32)h);
943  TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
944 
945  if ((text = pixGetText(pix)) != NULL)
946  TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, text);
947 
948  if (d == 1)
949  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
950  else if (d == 32 || d == 24) {
951  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
952  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
953  (l_uint16)8, (l_uint16)8, (l_uint16)8);
954  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)3);
955  } else if ((cmap = pixGetColormap(pix)) == NULL) {
956  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
957  } else { /* Save colormap in the tiff; not more than 256 colors */
958  pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
959  ncolors = pixcmapGetCount(cmap);
960  ncolors = L_MIN(256, ncolors); /* max 256 */
961  cmapsize = 1 << d;
962  cmapsize = L_MIN(256, cmapsize); /* power of 2; max 256 */
963  if (ncolors > cmapsize) {
964  L_WARNING("too many colors in cmap for tiff; truncating\n",
965  procName);
966  ncolors = cmapsize;
967  }
968  for (i = 0; i < ncolors; i++) {
969  redmap[i] = (rmap[i] << 8) | rmap[i];
970  greenmap[i] = (gmap[i] << 8) | gmap[i];
971  bluemap[i] = (bmap[i] << 8) | bmap[i];
972  }
973  for (i = ncolors; i < cmapsize; i++) /* init, even though not used */
974  redmap[i] = greenmap[i] = bluemap[i] = 0;
975  LEPT_FREE(rmap);
976  LEPT_FREE(gmap);
977  LEPT_FREE(bmap);
978 
979  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
980  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
981  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
982  TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
983  }
984 
985  if (d != 24 && d != 32) {
986  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
987  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
988  }
989 
990  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
991  if (comptype == IFF_TIFF) { /* no compression */
992  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
993  } else if (comptype == IFF_TIFF_G4) {
994  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
995  } else if (comptype == IFF_TIFF_G3) {
996  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
997  } else if (comptype == IFF_TIFF_RLE) {
998  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);
999  } else if (comptype == IFF_TIFF_PACKBITS) {
1000  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
1001  } else if (comptype == IFF_TIFF_LZW) {
1002  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
1003  } else if (comptype == IFF_TIFF_ZIP) {
1004  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
1005  } else if (comptype == IFF_TIFF_JPEG) {
1006  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
1007  } else {
1008  L_WARNING("unknown tiff compression; using none\n", procName);
1009  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
1010  }
1011 
1012  /* This is a no-op if arrays are NULL */
1013  writeCustomTiffTags(tif, natags, savals, satypes, nasizes);
1014 
1015  /* ------------- Write out the image data ------------- */
1016  tiffbpl = TIFFScanlineSize(tif);
1017  wpl = pixGetWpl(pix);
1018  bpl = 4 * wpl;
1019  if (tiffbpl > bpl)
1020  fprintf(stderr, "Big trouble: tiffbpl = %d, bpl = %d\n", tiffbpl, bpl);
1021  if ((linebuf = (l_uint8 *)LEPT_CALLOC(1, bpl)) == NULL)
1022  return ERROR_INT("calloc fail for linebuf", procName, 1);
1023 
1024  /* Use single strip for image */
1025  TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);
1026 
1027  if (d != 24 && d != 32) {
1028  if (d == 16)
1029  pixt = pixEndianTwoByteSwapNew(pix);
1030  else
1031  pixt = pixEndianByteSwapNew(pix);
1032  data = (l_uint8 *)pixGetData(pixt);
1033  for (i = 0; i < h; i++, data += bpl) {
1034  memcpy(linebuf, data, tiffbpl);
1035  if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1036  break;
1037  }
1038  pixDestroy(&pixt);
1039  } else if (d == 24) { /* See note 4 above: special case of 24 bpp rgb */
1040  for (i = 0; i < h; i++) {
1041  line = pixGetData(pix) + i * wpl;
1042  if (TIFFWriteScanline(tif, (l_uint8 *)line, i, 0) < 0)
1043  break;
1044  }
1045  } else { /* standard 32 bpp rgb */
1046  for (i = 0; i < h; i++) {
1047  line = pixGetData(pix) + i * wpl;
1048  for (j = 0, k = 0, ppixel = line; j < w; j++) {
1049  linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
1050  linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
1051  linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
1052  ppixel++;
1053  }
1054  if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1055  break;
1056  }
1057  }
1058 
1059 /* TIFFWriteDirectory(tif); */
1060  LEPT_FREE(linebuf);
1061 
1062  return 0;
1063 }
1064 
1065 
1095 static l_int32
1097  NUMA *natags,
1098  SARRAY *savals,
1099  SARRAY *satypes,
1100  NUMA *nasizes)
1101 {
1102 char *sval, *type;
1103 l_int32 i, n, ns, size, tagval, val;
1104 l_float64 dval;
1105 l_uint32 uval, uval2;
1106 
1107  PROCNAME("writeCustomTiffTags");
1108 
1109  if (!tif)
1110  return ERROR_INT("tif stream not defined", procName, 1);
1111  if (!natags && !savals && !satypes)
1112  return 0;
1113  if (!natags || !savals || !satypes)
1114  return ERROR_INT("not all arrays defined", procName, 1);
1115  n = numaGetCount(natags);
1116  if ((sarrayGetCount(savals) != n) || (sarrayGetCount(satypes) != n))
1117  return ERROR_INT("not all sa the same size", procName, 1);
1118 
1119  /* The sized arrays (4 args to TIFFSetField) are written first */
1120  if (nasizes) {
1121  ns = numaGetCount(nasizes);
1122  if (ns > n)
1123  return ERROR_INT("too many 4-arg tag calls", procName, 1);
1124  for (i = 0; i < ns; i++) {
1125  numaGetIValue(natags, i, &tagval);
1126  sval = sarrayGetString(savals, i, L_NOCOPY);
1127  type = sarrayGetString(satypes, i, L_NOCOPY);
1128  numaGetIValue(nasizes, i, &size);
1129  if (strcmp(type, "char*") && strcmp(type, "l_uint8*"))
1130  L_WARNING("array type not char* or l_uint8*; ignore\n",
1131  procName);
1132  TIFFSetField(tif, tagval, size, sval);
1133  }
1134  } else {
1135  ns = 0;
1136  }
1137 
1138  /* The typical tags (3 args to TIFFSetField) are now written */
1139  for (i = ns; i < n; i++) {
1140  numaGetIValue(natags, i, &tagval);
1141  sval = sarrayGetString(savals, i, L_NOCOPY);
1142  type = sarrayGetString(satypes, i, L_NOCOPY);
1143  if (!strcmp(type, "char*")) {
1144  TIFFSetField(tif, tagval, sval);
1145  } else if (!strcmp(type, "l_uint16")) {
1146  if (sscanf(sval, "%u", &uval) == 1) {
1147  TIFFSetField(tif, tagval, (l_uint16)uval);
1148  } else {
1149  fprintf(stderr, "val %s not of type %s\n", sval, type);
1150  return ERROR_INT("custom tag(s) not written", procName, 1);
1151  }
1152  } else if (!strcmp(type, "l_uint32")) {
1153  if (sscanf(sval, "%u", &uval) == 1) {
1154  TIFFSetField(tif, tagval, uval);
1155  } else {
1156  fprintf(stderr, "val %s not of type %s\n", sval, type);
1157  return ERROR_INT("custom tag(s) not written", procName, 1);
1158  }
1159  } else if (!strcmp(type, "l_int32")) {
1160  if (sscanf(sval, "%d", &val) == 1) {
1161  TIFFSetField(tif, tagval, val);
1162  } else {
1163  fprintf(stderr, "val %s not of type %s\n", sval, type);
1164  return ERROR_INT("custom tag(s) not written", procName, 1);
1165  }
1166  } else if (!strcmp(type, "l_float64")) {
1167  if (sscanf(sval, "%lf", &dval) == 1) {
1168  TIFFSetField(tif, tagval, dval);
1169  } else {
1170  fprintf(stderr, "val %s not of type %s\n", sval, type);
1171  return ERROR_INT("custom tag(s) not written", procName, 1);
1172  }
1173  } else if (!strcmp(type, "l_uint16-l_uint16")) {
1174  if (sscanf(sval, "%u-%u", &uval, &uval2) == 2) {
1175  TIFFSetField(tif, tagval, (l_uint16)uval, (l_uint16)uval2);
1176  } else {
1177  fprintf(stderr, "val %s not of type %s\n", sval, type);
1178  return ERROR_INT("custom tag(s) not written", procName, 1);
1179  }
1180  } else {
1181  return ERROR_INT("unknown type; tag(s) not written", procName, 1);
1182  }
1183  }
1184  return 0;
1185 }
1186 
1187 
1188 /*--------------------------------------------------------------*
1189  * Reading and writing multipage tiff *
1190  *--------------------------------------------------------------*/
1222 PIX *
1223 pixReadFromMultipageTiff(const char *fname,
1224  size_t *poffset)
1225 {
1226 l_int32 retval;
1227 size_t offset;
1228 PIX *pix;
1229 TIFF *tif;
1230 
1231  PROCNAME("pixReadFromMultipageTiff");
1232 
1233  if (!fname)
1234  return (PIX *)ERROR_PTR("fname not defined", procName, NULL);
1235  if (!poffset)
1236  return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);
1237 
1238  if ((tif = openTiff(fname, "r")) == NULL) {
1239  L_ERROR("tif open failed for %s\n", procName, fname);
1240  return NULL;
1241  }
1242 
1243  /* Set ptrs in the TIFF to the beginning of the image */
1244  offset = *poffset;
1245  retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
1246  : TIFFSetSubDirectory(tif, offset);
1247  if (retval == 0) {
1248  TIFFCleanup(tif);
1249  return NULL;
1250  }
1251 
1252  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
1253  TIFFCleanup(tif);
1254  return NULL;
1255  }
1256 
1257  /* Advance to the next image and return the new offset */
1258  TIFFReadDirectory(tif);
1259  *poffset = TIFFCurrentDirOffset(tif);
1260  TIFFClose(tif);
1261  return pix;
1262 }
1263 
1264 
1271 PIXA *
1272 pixaReadMultipageTiff(const char *filename)
1273 {
1274 l_int32 i, npages;
1275 FILE *fp;
1276 PIX *pix;
1277 PIXA *pixa;
1278 TIFF *tif;
1279 
1280  PROCNAME("pixaReadMultipageTiff");
1281 
1282  if (!filename)
1283  return (PIXA *)ERROR_PTR("filename not defined", procName, NULL);
1284 
1285  if ((fp = fopenReadStream(filename)) == NULL)
1286  return (PIXA *)ERROR_PTR("stream not opened", procName, NULL);
1287  if (fileFormatIsTiff(fp)) {
1288  tiffGetCount(fp, &npages);
1289  L_INFO(" Tiff: %d pages\n", procName, npages);
1290  } else {
1291  return (PIXA *)ERROR_PTR("file not tiff", procName, NULL);
1292  }
1293 
1294  if ((tif = fopenTiff(fp, "r")) == NULL)
1295  return (PIXA *)ERROR_PTR("tif not opened", procName, NULL);
1296 
1297  pixa = pixaCreate(npages);
1298  pix = NULL;
1299  for (i = 0; i < npages; i++) {
1300  if ((pix = pixReadFromTiffStream(tif)) != NULL) {
1301  pixaAddPix(pixa, pix, L_INSERT);
1302  } else {
1303  L_WARNING("pix not read for page %d\n", procName, i);
1304  }
1305 
1306  /* Advance to the next directory (i.e., the next image) */
1307  if (TIFFReadDirectory(tif) == 0)
1308  break;
1309  }
1310 
1311  fclose(fp);
1312  TIFFCleanup(tif);
1313  return pixa;
1314 }
1315 
1316 
1331 l_ok
1332 pixaWriteMultipageTiff(const char *fname,
1333  PIXA *pixa)
1334 {
1335 const char *modestr;
1336 l_int32 i, n;
1337 PIX *pix1, *pix2;
1338 
1339  PROCNAME("pixaWriteMultipageTiff");
1340 
1341  if (!fname)
1342  return ERROR_INT("fname not defined", procName, 1);
1343  if (!pixa)
1344  return ERROR_INT("pixa not defined", procName, 1);
1345 
1346  n = pixaGetCount(pixa);
1347  for (i = 0; i < n; i++) {
1348  modestr = (i == 0) ? "w" : "a";
1349  pix1 = pixaGetPix(pixa, i, L_CLONE);
1350  if (pixGetDepth(pix1) == 1) {
1351  pixWriteTiff(fname, pix1, IFF_TIFF_G4, modestr);
1352  } else {
1353  if (pixGetColormap(pix1)) {
1355  } else {
1356  pix2 = pixClone(pix1);
1357  }
1358  pixWriteTiff(fname, pix2, IFF_TIFF_ZIP, modestr);
1359  pixDestroy(&pix2);
1360  }
1361  pixDestroy(&pix1);
1362  }
1363 
1364  return 0;
1365 }
1366 
1367 
1392 l_ok
1393 writeMultipageTiff(const char *dirin,
1394  const char *substr,
1395  const char *fileout)
1396 {
1397 SARRAY *sa;
1398 
1399  PROCNAME("writeMultipageTiff");
1400 
1401  if (!dirin)
1402  return ERROR_INT("dirin not defined", procName, 1);
1403  if (!fileout)
1404  return ERROR_INT("fileout not defined", procName, 1);
1405 
1406  /* Get all filtered and sorted full pathnames. */
1407  sa = getSortedPathnamesInDirectory(dirin, substr, 0, 0);
1408 
1409  /* Generate the tiff file */
1410  writeMultipageTiffSA(sa, fileout);
1411  sarrayDestroy(&sa);
1412  return 0;
1413 }
1414 
1415 
1428 l_ok
1430  const char *fileout)
1431 {
1432 char *fname;
1433 const char *op;
1434 l_int32 i, nfiles, firstfile, format;
1435 PIX *pix, *pix1;
1436 
1437  PROCNAME("writeMultipageTiffSA");
1438 
1439  if (!sa)
1440  return ERROR_INT("sa not defined", procName, 1);
1441  if (!fileout)
1442  return ERROR_INT("fileout not defined", procName, 1);
1443 
1444  nfiles = sarrayGetCount(sa);
1445  firstfile = TRUE;
1446  for (i = 0; i < nfiles; i++) {
1447  op = (firstfile) ? "w" : "a";
1448  fname = sarrayGetString(sa, i, L_NOCOPY);
1449  findFileFormat(fname, &format);
1450  if (format == IFF_UNKNOWN) {
1451  L_INFO("format of %s not known\n", procName, fname);
1452  continue;
1453  }
1454 
1455  if ((pix = pixRead(fname)) == NULL) {
1456  L_WARNING("pix not made for file: %s\n", procName, fname);
1457  continue;
1458  }
1459  if (pixGetDepth(pix) == 1) {
1460  pixWriteTiff(fileout, pix, IFF_TIFF_G4, op);
1461  } else {
1462  if (pixGetColormap(pix)) {
1464  } else {
1465  pix1 = pixClone(pix);
1466  }
1467  pixWriteTiff(fileout, pix1, IFF_TIFF_ZIP, op);
1468  pixDestroy(&pix1);
1469  }
1470  firstfile = FALSE;
1471  pixDestroy(&pix);
1472  }
1473 
1474  return 0;
1475 }
1476 
1477 
1478 /*--------------------------------------------------------------*
1479  * Print info to stream *
1480  *--------------------------------------------------------------*/
1488 l_ok
1489 fprintTiffInfo(FILE *fpout,
1490  const char *tiffile)
1491 {
1492 TIFF *tif;
1493 
1494  PROCNAME("fprintTiffInfo");
1495 
1496  if (!tiffile)
1497  return ERROR_INT("tiffile not defined", procName, 1);
1498  if (!fpout)
1499  return ERROR_INT("stream out not defined", procName, 1);
1500 
1501  if ((tif = openTiff(tiffile, "rb")) == NULL)
1502  return ERROR_INT("tif not open for read", procName, 1);
1503 
1504  TIFFPrintDirectory(tif, fpout, 0);
1505  TIFFClose(tif);
1506 
1507  return 0;
1508 }
1509 
1510 
1511 /*--------------------------------------------------------------*
1512  * Get page count *
1513  *--------------------------------------------------------------*/
1521 l_ok
1522 tiffGetCount(FILE *fp,
1523  l_int32 *pn)
1524 {
1525 l_int32 i;
1526 TIFF *tif;
1527 
1528  PROCNAME("tiffGetCount");
1529 
1530  if (!fp)
1531  return ERROR_INT("stream not defined", procName, 1);
1532  if (!pn)
1533  return ERROR_INT("&n not defined", procName, 1);
1534  *pn = 0;
1535 
1536  if ((tif = fopenTiff(fp, "r")) == NULL)
1537  return ERROR_INT("tif not open for read", procName, 1);
1538 
1539  for (i = 1; ; i++) {
1540  if (TIFFReadDirectory(tif) == 0)
1541  break;
1542  if (i == MANY_PAGES_IN_TIFF_FILE + 1) {
1543  L_WARNING("big file: more than %d pages\n", procName,
1544  MANY_PAGES_IN_TIFF_FILE);
1545  }
1546  }
1547  *pn = i;
1548  TIFFCleanup(tif);
1549  return 0;
1550 }
1551 
1552 
1553 /*--------------------------------------------------------------*
1554  * Get resolution from tif *
1555  *--------------------------------------------------------------*/
1569 l_ok
1571  l_int32 *pxres,
1572  l_int32 *pyres)
1573 {
1574 TIFF *tif;
1575 
1576  PROCNAME("getTiffResolution");
1577 
1578  if (!pxres || !pyres)
1579  return ERROR_INT("&xres and &yres not both defined", procName, 1);
1580  *pxres = *pyres = 0;
1581  if (!fp)
1582  return ERROR_INT("stream not opened", procName, 1);
1583 
1584  if ((tif = fopenTiff(fp, "r")) == NULL)
1585  return ERROR_INT("tif not open for read", procName, 1);
1586  getTiffStreamResolution(tif, pxres, pyres);
1587  TIFFCleanup(tif);
1588  return 0;
1589 }
1590 
1591 
1605 static l_int32
1607  l_int32 *pxres,
1608  l_int32 *pyres)
1609 {
1610 l_uint16 resunit;
1611 l_int32 foundxres, foundyres;
1612 l_float32 fxres, fyres;
1613 
1614  PROCNAME("getTiffStreamResolution");
1615 
1616  if (!tif)
1617  return ERROR_INT("tif not opened", procName, 1);
1618  if (!pxres || !pyres)
1619  return ERROR_INT("&xres and &yres not both defined", procName, 1);
1620  *pxres = *pyres = 0;
1621 
1622  TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
1623  foundxres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fxres);
1624  foundyres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fyres);
1625  if (!foundxres && !foundyres) return 1;
1626  if (isnan(fxres) || isnan(fyres)) return 1;
1627  if (!foundxres && foundyres)
1628  fxres = fyres;
1629  else if (foundxres && !foundyres)
1630  fyres = fxres;
1631 
1632  /* Avoid overflow into int32; set max fxres and fyres to 5 x 10^8 */
1633  if (fxres < 0 || fxres > (1L << 29) || fyres < 0 || fyres > (1L << 29))
1634  return ERROR_INT("fxres and/or fyres values are invalid", procName, 1);
1635 
1636  if (resunit == RESUNIT_CENTIMETER) { /* convert to ppi */
1637  *pxres = (l_int32)(2.54 * fxres + 0.5);
1638  *pyres = (l_int32)(2.54 * fyres + 0.5);
1639  } else {
1640  *pxres = (l_int32)fxres;
1641  *pyres = (l_int32)fyres;
1642  }
1643 
1644  return 0;
1645 }
1646 
1647 
1648 /*--------------------------------------------------------------*
1649  * Get some tiff header information *
1650  *--------------------------------------------------------------*/
1671 l_ok
1672 readHeaderTiff(const char *filename,
1673  l_int32 n,
1674  l_int32 *pw,
1675  l_int32 *ph,
1676  l_int32 *pbps,
1677  l_int32 *pspp,
1678  l_int32 *pres,
1679  l_int32 *pcmap,
1680  l_int32 *pformat)
1681 {
1682 l_int32 ret;
1683 FILE *fp;
1684 
1685  PROCNAME("readHeaderTiff");
1686 
1687  if (pw) *pw = 0;
1688  if (ph) *ph = 0;
1689  if (pbps) *pbps = 0;
1690  if (pspp) *pspp = 0;
1691  if (pres) *pres = 0;
1692  if (pcmap) *pcmap = 0;
1693  if (pformat) *pformat = 0;
1694  if (!filename)
1695  return ERROR_INT("filename not defined", procName, 1);
1696  if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1697  return ERROR_INT("no results requested", procName, 1);
1698 
1699  if ((fp = fopenReadStream(filename)) == NULL)
1700  return ERROR_INT("image file not found", procName, 1);
1701  ret = freadHeaderTiff(fp, n, pw, ph, pbps, pspp, pres, pcmap, pformat);
1702  fclose(fp);
1703  return ret;
1704 }
1705 
1706 
1727 l_ok
1729  l_int32 n,
1730  l_int32 *pw,
1731  l_int32 *ph,
1732  l_int32 *pbps,
1733  l_int32 *pspp,
1734  l_int32 *pres,
1735  l_int32 *pcmap,
1736  l_int32 *pformat)
1737 {
1738 l_int32 i, ret, format;
1739 TIFF *tif;
1740 
1741  PROCNAME("freadHeaderTiff");
1742 
1743  if (pw) *pw = 0;
1744  if (ph) *ph = 0;
1745  if (pbps) *pbps = 0;
1746  if (pspp) *pspp = 0;
1747  if (pres) *pres = 0;
1748  if (pcmap) *pcmap = 0;
1749  if (pformat) *pformat = 0;
1750  if (!fp)
1751  return ERROR_INT("stream not defined", procName, 1);
1752  if (n < 0)
1753  return ERROR_INT("image index must be >= 0", procName, 1);
1754  if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1755  return ERROR_INT("no results requested", procName, 1);
1756 
1757  findFileFormatStream(fp, &format);
1758  if (format != IFF_TIFF &&
1759  format != IFF_TIFF_G3 && format != IFF_TIFF_G4 &&
1760  format != IFF_TIFF_RLE && format != IFF_TIFF_PACKBITS &&
1761  format != IFF_TIFF_LZW && format != IFF_TIFF_ZIP &&
1762  format != IFF_TIFF_JPEG)
1763  return ERROR_INT("file not tiff format", procName, 1);
1764 
1765  if ((tif = fopenTiff(fp, "r")) == NULL)
1766  return ERROR_INT("tif not open for read", procName, 1);
1767 
1768  for (i = 0; i < n; i++) {
1769  if (TIFFReadDirectory(tif) == 0)
1770  return ERROR_INT("image n not found in file", procName, 1);
1771  }
1772 
1773  ret = tiffReadHeaderTiff(tif, pw, ph, pbps, pspp, pres, pcmap, pformat);
1774  TIFFCleanup(tif);
1775  return ret;
1776 }
1777 
1778 
1799 l_ok
1800 readHeaderMemTiff(const l_uint8 *cdata,
1801  size_t size,
1802  l_int32 n,
1803  l_int32 *pw,
1804  l_int32 *ph,
1805  l_int32 *pbps,
1806  l_int32 *pspp,
1807  l_int32 *pres,
1808  l_int32 *pcmap,
1809  l_int32 *pformat)
1810 {
1811 l_uint8 *data;
1812 l_int32 i, ret;
1813 TIFF *tif;
1814 
1815  PROCNAME("readHeaderMemTiff");
1816 
1817  if (pw) *pw = 0;
1818  if (ph) *ph = 0;
1819  if (pbps) *pbps = 0;
1820  if (pspp) *pspp = 0;
1821  if (pres) *pres = 0;
1822  if (pcmap) *pcmap = 0;
1823  if (pformat) *pformat = 0;
1824  if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1825  return ERROR_INT("no results requested", procName, 1);
1826  if (!cdata)
1827  return ERROR_INT("cdata not defined", procName, 1);
1828 
1829  /* Open a tiff stream to memory */
1830  data = (l_uint8 *)cdata; /* we're really not going to change this */
1831  if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
1832  return ERROR_INT("tiff stream not opened", procName, 1);
1833 
1834  for (i = 0; i < n; i++) {
1835  if (TIFFReadDirectory(tif) == 0) {
1836  TIFFClose(tif);
1837  return ERROR_INT("image n not found in file", procName, 1);
1838  }
1839  }
1840 
1841  ret = tiffReadHeaderTiff(tif, pw, ph, pbps, pspp, pres, pcmap, pformat);
1842  TIFFClose(tif);
1843  return ret;
1844 }
1845 
1846 
1860 static l_int32
1862  l_int32 *pw,
1863  l_int32 *ph,
1864  l_int32 *pbps,
1865  l_int32 *pspp,
1866  l_int32 *pres,
1867  l_int32 *pcmap,
1868  l_int32 *pformat)
1869 {
1870 l_uint16 tiffcomp;
1871 l_uint16 bps, spp;
1872 l_uint16 *rmap, *gmap, *bmap;
1873 l_int32 xres, yres;
1874 l_uint32 w, h;
1875 
1876  PROCNAME("tiffReadHeaderTiff");
1877 
1878  if (!tif)
1879  return ERROR_INT("tif not opened", procName, 1);
1880 
1881  if (pw) {
1882  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
1883  *pw = w;
1884  }
1885  if (ph) {
1886  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
1887  *ph = h;
1888  }
1889  if (pbps) {
1890  TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
1891  *pbps = bps;
1892  }
1893  if (pspp) {
1894  TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
1895  *pspp = spp;
1896  }
1897  if (pres) {
1898  *pres = 300; /* default ppi */
1899  if (getTiffStreamResolution(tif, &xres, &yres) == 0)
1900  *pres = (l_int32)xres;
1901  }
1902  if (pcmap) {
1903  *pcmap = 0;
1904  if (TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap))
1905  *pcmap = 1;
1906  }
1907  if (pformat) {
1908  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
1909  *pformat = getTiffCompressedFormat(tiffcomp);
1910  }
1911  return 0;
1912 }
1913 
1914 
1934 l_ok
1936  l_int32 *pcomptype)
1937 {
1938 l_uint16 tiffcomp;
1939 TIFF *tif;
1940 
1941  PROCNAME("findTiffCompression");
1942 
1943  if (!pcomptype)
1944  return ERROR_INT("&comptype not defined", procName, 1);
1945  *pcomptype = IFF_UNKNOWN; /* init */
1946  if (!fp)
1947  return ERROR_INT("stream not defined", procName, 1);
1948 
1949  if ((tif = fopenTiff(fp, "r")) == NULL)
1950  return ERROR_INT("tif not opened", procName, 1);
1951  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
1952  *pcomptype = getTiffCompressedFormat(tiffcomp);
1953  TIFFCleanup(tif);
1954  return 0;
1955 }
1956 
1957 
1972 static l_int32
1973 getTiffCompressedFormat(l_uint16 tiffcomp)
1974 {
1975 l_int32 comptype;
1976 
1977  switch (tiffcomp)
1978  {
1979  case COMPRESSION_CCITTFAX4:
1980  comptype = IFF_TIFF_G4;
1981  break;
1982  case COMPRESSION_CCITTFAX3:
1983  comptype = IFF_TIFF_G3;
1984  break;
1985  case COMPRESSION_CCITTRLE:
1986  comptype = IFF_TIFF_RLE;
1987  break;
1988  case COMPRESSION_PACKBITS:
1989  comptype = IFF_TIFF_PACKBITS;
1990  break;
1991  case COMPRESSION_LZW:
1992  comptype = IFF_TIFF_LZW;
1993  break;
1994  case COMPRESSION_ADOBE_DEFLATE:
1995  comptype = IFF_TIFF_ZIP;
1996  break;
1997  case COMPRESSION_JPEG:
1998  comptype = IFF_TIFF_JPEG;
1999  break;
2000  default:
2001  comptype = IFF_TIFF;
2002  break;
2003  }
2004  return comptype;
2005 }
2006 
2007 
2008 /*--------------------------------------------------------------*
2009  * Extraction of tiff g4 data *
2010  *--------------------------------------------------------------*/
2022 l_ok
2023 extractG4DataFromFile(const char *filein,
2024  l_uint8 **pdata,
2025  size_t *pnbytes,
2026  l_int32 *pw,
2027  l_int32 *ph,
2028  l_int32 *pminisblack)
2029 {
2030 l_uint8 *inarray, *data;
2031 l_uint16 minisblack, comptype; /* accessors require l_uint16 */
2032 l_int32 istiff;
2033 l_uint32 w, h, rowsperstrip; /* accessors require l_uint32 */
2034 l_uint32 diroff;
2035 size_t fbytes, nbytes;
2036 FILE *fpin;
2037 TIFF *tif;
2038 
2039  PROCNAME("extractG4DataFromFile");
2040 
2041  if (!pdata)
2042  return ERROR_INT("&data not defined", procName, 1);
2043  if (!pnbytes)
2044  return ERROR_INT("&nbytes not defined", procName, 1);
2045  if (!pw && !ph && !pminisblack)
2046  return ERROR_INT("no output data requested", procName, 1);
2047  *pdata = NULL;
2048  *pnbytes = 0;
2049 
2050  if ((fpin = fopenReadStream(filein)) == NULL)
2051  return ERROR_INT("stream not opened to file", procName, 1);
2052  istiff = fileFormatIsTiff(fpin);
2053  fclose(fpin);
2054  if (!istiff)
2055  return ERROR_INT("filein not tiff", procName, 1);
2056 
2057  if ((inarray = l_binaryRead(filein, &fbytes)) == NULL)
2058  return ERROR_INT("inarray not made", procName, 1);
2059 
2060  /* Get metadata about the image */
2061  if ((tif = openTiff(filein, "rb")) == NULL) {
2062  LEPT_FREE(inarray);
2063  return ERROR_INT("tif not open for read", procName, 1);
2064  }
2065  TIFFGetField(tif, TIFFTAG_COMPRESSION, &comptype);
2066  if (comptype != COMPRESSION_CCITTFAX4) {
2067  LEPT_FREE(inarray);
2068  TIFFClose(tif);
2069  return ERROR_INT("filein is not g4 compressed", procName, 1);
2070  }
2071 
2072  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
2073  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
2074  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
2075  if (h != rowsperstrip)
2076  L_WARNING("more than 1 strip\n", procName);
2077  TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &minisblack); /* for 1 bpp */
2078 /* TIFFPrintDirectory(tif, stderr, 0); */
2079  TIFFClose(tif);
2080  if (pw) *pw = (l_int32)w;
2081  if (ph) *ph = (l_int32)h;
2082  if (pminisblack) *pminisblack = (l_int32)minisblack;
2083 
2084  /* The header has 8 bytes: the first 2 are the magic number,
2085  * the next 2 are the version, and the last 4 are the
2086  * offset to the first directory. That's what we want here.
2087  * We have to test the byte order before decoding 4 bytes! */
2088  if (inarray[0] == 0x4d) { /* big-endian */
2089  diroff = (inarray[4] << 24) | (inarray[5] << 16) |
2090  (inarray[6] << 8) | inarray[7];
2091  } else { /* inarray[0] == 0x49 : little-endian */
2092  diroff = (inarray[7] << 24) | (inarray[6] << 16) |
2093  (inarray[5] << 8) | inarray[4];
2094  }
2095 /* fprintf(stderr, " diroff = %d, %x\n", diroff, diroff); */
2096 
2097  /* Extract the ccittg4 encoded data from the tiff file.
2098  * We skip the 8 byte header and take nbytes of data,
2099  * up to the beginning of the directory (at diroff) */
2100  nbytes = diroff - 8;
2101  *pnbytes = nbytes;
2102  if ((data = (l_uint8 *)LEPT_CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
2103  LEPT_FREE(inarray);
2104  return ERROR_INT("data not allocated", procName, 1);
2105  }
2106  *pdata = data;
2107  memcpy(data, inarray + 8, nbytes);
2108  LEPT_FREE(inarray);
2109 
2110  return 0;
2111 }
2112 
2113 
2114 /*--------------------------------------------------------------*
2115  * Open tiff stream from file stream *
2116  *--------------------------------------------------------------*/
2137 static TIFF *
2138 fopenTiff(FILE *fp,
2139  const char *modestring)
2140 {
2141  PROCNAME("fopenTiff");
2142 
2143  if (!fp)
2144  return (TIFF *)ERROR_PTR("stream not opened", procName, NULL);
2145  if (!modestring)
2146  return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
2147 
2148  TIFFSetWarningHandler(NULL); /* disable warnings */
2149  TIFFSetErrorHandler(NULL); /* disable error messages */
2150 
2151  fseek(fp, 0, SEEK_SET);
2152  return TIFFClientOpen("TIFFstream", modestring, (thandle_t)fp,
2153  lept_read_proc, lept_write_proc, lept_seek_proc,
2154  lept_close_proc, lept_size_proc, NULL, NULL);
2155 }
2156 
2157 
2158 /*--------------------------------------------------------------*
2159  * Wrapper for TIFFOpen *
2160  *--------------------------------------------------------------*/
2173 static TIFF *
2174 openTiff(const char *filename,
2175  const char *modestring)
2176 {
2177 char *fname;
2178 TIFF *tif;
2179 
2180  PROCNAME("openTiff");
2181 
2182  if (!filename)
2183  return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
2184  if (!modestring)
2185  return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
2186 
2187  TIFFSetWarningHandler(NULL); /* disable warnings */
2188  TIFFSetErrorHandler(NULL); /* disable error messages */
2189 
2190  fname = genPathname(filename, NULL);
2191  tif = TIFFOpen(fname, modestring);
2192  LEPT_FREE(fname);
2193  return tif;
2194 }
2195 
2196 
2197 /*----------------------------------------------------------------------*
2198  * Memory I/O: reading memory --> pix and writing pix --> memory *
2199  *----------------------------------------------------------------------*/
2200 /* It would be nice to use open_memstream() and fmemopen()
2201  * for writing and reading to memory, rsp. These functions manage
2202  * memory for writes and reads that use a file streams interface.
2203  * Unfortunately, the tiff library only has an interface for reading
2204  * and writing to file descriptors, not to file streams. The tiff
2205  * library procedure is to open a "tiff stream" and read/write to it.
2206  * The library provides a client interface for managing the I/O
2207  * from memory, which requires seven callbacks. See the TIFFClientOpen
2208  * man page for callback signatures. Adam Langley provided the code
2209  * to do this. */
2210 
2232 {
2233  l_uint8 *buffer; /* expands to hold data when written to; */
2234  /* fixed size when read from. */
2235  size_t bufsize; /* current size allocated when written to; */
2236  /* fixed size of input data when read from. */
2237  size_t offset; /* byte offset from beginning of buffer. */
2238  size_t hw; /* high-water mark; max bytes in buffer. */
2239  l_uint8 **poutdata; /* input param for writing; data goes here. */
2240  size_t *poutsize; /* input param for writing; data size goes here. */
2241 };
2242 typedef struct L_Memstream L_MEMSTREAM;
2243 
2244 
2245  /* These are static functions for memory I/O */
2246 static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);
2247 static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
2248  size_t *poutsize);
2249 static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);
2250 static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
2251  tsize_t length);
2252 static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);
2253 static l_int32 tiffCloseCallback(thandle_t handle);
2254 static toff_t tiffSizeCallback(thandle_t handle);
2255 static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);
2256 static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);
2257 
2258 
2259 static L_MEMSTREAM *
2260 memstreamCreateForRead(l_uint8 *indata,
2261  size_t insize)
2262 {
2263 L_MEMSTREAM *mstream;
2264 
2265  mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2266  mstream->buffer = indata; /* handle to input data array */
2267  mstream->bufsize = insize; /* amount of input data */
2268  mstream->hw = insize; /* high-water mark fixed at input data size */
2269  mstream->offset = 0; /* offset always starts at 0 */
2270  return mstream;
2271 }
2272 
2273 
2274 static L_MEMSTREAM *
2275 memstreamCreateForWrite(l_uint8 **poutdata,
2276  size_t *poutsize)
2277 {
2278 L_MEMSTREAM *mstream;
2279 
2280  mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2281  mstream->buffer = (l_uint8 *)LEPT_CALLOC(8 * 1024, 1);
2282  mstream->bufsize = 8 * 1024;
2283  mstream->poutdata = poutdata; /* used only at end of write */
2284  mstream->poutsize = poutsize; /* ditto */
2285  mstream->hw = mstream->offset = 0;
2286  return mstream;
2287 }
2288 
2289 
2290 static tsize_t
2291 tiffReadCallback(thandle_t handle,
2292  tdata_t data,
2293  tsize_t length)
2294 {
2295 L_MEMSTREAM *mstream;
2296 size_t amount;
2297 
2298  mstream = (L_MEMSTREAM *)handle;
2299  amount = L_MIN((size_t)length, mstream->hw - mstream->offset);
2300 
2301  /* Fuzzed files can create this condition! */
2302  if (mstream->offset + amount > mstream->hw) {
2303  fprintf(stderr, "Bad file: amount too big: %lu\n",
2304  (unsigned long)amount);
2305  return 0;
2306  }
2307 
2308  memcpy(data, mstream->buffer + mstream->offset, amount);
2309  mstream->offset += amount;
2310  return amount;
2311 }
2312 
2313 
2314 static tsize_t
2315 tiffWriteCallback(thandle_t handle,
2316  tdata_t data,
2317  tsize_t length)
2318 {
2319 L_MEMSTREAM *mstream;
2320 size_t newsize;
2321 
2322  /* reallocNew() uses calloc to initialize the array.
2323  * If malloc is used instead, for some of the encoding methods,
2324  * not all the data in 'bufsize' bytes in the buffer will
2325  * have been initialized by the end of the compression. */
2326  mstream = (L_MEMSTREAM *)handle;
2327  if (mstream->offset + length > mstream->bufsize) {
2328  newsize = 2 * (mstream->offset + length);
2329  mstream->buffer = (l_uint8 *)reallocNew((void **)&mstream->buffer,
2330  mstream->hw, newsize);
2331  mstream->bufsize = newsize;
2332  }
2333 
2334  memcpy(mstream->buffer + mstream->offset, data, length);
2335  mstream->offset += length;
2336  mstream->hw = L_MAX(mstream->offset, mstream->hw);
2337  return length;
2338 }
2339 
2340 
2341 static toff_t
2342 tiffSeekCallback(thandle_t handle,
2343  toff_t offset,
2344  l_int32 whence)
2345 {
2346 L_MEMSTREAM *mstream;
2347 
2348  PROCNAME("tiffSeekCallback");
2349  mstream = (L_MEMSTREAM *)handle;
2350  switch (whence) {
2351  case SEEK_SET:
2352 /* fprintf(stderr, "seek_set: offset = %d\n", offset); */
2353  mstream->offset = offset;
2354  break;
2355  case SEEK_CUR:
2356 /* fprintf(stderr, "seek_cur: offset = %d\n", offset); */
2357  mstream->offset += offset;
2358  break;
2359  case SEEK_END:
2360 /* fprintf(stderr, "seek end: hw = %d, offset = %d\n",
2361  mstream->hw, offset); */
2362  mstream->offset = mstream->hw - offset; /* offset >= 0 */
2363  break;
2364  default:
2365  return (toff_t)ERROR_INT("bad whence value", procName,
2366  mstream->offset);
2367  }
2368 
2369  return mstream->offset;
2370 }
2371 
2372 
2373 static l_int32
2374 tiffCloseCallback(thandle_t handle)
2375 {
2376 L_MEMSTREAM *mstream;
2377 
2378  mstream = (L_MEMSTREAM *)handle;
2379  if (mstream->poutdata) { /* writing: save the output data */
2380  *mstream->poutdata = mstream->buffer;
2381  *mstream->poutsize = mstream->hw;
2382  }
2383  LEPT_FREE(mstream); /* never free the buffer! */
2384  return 0;
2385 }
2386 
2387 
2388 static toff_t
2389 tiffSizeCallback(thandle_t handle)
2390 {
2391 L_MEMSTREAM *mstream;
2392 
2393  mstream = (L_MEMSTREAM *)handle;
2394  return mstream->hw;
2395 }
2396 
2397 
2398 static l_int32
2399 tiffMapCallback(thandle_t handle,
2400  tdata_t *data,
2401  toff_t *length)
2402 {
2403 L_MEMSTREAM *mstream;
2404 
2405  mstream = (L_MEMSTREAM *)handle;
2406  *data = mstream->buffer;
2407  *length = mstream->hw;
2408  return 0;
2409 }
2410 
2411 
2412 static void
2413 tiffUnmapCallback(thandle_t handle,
2414  tdata_t data,
2415  toff_t length)
2416 {
2417  return;
2418 }
2419 
2420 
2441 static TIFF *
2442 fopenTiffMemstream(const char *filename,
2443  const char *operation,
2444  l_uint8 **pdata,
2445  size_t *pdatasize)
2446 {
2447 L_MEMSTREAM *mstream;
2448 TIFF *tif;
2449 
2450  PROCNAME("fopenTiffMemstream");
2451 
2452  if (!filename)
2453  return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
2454  if (!operation)
2455  return (TIFF *)ERROR_PTR("operation not defined", procName, NULL);
2456  if (!pdata)
2457  return (TIFF *)ERROR_PTR("&data not defined", procName, NULL);
2458  if (!pdatasize)
2459  return (TIFF *)ERROR_PTR("&datasize not defined", procName, NULL);
2460  if (strcmp(operation, "r") && strcmp(operation, "w"))
2461  return (TIFF *)ERROR_PTR("op not 'r' or 'w'", procName, NULL);
2462 
2463  if (!strcmp(operation, "r"))
2464  mstream = memstreamCreateForRead(*pdata, *pdatasize);
2465  else
2466  mstream = memstreamCreateForWrite(pdata, pdatasize);
2467 
2468  TIFFSetWarningHandler(NULL); /* disable warnings */
2469  TIFFSetErrorHandler(NULL); /* disable error messages */
2470 
2471  tif = TIFFClientOpen(filename, operation, (thandle_t)mstream,
2472  tiffReadCallback, tiffWriteCallback,
2473  tiffSeekCallback, tiffCloseCallback,
2474  tiffSizeCallback, tiffMapCallback,
2475  tiffUnmapCallback);
2476  if (!tif)
2477  LEPT_FREE(mstream);
2478  return tif;
2479 }
2480 
2481 
2502 PIX *
2503 pixReadMemTiff(const l_uint8 *cdata,
2504  size_t size,
2505  l_int32 n)
2506 {
2507 l_uint8 *data;
2508 l_int32 i;
2509 PIX *pix;
2510 TIFF *tif;
2511 
2512  PROCNAME("pixReadMemTiff");
2513 
2514  if (!cdata)
2515  return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
2516 
2517  data = (l_uint8 *)cdata; /* we're really not going to change this */
2518  if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2519  return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
2520 
2521  pix = NULL;
2522  for (i = 0; ; i++) {
2523  if (i == n) {
2524  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2525  TIFFClose(tif);
2526  return NULL;
2527  }
2528  pixSetInputFormat(pix, IFF_TIFF);
2529  break;
2530  }
2531  if (TIFFReadDirectory(tif) == 0)
2532  break;
2533  if (i == MANY_PAGES_IN_TIFF_FILE + 1) {
2534  L_WARNING("big file: more than %d pages\n", procName,
2535  MANY_PAGES_IN_TIFF_FILE);
2536  }
2537  }
2538 
2539  TIFFClose(tif);
2540  return pix;
2541 }
2542 
2543 
2567 PIX *
2568 pixReadMemFromMultipageTiff(const l_uint8 *cdata,
2569  size_t size,
2570  size_t *poffset)
2571 {
2572 l_uint8 *data;
2573 l_int32 retval;
2574 size_t offset;
2575 PIX *pix;
2576 TIFF *tif;
2577 
2578  PROCNAME("pixReadMemFromMultipageTiff");
2579 
2580  if (!cdata)
2581  return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
2582  if (!poffset)
2583  return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);
2584 
2585  data = (l_uint8 *)cdata; /* we're really not going to change this */
2586  if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2587  return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
2588 
2589  /* Set ptrs in the TIFF to the beginning of the image */
2590  offset = *poffset;
2591  retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
2592  : TIFFSetSubDirectory(tif, offset);
2593  if (retval == 0) {
2594  TIFFClose(tif);
2595  return NULL;
2596  }
2597 
2598  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2599  TIFFClose(tif);
2600  return NULL;
2601  }
2602 
2603  /* Advance to the next image and return the new offset */
2604  TIFFReadDirectory(tif);
2605  *poffset = TIFFCurrentDirOffset(tif);
2606  TIFFClose(tif);
2607  return pix;
2608 }
2609 
2610 
2623 PIXA *
2624 pixaReadMemMultipageTiff(const l_uint8 *data,
2625  size_t size)
2626 {
2627 size_t offset;
2628 PIX *pix;
2629 PIXA *pixa;
2630 
2631  PROCNAME("pixaReadMemMultipageTiff");
2632 
2633  if (!data)
2634  return (PIXA *)ERROR_PTR("data not defined", procName, NULL);
2635 
2636  offset = 0;
2637  pixa = pixaCreate(0);
2638  do {
2639  pix = pixReadMemFromMultipageTiff(data, size, &offset);
2640  pixaAddPix(pixa, pix, L_INSERT);
2641  } while (offset != 0);
2642  return pixa;
2643 }
2644 
2645 
2663 l_ok
2665  size_t *psize,
2666  PIXA *pixa)
2667 {
2668 const char *modestr;
2669 l_int32 i, n;
2670 FILE *fp;
2671 PIX *pix1, *pix2;
2672 
2673  PROCNAME("pixaWriteMemMultipageTiff");
2674 
2675  if (pdata) *pdata = NULL;
2676  if (!pdata)
2677  return ERROR_INT("pdata not defined", procName, 1);
2678  if (!pixa)
2679  return ERROR_INT("pixa not defined", procName, 1);
2680 
2681 #ifdef _WIN32
2682  if ((fp = fopenWriteWinTempfile()) == NULL)
2683  return ERROR_INT("tmpfile stream not opened", procName, 1);
2684 #else
2685  if ((fp = tmpfile()) == NULL)
2686  return ERROR_INT("tmpfile stream not opened", procName, 1);
2687 #endif /* _WIN32 */
2688 
2689  n = pixaGetCount(pixa);
2690  for (i = 0; i < n; i++) {
2691  modestr = (i == 0) ? "w" : "a";
2692  pix1 = pixaGetPix(pixa, i, L_CLONE);
2693  if (pixGetDepth(pix1) == 1) {
2694  pixWriteStreamTiffWA(fp, pix1, IFF_TIFF_G4, modestr);
2695  } else {
2696  if (pixGetColormap(pix1)) {
2698  } else {
2699  pix2 = pixClone(pix1);
2700  }
2701  pixWriteStreamTiffWA(fp, pix2, IFF_TIFF_ZIP, modestr);
2702  pixDestroy(&pix2);
2703  }
2704  pixDestroy(&pix1);
2705  }
2706 
2707  rewind(fp);
2708  *pdata = l_binaryReadStream(fp, psize);
2709  fclose(fp);
2710  return 0;
2711 }
2712 
2713 
2729 l_ok
2730 pixWriteMemTiff(l_uint8 **pdata,
2731  size_t *psize,
2732  PIX *pix,
2733  l_int32 comptype)
2734 {
2735  return pixWriteMemTiffCustom(pdata, psize, pix, comptype,
2736  NULL, NULL, NULL, NULL);
2737 }
2738 
2739 
2760 l_ok
2761 pixWriteMemTiffCustom(l_uint8 **pdata,
2762  size_t *psize,
2763  PIX *pix,
2764  l_int32 comptype,
2765  NUMA *natags,
2766  SARRAY *savals,
2767  SARRAY *satypes,
2768  NUMA *nasizes)
2769 {
2770 l_int32 ret;
2771 TIFF *tif;
2772 
2773  PROCNAME("pixWriteMemTiffCustom");
2774 
2775  if (!pdata)
2776  return ERROR_INT("&data not defined", procName, 1);
2777  if (!psize)
2778  return ERROR_INT("&size not defined", procName, 1);
2779  if (!pix)
2780  return ERROR_INT("&pix not defined", procName, 1);
2781  if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
2782  comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
2783  comptype != IFF_TIFF_JPEG) {
2784  L_WARNING("invalid compression type for bpp > 1\n", procName);
2785  comptype = IFF_TIFF_ZIP;
2786  }
2787 
2788  if ((tif = fopenTiffMemstream("tifferror", "w", pdata, psize)) == NULL)
2789  return ERROR_INT("tiff stream not opened", procName, 1);
2790  ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
2791  satypes, nasizes);
2792 
2793  TIFFClose(tif);
2794  return ret;
2795 }
2796 
2797 /* --------------------------------------------*/
2798 #endif /* HAVE_LIBTIFF */
2799 /* --------------------------------------------*/
l_ok pixWriteTiff(const char *filename, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteTiff()
Definition: tiffio.c:679
PIX * pixFlipLR(PIX *pixd, PIX *pixs)
pixFlipLR()
Definition: rotateorth.c:423
l_ok readHeaderTiff(const char *filename, l_int32 n, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
readHeaderTiff()
Definition: tiffio.c:1672
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
PIX * pixReadStreamTiff(FILE *fp, l_int32 n)
pixReadStreamTiff()
Definition: tiffio.c:406
static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres, l_int32 *pyres)
getTiffStreamResolution()
Definition: tiffio.c:1606
l_ok pixWriteMemTiff(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype)
pixWriteMemTiff()
Definition: tiffio.c:2730
Definition: pix.h:717
l_ok fprintTiffInfo(FILE *fpout, const char *tiffile)
fprintTiffInfo()
Definition: tiffio.c:1489
PIXA * pixaReadMultipageTiff(const char *filename)
pixaReadMultipageTiff()
Definition: tiffio.c:1272
l_ok pixWriteStreamTiffWA(FILE *fp, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteStreamTiffWA()
Definition: tiffio.c:823
l_ok extractG4DataFromFile(const char *filein, l_uint8 **pdata, size_t *pnbytes, l_int32 *pw, l_int32 *ph, l_int32 *pminisblack)
extractG4DataFromFile()
Definition: tiffio.c:2023
static l_int32 tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
tiffReadHeaderTiff()
Definition: tiffio.c:1861
char * genPathname(const char *dir, const char *fname)
genPathname()
Definition: utils2.c:2880
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:163
l_ok pixaWriteMultipageTiff(const char *fname, PIXA *pixa)
pixaWriteMultipageTiff()
Definition: tiffio.c:1332
Definition: pix.h:716
l_ok writeMultipageTiff(const char *dirin, const char *substr, const char *fileout)
writeMultipageTiff()
Definition: tiffio.c:1393
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
l_ok pixWriteStreamTiff(FILE *fp, PIX *pix, l_int32 comptype)
pixWriteStreamTiff()
Definition: tiffio.c:803
l_ok readHeaderMemTiff(const l_uint8 *cdata, size_t size, l_int32 n, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
readHeaderMemTiff()
Definition: tiffio.c:1800
Memory stream buffer used with TIFFClientOpen()
Definition: tiffio.c:2231
void * reallocNew(void **pindata, l_int32 oldsize, l_int32 newsize)
reallocNew()
Definition: utils2.c:1161
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1573
Definition: array.h:116
PIX * pixReadMemFromMultipageTiff(const l_uint8 *cdata, size_t size, size_t *poffset)
pixReadMemFromMultipageTiff()
Definition: tiffio.c:2568
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1483
static TIFF * fopenTiff(FILE *fp, const char *modestring)
fopenTiff()
Definition: tiffio.c:2138
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:111
l_ok freadHeaderTiff(FILE *fp, l_int32 n, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
freadHeaderTiff()
Definition: tiffio.c:1728
l_ok findFileFormatStream(FILE *fp, l_int32 *pformat)
findFileFormatStream()
Definition: readfile.c:615
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1212
PIX * pixEndianTwoByteSwapNew(PIX *pixs)
pixEndianTwoByteSwapNew()
Definition: pix2.c:3053
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
PIX * pixFlipTB(PIX *pixd, PIX *pixs)
pixFlipTB()
Definition: rotateorth.c:601
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
Definition: array.h:59
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok getTiffResolution(FILE *fp, l_int32 *pxres, l_int32 *pyres)
getTiffResolution()
Definition: tiffio.c:1570
l_ok pixcmapToArrays(PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:1856
l_ok pixWriteTiffCustom(const char *filename, PIX *pix, l_int32 comptype, const char *modestr, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteTiffCustom()
Definition: tiffio.c:736
static TIFF * fopenTiffMemstream(const char *filename, const char *operation, l_uint8 **pdata, size_t *pdatasize)
fopenTiffMemstream()
Definition: tiffio.c:2442
l_ok pixEndianByteSwap(PIX *pixs)
pixEndianByteSwap()
Definition: pix2.c:2942
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1307
static PIX * pixReadFromTiffStream(TIFF *tif)
pixReadFromTiffStream()
Definition: tiffio.c:467
l_ok pixEndianTwoByteSwap(PIX *pixs)
pixEndianTwoByteSwap()
Definition: pix2.c:3106
static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteToTiffStream()
Definition: tiffio.c:904
FILE * fopenWriteWinTempfile()
fopenWriteWinTempfile()
Definition: utils2.c:1780
static TIFF * openTiff(const char *filename, const char *modestring)
openTiff()
Definition: tiffio.c:2174
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
l_ok findFileFormat(const char *filename, l_int32 *pformat)
findFileFormat()
Definition: readfile.c:580
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:681
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
SARRAY * getSortedPathnamesInDirectory(const char *dirname, const char *substr, l_int32 first, l_int32 nfiles)
getSortedPathnamesInDirectory()
Definition: sarray1.c:1717
Definition: pix.h:454
PIX * pixReadMemTiff(const l_uint8 *cdata, size_t size, l_int32 n)
pixReadMemTiff()
Definition: tiffio.c:2503
PIX * pixEndianByteSwapNew(PIX *pixs)
pixEndianByteSwapNew()
Definition: pix2.c:2879
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
l_int32 fileFormatIsTiff(FILE *fp)
fileFormatIsTiff()
Definition: readfile.c:795
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1657
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1262
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:621
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:190
l_ok writeMultipageTiffSA(SARRAY *sa, const char *fileout)
writeMultipageTiffSA()
Definition: tiffio.c:1429
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1459
l_ok findTiffCompression(FILE *fp, l_int32 *pcomptype)
findTiffCompression()
Definition: tiffio.c:1935
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp)
getTiffCompressedFormat()
Definition: tiffio.c:1973
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:635
l_ok pixaWriteMemMultipageTiff(l_uint8 **pdata, size_t *psize, PIXA *pixa)
pixaWriteMemMultipageTiff()
Definition: tiffio.c:2664
Definition: pix.h:134
Definition: pix.h:719
PIX * pixReadTiff(const char *filename, l_int32 n)
pixReadTiff()
Definition: tiffio.c:369
PIX * pixReadFromMultipageTiff(const char *fname, size_t *poffset)
pixReadFromMultipageTiff()
Definition: tiffio.c:1223
Definition: pix.h:201
PIX * pixRotate90(PIX *pixs, l_int32 direction)
pixRotate90()
Definition: rotateorth.c:163
static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
writeCustomTiffTags()
Definition: tiffio.c:1096
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:341
l_ok tiffGetCount(FILE *fp, l_int32 *pn)
tiffGetCount()
Definition: tiffio.c:1522
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:631
l_ok pixWriteMemTiffCustom(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteMemTiffCustom()
Definition: tiffio.c:2761
PIXA * pixaReadMemMultipageTiff(const l_uint8 *data, size_t size)
pixaReadMemMultipageTiff()
Definition: tiffio.c:2624
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355