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 
27 /*
28  * mtiff_reg.c
29  *
30  *   Tests tiff I/O for:
31  *
32  *       - multipage tiff read/write
33  *       - writing special tiff tags to file [not tested here]
34  */
35 
36 #include "allheaders.h"
37 #include <string.h>
38 
39 static const char *weasel_rev = "/tmp/lept/tiff/weasel_rev.tif";
40 static const char *weasel_rev_rev = "/tmp/lept/tiff/weasel_rev_rev.tif";
41 static const char *weasel_orig = "/tmp/lept/tiff/weasel_orig.tif";
42 
main(int argc,char ** argv)43 int main(int    argc,
44          char **argv)
45 {
46 l_uint8      *data;
47 char         *fname, *filename;
48 const char   *str;
49 char          buf[512];
50 l_int32       i, n, npages, equal, success;
51 size_t        length, offset, size;
52 FILE         *fp;
53 NUMA         *naflags, *nasizes;
54 PIX          *pix, *pix1, *pix2;
55 PIXA         *pixa, *pixa1, *pixa2, *pixa3;
56 SARRAY       *savals, *satypes, *sa;
57 L_REGPARAMS  *rp;
58 
59    if (regTestSetup(argc, argv, &rp))
60         return 1;
61 
62     lept_mkdir("lept/tiff");
63 
64     /* ----------------------  Test multipage I/O  -----------------------*/
65         /* This puts every image file in the directory with a string
66          * match to "weasel8" into a multipage tiff file.
67          * Images with 1 bpp are coded as g4; the others as zip.
68          * It then reads back into a pix and displays.  */
69     writeMultipageTiff(".", "weasel8.", "/tmp/lept/tiff/weasel8.tif");
70     regTestCheckFile(rp, "/tmp/lept/tiff/weasel8.tif");  /* 0 */
71     pixa = pixaReadMultipageTiff("/tmp/lept/tiff/weasel8.tif");
72     pix1 = pixaDisplayTiledInRows(pixa, 1, 1200, 0.5, 0, 15, 4);
73     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 1 */
74     pixDisplayWithTitle(pix1, 0, 0, NULL, rp->display);
75     pixDestroy(&pix1);
76     pix1 = pixaDisplayTiledInRows(pixa, 8, 1200, 0.8, 0, 15, 4);
77     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 2 */
78     pixDisplayWithTitle(pix1, 0, 200, NULL, rp->display);
79     pixDestroy(&pix1);
80     pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.2, 0, 15, 4);
81     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 3 */
82     pixDisplayWithTitle(pix1, 0, 400, NULL, rp->display);
83     pixDestroy(&pix1);
84     pixaDestroy(&pixa);
85 
86         /* This uses the offset method for linearizing overhead of
87          * reading from a multi-image tiff file. */
88     offset = 0;
89     n = 0;
90     pixa = pixaCreate(8);
91     do {
92         pix1 = pixReadFromMultipageTiff("/tmp/lept/tiff/weasel8.tif", &offset);
93         if (!pix1) continue;
94         pixaAddPix(pixa, pix1, L_INSERT);
95         if (rp->display)
96              fprintf(stderr, "offset = %ld\n", (unsigned long)offset);
97         n++;
98     } while (offset != 0);
99     if (rp->display) fprintf(stderr, "Num images = %d\n", n);
100     pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.2, 0, 15, 4);
101     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 4 */
102     pixDisplayWithTitle(pix1, 0, 600, NULL, rp->display);
103     pixDestroy(&pix1);
104     pixaDestroy(&pixa);
105 
106         /* This uses the offset method for linearizing overhead of
107          * reading from a multi-image tiff file in memory. */
108     offset = 0;
109     n = 0;
110     pixa = pixaCreate(8);
111     data = l_binaryRead("/tmp/lept/tiff/weasel8.tif", &size);
112     do {
113         pix1 = pixReadMemFromMultipageTiff(data, size, &offset);
114         if (!pix1) continue;
115         pixaAddPix(pixa, pix1, L_INSERT);
116         if (rp->display)
117             fprintf(stderr, "offset = %ld\n", (unsigned long)offset);
118         n++;
119     } while (offset != 0);
120     if (rp->display) fprintf(stderr, "Num images = %d\n", n);
121     pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.2, 0, 15, 4);
122     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 5 */
123     pixDisplayWithTitle(pix1, 0, 800, NULL, rp->display);
124     pixDestroy(&pix1);
125     pixaDestroy(&pixa);
126     lept_free(data);
127     regTestCompareFiles(rp, 3, 4);  /* 6 */
128     regTestCompareFiles(rp, 3, 5);  /* 7 */
129 
130         /* This makes a 1000 image tiff file and gives timing
131          * for writing and reading.  Reading uses both the offset method
132          * for returning individual pix and atomic pixaReadMultipageTiff()
133          * method for returning a pixa of all the images.  Reading time
134          * is linear in the number of images, but the writing time is
135          *  quadratic, and the actual wall clock time is significantly
136          *  more than the printed value. */
137     pix1 = pixRead("char.tif");
138     startTimer();
139     pixWriteTiff("/tmp/lept/tiff/junkm.tif", pix1, IFF_TIFF_G4, "w");
140     for (i = 1; i < 1000; i++) {
141         pixWriteTiff("/tmp/lept/tiff/junkm.tif", pix1, IFF_TIFF_G4, "a");
142     }
143     regTestCheckFile(rp, "/tmp/lept/tiff/junkm.tif");  /* 8 */
144     pixDestroy(&pix1);
145     if (rp->display) {
146         fprintf(stderr, "\n1000 image file: /tmp/lept/tiff/junkm.tif\n");
147         fprintf(stderr, "Time to write 1000 images: %7.3f sec\n", stopTimer());
148     }
149 
150     startTimer();
151     offset = 0;
152     n = 0;
153     do {
154         pix1 = pixReadFromMultipageTiff("/tmp/lept/tiff/junkm.tif", &offset);
155         if (!pix1) continue;
156         if (rp->display && (n % 100 == 0))
157             fprintf(stderr, "offset = %ld\n", (unsigned long)offset);
158         pixDestroy(&pix1);
159         n++;
160     } while (offset != 0);
161     regTestCompareValues(rp, 1000, n, 0);  /* 9 */
162     if (rp->display)
163         fprintf(stderr, "Time to read %d images: %6.3f sec\n", n, stopTimer());
164 
165     startTimer();
166     pixa = pixaReadMultipageTiff("/tmp/lept/tiff/junkm.tif");
167     fprintf(stderr, "Time to read %d images and return a pixa: %6.3f sec\n",
168             pixaGetCount(pixa), stopTimer());
169     pix1 = pixaDisplayTiledInRows(pixa, 8, 1500, 0.8, 0, 15, 4);
170     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 10 */
171     pixDestroy(&pix1);
172     pixaDestroy(&pixa);
173 
174         /* This does the following sequence of operations:
175          * (1) makes pixa1 and writes a multipage tiff file from it
176          * (2) reads that file into memory
177          * (3) generates pixa2 from the data in memory
178          * (4) tiff compresses pixa2 back to memory
179          * (5) generates pixa3 by uncompressing the memory data
180          * (6) compares pixa3 with pixa1   */
181     pix1 = pixRead("weasel8.240c.png");  /* (1) */
182     pixa1 = pixaCreate(10);
183     for (i = 0; i < 10; i++)
184         pixaAddPix(pixa1, pix1, L_COPY);
185     pixDestroy(&pix1);
186     pixaWriteMultipageTiff("/tmp/lept/tiff/junkm2.tif", pixa1);
187     regTestCheckFile(rp, "/tmp/lept/tiff/junkm2.tif");  /* 11 */
188     data = l_binaryRead("/tmp/lept/tiff/junkm2.tif", &size);  /* (2) */
189     pixa2 = pixaCreate(10);  /* (3) */
190     offset = 0;
191     n = 0;
192     do {
193         pix1 = pixReadMemFromMultipageTiff(data, size, &offset);
194         pixaAddPix(pixa2, pix1, L_INSERT);
195         n++;
196     } while (offset != 0);
197     regTestCompareValues(rp, 10, n, 0);  /* 12 */
198     if (rp->display) fprintf(stderr, "\nRead %d images\n", n);
199     lept_free(data);
200     pixaWriteMemMultipageTiff(&data, &size, pixa2);  /* (4) */
201     pixa3 = pixaReadMemMultipageTiff(data, size);  /* (5) */
202     pix1 = pixaDisplayTiledInRows(pixa3, 8, 1500, 0.8, 0, 15, 4);
203     regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 13 */
204     pixDestroy(&pix1);
205     n = pixaGetCount(pixa3);
206     if (rp->display) fprintf(stderr, "Write/read %d images\n", n);
207     success = TRUE;
208     for (i = 0; i < n; i++) {
209         pix1 = pixaGetPix(pixa1, i, L_CLONE);
210         pix2 = pixaGetPix(pixa3, i, L_CLONE);
211         pixEqual(pix1, pix2, &equal);
212         if (!equal) success = FALSE;
213         pixDestroy(&pix1);
214         pixDestroy(&pix2);
215     }
216     regTestCompareValues(rp, TRUE, success, 0);  /* 14 */
217     pixaDestroy(&pixa1);
218     pixaDestroy(&pixa2);
219     pixaDestroy(&pixa3);
220     lept_free(data);
221 
222     /* ------------------ Test single-to-multipage I/O  -------------------*/
223         /* Read the files and generate a multipage tiff file of G4 images.
224          * Then convert that to a G4 compressed and ascii85 encoded PS file. */
225     sa = getSortedPathnamesInDirectory(".", "weasel4.", 0, 4);
226     if (rp->display) sarrayWriteStream(stderr, sa);
227     sarraySort(sa, sa, L_SORT_INCREASING);
228     if (rp->display) sarrayWriteStream(stderr, sa);
229     npages = sarrayGetCount(sa);
230     for (i = 0; i < npages; i++) {
231         fname = sarrayGetString(sa, i, L_NOCOPY);
232         filename = genPathname(".", fname);
233         pix1 = pixRead(filename);
234         if (!pix1) continue;
235         pix2 = pixConvertTo1(pix1, 128);
236         if (i == 0)
237             pixWriteTiff("/tmp/lept/tiff/weasel4", pix2, IFF_TIFF_G4, "w+");
238         else
239             pixWriteTiff("/tmp/lept/tiff/weasel4", pix2, IFF_TIFF_G4, "a");
240         pixDestroy(&pix1);
241         pixDestroy(&pix2);
242         lept_free(filename);
243     }
244     regTestCheckFile(rp, "/tmp/lept/tiff/junkm2.tif");  /* 15 */
245 
246         /* Write it out as a PS file */
247     fprintf(stderr, "Writing to: /tmp/lept/tiff/weasel4.ps\n");
248     convertTiffMultipageToPS("/tmp/lept/tiff/weasel4",
249                              "/tmp/lept/tiff/weasel4.ps", 0.95);
250     regTestCheckFile(rp, "/tmp/lept/tiff/weasel4.ps");  /* 16 */
251 
252         /* Write it out as a pdf file */
253     fprintf(stderr, "Writing to: /tmp/lept/tiff/weasel4.pdf\n");
254     l_pdfSetDateAndVersion(FALSE);
255     convertTiffMultipageToPdf("/tmp/lept/tiff/weasel4",
256                               "/tmp/lept/tiff/weasel4.pdf");
257     regTestCheckFile(rp, "/tmp/lept/tiff/weasel4.pdf");  /* 17 */
258     sarrayDestroy(&sa);
259 
260     /* ------------------  Test multipage I/O  -------------------*/
261         /* Read count of pages in tiff multipage  file */
262     writeMultipageTiff(".", "weasel2", weasel_orig);
263     regTestCheckFile(rp, weasel_orig);  /* 18 */
264     fp = lept_fopen(weasel_orig, "rb");
265     success = fileFormatIsTiff(fp);
266     regTestCompareValues(rp, TRUE, success, 0);  /* 19 */
267     if (success) {
268         tiffGetCount(fp, &npages);
269         regTestCompareValues(rp, 4, npages, 0);  /* 20 */
270         fprintf(stderr, " Tiff: %d page\n", npages);
271     }
272     lept_fclose(fp);
273 
274         /* Split into separate page files */
275     for (i = 0; i < npages + 1; i++) {   /* read one beyond to catch error */
276         pix1 = pixReadTiff(weasel_orig, i);
277         if (!pix1) continue;
278         snprintf(buf, sizeof(buf), "/tmp/lept/tiff/%03d.tif", i);
279         pixWrite(buf, pix1, IFF_TIFF_ZIP);
280         pixDestroy(&pix1);
281     }
282 
283         /* Read separate page files and write reversed file */
284     for (i = npages - 1; i >= 0; i--) {
285         snprintf(buf, sizeof(buf), "/tmp/lept/tiff/%03d.tif", i);
286         pix1 = pixRead(buf);
287         if (!pix1) continue;
288         if (i == npages - 1)
289             pixWriteTiff(weasel_rev, pix1, IFF_TIFF_ZIP, "w+");
290         else
291             pixWriteTiff(weasel_rev, pix1, IFF_TIFF_ZIP, "a");
292         pixDestroy(&pix1);
293     }
294     regTestCheckFile(rp, weasel_rev);  /* 21 */
295 
296         /* Read reversed file and reverse again */
297     pixa = pixaCreate(npages);
298     for (i = 0; i < npages; i++) {
299         pix1 = pixReadTiff(weasel_rev, i);
300         pixaAddPix(pixa, pix1, L_INSERT);
301     }
302     for (i = npages - 1; i >= 0; i--) {
303         pix1 = pixaGetPix(pixa, i, L_CLONE);
304         if (i == npages - 1)
305             pixWriteTiff(weasel_rev_rev, pix1, IFF_TIFF_ZIP, "w+");
306         else
307             pixWriteTiff(weasel_rev_rev, pix1, IFF_TIFF_ZIP, "a");
308         pixDestroy(&pix1);
309     }
310     regTestCheckFile(rp, weasel_rev_rev);  /* 22 */
311     regTestCompareFiles(rp, 18, 22);  /* 23 */
312     pixaDestroy(&pixa);
313 
314 
315 #if 0    /* -----   test adding custom public tags to a tiff header ----- */
316     pix = pixRead("feyn.tif");
317     naflags = numaCreate(10);
318     savals = sarrayCreate(10);
319     satypes = sarrayCreate(10);
320     nasizes = numaCreate(10);
321 
322 /*    numaAddNumber(naflags, TIFFTAG_XMLPACKET);  */ /* XMP:  700 */
323     numaAddNumber(naflags, 700);
324     str = "<xmp>This is a Fake XMP packet</xmp>\n<text>Guess what ...?</text>";
325     length = strlen(str);
326     sarrayAddString(savals, (char *)str, L_COPY);
327     sarrayAddString(satypes, (char *)"char*", L_COPY);
328     numaAddNumber(nasizes, length);  /* get it all */
329 
330     numaAddNumber(naflags, 269);  /* DOCUMENTNAME */
331     sarrayAddString(savals, (char *)"One silly title", L_COPY);
332     sarrayAddString(satypes, (char *)"const char*", L_COPY);
333     numaAddNumber(naflags, 270);  /* IMAGEDESCRIPTION */
334     sarrayAddString(savals, (char *)"One page of text", L_COPY);
335     sarrayAddString(satypes, (char *)"const char*", L_COPY);
336         /* the max sample is used by rendering programs
337          * to scale the dynamic range */
338     numaAddNumber(naflags, 281);  /* MAXSAMPLEVALUE */
339     sarrayAddString(savals, (char *)"4", L_COPY);
340     sarrayAddString(satypes, (char *)"l_uint16", L_COPY);
341         /* note that date is required to be a 20 byte string */
342     numaAddNumber(naflags, 306);  /* DATETIME */
343     sarrayAddString(savals, (char *)"2004:10:11 09:35:15", L_COPY);
344     sarrayAddString(satypes, (char *)"const char*", L_COPY);
345         /* note that page number requires 2 l_uint16 input */
346     numaAddNumber(naflags, 297);  /* PAGENUMBER */
347     sarrayAddString(savals, (char *)"1-412", L_COPY);
348     sarrayAddString(satypes, (char *)"l_uint16-l_uint16", L_COPY);
349     pixWriteTiffCustom("/tmp/lept/tiff/tags.tif", pix, IFF_TIFF_G4, "w", naflags,
350                        savals, satypes, nasizes);
351     fprintTiffInfo(stderr, (char *)"/tmp/lept/tiff/tags.tif");
352     fprintf(stderr, "num flags = %d\n", numaGetCount(naflags));
353     fprintf(stderr, "num sizes = %d\n", numaGetCount(nasizes));
354     fprintf(stderr, "num vals = %d\n", sarrayGetCount(savals));
355     fprintf(stderr, "num types = %d\n", sarrayGetCount(satypes));
356     numaDestroy(&naflags);
357     numaDestroy(&nasizes);
358     sarrayDestroy(&savals);
359     sarrayDestroy(&satypes);
360     pixDestroy(&pix);
361 #endif
362 
363     return regTestCleanup(rp);
364 }
365