Leptonica 1.82.0
Image processing and image analysis suite
tiffio.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
107#ifdef HAVE_CONFIG_H
108#include <config_auto.h>
109#endif /* HAVE_CONFIG_H */
110
111#include <string.h>
112#include <math.h> /* for isnan */
113#include <sys/types.h>
114#ifndef _MSC_VER
115#include <unistd.h>
116#else /* _MSC_VER */
117#include <io.h>
118#endif /* _MSC_VER */
119#include <fcntl.h>
120#include "allheaders.h"
121
122/* --------------------------------------------*/
123#if HAVE_LIBTIFF /* defined in environ.h */
124/* --------------------------------------------*/
125
126#include "tiff.h"
127#include "tiffio.h"
128
129static const l_int32 DefaultResolution = 300; /* ppi */
130static const l_int32 ManyPagesInTiffFile = 3000; /* warn if big */
131
132 /* Verified that tiflib makes valid g4 files of this size */
133static const l_int32 MaxTiffWidth = 1 << 20; /* 1M pixels */
134static const l_int32 MaxTiffHeight = 1 << 20; /* 1M pixels */
135
136 /* Check g4 data size */
137static const size_t MaxNumTiffBytes = (1 << 28) - 1; /* 256 MB */
138
139 /* All functions with TIFF interfaces are static. */
140static PIX *pixReadFromTiffStream(TIFF *tif);
141static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
142 l_int32 *pyres);
143static l_int32 tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
144 l_int32 *pheight, l_int32 *pbps,
145 l_int32 *pspp, l_int32 *pres,
146 l_int32 *pcmap, l_int32 *pformat);
147static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags,
148 SARRAY *savals, SARRAY *satypes,
149 NUMA *nasizes);
150static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
151 NUMA *natags, SARRAY *savals,
152 SARRAY *satypes, NUMA *nasizes);
153static TIFF *fopenTiff(FILE *fp, const char *modestring);
154static TIFF *openTiff(const char *filename, const char *modestring);
155
156 /* Static helper for tiff compression type */
157static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp);
158
159 /* Static function for memory I/O */
160static TIFF *fopenTiffMemstream(const char *filename, const char *operation,
161 l_uint8 **pdata, size_t *pdatasize);
162
163 /* This structure defines a transform to be performed on a TIFF image
164 * (note that the same transformation can be represented in
165 * several different ways using this structure since
166 * vflip + hflip + counterclockwise == clockwise). */
168 int vflip; /* if non-zero, image needs a vertical fip */
169 int hflip; /* if non-zero, image needs a horizontal flip */
170 int rotate; /* -1 -> counterclockwise 90-degree rotation,
171 0 -> no rotation
172 1 -> clockwise 90-degree rotation */
173};
174
175 /* This describes the transformations needed for a given orientation
176 * tag. The tag values start at 1, so you need to subtract 1 to get a
177 * valid index into this array. It is only valid when not using
178 * TIFFReadRGBAImageOriented(). */
179static struct tiff_transform tiff_orientation_transforms[] = {
180 {0, 0, 0},
181 {0, 1, 0},
182 {1, 1, 0},
183 {1, 0, 0},
184 {0, 1, -1},
185 {0, 0, 1},
186 {0, 1, 1},
187 {0, 0, -1}
188};
189
190 /* Same as above, except that test transformations are only valid
191 * when using TIFFReadRGBAImageOriented(). Transformations
192 * were determined empirically. See the libtiff mailing list for
193 * more discussion: http://www.asmail.be/msg0054683875.html */
194static struct tiff_transform tiff_partial_orientation_transforms[] = {
195 {0, 0, 0},
196 {0, 0, 0},
197 {0, 0, 0},
198 {0, 0, 0},
199 {0, 1, -1},
200 {0, 1, 1},
201 {1, 0, 1},
202 {0, 1, -1}
203};
204
205
206/*-----------------------------------------------------------------------*
207 * TIFFClientOpen() wrappers for FILE* *
208 * Provided by Jürgen Buchmüller *
209 * *
210 * We previously used TIFFFdOpen(), which used low-level file *
211 * descriptors. It had portability issues with Windows, along *
212 * with other limitations from lack of stream control operations. *
213 * These callbacks to TIFFClientOpen() avoid the problems. *
214 * *
215 * Jürgen made the functions use 64 bit file operations where possible *
216 * or required, namely for seek and size. On Windows there are specific *
217 * _fseeki64() and _ftelli64() functions. On unix it is common to look *
218 * for a macro _LARGEFILE64_SOURCE being defined, which makes available *
219 * the off64_t type, and to use fseeko() and ftello() in this case. *
220 *-----------------------------------------------------------------------*/
221static tsize_t
222lept_read_proc(thandle_t cookie,
223 tdata_t buff,
224 tsize_t size)
225{
226 FILE* fp = (FILE *)cookie;
227 tsize_t done;
228 if (!buff || !cookie || !fp)
229 return (tsize_t)-1;
230 done = fread(buff, 1, size, fp);
231 return done;
232}
233
234static tsize_t
235lept_write_proc(thandle_t cookie,
236 tdata_t buff,
237 tsize_t size)
238{
239 FILE* fp = (FILE *)cookie;
240 tsize_t done;
241 if (!buff || !cookie || !fp)
242 return (tsize_t)-1;
243 done = fwrite(buff, 1, size, fp);
244 return done;
245}
246
247static toff_t
248lept_seek_proc(thandle_t cookie,
249 toff_t offs,
250 int whence)
251{
252 FILE* fp = (FILE *)cookie;
253#if defined(_MSC_VER)
254 __int64 pos = 0;
255 if (!cookie || !fp)
256 return (tsize_t)-1;
257 switch (whence) {
258 case SEEK_SET:
259 pos = 0;
260 break;
261 case SEEK_CUR:
262 pos = ftell(fp);
263 break;
264 case SEEK_END:
265 _fseeki64(fp, 0, SEEK_END);
266 pos = _ftelli64(fp);
267 break;
268 }
269 pos = (__int64)(pos + offs);
270 _fseeki64(fp, pos, SEEK_SET);
271 if (pos == _ftelli64(fp))
272 return (tsize_t)pos;
273#elif defined(_LARGEFILE64_SOURCE)
274 off64_t pos = 0;
275 if (!cookie || !fp)
276 return (tsize_t)-1;
277 switch (whence) {
278 case SEEK_SET:
279 pos = 0;
280 break;
281 case SEEK_CUR:
282 pos = ftello(fp);
283 break;
284 case SEEK_END:
285 fseeko(fp, 0, SEEK_END);
286 pos = ftello(fp);
287 break;
288 }
289 pos = (off64_t)(pos + offs);
290 fseeko(fp, pos, SEEK_SET);
291 if (pos == ftello(fp))
292 return (tsize_t)pos;
293#else
294 off_t pos = 0;
295 if (!cookie || !fp)
296 return (tsize_t)-1;
297 switch (whence) {
298 case SEEK_SET:
299 pos = 0;
300 break;
301 case SEEK_CUR:
302 pos = ftell(fp);
303 break;
304 case SEEK_END:
305 fseek(fp, 0, SEEK_END);
306 pos = ftell(fp);
307 break;
308 }
309 pos = (off_t)(pos + offs);
310 fseek(fp, pos, SEEK_SET);
311 if (pos == ftell(fp))
312 return (tsize_t)pos;
313#endif
314 return (tsize_t)-1;
315}
316
317static int
318lept_close_proc(thandle_t cookie)
319{
320 FILE* fp = (FILE *)cookie;
321 if (!cookie || !fp)
322 return 0;
323 fseek(fp, 0, SEEK_SET);
324 return 0;
325}
326
327static toff_t
328lept_size_proc(thandle_t cookie)
329{
330 FILE* fp = (FILE *)cookie;
331#if defined(_MSC_VER)
332 __int64 pos;
333 __int64 size;
334 if (!cookie || !fp)
335 return (tsize_t)-1;
336 pos = _ftelli64(fp);
337 _fseeki64(fp, 0, SEEK_END);
338 size = _ftelli64(fp);
339 _fseeki64(fp, pos, SEEK_SET);
340#elif defined(_LARGEFILE64_SOURCE)
341 off64_t pos;
342 off64_t size;
343 if (!fp)
344 return (tsize_t)-1;
345 pos = ftello(fp);
346 fseeko(fp, 0, SEEK_END);
347 size = ftello(fp);
348 fseeko(fp, pos, SEEK_SET);
349#else
350 off_t pos;
351 off_t size;
352 if (!cookie || !fp)
353 return (tsize_t)-1;
354 pos = ftell(fp);
355 fseek(fp, 0, SEEK_END);
356 size = ftell(fp);
357 fseek(fp, pos, SEEK_SET);
358#endif
359 return (toff_t)size;
360}
361
362
363/*--------------------------------------------------------------*
364 * Reading from file *
365 *--------------------------------------------------------------*/
382PIX *
383pixReadTiff(const char *filename,
384 l_int32 n)
385{
386FILE *fp;
387PIX *pix;
388
389 PROCNAME("pixReadTiff");
390
391 if (!filename)
392 return (PIX *)ERROR_PTR("filename not defined", procName, NULL);
393
394 if ((fp = fopenReadStream(filename)) == NULL)
395 return (PIX *)ERROR_PTR("image file not found", procName, NULL);
396 pix = pixReadStreamTiff(fp, n);
397 fclose(fp);
398 return pix;
399}
400
401
402/*--------------------------------------------------------------*
403 * Reading from stream *
404 *--------------------------------------------------------------*/
419PIX *
421 l_int32 n)
422{
423PIX *pix;
424TIFF *tif;
425
426 PROCNAME("pixReadStreamTiff");
427
428 if (!fp)
429 return (PIX *)ERROR_PTR("stream not defined", procName, NULL);
430
431 if ((tif = fopenTiff(fp, "r")) == NULL)
432 return (PIX *)ERROR_PTR("tif not opened", procName, NULL);
433
434 if (TIFFSetDirectory(tif, n) == 0) {
435 TIFFCleanup(tif);
436 return NULL;
437 }
438 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
439 TIFFCleanup(tif);
440 return NULL;
441 }
442 TIFFCleanup(tif);
443 return pix;
444}
445
446
484static PIX *
486{
487char *text;
488l_uint8 *linebuf, *data, *rowptr;
489l_uint16 spp, bps, photometry, tiffcomp, orientation, sample_fmt;
490l_uint16 *redmap, *greenmap, *bluemap;
491l_int32 d, wpl, bpl, comptype, i, j, k, ncolors, rval, gval, bval, aval;
492l_int32 xres, yres, tiffbpl, packedbpl, half_size, twothirds_size;
493l_uint32 w, h, tiffword, read_oriented;
494l_uint32 *line, *ppixel, *tiffdata, *pixdata;
495PIX *pix, *pix1;
496PIXCMAP *cmap;
497
498 PROCNAME("pixReadFromTiffStream");
499
500 if (!tif)
501 return (PIX *)ERROR_PTR("tif not defined", procName, NULL);
502
503 read_oriented = 0;
504
505 /* Only accept uint image data:
506 * SAMPLEFORMAT_UINT = 1;
507 * SAMPLEFORMAT_INT = 2;
508 * SAMPLEFORMAT_IEEEFP = 3;
509 * SAMPLEFORMAT_VOID = 4; */
510 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_fmt);
511 if (sample_fmt != SAMPLEFORMAT_UINT) {
512 L_ERROR("sample format = %d is not uint\n", procName, sample_fmt);
513 return NULL;
514 }
515
516 /* Can't read tiff in tiled format. For what is involved, see, e.g:
517 * https://www.cs.rochester.edu/~nelson/courses/vision/\
518 * resources/tiff/libtiff.html#Tiles
519 * A tiled tiff can be converted to a normal (strip) tif:
520 * tiffcp -s <input-tiled-tif> <output-strip-tif> */
521 if (TIFFIsTiled(tif)) {
522 L_ERROR("tiled format is not supported\n", procName);
523 return NULL;
524 }
525
526 /* Old style jpeg is not supported. We tried supporting 8 bpp.
527 * TIFFReadScanline() fails on this format, so we used RGBA
528 * reading, which generates a 4 spp image, and pulled out the
529 * red component. However, there were problems with double-frees
530 * in cleanup. For RGB, tiffbpl is exactly half the size that
531 * you would expect for the raster data in a scanline, which
532 * is 3 * w. */
533 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
534 if (tiffcomp == COMPRESSION_OJPEG) {
535 L_ERROR("old style jpeg format is not supported\n", procName);
536 return NULL;
537 }
538
539 /* webp in tiff is in 4.1.0 and not yet supported in Adobe registry */
540#if defined(COMPRESSION_WEBP)
541 if (tiffcomp == COMPRESSION_WEBP) {
542 L_ERROR("webp in tiff not generally supported yet\n", procName);
543 return NULL;
544 }
545#endif /* COMPRESSION_WEBP */
546
547 /* Use default fields for bps and spp */
548 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
549 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
550 if (bps != 1 && bps != 2 && bps != 4 && bps != 8 && bps != 16) {
551 L_ERROR("invalid bps = %d\n", procName, bps);
552 return NULL;
553 }
554 if (spp == 2 && bps != 8) {
555 L_WARNING("for 2 spp, only handle 8 bps\n", procName);
556 return NULL;
557 }
558 if (spp == 1) {
559 d = bps;
560 } else if (spp == 2) { /* gray plus alpha */
561 d = 32; /* will convert to RGBA */
562 } else if (spp == 3 || spp == 4) {
563 d = 32;
564 } else {
565 L_ERROR("spp = %d; not in {1,2,3,4}\n", procName, spp);
566 return NULL;
567 }
568
569 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
570 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
571 if (w > MaxTiffWidth) {
572 L_ERROR("width = %d pixels; too large\n", procName, w);
573 return NULL;
574 }
575 if (h > MaxTiffHeight) {
576 L_ERROR("height = %d pixels; too large\n", procName, h);
577 return NULL;
578 }
579
580 /* The relation between the size of a byte buffer required to hold
581 a raster of image pixels (packedbpl) and the size of the tiff
582 buffer (tiffbuf) is either 1:1 or approximately 1.5:1 or 2:1,
583 depending on how the data is stored and subsampled. For security,
584 we test this relation between tiffbuf and the image parameters
585 w, spp and bps. */
586 tiffbpl = TIFFScanlineSize(tif);
587 packedbpl = (bps * spp * w + 7) / 8;
588 half_size = (L_ABS(2 * tiffbpl - packedbpl) <= 8);
589 twothirds_size = (L_ABS(3 * tiffbpl - 2 * packedbpl) <= 8);
590#if 0
591 if (half_size)
592 L_INFO("half_size: packedbpl = %d is approx. twice tiffbpl = %d\n",
593 procName, packedbpl, tiffbpl);
594 if (twothirds_size)
595 L_INFO("twothirds_size: packedbpl = %d is approx. 1.5 tiffbpl = %d\n",
596 procName, packedbpl, tiffbpl);
597 lept_stderr("tiffbpl = %d, packedbpl = %d, bps = %d, spp = %d, w = %d\n",
598 tiffbpl, packedbpl, bps, spp, w);
599#endif
600 if (tiffbpl != packedbpl && !half_size && !twothirds_size) {
601 L_ERROR("invalid tiffbpl: tiffbpl = %d, packedbpl = %d, "
602 "bps = %d, spp = %d, w = %d\n",
603 procName, tiffbpl, packedbpl, bps, spp, w);
604 return NULL;
605 }
606
607 /* Use a linebuf that will hold all the pixels generated
608 by tiff when reading (decompressing) a scanline. */
609 if ((pix = pixCreate(w, h, d)) == NULL)
610 return (PIX *)ERROR_PTR("pix not made", procName, NULL);
611 pixSetInputFormat(pix, IFF_TIFF);
612 data = (l_uint8 *)pixGetData(pix);
613 wpl = pixGetWpl(pix);
614 bpl = 4 * wpl;
615 if (spp == 1) {
616 linebuf = (l_uint8 *)LEPT_CALLOC(4 * wpl, sizeof(l_uint8));
617 for (i = 0; i < h; i++) {
618 if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
619 LEPT_FREE(linebuf);
620 pixDestroy(&pix);
621 L_ERROR("spp = 1, read fail at line %d\n", procName, i);
622 return NULL;
623 }
624 memcpy(data, linebuf, tiffbpl);
625 data += bpl;
626 }
627 if (bps <= 8)
629 else /* bps == 16 */
631 LEPT_FREE(linebuf);
632 } else if (spp == 2 && bps == 8) { /* gray plus alpha */
633 L_INFO("gray+alpha is not supported; converting to RGBA\n", procName);
634 pixSetSpp(pix, 4);
635 linebuf = (l_uint8 *)LEPT_CALLOC(4 * wpl, sizeof(l_uint8));
636 pixdata = pixGetData(pix);
637 for (i = 0; i < h; i++) {
638 if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
639 LEPT_FREE(linebuf);
640 pixDestroy(&pix);
641 L_ERROR("spp = 2, read fail at line %d\n", procName, i);
642 return NULL;
643 }
644 rowptr = linebuf;
645 ppixel = pixdata + i * wpl;
646 for (j = k = 0; j < w; j++) {
647 /* Copy gray value into r, g and b */
648 SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k]);
649 SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k]);
650 SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
651 SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
652 ppixel++;
653 }
654 }
655 LEPT_FREE(linebuf);
656 } else { /* rgb and rgba */
657 if ((tiffdata = (l_uint32 *)LEPT_CALLOC((size_t)w * h,
658 sizeof(l_uint32))) == NULL) {
659 pixDestroy(&pix);
660 return (PIX *)ERROR_PTR("calloc fail for tiffdata", procName, NULL);
661 }
662 /* TIFFReadRGBAImageOriented() converts to 8 bps */
663 if (!TIFFReadRGBAImageOriented(tif, w, h, tiffdata,
664 ORIENTATION_TOPLEFT, 0)) {
665 LEPT_FREE(tiffdata);
666 pixDestroy(&pix);
667 return (PIX *)ERROR_PTR("failed to read tiffdata", procName, NULL);
668 } else {
669 read_oriented = 1;
670 }
671
672 if (spp == 4) pixSetSpp(pix, 4);
673 line = pixGetData(pix);
674 for (i = 0; i < h; i++, line += wpl) {
675 for (j = 0, ppixel = line; j < w; j++) {
676 /* TIFFGet* are macros */
677 tiffword = tiffdata[i * w + j];
678 rval = TIFFGetR(tiffword);
679 gval = TIFFGetG(tiffword);
680 bval = TIFFGetB(tiffword);
681 if (spp == 3) {
682 composeRGBPixel(rval, gval, bval, ppixel);
683 } else { /* spp == 4 */
684 aval = TIFFGetA(tiffword);
685 composeRGBAPixel(rval, gval, bval, aval, ppixel);
686 }
687 ppixel++;
688 }
689 }
690 LEPT_FREE(tiffdata);
691 }
692
693 if (getTiffStreamResolution(tif, &xres, &yres) == 0) {
694 pixSetXRes(pix, xres);
695 pixSetYRes(pix, yres);
696 }
697
698 /* Find and save the compression type */
699 comptype = getTiffCompressedFormat(tiffcomp);
700 pixSetInputFormat(pix, comptype);
701
702 if (TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap)) {
703 /* Save the colormap as a pix cmap. Because the
704 * tiff colormap components are 16 bit unsigned,
705 * and go from black (0) to white (0xffff), the
706 * the pix cmap takes the most significant byte. */
707 if (bps > 8) {
708 pixDestroy(&pix);
709 return (PIX *)ERROR_PTR("colormap size > 256", procName, NULL);
710 }
711 if ((cmap = pixcmapCreate(bps)) == NULL) {
712 pixDestroy(&pix);
713 return (PIX *)ERROR_PTR("colormap not made", procName, NULL);
714 }
715 ncolors = 1 << bps;
716 for (i = 0; i < ncolors; i++)
717 pixcmapAddColor(cmap, redmap[i] >> 8, greenmap[i] >> 8,
718 bluemap[i] >> 8);
719 if (pixSetColormap(pix, cmap)) {
720 pixDestroy(&pix);
721 return (PIX *)ERROR_PTR("invalid colormap", procName, NULL);
722 }
723
724 /* Remove the colormap for 1 bpp. */
725 if (bps == 1) {
727 pixDestroy(&pix);
728 pix = pix1;
729 }
730 } else { /* No colormap: check photometry and invert if necessary */
731 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometry)) {
732 /* Guess default photometry setting. Assume min_is_white
733 * if compressed 1 bpp; min_is_black otherwise. */
734 if (tiffcomp == COMPRESSION_CCITTFAX3 ||
735 tiffcomp == COMPRESSION_CCITTFAX4 ||
736 tiffcomp == COMPRESSION_CCITTRLE ||
737 tiffcomp == COMPRESSION_CCITTRLEW) {
738 photometry = PHOTOMETRIC_MINISWHITE;
739 } else {
740 photometry = PHOTOMETRIC_MINISBLACK;
741 }
742 }
743 if ((d == 1 && photometry == PHOTOMETRIC_MINISBLACK) ||
744 (d == 8 && photometry == PHOTOMETRIC_MINISWHITE))
745 pixInvert(pix, pix);
746 }
747
748 if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
749 if (orientation >= 1 && orientation <= 8) {
750 struct tiff_transform *transform = (read_oriented) ?
751 &tiff_partial_orientation_transforms[orientation - 1] :
752 &tiff_orientation_transforms[orientation - 1];
753 if (transform->vflip) pixFlipTB(pix, pix);
754 if (transform->hflip) pixFlipLR(pix, pix);
755 if (transform->rotate) {
756 PIX *oldpix = pix;
757 pix = pixRotate90(oldpix, transform->rotate);
758 pixDestroy(&oldpix);
759 }
760 }
761 }
762
763 text = NULL;
764 TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &text);
765 if (text) pixSetText(pix, text);
766 return pix;
767}
768
769
770/*--------------------------------------------------------------*
771 * Writing to file *
772 *--------------------------------------------------------------*/
794l_ok
795pixWriteTiff(const char *filename,
796 PIX *pix,
797 l_int32 comptype,
798 const char *modestr)
799{
800 return pixWriteTiffCustom(filename, pix, comptype, modestr,
801 NULL, NULL, NULL, NULL);
802}
803
804
851l_ok
852pixWriteTiffCustom(const char *filename,
853 PIX *pix,
854 l_int32 comptype,
855 const char *modestr,
856 NUMA *natags,
857 SARRAY *savals,
858 SARRAY *satypes,
859 NUMA *nasizes)
860{
861l_int32 ret;
862TIFF *tif;
863
864 PROCNAME("pixWriteTiffCustom");
865
866 if (!filename)
867 return ERROR_INT("filename not defined", procName, 1);
868 if (!pix)
869 return ERROR_INT("pix not defined", procName, 1);
870
871 if ((tif = openTiff(filename, modestr)) == NULL)
872 return ERROR_INT("tif not opened", procName, 1);
873 ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
874 satypes, nasizes);
875 TIFFClose(tif);
876 return ret;
877}
878
879
880/*--------------------------------------------------------------*
881 * Writing to stream *
882 *--------------------------------------------------------------*/
910l_ok
912 PIX *pix,
913 l_int32 comptype)
914{
915 return pixWriteStreamTiffWA(fp, pix, comptype, "w");
916}
917
918
935l_ok
937 PIX *pix,
938 l_int32 comptype,
939 const char *modestr)
940{
941TIFF *tif;
942
943 PROCNAME("pixWriteStreamTiffWA");
944
945 if (!fp)
946 return ERROR_INT("stream not defined", procName, 1 );
947 if (!pix)
948 return ERROR_INT("pix not defined", procName, 1 );
949 if (strcmp(modestr, "w") && strcmp(modestr, "a")) {
950 L_ERROR("modestr = %s; not 'w' or 'a'\n", procName, modestr);
951 return 1;
952 }
953
954 if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
955 comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
956 comptype != IFF_TIFF_JPEG) {
957 L_WARNING("invalid compression type %d for bpp > 1; using TIFF_ZIP\n",
958 procName, comptype);
959 comptype = IFF_TIFF_ZIP;
960 }
961
962 if ((tif = fopenTiff(fp, modestr)) == NULL)
963 return ERROR_INT("tif not opened", procName, 1);
964
965 if (pixWriteToTiffStream(tif, pix, comptype, NULL, NULL, NULL, NULL)) {
966 TIFFCleanup(tif);
967 return ERROR_INT("tif write error", procName, 1);
968 }
969
970 TIFFCleanup(tif);
971 return 0;
972}
973
974
1010static l_int32
1012 PIX *pix,
1013 l_int32 comptype,
1014 NUMA *natags,
1015 SARRAY *savals,
1016 SARRAY *satypes,
1017 NUMA *nasizes)
1018{
1019l_uint8 *linebuf, *data;
1020l_uint16 redmap[256], greenmap[256], bluemap[256];
1021l_int32 w, h, d, spp, i, j, k, wpl, bpl, tiffbpl, ncolors, cmapsize;
1022l_int32 *rmap, *gmap, *bmap;
1023l_int32 xres, yres;
1024l_uint32 *line, *ppixel;
1025PIX *pixt;
1026PIXCMAP *cmap;
1027char *text;
1028
1029 PROCNAME("pixWriteToTiffStream");
1030
1031 if (!tif)
1032 return ERROR_INT("tif stream not defined", procName, 1);
1033 if (!pix)
1034 return ERROR_INT( "pix not defined", procName, 1 );
1035
1036 pixSetPadBits(pix, 0);
1037 pixGetDimensions(pix, &w, &h, &d);
1038 spp = pixGetSpp(pix);
1039 xres = pixGetXRes(pix);
1040 yres = pixGetYRes(pix);
1041 if (xres == 0) xres = DefaultResolution;
1042 if (yres == 0) yres = DefaultResolution;
1043
1044 /* ------------------ Write out the header ------------- */
1045 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (l_uint32)RESUNIT_INCH);
1046 TIFFSetField(tif, TIFFTAG_XRESOLUTION, (l_float64)xres);
1047 TIFFSetField(tif, TIFFTAG_YRESOLUTION, (l_float64)yres);
1048
1049 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (l_uint32)w);
1050 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (l_uint32)h);
1051 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
1052
1053 if ((text = pixGetText(pix)) != NULL)
1054 TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, text);
1055
1056 if (d == 1 && !pixGetColormap(pix)) {
1057 /* If d == 1, preserve the colormap. Note that when
1058 * d == 1 pix with colormaps are read, the colormaps
1059 * are removed. The only pix in leptonica that have
1060 * colormaps are made programmatically. */
1061 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
1062 } else if ((d == 32 && spp == 3) || d == 24) {
1063 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
1064 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)3);
1065 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
1066 (l_uint16)8, (l_uint16)8, (l_uint16)8);
1067 } else if (d == 32 && spp == 4) {
1068 l_uint16 val[1];
1069 val[0] = EXTRASAMPLE_ASSOCALPHA;
1070 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, (l_uint16)1, &val);
1071 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
1072 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)4);
1073 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
1074 (l_uint16)8, (l_uint16)8, (l_uint16)8, (l_uint16)8);
1075 } else if (d == 16) { /* we only support spp = 1, bps = 16 */
1076 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
1077 } else if ((cmap = pixGetColormap(pix)) == NULL) {
1078 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
1079 } else { /* Save colormap in the tiff; not more than 256 colors */
1080 if (d > 8) {
1081 L_ERROR("d = %d > 8 with colormap!; reducing to 8\n", procName, d);
1082 d = 8;
1083 }
1084 pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
1085 ncolors = pixcmapGetCount(cmap);
1086 ncolors = L_MIN(256, ncolors); /* max 256 */
1087 cmapsize = 1 << d;
1088 cmapsize = L_MIN(256, cmapsize); /* power of 2; max 256 */
1089 if (ncolors > cmapsize) {
1090 L_WARNING("too many colors in cmap for tiff; truncating\n",
1091 procName);
1092 ncolors = cmapsize;
1093 }
1094 for (i = 0; i < ncolors; i++) {
1095 redmap[i] = (rmap[i] << 8) | rmap[i];
1096 greenmap[i] = (gmap[i] << 8) | gmap[i];
1097 bluemap[i] = (bmap[i] << 8) | bmap[i];
1098 }
1099 for (i = ncolors; i < cmapsize; i++) /* init, even though not used */
1100 redmap[i] = greenmap[i] = bluemap[i] = 0;
1101 LEPT_FREE(rmap);
1102 LEPT_FREE(gmap);
1103 LEPT_FREE(bmap);
1104
1105 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
1106 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
1107 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
1108 TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
1109 }
1110
1111 if (d <= 16) {
1112 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
1113 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
1114 }
1115
1116 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
1117 if (comptype == IFF_TIFF) { /* no compression */
1118 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
1119 } else if (comptype == IFF_TIFF_G4) {
1120 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
1121 } else if (comptype == IFF_TIFF_G3) {
1122 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
1123 } else if (comptype == IFF_TIFF_RLE) {
1124 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);
1125 } else if (comptype == IFF_TIFF_PACKBITS) {
1126 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
1127 } else if (comptype == IFF_TIFF_LZW) {
1128 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
1129 } else if (comptype == IFF_TIFF_ZIP) {
1130 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
1131 } else if (comptype == IFF_TIFF_JPEG) {
1132 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
1133 } else {
1134 L_WARNING("unknown tiff compression; using none\n", procName);
1135 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
1136 }
1137
1138 /* This is a no-op if arrays are NULL */
1139 writeCustomTiffTags(tif, natags, savals, satypes, nasizes);
1140
1141 /* ------------- Write out the image data ------------- */
1142 tiffbpl = TIFFScanlineSize(tif);
1143 wpl = pixGetWpl(pix);
1144 bpl = 4 * wpl;
1145 if (tiffbpl > bpl)
1146 lept_stderr("Big trouble: tiffbpl = %d, bpl = %d\n", tiffbpl, bpl);
1147 if ((linebuf = (l_uint8 *)LEPT_CALLOC(1, bpl)) == NULL)
1148 return ERROR_INT("calloc fail for linebuf", procName, 1);
1149
1150 /* Use single strip for image */
1151 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);
1152
1153 if (d != 24 && d != 32) {
1154 if (d == 16)
1155 pixt = pixEndianTwoByteSwapNew(pix);
1156 else
1157 pixt = pixEndianByteSwapNew(pix);
1158 data = (l_uint8 *)pixGetData(pixt);
1159 for (i = 0; i < h; i++, data += bpl) {
1160 memcpy(linebuf, data, tiffbpl);
1161 if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1162 break;
1163 }
1164 pixDestroy(&pixt);
1165 } else if (d == 24) { /* See note 4 above: special case of 24 bpp rgb */
1166 for (i = 0; i < h; i++) {
1167 line = pixGetData(pix) + i * wpl;
1168 if (TIFFWriteScanline(tif, (l_uint8 *)line, i, 0) < 0)
1169 break;
1170 }
1171 } else { /* 32 bpp rgb or rgba */
1172 for (i = 0; i < h; i++) {
1173 line = pixGetData(pix) + i * wpl;
1174 for (j = 0, k = 0, ppixel = line; j < w; j++) {
1175 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
1176 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
1177 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
1178 if (spp == 4)
1179 linebuf[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
1180 ppixel++;
1181 }
1182 if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1183 break;
1184 }
1185 }
1186
1187/* TIFFWriteDirectory(tif); */
1188 LEPT_FREE(linebuf);
1189
1190 return 0;
1191}
1192
1193
1223static l_int32
1225 NUMA *natags,
1226 SARRAY *savals,
1227 SARRAY *satypes,
1228 NUMA *nasizes)
1229{
1230char *sval, *type;
1231l_int32 i, n, ns, size, tagval, val;
1232l_float64 dval;
1233l_uint32 uval, uval2;
1234
1235 PROCNAME("writeCustomTiffTags");
1236
1237 if (!tif)
1238 return ERROR_INT("tif stream not defined", procName, 1);
1239 if (!natags && !savals && !satypes)
1240 return 0;
1241 if (!natags || !savals || !satypes)
1242 return ERROR_INT("not all arrays defined", procName, 1);
1243 n = numaGetCount(natags);
1244 if ((sarrayGetCount(savals) != n) || (sarrayGetCount(satypes) != n))
1245 return ERROR_INT("not all sa the same size", procName, 1);
1246
1247 /* The sized arrays (4 args to TIFFSetField) are written first */
1248 if (nasizes) {
1249 ns = numaGetCount(nasizes);
1250 if (ns > n)
1251 return ERROR_INT("too many 4-arg tag calls", procName, 1);
1252 for (i = 0; i < ns; i++) {
1253 numaGetIValue(natags, i, &tagval);
1254 sval = sarrayGetString(savals, i, L_NOCOPY);
1255 type = sarrayGetString(satypes, i, L_NOCOPY);
1256 numaGetIValue(nasizes, i, &size);
1257 if (strcmp(type, "char*") && strcmp(type, "l_uint8*"))
1258 L_WARNING("array type not char* or l_uint8*; ignore\n",
1259 procName);
1260 TIFFSetField(tif, tagval, size, sval);
1261 }
1262 } else {
1263 ns = 0;
1264 }
1265
1266 /* The typical tags (3 args to TIFFSetField) are now written */
1267 for (i = ns; i < n; i++) {
1268 numaGetIValue(natags, i, &tagval);
1269 sval = sarrayGetString(savals, i, L_NOCOPY);
1270 type = sarrayGetString(satypes, i, L_NOCOPY);
1271 if (!strcmp(type, "char*") || !strcmp(type, "const char*")) {
1272 TIFFSetField(tif, tagval, sval);
1273 } else if (!strcmp(type, "l_uint16")) {
1274 if (sscanf(sval, "%u", &uval) == 1) {
1275 TIFFSetField(tif, tagval, (l_uint16)uval);
1276 } else {
1277 lept_stderr("val %s not of type %s\n", sval, type);
1278 return ERROR_INT("custom tag(s) not written", procName, 1);
1279 }
1280 } else if (!strcmp(type, "l_uint32")) {
1281 if (sscanf(sval, "%u", &uval) == 1) {
1282 TIFFSetField(tif, tagval, uval);
1283 } else {
1284 lept_stderr("val %s not of type %s\n", sval, type);
1285 return ERROR_INT("custom tag(s) not written", procName, 1);
1286 }
1287 } else if (!strcmp(type, "l_int32")) {
1288 if (sscanf(sval, "%d", &val) == 1) {
1289 TIFFSetField(tif, tagval, val);
1290 } else {
1291 lept_stderr("val %s not of type %s\n", sval, type);
1292 return ERROR_INT("custom tag(s) not written", procName, 1);
1293 }
1294 } else if (!strcmp(type, "l_float64")) {
1295 if (sscanf(sval, "%lf", &dval) == 1) {
1296 TIFFSetField(tif, tagval, dval);
1297 } else {
1298 lept_stderr("val %s not of type %s\n", sval, type);
1299 return ERROR_INT("custom tag(s) not written", procName, 1);
1300 }
1301 } else if (!strcmp(type, "l_uint16-l_uint16")) {
1302 if (sscanf(sval, "%u-%u", &uval, &uval2) == 2) {
1303 TIFFSetField(tif, tagval, (l_uint16)uval, (l_uint16)uval2);
1304 } else {
1305 lept_stderr("val %s not of type %s\n", sval, type);
1306 return ERROR_INT("custom tag(s) not written", procName, 1);
1307 }
1308 } else {
1309 lept_stderr("unknown type %s\n",type);
1310 return ERROR_INT("unknown type; tag(s) not written", procName, 1);
1311 }
1312 }
1313 return 0;
1314}
1315
1316
1317/*--------------------------------------------------------------*
1318 * Reading and writing multipage tiff *
1319 *--------------------------------------------------------------*/
1351PIX *
1353 size_t *poffset)
1354{
1355l_int32 retval;
1356size_t offset;
1357PIX *pix;
1358TIFF *tif;
1359
1360 PROCNAME("pixReadFromMultipageTiff");
1361
1362 if (!fname)
1363 return (PIX *)ERROR_PTR("fname not defined", procName, NULL);
1364 if (!poffset)
1365 return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);
1366
1367 if ((tif = openTiff(fname, "r")) == NULL) {
1368 L_ERROR("tif open failed for %s\n", procName, fname);
1369 return NULL;
1370 }
1371
1372 /* Set ptrs in the TIFF to the beginning of the image */
1373 offset = *poffset;
1374 retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
1375 : TIFFSetSubDirectory(tif, offset);
1376 if (retval == 0) {
1377 TIFFClose(tif);
1378 return NULL;
1379 }
1380
1381 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
1382 TIFFClose(tif);
1383 return NULL;
1384 }
1385
1386 /* Advance to the next image and return the new offset */
1387 TIFFReadDirectory(tif);
1388 *poffset = TIFFCurrentDirOffset(tif);
1389 TIFFClose(tif);
1390 return pix;
1391}
1392
1393
1400PIXA *
1401pixaReadMultipageTiff(const char *filename)
1402{
1403l_int32 i, npages;
1404FILE *fp;
1405PIX *pix;
1406PIXA *pixa;
1407TIFF *tif;
1408
1409 PROCNAME("pixaReadMultipageTiff");
1410
1411 if (!filename)
1412 return (PIXA *)ERROR_PTR("filename not defined", procName, NULL);
1413
1414 if ((fp = fopenReadStream(filename)) == NULL)
1415 return (PIXA *)ERROR_PTR("stream not opened", procName, NULL);
1416 if (fileFormatIsTiff(fp)) {
1417 tiffGetCount(fp, &npages);
1418 L_INFO(" Tiff: %d pages\n", procName, npages);
1419 } else {
1420 return (PIXA *)ERROR_PTR("file not tiff", procName, NULL);
1421 }
1422
1423 if ((tif = fopenTiff(fp, "r")) == NULL)
1424 return (PIXA *)ERROR_PTR("tif not opened", procName, NULL);
1425
1426 pixa = pixaCreate(npages);
1427 pix = NULL;
1428 for (i = 0; i < npages; i++) {
1429 if ((pix = pixReadFromTiffStream(tif)) != NULL) {
1430 pixaAddPix(pixa, pix, L_INSERT);
1431 } else {
1432 L_WARNING("pix not read for page %d\n", procName, i);
1433 }
1434
1435 /* Advance to the next directory (i.e., the next image) */
1436 if (TIFFReadDirectory(tif) == 0)
1437 break;
1438 }
1439
1440 fclose(fp);
1441 TIFFCleanup(tif);
1442 return pixa;
1443}
1444
1445
1460l_ok
1461pixaWriteMultipageTiff(const char *fname,
1462 PIXA *pixa)
1463{
1464const char *modestr;
1465l_int32 i, n;
1466PIX *pix1;
1467
1468 PROCNAME("pixaWriteMultipageTiff");
1469
1470 if (!fname)
1471 return ERROR_INT("fname not defined", procName, 1);
1472 if (!pixa)
1473 return ERROR_INT("pixa not defined", procName, 1);
1474
1475 n = pixaGetCount(pixa);
1476 for (i = 0; i < n; i++) {
1477 modestr = (i == 0) ? "w" : "a";
1478 pix1 = pixaGetPix(pixa, i, L_CLONE);
1479 if (pixGetDepth(pix1) == 1)
1480 pixWriteTiff(fname, pix1, IFF_TIFF_G4, modestr);
1481 else
1482 pixWriteTiff(fname, pix1, IFF_TIFF_ZIP, modestr);
1483 pixDestroy(&pix1);
1484 }
1485
1486 return 0;
1487}
1488
1489
1514l_ok
1515writeMultipageTiff(const char *dirin,
1516 const char *substr,
1517 const char *fileout)
1518{
1519SARRAY *sa;
1520
1521 PROCNAME("writeMultipageTiff");
1522
1523 if (!dirin)
1524 return ERROR_INT("dirin not defined", procName, 1);
1525 if (!fileout)
1526 return ERROR_INT("fileout not defined", procName, 1);
1527
1528 /* Get all filtered and sorted full pathnames. */
1529 sa = getSortedPathnamesInDirectory(dirin, substr, 0, 0);
1530
1531 /* Generate the tiff file */
1532 writeMultipageTiffSA(sa, fileout);
1533 sarrayDestroy(&sa);
1534 return 0;
1535}
1536
1537
1550l_ok
1552 const char *fileout)
1553{
1554char *fname;
1555const char *op;
1556l_int32 i, nfiles, firstfile, format;
1557PIX *pix;
1558
1559 PROCNAME("writeMultipageTiffSA");
1560
1561 if (!sa)
1562 return ERROR_INT("sa not defined", procName, 1);
1563 if (!fileout)
1564 return ERROR_INT("fileout not defined", procName, 1);
1565
1566 nfiles = sarrayGetCount(sa);
1567 firstfile = TRUE;
1568 for (i = 0; i < nfiles; i++) {
1569 op = (firstfile) ? "w" : "a";
1570 fname = sarrayGetString(sa, i, L_NOCOPY);
1571 findFileFormat(fname, &format);
1572 if (format == IFF_UNKNOWN) {
1573 L_INFO("format of %s not known\n", procName, fname);
1574 continue;
1575 }
1576
1577 if ((pix = pixRead(fname)) == NULL) {
1578 L_WARNING("pix not made for file: %s\n", procName, fname);
1579 continue;
1580 }
1581 if (pixGetDepth(pix) == 1)
1582 pixWriteTiff(fileout, pix, IFF_TIFF_G4, op);
1583 else
1584 pixWriteTiff(fileout, pix, IFF_TIFF_ZIP, op);
1585 firstfile = FALSE;
1586 pixDestroy(&pix);
1587 }
1588
1589 return 0;
1590}
1591
1592
1593/*--------------------------------------------------------------*
1594 * Print info to stream *
1595 *--------------------------------------------------------------*/
1603l_ok
1604fprintTiffInfo(FILE *fpout,
1605 const char *tiffile)
1606{
1607TIFF *tif;
1608
1609 PROCNAME("fprintTiffInfo");
1610
1611 if (!tiffile)
1612 return ERROR_INT("tiffile not defined", procName, 1);
1613 if (!fpout)
1614 return ERROR_INT("stream out not defined", procName, 1);
1615
1616 if ((tif = openTiff(tiffile, "rb")) == NULL)
1617 return ERROR_INT("tif not open for read", procName, 1);
1618
1619 TIFFPrintDirectory(tif, fpout, 0);
1620 TIFFClose(tif);
1621
1622 return 0;
1623}
1624
1625
1626/*--------------------------------------------------------------*
1627 * Get page count *
1628 *--------------------------------------------------------------*/
1636l_ok
1638 l_int32 *pn)
1639{
1640l_int32 i;
1641TIFF *tif;
1642
1643 PROCNAME("tiffGetCount");
1644
1645 if (!fp)
1646 return ERROR_INT("stream not defined", procName, 1);
1647 if (!pn)
1648 return ERROR_INT("&n not defined", procName, 1);
1649 *pn = 0;
1650
1651 if ((tif = fopenTiff(fp, "r")) == NULL)
1652 return ERROR_INT("tif not open for read", procName, 1);
1653
1654 for (i = 1; ; i++) {
1655 if (TIFFReadDirectory(tif) == 0)
1656 break;
1657 if (i == ManyPagesInTiffFile + 1) {
1658 L_WARNING("big file: more than %d pages\n", procName,
1659 ManyPagesInTiffFile);
1660 }
1661 }
1662 *pn = i;
1663 TIFFCleanup(tif);
1664 return 0;
1665}
1666
1667
1668/*--------------------------------------------------------------*
1669 * Get resolution from tif *
1670 *--------------------------------------------------------------*/
1684l_ok
1686 l_int32 *pxres,
1687 l_int32 *pyres)
1688{
1689TIFF *tif;
1690
1691 PROCNAME("getTiffResolution");
1692
1693 if (!pxres || !pyres)
1694 return ERROR_INT("&xres and &yres not both defined", procName, 1);
1695 *pxres = *pyres = 0;
1696 if (!fp)
1697 return ERROR_INT("stream not opened", procName, 1);
1698
1699 if ((tif = fopenTiff(fp, "r")) == NULL)
1700 return ERROR_INT("tif not open for read", procName, 1);
1701 getTiffStreamResolution(tif, pxres, pyres);
1702 TIFFCleanup(tif);
1703 return 0;
1704}
1705
1706
1720static l_int32
1722 l_int32 *pxres,
1723 l_int32 *pyres)
1724{
1725l_uint16 resunit;
1726l_int32 foundxres, foundyres;
1727l_float32 fxres, fyres;
1728
1729 PROCNAME("getTiffStreamResolution");
1730
1731 if (!tif)
1732 return ERROR_INT("tif not opened", procName, 1);
1733 if (!pxres || !pyres)
1734 return ERROR_INT("&xres and &yres not both defined", procName, 1);
1735 *pxres = *pyres = 0;
1736
1737 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
1738 foundxres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fxres);
1739 foundyres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fyres);
1740 if (!foundxres && !foundyres) return 1;
1741 if (isnan(fxres) || isnan(fyres)) return 1;
1742 if (!foundxres && foundyres)
1743 fxres = fyres;
1744 else if (foundxres && !foundyres)
1745 fyres = fxres;
1746
1747 /* Avoid overflow into int32; set max fxres and fyres to 5 x 10^8 */
1748 if (fxres < 0 || fxres > (1L << 29) || fyres < 0 || fyres > (1L << 29))
1749 return ERROR_INT("fxres and/or fyres values are invalid", procName, 1);
1750
1751 if (resunit == RESUNIT_CENTIMETER) { /* convert to ppi */
1752 *pxres = (l_int32)(2.54 * fxres + 0.5);
1753 *pyres = (l_int32)(2.54 * fyres + 0.5);
1754 } else {
1755 *pxres = (l_int32)fxres;
1756 *pyres = (l_int32)fyres;
1757 }
1758
1759 return 0;
1760}
1761
1762
1763/*--------------------------------------------------------------*
1764 * Get some tiff header information *
1765 *--------------------------------------------------------------*/
1786l_ok
1787readHeaderTiff(const char *filename,
1788 l_int32 n,
1789 l_int32 *pw,
1790 l_int32 *ph,
1791 l_int32 *pbps,
1792 l_int32 *pspp,
1793 l_int32 *pres,
1794 l_int32 *pcmap,
1795 l_int32 *pformat)
1796{
1797l_int32 ret;
1798FILE *fp;
1799
1800 PROCNAME("readHeaderTiff");
1801
1802 if (pw) *pw = 0;
1803 if (ph) *ph = 0;
1804 if (pbps) *pbps = 0;
1805 if (pspp) *pspp = 0;
1806 if (pres) *pres = 0;
1807 if (pcmap) *pcmap = 0;
1808 if (pformat) *pformat = 0;
1809 if (!filename)
1810 return ERROR_INT("filename not defined", procName, 1);
1811 if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1812 return ERROR_INT("no results requested", procName, 1);
1813
1814 if ((fp = fopenReadStream(filename)) == NULL)
1815 return ERROR_INT("image file not found", procName, 1);
1816 ret = freadHeaderTiff(fp, n, pw, ph, pbps, pspp, pres, pcmap, pformat);
1817 fclose(fp);
1818 return ret;
1819}
1820
1821
1842l_ok
1844 l_int32 n,
1845 l_int32 *pw,
1846 l_int32 *ph,
1847 l_int32 *pbps,
1848 l_int32 *pspp,
1849 l_int32 *pres,
1850 l_int32 *pcmap,
1851 l_int32 *pformat)
1852{
1853l_int32 i, ret, format;
1854TIFF *tif;
1855
1856 PROCNAME("freadHeaderTiff");
1857
1858 if (pw) *pw = 0;
1859 if (ph) *ph = 0;
1860 if (pbps) *pbps = 0;
1861 if (pspp) *pspp = 0;
1862 if (pres) *pres = 0;
1863 if (pcmap) *pcmap = 0;
1864 if (pformat) *pformat = 0;
1865 if (!fp)
1866 return ERROR_INT("stream not defined", procName, 1);
1867 if (n < 0)
1868 return ERROR_INT("image index must be >= 0", procName, 1);
1869 if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1870 return ERROR_INT("no results requested", procName, 1);
1871
1872 findFileFormatStream(fp, &format);
1873 if (!L_FORMAT_IS_TIFF(format))
1874 return ERROR_INT("file not tiff format", procName, 1);
1875
1876 if ((tif = fopenTiff(fp, "r")) == NULL)
1877 return ERROR_INT("tif not open for read", procName, 1);
1878
1879 for (i = 0; i < n; i++) {
1880 if (TIFFReadDirectory(tif) == 0)
1881 return ERROR_INT("image n not found in file", procName, 1);
1882 }
1883
1884 ret = tiffReadHeaderTiff(tif, pw, ph, pbps, pspp, pres, pcmap, pformat);
1885 TIFFCleanup(tif);
1886 return ret;
1887}
1888
1889
1910l_ok
1911readHeaderMemTiff(const l_uint8 *cdata,
1912 size_t size,
1913 l_int32 n,
1914 l_int32 *pw,
1915 l_int32 *ph,
1916 l_int32 *pbps,
1917 l_int32 *pspp,
1918 l_int32 *pres,
1919 l_int32 *pcmap,
1920 l_int32 *pformat)
1921{
1922l_uint8 *data;
1923l_int32 i, ret;
1924TIFF *tif;
1925
1926 PROCNAME("readHeaderMemTiff");
1927
1928 if (pw) *pw = 0;
1929 if (ph) *ph = 0;
1930 if (pbps) *pbps = 0;
1931 if (pspp) *pspp = 0;
1932 if (pres) *pres = 0;
1933 if (pcmap) *pcmap = 0;
1934 if (pformat) *pformat = 0;
1935 if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1936 return ERROR_INT("no results requested", procName, 1);
1937 if (!cdata)
1938 return ERROR_INT("cdata not defined", procName, 1);
1939
1940 /* Open a tiff stream to memory */
1941 data = (l_uint8 *)cdata; /* we're really not going to change this */
1942 if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
1943 return ERROR_INT("tiff stream not opened", procName, 1);
1944
1945 for (i = 0; i < n; i++) {
1946 if (TIFFReadDirectory(tif) == 0) {
1947 TIFFClose(tif);
1948 return ERROR_INT("image n not found in file", procName, 1);
1949 }
1950 }
1951
1952 ret = tiffReadHeaderTiff(tif, pw, ph, pbps, pspp, pres, pcmap, pformat);
1953 TIFFClose(tif);
1954 return ret;
1955}
1956
1957
1971static l_int32
1973 l_int32 *pw,
1974 l_int32 *ph,
1975 l_int32 *pbps,
1976 l_int32 *pspp,
1977 l_int32 *pres,
1978 l_int32 *pcmap,
1979 l_int32 *pformat)
1980{
1981l_uint16 tiffcomp;
1982l_uint16 bps, spp;
1983l_uint16 *rmap, *gmap, *bmap;
1984l_int32 xres, yres;
1985l_uint32 w, h;
1986
1987 PROCNAME("tiffReadHeaderTiff");
1988
1989 if (!tif)
1990 return ERROR_INT("tif not opened", procName, 1);
1991
1992 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
1993 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
1994 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
1995 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
1996 if (w < 1 || h < 1)
1997 return ERROR_INT("tif w and h not both > 0", procName, 1);
1998 if (bps != 1 && bps != 2 && bps != 4 && bps != 8 && bps != 16)
1999 return ERROR_INT("bps not in set {1,2,4,8,16}", procName, 1);
2000 if (spp != 1 && spp != 2 && spp != 3 && spp != 4)
2001 return ERROR_INT("spp not in set {1,2,3,4}", procName, 1);
2002 if (pw) *pw = w;
2003 if (ph) *ph = h;
2004 if (pbps) *pbps = bps;
2005 if (pspp) *pspp = spp;
2006 if (pres) {
2007 *pres = 300; /* default ppi */
2008 if (getTiffStreamResolution(tif, &xres, &yres) == 0)
2009 *pres = (l_int32)xres;
2010 }
2011 if (pcmap) {
2012 *pcmap = 0;
2013 if (TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap))
2014 *pcmap = 1;
2015 }
2016 if (pformat) {
2017 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
2018 *pformat = getTiffCompressedFormat(tiffcomp);
2019 }
2020 return 0;
2021}
2022
2023
2043l_ok
2045 l_int32 *pcomptype)
2046{
2047l_uint16 tiffcomp;
2048TIFF *tif;
2049
2050 PROCNAME("findTiffCompression");
2051
2052 if (!pcomptype)
2053 return ERROR_INT("&comptype not defined", procName, 1);
2054 *pcomptype = IFF_UNKNOWN; /* init */
2055 if (!fp)
2056 return ERROR_INT("stream not defined", procName, 1);
2057
2058 if ((tif = fopenTiff(fp, "r")) == NULL)
2059 return ERROR_INT("tif not opened", procName, 1);
2060 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
2061 *pcomptype = getTiffCompressedFormat(tiffcomp);
2062 TIFFCleanup(tif);
2063 return 0;
2064}
2065
2066
2081static l_int32
2082getTiffCompressedFormat(l_uint16 tiffcomp)
2083{
2084l_int32 comptype;
2085
2086 switch (tiffcomp)
2087 {
2088 case COMPRESSION_CCITTFAX4:
2089 comptype = IFF_TIFF_G4;
2090 break;
2091 case COMPRESSION_CCITTFAX3:
2092 comptype = IFF_TIFF_G3;
2093 break;
2094 case COMPRESSION_CCITTRLE:
2095 comptype = IFF_TIFF_RLE;
2096 break;
2097 case COMPRESSION_PACKBITS:
2098 comptype = IFF_TIFF_PACKBITS;
2099 break;
2100 case COMPRESSION_LZW:
2101 comptype = IFF_TIFF_LZW;
2102 break;
2103 case COMPRESSION_ADOBE_DEFLATE:
2104 comptype = IFF_TIFF_ZIP;
2105 break;
2106 case COMPRESSION_JPEG:
2107 comptype = IFF_TIFF_JPEG;
2108 break;
2109 default:
2110 comptype = IFF_TIFF;
2111 break;
2112 }
2113 return comptype;
2114}
2115
2116
2117/*--------------------------------------------------------------*
2118 * Extraction of tiff g4 data *
2119 *--------------------------------------------------------------*/
2131l_ok
2132extractG4DataFromFile(const char *filein,
2133 l_uint8 **pdata,
2134 size_t *pnbytes,
2135 l_int32 *pw,
2136 l_int32 *ph,
2137 l_int32 *pminisblack)
2138{
2139l_uint8 *inarray, *data;
2140l_uint16 minisblack, comptype; /* accessors require l_uint16 */
2141l_int32 istiff;
2142l_uint32 w, h, rowsperstrip; /* accessors require l_uint32 */
2143l_uint32 diroff;
2144size_t fbytes, nbytes;
2145FILE *fpin;
2146TIFF *tif;
2147
2148 PROCNAME("extractG4DataFromFile");
2149
2150 if (!pdata)
2151 return ERROR_INT("&data not defined", procName, 1);
2152 if (!pnbytes)
2153 return ERROR_INT("&nbytes not defined", procName, 1);
2154 if (!pw && !ph && !pminisblack)
2155 return ERROR_INT("no output data requested", procName, 1);
2156 *pdata = NULL;
2157 *pnbytes = 0;
2158
2159 if ((fpin = fopenReadStream(filein)) == NULL)
2160 return ERROR_INT("stream not opened to file", procName, 1);
2161 istiff = fileFormatIsTiff(fpin);
2162 fclose(fpin);
2163 if (!istiff)
2164 return ERROR_INT("filein not tiff", procName, 1);
2165
2166 if ((inarray = l_binaryRead(filein, &fbytes)) == NULL)
2167 return ERROR_INT("inarray not made", procName, 1);
2168
2169 /* Get metadata about the image */
2170 if ((tif = openTiff(filein, "rb")) == NULL) {
2171 LEPT_FREE(inarray);
2172 return ERROR_INT("tif not open for read", procName, 1);
2173 }
2174 TIFFGetField(tif, TIFFTAG_COMPRESSION, &comptype);
2175 if (comptype != COMPRESSION_CCITTFAX4) {
2176 LEPT_FREE(inarray);
2177 TIFFClose(tif);
2178 return ERROR_INT("filein is not g4 compressed", procName, 1);
2179 }
2180
2181 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
2182 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
2183 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
2184 if (h != rowsperstrip)
2185 L_WARNING("more than 1 strip\n", procName);
2186 TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &minisblack); /* for 1 bpp */
2187/* TIFFPrintDirectory(tif, stderr, 0); */
2188 TIFFClose(tif);
2189 if (pw) *pw = (l_int32)w;
2190 if (ph) *ph = (l_int32)h;
2191 if (pminisblack) *pminisblack = (l_int32)minisblack;
2192
2193 /* The header has 8 bytes: the first 2 are the magic number,
2194 * the next 2 are the version, and the last 4 are the
2195 * offset to the first directory. That's what we want here.
2196 * We have to test the byte order before decoding 4 bytes! */
2197 if (inarray[0] == 0x4d) { /* big-endian */
2198 diroff = (inarray[4] << 24) | (inarray[5] << 16) |
2199 (inarray[6] << 8) | inarray[7];
2200 } else { /* inarray[0] == 0x49 : little-endian */
2201 diroff = (inarray[7] << 24) | (inarray[6] << 16) |
2202 (inarray[5] << 8) | inarray[4];
2203 }
2204/* lept_stderr(" diroff = %d, %x\n", diroff, diroff); */
2205
2206 /* Extract the ccittg4 encoded data from the tiff file.
2207 * We skip the 8 byte header and take nbytes of data,
2208 * up to the beginning of the directory (at diroff) */
2209 nbytes = diroff - 8;
2210 if (nbytes > MaxNumTiffBytes) {
2211 LEPT_FREE(inarray);
2212 L_ERROR("requesting %zu bytes > %zu\n", procName,
2213 nbytes, MaxNumTiffBytes);
2214 return 1;
2215 }
2216 *pnbytes = nbytes;
2217 if ((data = (l_uint8 *)LEPT_CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
2218 LEPT_FREE(inarray);
2219 return ERROR_INT("data not allocated", procName, 1);
2220 }
2221 *pdata = data;
2222 memcpy(data, inarray + 8, nbytes);
2223 LEPT_FREE(inarray);
2224
2225 return 0;
2226}
2227
2228
2229/*--------------------------------------------------------------*
2230 * Open tiff stream from file stream *
2231 *--------------------------------------------------------------*/
2252static TIFF *
2253fopenTiff(FILE *fp,
2254 const char *modestring)
2255{
2256 PROCNAME("fopenTiff");
2257
2258 if (!fp)
2259 return (TIFF *)ERROR_PTR("stream not opened", procName, NULL);
2260 if (!modestring)
2261 return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
2262
2263 TIFFSetWarningHandler(NULL); /* disable warnings */
2264 TIFFSetErrorHandler(NULL); /* disable error messages */
2265
2266 fseek(fp, 0, SEEK_SET);
2267 return TIFFClientOpen("TIFFstream", modestring, (thandle_t)fp,
2268 lept_read_proc, lept_write_proc, lept_seek_proc,
2269 lept_close_proc, lept_size_proc, NULL, NULL);
2270}
2271
2272
2273/*--------------------------------------------------------------*
2274 * Wrapper for TIFFOpen *
2275 *--------------------------------------------------------------*/
2288static TIFF *
2289openTiff(const char *filename,
2290 const char *modestring)
2291{
2292char *fname;
2293TIFF *tif;
2294
2295 PROCNAME("openTiff");
2296
2297 if (!filename)
2298 return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
2299 if (!modestring)
2300 return (TIFF *)ERROR_PTR("modestring not defined", procName, NULL);
2301
2302 TIFFSetWarningHandler(NULL); /* disable warnings */
2303 TIFFSetErrorHandler(NULL); /* disable error messages */
2304
2305 fname = genPathname(filename, NULL);
2306 tif = TIFFOpen(fname, modestring);
2307 LEPT_FREE(fname);
2308 return tif;
2309}
2310
2311
2312/*----------------------------------------------------------------------*
2313 * Memory I/O: reading memory --> pix and writing pix --> memory *
2314 *----------------------------------------------------------------------*/
2315/* It would be nice to use open_memstream() and fmemopen()
2316 * for writing and reading to memory, rsp. These functions manage
2317 * memory for writes and reads that use a file streams interface.
2318 * Unfortunately, the tiff library only has an interface for reading
2319 * and writing to file descriptors, not to file streams. The tiff
2320 * library procedure is to open a "tiff stream" and read/write to it.
2321 * The library provides a client interface for managing the I/O
2322 * from memory, which requires seven callbacks. See the TIFFClientOpen
2323 * man page for callback signatures. Adam Langley provided the code
2324 * to do this. */
2325
2347{
2348 l_uint8 *buffer; /* expands to hold data when written to; */
2349 /* fixed size when read from. */
2350 size_t bufsize; /* current size allocated when written to; */
2351 /* fixed size of input data when read from. */
2352 size_t offset; /* byte offset from beginning of buffer. */
2353 size_t hw; /* high-water mark; max bytes in buffer. */
2354 l_uint8 **poutdata; /* input param for writing; data goes here. */
2355 size_t *poutsize; /* input param for writing; data size goes here. */
2356};
2357typedef struct L_Memstream L_MEMSTREAM;
2358
2359
2360 /* These are static functions for memory I/O */
2361static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);
2362static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
2363 size_t *poutsize);
2364static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);
2365static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
2366 tsize_t length);
2367static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);
2368static l_int32 tiffCloseCallback(thandle_t handle);
2369static toff_t tiffSizeCallback(thandle_t handle);
2370static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);
2371static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);
2372
2373
2374static L_MEMSTREAM *
2375memstreamCreateForRead(l_uint8 *indata,
2376 size_t insize)
2377{
2378L_MEMSTREAM *mstream;
2379
2380 mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2381 mstream->buffer = indata; /* handle to input data array */
2382 mstream->bufsize = insize; /* amount of input data */
2383 mstream->hw = insize; /* high-water mark fixed at input data size */
2384 mstream->offset = 0; /* offset always starts at 0 */
2385 return mstream;
2386}
2387
2388
2389static L_MEMSTREAM *
2390memstreamCreateForWrite(l_uint8 **poutdata,
2391 size_t *poutsize)
2392{
2393L_MEMSTREAM *mstream;
2394
2395 mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2396 mstream->buffer = (l_uint8 *)LEPT_CALLOC(8 * 1024, 1);
2397 mstream->bufsize = 8 * 1024;
2398 mstream->poutdata = poutdata; /* used only at end of write */
2399 mstream->poutsize = poutsize; /* ditto */
2400 mstream->hw = mstream->offset = 0;
2401 return mstream;
2402}
2403
2404
2405static tsize_t
2406tiffReadCallback(thandle_t handle,
2407 tdata_t data,
2408 tsize_t length)
2409{
2410L_MEMSTREAM *mstream;
2411size_t amount;
2412
2413 mstream = (L_MEMSTREAM *)handle;
2414 amount = L_MIN((size_t)length, mstream->hw - mstream->offset);
2415
2416 /* Fuzzed files can create this condition! */
2417 if (mstream->offset + amount < amount || /* overflow */
2418 mstream->offset + amount > mstream->hw) {
2419 lept_stderr("Bad file: amount too big: %zu\n", amount);
2420 return 0;
2421 }
2422
2423 memcpy(data, mstream->buffer + mstream->offset, amount);
2424 mstream->offset += amount;
2425 return amount;
2426}
2427
2428
2429static tsize_t
2430tiffWriteCallback(thandle_t handle,
2431 tdata_t data,
2432 tsize_t length)
2433{
2434L_MEMSTREAM *mstream;
2435size_t newsize;
2436
2437 /* reallocNew() uses calloc to initialize the array.
2438 * If malloc is used instead, for some of the encoding methods,
2439 * not all the data in 'bufsize' bytes in the buffer will
2440 * have been initialized by the end of the compression. */
2441 mstream = (L_MEMSTREAM *)handle;
2442 if (mstream->offset + length > mstream->bufsize) {
2443 newsize = 2 * (mstream->offset + length);
2444 mstream->buffer = (l_uint8 *)reallocNew((void **)&mstream->buffer,
2445 mstream->hw, newsize);
2446 mstream->bufsize = newsize;
2447 }
2448
2449 memcpy(mstream->buffer + mstream->offset, data, length);
2450 mstream->offset += length;
2451 mstream->hw = L_MAX(mstream->offset, mstream->hw);
2452 return length;
2453}
2454
2455
2456static toff_t
2457tiffSeekCallback(thandle_t handle,
2458 toff_t offset,
2459 l_int32 whence)
2460{
2461L_MEMSTREAM *mstream;
2462
2463 PROCNAME("tiffSeekCallback");
2464 mstream = (L_MEMSTREAM *)handle;
2465 switch (whence) {
2466 case SEEK_SET:
2467/* lept_stderr("seek_set: offset = %d\n", offset); */
2468 if((size_t)offset != offset) { /* size_t overflow on uint32 */
2469 return (toff_t)ERROR_INT("too large offset value", procName, 1);
2470 }
2471 mstream->offset = offset;
2472 break;
2473 case SEEK_CUR:
2474/* lept_stderr("seek_cur: offset = %d\n", offset); */
2475 mstream->offset += offset;
2476 break;
2477 case SEEK_END:
2478/* lept_stderr("seek end: hw = %d, offset = %d\n",
2479 mstream->hw, offset); */
2480 mstream->offset = mstream->hw - offset; /* offset >= 0 */
2481 break;
2482 default:
2483 return (toff_t)ERROR_INT("bad whence value", procName,
2484 mstream->offset);
2485 }
2486
2487 return mstream->offset;
2488}
2489
2490
2491static l_int32
2492tiffCloseCallback(thandle_t handle)
2493{
2494L_MEMSTREAM *mstream;
2495
2496 mstream = (L_MEMSTREAM *)handle;
2497 if (mstream->poutdata) { /* writing: save the output data */
2498 *mstream->poutdata = mstream->buffer;
2499 *mstream->poutsize = mstream->hw;
2500 }
2501 LEPT_FREE(mstream); /* never free the buffer! */
2502 return 0;
2503}
2504
2505
2506static toff_t
2507tiffSizeCallback(thandle_t handle)
2508{
2509L_MEMSTREAM *mstream;
2510
2511 mstream = (L_MEMSTREAM *)handle;
2512 return mstream->hw;
2513}
2514
2515
2516static l_int32
2517tiffMapCallback(thandle_t handle,
2518 tdata_t *data,
2519 toff_t *length)
2520{
2521L_MEMSTREAM *mstream;
2522
2523 mstream = (L_MEMSTREAM *)handle;
2524 *data = mstream->buffer;
2525 *length = mstream->hw;
2526 return 0;
2527}
2528
2529
2530static void
2531tiffUnmapCallback(thandle_t handle,
2532 tdata_t data,
2533 toff_t length)
2534{
2535 return;
2536}
2537
2538
2559static TIFF *
2560fopenTiffMemstream(const char *filename,
2561 const char *operation,
2562 l_uint8 **pdata,
2563 size_t *pdatasize)
2564{
2565L_MEMSTREAM *mstream;
2566TIFF *tif;
2567
2568 PROCNAME("fopenTiffMemstream");
2569
2570 if (!filename)
2571 return (TIFF *)ERROR_PTR("filename not defined", procName, NULL);
2572 if (!operation)
2573 return (TIFF *)ERROR_PTR("operation not defined", procName, NULL);
2574 if (!pdata)
2575 return (TIFF *)ERROR_PTR("&data not defined", procName, NULL);
2576 if (!pdatasize)
2577 return (TIFF *)ERROR_PTR("&datasize not defined", procName, NULL);
2578 if (strcmp(operation, "r") && strcmp(operation, "w"))
2579 return (TIFF *)ERROR_PTR("op not 'r' or 'w'", procName, NULL);
2580
2581 if (!strcmp(operation, "r"))
2582 mstream = memstreamCreateForRead(*pdata, *pdatasize);
2583 else
2584 mstream = memstreamCreateForWrite(pdata, pdatasize);
2585
2586 TIFFSetWarningHandler(NULL); /* disable warnings */
2587 TIFFSetErrorHandler(NULL); /* disable error messages */
2588
2589 tif = TIFFClientOpen(filename, operation, (thandle_t)mstream,
2590 tiffReadCallback, tiffWriteCallback,
2591 tiffSeekCallback, tiffCloseCallback,
2592 tiffSizeCallback, tiffMapCallback,
2593 tiffUnmapCallback);
2594 if (!tif)
2595 LEPT_FREE(mstream);
2596 return tif;
2597}
2598
2599
2620PIX *
2621pixReadMemTiff(const l_uint8 *cdata,
2622 size_t size,
2623 l_int32 n)
2624{
2625l_uint8 *data;
2626l_int32 i;
2627PIX *pix;
2628TIFF *tif;
2629
2630 PROCNAME("pixReadMemTiff");
2631
2632 if (!cdata)
2633 return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
2634
2635 data = (l_uint8 *)cdata; /* we're really not going to change this */
2636 if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2637 return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
2638
2639 pix = NULL;
2640 for (i = 0; ; i++) {
2641 if (i == n) {
2642 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2643 TIFFClose(tif);
2644 return NULL;
2645 }
2646 pixSetInputFormat(pix, IFF_TIFF);
2647 break;
2648 }
2649 if (TIFFReadDirectory(tif) == 0)
2650 break;
2651 if (i == ManyPagesInTiffFile + 1) {
2652 L_WARNING("big file: more than %d pages\n", procName,
2653 ManyPagesInTiffFile);
2654 }
2655 }
2656
2657 TIFFClose(tif);
2658 return pix;
2659}
2660
2661
2685PIX *
2686pixReadMemFromMultipageTiff(const l_uint8 *cdata,
2687 size_t size,
2688 size_t *poffset)
2689{
2690l_uint8 *data;
2691l_int32 retval;
2692size_t offset;
2693PIX *pix;
2694TIFF *tif;
2695
2696 PROCNAME("pixReadMemFromMultipageTiff");
2697
2698 if (!cdata)
2699 return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
2700 if (!poffset)
2701 return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);
2702
2703 data = (l_uint8 *)cdata; /* we're really not going to change this */
2704 if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2705 return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);
2706
2707 /* Set ptrs in the TIFF to the beginning of the image */
2708 offset = *poffset;
2709 retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
2710 : TIFFSetSubDirectory(tif, offset);
2711 if (retval == 0) {
2712 TIFFClose(tif);
2713 return NULL;
2714 }
2715
2716 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2717 TIFFClose(tif);
2718 return NULL;
2719 }
2720
2721 /* Advance to the next image and return the new offset */
2722 TIFFReadDirectory(tif);
2723 *poffset = TIFFCurrentDirOffset(tif);
2724 TIFFClose(tif);
2725 return pix;
2726}
2727
2728
2741PIXA *
2742pixaReadMemMultipageTiff(const l_uint8 *data,
2743 size_t size)
2744{
2745size_t offset;
2746PIX *pix;
2747PIXA *pixa;
2748
2749 PROCNAME("pixaReadMemMultipageTiff");
2750
2751 if (!data)
2752 return (PIXA *)ERROR_PTR("data not defined", procName, NULL);
2753
2754 offset = 0;
2755 pixa = pixaCreate(0);
2756 do {
2757 pix = pixReadMemFromMultipageTiff(data, size, &offset);
2758 pixaAddPix(pixa, pix, L_INSERT);
2759 } while (offset != 0);
2760 return pixa;
2761}
2762
2763
2781l_ok
2783 size_t *psize,
2784 PIXA *pixa)
2785{
2786const char *modestr;
2787l_int32 i, n;
2788FILE *fp;
2789PIX *pix1;
2790
2791 PROCNAME("pixaWriteMemMultipageTiff");
2792
2793 if (pdata) *pdata = NULL;
2794 if (!pdata)
2795 return ERROR_INT("pdata not defined", procName, 1);
2796 if (!pixa)
2797 return ERROR_INT("pixa not defined", procName, 1);
2798
2799#ifdef _WIN32
2800 if ((fp = fopenWriteWinTempfile()) == NULL)
2801 return ERROR_INT("tmpfile stream not opened", procName, 1);
2802#else
2803 if ((fp = tmpfile()) == NULL)
2804 return ERROR_INT("tmpfile stream not opened", procName, 1);
2805#endif /* _WIN32 */
2806
2807 n = pixaGetCount(pixa);
2808 for (i = 0; i < n; i++) {
2809 modestr = (i == 0) ? "w" : "a";
2810 pix1 = pixaGetPix(pixa, i, L_CLONE);
2811 if (pixGetDepth(pix1) == 1)
2812 pixWriteStreamTiffWA(fp, pix1, IFF_TIFF_G4, modestr);
2813 else
2814 pixWriteStreamTiffWA(fp, pix1, IFF_TIFF_ZIP, modestr);
2815 pixDestroy(&pix1);
2816 }
2817
2818 rewind(fp);
2819 *pdata = l_binaryReadStream(fp, psize);
2820 fclose(fp);
2821 return 0;
2822}
2823
2824
2840l_ok
2841pixWriteMemTiff(l_uint8 **pdata,
2842 size_t *psize,
2843 PIX *pix,
2844 l_int32 comptype)
2845{
2846 return pixWriteMemTiffCustom(pdata, psize, pix, comptype,
2847 NULL, NULL, NULL, NULL);
2848}
2849
2850
2871l_ok
2873 size_t *psize,
2874 PIX *pix,
2875 l_int32 comptype,
2876 NUMA *natags,
2877 SARRAY *savals,
2878 SARRAY *satypes,
2879 NUMA *nasizes)
2880{
2881l_int32 ret;
2882TIFF *tif;
2883
2884 PROCNAME("pixWriteMemTiffCustom");
2885
2886 if (!pdata)
2887 return ERROR_INT("&data not defined", procName, 1);
2888 if (!psize)
2889 return ERROR_INT("&size not defined", procName, 1);
2890 if (!pix)
2891 return ERROR_INT("&pix not defined", procName, 1);
2892 if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
2893 comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
2894 comptype != IFF_TIFF_JPEG) {
2895 L_WARNING("invalid compression type for bpp > 1\n", procName);
2896 comptype = IFF_TIFF_ZIP;
2897 }
2898
2899 if ((tif = fopenTiffMemstream("tifferror", "w", pdata, psize)) == NULL)
2900 return ERROR_INT("tiff stream not opened", procName, 1);
2901 ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
2902 satypes, nasizes);
2903
2904 TIFFClose(tif);
2905 return ret;
2906}
2907
2908/* --------------------------------------------*/
2909#endif /* HAVE_LIBTIFF */
2910/* --------------------------------------------*/
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:708
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
l_ok pixcmapToArrays(const PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:2068
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1699
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1536
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1512
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
PIX * pixEndianByteSwapNew(PIX *pixs)
pixEndianByteSwapNew()
Definition: pix2.c:3010
l_ok pixEndianTwoByteSwap(PIX *pixs)
pixEndianTwoByteSwap()
Definition: pix2.c:3239
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1382
l_ok composeRGBAPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval, l_uint32 *ppixel)
composeRGBAPixel()
Definition: pix2.c:2783
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
PIX * pixEndianTwoByteSwapNew(PIX *pixs)
pixEndianTwoByteSwapNew()
Definition: pix2.c:3185
l_ok pixEndianByteSwap(PIX *pixs)
pixEndianByteSwap()
Definition: pix2.c:3074
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
@ COLOR_BLUE
Definition: pix.h:206
@ COLOR_RED
Definition: pix.h:204
@ L_ALPHA_CHANNEL
Definition: pix.h:207
@ COLOR_GREEN
Definition: pix.h:205
@ REMOVE_CMAP_BASED_ON_SRC
Definition: pix.h:260
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:328
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:193
l_ok findFileFormat(const char *filename, l_int32 *pformat)
findFileFormat()
Definition: readfile.c:584
l_ok findFileFormatStream(FILE *fp, l_int32 *pformat)
findFileFormatStream()
Definition: readfile.c:619
l_int32 fileFormatIsTiff(FILE *fp)
fileFormatIsTiff()
Definition: readfile.c:800
PIX * pixRotate90(PIX *pixs, l_int32 direction)
pixRotate90()
Definition: rotateorth.c:166
PIX * pixFlipTB(PIX *pixd, PIX *pixs)
pixFlipTB()
Definition: rotateorth.c:605
PIX * pixFlipLR(PIX *pixd, PIX *pixs)
pixFlipLR()
Definition: rotateorth.c:427
SARRAY * getSortedPathnamesInDirectory(const char *dirname, const char *substr, l_int32 first, l_int32 nfiles)
getSortedPathnamesInDirectory()
Definition: sarray1.c:1848
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
Memory stream buffer used with TIFFClientOpen()
Definition: tiffio.c:2347
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
Definition: array.h:127
static l_int32 tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
tiffReadHeaderTiff()
Definition: tiffio.c:1972
static TIFF * fopenTiffMemstream(const char *filename, const char *operation, l_uint8 **pdata, size_t *pdatasize)
fopenTiffMemstream()
Definition: tiffio.c:2560
l_ok pixaWriteMemMultipageTiff(l_uint8 **pdata, size_t *psize, PIXA *pixa)
pixaWriteMemMultipageTiff()
Definition: tiffio.c:2782
l_ok fprintTiffInfo(FILE *fpout, const char *tiffile)
fprintTiffInfo()
Definition: tiffio.c:1604
PIX * pixReadTiff(const char *filename, l_int32 n)
pixReadTiff()
Definition: tiffio.c:383
PIXA * pixaReadMultipageTiff(const char *filename)
pixaReadMultipageTiff()
Definition: tiffio.c:1401
l_ok pixWriteStreamTiffWA(FILE *fp, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteStreamTiffWA()
Definition: tiffio.c:936
static TIFF * openTiff(const char *filename, const char *modestring)
openTiff()
Definition: tiffio.c:2289
l_ok readHeaderTiff(const char *filename, l_int32 n, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
readHeaderTiff()
Definition: tiffio.c:1787
l_ok readHeaderMemTiff(const l_uint8 *cdata, size_t size, l_int32 n, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
readHeaderMemTiff()
Definition: tiffio.c:1911
l_ok pixWriteMemTiffCustom(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteMemTiffCustom()
Definition: tiffio.c:2872
l_ok findTiffCompression(FILE *fp, l_int32 *pcomptype)
findTiffCompression()
Definition: tiffio.c:2044
static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
writeCustomTiffTags()
Definition: tiffio.c:1224
PIX * pixReadFromMultipageTiff(const char *fname, size_t *poffset)
pixReadFromMultipageTiff()
Definition: tiffio.c:1352
l_ok getTiffResolution(FILE *fp, l_int32 *pxres, l_int32 *pyres)
getTiffResolution()
Definition: tiffio.c:1685
PIX * pixReadStreamTiff(FILE *fp, l_int32 n)
pixReadStreamTiff()
Definition: tiffio.c:420
static PIX * pixReadFromTiffStream(TIFF *tif)
pixReadFromTiffStream()
Definition: tiffio.c:485
PIXA * pixaReadMemMultipageTiff(const l_uint8 *data, size_t size)
pixaReadMemMultipageTiff()
Definition: tiffio.c:2742
l_ok pixWriteTiff(const char *filename, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteTiff()
Definition: tiffio.c:795
l_ok writeMultipageTiff(const char *dirin, const char *substr, const char *fileout)
writeMultipageTiff()
Definition: tiffio.c:1515
l_ok pixWriteTiffCustom(const char *filename, PIX *pix, l_int32 comptype, const char *modestr, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteTiffCustom()
Definition: tiffio.c:852
PIX * pixReadMemFromMultipageTiff(const l_uint8 *cdata, size_t size, size_t *poffset)
pixReadMemFromMultipageTiff()
Definition: tiffio.c:2686
static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteToTiffStream()
Definition: tiffio.c:1011
l_ok pixWriteStreamTiff(FILE *fp, PIX *pix, l_int32 comptype)
pixWriteStreamTiff()
Definition: tiffio.c:911
PIX * pixReadMemTiff(const l_uint8 *cdata, size_t size, l_int32 n)
pixReadMemTiff()
Definition: tiffio.c:2621
l_ok writeMultipageTiffSA(SARRAY *sa, const char *fileout)
writeMultipageTiffSA()
Definition: tiffio.c:1551
l_ok pixWriteMemTiff(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype)
pixWriteMemTiff()
Definition: tiffio.c:2841
static TIFF * fopenTiff(FILE *fp, const char *modestring)
fopenTiff()
Definition: tiffio.c:2253
l_ok pixaWriteMultipageTiff(const char *fname, PIXA *pixa)
pixaWriteMultipageTiff()
Definition: tiffio.c:1461
static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp)
getTiffCompressedFormat()
Definition: tiffio.c:2082
l_ok tiffGetCount(FILE *fp, l_int32 *pn)
tiffGetCount()
Definition: tiffio.c:1637
static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres, l_int32 *pyres)
getTiffStreamResolution()
Definition: tiffio.c:1721
l_ok freadHeaderTiff(FILE *fp, l_int32 n, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pres, l_int32 *pcmap, l_int32 *pformat)
freadHeaderTiff()
Definition: tiffio.c:1843
l_ok extractG4DataFromFile(const char *filein, l_uint8 **pdata, size_t *pnbytes, l_int32 *pw, l_int32 *ph, l_int32 *pminisblack)
extractG4DataFromFile()
Definition: tiffio.c:2132
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
FILE * fopenWriteWinTempfile(void)
fopenWriteWinTempfile()
Definition: utils2.c:2055
char * genPathname(const char *dir, const char *fname)
genPathname()
Definition: utils2.c:3173
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1352
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402
void * reallocNew(void **pindata, size_t oldsize, size_t newsize)
reallocNew()
Definition: utils2.c:1302