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