Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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
118#ifdef HAVE_CONFIG_H
119#include <config_auto.h>
120#endif /* HAVE_CONFIG_H */
121
122#include <string.h>
123#include <math.h> /* for isnan */
124#include <sys/types.h>
125#ifndef _MSC_VER
126#include <unistd.h>
127#else /* _MSC_VER */
128#include <io.h>
129#endif /* _MSC_VER */
130#include <fcntl.h>
131#include "allheaders.h"
132
133/* ---------------------------------------------------------*/
134#if HAVE_LIBTIFF && HAVE_LIBJPEG /* defined in environ.h */
135/* ---------------------------------------------------------*/
136
137#include "tiff.h"
138#include "tiffio.h"
139
140static const l_int32 DefaultResolution = 300; /* ppi */
141static const l_int32 ManyPagesInTiffFile = 3000; /* warn if big */
142
143 /* Verified that tiflib makes valid g4 files of this size */
144static const l_int32 MaxTiffWidth = 1 << 20; /* 1M pixels */
145static const l_int32 MaxTiffHeight = 1 << 20; /* 1M pixels */
146
147 /* Check g4 data size */
148static const size_t MaxNumTiffBytes = (1 << 28) - 1; /* 256 MB */
149
150 /* All functions with TIFF interfaces are static. */
151static PIX *pixReadFromTiffStream(TIFF *tif);
152static l_int32 getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
153 l_int32 *pyres);
154static l_int32 tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
155 l_int32 *pheight, l_int32 *pbps,
156 l_int32 *pspp, l_int32 *pres,
157 l_int32 *pcmap, l_int32 *pformat);
158static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags,
159 SARRAY *savals, SARRAY *satypes,
160 NUMA *nasizes);
161static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
162 NUMA *natags, SARRAY *savals,
163 SARRAY *satypes, NUMA *nasizes);
164static TIFF *fopenTiff(FILE *fp, const char *modestring);
165static TIFF *openTiff(const char *filename, const char *modestring);
166
167 /* Static helper for tiff compression type */
168static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp);
169
170 /* Static function for memory I/O */
171static TIFF *fopenTiffMemstream(const char *filename, const char *operation,
172 l_uint8 **pdata, size_t *pdatasize);
173
174 /* This structure defines a transform to be performed on a TIFF image
175 * (note that the same transformation can be represented in
176 * several different ways using this structure since
177 * vflip + hflip + counterclockwise == clockwise). */
179 int vflip; /* if non-zero, image needs a vertical fip */
180 int hflip; /* if non-zero, image needs a horizontal flip */
181 int rotate; /* -1 -> counterclockwise 90-degree rotation,
182 0 -> no rotation
183 1 -> clockwise 90-degree rotation */
184};
185
186 /* This describes the transformations needed for a given orientation
187 * tag. The tag values start at 1, so you need to subtract 1 to get a
188 * valid index into this array. It is only valid when not using
189 * TIFFReadRGBAImageOriented(). */
190static struct tiff_transform tiff_orientation_transforms[] = {
191 {0, 0, 0},
192 {0, 1, 0},
193 {1, 1, 0},
194 {1, 0, 0},
195 {0, 1, -1},
196 {0, 0, 1},
197 {0, 1, 1},
198 {0, 0, -1}
199};
200
201 /* Same as above, except that test transformations are only valid
202 * when using TIFFReadRGBAImageOriented(). Transformations
203 * were determined empirically. See the libtiff mailing list for
204 * more discussion: http://www.asmail.be/msg0054683875.html */
205static struct tiff_transform tiff_partial_orientation_transforms[] = {
206 {0, 0, 0},
207 {0, 0, 0},
208 {0, 0, 0},
209 {0, 0, 0},
210 {0, 1, -1},
211 {0, 1, 1},
212 {1, 0, 1},
213 {0, 1, -1}
214};
215
216
217/*-----------------------------------------------------------------------*
218 * TIFFClientOpen() wrappers for FILE* *
219 * Provided by Jürgen Buchmüller *
220 * *
221 * We previously used TIFFFdOpen(), which used low-level file *
222 * descriptors. It had portability issues with Windows, along *
223 * with other limitations from lack of stream control operations. *
224 * These callbacks to TIFFClientOpen() avoid the problems. *
225 * *
226 * Jürgen made the functions use 64 bit file operations where possible *
227 * or required, namely for seek and size. On Windows there are specific *
228 * _fseeki64() and _ftelli64() functions. On unix it is common to look *
229 * for a macro _LARGEFILE64_SOURCE being defined, which makes available *
230 * the off64_t type, and to use fseeko() and ftello() in this case. *
231 *-----------------------------------------------------------------------*/
232static tsize_t
233lept_read_proc(thandle_t cookie,
234 tdata_t buff,
235 tsize_t size)
236{
237 FILE* fp = (FILE *)cookie;
238 tsize_t done;
239 if (!buff || !cookie || !fp)
240 return (tsize_t)-1;
241 done = fread(buff, 1, size, fp);
242 return done;
243}
244
245static tsize_t
246lept_write_proc(thandle_t cookie,
247 tdata_t buff,
248 tsize_t size)
249{
250 FILE* fp = (FILE *)cookie;
251 tsize_t done;
252 if (!buff || !cookie || !fp)
253 return (tsize_t)-1;
254 done = fwrite(buff, 1, size, fp);
255 return done;
256}
257
258static toff_t
259lept_seek_proc(thandle_t cookie,
260 toff_t offs,
261 int whence)
262{
263 FILE* fp = (FILE *)cookie;
264#if defined(_MSC_VER)
265 __int64 pos = 0;
266 if (!cookie || !fp)
267 return (tsize_t)-1;
268 switch (whence) {
269 case SEEK_SET:
270 pos = 0;
271 break;
272 case SEEK_CUR:
273 pos = ftell(fp);
274 break;
275 case SEEK_END:
276 _fseeki64(fp, 0, SEEK_END);
277 pos = _ftelli64(fp);
278 break;
279 }
280 pos = (__int64)(pos + offs);
281 _fseeki64(fp, pos, SEEK_SET);
282 if (pos == _ftelli64(fp))
283 return (tsize_t)pos;
284#elif defined(_LARGEFILE64_SOURCE)
285 off64_t pos = 0;
286 if (!cookie || !fp)
287 return (tsize_t)-1;
288 switch (whence) {
289 case SEEK_SET:
290 pos = 0;
291 break;
292 case SEEK_CUR:
293 pos = ftello(fp);
294 break;
295 case SEEK_END:
296 fseeko(fp, 0, SEEK_END);
297 pos = ftello(fp);
298 break;
299 }
300 pos = (off64_t)(pos + offs);
301 fseeko(fp, pos, SEEK_SET);
302 if (pos == ftello(fp))
303 return (tsize_t)pos;
304#else
305 off_t pos = 0;
306 if (!cookie || !fp)
307 return (tsize_t)-1;
308 switch (whence) {
309 case SEEK_SET:
310 pos = 0;
311 break;
312 case SEEK_CUR:
313 pos = ftell(fp);
314 break;
315 case SEEK_END:
316 fseek(fp, 0, SEEK_END);
317 pos = ftell(fp);
318 break;
319 }
320 pos = (off_t)(pos + offs);
321 fseek(fp, pos, SEEK_SET);
322 if (pos == ftell(fp))
323 return (tsize_t)pos;
324#endif
325 return (tsize_t)-1;
326}
327
328static int
329lept_close_proc(thandle_t cookie)
330{
331 FILE* fp = (FILE *)cookie;
332 if (!cookie || !fp)
333 return 0;
334 fseek(fp, 0, SEEK_SET);
335 return 0;
336}
337
338static toff_t
339lept_size_proc(thandle_t cookie)
340{
341 FILE* fp = (FILE *)cookie;
342#if defined(_MSC_VER)
343 __int64 pos;
344 __int64 size;
345 if (!cookie || !fp)
346 return (tsize_t)-1;
347 pos = _ftelli64(fp);
348 _fseeki64(fp, 0, SEEK_END);
349 size = _ftelli64(fp);
350 _fseeki64(fp, pos, SEEK_SET);
351#elif defined(_LARGEFILE64_SOURCE)
352 off64_t pos;
353 off64_t size;
354 if (!fp)
355 return (tsize_t)-1;
356 pos = ftello(fp);
357 fseeko(fp, 0, SEEK_END);
358 size = ftello(fp);
359 fseeko(fp, pos, SEEK_SET);
360#else
361 off_t pos;
362 off_t size;
363 if (!cookie || !fp)
364 return (tsize_t)-1;
365 pos = ftell(fp);
366 fseek(fp, 0, SEEK_END);
367 size = ftell(fp);
368 fseek(fp, pos, SEEK_SET);
369#endif
370 return (toff_t)size;
371}
372
373
374/*--------------------------------------------------------------*
375 * Reading from file *
376 *--------------------------------------------------------------*/
393PIX *
394pixReadTiff(const char *filename,
395 l_int32 n)
396{
397FILE *fp;
398PIX *pix;
399
400 if (!filename)
401 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL);
402
403 if ((fp = fopenReadStream(filename)) == NULL)
404 return (PIX *)ERROR_PTR_1("image file not found",
405 filename, __func__, NULL);
406 pix = pixReadStreamTiff(fp, n);
407 fclose(fp);
408 return pix;
409}
410
411
412/*--------------------------------------------------------------*
413 * Reading from stream *
414 *--------------------------------------------------------------*/
429PIX *
431 l_int32 n)
432{
433PIX *pix;
434TIFF *tif;
435
436 if (!fp)
437 return (PIX *)ERROR_PTR("stream not defined", __func__, NULL);
438
439 if ((tif = fopenTiff(fp, "r")) == NULL)
440 return (PIX *)ERROR_PTR("tif not opened", __func__, NULL);
441
442 if (TIFFSetDirectory(tif, n) == 0) {
443 TIFFCleanup(tif);
444 return NULL;
445 }
446 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
447 TIFFCleanup(tif);
448 return NULL;
449 }
450 TIFFCleanup(tif);
451 return pix;
452}
453
454
497static PIX *
499{
500char *text;
501l_uint8 *linebuf, *data, *rowptr;
502l_uint16 spp, bps, photometry, tiffcomp, orientation, sample_fmt;
503l_uint16 *redmap, *greenmap, *bluemap;
504l_int32 d, wpl, bpl, comptype, i, j, k, ncolors, rval, gval, bval, aval;
505l_int32 xres, yres, tiffbpl, packedbpl, half_size, twothirds_size;
506l_uint32 w, h, tiffword, read_oriented;
507l_uint32 *line, *ppixel, *tiffdata, *pixdata;
508PIX *pix, *pix1;
509PIXCMAP *cmap;
510
511 if (!tif)
512 return (PIX *)ERROR_PTR("tif not defined", __func__, NULL);
513
514 read_oriented = 0;
515
516 /* Only accept uint image data:
517 * SAMPLEFORMAT_UINT = 1;
518 * SAMPLEFORMAT_INT = 2;
519 * SAMPLEFORMAT_IEEEFP = 3;
520 * SAMPLEFORMAT_VOID = 4; */
521 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_fmt);
522 if (sample_fmt != SAMPLEFORMAT_UINT) {
523 L_ERROR("sample format = %d is not uint\n", __func__, sample_fmt);
524 return NULL;
525 }
526
527 /* Can't read tiff in tiled format. For what is involved, see, e.g:
528 * https://www.cs.rochester.edu/~nelson/courses/vision/\
529 * resources/tiff/libtiff.html#Tiles
530 * A tiled tiff can be converted to a normal (strip) tif:
531 * tiffcp -s <input-tiled-tif> <output-strip-tif> */
532 if (TIFFIsTiled(tif)) {
533 L_ERROR("tiled format is not supported\n", __func__);
534 return NULL;
535 }
536
537 /* Old style jpeg is not supported. We tried supporting 8 bpp.
538 * TIFFReadScanline() fails on this format, so we used RGBA
539 * reading, which generates a 4 spp image, and pulled out the
540 * red component. However, there were problems with double-frees
541 * in cleanup. For RGB, tiffbpl is exactly half the size that
542 * you would expect for the raster data in a scanline, which
543 * is 3 * w. */
544 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
545 if (tiffcomp == COMPRESSION_OJPEG) {
546 L_ERROR("old style jpeg format is not supported\n", __func__);
547 return NULL;
548 }
549
550 /* webp in tiff is in 4.1.0 and not yet supported in Adobe registry */
551#if defined(COMPRESSION_WEBP)
552 if (tiffcomp == COMPRESSION_WEBP) {
553 L_ERROR("webp in tiff not generally supported yet\n", __func__);
554 return NULL;
555 }
556#endif /* COMPRESSION_WEBP */
557
558 /* Use default fields for bps and spp */
559 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
560 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
561 if (bps != 1 && bps != 2 && bps != 4 && bps != 8 && bps != 16) {
562 L_ERROR("invalid bps = %d\n", __func__, bps);
563 return NULL;
564 }
565 if (spp == 2 && bps != 8) {
566 L_ERROR("for 2 spp, only handle 8 bps; this is %d bps\n",
567 __func__, bps);
568 return NULL;
569 }
570 if ((spp == 3 || spp == 4) && bps < 8) {
571 L_ERROR("for 3 and 4 spp, only handle 8 and 16 bps; this is %d bps\n",
572 __func__, bps);
573 return NULL;
574 }
575 if (spp == 1) {
576 d = bps;
577 } else if (spp == 2) { /* gray plus alpha */
578 d = 32; /* will convert to RGBA */
579 } else if (spp == 3 || spp == 4) {
580 d = 32;
581 } else {
582 L_ERROR("spp = %d; not in {1,2,3,4}\n", __func__, spp);
583 return NULL;
584 }
585
586 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
587 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
588 if (w > MaxTiffWidth) {
589 L_ERROR("width = %d pixels; too large\n", __func__, w);
590 return NULL;
591 }
592 if (h > MaxTiffHeight) {
593 L_ERROR("height = %d pixels; too large\n", __func__, h);
594 return NULL;
595 }
596
597 /* The relation between the size of a byte buffer required to hold
598 a raster of image pixels (packedbpl) and the size of the tiff
599 buffer (tiffbuf) is either 1:1 or approximately 1.5:1 or 2:1,
600 depending on how the data is stored and subsampled. For security,
601 we test this relation between tiffbuf and the image parameters
602 w, spp and bps. */
603 tiffbpl = TIFFScanlineSize(tif);
604 packedbpl = (bps * spp * w + 7) / 8;
605 half_size = (L_ABS(2 * tiffbpl - packedbpl) <= 8);
606 twothirds_size = (L_ABS(3 * tiffbpl - 2 * packedbpl) <= 8);
607#if 0
608 if (half_size)
609 L_INFO("half_size: packedbpl = %d is approx. twice tiffbpl = %d\n",
610 __func__, packedbpl, tiffbpl);
611 if (twothirds_size)
612 L_INFO("twothirds_size: packedbpl = %d is approx. 1.5 tiffbpl = %d\n",
613 __func__, packedbpl, tiffbpl);
614 lept_stderr("tiffbpl = %d, packedbpl = %d, bps = %d, spp = %d, w = %d\n",
615 tiffbpl, packedbpl, bps, spp, w);
616#endif
617 if (tiffbpl != packedbpl && !half_size && !twothirds_size) {
618 L_ERROR("invalid tiffbpl: tiffbpl = %d, packedbpl = %d, "
619 "bps = %d, spp = %d, w = %d\n",
620 __func__, tiffbpl, packedbpl, bps, spp, w);
621 return NULL;
622 }
623
624 /* Use a linebuf that will hold all the pixels generated
625 by tiff when reading (decompressing) a scanline. */
626 if ((pix = pixCreate(w, h, d)) == NULL)
627 return (PIX *)ERROR_PTR("pix not made", __func__, NULL);
628 pixSetInputFormat(pix, IFF_TIFF);
629 data = (l_uint8 *)pixGetData(pix);
630 wpl = pixGetWpl(pix);
631 bpl = 4 * wpl;
632 if (spp == 1) {
633 linebuf = (l_uint8 *)LEPT_CALLOC(4 * wpl, sizeof(l_uint8));
634 for (i = 0; i < h; i++) {
635 if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
636 LEPT_FREE(linebuf);
637 pixDestroy(&pix);
638 L_ERROR("spp = 1, read fail at line %d\n", __func__, i);
639 return NULL;
640 }
641 memcpy(data, linebuf, tiffbpl);
642 data += bpl;
643 }
644 if (bps <= 8)
645 pixEndianByteSwap(pix);
646 else /* bps == 16 */
647 pixEndianTwoByteSwap(pix);
648 LEPT_FREE(linebuf);
649 } else if (spp == 2 && bps == 8) { /* gray plus alpha */
650 L_INFO("gray+alpha is not supported; converting to RGBA\n", __func__);
651 pixSetSpp(pix, 4);
652 linebuf = (l_uint8 *)LEPT_CALLOC(4 * wpl, sizeof(l_uint8));
653 pixdata = pixGetData(pix);
654 for (i = 0; i < h; i++) {
655 if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
656 LEPT_FREE(linebuf);
657 pixDestroy(&pix);
658 L_ERROR("spp = 2, read fail at line %d\n", __func__, i);
659 return NULL;
660 }
661 rowptr = linebuf;
662 ppixel = pixdata + i * wpl;
663 for (j = k = 0; j < w; j++) {
664 /* Copy gray value into r, g and b */
665 SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k]);
666 SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k]);
667 SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
668 SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
669 ppixel++;
670 }
671 }
672 LEPT_FREE(linebuf);
673 } else { /* rgb and rgba */
674 if ((tiffdata = (l_uint32 *)LEPT_CALLOC((size_t)w * h,
675 sizeof(l_uint32))) == NULL) {
676 pixDestroy(&pix);
677 return (PIX *)ERROR_PTR("calloc fail for tiffdata", __func__, NULL);
678 }
679 /* TIFFReadRGBAImageOriented() converts to 8 bps */
680 if (!TIFFReadRGBAImageOriented(tif, w, h, tiffdata,
681 ORIENTATION_TOPLEFT, 0)) {
682 LEPT_FREE(tiffdata);
683 pixDestroy(&pix);
684 return (PIX *)ERROR_PTR("failed to read tiffdata", __func__, NULL);
685 } else {
686 read_oriented = 1;
687 }
688
689 if (spp == 4) pixSetSpp(pix, 4);
690 line = pixGetData(pix);
691 for (i = 0; i < h; i++, line += wpl) {
692 for (j = 0, ppixel = line; j < w; j++) {
693 /* TIFFGet* are macros */
694 tiffword = tiffdata[i * w + j];
695 rval = TIFFGetR(tiffword);
696 gval = TIFFGetG(tiffword);
697 bval = TIFFGetB(tiffword);
698 if (spp == 3) {
699 composeRGBPixel(rval, gval, bval, ppixel);
700 } else { /* spp == 4 */
701 aval = TIFFGetA(tiffword);
702 composeRGBAPixel(rval, gval, bval, aval, ppixel);
703 }
704 ppixel++;
705 }
706 }
707 LEPT_FREE(tiffdata);
708 }
709
710 if (getTiffStreamResolution(tif, &xres, &yres) == 0) {
711 pixSetXRes(pix, xres);
712 pixSetYRes(pix, yres);
713 }
714
715 /* Find and save the compression type */
716 comptype = getTiffCompressedFormat(tiffcomp);
717 pixSetInputFormat(pix, comptype);
718
719 if (TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap)) {
720 /* Save the colormap as a pix cmap. Because the
721 * tiff colormap components are 16 bit unsigned,
722 * and go from black (0) to white (0xffff), the
723 * the pix cmap takes the most significant byte. */
724 if (bps > 8) {
725 pixDestroy(&pix);
726 return (PIX *)ERROR_PTR("colormap size > 256", __func__, NULL);
727 }
728 if ((cmap = pixcmapCreate(bps)) == NULL) {
729 pixDestroy(&pix);
730 return (PIX *)ERROR_PTR("colormap not made", __func__, NULL);
731 }
732 ncolors = 1 << bps;
733 for (i = 0; i < ncolors; i++)
734 pixcmapAddColor(cmap, redmap[i] >> 8, greenmap[i] >> 8,
735 bluemap[i] >> 8);
736 if (pixSetColormap(pix, cmap)) {
737 pixDestroy(&pix);
738 return (PIX *)ERROR_PTR("invalid colormap", __func__, NULL);
739 }
740
741 /* Remove the colormap for 1 bpp. */
742 if (bps == 1) {
743 pix1 = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
744 pixDestroy(&pix);
745 pix = pix1;
746 }
747 } else { /* No colormap: check photometry and invert if necessary */
748 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometry)) {
749 /* Guess default photometry setting. Assume min_is_white
750 * if compressed 1 bpp; min_is_black otherwise. */
751 if (tiffcomp == COMPRESSION_CCITTFAX3 ||
752 tiffcomp == COMPRESSION_CCITTFAX4 ||
753 tiffcomp == COMPRESSION_CCITTRLE ||
754 tiffcomp == COMPRESSION_CCITTRLEW) {
755 photometry = PHOTOMETRIC_MINISWHITE;
756 } else {
757 photometry = PHOTOMETRIC_MINISBLACK;
758 }
759 }
760 if ((d == 1 && photometry == PHOTOMETRIC_MINISBLACK) ||
761 (d == 8 && photometry == PHOTOMETRIC_MINISWHITE))
762 pixInvert(pix, pix);
763 }
764
765 if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
766 if (orientation >= 1 && orientation <= 8) {
767 struct tiff_transform *transform = (read_oriented) ?
768 &tiff_partial_orientation_transforms[orientation - 1] :
769 &tiff_orientation_transforms[orientation - 1];
770 if (transform->vflip) pixFlipTB(pix, pix);
771 if (transform->hflip) pixFlipLR(pix, pix);
772 if (transform->rotate) {
773 PIX *oldpix = pix;
774 pix = pixRotate90(oldpix, transform->rotate);
775 pixDestroy(&oldpix);
776 }
777 }
778 }
779
780 text = NULL;
781 TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &text);
782 if (text) pixSetText(pix, text);
783 return pix;
784}
785
786
787/*--------------------------------------------------------------*
788 * Writing to file *
789 *--------------------------------------------------------------*/
811l_ok
812pixWriteTiff(const char *filename,
813 PIX *pix,
814 l_int32 comptype,
815 const char *modestr)
816{
817 return pixWriteTiffCustom(filename, pix, comptype, modestr,
818 NULL, NULL, NULL, NULL);
819}
820
821
868l_ok
869pixWriteTiffCustom(const char *filename,
870 PIX *pix,
871 l_int32 comptype,
872 const char *modestr,
873 NUMA *natags,
874 SARRAY *savals,
875 SARRAY *satypes,
876 NUMA *nasizes)
877{
878l_int32 ret;
879TIFF *tif;
880
881 if (!filename)
882 return ERROR_INT("filename not defined", __func__, 1);
883 if (!pix)
884 return ERROR_INT("pix not defined", __func__, 1);
885
886 if ((tif = openTiff(filename, modestr)) == NULL)
887 return ERROR_INT("tif not opened", __func__, 1);
888 ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
889 satypes, nasizes);
890 TIFFClose(tif);
891 return ret;
892}
893
894
895/*--------------------------------------------------------------*
896 * Writing to stream *
897 *--------------------------------------------------------------*/
925l_ok
927 PIX *pix,
928 l_int32 comptype)
929{
930 return pixWriteStreamTiffWA(fp, pix, comptype, "w");
931}
932
933
950l_ok
952 PIX *pix,
953 l_int32 comptype,
954 const char *modestr)
955{
956TIFF *tif;
957
958 if (!fp)
959 return ERROR_INT("stream not defined", __func__, 1 );
960 if (!pix)
961 return ERROR_INT("pix not defined", __func__, 1 );
962 if (strcmp(modestr, "w") && strcmp(modestr, "a")) {
963 L_ERROR("modestr = %s; not 'w' or 'a'\n", __func__, modestr);
964 return 1;
965 }
966
967 if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
968 comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
969 comptype != IFF_TIFF_JPEG) {
970 L_WARNING("invalid compression type %d for bpp > 1; using TIFF_ZIP\n",
971 __func__, comptype);
972 comptype = IFF_TIFF_ZIP;
973 }
974
975 if ((tif = fopenTiff(fp, modestr)) == NULL)
976 return ERROR_INT("tif not opened", __func__, 1);
977
978 if (pixWriteToTiffStream(tif, pix, comptype, NULL, NULL, NULL, NULL)) {
979 TIFFCleanup(tif);
980 return ERROR_INT("tif write error", __func__, 1);
981 }
982
983 TIFFCleanup(tif);
984 return 0;
985}
986
987
1023static l_int32
1025 PIX *pix,
1026 l_int32 comptype,
1027 NUMA *natags,
1028 SARRAY *savals,
1029 SARRAY *satypes,
1030 NUMA *nasizes)
1031{
1032l_uint8 *linebuf, *data;
1033l_uint16 redmap[256], greenmap[256], bluemap[256];
1034l_int32 w, h, d, spp, i, j, k, wpl, bpl, tiffbpl, ncolors, cmapsize;
1035l_int32 *rmap, *gmap, *bmap;
1036l_int32 xres, yres;
1037l_uint32 *line, *ppixel;
1038PIX *pixt;
1039PIXCMAP *cmap;
1040char *text;
1041
1042 if (!tif)
1043 return ERROR_INT("tif stream not defined", __func__, 1);
1044 if (!pix)
1045 return ERROR_INT( "pix not defined", __func__, 1 );
1046
1047 pixSetPadBits(pix, 0);
1048 pixGetDimensions(pix, &w, &h, &d);
1049 spp = pixGetSpp(pix);
1050 xres = pixGetXRes(pix);
1051 yres = pixGetYRes(pix);
1052 if (xres == 0) xres = DefaultResolution;
1053 if (yres == 0) yres = DefaultResolution;
1054
1055 /* ------------------ Write out the header ------------- */
1056 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (l_uint32)RESUNIT_INCH);
1057 TIFFSetField(tif, TIFFTAG_XRESOLUTION, (l_float64)xres);
1058 TIFFSetField(tif, TIFFTAG_YRESOLUTION, (l_float64)yres);
1059
1060 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (l_uint32)w);
1061 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (l_uint32)h);
1062 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
1063
1064 if ((text = pixGetText(pix)) != NULL)
1065 TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, text);
1066
1067 if (d == 1 && !pixGetColormap(pix)) {
1068 /* If d == 1, preserve the colormap. Note that when
1069 * d == 1 pix with colormaps are read, the colormaps
1070 * are removed. The only pix in leptonica that have
1071 * colormaps are made programmatically. */
1072 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
1073 } else if ((d == 32 && spp == 3) || d == 24) {
1074 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
1075 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)3);
1076 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
1077 (l_uint16)8, (l_uint16)8, (l_uint16)8);
1078 } else if (d == 32 && spp == 4) {
1079 l_uint16 val[1];
1080 val[0] = EXTRASAMPLE_ASSOCALPHA;
1081 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, (l_uint16)1, &val);
1082 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
1083 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)4);
1084 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
1085 (l_uint16)8, (l_uint16)8, (l_uint16)8, (l_uint16)8);
1086 } else if (d == 16) { /* we only support spp = 1, bps = 16 */
1087 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
1088 } else if ((cmap = pixGetColormap(pix)) == NULL) {
1089 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
1090 } else { /* Save colormap in the tiff; not more than 256 colors */
1091 if (d > 8) {
1092 L_ERROR("d = %d > 8 with colormap!; reducing to 8\n", __func__, d);
1093 d = 8;
1094 }
1095 pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
1096 ncolors = pixcmapGetCount(cmap);
1097 ncolors = L_MIN(256, ncolors); /* max 256 */
1098 cmapsize = 1 << d;
1099 cmapsize = L_MIN(256, cmapsize); /* power of 2; max 256 */
1100 if (ncolors > cmapsize) {
1101 L_WARNING("too many colors in cmap for tiff; truncating\n",
1102 __func__);
1103 ncolors = cmapsize;
1104 }
1105 for (i = 0; i < ncolors; i++) {
1106 redmap[i] = (rmap[i] << 8) | rmap[i];
1107 greenmap[i] = (gmap[i] << 8) | gmap[i];
1108 bluemap[i] = (bmap[i] << 8) | bmap[i];
1109 }
1110 for (i = ncolors; i < cmapsize; i++) /* init, even though not used */
1111 redmap[i] = greenmap[i] = bluemap[i] = 0;
1112 LEPT_FREE(rmap);
1113 LEPT_FREE(gmap);
1114 LEPT_FREE(bmap);
1115
1116 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
1117 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
1118 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
1119 TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
1120 }
1121
1122 if (d <= 16) {
1123 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
1124 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
1125 }
1126
1127 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
1128 if (comptype == IFF_TIFF) { /* no compression */
1129 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
1130 } else if (comptype == IFF_TIFF_G4) {
1131 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
1132 } else if (comptype == IFF_TIFF_G3) {
1133 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
1134 } else if (comptype == IFF_TIFF_RLE) {
1135 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);
1136 } else if (comptype == IFF_TIFF_PACKBITS) {
1137 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
1138 } else if (comptype == IFF_TIFF_LZW) {
1139 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
1140 } else if (comptype == IFF_TIFF_ZIP) {
1141 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
1142 } else if (comptype == IFF_TIFF_JPEG) {
1143 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
1144 } else {
1145 L_WARNING("unknown tiff compression; using none\n", __func__);
1146 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
1147 }
1148
1149 /* This is a no-op if arrays are NULL */
1150 writeCustomTiffTags(tif, natags, savals, satypes, nasizes);
1151
1152 /* ------------- Write out the image data ------------- */
1153 tiffbpl = TIFFScanlineSize(tif);
1154 wpl = pixGetWpl(pix);
1155 bpl = 4 * wpl;
1156 if (tiffbpl > bpl)
1157 lept_stderr("Big trouble: tiffbpl = %d, bpl = %d\n", tiffbpl, bpl);
1158 if ((linebuf = (l_uint8 *)LEPT_CALLOC(1, bpl)) == NULL)
1159 return ERROR_INT("calloc fail for linebuf", __func__, 1);
1160
1161 /* Use single strip for image */
1162 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);
1163
1164 if (d != 24 && d != 32) {
1165 if (d == 16)
1166 pixt = pixEndianTwoByteSwapNew(pix);
1167 else
1168 pixt = pixEndianByteSwapNew(pix);
1169 data = (l_uint8 *)pixGetData(pixt);
1170 for (i = 0; i < h; i++, data += bpl) {
1171 memcpy(linebuf, data, tiffbpl);
1172 if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1173 break;
1174 }
1175 pixDestroy(&pixt);
1176 } else if (d == 24) { /* See note 4 above: special case of 24 bpp rgb */
1177 for (i = 0; i < h; i++) {
1178 line = pixGetData(pix) + i * wpl;
1179 if (TIFFWriteScanline(tif, (l_uint8 *)line, i, 0) < 0)
1180 break;
1181 }
1182 } else { /* 32 bpp rgb or rgba */
1183 for (i = 0; i < h; i++) {
1184 line = pixGetData(pix) + i * wpl;
1185 for (j = 0, k = 0, ppixel = line; j < w; j++) {
1186 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
1187 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
1188 linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
1189 if (spp == 4)
1190 linebuf[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
1191 ppixel++;
1192 }
1193 if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
1194 break;
1195 }
1196 }
1197
1198/* TIFFWriteDirectory(tif); */
1199 LEPT_FREE(linebuf);
1200
1201 return 0;
1202}
1203
1204
1234static l_int32
1236 NUMA *natags,
1237 SARRAY *savals,
1238 SARRAY *satypes,
1239 NUMA *nasizes)
1240{
1241char *sval, *type;
1242l_int32 i, n, ns, size, tagval, val;
1243l_float64 dval;
1244l_uint32 uval, uval2;
1245
1246 if (!tif)
1247 return ERROR_INT("tif stream not defined", __func__, 1);
1248 if (!natags && !savals && !satypes)
1249 return 0;
1250 if (!natags || !savals || !satypes)
1251 return ERROR_INT("not all arrays defined", __func__, 1);
1252 n = numaGetCount(natags);
1253 if ((sarrayGetCount(savals) != n) || (sarrayGetCount(satypes) != n))
1254 return ERROR_INT("not all sa the same size", __func__, 1);
1255
1256 /* The sized arrays (4 args to TIFFSetField) are written first */
1257 if (nasizes) {
1258 ns = numaGetCount(nasizes);
1259 if (ns > n)
1260 return ERROR_INT("too many 4-arg tag calls", __func__, 1);
1261 for (i = 0; i < ns; i++) {
1262 numaGetIValue(natags, i, &tagval);
1263 sval = sarrayGetString(savals, i, L_NOCOPY);
1264 type = sarrayGetString(satypes, i, L_NOCOPY);
1265 numaGetIValue(nasizes, i, &size);
1266 if (strcmp(type, "char*") && strcmp(type, "l_uint8*"))
1267 L_WARNING("array type not char* or l_uint8*; ignore\n",
1268 __func__);
1269 TIFFSetField(tif, tagval, size, sval);
1270 }
1271 } else {
1272 ns = 0;
1273 }
1274
1275 /* The typical tags (3 args to TIFFSetField) are now written */
1276 for (i = ns; i < n; i++) {
1277 numaGetIValue(natags, i, &tagval);
1278 sval = sarrayGetString(savals, i, L_NOCOPY);
1279 type = sarrayGetString(satypes, i, L_NOCOPY);
1280 if (!strcmp(type, "char*") || !strcmp(type, "const char*")) {
1281 TIFFSetField(tif, tagval, sval);
1282 } else if (!strcmp(type, "l_uint16")) {
1283 if (sscanf(sval, "%u", &uval) == 1) {
1284 TIFFSetField(tif, tagval, (l_uint16)uval);
1285 } else {
1286 lept_stderr("val %s not of type %s\n", sval, type);
1287 return ERROR_INT("custom tag(s) not written", __func__, 1);
1288 }
1289 } else if (!strcmp(type, "l_uint32")) {
1290 if (sscanf(sval, "%u", &uval) == 1) {
1291 TIFFSetField(tif, tagval, uval);
1292 } else {
1293 lept_stderr("val %s not of type %s\n", sval, type);
1294 return ERROR_INT("custom tag(s) not written", __func__, 1);
1295 }
1296 } else if (!strcmp(type, "l_int32")) {
1297 if (sscanf(sval, "%d", &val) == 1) {
1298 TIFFSetField(tif, tagval, val);
1299 } else {
1300 lept_stderr("val %s not of type %s\n", sval, type);
1301 return ERROR_INT("custom tag(s) not written", __func__, 1);
1302 }
1303 } else if (!strcmp(type, "l_float64")) {
1304 if (sscanf(sval, "%lf", &dval) == 1) {
1305 TIFFSetField(tif, tagval, dval);
1306 } else {
1307 lept_stderr("val %s not of type %s\n", sval, type);
1308 return ERROR_INT("custom tag(s) not written", __func__, 1);
1309 }
1310 } else if (!strcmp(type, "l_uint16-l_uint16")) {
1311 if (sscanf(sval, "%u-%u", &uval, &uval2) == 2) {
1312 TIFFSetField(tif, tagval, (l_uint16)uval, (l_uint16)uval2);
1313 } else {
1314 lept_stderr("val %s not of type %s\n", sval, type);
1315 return ERROR_INT("custom tag(s) not written", __func__, 1);
1316 }
1317 } else {
1318 lept_stderr("unknown type %s\n",type);
1319 return ERROR_INT("unknown type; tag(s) not written", __func__, 1);
1320 }
1321 }
1322 return 0;
1323}
1324
1325
1326/*--------------------------------------------------------------*
1327 * Reading and writing multipage tiff *
1328 *--------------------------------------------------------------*/
1360PIX *
1362 size_t *poffset)
1363{
1364l_int32 retval;
1365size_t offset;
1366PIX *pix;
1367TIFF *tif;
1368
1369 if (!fname)
1370 return (PIX *)ERROR_PTR("fname not defined", __func__, NULL);
1371 if (!poffset)
1372 return (PIX *)ERROR_PTR("&offset not defined", __func__, NULL);
1373
1374 if ((tif = openTiff(fname, "r")) == NULL) {
1375 L_ERROR("tif open failed for %s\n", __func__, fname);
1376 return NULL;
1377 }
1378
1379 /* Set ptrs in the TIFF to the beginning of the image */
1380 offset = *poffset;
1381 retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
1382 : TIFFSetSubDirectory(tif, offset);
1383 if (retval == 0) {
1384 TIFFClose(tif);
1385 return NULL;
1386 }
1387
1388 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
1389 TIFFClose(tif);
1390 return NULL;
1391 }
1392
1393 /* Advance to the next image and return the new offset */
1394 TIFFReadDirectory(tif);
1395 *poffset = TIFFCurrentDirOffset(tif);
1396 TIFFClose(tif);
1397 return pix;
1398}
1399
1400
1407PIXA *
1408pixaReadMultipageTiff(const char *filename)
1409{
1410l_int32 i, npages;
1411FILE *fp;
1412PIX *pix;
1413PIXA *pixa;
1414TIFF *tif;
1415
1416 if (!filename)
1417 return (PIXA *)ERROR_PTR("filename not defined", __func__, NULL);
1418
1419 if ((fp = fopenReadStream(filename)) == NULL)
1420 return (PIXA *)ERROR_PTR_1("stream not opened",
1421 filename, __func__, NULL);
1422 if (fileFormatIsTiff(fp)) {
1423 tiffGetCount(fp, &npages);
1424 L_INFO(" Tiff: %d pages\n", __func__, npages);
1425 } else {
1426 return (PIXA *)ERROR_PTR_1("file is not tiff",
1427 filename, __func__, NULL);
1428 }
1429
1430 if ((tif = fopenTiff(fp, "r")) == NULL)
1431 return (PIXA *)ERROR_PTR_1("tif not opened",
1432 filename, __func__, NULL);
1433
1434 pixa = pixaCreate(npages);
1435 pix = NULL;
1436 for (i = 0; i < npages; i++) {
1437 if ((pix = pixReadFromTiffStream(tif)) != NULL) {
1438 pixaAddPix(pixa, pix, L_INSERT);
1439 } else {
1440 L_WARNING("pix not read for page %d\n", __func__, i);
1441 }
1442
1443 /* Advance to the next directory (i.e., the next image) */
1444 if (TIFFReadDirectory(tif) == 0)
1445 break;
1446 }
1447
1448 fclose(fp);
1449 TIFFCleanup(tif);
1450 return pixa;
1451}
1452
1453
1468l_ok
1469pixaWriteMultipageTiff(const char *fname,
1470 PIXA *pixa)
1471{
1472const char *modestr;
1473l_int32 i, n;
1474PIX *pix1;
1475
1476 if (!fname)
1477 return ERROR_INT("fname not defined", __func__, 1);
1478 if (!pixa)
1479 return ERROR_INT("pixa not defined", __func__, 1);
1480
1481 n = pixaGetCount(pixa);
1482 for (i = 0; i < n; i++) {
1483 modestr = (i == 0) ? "w" : "a";
1484 pix1 = pixaGetPix(pixa, i, L_CLONE);
1485 if (pixGetDepth(pix1) == 1)
1486 pixWriteTiff(fname, pix1, IFF_TIFF_G4, modestr);
1487 else
1488 pixWriteTiff(fname, pix1, IFF_TIFF_ZIP, modestr);
1489 pixDestroy(&pix1);
1490 }
1491
1492 return 0;
1493}
1494
1495
1520l_ok
1521writeMultipageTiff(const char *dirin,
1522 const char *substr,
1523 const char *fileout)
1524{
1525SARRAY *sa;
1526
1527 if (!dirin)
1528 return ERROR_INT("dirin not defined", __func__, 1);
1529 if (!fileout)
1530 return ERROR_INT("fileout not defined", __func__, 1);
1531
1532 /* Get all filtered and sorted full pathnames. */
1533 sa = getSortedPathnamesInDirectory(dirin, substr, 0, 0);
1534
1535 /* Generate the tiff file */
1536 writeMultipageTiffSA(sa, fileout);
1537 sarrayDestroy(&sa);
1538 return 0;
1539}
1540
1541
1554l_ok
1556 const char *fileout)
1557{
1558char *fname;
1559const char *op;
1560l_int32 i, nfiles, firstfile, format;
1561PIX *pix;
1562
1563 if (!sa)
1564 return ERROR_INT("sa not defined", __func__, 1);
1565 if (!fileout)
1566 return ERROR_INT("fileout not defined", __func__, 1);
1567
1568 nfiles = sarrayGetCount(sa);
1569 firstfile = TRUE;
1570 for (i = 0; i < nfiles; i++) {
1571 op = (firstfile) ? "w" : "a";
1572 fname = sarrayGetString(sa, i, L_NOCOPY);
1573 findFileFormat(fname, &format);
1574 if (format == IFF_UNKNOWN) {
1575 L_INFO("format of %s not known\n", __func__, fname);
1576 continue;
1577 }
1578
1579 if ((pix = pixRead(fname)) == NULL) {
1580 L_WARNING("pix not made for file: %s\n", __func__, fname);
1581 continue;
1582 }
1583 if (pixGetDepth(pix) == 1)
1584 pixWriteTiff(fileout, pix, IFF_TIFF_G4, op);
1585 else
1586 pixWriteTiff(fileout, pix, IFF_TIFF_ZIP, op);
1587 firstfile = FALSE;
1588 pixDestroy(&pix);
1589 }
1590
1591 return 0;
1592}
1593
1594
1595/*--------------------------------------------------------------*
1596 * Print info to stream *
1597 *--------------------------------------------------------------*/
1605l_ok
1606fprintTiffInfo(FILE *fpout,
1607 const char *tiffile)
1608{
1609TIFF *tif;
1610
1611 if (!tiffile)
1612 return ERROR_INT("tiffile not defined", __func__, 1);
1613 if (!fpout)
1614 return ERROR_INT("stream out not defined", __func__, 1);
1615
1616 if ((tif = openTiff(tiffile, "rb")) == NULL)
1617 return ERROR_INT("tif not open for read", __func__, 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 if (!fp)
1644 return ERROR_INT("stream not defined", __func__, 1);
1645 if (!pn)
1646 return ERROR_INT("&n not defined", __func__, 1);
1647 *pn = 0;
1648
1649 if ((tif = fopenTiff(fp, "r")) == NULL)
1650 return ERROR_INT("tif not open for read", __func__, 1);
1651
1652 for (i = 1; ; i++) {
1653 if (TIFFReadDirectory(tif) == 0)
1654 break;
1655 if (i == ManyPagesInTiffFile + 1) {
1656 L_WARNING("big file: more than %d pages\n", __func__,
1657 ManyPagesInTiffFile);
1658 }
1659 }
1660 *pn = i;
1661 TIFFCleanup(tif);
1662 return 0;
1663}
1664
1665
1666/*--------------------------------------------------------------*
1667 * Get resolution from tif *
1668 *--------------------------------------------------------------*/
1682l_ok
1684 l_int32 *pxres,
1685 l_int32 *pyres)
1686{
1687TIFF *tif;
1688
1689 if (!pxres || !pyres)
1690 return ERROR_INT("&xres and &yres not both defined", __func__, 1);
1691 *pxres = *pyres = 0;
1692 if (!fp)
1693 return ERROR_INT("stream not opened", __func__, 1);
1694
1695 if ((tif = fopenTiff(fp, "r")) == NULL)
1696 return ERROR_INT("tif not open for read", __func__, 1);
1697 getTiffStreamResolution(tif, pxres, pyres);
1698 TIFFCleanup(tif);
1699 return 0;
1700}
1701
1702
1716static l_int32
1718 l_int32 *pxres,
1719 l_int32 *pyres)
1720{
1721l_uint16 resunit;
1722l_int32 foundxres, foundyres;
1723l_float32 fxres, fyres;
1724
1725 if (!tif)
1726 return ERROR_INT("tif not opened", __func__, 1);
1727 if (!pxres || !pyres)
1728 return ERROR_INT("&xres and &yres not both defined", __func__, 1);
1729 *pxres = *pyres = 0;
1730
1731 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
1732 foundxres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fxres);
1733 foundyres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fyres);
1734 if (!foundxres && !foundyres) return 1;
1735 if (isnan(fxres) || isnan(fyres)) return 1;
1736 if (!foundxres && foundyres)
1737 fxres = fyres;
1738 else if (foundxres && !foundyres)
1739 fyres = fxres;
1740
1741 /* Avoid overflow into int32; set max fxres and fyres to 5 x 10^8 */
1742 if (fxres < 0 || fxres > (1L << 29) || fyres < 0 || fyres > (1L << 29))
1743 return ERROR_INT("fxres and/or fyres values are invalid", __func__, 1);
1744
1745 if (resunit == RESUNIT_CENTIMETER) { /* convert to ppi */
1746 *pxres = (l_int32)(2.54 * fxres + 0.5);
1747 *pyres = (l_int32)(2.54 * fyres + 0.5);
1748 } else {
1749 *pxres = (l_int32)(fxres + 0.5);
1750 *pyres = (l_int32)(fyres + 0.5);
1751 }
1752
1753 return 0;
1754}
1755
1756
1757/*--------------------------------------------------------------*
1758 * Get some tiff header information *
1759 *--------------------------------------------------------------*/
1780l_ok
1781readHeaderTiff(const char *filename,
1782 l_int32 n,
1783 l_int32 *pw,
1784 l_int32 *ph,
1785 l_int32 *pbps,
1786 l_int32 *pspp,
1787 l_int32 *pres,
1788 l_int32 *pcmap,
1789 l_int32 *pformat)
1790{
1791l_int32 ret;
1792FILE *fp;
1793
1794 if (pw) *pw = 0;
1795 if (ph) *ph = 0;
1796 if (pbps) *pbps = 0;
1797 if (pspp) *pspp = 0;
1798 if (pres) *pres = 0;
1799 if (pcmap) *pcmap = 0;
1800 if (pformat) *pformat = 0;
1801 if (!filename)
1802 return ERROR_INT("filename not defined", __func__, 1);
1803 if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1804 return ERROR_INT("no results requested", __func__, 1);
1805
1806 if ((fp = fopenReadStream(filename)) == NULL)
1807 return ERROR_INT_1("image file not found", filename, __func__, 1);
1808 ret = freadHeaderTiff(fp, n, pw, ph, pbps, pspp, pres, pcmap, pformat);
1809 fclose(fp);
1810 return ret;
1811}
1812
1813
1834l_ok
1836 l_int32 n,
1837 l_int32 *pw,
1838 l_int32 *ph,
1839 l_int32 *pbps,
1840 l_int32 *pspp,
1841 l_int32 *pres,
1842 l_int32 *pcmap,
1843 l_int32 *pformat)
1844{
1845l_int32 i, ret, format;
1846TIFF *tif;
1847
1848 if (pw) *pw = 0;
1849 if (ph) *ph = 0;
1850 if (pbps) *pbps = 0;
1851 if (pspp) *pspp = 0;
1852 if (pres) *pres = 0;
1853 if (pcmap) *pcmap = 0;
1854 if (pformat) *pformat = 0;
1855 if (!fp)
1856 return ERROR_INT("stream not defined", __func__, 1);
1857 if (n < 0)
1858 return ERROR_INT("image index must be >= 0", __func__, 1);
1859 if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1860 return ERROR_INT("no results requested", __func__, 1);
1861
1862 findFileFormatStream(fp, &format);
1863 if (!L_FORMAT_IS_TIFF(format))
1864 return ERROR_INT("file not tiff format", __func__, 1);
1865
1866 if ((tif = fopenTiff(fp, "r")) == NULL)
1867 return ERROR_INT("tif not open for read", __func__, 1);
1868
1869 for (i = 0; i < n; i++) {
1870 if (TIFFReadDirectory(tif) == 0)
1871 return ERROR_INT("image n not found in file", __func__, 1);
1872 }
1873
1874 ret = tiffReadHeaderTiff(tif, pw, ph, pbps, pspp, pres, pcmap, pformat);
1875 TIFFCleanup(tif);
1876 return ret;
1877}
1878
1879
1901l_ok
1902readHeaderMemTiff(const l_uint8 *cdata,
1903 size_t size,
1904 l_int32 n,
1905 l_int32 *pw,
1906 l_int32 *ph,
1907 l_int32 *pbps,
1908 l_int32 *pspp,
1909 l_int32 *pres,
1910 l_int32 *pcmap,
1911 l_int32 *pformat)
1912{
1913l_uint8 *data;
1914l_int32 i, ret;
1915TIFF *tif;
1916
1917 if (pw) *pw = 0;
1918 if (ph) *ph = 0;
1919 if (pbps) *pbps = 0;
1920 if (pspp) *pspp = 0;
1921 if (pres) *pres = 0;
1922 if (pcmap) *pcmap = 0;
1923 if (pformat) *pformat = 0;
1924 if (!pw && !ph && !pbps && !pspp && !pres && !pcmap && !pformat)
1925 return ERROR_INT("no results requested", __func__, 1);
1926 if (!cdata)
1927 return ERROR_INT("cdata not defined", __func__, 1);
1928
1929 /* Open a tiff stream to memory */
1930 data = (l_uint8 *)cdata; /* we're really not going to change this */
1931 if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
1932 return ERROR_INT("tiff stream not opened", __func__, 1);
1933
1934 for (i = 0; i < n; i++) {
1935 if (TIFFReadDirectory(tif) == 0) {
1936 TIFFClose(tif);
1937 return ERROR_INT("image n not found in file", __func__, 1);
1938 }
1939 }
1940
1941 ret = tiffReadHeaderTiff(tif, pw, ph, pbps, pspp, pres, pcmap, pformat);
1942 TIFFClose(tif);
1943 return ret;
1944}
1945
1946
1960static l_int32
1962 l_int32 *pw,
1963 l_int32 *ph,
1964 l_int32 *pbps,
1965 l_int32 *pspp,
1966 l_int32 *pres,
1967 l_int32 *pcmap,
1968 l_int32 *pformat)
1969{
1970l_uint16 tiffcomp;
1971l_uint16 bps, spp;
1972l_uint16 *rmap, *gmap, *bmap;
1973l_int32 xres, yres;
1974l_uint32 w, h;
1975
1976 if (!tif)
1977 return ERROR_INT("tif not opened", __func__, 1);
1978
1979 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
1980 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
1981 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
1982 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
1983 if (w < 1 || h < 1)
1984 return ERROR_INT("tif w and h not both > 0", __func__, 1);
1985 if (bps != 1 && bps != 2 && bps != 4 && bps != 8 && bps != 16)
1986 return ERROR_INT("bps not in set {1,2,4,8,16}", __func__, 1);
1987 if (spp != 1 && spp != 2 && spp != 3 && spp != 4)
1988 return ERROR_INT("spp not in set {1,2,3,4}", __func__, 1);
1989 if (pw) *pw = w;
1990 if (ph) *ph = h;
1991 if (pbps) *pbps = bps;
1992 if (pspp) *pspp = spp;
1993 if (pres) {
1994 if (getTiffStreamResolution(tif, &xres, &yres) == 0)
1995 *pres = (l_int32)xres;
1996 }
1997 if (pcmap) {
1998 if (TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap))
1999 *pcmap = 1;
2000 }
2001 if (pformat) {
2002 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
2003 *pformat = getTiffCompressedFormat(tiffcomp);
2004 }
2005 return 0;
2006}
2007
2008
2028l_ok
2030 l_int32 *pcomptype)
2031{
2032l_uint16 tiffcomp;
2033TIFF *tif;
2034
2035 if (!pcomptype)
2036 return ERROR_INT("&comptype not defined", __func__, 1);
2037 *pcomptype = IFF_UNKNOWN; /* init */
2038 if (!fp)
2039 return ERROR_INT("stream not defined", __func__, 1);
2040
2041 if ((tif = fopenTiff(fp, "r")) == NULL)
2042 return ERROR_INT("tif not opened", __func__, 1);
2043 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
2044 *pcomptype = getTiffCompressedFormat(tiffcomp);
2045 TIFFCleanup(tif);
2046 return 0;
2047}
2048
2049
2064static l_int32
2065getTiffCompressedFormat(l_uint16 tiffcomp)
2066{
2067l_int32 comptype;
2068
2069 switch (tiffcomp)
2070 {
2071 case COMPRESSION_CCITTFAX4:
2072 comptype = IFF_TIFF_G4;
2073 break;
2074 case COMPRESSION_CCITTFAX3:
2075 comptype = IFF_TIFF_G3;
2076 break;
2077 case COMPRESSION_CCITTRLE:
2078 comptype = IFF_TIFF_RLE;
2079 break;
2080 case COMPRESSION_PACKBITS:
2081 comptype = IFF_TIFF_PACKBITS;
2082 break;
2083 case COMPRESSION_LZW:
2084 comptype = IFF_TIFF_LZW;
2085 break;
2086 case COMPRESSION_ADOBE_DEFLATE:
2087 comptype = IFF_TIFF_ZIP;
2088 break;
2089 case COMPRESSION_JPEG:
2090 comptype = IFF_TIFF_JPEG;
2091 break;
2092 default:
2093 comptype = IFF_TIFF;
2094 break;
2095 }
2096 return comptype;
2097}
2098
2099
2100/*--------------------------------------------------------------*
2101 * Extraction of tiff g4 data *
2102 *--------------------------------------------------------------*/
2114l_ok
2115extractG4DataFromFile(const char *filein,
2116 l_uint8 **pdata,
2117 size_t *pnbytes,
2118 l_int32 *pw,
2119 l_int32 *ph,
2120 l_int32 *pminisblack)
2121{
2122l_uint8 *inarray, *data;
2123l_uint16 minisblack, comptype; /* accessors require l_uint16 */
2124l_int32 istiff;
2125l_uint32 w, h, rowsperstrip; /* accessors require l_uint32 */
2126l_uint32 diroff;
2127size_t fbytes, nbytes;
2128FILE *fpin;
2129TIFF *tif;
2130
2131 if (!pdata)
2132 return ERROR_INT("&data not defined", __func__, 1);
2133 if (!pnbytes)
2134 return ERROR_INT("&nbytes not defined", __func__, 1);
2135 if (!pw && !ph && !pminisblack)
2136 return ERROR_INT("no output data requested", __func__, 1);
2137 *pdata = NULL;
2138 *pnbytes = 0;
2139
2140 if ((fpin = fopenReadStream(filein)) == NULL)
2141 return ERROR_INT_1("stream not opened to file", filein, __func__, 1);
2142 istiff = fileFormatIsTiff(fpin);
2143 fclose(fpin);
2144 if (!istiff)
2145 return ERROR_INT_1("filein not tiff", filein, __func__, 1);
2146
2147 if ((inarray = l_binaryRead(filein, &fbytes)) == NULL)
2148 return ERROR_INT_1("inarray not made", filein, __func__, 1);
2149
2150 /* Get metadata about the image */
2151 if ((tif = openTiff(filein, "rb")) == NULL) {
2152 LEPT_FREE(inarray);
2153 return ERROR_INT_1("tif not open for read", filein, __func__, 1);
2154 }
2155 TIFFGetField(tif, TIFFTAG_COMPRESSION, &comptype);
2156 if (comptype != COMPRESSION_CCITTFAX4) {
2157 LEPT_FREE(inarray);
2158 TIFFClose(tif);
2159 return ERROR_INT_1("filein is not g4 compressed", filein, __func__, 1);
2160 }
2161
2162 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
2163 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
2164 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
2165 if (h != rowsperstrip)
2166 L_WARNING("more than 1 strip\n", __func__);
2167 /* From the standard:
2168 TIFFTAG_PHOTOMETRIC = 0 (false) --> min value is white.
2169 TIFFTAG_PHOTOMETRIC = 1 (true) --> min value is black.
2170 Most 1 bpp tiffs have the tag value 0 (black is 1),
2171 because there are fewer black pixels than white pixels,
2172 so it makes sense to encode runs of black pixels. */
2173 TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &minisblack);
2174/* TIFFPrintDirectory(tif, stderr, 0); */
2175 TIFFClose(tif);
2176 if (pw) *pw = (l_int32)w;
2177 if (ph) *ph = (l_int32)h;
2178 if (pminisblack) *pminisblack = (l_int32)minisblack;
2179
2180 /* The header has 8 bytes: the first 2 are the magic number,
2181 * the next 2 are the version, and the last 4 are the
2182 * offset to the first directory. That's what we want here.
2183 * We have to test the byte order before decoding 4 bytes! */
2184 if (inarray[0] == 0x4d) { /* big-endian */
2185 diroff = (inarray[4] << 24) | (inarray[5] << 16) |
2186 (inarray[6] << 8) | inarray[7];
2187 } else { /* inarray[0] == 0x49 : little-endian */
2188 diroff = (inarray[7] << 24) | (inarray[6] << 16) |
2189 (inarray[5] << 8) | inarray[4];
2190 }
2191/* lept_stderr(" diroff = %d, %x\n", diroff, diroff); */
2192
2193 /* Extract the ccittg4 encoded data from the tiff file.
2194 * We skip the 8 byte header and take nbytes of data,
2195 * up to the beginning of the directory (at diroff) */
2196 nbytes = diroff - 8;
2197 if (nbytes > MaxNumTiffBytes) {
2198 LEPT_FREE(inarray);
2199 L_ERROR("requesting %zu bytes > %zu\n", __func__,
2200 nbytes, MaxNumTiffBytes);
2201 return 1;
2202 }
2203 *pnbytes = nbytes;
2204 if ((data = (l_uint8 *)LEPT_CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
2205 LEPT_FREE(inarray);
2206 return ERROR_INT("data not allocated", __func__, 1);
2207 }
2208 *pdata = data;
2209 memcpy(data, inarray + 8, nbytes);
2210 LEPT_FREE(inarray);
2211
2212 return 0;
2213}
2214
2215
2216/*--------------------------------------------------------------*
2217 * Open tiff stream from file stream *
2218 *--------------------------------------------------------------*/
2239static TIFF *
2240fopenTiff(FILE *fp,
2241 const char *modestring)
2242{
2243 if (!fp)
2244 return (TIFF *)ERROR_PTR("stream not opened", __func__, NULL);
2245 if (!modestring)
2246 return (TIFF *)ERROR_PTR("modestring not defined", __func__, NULL);
2247
2248 TIFFSetWarningHandler(NULL); /* disable warnings */
2249 TIFFSetErrorHandler(NULL); /* disable error messages */
2250
2251 fseek(fp, 0, SEEK_SET);
2252 return TIFFClientOpen("TIFFstream", modestring, (thandle_t)fp,
2253 lept_read_proc, lept_write_proc, lept_seek_proc,
2254 lept_close_proc, lept_size_proc, NULL, NULL);
2255}
2256
2257
2258/*--------------------------------------------------------------*
2259 * Wrapper for TIFFOpen *
2260 *--------------------------------------------------------------*/
2273static TIFF *
2274openTiff(const char *filename,
2275 const char *modestring)
2276{
2277char *fname;
2278TIFF *tif;
2279
2280 if (!filename)
2281 return (TIFF *)ERROR_PTR("filename not defined", __func__, NULL);
2282 if (!modestring)
2283 return (TIFF *)ERROR_PTR("modestring not defined", __func__, NULL);
2284
2285 TIFFSetWarningHandler(NULL); /* disable warnings */
2286 TIFFSetErrorHandler(NULL); /* disable error messages */
2287
2288 fname = genPathname(filename, NULL);
2289 tif = TIFFOpen(fname, modestring);
2290 LEPT_FREE(fname);
2291 return tif;
2292}
2293
2294
2295/*----------------------------------------------------------------------*
2296 * Memory I/O: reading memory --> pix and writing pix --> memory *
2297 *----------------------------------------------------------------------*/
2298/* It would be nice to use open_memstream() and fmemopen()
2299 * for writing and reading to memory, rsp. These functions manage
2300 * memory for writes and reads that use a file streams interface.
2301 * Unfortunately, the tiff library only has an interface for reading
2302 * and writing to file descriptors, not to file streams. The tiff
2303 * library procedure is to open a "tiff stream" and read/write to it.
2304 * The library provides a client interface for managing the I/O
2305 * from memory, which requires seven callbacks. See the TIFFClientOpen
2306 * man page for callback signatures. Adam Langley provided the code
2307 * to do this. */
2308
2330{
2331 l_uint8 *buffer; /* expands to hold data when written to; */
2332 /* fixed size when read from. */
2333 size_t bufsize; /* current size allocated when written to; */
2334 /* fixed size of input data when read from. */
2335 size_t offset; /* byte offset from beginning of buffer. */
2336 size_t hw; /* high-water mark; max bytes in buffer. */
2337 l_uint8 **poutdata; /* input param for writing; data goes here. */
2338 size_t *poutsize; /* input param for writing; data size goes here. */
2339};
2340typedef struct L_Memstream L_MEMSTREAM;
2341
2342
2343 /* These are static functions for memory I/O */
2344static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);
2345static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
2346 size_t *poutsize);
2347static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);
2348static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
2349 tsize_t length);
2350static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);
2351static l_int32 tiffCloseCallback(thandle_t handle);
2352static toff_t tiffSizeCallback(thandle_t handle);
2353static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);
2354static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);
2355
2356
2357static L_MEMSTREAM *
2358memstreamCreateForRead(l_uint8 *indata,
2359 size_t insize)
2360{
2361L_MEMSTREAM *mstream;
2362
2363 mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2364 mstream->buffer = indata; /* handle to input data array */
2365 mstream->bufsize = insize; /* amount of input data */
2366 mstream->hw = insize; /* high-water mark fixed at input data size */
2367 mstream->offset = 0; /* offset always starts at 0 */
2368 return mstream;
2369}
2370
2371
2372static L_MEMSTREAM *
2373memstreamCreateForWrite(l_uint8 **poutdata,
2374 size_t *poutsize)
2375{
2376L_MEMSTREAM *mstream;
2377
2378 mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
2379 mstream->buffer = (l_uint8 *)LEPT_CALLOC(8 * 1024, 1);
2380 mstream->bufsize = 8 * 1024;
2381 mstream->poutdata = poutdata; /* used only at end of write */
2382 mstream->poutsize = poutsize; /* ditto */
2383 mstream->hw = mstream->offset = 0;
2384 return mstream;
2385}
2386
2387
2388static tsize_t
2389tiffReadCallback(thandle_t handle,
2390 tdata_t data,
2391 tsize_t length)
2392{
2393L_MEMSTREAM *mstream;
2394size_t amount;
2395
2396 mstream = (L_MEMSTREAM *)handle;
2397 amount = L_MIN((size_t)length, mstream->hw - mstream->offset);
2398
2399 /* Fuzzed files can create this condition! */
2400 if (mstream->offset + amount < amount || /* overflow */
2401 mstream->offset + amount > mstream->hw) {
2402 lept_stderr("Bad file: amount too big: %zu\n", amount);
2403 return 0;
2404 }
2405
2406 memcpy(data, mstream->buffer + mstream->offset, amount);
2407 mstream->offset += amount;
2408 return amount;
2409}
2410
2411
2412static tsize_t
2413tiffWriteCallback(thandle_t handle,
2414 tdata_t data,
2415 tsize_t length)
2416{
2417L_MEMSTREAM *mstream;
2418size_t newsize;
2419
2420 /* reallocNew() uses calloc to initialize the array.
2421 * If malloc is used instead, for some of the encoding methods,
2422 * not all the data in 'bufsize' bytes in the buffer will
2423 * have been initialized by the end of the compression. */
2424 mstream = (L_MEMSTREAM *)handle;
2425 if (mstream->offset + length > mstream->bufsize) {
2426 newsize = 2 * (mstream->offset + length);
2427 mstream->buffer = (l_uint8 *)reallocNew((void **)&mstream->buffer,
2428 mstream->hw, newsize);
2429 mstream->bufsize = newsize;
2430 }
2431
2432 memcpy(mstream->buffer + mstream->offset, data, length);
2433 mstream->offset += length;
2434 mstream->hw = L_MAX(mstream->offset, mstream->hw);
2435 return length;
2436}
2437
2438
2439static toff_t
2440tiffSeekCallback(thandle_t handle,
2441 toff_t offset,
2442 l_int32 whence)
2443{
2444L_MEMSTREAM *mstream;
2445
2446 mstream = (L_MEMSTREAM *)handle;
2447 switch (whence) {
2448 case SEEK_SET:
2449/* lept_stderr("seek_set: offset = %d\n", offset); */
2450 if((size_t)offset != offset) { /* size_t overflow on uint32 */
2451 return (toff_t)ERROR_INT("too large offset value", __func__, 1);
2452 }
2453 mstream->offset = offset;
2454 break;
2455 case SEEK_CUR:
2456/* lept_stderr("seek_cur: offset = %d\n", offset); */
2457 mstream->offset += offset;
2458 break;
2459 case SEEK_END:
2460/* lept_stderr("seek end: hw = %d, offset = %d\n",
2461 mstream->hw, offset); */
2462 mstream->offset = mstream->hw - offset; /* offset >= 0 */
2463 break;
2464 default:
2465 return (toff_t)ERROR_INT("bad whence value", __func__,
2466 mstream->offset);
2467 }
2468
2469 return mstream->offset;
2470}
2471
2472
2473static l_int32
2474tiffCloseCallback(thandle_t handle)
2475{
2476L_MEMSTREAM *mstream;
2477
2478 mstream = (L_MEMSTREAM *)handle;
2479 if (mstream->poutdata) { /* writing: save the output data */
2480 *mstream->poutdata = mstream->buffer;
2481 *mstream->poutsize = mstream->hw;
2482 }
2483 LEPT_FREE(mstream); /* never free the buffer! */
2484 return 0;
2485}
2486
2487
2488static toff_t
2489tiffSizeCallback(thandle_t handle)
2490{
2491L_MEMSTREAM *mstream;
2492
2493 mstream = (L_MEMSTREAM *)handle;
2494 return mstream->hw;
2495}
2496
2497
2498static l_int32
2499tiffMapCallback(thandle_t handle,
2500 tdata_t *data,
2501 toff_t *length)
2502{
2503L_MEMSTREAM *mstream;
2504
2505 mstream = (L_MEMSTREAM *)handle;
2506 *data = mstream->buffer;
2507 *length = mstream->hw;
2508 return 0;
2509}
2510
2511
2512static void
2513tiffUnmapCallback(thandle_t handle,
2514 tdata_t data,
2515 toff_t length)
2516{
2517 return;
2518}
2519
2520
2541static TIFF *
2542fopenTiffMemstream(const char *filename,
2543 const char *operation,
2544 l_uint8 **pdata,
2545 size_t *pdatasize)
2546{
2547L_MEMSTREAM *mstream;
2548TIFF *tif;
2549
2550 if (!filename)
2551 return (TIFF *)ERROR_PTR("filename not defined", __func__, NULL);
2552 if (!operation)
2553 return (TIFF *)ERROR_PTR("operation not defined", __func__, NULL);
2554 if (!pdata)
2555 return (TIFF *)ERROR_PTR("&data not defined", __func__, NULL);
2556 if (!pdatasize)
2557 return (TIFF *)ERROR_PTR("&datasize not defined", __func__, NULL);
2558 if (strcmp(operation, "r") && strcmp(operation, "w"))
2559 return (TIFF *)ERROR_PTR("op not 'r' or 'w'", __func__, NULL);
2560
2561 if (!strcmp(operation, "r"))
2562 mstream = memstreamCreateForRead(*pdata, *pdatasize);
2563 else
2564 mstream = memstreamCreateForWrite(pdata, pdatasize);
2565 if (!mstream)
2566 return (TIFF *)ERROR_PTR("mstream not made", __func__, NULL);
2567
2568 TIFFSetWarningHandler(NULL); /* disable warnings */
2569 TIFFSetErrorHandler(NULL); /* disable error messages */
2570
2571 tif = TIFFClientOpen(filename, operation, (thandle_t)mstream,
2572 tiffReadCallback, tiffWriteCallback,
2573 tiffSeekCallback, tiffCloseCallback,
2574 tiffSizeCallback, tiffMapCallback,
2575 tiffUnmapCallback);
2576 if (!tif)
2577 LEPT_FREE(mstream);
2578 return tif;
2579}
2580
2581
2602PIX *
2603pixReadMemTiff(const l_uint8 *cdata,
2604 size_t size,
2605 l_int32 n)
2606{
2607l_uint8 *data;
2608l_int32 i;
2609PIX *pix;
2610TIFF *tif;
2611
2612 if (!cdata)
2613 return (PIX *)ERROR_PTR("cdata not defined", __func__, NULL);
2614
2615 data = (l_uint8 *)cdata; /* we're really not going to change this */
2616 if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2617 return (PIX *)ERROR_PTR("tiff stream not opened", __func__, NULL);
2618
2619 pix = NULL;
2620 for (i = 0; ; i++) {
2621 if (i == n) {
2622 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2623 TIFFClose(tif);
2624 return NULL;
2625 }
2626 pixSetInputFormat(pix, IFF_TIFF);
2627 break;
2628 }
2629 if (TIFFReadDirectory(tif) == 0)
2630 break;
2631 if (i == ManyPagesInTiffFile + 1) {
2632 L_WARNING("big file: more than %d pages\n", __func__,
2633 ManyPagesInTiffFile);
2634 }
2635 }
2636
2637 TIFFClose(tif);
2638 return pix;
2639}
2640
2641
2665PIX *
2666pixReadMemFromMultipageTiff(const l_uint8 *cdata,
2667 size_t size,
2668 size_t *poffset)
2669{
2670l_uint8 *data;
2671l_int32 retval;
2672size_t offset;
2673PIX *pix;
2674TIFF *tif;
2675
2676 if (!cdata)
2677 return (PIX *)ERROR_PTR("cdata not defined", __func__, NULL);
2678 if (!poffset)
2679 return (PIX *)ERROR_PTR("&offset not defined", __func__, NULL);
2680
2681 data = (l_uint8 *)cdata; /* we're really not going to change this */
2682 if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
2683 return (PIX *)ERROR_PTR("tiff stream not opened", __func__, NULL);
2684
2685 /* Set ptrs in the TIFF to the beginning of the image */
2686 offset = *poffset;
2687 retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
2688 : TIFFSetSubDirectory(tif, offset);
2689 if (retval == 0) {
2690 TIFFClose(tif);
2691 return NULL;
2692 }
2693
2694 if ((pix = pixReadFromTiffStream(tif)) == NULL) {
2695 TIFFClose(tif);
2696 return NULL;
2697 }
2698
2699 /* Advance to the next image and return the new offset */
2700 TIFFReadDirectory(tif);
2701 *poffset = TIFFCurrentDirOffset(tif);
2702 TIFFClose(tif);
2703 return pix;
2704}
2705
2706
2719PIXA *
2720pixaReadMemMultipageTiff(const l_uint8 *data,
2721 size_t size)
2722{
2723size_t offset;
2724PIX *pix;
2725PIXA *pixa;
2726
2727 if (!data)
2728 return (PIXA *)ERROR_PTR("data not defined", __func__, NULL);
2729
2730 offset = 0;
2731 pixa = pixaCreate(0);
2732 do {
2733 pix = pixReadMemFromMultipageTiff(data, size, &offset);
2734 pixaAddPix(pixa, pix, L_INSERT);
2735 } while (offset != 0);
2736 return pixa;
2737}
2738
2739
2757l_ok
2759 size_t *psize,
2760 PIXA *pixa)
2761{
2762const char *modestr;
2763l_int32 i, n;
2764FILE *fp;
2765PIX *pix1;
2766
2767 if (pdata) *pdata = NULL;
2768 if (!pdata)
2769 return ERROR_INT("pdata not defined", __func__, 1);
2770 if (!pixa)
2771 return ERROR_INT("pixa not defined", __func__, 1);
2772
2773#ifdef _WIN32
2774 if ((fp = fopenWriteWinTempfile()) == NULL)
2775 return ERROR_INT("tmpfile stream not opened", __func__, 1);
2776#else
2777 if ((fp = tmpfile()) == NULL)
2778 return ERROR_INT("tmpfile stream not opened", __func__, 1);
2779#endif /* _WIN32 */
2780
2781 n = pixaGetCount(pixa);
2782 for (i = 0; i < n; i++) {
2783 modestr = (i == 0) ? "w" : "a";
2784 pix1 = pixaGetPix(pixa, i, L_CLONE);
2785 if (pixGetDepth(pix1) == 1)
2786 pixWriteStreamTiffWA(fp, pix1, IFF_TIFF_G4, modestr);
2787 else
2788 pixWriteStreamTiffWA(fp, pix1, IFF_TIFF_ZIP, modestr);
2789 pixDestroy(&pix1);
2790 }
2791
2792 rewind(fp);
2793 *pdata = l_binaryReadStream(fp, psize);
2794 fclose(fp);
2795 return 0;
2796}
2797
2798
2814l_ok
2815pixWriteMemTiff(l_uint8 **pdata,
2816 size_t *psize,
2817 PIX *pix,
2818 l_int32 comptype)
2819{
2820 return pixWriteMemTiffCustom(pdata, psize, pix, comptype,
2821 NULL, NULL, NULL, NULL);
2822}
2823
2824
2845l_ok
2847 size_t *psize,
2848 PIX *pix,
2849 l_int32 comptype,
2850 NUMA *natags,
2851 SARRAY *savals,
2852 SARRAY *satypes,
2853 NUMA *nasizes)
2854{
2855l_int32 ret;
2856TIFF *tif;
2857
2858 if (!pdata)
2859 return ERROR_INT("&data not defined", __func__, 1);
2860 if (!psize)
2861 return ERROR_INT("&size not defined", __func__, 1);
2862 if (!pix)
2863 return ERROR_INT("&pix not defined", __func__, 1);
2864 if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
2865 comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
2866 comptype != IFF_TIFF_JPEG) {
2867 L_WARNING("invalid compression type for bpp > 1\n", __func__);
2868 comptype = IFF_TIFF_ZIP;
2869 }
2870
2871 if ((tif = fopenTiffMemstream("tifferror", "w", pdata, psize)) == NULL)
2872 return ERROR_INT("tiff stream not opened", __func__, 1);
2873 ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
2874 satypes, nasizes);
2875
2876 TIFFClose(tif);
2877 return ret;
2878}
2879
2880/* ---------------------------------------*/
2881#endif /* HAVE_LIBTIFF && HAVE_LIBJPEG */
2882/* ---------------------------------------*/
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ L_ALPHA_CHANNEL
Definition pix.h:331
@ COLOR_GREEN
Definition pix.h:329
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
@ L_CLONE
Definition pix.h:506
@ L_NOCOPY
Definition pix.h:503
@ L_INSERT
Definition pix.h:504
Memory stream buffer used with TIFFClientOpen()
Definition tiffio.c:2330
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:1961
static TIFF * fopenTiffMemstream(const char *filename, const char *operation, l_uint8 **pdata, size_t *pdatasize)
fopenTiffMemstream()
Definition tiffio.c:2542
l_ok pixaWriteMemMultipageTiff(l_uint8 **pdata, size_t *psize, PIXA *pixa)
pixaWriteMemMultipageTiff()
Definition tiffio.c:2758
l_ok fprintTiffInfo(FILE *fpout, const char *tiffile)
fprintTiffInfo()
Definition tiffio.c:1606
PIX * pixReadTiff(const char *filename, l_int32 n)
pixReadTiff()
Definition tiffio.c:394
PIXA * pixaReadMultipageTiff(const char *filename)
pixaReadMultipageTiff()
Definition tiffio.c:1408
l_ok pixWriteStreamTiffWA(FILE *fp, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteStreamTiffWA()
Definition tiffio.c:951
static TIFF * openTiff(const char *filename, const char *modestring)
openTiff()
Definition tiffio.c:2274
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:1781
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:1902
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:2846
l_ok findTiffCompression(FILE *fp, l_int32 *pcomptype)
findTiffCompression()
Definition tiffio.c:2029
static l_int32 writeCustomTiffTags(TIFF *tif, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
writeCustomTiffTags()
Definition tiffio.c:1235
PIX * pixReadFromMultipageTiff(const char *fname, size_t *poffset)
pixReadFromMultipageTiff()
Definition tiffio.c:1361
l_ok getTiffResolution(FILE *fp, l_int32 *pxres, l_int32 *pyres)
getTiffResolution()
Definition tiffio.c:1683
PIX * pixReadStreamTiff(FILE *fp, l_int32 n)
pixReadStreamTiff()
Definition tiffio.c:430
static PIX * pixReadFromTiffStream(TIFF *tif)
pixReadFromTiffStream()
Definition tiffio.c:498
PIXA * pixaReadMemMultipageTiff(const l_uint8 *data, size_t size)
pixaReadMemMultipageTiff()
Definition tiffio.c:2720
l_ok pixWriteTiff(const char *filename, PIX *pix, l_int32 comptype, const char *modestr)
pixWriteTiff()
Definition tiffio.c:812
l_ok writeMultipageTiff(const char *dirin, const char *substr, const char *fileout)
writeMultipageTiff()
Definition tiffio.c:1521
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:869
PIX * pixReadMemFromMultipageTiff(const l_uint8 *cdata, size_t size, size_t *poffset)
pixReadMemFromMultipageTiff()
Definition tiffio.c:2666
static l_int32 pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype, NUMA *natags, SARRAY *savals, SARRAY *satypes, NUMA *nasizes)
pixWriteToTiffStream()
Definition tiffio.c:1024
l_ok pixWriteStreamTiff(FILE *fp, PIX *pix, l_int32 comptype)
pixWriteStreamTiff()
Definition tiffio.c:926
PIX * pixReadMemTiff(const l_uint8 *cdata, size_t size, l_int32 n)
pixReadMemTiff()
Definition tiffio.c:2603
l_ok writeMultipageTiffSA(SARRAY *sa, const char *fileout)
writeMultipageTiffSA()
Definition tiffio.c:1555
l_ok pixWriteMemTiff(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype)
pixWriteMemTiff()
Definition tiffio.c:2815
static TIFF * fopenTiff(FILE *fp, const char *modestring)
fopenTiff()
Definition tiffio.c:2240
l_ok pixaWriteMultipageTiff(const char *fname, PIXA *pixa)
pixaWriteMultipageTiff()
Definition tiffio.c:1469
static l_int32 getTiffCompressedFormat(l_uint16 tiffcomp)
getTiffCompressedFormat()
Definition tiffio.c:2065
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:1717
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:1835
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:2115