Leptonica  1.73
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 <sys/types.h>
105 #ifndef _MSC_VER
106 #include <unistd.h>
107 #else /* _MSC_VER */
108 #include <io.h>
109 #endif /* _MSC_VER */
110 #include <fcntl.h>
111 #include "allheaders.h"
112 
113 /* --------------------------------------------*/
114 #if HAVE_LIBTIFF /* defined in environ.h */
115 /* --------------------------------------------*/
116 
117 #include "tiff.h"
118 #include "tiffio.h"
119 
120 static const l_int32 DEFAULT_RESOLUTION = 300; /* ppi */
121 static const l_int32 MANY_PAGES_IN_TIFF_FILE = 3000; /* warn if big */
122 
123 
124  /* All functions with TIFF interfaces are static. */
125 static PIX *pixReadFromTiffStream(TIFF *tif);
126 static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
127  l_int32 *pyres);
128 static l_int32 tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
129  l_int32 *pheight, l_int32 *pbps,
130  l_int32 *pspp, l_int32 *pres,
131  l_int32 *pcmap, l_int32 *pformat);
132 static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags,
133  SARRAY *savals, SARRAY *satypes,
134  NUMA *nasizes);
135 static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
136  NUMA *natags, SARRAY *savals,
137  SARRAY *satypes, NUMA *nasizes);
138 static TIFF *fopenTiff(FILE *fp, const char *modestring);
139 static TIFF *openTiff(const char *filename, const char *modestring);
140 
141  /* Static helper for tiff compression type */
142 static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp);
143 
144  /* Static function for memory I/O */
145 static TIFF *fopenTiffMemstream(const char *filename, const char *operation,
146  l_uint8 **pdata, size_t *pdatasize);
147 
148  /* Static dummy warning/error handler */
149 static void dummyHandler(const char *module, const char *fmt, va_list ap) {};
150 
151  /* This structure defines a transform to be performed on a TIFF image
152  * (note that the same transformation can be represented in
153  * several different ways using this structure since
154  * vflip + hflip + counterclockwise == clockwise). */
156  int vflip; /* if non-zero, image needs a vertical fip */
157  int hflip; /* if non-zero, image needs a horizontal flip */
158  int rotate; /* -1 -> counterclockwise 90-degree rotation,
159  0 -> no rotation
160  1 -> clockwise 90-degree rotation */
161 };
162 
163  /* This describes the transformations needed for a given orientation
164  * tag. The tag values start at 1, so you need to subtract 1 to get a
165  * valid index into this array. It is only valid when not using
166  * TIFFReadRGBAImageOriented(). */
167 static struct tiff_transform tiff_orientation_transforms[] = {
168  {0, 0, 0},
169  {0, 1, 0},
170  {1, 1, 0},
171  {1, 0, 0},
172  {0, 1, -1},
173  {0, 0, 1},
174  {0, 1, 1},
175  {0, 0, -1}
176 };
177 
178  /* Same as above, except that test transformations are only valid
179  * when using TIFFReadRGBAImageOriented(). Transformations
180  * were determined empirically. See the libtiff mailing list for
181  * more discussion: http://www.asmail.be/msg0054683875.html */
182 static struct tiff_transform tiff_partial_orientation_transforms[] = {
183  {0, 0, 0},
184  {0, 0, 0},
185  {0, 0, 0},
186  {0, 0, 0},
187  {0, 1, -1},
188  {0, 1, 1},
189  {1, 0, 1},
190  {0, 1, -1}
191 };
192 
193 
194 /*-----------------------------------------------------------------------*
195  * TIFFClientOpen() wrappers for FILE* *
196  * Provided by Jürgen Buchmüller *
197  * *
198  * We previously used TIFFFdOpen(), which used low-level file *
199  * descriptors. It had portability issues with Windows, along *
200  * with other limitations from lack of stream control operations. *
201  * These callbacks to TIFFClientOpen() avoid the problems. *
202  * *
203  * Jürgen made the functions use 64 bit file operations where possible *
204  * or required, namely for seek and size. On Windows there are specific *
205  * _fseeki64() and _ftelli64() functions, whereas on unix it is *
206  * common to look for a macro _LARGEFILE_SOURCE being defined and *
207  * use fseeko() and ftello() in this case. *
208  *-----------------------------------------------------------------------*/
209 static tsize_t
210 lept_read_proc(thandle_t cookie,
211  tdata_t buff,
212  tsize_t size)
213 {
214  FILE* fp = (FILE *)cookie;
215  tsize_t done;
216  if (!buff || !cookie || !fp)
217  return (tsize_t)-1;
218  done = fread(buff, 1, size, fp);
219  return done;
220 }
221 
222 static tsize_t
223 lept_write_proc(thandle_t cookie,
224  tdata_t buff,
225  tsize_t size)
226 {
227  FILE* fp = (FILE *)cookie;
228  tsize_t done;
229  if (!buff || !cookie || !fp)
230  return (tsize_t)-1;
231  done = fwrite(buff, 1, size, fp);
232  return done;
233 }
234 
235 static toff_t
236 lept_seek_proc(thandle_t cookie,
237  toff_t offs,
238  int whence)
239 {
240  FILE* fp = (FILE *)cookie;
241 #if defined(_MSC_VER)
242  __int64 pos = 0;
243  if (!cookie || !fp)
244  return (tsize_t)-1;
245  switch (whence) {
246  case SEEK_SET:
247  pos = 0;
248  break;
249  case SEEK_CUR:
250  pos = ftell(fp);
251  break;
252  case SEEK_END:
253  _fseeki64(fp, 0, SEEK_END);
254  pos = _ftelli64(fp);
255  break;
256  }
257  pos = (__int64)(pos + offs);
258  _fseeki64(fp, pos, SEEK_SET);
259  if (pos == _ftelli64(fp))
260  return (tsize_t)pos;
261 #elif defined(_LARGEFILE_SOURCE)
262  off64_t pos = 0;
263  if (!cookie || !fp)
264  return (tsize_t)-1;
265  switch (whence) {
266  case SEEK_SET:
267  pos = 0;
268  break;
269  case SEEK_CUR:
270  pos = ftello(fp);
271  break;
272  case SEEK_END:
273  fseeko(fp, 0, SEEK_END);
274  pos = ftello(fp);
275  break;
276  }
277  pos = (off64_t)(pos + offs);
278  fseeko(fp, pos, SEEK_SET);
279  if (pos == ftello(fp))
280  return (tsize_t)pos;
281 #else
282  off_t pos = 0;
283  if (!cookie || !fp)
284  return (tsize_t)-1;
285  switch (whence) {
286  case SEEK_SET:
287  pos = 0;
288  break;
289  case SEEK_CUR:
290  pos = ftell(fp);
291  break;
292  case SEEK_END:
293  fseek(fp, 0, SEEK_END);
294  pos = ftell(fp);
295  break;
296  }
297  pos = (off_t)(pos + offs);
298  fseek(fp, pos, SEEK_SET);
299  if (pos == ftell(fp))
300  return (tsize_t)pos;
301 #endif
302  return (tsize_t)-1;
303 }
304 
305 static int
306 lept_close_proc(thandle_t cookie)
307 {
308  FILE* fp = (FILE *)cookie;
309  if (!cookie || !fp)
310  return 0;
311  fseek(fp, 0, SEEK_SET);
312  return 0;
313 }
314 
315 static toff_t
316 lept_size_proc(thandle_t cookie)
317 {
318  FILE* fp = (FILE *)cookie;
319 #if defined(_MSC_VER)
320  __int64 pos;
321  __int64 size;
322  if (!cookie || !fp)
323  return (tsize_t)-1;
324  pos = _ftelli64(fp);
325  _fseeki64(fp, 0, SEEK_END);
326  size = _ftelli64(fp);
327  _fseeki64(fp, pos, SEEK_SET);
328 #elif defined(_LARGEFILE_SOURCE)
329  off64_t pos;
330  off64_t size;
331  if (!fp)
332  return (tsize_t)-1;
333  pos = ftello(fp);
334  fseeko(fp, 0, SEEK_END);
335  size = ftello(fp);
336  fseeko(fp, pos, SEEK_SET);
337 #else
338  off_t pos;
339  off_t size;
340  if (!cookie || !fp)
341  return (tsize_t)-1;
342  pos = ftell(fp);
343  fseek(fp, 0, SEEK_END);
344  size = ftell(fp);
345  fseek(fp, pos, SEEK_SET);
346 #endif
347  return (toff_t)size;
348 }
349 
350 
351 /*--------------------------------------------------------------*
352  * Reading from file *
353  *--------------------------------------------------------------*/
370 PIX *
371 pixReadTiff(const char *filename,
372  l_int32 n)
373 {
374 FILE *fp;
375 PIX *pix;
376 
377  PROCNAME("pixReadTiff");
378 
379  if (!filename)
380  return (PIX *)ERROR_PTR("filename not defined", procName, NULL);
381 
382  if ((fp = fopenReadStream(filename)) == NULL)
383  return (PIX *)ERROR_PTR("image file not found", procName, NULL);
384  pix = pixReadStreamTiff(fp, n);
385  fclose(fp);
386  return pix;
387 }
388 
389 
390 /*--------------------------------------------------------------*
391  * Reading from stream *
392  *--------------------------------------------------------------*/
407 PIX *
409  l_int32 n)
410 {
411 PIX *pix;
412 TIFF *tif;
413 
414  PROCNAME("pixReadStreamTiff");
415 
416  if (!fp)
417  return (PIX *)ERROR_PTR("stream not defined", procName, NULL);
418 
419  if ((tif = fopenTiff(fp, "r")) == NULL)
420  return (PIX *)ERROR_PTR("tif not opened", procName, NULL);
421 
422  if (TIFFSetDirectory(tif, n) == 0) {
423  TIFFCleanup(tif);
424  return NULL;
425  }
426  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
427  TIFFCleanup(tif);
428  return NULL;
429  }
430  TIFFCleanup(tif);
431  return pix;
432 }
433 
434 
468 static PIX *
470 {
471 l_uint8 *linebuf, *data;
472 l_uint16 spp, bps, bpp, photometry, tiffcomp, orientation;
473 l_uint16 *redmap, *greenmap, *bluemap;
474 l_int32 d, wpl, bpl, comptype, i, j, ncolors, rval, gval, bval;
475 l_int32 xres, yres;
476 l_uint32 w, h, tiffbpl, tiffword;
477 l_uint32 *line, *ppixel, *tiffdata;
478 l_uint32 read_oriented;
479 PIX *pix;
480 PIXCMAP *cmap;
481 
482  PROCNAME("pixReadFromTiffStream");
483 
484  if (!tif)
485  return (PIX *)ERROR_PTR("tif not defined", procName, NULL);
486 
487  read_oriented = 0;
488 
489  /* Use default fields for bps and spp */
490  TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
491  TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
492  bpp = bps * spp;
493  if (bpp > 32)
494  L_WARNING("bpp = %d; stripping 16 bit rgb samples down to 8\n",
495  procName, bpp);
496  if (spp == 1)
497  d = bps;
498  else if (spp == 3 || spp == 4)
499  d = 32;
500  else
501  return (PIX *)ERROR_PTR("spp not in set {1,3,4}", procName, NULL);
502 
503  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
504  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
505  tiffbpl = TIFFScanlineSize(tif);
506 
507  if ((pix = pixCreate(w, h, d)) == NULL)
508  return (PIX *)ERROR_PTR("pix not made", procName, NULL);
509  pixSetInputFormat(pix, IFF_TIFF);
510  data = (l_uint8 *)pixGetData(pix);
511  wpl = pixGetWpl(pix);
512  bpl = 4 * wpl;
513 
514  /* Read the data */
515  if (spp == 1) {
516  linebuf = (l_uint8 *)LEPT_CALLOC(tiffbpl + 1, sizeof(l_uint8));
517  for (i = 0 ; i < h ; i++) {
518  if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
519  LEPT_FREE(linebuf);
520  pixDestroy(&pix);
521  return (PIX *)ERROR_PTR("line read fail", procName, NULL);
522  }
523  memcpy((char *)data, (char *)linebuf, tiffbpl);
524  data += bpl;
525  }
526  if (bps <= 8)
527  pixEndianByteSwap(pix);
528  else /* bps == 16 */
530  LEPT_FREE(linebuf);
531  }
532  else { /* rgb */
533  if ((tiffdata = (l_uint32 *)LEPT_CALLOC(w * h, sizeof(l_uint32)))
534  == NULL) {
535  pixDestroy(&pix);
536  return (PIX *)ERROR_PTR("calloc fail for tiffdata", procName, NULL);
537  }
538  /* TIFFReadRGBAImageOriented() converts to 8 bps */
539  if (!TIFFReadRGBAImageOriented(tif, w, h, (uint32 *)tiffdata,
540  ORIENTATION_TOPLEFT, 0)) {
541  LEPT_FREE(tiffdata);
542  pixDestroy(&pix);
543  return (PIX *)ERROR_PTR("failed to read tiffdata", procName, NULL);
544  } else {
545  read_oriented = 1;
546  }
547 
548  line = pixGetData(pix);
549  for (i = 0 ; i < h ; i++, line += wpl) {
550  for (j = 0, ppixel = line; j < w; j++) {
551  /* TIFFGet* are macros */
552  tiffword = tiffdata[i * w + j];
553  rval = TIFFGetR(tiffword);
554  gval = TIFFGetG(tiffword);
555  bval = TIFFGetB(tiffword);
556  composeRGBPixel(rval, gval, bval, ppixel);
557  ppixel++;
558  }
559  }
560  LEPT_FREE(tiffdata);
561  }
562 
563  if (getTiffStreamResolution(tif, &xres, &yres) == 0) {
564  pixSetXRes(pix, xres);
565  pixSetYRes(pix, yres);
566  }
567 
568  /* Find and save the compression type */
569  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
570  comptype = getTiffCompressedFormat(tiffcomp);
571  pixSetInputFormat(pix, comptype);
572 
573  if (TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap)) {
574  /* Save the colormap as a pix cmap. Because the
575  * tiff colormap components are 16 bit unsigned,
576  * and go from black (0) to white (0xffff), the
577  * the pix cmap takes the most significant byte. */
578  if (bps > 8) {
579  pixDestroy(&pix);
580  return (PIX *)ERROR_PTR("invalid bps; > 8", procName, NULL);
581  }
582  if ((cmap = pixcmapCreate(bps)) == NULL) {
583  pixDestroy(&pix);
584  return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
585  }
586  ncolors = 1 << bps;
587  for (i = 0; i < ncolors; i++)
588  pixcmapAddColor(cmap, redmap[i] >> 8, greenmap[i] >> 8,
589  bluemap[i] >> 8);
590  pixSetColormap(pix, cmap);
591  } else { /* No colormap: check photometry and invert if necessary */
592  if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometry)) {
593  /* Guess default photometry setting. Assume min_is_white
594  * if compressed 1 bpp; min_is_black otherwise. */
595  if (tiffcomp == COMPRESSION_CCITTFAX3 ||
596  tiffcomp == COMPRESSION_CCITTFAX4 ||
597  tiffcomp == COMPRESSION_CCITTRLE ||
598  tiffcomp == COMPRESSION_CCITTRLEW) {
599  photometry = PHOTOMETRIC_MINISWHITE;
600  } else {
601  photometry = PHOTOMETRIC_MINISBLACK;
602  }
603  }
604  if ((d == 1 && photometry == PHOTOMETRIC_MINISBLACK) ||
605  (d == 8 && photometry == PHOTOMETRIC_MINISWHITE))
606  pixInvert(pix, pix);
607  }
608 
609  if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
610  if (orientation >= 1 && orientation <= 8) {
611  struct tiff_transform *transform = (read_oriented) ?
612  &tiff_partial_orientation_transforms[orientation - 1] :
613  &tiff_orientation_transforms[orientation - 1];
614  if (transform->vflip) pixFlipTB(pix, pix);
615  if (transform->hflip) pixFlipLR(pix, pix);
616  if (transform->rotate) {
617  PIX *oldpix = pix;
618  pix = pixRotate90(oldpix, transform->rotate);
619  pixDestroy(&oldpix);
620  }
621  }
622  }
623 
624  return pix;
625 }
626 
627 
628 
629 /*--------------------------------------------------------------*
630  * Writing to file *
631  *--------------------------------------------------------------*/
653 l_int32
654 pixWriteTiff(const char *filename,
655  PIX *pix,
656  l_int32 comptype,
657  const char *modestr)
658 {
659  return pixWriteTiffCustom(filename, pix, comptype, modestr,
660  NULL, NULL, NULL, NULL);
661 }
662 
663 
710 l_int32
711 pixWriteTiffCustom(const char *filename,
712  PIX *pix,
713  l_int32 comptype,
714  const char *modestr,
715  NUMA *natags,
716  SARRAY *savals,
717  SARRAY *satypes,
718  NUMA *nasizes)
719 {
720 l_int32 ret;
721 TIFF *tif;
722 
723  PROCNAME("pixWriteTiffCustom");
724 
725  if (!filename)
726  return ERROR_INT("filename not defined", procName, 1);
727  if (!pix)
728  return ERROR_INT("pix not defined", procName, 1);
729 
730  if ((tif = openTiff(filename, modestr)) == NULL)
731  return ERROR_INT("tif not opened", procName, 1);
732  ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
733  satypes, nasizes);
734  TIFFClose(tif);
735 
736  return ret;
737 }
738 
739 
740 /*--------------------------------------------------------------*
741  * Writing to stream *
742  *--------------------------------------------------------------*/
769 l_int32
771  PIX *pix,
772  l_int32 comptype)
773 {
774  return pixWriteStreamTiffWA(fp, pix, comptype, "w");
775 }
776 
777 
789 l_int32
791  PIX *pix,
792  l_int32 comptype,
793  const char *modestr)
794 {
795 TIFF *tif;
796 
797  PROCNAME("pixWriteStreamTiffWA");
798 
799  if (!fp)
800  return ERROR_INT("stream not defined", procName, 1 );
801  if (!pix)
802  return ERROR_INT("pix not defined", procName, 1 );
803  if (strcmp(modestr, "w") && strcmp(modestr, "a"))
804  return ERROR_INT("modestr not 'w' or 'a'", procName, 1 );
805 
806  if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
807  comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP) {
808  L_WARNING("invalid compression type for bpp > 1\n", procName);
809  comptype = IFF_TIFF_ZIP;
810  }
811 
812  if ((tif = fopenTiff(fp, modestr)) == NULL)
813  return ERROR_INT("tif not opened", procName, 1);
814 
815  if (pixWriteToTiffStream(tif, pix, comptype, NULL, NULL, NULL, NULL)) {
816  TIFFCleanup(tif);
817  return ERROR_INT("tif write error", procName, 1);
818  }
819 
820  TIFFCleanup(tif);
821  return 0;
822 }
823 
824 
859 static l_int32
861  PIX *pix,
862  l_int32 comptype,
863  NUMA *natags,
864  SARRAY *savals,
865  SARRAY *satypes,
866  NUMA *nasizes)
867 {
868 l_uint8 *linebuf, *data;
869 l_uint16 redmap[256], greenmap[256], bluemap[256];
870 l_int32 w, h, d, i, j, k, wpl, bpl, tiffbpl, ncolors, cmapsize;
871 l_int32 *rmap, *gmap, *bmap;
872 l_int32 xres, yres;
873 l_uint32 *line, *ppixel;
874 PIX *pixt;
875 PIXCMAP *cmap;
876 char *text;
877 
878  PROCNAME("pixWriteToTiffStream");
879 
880  if (!tif)
881  return ERROR_INT("tif stream not defined", procName, 1);
882  if (!pix)
883  return ERROR_INT( "pix not defined", procName, 1 );
884 
885  pixSetPadBits(pix, 0);
886  pixGetDimensions(pix, &w, &h, &d);
887  xres = pixGetXRes(pix);
888  yres = pixGetYRes(pix);
889  if (xres == 0) xres = DEFAULT_RESOLUTION;
890  if (yres == 0) yres = DEFAULT_RESOLUTION;
891 
892  /* ------------------ Write out the header ------------- */
893  TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (l_uint32)RESUNIT_INCH);
894  TIFFSetField(tif, TIFFTAG_XRESOLUTION, (l_float64)xres);
895  TIFFSetField(tif, TIFFTAG_YRESOLUTION, (l_float64)yres);
896 
897  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (l_uint32)w);
898  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (l_uint32)h);
899  TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
900 
901  if ((text = pixGetText(pix)) != NULL)
902  TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, text);
903 
904  if (d == 1)
905  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
906  else if (d == 32 || d == 24) {
907  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
908  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
909  (l_uint16)8, (l_uint16)8, (l_uint16)8);
910  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)3);
911  } else if ((cmap = pixGetColormap(pix)) == NULL) {
912  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
913  } else { /* Save colormap in the tiff; not more than 256 colors */
914  pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
915  ncolors = pixcmapGetCount(cmap);
916  ncolors = L_MIN(256, ncolors); /* max 256 */
917  cmapsize = 1 << d;
918  cmapsize = L_MIN(256, cmapsize); /* power of 2; max 256 */
919  if (ncolors > cmapsize) {
920  L_WARNING("too many colors in cmap for tiff; truncating\n",
921  procName);
922  ncolors = cmapsize;
923  }
924  for (i = 0; i < ncolors; i++) {
925  redmap[i] = (rmap[i] << 8) | rmap[i];
926  greenmap[i] = (gmap[i] << 8) | gmap[i];
927  bluemap[i] = (bmap[i] << 8) | bmap[i];
928  }
929  for (i = ncolors; i < cmapsize; i++) /* init, even though not used */
930  redmap[i] = greenmap[i] = bluemap[i] = 0;
931  LEPT_FREE(rmap);
932  LEPT_FREE(gmap);
933  LEPT_FREE(bmap);
934 
935  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
936  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
937  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
938  TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
939  }
940 
941  if (d != 24 && d != 32) {
942  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
943  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
944  }
945 
946  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
947  if (comptype == IFF_TIFF) { /* no compression */
948  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
949  } else if (comptype == IFF_TIFF_G4) {
950  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
951  } else if (comptype == IFF_TIFF_G3) {
952  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
953  } else if (comptype == IFF_TIFF_RLE) {
954  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);
955  } else if (comptype == IFF_TIFF_PACKBITS) {
956  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
957  } else if (comptype == IFF_TIFF_LZW) {
958  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
959  } else if (comptype == IFF_TIFF_ZIP) {
960  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
961  } else {
962  L_WARNING("unknown tiff compression; using none\n", procName);
963  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
964  }
965 
966  /* This is a no-op if arrays are NULL */
967  writeCustomTiffTags(tif, natags, savals, satypes, nasizes);
968 
969  /* ------------- Write out the image data ------------- */
970  tiffbpl = TIFFScanlineSize(tif);
971  wpl = pixGetWpl(pix);
972  bpl = 4 * wpl;
973  if (tiffbpl > bpl)
974  fprintf(stderr, "Big trouble: tiffbpl = %d, bpl = %d\n", tiffbpl, bpl);
975  if ((linebuf = (l_uint8 *)LEPT_CALLOC(1, bpl)) == NULL)
976  return ERROR_INT("calloc fail for linebuf", procName, 1);
977 
978  /* Use single strip for image */
979  TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);
980 
981  if (d != 24 && d != 32) {
982  if (d == 16)
983  pixt = pixEndianTwoByteSwapNew(pix);
984  else
985  pixt = pixEndianByteSwapNew(pix);
986  data = (l_uint8 *)pixGetData(pixt);
987  for (i = 0; i < h; i++, data += bpl) {
988  memcpy((char *)linebuf, (char *)data, tiffbpl);
989  if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
990  break;
991  }
992  pixDestroy(&pixt);
993  } else if (d == 24) { /* See note 4 above: special case of 24 bpp rgb */
994  for (i = 0; i < h; i++) {
995  line = pixGetData(pix) + i * wpl;
996  if (TIFFWriteScanline(tif, (l_uint8 *)line, i, 0) < 0)
997  break;
998  }
999  } else { /* standard 32 bpp rgb */
1000  for (i = 0; i < h; i++) {
1001  line = pixGetData(pix) + i * wpl;
1002  for (j = 0, k = 0, ppixel = line; j < w; j++) {
1003  linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
1004  linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
1005  linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
1006  ppixel++;
1007  }
1008  if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1009  break;
1010  }
1011  }
1012 
1013 /* TIFFWriteDirectory(tif); */
1014  LEPT_FREE(linebuf);
1015 
1016  return 0;
1017 }
1018 
1019 
1049 static l_int32
1051  NUMA *natags,
1052  SARRAY *savals,
1053  SARRAY *satypes,
1054  NUMA *nasizes)
1055 {
1056 char *sval, *type;
1057 l_int32 i, n, ns, size, tagval, val;
1058 l_float64 dval;
1059 l_uint32 uval, uval2;
1060 
1061  PROCNAME("writeCustomTiffTags");
1062 
1063  if (!tif)
1064  return ERROR_INT("tif stream not defined", procName, 1);
1065  if (!natags && !savals && !satypes)
1066  return 0;
1067  if (!natags || !savals || !satypes)
1068  return ERROR_INT("not all arrays defined", procName, 1);
1069  n = numaGetCount(natags);
1070  if ((sarrayGetCount(savals) != n) || (sarrayGetCount(satypes) != n))
1071  return ERROR_INT("not all sa the same size", procName, 1);
1072 
1073  /* The sized arrays (4 args to TIFFSetField) are written first */
1074  if (nasizes) {
1075  ns = numaGetCount(nasizes);
1076  if (ns > n)
1077  return ERROR_INT("too many 4-arg tag calls", procName, 1);
1078  for (i = 0; i < ns; i++) {
1079  numaGetIValue(natags, i, &tagval);
1080  sval = sarrayGetString(savals, i, L_NOCOPY);
1081  type = sarrayGetString(satypes, i, L_NOCOPY);
1082  numaGetIValue(nasizes, i, &size);
1083  if (strcmp(type, "char*") && strcmp(type, "l_uint8*"))
1084  L_WARNING("array type not char* or l_uint8*; ignore\n",
1085  procName);
1086  TIFFSetField(tif, tagval, size, sval);
1087  }
1088  } else {
1089  ns = 0;
1090  }
1091 
1092  /* The typical tags (3 args to TIFFSetField) are now written */
1093  for (i = ns; i < n; i++) {
1094  numaGetIValue(natags, i, &tagval);
1095  sval = sarrayGetString(savals, i, L_NOCOPY);
1096  type = sarrayGetString(satypes, i, L_NOCOPY);
1097  if (!strcmp(type, "char*")) {
1098  TIFFSetField(tif, tagval, sval);
1099  } else if (!strcmp(type, "l_uint16")) {
1100  if (sscanf(sval, "%u", &uval) == 1) {
1101  TIFFSetField(tif, tagval, (l_uint16)uval);
1102  } else {
1103  fprintf(stderr, "val %s not of type %s\n", sval, type);
1104  return ERROR_INT("custom tag(s) not written", procName, 1);
1105  }
1106  } else if (!strcmp(type, "l_uint32")) {
1107  if (sscanf(sval, "%u", &uval) == 1) {
1108  TIFFSetField(tif, tagval, uval);
1109  } else {
1110  fprintf(stderr, "val %s not of type %s\n", sval, type);
1111  return ERROR_INT("custom tag(s) not written", procName, 1);
1112  }
1113  } else if (!strcmp(type, "l_int32")) {
1114  if (sscanf(sval, "%d", &val) == 1) {
1115  TIFFSetField(tif, tagval, val);
1116  } else {
1117  fprintf(stderr, "val %s not of type %s\n", sval, type);
1118  return ERROR_INT("custom tag(s) not written", procName, 1);
1119  }
1120  } else if (!strcmp(type, "l_float64")) {
1121  if (sscanf(sval, "%lf", &dval) == 1) {
1122  TIFFSetField(tif, tagval, dval);
1123  } else {
1124  fprintf(stderr, "val %s not of type %s\n", sval, type);
1125  return ERROR_INT("custom tag(s) not written", procName, 1);
1126  }
1127  } else if (!strcmp(type, "l_uint16-l_uint16")) {
1128  if (sscanf(sval, "%u-%u", &uval, &uval2) == 2) {
1129  TIFFSetField(tif, tagval, (l_uint16)uval, (l_uint16)uval2);
1130  } else {
1131  fprintf(stderr, "val %s not of type %s\n", sval, type);
1132  return ERROR_INT("custom tag(s) not written", procName, 1);
1133  }
1134  } else {
1135  return ERROR_INT("unknown type; tag(s) not written", procName, 1);
1136  }
1137  }
1138  return 0;
1139 }
1140 
1141 
1142 /*--------------------------------------------------------------*
1143  * Reading and writing multipage tiff *
1144  *--------------------------------------------------------------*/
1176 PIX *
1177 pixReadFromMultipageTiff(const char *fname,
1178  size_t *poffset)
1179 {
1180 l_int32 retval;
1181 size_t offset;
1182 PIX *pix;
1183 TIFF *tif;
1184 
1185  PROCNAME("pixReadFromMultipageTiff");
1186 
1187  if (!fname)
1188  return (PIX *)ERROR_PTR("fname not defined", procName, NULL);
1189  if (!poffset)
1190  return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);
1191 
1192  if ((tif = openTiff(fname, "r")) == NULL) {
1193  L_ERROR("tif open failed for %s\n", procName, fname);
1194  return NULL;
1195  }
1196 
1197  /* Set ptrs in the TIFF to the beginning of the image */
1198  offset = *poffset;
1199  retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
1200  : TIFFSetSubDirectory(tif, offset);
1201  if (retval == 0) {
1202  TIFFCleanup(tif);
1203  return NULL;
1204  }
1205 
1206  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
1207  TIFFCleanup(tif);
1208  return NULL;
1209  }
1210 
1211  /* Advance to the next image and return the new offset */
1212  TIFFReadDirectory(tif);
1213  *poffset = TIFFCurrentDirOffset(tif);
1214  TIFFClose(tif);
1215  return pix;
1216 }
1217 
1218 
1225 PIXA *
1226 pixaReadMultipageTiff(const char *filename)
1227 {
1228 l_int32 i, npages;
1229 FILE *fp;
1230 PIX *pix;
1231 PIXA *pixa;
1232 TIFF *tif;
1233 
1234  PROCNAME("pixaReadMultipageTiff");
1235 
1236  if (!filename)
1237  return (PIXA *)ERROR_PTR("filename not defined", procName, NULL);
1238 
1239  if ((fp = fopenReadStream(filename)) == NULL)
1240  return (PIXA *)ERROR_PTR("stream not opened", procName, NULL);
1241  if (fileFormatIsTiff(fp)) {
1242  tiffGetCount(fp, &npages);
1243  L_INFO(" Tiff: %d pages\n", procName, npages);
1244  } else {
1245  return (PIXA *)ERROR_PTR("file not tiff", procName, NULL);
1246  }
1247 
1248  if ((tif = fopenTiff(fp, "r")) == NULL)
1249  return (PIXA *)ERROR_PTR("tif not opened", procName, NULL);
1250 
1251  pixa = pixaCreate(npages);
1252  pix = NULL;
1253  for (i = 0; i < npages; i++) {
1254  if ((pix = pixReadFromTiffStream(tif)) != NULL) {
1255  pixaAddPix(pixa, pix, L_INSERT);
1256  } else {
1257  L_WARNING("pix not read for page %d\n", procName, i);
1258  }
1259 
1260  /* Advance to the next directory (i.e., the next image) */
1261  if (TIFFReadDirectory(tif) == 0)
1262  break;
1263  }
1264 
1265  fclose(fp);
1266  TIFFCleanup(tif);
1267  return pixa;
1268 }
1269 
1270 
1285 l_int32
1286 pixaWriteMultipageTiff(const char *fname,
1287  PIXA *pixa)
1288 {
1289 const char *modestr;
1290 l_int32 i, n;
1291 PIX *pix1, *pix2;
1292 
1293  PROCNAME("pixaWriteMultipageTiff");
1294 
1295  if (!fname)
1296  return ERROR_INT("fname not defined", procName, 1);
1297  if (!pixa)
1298  return ERROR_INT("pixa not defined", procName, 1);
1299 
1300  n = pixaGetCount(pixa);
1301  for (i = 0; i < n; i++) {
1302  modestr = (i == 0) ? "w" : "a";
1303  pix1 = pixaGetPix(pixa, i, L_CLONE);
1304  if (pixGetDepth(pix1) == 1) {
1305  pixWriteTiff(fname, pix1, IFF_TIFF_G4, modestr);
1306  } else {
1307  if (pixGetColormap(pix1)) {
1309  } else {
1310  pix2 = pixClone(pix1);
1311  }
1312  pixWriteTiff(fname, pix2, IFF_TIFF_ZIP, modestr);
1313  pixDestroy(&pix2);
1314  }
1315  pixDestroy(&pix1);
1316  }
1317 
1318  return 0;
1319 }
1320 
1321 
1346 l_int32
1347 writeMultipageTiff(const char *dirin,
1348  const char *substr,
1349  const char *fileout)
1350 {
1351 SARRAY *sa;
1352 
1353  PROCNAME("writeMultipageTiff");
1354 
1355  if (!dirin)
1356  return ERROR_INT("dirin not defined", procName, 1);
1357  if (!fileout)
1358  return ERROR_INT("fileout not defined", procName, 1);
1359 
1360  /* Get all filtered and sorted full pathnames. */
1361  sa = getSortedPathnamesInDirectory(dirin, substr, 0, 0);
1362 
1363  /* Generate the tiff file */
1364  writeMultipageTiffSA(sa, fileout);
1365  sarrayDestroy(&sa);
1366  return 0;
1367 }
1368 
1369 
1382 l_int32
1384  const char *fileout)
1385 {
1386 char *fname;
1387 const char *op;
1388 l_int32 i, nfiles, firstfile, format;
1389 PIX *pix, *pix1;
1390 
1391  PROCNAME("writeMultipageTiffSA");
1392 
1393  if (!sa)
1394  return ERROR_INT("sa not defined", procName, 1);
1395  if (!fileout)
1396  return ERROR_INT("fileout not defined", procName, 1);
1397 
1398  nfiles = sarrayGetCount(sa);
1399  firstfile = TRUE;
1400  for (i = 0; i < nfiles; i++) {
1401  op = (firstfile) ? "w" : "a";
1402  fname = sarrayGetString(sa, i, L_NOCOPY);
1403  findFileFormat(fname, &format);
1404  if (format == IFF_UNKNOWN) {
1405  L_INFO("format of %s not known\n", procName, fname);
1406  continue;
1407  }
1408 
1409  if ((pix = pixRead(fname)) == NULL) {
1410  L_WARNING("pix not made for file: %s\n", procName, fname);
1411  continue;
1412  }
1413  if (pixGetDepth(pix) == 1) {
1414  pixWriteTiff(fileout, pix, IFF_TIFF_G4, op);
1415  } else {
1416  if (pixGetColormap(pix)) {
1418  } else {
1419  pix1 = pixClone(pix);
1420  }
1421  pixWriteTiff(fileout, pix1, IFF_TIFF_ZIP, op);
1422  pixDestroy(&pix1);
1423  }
1424  firstfile = FALSE;
1425  pixDestroy(&pix);
1426  }
1427 
1428  return 0;
1429 }
1430 
1431 
1432 /*--------------------------------------------------------------*
1433  * Print info to stream *
1434  *--------------------------------------------------------------*/
1442 l_int32
1443 fprintTiffInfo(FILE *fpout,
1444  const char *tiffile)
1445 {
1446 TIFF *tif;
1447 
1448  PROCNAME("fprintTiffInfo");
1449 
1450  if (!tiffile)
1451  return ERROR_INT("tiffile not defined", procName, 1);
1452  if (!fpout)
1453  return ERROR_INT("stream out not defined", procName, 1);
1454 
1455  if ((tif = openTiff(tiffile, "rb")) == NULL)
1456  return ERROR_INT("tif not open for read", procName, 1);
1457 
1458  TIFFPrintDirectory(tif, fpout, 0);
1459  TIFFClose(tif);
1460 
1461  return 0;
1462 }
1463 
1464 
1465 /*--------------------------------------------------------------*
1466  * Get page count *
1467  *--------------------------------------------------------------*/
1475 l_int32
1476 tiffGetCount(FILE *fp,
1477  l_int32 *pn)
1478 {
1479 l_int32 i;
1480 TIFF *tif;
1481 
1482  PROCNAME("tiffGetCount");
1483 
1484  if (!fp)
1485  return ERROR_INT("stream not defined", procName, 1);
1486  if (!pn)
1487  return ERROR_INT("&n not defined", procName, 1);
1488  *pn = 0;
1489 
1490  if ((tif = fopenTiff(fp, "r")) == NULL)
1491  return ERROR_INT("tif not open for read", procName, 1);
1492 
1493  for (i = 1; ; i++) {
1494  if (TIFFReadDirectory(tif) == 0)
1495  break;
1496  if (i == MANY_PAGES_IN_TIFF_FILE + 1) {
1497  L_WARNING("big file: more than %d pages\n", procName,
1498  MANY_PAGES_IN_TIFF_FILE);
1499  }
1500  }
1501  *pn = i;
1502  TIFFCleanup(tif);
1503  return 0;
1504 }
1505 
1506 
1507 /*--------------------------------------------------------------*
1508  * Get resolution from tif *
1509  *--------------------------------------------------------------*/
1523 l_int32
1525  l_int32 *pxres,
1526  l_int32 *pyres)
1527 {
1528 TIFF *tif;
1529 
1530  PROCNAME("getTiffResolution");
1531 
1532  if (!pxres || !pyres)
1533  return ERROR_INT("&xres and &yres not both defined", procName, 1);
1534  *pxres = *pyres = 0;
1535  if (!fp)
1536  return ERROR_INT("stream not opened", procName, 1);
1537 
1538  if ((tif = fopenTiff(fp, "r")) == NULL)
1539  return ERROR_INT("tif not open for read", procName, 1);
1540  getTiffStreamResolution(tif, pxres, pyres);
1541  TIFFCleanup(tif);
1542  return 0;
1543 }
1544 
1545 
1559 static l_int32
1561  l_int32 *pxres,
1562  l_int32 *pyres)
1563 {
1564 l_uint16 resunit;
1565 l_int32 foundxres, foundyres;
1566 l_float32 fxres, fyres;
1567 
1568  PROCNAME("getTiffStreamResolution");
1569 
1570  if (!tif)
1571  return ERROR_INT("tif not opened", procName, 1);
1572  if (!pxres || !pyres)
1573  return ERROR_INT("&xres and &yres not both defined", procName, 1);
1574  *pxres = *pyres = 0;
1575 
1576  TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
1577  foundxres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fxres);
1578  foundyres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fyres);
1579  if (!foundxres && !foundyres) return 1;
1580  if (!foundxres && foundyres)
1581  fxres = fyres;
1582  else if (foundxres && !foundyres)
1583  fyres = fxres;
1584 
1585  if (resunit == RESUNIT_CENTIMETER) { /* convert to ppi */
1586  *pxres = (l_int32)(2.54 * fxres + 0.5);
1587  *pyres = (l_int32)(2.54 * fyres + 0.5);
1588  } else {
1589  *pxres = (l_int32)fxres;
1590  *pyres = (l_int32)fyres;
1591  }
1592 
1593  return 0;
1594 }
1595 
1596 
1597 /*--------------------------------------------------------------*
1598  * Get some tiff header information *
1599  *--------------------------------------------------------------*/
1620 l_int32
1621 readHeaderTiff(const char *filename,
1622  l_int32 n,
1623  l_int32 *pwidth,
1624  l_int32 *pheight,
1625  l_int32 *pbps,
1626  l_int32 *pspp,
1627  l_int32 *pres,
1628  l_int32 *pcmap,
1629  l_int32 *pformat)
1630 {
1631 l_int32 ret;
1632 FILE *fp;
1633 
1634  PROCNAME("readHeaderTiff");
1635 
1636  if (!filename)
1637  return ERROR_INT("filename not defined", procName, 1);
1638  if (!pwidth || !pheight || !pbps || !pspp)
1639  return ERROR_INT("input ptr(s) not all defined", procName, 1);
1640  *pwidth = *pheight = *pbps = *pspp = 0;
1641  if (pres) *pres = 0;
1642  if (pcmap) *pcmap = 0;
1643 
1644  if ((fp = fopenReadStream(filename)) == NULL)
1645  return ERROR_INT("image file not found", procName, 1);
1646  ret = freadHeaderTiff(fp, n, pwidth, pheight, pbps, pspp,
1647  pres, pcmap, pformat);
1648  fclose(fp);
1649  return ret;
1650 }
1651 
1652 
1673 l_int32
1675  l_int32 n,
1676  l_int32 *pwidth,
1677  l_int32 *pheight,
1678  l_int32 *pbps,
1679  l_int32 *pspp,
1680  l_int32 *pres,
1681  l_int32 *pcmap,
1682  l_int32 *pformat)
1683 {
1684 l_int32 i, ret, format;
1685 TIFF *tif;
1686 
1687  PROCNAME("freadHeaderTiff");
1688 
1689  if (!fp)
1690  return ERROR_INT("stream not defined", procName, 1);
1691  if (n < 0)
1692  return ERROR_INT("image index must be >= 0", procName, 1);
1693  if (!pwidth || !pheight || !pbps || !pspp)
1694  return ERROR_INT("input ptr(s) not all defined", procName, 1);
1695  *pwidth = *pheight = *pbps = *pspp = 0;
1696  if (pres) *pres = 0;
1697  if (pcmap) *pcmap = 0;
1698  if (pformat) *pformat = 0;
1699 
1700  findFileFormatStream(fp, &format);
1701  if (format != IFF_TIFF &&
1702  format != IFF_TIFF_G3 && format != IFF_TIFF_G4 &&
1703  format != IFF_TIFF_RLE && format != IFF_TIFF_PACKBITS &&
1704  format != IFF_TIFF_LZW && format != IFF_TIFF_ZIP)
1705  return ERROR_INT("file not tiff format", procName, 1);
1706 
1707  if ((tif = fopenTiff(fp, "r")) == NULL)
1708  return ERROR_INT("tif not open for read", procName, 1);
1709 
1710  for (i = 0; i < n; i++) {
1711  if (TIFFReadDirectory(tif) == 0)
1712  return ERROR_INT("image n not found in file", procName, 1);
1713  }
1714 
1715  ret = tiffReadHeaderTiff(tif, pwidth, pheight, pbps, pspp,
1716  pres, pcmap, pformat);
1717  TIFFCleanup(tif);
1718  return ret;
1719 }
1720 
1721 
1742 l_int32
1743 readHeaderMemTiff(const l_uint8 *cdata,
1744  size_t size,
1745  l_int32 n,
1746  l_int32 *pwidth,
1747  l_int32 *pheight,
1748  l_int32 *pbps,
1749  l_int32 *pspp,
1750  l_int32 *pres,
1751  l_int32 *pcmap,
1752  l_int32 *pformat)
1753 {
1754 l_uint8 *data;
1755 l_int32 i, ret;
1756 TIFF *tif;
1757 
1758  PROCNAME("readHeaderMemTiff");
1759 
1760  if (!cdata)
1761  return ERROR_INT("cdata not defined", procName, 1);
1762  if (!pwidth || !pheight || !pbps || !pspp)
1763  return ERROR_INT("input ptr(s) not all defined", procName, 1);
1764  *pwidth = *pheight = *pbps = *pspp = 0;
1765  if (pres) *pres = 0;
1766  if (pcmap) *pcmap = 0;
1767  if (pformat) *pformat = 0;
1768 
1769  /* Open a tiff stream to memory */
1770  data = (l_uint8 *)cdata; /* we're really not going to change this */
1771  if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
1772  return ERROR_INT("tiff stream not opened", procName, 1);
1773 
1774  for (i = 0; i < n; i++) {
1775  if (TIFFReadDirectory(tif) == 0) {
1776  TIFFClose(tif);
1777  return ERROR_INT("image n not found in file", procName, 1);
1778  }
1779  }
1780 
1781  ret = tiffReadHeaderTiff(tif, pwidth, pheight, pbps, pspp,
1782  pres, pcmap, pformat);
1783  TIFFClose(tif);
1784  return ret;
1785 }
1786 
1787 
1801 static l_int32
1803  l_int32 *pwidth,
1804  l_int32 *pheight,
1805  l_int32 *pbps,
1806  l_int32 *pspp,
1807  l_int32 *pres,
1808  l_int32 *pcmap,
1809  l_int32 *pformat)
1810 {
1811 l_uint16 tiffcomp;
1812 l_uint16 bps, spp;
1813 l_uint16 *rmap, *gmap, *bmap;
1814 l_int32 xres, yres;
1815 l_uint32 w, h;
1816 
1817  PROCNAME("tiffReadHeaderTiff");
1818 
1819  if (!tif)
1820  return ERROR_INT("tif not opened", procName, 1);
1821 
1822  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
1823  *pwidth = w;
1824  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
1825  *pheight = h;
1826  TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
1827  *pbps = bps;
1828  TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
1829  *pspp = spp;
1830 
1831  if (pres) {
1832  *pres = 300; /* default ppi */
1833  if (getTiffStreamResolution(tif, &xres, &yres) == 0)
1834  *pres = (l_int32)xres;
1835  }
1836 
1837  if (pcmap) {
1838  *pcmap = 0;
1839  if (TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap))
1840  *pcmap = 1;
1841  }
1842 
1843  if (pformat) {
1844  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
1845  *pformat = getTiffCompressedFormat(tiffcomp);
1846  }
1847  return 0;
1848 }
1849 
1850 
1870 l_int32
1872  l_int32 *pcomptype)
1873 {
1874 l_uint16 tiffcomp;
1875 TIFF *tif;
1876 
1877  PROCNAME("findTiffCompression");
1878 
1879  if (!pcomptype)
1880  return ERROR_INT("&comptype not defined", procName, 1);
1881  *pcomptype = IFF_UNKNOWN; /* init */
1882  if (!fp)
1883  return ERROR_INT("stream not defined", procName, 1);
1884 
1885  if ((tif = fopenTiff(fp, "r")) == NULL)
1886  return ERROR_INT("tif not opened", procName, 1);
1887  TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
1888  *pcomptype = getTiffCompressedFormat(tiffcomp);
1889  TIFFCleanup(tif);
1890  return 0;
1891 }
1892 
1893 
1908 static l_int32
1909 getTiffCompressedFormat(l_uint16 tiffcomp)
1910 {
1911 l_int32 comptype;
1912 
1913  switch (tiffcomp)
1914  {
1915  case COMPRESSION_CCITTFAX4:
1916  comptype = IFF_TIFF_G4;
1917  break;
1918  case COMPRESSION_CCITTFAX3:
1919  comptype = IFF_TIFF_G3;
1920  break;
1921  case COMPRESSION_CCITTRLE:
1922  comptype = IFF_TIFF_RLE;
1923  break;
1924  case COMPRESSION_PACKBITS:
1925  comptype = IFF_TIFF_PACKBITS;
1926  break;
1927  case COMPRESSION_LZW:
1928  comptype = IFF_TIFF_LZW;
1929  break;
1930  case COMPRESSION_ADOBE_DEFLATE:
1931  comptype = IFF_TIFF_ZIP;
1932  break;
1933  default:
1934  comptype = IFF_TIFF;
1935  break;
1936  }
1937  return comptype;
1938 }
1939 
1940 
1941 /*--------------------------------------------------------------*
1942  * Extraction of tiff g4 data *
1943  *--------------------------------------------------------------*/
1955 l_int32
1956 extractG4DataFromFile(const char *filein,
1957  l_uint8 **pdata,
1958  size_t *pnbytes,
1959  l_int32 *pw,
1960  l_int32 *ph,
1961  l_int32 *pminisblack)
1962 {
1963 l_uint8 *inarray, *data;
1964 l_uint16 minisblack, comptype; /* accessors require l_uint16 */
1965 l_int32 istiff;
1966 l_uint32 w, h, rowsperstrip; /* accessors require l_uint32 */
1967 l_uint32 diroff;
1968 size_t fbytes, nbytes;
1969 FILE *fpin;
1970 TIFF *tif;
1971 
1972  PROCNAME("extractG4DataFromFile");
1973 
1974  if (!pdata)
1975  return ERROR_INT("&data not defined", procName, 1);
1976  if (!pnbytes)
1977  return ERROR_INT("&nbytes not defined", procName, 1);
1978  if (!pw && !ph && !pminisblack)
1979  return ERROR_INT("no output data requested", procName, 1);
1980  *pdata = NULL;
1981  *pnbytes = 0;
1982 
1983  if ((fpin = fopenReadStream(filein)) == NULL)
1984  return ERROR_INT("stream not opened to file", procName, 1);
1985  istiff = fileFormatIsTiff(fpin);
1986  fclose(fpin);
1987  if (!istiff)
1988  return ERROR_INT("filein not tiff", procName, 1);
1989 
1990  if ((inarray = l_binaryRead(filein, &fbytes)) == NULL)
1991  return ERROR_INT("inarray not made", procName, 1);
1992 
1993  /* Get metadata about the image */
1994  if ((tif = openTiff(filein, "rb")) == NULL) {
1995  LEPT_FREE(inarray);
1996  return ERROR_INT("tif not open for read", procName, 1);
1997  }
1998  TIFFGetField(tif, TIFFTAG_COMPRESSION, &comptype);
1999  if (comptype != COMPRESSION_CCITTFAX4) {
2000  LEPT_FREE(inarray);
2001  TIFFClose(tif);
2002  return ERROR_INT("filein is not g4 compressed", procName, 1);
2003  }
2004 
2005  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
2006  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
2007  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
2008  if (h != rowsperstrip)
2009  L_WARNING("more than 1 strip\n", procName);
2010  TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &minisblack); /* for 1 bpp */
2011 /* TIFFPrintDirectory(tif, stderr, 0); */
2012  TIFFClose(tif);
2013  if (pw) *pw = (l_int32)w;
2014  if (ph) *ph = (l_int32)h;
2015  if (pminisblack) *pminisblack = (l_int32)minisblack;
2016 
2017  /* The header has 8 bytes: the first 2 are the magic number,
2018  * the next 2 are the version, and the last 4 are the
2019  * offset to the first directory. That's what we want here.
2020  * We have to test the byte order before decoding 4 bytes! */
2021  if (inarray[0] == 0x4d) { /* big-endian */
2022  diroff = (inarray[4] << 24) | (inarray[5] << 16) |
2023  (inarray[6] << 8) | inarray[7];
2024  } else { /* inarray[0] == 0x49 : little-endian */
2025  diroff = (inarray[7] << 24) | (inarray[6] << 16) |
2026  (inarray[5] << 8) | inarray[4];
2027  }
2028 /* fprintf(stderr, " diroff = %d, %x\n", diroff, diroff); */
2029 
2030  /* Extract the ccittg4 encoded data from the tiff file.
2031  * We skip the 8 byte header and take nbytes of data,
2032  * up to the beginning of the directory (at diroff) */
2033  nbytes = diroff - 8;
2034  *pnbytes = nbytes;
2035  if ((data = (l_uint8 *)LEPT_CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
2036  LEPT_FREE(inarray);
2037  return ERROR_INT("data not allocated", procName, 1);
2038  }
2039  *pdata = data;
2040  memcpy(data, inarray + 8, nbytes);
2041  LEPT_FREE(inarray);
2042 
2043  return 0;
2044 }
2045 
2046 
2047 /*--------------------------------------------------------------*
2048  * Open tiff stream from file stream *
2049  *--------------------------------------------------------------*/
2070 static TIFF *
2071 fopenTiff(FILE *fp,
2072  const char *modestring)
2073 {
2074  PROCNAME("fopenTiff");
2075 
2076  if (!fp)
2077  return (TIFF *)ERROR_PTR("stream not opened", procName, NULL);
2078  if (!modestring)
2079  return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
2080 
2081  TIFFSetWarningHandler(dummyHandler); /* disable warnings */
2082 
2083  fseek(fp, 0, SEEK_SET);
2084  return TIFFClientOpen("TIFFstream", modestring, (thandle_t)fp,
2085  lept_read_proc, lept_write_proc, lept_seek_proc,
2086  lept_close_proc, lept_size_proc, NULL, NULL);
2087 }
2088 
2089 
2090 /*--------------------------------------------------------------*
2091  * Wrapper for TIFFOpen *
2092  *--------------------------------------------------------------*/
2105 static TIFF *
2106 openTiff(const char *filename,
2107  const char *modestring)
2108 {
2109 char *fname;
2110 TIFF *tif;
2111 
2112  PROCNAME("openTiff");
2113 
2114  if (!filename)
2115  return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
2116  if (!modestring)
2117  return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
2118 
2119  TIFFSetWarningHandler(dummyHandler); /* disable warnings */
2120 
2121  fname = genPathname(filename, NULL);
2122  tif = TIFFOpen(fname, modestring);
2123  LEPT_FREE(fname);
2124  return tif;
2125 }
2126 
2127 
2128 /*----------------------------------------------------------------------*
2129  * Memory I/O: reading memory --> pix and writing pix --> memory *
2130  *----------------------------------------------------------------------*/
2131 /* It would be nice to use open_memstream() and fmemopen()
2132  * for writing and reading to memory, rsp. These functions manage
2133  * memory for writes and reads that use a file streams interface.
2134  * Unfortunately, the tiff library only has an interface for reading
2135  * and writing to file descriptors, not to file streams. The tiff
2136  * library procedure is to open a "tiff stream" and read/write to it.
2137  * The library provides a client interface for managing the I/O
2138  * from memory, which requires seven callbacks. See the TIFFClientOpen
2139  * man page for callback signatures. Adam Langley provided the code
2140  * to do this. */
2141 
2163 {
2164  l_uint8 *buffer; /* expands to hold data when written to; */
2165  /* fixed size when read from. */
2166  size_t bufsize; /* current size allocated when written to; */
2167  /* fixed size of input data when read from. */
2168  size_t offset; /* byte offset from beginning of buffer. */
2169  size_t hw; /* high-water mark; max bytes in buffer. */
2170  l_uint8 **poutdata; /* input param for writing; data goes here. */
2171  size_t *poutsize; /* input param for writing; data size goes here. */
2172 };
2173 typedef struct L_Memstream L_MEMSTREAM;
2174 
2175 
2176  /* These are static functions for memory I/O */
2177 static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);
2178 static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
2179  size_t *poutsize);
2180 static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);
2181 static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
2182  tsize_t length);
2183 static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);
2184 static l_int32 tiffCloseCallback(thandle_t handle);
2185 static toff_t tiffSizeCallback(thandle_t handle);
2186 static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);
2187 static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);
2188 
2189 
2190 static L_MEMSTREAM *
2191 memstreamCreateForRead(l_uint8 *indata,
2192  size_t insize)
2193 {
2194 L_MEMSTREAM *mstream;
2195 
2196  mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2197  mstream->buffer = indata; /* handle to input data array */
2198  mstream->bufsize = insize; /* amount of input data */
2199  mstream->hw = insize; /* high-water mark fixed at input data size */
2200  mstream->offset = 0; /* offset always starts at 0 */
2201  return mstream;
2202 }
2203 
2204 
2205 static L_MEMSTREAM *
2206 memstreamCreateForWrite(l_uint8 **poutdata,
2207  size_t *poutsize)
2208 {
2209 L_MEMSTREAM *mstream;
2210 
2211  mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2212  mstream->buffer = (l_uint8 *)LEPT_CALLOC(8 * 1024, 1);
2213  mstream->bufsize = 8 * 1024;
2214  mstream->poutdata = poutdata; /* used only at end of write */
2215  mstream->poutsize = poutsize; /* ditto */
2216  mstream->hw = mstream->offset = 0;
2217  return mstream;
2218 }
2219 
2220 
2221 static tsize_t
2222 tiffReadCallback(thandle_t handle,
2223  tdata_t data,
2224  tsize_t length)
2225 {
2226 L_MEMSTREAM *mstream;
2227 size_t amount;
2228 
2229  mstream = (L_MEMSTREAM *)handle;
2230  amount = L_MIN((size_t)length, mstream->hw - mstream->offset);
2231 
2232  /* Fuzzed files can create this condition! */
2233  if (mstream->offset + amount > mstream->hw) {
2234  fprintf(stderr, "Bad file: amount too big: %lu\n",
2235  (unsigned long)amount);
2236  return 0;
2237  }
2238 
2239  memcpy(data, mstream->buffer + mstream->offset, amount);
2240  mstream->offset += amount;
2241  return amount;
2242 }
2243 
2244 
2245 static tsize_t
2246 tiffWriteCallback(thandle_t handle,
2247  tdata_t data,
2248  tsize_t length)
2249 {
2250 L_MEMSTREAM *mstream;
2251 size_t newsize;
2252 
2253  /* reallocNew() uses calloc to initialize the array.
2254  * If malloc is used instead, for some of the encoding methods,
2255  * not all the data in 'bufsize' bytes in the buffer will
2256  * have been initialized by the end of the compression. */
2257  mstream = (L_MEMSTREAM *)handle;
2258  if (mstream->offset + length > mstream->bufsize) {
2259  newsize = 2 * (mstream->offset + length);
2260  mstream->buffer = (l_uint8 *)reallocNew((void **)&mstream->buffer,
2261  mstream->hw, newsize);
2262  mstream->bufsize = newsize;
2263  }
2264 
2265  memcpy(mstream->buffer + mstream->offset, data, length);
2266  mstream->offset += length;
2267  mstream->hw = L_MAX(mstream->offset, mstream->hw);
2268  return length;
2269 }
2270 
2271 
2272 static toff_t
2273 tiffSeekCallback(thandle_t handle,
2274  toff_t offset,
2275  l_int32 whence)
2276 {
2277 L_MEMSTREAM *mstream;
2278 
2279  PROCNAME("tiffSeekCallback");
2280  mstream = (L_MEMSTREAM *)handle;
2281  switch (whence) {
2282  case SEEK_SET:
2283 /* fprintf(stderr, "seek_set: offset = %d\n", offset); */
2284  mstream->offset = offset;
2285  break;
2286  case SEEK_CUR:
2287 /* fprintf(stderr, "seek_cur: offset = %d\n", offset); */
2288  mstream->offset += offset;
2289  break;
2290  case SEEK_END:
2291 /* fprintf(stderr, "seek end: hw = %d, offset = %d\n",
2292  mstream->hw, offset); */
2293  mstream->offset = mstream->hw - offset; /* offset >= 0 */
2294  break;
2295  default:
2296  return (toff_t)ERROR_INT("bad whence value", procName,
2297  mstream->offset);
2298  }
2299 
2300  return mstream->offset;
2301 }
2302 
2303 
2304 static l_int32
2305 tiffCloseCallback(thandle_t handle)
2306 {
2307 L_MEMSTREAM *mstream;
2308 
2309  mstream = (L_MEMSTREAM *)handle;
2310  if (mstream->poutdata) { /* writing: save the output data */
2311  *mstream->poutdata = mstream->buffer;
2312  *mstream->poutsize = mstream->hw;
2313  }
2314  LEPT_FREE(mstream); /* never free the buffer! */
2315  return 0;
2316 }
2317 
2318 
2319 static toff_t
2320 tiffSizeCallback(thandle_t handle)
2321 {
2322 L_MEMSTREAM *mstream;
2323 
2324  mstream = (L_MEMSTREAM *)handle;
2325  return mstream->hw;
2326 }
2327 
2328 
2329 static l_int32
2330 tiffMapCallback(thandle_t handle,
2331  tdata_t *data,
2332  toff_t *length)
2333 {
2334 L_MEMSTREAM *mstream;
2335 
2336  mstream = (L_MEMSTREAM *)handle;
2337  *data = mstream->buffer;
2338  *length = mstream->hw;
2339  return 0;
2340 }
2341 
2342 
2343 static void
2344 tiffUnmapCallback(thandle_t handle,
2345  tdata_t data,
2346  toff_t length)
2347 {
2348  return;
2349 }
2350 
2351 
2372 static TIFF *
2373 fopenTiffMemstream(const char *filename,
2374  const char *operation,
2375  l_uint8 **pdata,
2376  size_t *pdatasize)
2377 {
2378 L_MEMSTREAM *mstream;
2379 
2380  PROCNAME("fopenTiffMemstream");
2381 
2382  if (!filename)
2383  return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
2384  if (!operation)
2385  return (TIFF *)ERROR_PTR("operation not defined", procName, NULL);
2386  if (!pdata)
2387  return (TIFF *)ERROR_PTR("&data not defined", procName, NULL);
2388  if (!pdatasize)
2389  return (TIFF *)ERROR_PTR("&datasize not defined", procName, NULL);
2390  if (strcmp(operation, "r") && strcmp(operation, "w"))
2391  return (TIFF *)ERROR_PTR("op not 'r' or 'w'", procName, NULL);
2392 
2393  if (!strcmp(operation, "r"))
2394  mstream = memstreamCreateForRead(*pdata, *pdatasize);
2395  else
2396  mstream = memstreamCreateForWrite(pdata, pdatasize);
2397 
2398  TIFFSetWarningHandler(dummyHandler); /* disable warnings */
2399 
2400  return TIFFClientOpen(filename, operation, (thandle_t)mstream,
2401  tiffReadCallback, tiffWriteCallback,
2402  tiffSeekCallback, tiffCloseCallback,
2403  tiffSizeCallback, tiffMapCallback,
2404  tiffUnmapCallback);
2405 }
2406 
2407 
2428 PIX *
2429 pixReadMemTiff(const l_uint8 *cdata,
2430  size_t size,
2431  l_int32 n)
2432 {
2433 l_uint8 *data;
2434 l_int32 i;
2435 PIX *pix;
2436 TIFF *tif;
2437 
2438  PROCNAME("pixReadMemTiff");
2439 
2440  if (!cdata)
2441  return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
2442 
2443  data = (l_uint8 *)cdata; /* we're really not going to change this */
2444  if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2445  return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
2446 
2447  pix = NULL;
2448  for (i = 0; ; i++) {
2449  if (i == n) {
2450  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2451  TIFFClose(tif);
2452  return NULL;
2453  }
2454  pixSetInputFormat(pix, IFF_TIFF);
2455  break;
2456  }
2457  if (TIFFReadDirectory(tif) == 0)
2458  break;
2459  if (i == MANY_PAGES_IN_TIFF_FILE + 1) {
2460  L_WARNING("big file: more than %d pages\n", procName,
2461  MANY_PAGES_IN_TIFF_FILE);
2462  }
2463  }
2464 
2465  TIFFClose(tif);
2466  return pix;
2467 }
2468 
2469 
2493 PIX *
2494 pixReadMemFromMultipageTiff(const l_uint8 *cdata,
2495  size_t size,
2496  size_t *poffset)
2497 {
2498 l_uint8 *data;
2499 l_int32 retval;
2500 size_t offset;
2501 PIX *pix;
2502 TIFF *tif;
2503 
2504  PROCNAME("pixReadMemFromMultipageTiff");
2505 
2506  if (!cdata)
2507  return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
2508  if (!poffset)
2509  return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);
2510 
2511  data = (l_uint8 *)cdata; /* we're really not going to change this */
2512  if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2513  return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
2514 
2515  /* Set ptrs in the TIFF to the beginning of the image */
2516  offset = *poffset;
2517  retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
2518  : TIFFSetSubDirectory(tif, offset);
2519  if (retval == 0) {
2520  TIFFClose(tif);
2521  return NULL;
2522  }
2523 
2524  if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2525  TIFFClose(tif);
2526  return NULL;
2527  }
2528 
2529  /* Advance to the next image and return the new offset */
2530  TIFFReadDirectory(tif);
2531  *poffset = TIFFCurrentDirOffset(tif);
2532  TIFFClose(tif);
2533  return pix;
2534 }
2535 
2536 
2549 PIXA *
2550 pixaReadMemMultipageTiff(const l_uint8 *data,
2551  size_t size)
2552 {
2553 size_t offset;
2554 PIX *pix;
2555 PIXA *pixa;
2556 
2557  PROCNAME("pixaReadMemMultipageTiff");
2558 
2559  if (!data)
2560  return (PIXA *)ERROR_PTR("data not defined", procName, NULL);
2561 
2562  offset = 0;
2563  pixa = pixaCreate(0);
2564  do {
2565  pix = pixReadMemFromMultipageTiff(data, size, &offset);
2566  pixaAddPix(pixa, pix, L_INSERT);
2567  } while (offset != 0);
2568  return pixa;
2569 }
2570 
2571 
2589 l_int32
2591  size_t *psize,
2592  PIXA *pixa)
2593 {
2594 const char *modestr;
2595 l_int32 i, n;
2596 FILE *fp;
2597 PIX *pix1, *pix2;
2598 
2599  PROCNAME("pixaWriteMemMultipageTiff");
2600 
2601  if (pdata) *pdata = NULL;
2602  if (!pdata)
2603  return ERROR_INT("pdata not defined", procName, 1);
2604  if (!pixa)
2605  return ERROR_INT("pixa not defined", procName, 1);
2606 
2607 #ifdef _WIN32
2608  if ((fp = fopenWriteWinTempfile()) == NULL)
2609  return ERROR_INT("tmpfile stream not opened", procName, 1);
2610 #else
2611  if ((fp = tmpfile()) == NULL)
2612  return ERROR_INT("tmpfile stream not opened", procName, 1);
2613 #endif /* _WIN32 */
2614 
2615  n = pixaGetCount(pixa);
2616  for (i = 0; i < n; i++) {
2617  modestr = (i == 0) ? "w" : "a";
2618  pix1 = pixaGetPix(pixa, i, L_CLONE);
2619  if (pixGetDepth(pix1) == 1) {
2620  pixWriteStreamTiffWA(fp, pix1, IFF_TIFF_G4, modestr);
2621  } else {
2622  if (pixGetColormap(pix1)) {
2624  } else {
2625  pix2 = pixClone(pix1);
2626  }
2627  pixWriteStreamTiffWA(fp, pix2, IFF_TIFF_ZIP, modestr);
2628  pixDestroy(&pix2);
2629  }
2630  pixDestroy(&pix1);
2631  }
2632 
2633  rewind(fp);
2634  *pdata = l_binaryReadStream(fp, psize);
2635  fclose(fp);
2636  return 0;
2637 }
2638 
2639 
2655 l_int32
2656 pixWriteMemTiff(l_uint8 **pdata,
2657  size_t *psize,
2658  PIX *pix,
2659  l_int32 comptype)
2660 {
2661  return pixWriteMemTiffCustom(pdata, psize, pix, comptype,
2662  NULL, NULL, NULL, NULL);
2663 }
2664 
2665 
2686 l_int32
2687 pixWriteMemTiffCustom(l_uint8 **pdata,
2688  size_t *psize,
2689  PIX *pix,
2690  l_int32 comptype,
2691  NUMA *natags,
2692  SARRAY *savals,
2693  SARRAY *satypes,
2694  NUMA *nasizes)
2695 {
2696 l_int32 ret;
2697 TIFF *tif;
2698 
2699  PROCNAME("pixWriteMemTiffCustom");
2700 
2701  if (!pdata)
2702  return ERROR_INT("&data not defined", procName, 1);
2703  if (!psize)
2704  return ERROR_INT("&size not defined", procName, 1);
2705  if (!pix)
2706  return ERROR_INT("&pix not defined", procName, 1);
2707  if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
2708  comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP) {
2709  L_WARNING("invalid compression type for bpp > 1\n", procName);
2710  comptype = IFF_TIFF_ZIP;
2711  }
2712 
2713  if ((tif = fopenTiffMemstream("tifferror", "w", pdata, psize)) == NULL)
2714  return ERROR_INT("tiff stream not opened", procName, 1);
2715  ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
2716  satypes, nasizes);
2717 
2718  TIFFClose(tif);
2719  return ret;
2720 }
2721 
2722 /* --------------------------------------------*/
2723 #endif /* HAVE_LIBTIFF */
2724 /* --------------------------------------------*/
PIX * pixFlipLR(PIX *pixd, PIX *pixs)
pixFlipLR()
Definition: rotateorth.c:423
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
PIX * pixReadStreamTiff(FILE *fp, l_int32 n)
pixReadStreamTiff()
Definition: tiffio.c:408
static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres, l_int32 *pyres)
getTiffStreamResolution()
Definition: tiffio.c:1560
l_int32 pixEndianByteSwap(PIX *pixs)
pixEndianByteSwap()
Definition: pix2.c:2930
PIXA * pixaReadMultipageTiff(const char *filename)
pixaReadMultipageTiff()
Definition: tiffio.c:1226
l_int32 findFileFormatStream(FILE *fp, l_int32 *pformat)
findFileFormatStream()
Definition: readfile.c:603
l_int32 pixEndianTwoByteSwap(PIX *pixs)
pixEndianTwoByteSwap()
Definition: pix2.c:3092
char * genPathname(const char *dir, const char *fname)
genPathname()
Definition: utils2.c:2759
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:161
Definition: pix.h:704
l_int32 pixaWriteMemMultipageTiff(l_uint8 **pdata, size_t *psize, PIXA *pixa)
pixaWriteMemMultipageTiff()
Definition: tiffio.c:2590
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:1602
l_int32 pixcmapToArrays(PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:1813
l_int32 pixWriteMemTiffCustom(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteMemTiffCustom()
Definition: tiffio.c:2687
Memory stream buffer used with TIFFClientOpen()
Definition: tiffio.c:2162
void * reallocNew(void **pindata, l_int32 oldsize, l_int32 newsize)
reallocNew()
Definition: utils2.c:1102
l_int32 findFileFormat(const char *filename, l_int32 *pformat)
findFileFormat()
Definition: readfile.c:568
l_int32 readHeaderTiff(const char *filename, l_int32 n, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
readHeaderTiff()
Definition: tiffio.c:1621
Definition: array.h:116
PIX * pixReadMemFromMultipageTiff(const l_uint8 *cdata, size_t size, size_t *poffset)
pixReadMemFromMultipageTiff()
Definition: tiffio.c:2494
static TIFF * fopenTiff(FILE *fp, const char *modestring)
fopenTiff()
Definition: tiffio.c:2071
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:110
l_int32 pixWriteTiff(const char *filename, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteTiff()
Definition: tiffio.c:654
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1154
l_int32 writeMultipageTiffSA(SARRAY *sa, const char *fileout)
writeMultipageTiffSA()
Definition: tiffio.c:1383
PIX * pixEndianTwoByteSwapNew(PIX *pixs)
pixEndianTwoByteSwapNew()
Definition: pix2.c:3039
l_int32 fprintTiffInfo(FILE *fpout, const char *tiffile)
fprintTiffInfo()
Definition: tiffio.c:1443
PIX * pixFlipTB(PIX *pixd, PIX *pixs)
pixFlipTB()
Definition: rotateorth.c:601
Definition: array.h:59
static const l_int32 L_INSERT
Definition: pix.h:710
l_int32 pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:299
l_int32 tiffGetCount(FILE *fp, l_int32 *pn)
tiffGetCount()
Definition: tiffio.c:1476
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_int32 pixWriteMemTiff(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype)
pixWriteMemTiff()
Definition: tiffio.c:2656
l_int32 pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
static TIFF * fopenTiffMemstream(const char *filename, const char *operation, l_uint8 **pdata, size_t *pdatasize)
fopenTiffMemstream()
Definition: tiffio.c:2373
l_int32 pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1295
l_int32 pixWriteStreamTiffWA(FILE *fp, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteStreamTiffWA()
Definition: tiffio.c:790
l_int32 pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1556
static PIX * pixReadFromTiffStream(TIFF *tif)
pixReadFromTiffStream()
Definition: tiffio.c:469
static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteToTiffStream()
Definition: tiffio.c:860
FILE * fopenWriteWinTempfile()
fopenWriteWinTempfile()
Definition: utils2.c:1716
static TIFF * openTiff(const char *filename, const char *modestring)
openTiff()
Definition: tiffio.c:2106
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:182
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:675
l_int32 pixaWriteMultipageTiff(const char *fname, PIXA *pixa)
pixaWriteMultipageTiff()
Definition: tiffio.c:1286
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:517
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:545
SARRAY * getSortedPathnamesInDirectory(const char *dirname, const char *substr, l_int32 first, l_int32 nfiles)
getSortedPathnamesInDirectory()
Definition: sarray1.c:1710
l_int32 freadHeaderTiff(FILE *fp, l_int32 n, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
freadHeaderTiff()
Definition: tiffio.c:1674
Definition: pix.h:454
PIX * pixReadMemTiff(const l_uint8 *cdata, size_t size, l_int32 n)
pixReadMemTiff()
Definition: tiffio.c:2429
PIX * pixEndianByteSwapNew(PIX *pixs)
pixEndianByteSwapNew()
Definition: pix2.c:2867
l_int32 writeMultipageTiff(const char *dirin, const char *substr, const char *fileout)
writeMultipageTiff()
Definition: tiffio.c:1347
l_int32 pixWriteTiffCustom(const char *filename, PIX *pix, l_int32 comptype, const char *modestr, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteTiffCustom()
Definition: tiffio.c:711
l_int32 fileFormatIsTiff(FILE *fp)
fileFormatIsTiff()
Definition: readfile.c:783
l_int32 findTiffCompression(FILE *fp, l_int32 *pcomptype)
findTiffCompression()
Definition: tiffio.c:1871
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1593
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1200
l_int32 extractG4DataFromFile(const char *filein, l_uint8 **pdata, size_t *pnbytes, l_int32 *pw, l_int32 *ph, l_int32 *pminisblack)
extractG4DataFromFile()
Definition: tiffio.c:1956
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:615
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:189
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1442
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:660
l_int32 composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2659
static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp)
getTiffCompressedFormat()
Definition: tiffio.c:1909
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:593
Definition: pix.h:134
Definition: pix.h:706
PIX * pixReadTiff(const char *filename, l_int32 n)
pixReadTiff()
Definition: tiffio.c:371
l_int32 readHeaderMemTiff(const l_uint8 *cdata, size_t size, l_int32 n, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
readHeaderMemTiff()
Definition: tiffio.c:1743
l_int32 pixWriteStreamTiff(FILE *fp, PIX *pix, l_int32 comptype)
pixWriteStreamTiff()
Definition: tiffio.c:770
PIX * pixReadFromMultipageTiff(const char *fname, size_t *poffset)
pixReadFromMultipageTiff()
Definition: tiffio.c:1177
Definition: pix.h:201
l_int32 numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:726
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:1050
l_int32 pixGetDimensions(PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1052
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:1802
l_int32 getTiffResolution(FILE *fp, l_int32 *pxres, l_int32 *pyres)
getTiffResolution()
Definition: tiffio.c:1524
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:620
PIXA * pixaReadMemMultipageTiff(const l_uint8 *data, size_t size)
pixaReadMemMultipageTiff()
Definition: tiffio.c:2550
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:349