• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *  tiffio.c
18  *
19  *     Reading tiff:
20  *             PIX       *pixReadTiff()    [ special top level ]
21  *             PIX       *pixReadStreamTiff()
22  *      static PIX       *pixReadFromTiffStream()
23  *
24  *     Writing tiff:
25  *             l_int32    pixWriteTiff()   [ special top level ]
26  *             l_int32    pixWriteTiffCustom()   [ special top level ]
27  *             l_int32    pixWriteStreamTiff()
28  *      static l_int32    pixWriteToTiffStream()
29  *      static l_int32    writeCustomTiffTags()
30  *
31  *     Information about tiff file
32  *             l_int32    fprintTiffInfo()
33  *             l_int32    tiffGetCount()
34  *      static l_int32    tiffGetResolution()
35  *             l_int32    readHeaderTiff()
36  *             l_int32    freadHeaderTiff()
37  *             l_int32    readHeaderMemTiff()
38  *      static l_int32    tiffReadHeaderTiff()
39  *             l_int32    findTiffCompression()
40  *
41  *     Extraction of tiff g4 data:
42  *             l_int32    extractTiffG4DataFromFile()
43  *
44  *     Open tiff stream from file stream
45  *      static TIFF      *fopenTiff()
46  *
47  *     Memory I/O: reading memory --> pix and writing pix --> memory
48  *             [10 static helper functions]
49  *             l_int32    pixReadMemTiff();
50  *             l_int32    pixWriteMemTiff();
51  *             l_int32    pixWriteMemTiffCustom();
52  *
53  *   Note:  You should be using version 3.7.4 of libtiff to be certain
54  *          that all the necessary functions are included.
55  */
56 
57 #include <stdio.h>
58 #include <string.h>
59 #include <stdlib.h>
60 #include <sys/types.h>
61 #ifndef COMPILER_MSVC
62 #include <unistd.h>
63 #else  /* COMPILER_MSVC */
64 #include <io.h>
65 #define seek _seek;
66 #endif  /* COMPILER_MSVC */
67 #include <fcntl.h>
68 #include "allheaders.h"
69 
70 #ifdef HAVE_CONFIG_H
71 #include "config_auto.h"
72 #endif  /* HAVE_CONFIG_H */
73 
74 /* --------------------------------------------*/
75 #if  HAVE_LIBTIFF   /* defined in environ.h */
76 /* --------------------------------------------*/
77 
78 #include "tiff.h"
79 #include "tiffio.h"
80 
81 static const l_int32  DEFAULT_RESOLUTION = 300;   /* ppi */
82 static const l_int32  MAX_PAGES_IN_TIFF_FILE = 3000;  /* should be enough */
83 
84 
85     /* All functions with TIFF interfaces are static. */
86 static PIX      *pixReadFromTiffStream(TIFF *tif);
87 static l_int32   tiffGetResolution(TIFF *tif, l_uint32 *pxres, l_uint32 *pyres);
88 static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
89                                     l_int32 *pheight, l_int32 *pbps,
90                                     l_int32 *pspp, l_int32 *pres,
91                                     l_int32 *pcmap);
92 static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
93                                      SARRAY *savals, SARRAY  *satypes,
94                                      NUMA *nasizes);
95 static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
96                                       NUMA *natags, SARRAY *savals,
97                                       SARRAY *satypes, NUMA *nasizes);
98 static TIFF     *fopenTiff(FILE *fp, const char *modestr);
99 
100     /* Static function for memory I/O */
101 static TIFF *fopenTiffMemstream(const char *filename, const char *operation,
102                                 l_uint8 **pdata, size_t *pdatasize);
103 
104 
105     /* This structure defines a transform to be performed on a TIFF image
106      * (note that the same transformation can be represented in
107      * several different ways using this structure since
108      * vflip + hflip + counterclockwise == clockwise). */
109 struct tiff_transform {
110     int vflip;    /* if non-zero, image needs a vertical fip */
111     int hflip;    /* if non-zero, image needs a horizontal flip */
112     int rotate;   /* -1 -> counterclockwise 90-degree rotation,
113                       0 -> no rotation
114                       1 -> clockwise 90-degree rotation */
115 };
116 
117     /* This describes the transformations needed for a given orientation
118      * tag.  The tag values start at 1, so you need to subtract 1 to get a
119      * valid index into this array. */
120 static struct tiff_transform tiff_orientation_transforms[] = {
121     {0, 0, 0},
122     {0, 1, 0},
123     {1, 1, 0},
124     {1, 0, 0},
125     {0, 1, -1},
126     {0, 0, 1},
127     {0, 1, 1},
128     {0, 0, -1}
129 };
130 
131 
132 
133 /*--------------------------------------------------------------*
134  *                      Reading from file                       *
135  *--------------------------------------------------------------*/
136 /*!
137  *  pixReadTiff()
138  *
139  *      Input:  filename
140  *              page number (0 based)
141  *      Return: pix, or null on error
142  *
143  *  Notes:
144  *      (1) This is a version of pixRead(), specialized for tiff
145  *          files, that allows specification of the page to be returned
146  *      (2) We must call findFileFormat() to get the actual tiff
147  *          compression format.
148  */
149 PIX *
pixReadTiff(const char * filename,l_int32 n)150 pixReadTiff(const char  *filename,
151             l_int32      n)
152 {
153 l_int32  format;
154 FILE    *fp;
155 PIX     *pix;
156 
157     PROCNAME("pixReadTiff");
158 
159     if (!filename)
160         return (PIX *)ERROR_PTR("filename not defined", procName, NULL);
161 
162     if ((fp = fopenReadStream(filename)) == NULL)
163         return (PIX *)ERROR_PTR("image file not found", procName, NULL);
164     if ((pix = pixReadStreamTiff(fp, n)) == NULL) {
165         fclose(fp);
166         return (PIX *)ERROR_PTR("pix not read", procName, NULL);
167     }
168     format = findFileFormat(fp);
169     fclose(fp);
170     pixSetInputFormat(pix, format);
171 
172     return pix;
173 }
174 
175 
176 /*--------------------------------------------------------------*
177  *                     Reading from stream                      *
178  *--------------------------------------------------------------*/
179 /*!
180  *  pixReadStreamTiff()
181  *
182  *      Input:  stream
183  *              n (page number: 0 based)
184  *      Return: pix, or null on error (e.g., if the page number is invalid)
185  */
186 PIX *
pixReadStreamTiff(FILE * fp,l_int32 n)187 pixReadStreamTiff(FILE    *fp,
188                   l_int32  n)
189 {
190 l_int32  i, pagefound;
191 PIX     *pix;
192 TIFF    *tif;
193 
194     PROCNAME("pixReadStreamTiff");
195 
196     if (!fp)
197         return (PIX *)ERROR_PTR("stream not defined", procName, NULL);
198 
199     if ((tif = fopenTiff(fp, "r")) == NULL)
200         return (PIX *)ERROR_PTR("tif not opened", procName, NULL);
201 
202     pagefound = FALSE;
203     pix = NULL;
204     for (i = 0; i < MAX_PAGES_IN_TIFF_FILE; i++) {
205         if (i == n) {
206             pagefound = TRUE;
207             if ((pix = pixReadFromTiffStream(tif)) == NULL) {
208                 TIFFCleanup(tif);
209                 return (PIX *)ERROR_PTR("pix not read", procName, NULL);
210             }
211             break;
212         }
213         if (TIFFReadDirectory(tif) == 0)
214             break;
215     }
216 
217     if (pagefound == FALSE) {
218         L_WARNING_INT("tiff page %d not found", procName, n);
219         TIFFCleanup(tif);
220         return NULL;
221     }
222 
223         /* Set to generic input format; refinement is done
224          * in pixReadStream() using findFileFormat(). */
225     pixSetInputFormat(pix, IFF_TIFF);
226     TIFFCleanup(tif);
227     return pix;
228 }
229 
230 
231 /*!
232  *  pixReadFromTiffStream()
233  *
234  *      Input:  stream
235  *      Return: pix, or null on error
236  */
237 static PIX *
pixReadFromTiffStream(TIFF * tif)238 pixReadFromTiffStream(TIFF  *tif)
239 {
240 l_uint8   *linebuf, *data;
241 l_uint16   spp, bps, bpp, tiffbpl, photometry, compress, orientation;
242 l_uint16  *redmap, *greenmap, *bluemap;
243 l_int32    d, wpl, bpl, i, j, k, ncolors, rval, gval, bval;
244 l_uint32   w, h, xres, yres, tiffword;
245 l_uint32  *line, *ppixel, *tiffdata;
246 PIX       *pix;
247 PIXCMAP   *cmap;
248 
249     PROCNAME("pixReadFromTiffStream");
250 
251     if (!tif)
252         return (PIX *)ERROR_PTR("tif not defined", procName, NULL);
253 
254         /* Use default fields for bps and spp */
255     TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
256     TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
257     bpp = bps * spp;
258     if (bpp > 24)
259         return (PIX *)ERROR_PTR("can't handle bpp > 24", procName, NULL);
260     if (spp == 1)
261         d = bps;
262     else if (spp == 3)
263         d = 32;
264     else
265         return (PIX *)ERROR_PTR("spp not in set {1,3}", procName, NULL);
266 
267     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
268     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
269     tiffbpl = TIFFScanlineSize(tif);
270 
271     if ((pix = pixCreate(w, h, d)) == NULL)
272         return (PIX *)ERROR_PTR("pix not made", procName, NULL);
273     data = (l_uint8 *)pixGetData(pix);
274     wpl = pixGetWpl(pix);
275     bpl = 4 * wpl;
276 
277         /* Read the data */
278     if (spp == 1) {
279         if ((linebuf = (l_uint8 *)CALLOC(tiffbpl + 1, sizeof(l_uint8))) == NULL)
280             return (PIX *)ERROR_PTR("calloc fail for linebuf", procName, NULL);
281 
282         for (i = 0 ; i < h ; i++) {
283             if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
284                 FREE(linebuf);
285                 pixDestroy(&pix);
286                 return (PIX *)ERROR_PTR("line read fail", procName, NULL);
287             }
288             memcpy((char *)data, (char *)linebuf, tiffbpl);
289             data += bpl;
290         }
291         if (bps <= 8)
292             pixEndianByteSwap(pix);
293         else   /* bps == 16 */
294             pixEndianTwoByteSwap(pix);
295         FREE(linebuf);
296     }
297     else {  /* rgb */
298         if ((tiffdata = (l_uint32 *)CALLOC(w * h, sizeof(l_uint32))) == NULL) {
299             pixDestroy(&pix);
300             return (PIX *)ERROR_PTR("calloc fail for tiffdata", procName, NULL);
301         }
302         if (!TIFFReadRGBAImageOriented(tif, w, h, (uint32 *)tiffdata,
303                                        ORIENTATION_TOPLEFT, 0)) {
304             FREE(tiffdata);
305             pixDestroy(&pix);
306             return (PIX *)ERROR_PTR("failed to read tiffdata", procName, NULL);
307         }
308 
309         line = pixGetData(pix);
310         for (i = 0 ; i < h ; i++, line += wpl) {
311             for (j = 0, k = 0, ppixel = line; j < w; j++) {
312                     /* TIFFGet* are macros */
313                 tiffword = tiffdata[i * w + j];
314                 rval = TIFFGetR(tiffword);
315                 gval = TIFFGetG(tiffword);
316                 bval = TIFFGetB(tiffword);
317                 composeRGBPixel(rval, gval, bval, ppixel);
318                 ppixel++;
319             }
320         }
321         FREE(tiffdata);
322     }
323 
324     if (tiffGetResolution(tif, &xres, &yres)) {
325         pixSetXRes(pix, xres);
326         pixSetYRes(pix, yres);
327     }
328 
329     if (TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap)) {
330             /* Save the colormap as a pix cmap.  Because the
331              * tiff colormap components are 16 bit unsigned,
332              * and go from black (0) to white (0xffff), the
333              * the pix cmap takes the most significant byte. */
334         if ((cmap = pixcmapCreate(bps)) == NULL) {
335             pixDestroy(&pix);
336             return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
337         }
338         ncolors = 1 << bps;
339         for (i = 0; i < ncolors; i++)
340             pixcmapAddColor(cmap, redmap[i] >> 8, greenmap[i] >> 8,
341                             bluemap[i] >> 8);
342         pixSetColormap(pix, cmap);
343     }
344     else {   /* No colormap: check photometry and invert if necessary */
345         if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometry)) {
346                 /* Guess default photometry setting.  Assume min_is_white
347                  * if compressed 1 bpp; min_is_black otherwise. */
348             TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress);
349             if (compress == COMPRESSION_CCITTFAX3 ||
350                 compress == COMPRESSION_CCITTFAX4 ||
351                 compress == COMPRESSION_CCITTRLE ||
352                 compress == COMPRESSION_CCITTRLEW) {
353                 photometry = PHOTOMETRIC_MINISWHITE;
354             }
355             else
356                 photometry = PHOTOMETRIC_MINISBLACK;
357         }
358         if ((d == 1 && photometry == PHOTOMETRIC_MINISBLACK) ||
359             (d == 8 && photometry == PHOTOMETRIC_MINISWHITE))
360             pixInvert(pix, pix);
361     }
362 
363     if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
364         if (orientation >= 1 && orientation <= 8) {
365             struct tiff_transform *transform =
366               &tiff_orientation_transforms[orientation - 1];
367             if (transform->vflip) pixFlipTB(pix, pix);
368             if (transform->hflip) pixFlipLR(pix, pix);
369             if (transform->rotate) {
370                 PIX *oldpix = pix;
371                 pix = pixRotate90(oldpix, transform->rotate);
372                 pixDestroy(&oldpix);
373             }
374         }
375     }
376 
377     return pix;
378 }
379 
380 
381 /*--------------------------------------------------------------*
382  *                       Writing to file                        *
383  *--------------------------------------------------------------*/
384 /*!
385  *  pixWriteTiff()
386  *
387  *      Input:  filename (to write to)
388  *              pix
389  *              comptype (IFF_TIFF, IFF_TIFF_RLE, IFF_TIFF_PACKBITS,
390  *                        IFF_TIFF_G3, IFF_TIFF_G4,
391  *                        IFF_TIFF_LZW, IFF_TIFF_ZIP)
392  *              modestring ("a" or "w")
393  *      Return: 0 if OK, 1 on error
394  *
395  *  Notes:
396  *      (1) For multi-page tiff, write the first pix with mode "w" and
397  *          all subsequent pix with mode "a".
398  */
399 l_int32
pixWriteTiff(const char * filename,PIX * pix,l_int32 comptype,const char * modestring)400 pixWriteTiff(const char  *filename,
401              PIX         *pix,
402              l_int32      comptype,
403              const char  *modestring)
404 {
405     return pixWriteTiffCustom(filename, pix, comptype, modestring,
406                               NULL, NULL, NULL, NULL);
407 }
408 
409 
410 /*!
411  *  pixWriteTiffCustom()
412  *
413  *      Input:  filename (to write to)
414  *              pix
415  *              comptype (IFF_TIFF, IFF_TIFF_RLE, IFF_TIFF_PACKBITS,
416  *                        IFF_TIFF_G3, IFF_TIFF_G4)
417  *                        IFF_TIFF_LZW, IFF_TIFF_ZIP)
418  *              modestring ("a" or "w")
419  *              natags (<optional> NUMA of custom tiff tags)
420  *              savals (<optional> SARRAY of values)
421  *              satypes (<optional> SARRAY of types)
422  *              nasizes (<optional> NUMA of sizes)
423  *      Return: 0 if OK, 1 on error
424  *
425  *  Usage:
426  *      (1) This writes a page image to a tiff file, with optional
427  *          extra tags defined in tiff.h
428  *      (2) For multi-page tiff, write the first pix with mode "w" and
429  *          all subsequent pix with mode "a".
430  *      (3) For the custom tiff tags:
431  *          (a) The three arrays {natags, savals, satypes} must all be
432  *              either NULL or defined and of equal size.
433  *          (b) If they are defined, the tags are an array of integers,
434  *              the vals are an array of values in string format, and
435  *              the types are an array of types in string format.
436  *          (c) All valid tags are definined in tiff.h.
437  *          (d) The types allowed are the set of strings:
438  *                "char*"
439  *                "l_uint8*"
440  *                "l_uint16"
441  *                "l_uint32"
442  *                "l_int32"
443  *                "l_float64"
444  *                "l_uint16-l_uint16" (note the dash; use it between the
445  *                                    two l_uint16 vals in the val string)
446  *              Of these, "char*" and "l_uint16" are the most commonly used.
447  *          (e) The last array, nasizes, is also optional.  It is for
448  *              tags that take an array of bytes for a value, a number of
449  *              elements in the array, and a type that is either "char*"
450  *              or "l_uint8*" (probably either will work).
451  *              Use NULL if there are no such tags.
452  *          (f) VERY IMPORTANT: if there are any tags that require the
453  *              extra size value, stored in nasizes, they must be
454  *              written first!
455  */
456 l_int32
pixWriteTiffCustom(const char * filename,PIX * pix,l_int32 comptype,const char * modestring,NUMA * natags,SARRAY * savals,SARRAY * satypes,NUMA * nasizes)457 pixWriteTiffCustom(const char  *filename,
458                    PIX         *pix,
459                    l_int32      comptype,
460                    const char  *modestring,
461                    NUMA        *natags,
462                    SARRAY      *savals,
463                    SARRAY      *satypes,
464                    NUMA        *nasizes)
465 {
466 l_int32  ret;
467 TIFF    *tif;
468 
469     PROCNAME("pixWriteTiffCustom");
470 
471     if (!filename)
472         return ERROR_INT("filename not defined", procName, 1);
473     if (!pix)
474         return ERROR_INT("pix not defined", procName, 1);
475 
476     if ((tif = TIFFOpen(filename, modestring)) == NULL)
477         return ERROR_INT("tif not opened", procName, 1);
478     ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
479                                satypes, nasizes);
480     TIFFClose(tif);
481 
482     return ret;
483 }
484 
485 
486 /*--------------------------------------------------------------*
487  *                       Writing to stream                      *
488  *--------------------------------------------------------------*/
489 /*!
490  *  pixWriteStreamTiff()
491  *
492  *      Input:  stream (opened for append or write)
493  *              pix
494  *              comptype (IFF_TIFF, IFF_TIFF_RLE, IFF_TIFF_PACKBITS,
495  *                        IFF_TIFF_G3, IFF_TIFF_G4,
496  *                        IFF_TIFF_LZW, IFF_TIFF_ZIP)
497  *      Return: 0 if OK, 1 on error
498  *
499  *  Notes:
500  *      (1) For images with bpp > 1, this resets the comptype, if
501  *          necessary, to write uncompressed data.
502  *      (2) G3 and G4 are only defined for 1 bpp.
503  *      (3) We only allow PACKBITS for bpp = 1, because for bpp > 1
504  *          it typically expands images that are not synthetically generated.
505  *      (4) G4 compression is typically about twice as good as G3.
506  *          G4 is excellent for binary compression of text/line-art,
507  *          but terrible for halftones and dithered patterns.  (In
508  *          fact, G4 on halftones can give a file that is larger
509  *          than uncompressed!)  If a binary image has dithered
510  *          regions, it is usually better to compress with png.
511  */
512 l_int32
pixWriteStreamTiff(FILE * fp,PIX * pix,l_int32 comptype)513 pixWriteStreamTiff(FILE    *fp,
514                    PIX     *pix,
515                    l_int32  comptype)
516 {
517 TIFF  *tif;
518 
519     PROCNAME("pixWriteStreamTiff");
520 
521     if (!fp)
522         return ERROR_INT("stream not defined", procName, 1 );
523     if (!pix)
524         return ERROR_INT("pix not defined", procName, 1 );
525 
526     if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
527         comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP) {
528         L_WARNING("invalid compression type for image with bpp > 1", procName);
529         comptype = IFF_TIFF;
530     }
531 
532     if ((tif = fopenTiff(fp, "w")) == NULL)
533         return ERROR_INT("tif not opened", procName, 1);
534 
535     if (pixWriteToTiffStream(tif, pix, comptype, NULL, NULL, NULL, NULL)) {
536         TIFFCleanup(tif);
537         return ERROR_INT("tif write error", procName, 1);
538     }
539 
540     TIFFCleanup(tif);
541     return 0;
542 }
543 
544 
545 /*!
546  *  pixWriteToTiffStream()
547  *
548  *      Input:  tif (data structure, opened to a file)
549  *              pix
550  *              comptype  (IFF_TIFF: for any image; no compression
551  *                         IFF_TIFF_RLE, IFF_TIFF_PACKBITS: for 1 bpp only
552  *                         IFF_TIFF_G4 and IFF_TIFF_G3: for 1 bpp only
553  *                         IFF_TIFF_LZW, IFF_TIFF_ZIP: for any image
554  *              natags (<optional> NUMA of custom tiff tags)
555  *              savals (<optional> SARRAY of values)
556  *              satypes (<optional> SARRAY of types)
557  *              nasizes (<optional> NUMA of sizes)
558  *      Return: 0 if OK, 1 on error
559  *
560  *  Notes:
561  *      (1) This static function should only be called through higher
562  *          level functions in this file; namely, pixWriteTiffCustom(),
563  *          pixWriteTiff(), pixWriteStreamTiff(), pixWriteMemTiff()
564  *          and pixWriteMemTiffCustom().
565  *      (2) We only allow PACKBITS for bpp = 1, because for bpp > 1
566  *          it typically expands images that are not synthetically generated.
567  *      (3) See pixWriteTiffCustom() for details on how to use
568  *          the last four parameters for customized tiff tags.
569  *      (4) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
570  *          and 32.  However, it is possible, and in some cases desirable,
571  *          to write out a tiff file using an rgb pix that has 24 bpp.
572  *          This can be created by appending the raster data for a 24 bpp
573  *          image (with proper scanline padding) directly to a 24 bpp
574  *          pix that was created without a data array.  See note in
575  *          pixWriteStreamPng() for an example.
576  */
577 static l_int32
pixWriteToTiffStream(TIFF * tif,PIX * pix,l_int32 comptype,NUMA * natags,SARRAY * savals,SARRAY * satypes,NUMA * nasizes)578 pixWriteToTiffStream(TIFF    *tif,
579                      PIX     *pix,
580                      l_int32  comptype,
581                      NUMA    *natags,
582                      SARRAY  *savals,
583                      SARRAY  *satypes,
584                      NUMA    *nasizes)
585 {
586 l_uint8   *linebuf, *data;
587 l_uint16   redmap[256], greenmap[256], bluemap[256];
588 l_int32    w, h, d, i, j, k, wpl, bpl, tiffbpl, ncolors, cmapsize;
589 l_int32   *rmap, *gmap, *bmap;
590 l_uint32   xres, yres;
591 l_uint32  *line, *ppixel;
592 PIX       *pixt;
593 PIXCMAP   *cmap;
594 char      *text;
595 
596     PROCNAME("pixWriteToTiffStream");
597 
598     if (!tif)
599         return ERROR_INT("tif stream not defined", procName, 1);
600     if (!pix)
601         return ERROR_INT( "pix not defined", procName, 1 );
602 
603     pixGetDimensions(pix, &w, &h, &d);
604     xres = pixGetXRes(pix);
605     yres = pixGetYRes(pix);
606     if (xres == 0) xres = DEFAULT_RESOLUTION;
607     if (yres == 0) yres = DEFAULT_RESOLUTION;
608 
609         /* ------------------ Write out the header -------------  */
610     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (l_uint32)RESUNIT_INCH);
611     TIFFSetField(tif, TIFFTAG_XRESOLUTION, (l_float64)xres);
612     TIFFSetField(tif, TIFFTAG_YRESOLUTION, (l_float64)yres);
613 
614     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (l_uint32)w);
615     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (l_uint32)h);
616     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
617 
618     if ((text = pixGetText(pix)) != NULL)
619         TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, text);
620 
621     if (d == 1)
622         TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
623     else if (d == 32 || d == 24) {
624         TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
625         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
626                        (l_uint16)8, (l_uint16)8, (l_uint16)8);
627         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)3);
628     }
629     else if ((cmap = pixGetColormap(pix)) == NULL)
630         TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
631     else {  /* Save colormap in the tiff; not more than 256 colors */
632         pixcmapToArrays(cmap, &rmap, &gmap, &bmap);
633         ncolors = pixcmapGetCount(cmap);
634         ncolors = L_MIN(256, ncolors);  /* max 256 */
635         cmapsize = 1 << d;
636         cmapsize = L_MIN(256, cmapsize);  /* power of 2; max 256 */
637         if (ncolors > cmapsize) {
638             L_WARNING("too many colors in cmap for tiff; truncating", procName);
639             ncolors = cmapsize;
640         }
641         for (i = 0; i < ncolors; i++) {
642             redmap[i] = (rmap[i] << 8) | rmap[i];
643             greenmap[i] = (gmap[i] << 8) | gmap[i];
644             bluemap[i] = (bmap[i] << 8) | bmap[i];
645         }
646         for (i = ncolors; i < cmapsize; i++)  /* init, even though not used */
647             redmap[i] = greenmap[i] = bluemap[i] = 0;
648         FREE(rmap);
649         FREE(gmap);
650         FREE(bmap);
651 
652         TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
653         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
654         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
655         TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
656     }
657 
658     if (d != 24 && d != 32) {
659         TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
660         TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
661     }
662 
663     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
664     if (comptype == IFF_TIFF)  /* no compression */
665         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
666     else if (comptype == IFF_TIFF_G4)
667         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
668     else if (comptype == IFF_TIFF_G3)
669         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
670     else if (comptype == IFF_TIFF_RLE)
671         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);
672     else if (comptype == IFF_TIFF_PACKBITS)
673         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
674     else if (comptype == IFF_TIFF_LZW)
675         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
676     else if (comptype == IFF_TIFF_ZIP)
677         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
678     else {
679         L_WARNING("unknown tiff compression; using none", procName);
680         TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
681     }
682 
683         /* This is a no-op if arrays are NULL */
684     writeCustomTiffTags(tif, natags, savals, satypes, nasizes);
685 
686         /* ------------- Write out the image data -------------  */
687     tiffbpl = TIFFScanlineSize(tif);
688     wpl = pixGetWpl(pix);
689     bpl = 4 * wpl;
690     if (tiffbpl > bpl)
691         fprintf(stderr, "Big trouble: tiffbpl = %d, bpl = %d\n", tiffbpl, bpl);
692     if ((linebuf = (l_uint8 *)CALLOC(1, bpl)) == NULL)
693         return ERROR_INT("calloc fail for linebuf", procName, 1);
694 
695         /* Use single strip for image */
696     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);
697 
698     if (d != 24 && d != 32) {
699         if (d == 16)
700             pixt = pixEndianTwoByteSwapNew(pix);
701         else
702             pixt = pixEndianByteSwapNew(pix);
703         data = (l_uint8 *)pixGetData(pixt);
704         for (i = 0; i < h; i++, data += bpl) {
705             memcpy((char *)linebuf, (char *)data, tiffbpl);
706             if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
707                 break;
708         }
709         pixDestroy(&pixt);
710     }
711     else if (d == 24) {  /* See note 4 above: special case of 24 bpp rgb */
712         for (i = 0; i < h; i++) {
713             line = pixGetData(pix) + i * wpl;
714             if (TIFFWriteScanline(tif, (l_uint8 *)line, i, 0) < 0)
715                 break;
716         }
717     }
718     else {  /* standard 32 bpp rgb */
719         for (i = 0; i < h; i++) {
720             line = pixGetData(pix) + i * wpl;
721             for (j = 0, k = 0, ppixel = line; j < w; j++) {
722                 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
723                 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
724                 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
725                 ppixel++;
726             }
727             if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
728                 break;
729         }
730     }
731 
732 /*    TIFFWriteDirectory(tif); */
733     FREE(linebuf);
734 
735     return 0;
736 }
737 
738 
739 /*!
740  *  writeCustomTiffTags()
741  *
742  *      Input:  tif
743  *              natags (<optional> NUMA of custom tiff tags)
744  *              savals (<optional> SARRAY of values)
745  *              satypes (<optional> SARRAY of types)
746  *              nasizes (<optional> NUMA of sizes)
747  *      Return: 0 if OK, 1 on error
748  *
749  *  Notes:
750  *      (1) This static function should be called indirectly through
751  *          higher level functions, such as pixWriteTiffCustom(),
752  *          which call pixWriteToTiffStream().  See details in
753  *          pixWriteTiffCustom() for using the 4 input arrays.
754  *      (2) This is a no-op if the first 3 arrays are all NULL.
755  *      (3) Otherwise, the first 3 arrays must be defined and all
756  *          of equal size.
757  *      (4) The fourth array is always optional.
758  *      (5) The most commonly used types are "char*" and "u_int16".
759  *          See tiff.h for a full listing of the tiff tags.
760  *          Note that many of these tags, in particular the bit tags,
761  *          are intended to be private, and cannot be set by this function.
762  *          Examples are the STRIPOFFSETS and STRIPBYTECOUNTS tags,
763  *          which are bit tags that are automatically set in the header,
764  *          and can be extracted using tiffdump.
765  */
766 static l_int32
writeCustomTiffTags(TIFF * tif,NUMA * natags,SARRAY * savals,SARRAY * satypes,NUMA * nasizes)767 writeCustomTiffTags(TIFF    *tif,
768                     NUMA    *natags,
769                     SARRAY  *savals,
770                     SARRAY  *satypes,
771                     NUMA    *nasizes)
772 {
773 char      *sval, *type;
774 l_int32    i, n, ns, size, tagval, val;
775 l_float64  dval;
776 l_uint32   uval, uval2;
777 
778     PROCNAME("writeCustomTiffTags");
779 
780     if (!tif)
781         return ERROR_INT("tif stream not defined", procName, 1);
782     if (!natags && !savals && !satypes)
783         return 0;
784     if (!natags || !savals || !satypes)
785         return ERROR_INT("not all arrays defined", procName, 1);
786     n = numaGetCount(natags);
787     if ((sarrayGetCount(savals) != n) || (sarrayGetCount(satypes) != n))
788         return ERROR_INT("not all sa the same size", procName, 1);
789 
790         /* The sized arrays (4 args to TIFFSetField) are written first */
791     if (nasizes) {
792         ns = numaGetCount(nasizes);
793         if (ns > n)
794             return ERROR_INT("too many 4-arg tag calls", procName, 1);
795         for (i = 0; i < ns; i++) {
796             numaGetIValue(natags, i, &tagval);
797             sval = sarrayGetString(savals, i, 0);
798             type = sarrayGetString(satypes, i, 0);
799             numaGetIValue(nasizes, i, &size);
800             if (strcmp(type, "char*") && strcmp(type, "l_uint8*"))
801                 L_WARNING("array type not char* or l_uint8*; ignore", procName);
802             TIFFSetField(tif, tagval, size, sval);
803         }
804     }
805     else
806         ns = 0;
807 
808         /* The typical tags (3 args to TIFFSetField) are now written */
809     for (i = ns; i < n; i++) {
810         numaGetIValue(natags, i, &tagval);
811         sval = sarrayGetString(savals, i, 0);
812         type = sarrayGetString(satypes, i, 0);
813         if (!strcmp(type, "char*")) {
814             TIFFSetField(tif, tagval, sval);
815         }
816         else if (!strcmp(type, "l_uint16")) {
817             if (sscanf(sval, "%u", &uval) == 1) {
818                 TIFFSetField(tif, tagval, (l_uint16)uval);
819             }
820             else {
821                 fprintf(stderr, "val %s not of type %s\n", sval, type);
822                 return ERROR_INT("custom tag(s) not written", procName, 1);
823             }
824         }
825         else if (!strcmp(type, "l_uint32")) {
826             if (sscanf(sval, "%u", &uval) == 1) {
827                 TIFFSetField(tif, tagval, uval);
828             }
829             else {
830                 fprintf(stderr, "val %s not of type %s\n", sval, type);
831                 return ERROR_INT("custom tag(s) not written", procName, 1);
832             }
833         }
834         else if (!strcmp(type, "l_int32")) {
835             if (sscanf(sval, "%d", &val) == 1) {
836                 TIFFSetField(tif, tagval, val);
837             }
838             else {
839                 fprintf(stderr, "val %s not of type %s\n", sval, type);
840                 return ERROR_INT("custom tag(s) not written", procName, 1);
841             }
842         }
843         else if (!strcmp(type, "l_float64")) {
844             if (sscanf(sval, "%f", &dval) == 1) {
845                 TIFFSetField(tif, tagval, dval);
846             }
847             else {
848                 fprintf(stderr, "val %s not of type %s\n", sval, type);
849                 return ERROR_INT("custom tag(s) not written", procName, 1);
850             }
851         }
852         else if (!strcmp(type, "l_uint16-l_uint16")) {
853             if (sscanf(sval, "%u-%u", &uval, &uval2) == 2) {
854                 TIFFSetField(tif, tagval, (l_uint16)uval, (l_uint16)uval2);
855             }
856             else {
857                 fprintf(stderr, "val %s not of type %s\n", sval, type);
858                 return ERROR_INT("custom tag(s) not written", procName, 1);
859             }
860         }
861         else
862             return ERROR_INT("unknown type; tag(s) not written", procName, 1);
863     }
864     return 0;
865 }
866 
867 
868 /*--------------------------------------------------------------*
869  *                   Print info to stream                       *
870  *--------------------------------------------------------------*/
871 /*
872  *  fprintTiffInfo()
873  *
874  *      Input:  stream (for output of tag data)
875  *              tiffile (input)
876  *      Return: 0 if OK; 1 on error
877  */
878 l_int32
fprintTiffInfo(FILE * fpout,const char * tiffile)879 fprintTiffInfo(FILE        *fpout,
880                const char  *tiffile)
881 {
882 TIFF  *tif;
883 
884     PROCNAME("fprintTiffInfo");
885 
886     if (!tiffile)
887         return ERROR_INT("tiffile not defined", procName, 1);
888     if (!fpout)
889         return ERROR_INT("stream out not defined", procName, 1);
890 
891     if ((tif = TIFFOpen(tiffile, "r")) == NULL)
892         return ERROR_INT("tif not open for read", procName, 1);
893 
894     TIFFPrintDirectory(tif, fpout, 0);
895     TIFFClose(tif);
896 
897     return 0;
898 }
899 
900 
901 /*--------------------------------------------------------------*
902  *                   Get count from stream                      *
903  *--------------------------------------------------------------*/
904 /*
905  *  tiffGetCount()
906  *
907  *      Input:  stream (opened for read)
908  *              &n (<return> number of images)
909  *      Return: 0 if OK; 1 on error
910  */
911 l_int32
tiffGetCount(FILE * fp,l_int32 * pn)912 tiffGetCount(FILE     *fp,
913              l_int32  *pn)
914 {
915 l_int32  i;
916 TIFF    *tif;
917 
918     PROCNAME("tiffGetCount");
919 
920     if (!fp)
921         return ERROR_INT("stream not defined", procName, 1);
922     if (!pn)
923         return ERROR_INT("&n not defined", procName, 1);
924     *pn = 0;
925 
926     if ((tif = fopenTiff(fp, "r")) == NULL)
927         return ERROR_INT("tif not open for read", procName, 1);
928 
929     for (i = 1; i < MAX_PAGES_IN_TIFF_FILE; i++) {
930         if (TIFFReadDirectory(tif) == 0)
931             break;
932     }
933     *pn = i;
934     TIFFCleanup(tif);
935     return 0;
936 }
937 
938 
939 /*--------------------------------------------------------------*
940  *                   Get resolution from tif                    *
941  *--------------------------------------------------------------*/
942 /*
943  *  tiffGetResolution()
944  *
945  *      Input:  tiff stream (opened for read)
946  *              &xres, &yres (<return> resolution in ppi)
947  *      Return: 1 if OK; 0 on error   (nonstandard)
948  *
949  *  Notes:
950  *      (1) If neither resolution field is set, this is not an error;
951  *          the returned resolution values are 0 (designating 'unknown').
952  */
953 static l_int32
tiffGetResolution(TIFF * tif,l_uint32 * pxres,l_uint32 * pyres)954 tiffGetResolution(TIFF      *tif,
955                   l_uint32  *pxres,
956                   l_uint32  *pyres)
957 {
958 l_uint16   resunit;
959 l_int32    foundxres, foundyres;
960 l_float32  fxres, fyres;
961 
962     PROCNAME("tiffGetResolution");
963 
964     if (!tif)
965         return ERROR_INT("tif not opened", procName, 0);
966     if (!pxres || !pyres)
967         return ERROR_INT("&xres and &yres not both defined", procName, 0);
968     *pxres = *pyres = 0;
969 
970     TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
971     foundxres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fxres);
972     foundyres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fyres);
973     if (!foundxres && !foundyres) return 1;
974     if (!foundxres && foundyres)
975         fxres = fyres;
976     else if (foundxres && !foundyres)
977         fyres = fxres;
978 
979     if (resunit == RESUNIT_CENTIMETER) {  /* convert to ppi */
980         *pxres = (l_uint32)(2.54 * fxres + 0.5);
981         *pyres = (l_uint32)(2.54 * fyres + 0.5);
982     }
983     else {
984         *pxres = (l_uint32)fxres;
985         *pyres = (l_uint32)fyres;
986     }
987 
988     return 1;
989 }
990 
991 
992 /*--------------------------------------------------------------*
993  *              Get some tiff header information                *
994  *--------------------------------------------------------------*/
995 /*!
996  *  readHeaderTiff()
997  *
998  *      Input:  filename
999  *              n (page image number: 0-based)
1000  *              &width (<return>)
1001  *              &height (<return>)
1002  *              &bps (<return> bits per sample -- 1, 2, 4 or 8)
1003  *              &spp (<return>; samples per pixel -- 1 or 3)
1004  *              &res (<optional return>; resolution in x dir; NULL to ignore)
1005  *              &cmap (<optional return>; colormap exists; input NULL to ignore)
1006  *      Return: 0 if OK, 1 on error
1007  *
1008  *  Notes:
1009  *      (1) If there is a colormap, cmap is returned as 1; else 0.
1010  *      (2) If @n is equal to or greater than the number of images, returns 1.
1011  */
1012 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)1013 readHeaderTiff(const char *filename,
1014                l_int32     n,
1015                l_int32    *pwidth,
1016                l_int32    *pheight,
1017                l_int32    *pbps,
1018                l_int32    *pspp,
1019                l_int32    *pres,
1020                l_int32    *pcmap)
1021 {
1022 l_int32  ret;
1023 FILE    *fp;
1024 
1025     PROCNAME("readHeaderTiff");
1026 
1027     if (!filename)
1028         return ERROR_INT("filename not defined", procName, 1);
1029     if (!pwidth || !pheight || !pbps || !pspp)
1030         return ERROR_INT("input ptr(s) not all defined", procName, 1);
1031     *pwidth = *pheight = *pbps = *pspp = 0;
1032     if (pres) *pres = 0;
1033     if (pcmap) *pcmap = 0;
1034 
1035     if ((fp = fopenReadStream(filename)) == NULL)
1036         return ERROR_INT("image file not found", procName, 1);
1037     ret = freadHeaderTiff(fp, n, pwidth, pheight, pbps, pspp, pres, pcmap);
1038     fclose(fp);
1039     return ret;
1040 }
1041 
1042 
1043 /*!
1044  *  freadHeaderTiff()
1045  *
1046  *      Input:  stream
1047  *              n (page image number: 0-based)
1048  *              &width (<return>)
1049  *              &height (<return>)
1050  *              &bps (<return> bits per sample -- 1, 2, 4 or 8)
1051  *              &spp (<return>; samples per pixel -- 1 or 3)
1052  *              &res (<optional return>; resolution in x dir; NULL to ignore)
1053  *              &cmap (<optional return>; colormap exists; input NULL to ignore)
1054  *      Return: 0 if OK, 1 on error
1055  *
1056  *  Notes:
1057  *      (1) If there is a colormap, cmap is returned as 1; else 0.
1058  *      (2) If @n is equal to or greater than the number of images, returns 1.
1059  */
1060 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)1061 freadHeaderTiff(FILE     *fp,
1062                 l_int32   n,
1063                 l_int32  *pwidth,
1064                 l_int32  *pheight,
1065                 l_int32  *pbps,
1066                 l_int32  *pspp,
1067                 l_int32  *pres,
1068                 l_int32  *pcmap)
1069 {
1070 l_int32  i, ret, format;
1071 TIFF    *tif;
1072 
1073     PROCNAME("freadHeaderTiff");
1074 
1075     if (!fp)
1076         return ERROR_INT("stream not defined", procName, 1);
1077     if (n < 0)
1078         return ERROR_INT("image index must be >= 0", procName, 1);
1079     if (!pwidth || !pheight || !pbps || !pspp)
1080         return ERROR_INT("input ptr(s) not all defined", procName, 1);
1081     *pwidth = *pheight = *pbps = *pspp = 0;
1082     if (pres) *pres = 0;
1083     if (pcmap) *pcmap = 0;
1084 
1085     format = findFileFormat(fp);
1086     if (format != IFF_TIFF &&
1087         format != IFF_TIFF_G3 && format != IFF_TIFF_G4 &&
1088         format != IFF_TIFF_RLE && format != IFF_TIFF_PACKBITS &&
1089         format != IFF_TIFF_LZW && format != IFF_TIFF_ZIP)
1090         return ERROR_INT("file not tiff format", procName, 1);
1091 
1092     if ((tif = fopenTiff(fp, "r")) == NULL)
1093         return ERROR_INT("tif not open for read", procName, 1);
1094 
1095     for (i = 0; i < n; i++) {
1096         if (TIFFReadDirectory(tif) == 0)
1097             return ERROR_INT("image n not found in file", procName, 1);
1098     }
1099 
1100     ret = tiffReadHeaderTiff(tif, pwidth, pheight, pbps, pspp, pres, pcmap);
1101 
1102     TIFFCleanup(tif);
1103     return ret;
1104 }
1105 
1106 
1107 /*!
1108  *  readHeaderMemTiff()
1109  *
1110  *      Input:  cdata (const; tiff-encoded)
1111  *              size (size of data)
1112  *              n (page image number: 0-based)
1113  *              &width (<return>)
1114  *              &height (<return>)
1115  *              &bps (<return> bits per sample -- 1, 2, 4 or 8)
1116  *              &spp (<return>; samples per pixel -- 1 or 3)
1117  *              &res (<optional return>; resolution in x dir; NULL to ignore)
1118  *              &cmap (<optional return>; colormap exists; input NULL to ignore)
1119  *      Return: 0 if OK, 1 on error
1120  *
1121  *  Notes:
1122  *      (1) Use TIFFClose(); TIFFCleanup() doesn't free internal memstream.
1123  */
1124 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)1125 readHeaderMemTiff(const l_uint8  *cdata,
1126                   size_t          size,
1127                   l_int32         n,
1128                   l_int32        *pwidth,
1129                   l_int32        *pheight,
1130                   l_int32        *pbps,
1131                   l_int32        *pspp,
1132                   l_int32        *pres,
1133                   l_int32        *pcmap)
1134 {
1135 l_uint8  *data;
1136 l_int32   i, ret;
1137 TIFF     *tif;
1138 
1139     PROCNAME("readHeaderMemTiff");
1140 
1141     if (!cdata)
1142         return ERROR_INT("cdata not defined", procName, 1);
1143     if (!pwidth || !pheight || !pbps || !pspp)
1144         return ERROR_INT("input ptr(s) not all defined", procName, 1);
1145     *pwidth = *pheight = *pbps = *pspp = 0;
1146     if (pres) *pres = 0;
1147     if (pcmap) *pcmap = 0;
1148 
1149         /* Open a tiff stream to memory */
1150     data = (l_uint8 *)cdata;  /* we're really not going to change this */
1151     if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
1152         return ERROR_INT("tiff stream not opened", procName, 1);
1153 
1154     for (i = 0; i < n; i++) {
1155         if (TIFFReadDirectory(tif) == 0) {
1156             TIFFClose(tif);
1157             return ERROR_INT("image n not found in file", procName, 1);
1158         }
1159     }
1160 
1161     ret = tiffReadHeaderTiff(tif, pwidth, pheight, pbps, pspp, pres, pcmap);
1162 
1163     TIFFClose(tif);
1164     return ret;
1165 }
1166 
1167 
1168 /*!
1169  *  tiffReadHeaderTiff()
1170  *
1171  *      Input:  tif
1172  *              &width (<return>)
1173  *              &height (<return>)
1174  *              &bps (<return> bits per sample -- 1, 2, 4 or 8)
1175  *              &spp (<return>; samples per pixel -- 1 or 3)
1176  *              &res (<optional return>; resolution in x dir; NULL to ignore)
1177  *              &cmap (<optional return>; colormap exists; input NULL to ignore)
1178  *      Return: 0 if OK, 1 on error
1179  */
1180 static l_int32
tiffReadHeaderTiff(TIFF * tif,l_int32 * pwidth,l_int32 * pheight,l_int32 * pbps,l_int32 * pspp,l_int32 * pres,l_int32 * pcmap)1181 tiffReadHeaderTiff(TIFF     *tif,
1182                    l_int32  *pwidth,
1183                    l_int32  *pheight,
1184                    l_int32  *pbps,
1185                    l_int32  *pspp,
1186                    l_int32  *pres,
1187                    l_int32  *pcmap)
1188 {
1189 l_uint16   bps, spp;
1190 l_uint16  *rmap, *gmap, *bmap;
1191 l_uint32   w, h, xres, yres;
1192 
1193     PROCNAME("tiffReadHeaderTiff");
1194 
1195     if (!tif)
1196         return ERROR_INT("tif not opened", procName, 1);
1197 
1198     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
1199     *pwidth = w;
1200     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
1201     *pheight = h;
1202     TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
1203     *pbps = bps;
1204     TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
1205     *pspp = spp;
1206 
1207     if (pres) {
1208         *pres = 300;  /* default ppi */
1209         if (tiffGetResolution(tif, &xres, &yres))
1210             *pres = (l_int32)xres;
1211     }
1212 
1213     if (pcmap) {
1214         *pcmap = 0;
1215         if (TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap))
1216             *pcmap = 1;
1217     }
1218 
1219     return 0;
1220 }
1221 
1222 
1223 /*!
1224  *  findTiffCompression()
1225  *
1226  *      Input:  stream
1227  *              &comp (<return> compression type)
1228  *      Return: 0 if OK, 1 on error
1229  *
1230  *  Notes:
1231  *      (1) The returned compression type is that defined in
1232  *          the enum in imageio.h.  It is not the tiff flag value.
1233  *      (2) The compression type is initialized to IFF_UNKNOWN.
1234  *          If it is not one of the specified types, the returned
1235  *          type is IFF_TIFF, which indicates no compression.
1236  */
1237 l_int32
findTiffCompression(FILE * fp,l_int32 * pcomp)1238 findTiffCompression(FILE     *fp,
1239                     l_int32  *pcomp)
1240 {
1241 l_uint16  comp;
1242 TIFF     *tif;
1243 
1244     PROCNAME("findTiffCompression");
1245 
1246     if (!pcomp)
1247         return ERROR_INT("&comp not defined", procName, 1);
1248     *pcomp = IFF_UNKNOWN;  /* init */
1249     if (!fp)
1250         return ERROR_INT("stream not defined", procName, 1);
1251 
1252     if ((tif = fopenTiff(fp, "r")) == NULL)
1253         return ERROR_INT("tif not opened", procName, 1);
1254     TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &comp);
1255     switch (comp)
1256     {
1257     case COMPRESSION_CCITTFAX4:
1258         *pcomp = IFF_TIFF_G4;
1259         break;
1260     case COMPRESSION_CCITTFAX3:
1261         *pcomp = IFF_TIFF_G3;
1262         break;
1263     case COMPRESSION_CCITTRLE:
1264         *pcomp = IFF_TIFF_RLE;
1265         break;
1266     case COMPRESSION_PACKBITS:
1267         *pcomp = IFF_TIFF_PACKBITS;
1268         break;
1269     case COMPRESSION_LZW:
1270         *pcomp = IFF_TIFF_LZW;
1271         break;
1272     case COMPRESSION_ADOBE_DEFLATE:
1273         *pcomp = IFF_TIFF_ZIP;
1274         break;
1275     default:
1276         *pcomp = IFF_TIFF;
1277         break;
1278     }
1279 
1280     TIFFCleanup(tif);
1281     return 0;
1282 }
1283 
1284 
1285 /*--------------------------------------------------------------*
1286  *                   Extraction of tiff g4 data                 *
1287  *--------------------------------------------------------------*/
1288 /*!
1289  *  extractTiffG4DataFromFile()
1290  *
1291  *      Input:  filein
1292  *              &data (<return> binary data of ccitt g4 encoded stream)
1293  *              &nbytes (<return> size of binary data)
1294  *              &w (<return optional> image width)
1295  *              &h (<return optional> image height)
1296  *              &minisblack (<return optional> boolean)
1297  *      Return: 0 if OK, 1 on error
1298  */
1299 l_int32
extractTiffG4DataFromFile(const char * filein,l_uint8 ** pdata,l_int32 * pnbytes,l_int32 * pw,l_int32 * ph,l_int32 * pminisblack)1300 extractTiffG4DataFromFile(const char  *filein,
1301                           l_uint8    **pdata,
1302                           l_int32     *pnbytes,
1303                           l_int32     *pw,
1304                           l_int32     *ph,
1305                           l_int32     *pminisblack)
1306 {
1307 l_uint8  *inarray, *data;
1308 l_uint16  minisblack, comptype;  /* accessors require l_uint16 */
1309 l_int32   istiff, fbytes, nbytes;
1310 l_uint32  w, h, rowsperstrip;  /* accessors require l_uint32 */
1311 l_uint32  diroff;
1312 FILE     *fpin;
1313 TIFF     *tif;
1314 
1315     PROCNAME("extractTiffG4DataFromFile");
1316 
1317     if (!pdata)
1318         return ERROR_INT("&data not defined", procName, 1);
1319     if (!pnbytes)
1320         return ERROR_INT("&nbytes not defined", procName, 1);
1321     if (!pw && !ph && !pminisblack)
1322         return ERROR_INT("no output data requested", procName, 1);
1323     *pdata = NULL;
1324     *pnbytes = 0;
1325 
1326     if ((fpin = fopen(filein, "r")) == NULL)
1327         return ERROR_INT("filein not defined", procName, 1);
1328     istiff = fileFormatIsTiff(fpin);
1329     fclose(fpin);
1330     if (!istiff)
1331         return ERROR_INT("filein not tiff", procName, 1);
1332 
1333     if ((inarray = arrayRead(filein, &fbytes)) == NULL)
1334         return ERROR_INT("inarray not made", procName, 1);
1335 
1336         /* Get metadata about the image */
1337     if ((tif = TIFFOpen(filein, "r")) == NULL)
1338         return ERROR_INT("tif not open for read", procName, 1);
1339     TIFFGetField(tif, TIFFTAG_COMPRESSION, &comptype);
1340     if (comptype != COMPRESSION_CCITTFAX4) {
1341         FREE(inarray);
1342         TIFFClose(tif);
1343         return ERROR_INT("filein is not g4 compressed", procName, 1);
1344     }
1345 
1346     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
1347     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
1348     TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
1349     if (h != rowsperstrip)
1350         L_WARNING("more than 1 strip", procName);
1351     TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &minisblack);  /* for 1 bpp */
1352 /*    TIFFPrintDirectory(tif, stderr, 0); */
1353     TIFFClose(tif);
1354     if (pw) *pw = (l_int32)w;
1355     if (ph) *ph = (l_int32)h;
1356     if (pminisblack) *pminisblack = (l_int32)minisblack;
1357 
1358         /* The header has 8 bytes: the first 2 are the magic number,
1359          * the next 2 are the version, and the last 4 are the
1360          * offset to the first directory.  That's what we want here.
1361          * We have to test the byte order before decoding 4 bytes! */
1362     if (inarray[0] == 0x4d) {  /* big-endian */
1363         diroff = (inarray[4] << 24) | (inarray[5] << 16) |
1364                  (inarray[6] << 8) | inarray[7];
1365     }
1366     else  {   /* inarray[0] == 0x49 :  little-endian */
1367         diroff = (inarray[7] << 24) | (inarray[6] << 16) |
1368                  (inarray[5] << 8) | inarray[4];
1369     }
1370 /*    fprintf(stderr, " diroff = %d, %x\n", diroff, diroff); */
1371 
1372         /* Extract the ccittg4 encoded data from the tiff file.
1373          * We skip the 8 byte header and take nbytes of data,
1374          * up to the beginning of the directory (at diroff)  */
1375     nbytes = diroff - 8;
1376     *pnbytes = nbytes;
1377     if ((data = (l_uint8 *)CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
1378         FREE(inarray);
1379         return ERROR_INT("data not allocated", procName, 1);
1380     }
1381     *pdata = data;
1382     memcpy(data, inarray + 8, nbytes);
1383     FREE(inarray);
1384 
1385     return 0;
1386 }
1387 
1388 
1389 /*--------------------------------------------------------------*
1390  *               Open tiff stream from file stream              *
1391  *--------------------------------------------------------------*/
1392 /*!
1393  *  fopenTiff()
1394  *
1395  *      Input:  stream
1396  *              modestring ("r", "w", ...)
1397  *      Return: tiff (data structure, opened for a file descriptor)
1398  *
1399  *  Notes:
1400  *      (1) Why is this here?  Leffler did not provide a function that
1401  *          takes a stream and gives a TIFF.  He only gave one that
1402  *          generates a TIFF starting with a file descriptor.  So we
1403  *          need to make it here, because it is useful to have functions
1404  *          that take a stream as input.
1405  *      (2) Requires lseek to rewind to BOF; fseek won't hack it.
1406  *      (3) When linking with windows, suggest you use tif_unix.c
1407  *          instead of tif_win32.c, because it has been reported that
1408  *          the file descriptor returned from fileno() does not work
1409  *          with TIFFFdOpen() in tif_win32.c.  (win32 requires a
1410  *          "handle", which is an integer returned by _get_osfhandle(fd).)
1411  */
1412 static TIFF *
fopenTiff(FILE * fp,const char * modestring)1413 fopenTiff(FILE        *fp,
1414           const char  *modestring)
1415 {
1416 l_int32  fd;
1417 
1418     PROCNAME("fopenTiff");
1419 
1420     if (!fp)
1421         return (TIFF *)ERROR_PTR("stream not opened", procName, NULL);
1422     if (!modestring)
1423         return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
1424 
1425     if ((fd = fileno(fp)) < 0)
1426         return (TIFF *)ERROR_PTR("invalid file descriptor", procName, NULL);
1427     lseek(fd, 0, SEEK_SET);
1428 
1429     return TIFFFdOpen(fd, "TIFFstream", modestring);
1430 }
1431 
1432 
1433 /*----------------------------------------------------------------------*
1434  *     Memory I/O: reading memory --> pix and writing pix --> memory    *
1435  *----------------------------------------------------------------------*/
1436 /*  It would be nice to use open_memstream() and fmemopen()
1437  *  for writing and reading to memory, rsp.  These functions manage
1438  *  memory for writes and reads that use a file streams interface.
1439  *  Unfortunately, the tiff library only has an interface for reading
1440  *  and writing to file descriptors, not to file streams.  The tiff
1441  *  library procedure is to open a "tiff stream" and read/write to it.
1442  *  The library provides a client interface for managing the I/O
1443  *  from memory, which requires seven callbacks.  See the TIFFClientOpen
1444  *  man page for callback signatures.  Adam Langley provided the code
1445  *  to do this.  */
1446 
1447 /*
1448  *  The L_Memstram @buffer has different functions in writing and reading.
1449  *
1450  *     * In reading, it is assigned to the data and read from as
1451  *       the tiff library uncompresses the data and generates the pix.
1452  *       The @offset points to the current read position in the data,
1453  *       and the @hw always gives the number of bytes of data.
1454  *       The @outdata and @outsize ptrs are not used.
1455  *       When finished, tiffCloseCallback() simply frees the L_Memstream.
1456  *
1457  *     * In writing, it accepts the data that the tiff library
1458  *       produces when a pix is compressed.  the buffer points to a
1459  *       malloced area of @bufsize bytes.  The current writing position
1460  *       in the buffer is @offset and the most ever written is @hw.
1461  *       The buffer is expanded as necessary.  When finished,
1462  *       tiffCloseCallback() assigns the @outdata and @outsize ptrs
1463  *       to the @buffer and @bufsize results, and frees the L_Memstream.
1464  */
1465 struct L_Memstream
1466 {
1467     l_uint8   *buffer;    /* expands to hold data when written to;         */
1468                           /* fixed size when read from.                    */
1469     size_t     bufsize;   /* current size allocated when written to;       */
1470                           /* fixed size of input data when read from.      */
1471     size_t     offset;    /* byte offset from beginning of buffer.         */
1472     size_t     hw;        /* high-water mark; max bytes in buffer.         */
1473     l_uint8  **poutdata;  /* input param for writing; data goes here.      */
1474     size_t    *poutsize;  /* input param for writing; data size goes here. */
1475 };
1476 typedef struct L_Memstream  L_MEMSTREAM;
1477 
1478 
1479     /* These are static functions for memory I/O */
1480 static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);
1481 static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
1482                                             size_t *poutsize);
1483 static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);
1484 static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
1485                                  tsize_t length);
1486 static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);
1487 static l_int32 tiffCloseCallback(thandle_t handle);
1488 static toff_t tiffSizeCallback(thandle_t handle);
1489 static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);
1490 static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);
1491 
1492 
1493 static L_MEMSTREAM *
memstreamCreateForRead(l_uint8 * indata,size_t insize)1494 memstreamCreateForRead(l_uint8  *indata,
1495                        size_t    insize)
1496 {
1497 L_MEMSTREAM  *mstream;
1498 
1499     mstream = (L_MEMSTREAM *)CALLOC(1, sizeof(L_MEMSTREAM));
1500     mstream->buffer = indata;   /* handle to input data array */
1501     mstream->bufsize = insize;  /* amount of input data */
1502     mstream->hw = insize;       /* high-water mark fixed at input data size */
1503     mstream->offset = 0;        /* offset always starts at 0 */
1504     return mstream;
1505 }
1506 
1507 
1508 static L_MEMSTREAM *
memstreamCreateForWrite(l_uint8 ** poutdata,size_t * poutsize)1509 memstreamCreateForWrite(l_uint8  **poutdata,
1510                         size_t    *poutsize)
1511 {
1512 L_MEMSTREAM  *mstream;
1513 
1514     mstream = (L_MEMSTREAM *)CALLOC(1, sizeof(L_MEMSTREAM));
1515     mstream->buffer = (l_uint8 *)CALLOC(8 * 1024, 1);
1516     mstream->bufsize = 8 * 1024;
1517     mstream->poutdata = poutdata;  /* used only at end of write */
1518     mstream->poutsize = poutsize;  /* ditto  */
1519     mstream->hw = mstream->offset = 0;
1520     return mstream;
1521 }
1522 
1523 
1524 static tsize_t
tiffReadCallback(thandle_t handle,tdata_t data,tsize_t length)1525 tiffReadCallback(thandle_t  handle,
1526                  tdata_t    data,
1527                  tsize_t    length)
1528 {
1529 L_MEMSTREAM  *mstream;
1530 size_t        amount;
1531 
1532     mstream = (L_MEMSTREAM *)handle;
1533     amount = L_MIN((size_t)length, mstream->hw - mstream->offset);
1534     memcpy(data, mstream->buffer + mstream->offset, amount);
1535     mstream->offset += amount;
1536     return amount;
1537 }
1538 
1539 
1540 static tsize_t
tiffWriteCallback(thandle_t handle,tdata_t data,tsize_t length)1541 tiffWriteCallback(thandle_t  handle,
1542                   tdata_t    data,
1543                   tsize_t    length)
1544 {
1545 L_MEMSTREAM  *mstream;
1546 size_t        newsize;
1547 
1548         /* reallocNew() uses calloc to initialize the array.
1549          * If malloc is used instead, for some of the encoding methods,
1550          * not all the data in 'bufsize' bytes in the buffer will
1551          * have been initialized by the end of the compression. */
1552     mstream = (L_MEMSTREAM *)handle;
1553     if (mstream->offset + length > mstream->bufsize) {
1554         newsize = 2 * (mstream->offset + length);
1555         mstream->buffer = (l_uint8 *)reallocNew((void **)&mstream->buffer,
1556                                                 mstream->offset, newsize);
1557         mstream->bufsize = newsize;
1558     }
1559 
1560     memcpy(mstream->buffer + mstream->offset, data, length);
1561     mstream->offset += length;
1562     mstream->hw = L_MAX(mstream->offset, mstream->hw);
1563     return length;
1564 }
1565 
1566 
1567 static toff_t
tiffSeekCallback(thandle_t handle,toff_t offset,l_int32 whence)1568 tiffSeekCallback(thandle_t  handle,
1569                  toff_t     offset,
1570                  l_int32    whence)
1571 {
1572 L_MEMSTREAM  *mstream;
1573 
1574     PROCNAME("tiffSeekCallback");
1575     mstream = (L_MEMSTREAM *)handle;
1576     switch (whence) {
1577         case SEEK_SET:
1578 /*            fprintf(stderr, "seek_set: offset = %d\n", offset); */
1579             mstream->offset = offset;
1580             break;
1581         case SEEK_CUR:
1582 /*            fprintf(stderr, "seek_cur: offset = %d\n", offset); */
1583             mstream->offset += offset;
1584             break;
1585         case SEEK_END:
1586 /*            fprintf(stderr, "seek end: hw = %d, offset = %d\n",
1587                     mstream->hw, offset); */
1588             mstream->offset = mstream->hw - offset;  /* offset >= 0 */
1589             break;
1590         default:
1591             return (toff_t)ERROR_INT("bad whence value", procName,
1592                                      mstream->offset);
1593     }
1594 
1595     return mstream->offset;
1596 }
1597 
1598 
1599 static l_int32
tiffCloseCallback(thandle_t handle)1600 tiffCloseCallback(thandle_t  handle)
1601 {
1602 L_MEMSTREAM  *mstream;
1603 
1604     mstream = (L_MEMSTREAM *)handle;
1605     if (mstream->poutdata) {   /* writing: save the output data */
1606         *mstream->poutdata = mstream->buffer;
1607         *mstream->poutsize = mstream->hw;
1608     }
1609     FREE(mstream);  /* never free the buffer! */
1610     return 0;
1611 }
1612 
1613 
1614 static toff_t
tiffSizeCallback(thandle_t handle)1615 tiffSizeCallback(thandle_t  handle)
1616 {
1617 L_MEMSTREAM  *mstream;
1618 
1619     mstream = (L_MEMSTREAM *)handle;
1620     return mstream->hw;
1621 }
1622 
1623 
1624 static l_int32
tiffMapCallback(thandle_t handle,tdata_t * data,toff_t * length)1625 tiffMapCallback(thandle_t  handle,
1626                 tdata_t   *data,
1627                 toff_t    *length)
1628 {
1629 L_MEMSTREAM  *mstream;
1630 
1631     mstream = (L_MEMSTREAM *)handle;
1632     *data = mstream->buffer;
1633     *length = mstream->hw;
1634     return 0;
1635 }
1636 
1637 
1638 static void
tiffUnmapCallback(thandle_t handle,tdata_t data,toff_t length)1639 tiffUnmapCallback(thandle_t  handle,
1640                   tdata_t    data,
1641                   toff_t     length)
1642 {
1643     return;
1644 }
1645 
1646 
1647 /*!
1648  *  fopenTiffMemstream()
1649  *
1650  *      Input:  filename (for error output; can be "")
1651  *              operation ("w" for write, "r" for read)
1652  *              &data (<return> written data)
1653  *              &datasize (<return> size of written data)
1654  *      Return: tiff (data structure, opened for write to memory)
1655  *
1656  *  Notes:
1657  *      (1) This wraps up a number of callbacks for either:
1658  *            * reading from tiff in memory buffer --> pix
1659  *            * writing from pix --> tiff in memory buffer
1660  *      (2) After use, the memstream is automatically destroyed when
1661  *          TIFFClose() is called.  TIFFCleanup() doesn't free the memstream.
1662  */
1663 static TIFF *
fopenTiffMemstream(const char * filename,const char * operation,l_uint8 ** pdata,size_t * pdatasize)1664 fopenTiffMemstream(const char  *filename,
1665                    const char  *operation,
1666                    l_uint8    **pdata,
1667                    size_t      *pdatasize)
1668 {
1669 L_MEMSTREAM  *mstream;
1670 
1671     PROCNAME("fopenTiffMemstream");
1672 
1673     if (!filename)
1674         return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
1675     if (!operation)
1676         return (TIFF *)ERROR_PTR("operation not defined", procName, NULL);
1677     if (!pdata)
1678         return (TIFF *)ERROR_PTR("&data not defined", procName, NULL);
1679     if (!pdatasize)
1680         return (TIFF *)ERROR_PTR("&datasize not defined", procName, NULL);
1681     if (!strcmp(operation, "r") && !strcmp(operation, "w"))
1682         return (TIFF *)ERROR_PTR("operation not 'r' or 'w'}", procName, NULL);
1683 
1684     if (!strcmp(operation, "r"))
1685         mstream = memstreamCreateForRead(*pdata, *pdatasize);
1686     else
1687         mstream = memstreamCreateForWrite(pdata, pdatasize);
1688 
1689     return TIFFClientOpen(filename, operation, mstream,
1690                           tiffReadCallback, tiffWriteCallback,
1691                           tiffSeekCallback, tiffCloseCallback,
1692                           tiffSizeCallback, tiffMapCallback,
1693                           tiffUnmapCallback);
1694 }
1695 
1696 
1697 /*!
1698  *  pixReadMemTiff()
1699  *
1700  *      Input:  data (const; tiff-encoded)
1701  *              datasize (size of data)
1702  *              n (page image number: 0-based)
1703  *      Return: pix, or null on error
1704  *
1705  *  Notes:
1706  *      (1) This is a version of pixReadTiff(), where the data is read
1707  *          from a memory buffer and uncompressed.
1708  *      (2) Use TIFFClose(); TIFFCleanup() doesn't free internal memstream.
1709  */
1710 PIX *
pixReadMemTiff(const l_uint8 * cdata,size_t size,l_int32 n)1711 pixReadMemTiff(const l_uint8  *cdata,
1712                size_t          size,
1713                l_int32         n)
1714 {
1715 l_uint8  *data;
1716 l_int32   i, pagefound;
1717 PIX      *pix;
1718 TIFF     *tif;
1719 
1720     PROCNAME("pixReadMemTiff");
1721 
1722     if (!cdata)
1723         return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
1724 
1725     data = (l_uint8 *)cdata;  /* we're really not going to change this */
1726     if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
1727         return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
1728 
1729     pagefound = FALSE;
1730     pix = NULL;
1731     for (i = 0; i < MAX_PAGES_IN_TIFF_FILE; i++) {
1732         if (i == n) {
1733             pagefound = TRUE;
1734             if ((pix = pixReadFromTiffStream(tif)) == NULL) {
1735                 TIFFClose(tif);
1736                 return (PIX *)ERROR_PTR("pix not read", procName, NULL);
1737             }
1738             pixSetInputFormat(pix, IFF_TIFF);
1739             break;
1740         }
1741         if (TIFFReadDirectory(tif) == 0)
1742             break;
1743     }
1744 
1745     if (pagefound == FALSE)
1746         L_WARNING_INT("tiff page %d not found", procName, n);
1747 
1748     TIFFClose(tif);
1749     return pix;
1750 }
1751 
1752 
1753 /*!
1754  *  pixWriteMemTiff()
1755  *
1756  *      Input:  &data (<return> data of tiff compressed image)
1757  *              &size (<return> size of returned data)
1758  *              pix
1759  *              comptype (IFF_TIFF, IFF_TIFF_RLE, IFF_TIFF_PACKBITS,
1760  *                        IFF_TIFF_G3, IFF_TIFF_G4,
1761  *                        IFF_TIFF_LZW, IFF_TIFF_ZIP)
1762  *      Return: 0 if OK, 1 on error
1763  *
1764  *  Usage:
1765  *      (1) See pixWriteTiff().  This version writes to
1766  *          memory instead of to a file.
1767  */
1768 l_int32
pixWriteMemTiff(l_uint8 ** pdata,size_t * psize,PIX * pix,l_int32 comptype)1769 pixWriteMemTiff(l_uint8  **pdata,
1770                 size_t    *psize,
1771                 PIX       *pix,
1772                 l_int32    comptype)
1773 {
1774     return pixWriteMemTiffCustom(pdata, psize, pix, comptype,
1775                                  NULL, NULL, NULL, NULL);
1776 }
1777 
1778 
1779 /*!
1780  *  pixWriteMemTiffCustom()
1781  *
1782  *      Input:  &data (<return> data of tiff compressed image)
1783  *              &size (<return> size of returned data)
1784  *              pix
1785  *              comptype (IFF_TIFF, IFF_TIFF_RLE, IFF_TIFF_PACKBITS,
1786  *                        IFF_TIFF_G3, IFF_TIFF_G4,
1787  *                        IFF_TIFF_LZW, IFF_TIFF_ZIP)
1788  *              natags (<optional> NUMA of custom tiff tags)
1789  *              savals (<optional> SARRAY of values)
1790  *              satypes (<optional> SARRAY of types)
1791  *              nasizes (<optional> NUMA of sizes)
1792  *      Return: 0 if OK, 1 on error
1793  *
1794  *  Usage:
1795  *      (1) See pixWriteTiffCustom().  This version writes to
1796  *          memory instead of to a file.
1797  *      (2) Use TIFFClose(); TIFFCleanup() doesn't free internal memstream.
1798  */
1799 l_int32
pixWriteMemTiffCustom(l_uint8 ** pdata,size_t * psize,PIX * pix,l_int32 comptype,NUMA * natags,SARRAY * savals,SARRAY * satypes,NUMA * nasizes)1800 pixWriteMemTiffCustom(l_uint8  **pdata,
1801                       size_t    *psize,
1802                       PIX       *pix,
1803                       l_int32    comptype,
1804                       NUMA      *natags,
1805                       SARRAY    *savals,
1806                       SARRAY    *satypes,
1807                       NUMA      *nasizes)
1808 {
1809 l_int32  ret;
1810 TIFF    *tif;
1811 
1812     PROCNAME("pixWriteMemTiffCustom");
1813 
1814     if (!pdata)
1815         return ERROR_INT("&data not defined", procName, 1);
1816     if (!psize)
1817         return ERROR_INT("&size not defined", procName, 1);
1818     if (!pix)
1819         return ERROR_INT("&pix not defined", procName, 1);
1820     if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
1821         comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP) {
1822         L_WARNING("invalid compression type for image with bpp > 1", procName);
1823         comptype = IFF_TIFF;
1824     }
1825 
1826     if ((tif = fopenTiffMemstream("tifferror", "w", pdata, psize)) == NULL)
1827         return ERROR_INT("tiff stream not opened", procName, 1);
1828     ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
1829                                satypes, nasizes);
1830 
1831     TIFFClose(tif);
1832     return ret;
1833 }
1834 
1835 /* --------------------------------------------*/
1836 #endif  /* HAVE_LIBTIFF */
1837 /* --------------------------------------------*/
1838 
1839