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