New comit of SDL2
[supertux.git] / src / SDL2 / external / tiff-4.0.3 / tools / fax2tiff.c
1 /* $Id: fax2tiff.c,v 1.22 2010-03-10 18:56:49 bfriesen Exp $ */
2
3 /*
4  * Copyright (c) 1990-1997 Sam Leffler
5  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and 
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that (i) the above copyright notices and this permission notice appear in
10  * all copies of the software and related documentation, and (ii) the names of
11  * Sam Leffler and Silicon Graphics may not be used in any advertising or
12  * publicity relating to the software without the specific, prior written
13  * permission of Sam Leffler and Silicon Graphics.
14  * 
15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
18  * 
19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
24  * OF THIS SOFTWARE.
25  */
26
27 /* 
28  * Convert a CCITT Group 3 or 4 FAX file to TIFF Group 3 or 4 format.
29  */
30 #include "tif_config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>             /* should have atof & getopt */
34
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38
39 #ifdef HAVE_FCNTL_H
40 # include <fcntl.h>
41 #endif
42
43 #ifdef HAVE_IO_H
44 # include <io.h>
45 #endif
46
47 #ifdef NEED_LIBPORT
48 # include "libport.h"
49 #endif
50
51 #include "tiffiop.h"
52
53 #ifndef EXIT_SUCCESS
54 # define EXIT_SUCCESS   0
55 #endif
56 #ifndef EXIT_FAILURE
57 # define EXIT_FAILURE   1
58 #endif
59
60 #define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
61
62 TIFF    *faxTIFF;
63 char    *rowbuf;
64 char    *refbuf;
65
66 uint32  xsize = 1728;
67 int     verbose;
68 int     stretch;
69 uint16  badfaxrun;
70 uint32  badfaxlines;
71
72 int     copyFaxFile(TIFF* tifin, TIFF* tifout);
73 static  void usage(void);
74
75 int
76 main(int argc, char* argv[])
77 {
78         FILE *in;
79         TIFF *out = NULL;
80         TIFFErrorHandler whandler = NULL;
81         int compression_in = COMPRESSION_CCITTFAX3;
82         int compression_out = COMPRESSION_CCITTFAX3;
83         int fillorder_in = FILLORDER_LSB2MSB;
84         int fillorder_out = FILLORDER_LSB2MSB;
85         uint32 group3options_in = 0;    /* 1d-encoded */
86         uint32 group3options_out = 0;   /* 1d-encoded */
87         uint32 group4options_in = 0;    /* compressed */
88         uint32 group4options_out = 0;   /* compressed */
89         uint32 defrowsperstrip = (uint32) 0;
90         uint32 rowsperstrip;
91         int photometric_in = PHOTOMETRIC_MINISWHITE;
92         int photometric_out = PHOTOMETRIC_MINISWHITE;
93         int mode = FAXMODE_CLASSF;
94         int rows;
95         int c;
96         int pn, npages;
97         float resY = 196.0;
98         extern int optind;
99         extern char* optarg;
100
101
102         while ((c = getopt(argc, argv, "R:X:o:1234ABLMPUW5678abcflmprsuvwz?")) != -1)
103                 switch (c) {
104                         /* input-related options */
105                 case '3':               /* input is g3-encoded */
106                         compression_in = COMPRESSION_CCITTFAX3;
107                         break;
108                 case '4':               /* input is g4-encoded */
109                         compression_in = COMPRESSION_CCITTFAX4;
110                         break;
111                 case 'U':               /* input is uncompressed (g3 and g4) */
112                         group3options_in |= GROUP3OPT_UNCOMPRESSED;
113                         group4options_in |= GROUP4OPT_UNCOMPRESSED;
114                         break;
115                 case '1':               /* input is 1d-encoded (g3 only) */
116                         group3options_in &= ~GROUP3OPT_2DENCODING;
117                         break;
118                 case '2':               /* input is 2d-encoded (g3 only) */
119                         group3options_in |= GROUP3OPT_2DENCODING;
120                         break;
121                 case 'P':       /* input has not-aligned EOL (g3 only) */
122                         group3options_in &= ~GROUP3OPT_FILLBITS;
123                         break;
124                 case 'A':               /* input has aligned EOL (g3 only) */
125                         group3options_in |= GROUP3OPT_FILLBITS;
126                         break;
127                 case 'W':               /* input has 0 mean white */
128                         photometric_in = PHOTOMETRIC_MINISWHITE;
129                         break;
130                 case 'B':               /* input has 0 mean black */
131                         photometric_in = PHOTOMETRIC_MINISBLACK;
132                         break;
133                 case 'L':               /* input has lsb-to-msb fillorder */
134                         fillorder_in = FILLORDER_LSB2MSB;
135                         break;
136                 case 'M':               /* input has msb-to-lsb fillorder */
137                         fillorder_in = FILLORDER_MSB2LSB;
138                         break;
139                 case 'R':               /* input resolution */
140                         resY = (float) atof(optarg);
141                         break;
142                 case 'X':               /* input width */
143                         xsize = (uint32) atoi(optarg);
144                         break;
145
146                         /* output-related options */
147                 case '7':               /* generate g3-encoded output */
148                         compression_out = COMPRESSION_CCITTFAX3;
149                         break;
150                 case '8':               /* generate g4-encoded output */
151                         compression_out = COMPRESSION_CCITTFAX4;
152                         break;
153                 case 'u':       /* generate uncompressed output (g3 and g4) */
154                         group3options_out |= GROUP3OPT_UNCOMPRESSED;
155                         group4options_out |= GROUP4OPT_UNCOMPRESSED;
156                         break;
157                 case '5':       /* generate 1d-encoded output (g3 only) */
158                         group3options_out &= ~GROUP3OPT_2DENCODING;
159                         break;
160                 case '6':       /* generate 2d-encoded output (g3 only) */
161                         group3options_out |= GROUP3OPT_2DENCODING;
162                         break;
163                 case 'c':               /* generate "classic" g3 format */
164                         mode = FAXMODE_CLASSIC;
165                         break;
166                 case 'f':               /* generate Class F format */
167                         mode = FAXMODE_CLASSF;
168                         break;
169                 case 'm':               /* output's fillorder is msb-to-lsb */
170                         fillorder_out = FILLORDER_MSB2LSB;
171                         break;
172                 case 'l':               /* output's fillorder is lsb-to-msb */
173                         fillorder_out = FILLORDER_LSB2MSB;
174                         break;
175                 case 'o':
176                         out = TIFFOpen(optarg, "w");
177                         if (out == NULL) {
178                                 fprintf(stderr,
179                                     "%s: Can not create or open %s\n",
180                                     argv[0], optarg);
181                                 return EXIT_FAILURE;
182                         }
183                         break;
184                 case 'a':       /* generate EOL-aligned output (g3 only) */
185                         group3options_out |= GROUP3OPT_FILLBITS;
186                         break;
187                 case 'p':       /* generate not EOL-aligned output (g3 only) */
188                         group3options_out &= ~GROUP3OPT_FILLBITS;
189                         break;
190                 case 'r':               /* rows/strip */
191                         defrowsperstrip = atol(optarg);
192                         break;
193                 case 's':               /* stretch image by dup'ng scanlines */
194                         stretch = 1;
195                         break;
196                 case 'w':               /* undocumented -- for testing */
197                         photometric_out = PHOTOMETRIC_MINISWHITE;
198                         break;
199                 case 'b':               /* undocumented -- for testing */
200                         photometric_out = PHOTOMETRIC_MINISBLACK;
201                         break;
202                 case 'z':               /* undocumented -- for testing */
203                         compression_out = COMPRESSION_LZW;
204                         break;
205                 case 'v':               /* -v for info */
206                         verbose++;
207                         break;
208                 case '?':
209                         usage();
210                         /*NOTREACHED*/
211                 }
212         npages = argc - optind;
213         if (npages < 1)
214                 usage();
215
216         rowbuf = _TIFFmalloc(TIFFhowmany8(xsize));
217         refbuf = _TIFFmalloc(TIFFhowmany8(xsize));
218         if (rowbuf == NULL || refbuf == NULL) {
219                 fprintf(stderr, "%s: Not enough memory\n", argv[0]);
220                 return (EXIT_FAILURE);
221         }
222
223         if (out == NULL) {
224                 out = TIFFOpen("fax.tif", "w");
225                 if (out == NULL) {
226                         fprintf(stderr, "%s: Can not create fax.tif\n",
227                             argv[0]);
228                         return (EXIT_FAILURE);
229                 }
230         }
231                 
232         faxTIFF = TIFFClientOpen("(FakeInput)", "w",
233         /* TIFFClientOpen() fails if we don't set existing value here */
234                                  TIFFClientdata(out),
235                                  TIFFGetReadProc(out), TIFFGetWriteProc(out),
236                                  TIFFGetSeekProc(out), TIFFGetCloseProc(out),
237                                  TIFFGetSizeProc(out), TIFFGetMapFileProc(out),
238                                  TIFFGetUnmapFileProc(out));
239         if (faxTIFF == NULL) {
240                 fprintf(stderr, "%s: Can not create fake input file\n",
241                     argv[0]);
242                 return (EXIT_FAILURE);
243         }
244         TIFFSetMode(faxTIFF, O_RDONLY);
245         TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH,       xsize);
246         TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL,  1);
247         TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE,    1);
248         TIFFSetField(faxTIFF, TIFFTAG_FILLORDER,        fillorder_in);
249         TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG,     PLANARCONFIG_CONTIG);
250         TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC,      photometric_in);
251         TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION,      resY);
252         TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT,   RESUNIT_INCH);
253         
254         /* NB: this must be done after directory info is setup */
255         TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, compression_in);
256         if (compression_in == COMPRESSION_CCITTFAX3)
257                 TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, group3options_in);
258         else if (compression_in == COMPRESSION_CCITTFAX4)
259                 TIFFSetField(faxTIFF, TIFFTAG_GROUP4OPTIONS, group4options_in);
260         for (pn = 0; optind < argc; pn++, optind++) {
261                 in = fopen(argv[optind], "rb");
262                 if (in == NULL) {
263                         fprintf(stderr,
264                             "%s: %s: Can not open\n", argv[0], argv[optind]);
265                         continue;
266                 }
267 #if defined(_WIN32) && defined(USE_WIN32_FILEIO)
268                 TIFFSetClientdata(faxTIFF, (thandle_t)_get_osfhandle(fileno(in)));
269 #else
270                 TIFFSetClientdata(faxTIFF, (thandle_t)fileno(in));
271 #endif
272                 TIFFSetFileName(faxTIFF, (const char*)argv[optind]);
273                 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, xsize);
274                 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
275                 TIFFSetField(out, TIFFTAG_COMPRESSION, compression_out);
276                 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric_out);
277                 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
278                 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
279                 switch (compression_out) {
280                         /* g3 */
281                         case COMPRESSION_CCITTFAX3:
282                         TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
283                                      group3options_out);
284                         TIFFSetField(out, TIFFTAG_FAXMODE, mode);
285                         rowsperstrip =
286                                 (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
287                         break;
288
289                         /* g4 */
290                         case COMPRESSION_CCITTFAX4:
291                         TIFFSetField(out, TIFFTAG_GROUP4OPTIONS,
292                                      group4options_out);
293                         TIFFSetField(out, TIFFTAG_FAXMODE, mode);
294                         rowsperstrip =
295                                 (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
296                         break;
297
298                         default:
299                         rowsperstrip = (defrowsperstrip) ?
300                                 defrowsperstrip : TIFFDefaultStripSize(out, 0);
301                 }
302                 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
303                 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
304                 TIFFSetField(out, TIFFTAG_FILLORDER, fillorder_out);
305                 TIFFSetField(out, TIFFTAG_SOFTWARE, "fax2tiff");
306                 TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0);
307                 if (!stretch) {
308                         TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &resY);
309                         TIFFSetField(out, TIFFTAG_YRESOLUTION, resY);
310                 } else
311                         TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.);
312                 TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
313                 TIFFSetField(out, TIFFTAG_PAGENUMBER, pn, npages);
314
315                 if (!verbose)
316                     whandler = TIFFSetWarningHandler(NULL);
317                 rows = copyFaxFile(faxTIFF, out);
318                 fclose(in);
319                 if (!verbose)
320                     (void) TIFFSetWarningHandler(whandler);
321
322                 TIFFSetField(out, TIFFTAG_IMAGELENGTH, rows);
323
324                 if (verbose) {
325                         fprintf(stderr, "%s:\n", argv[optind]);
326                         fprintf(stderr, "%d rows in input\n", rows);
327                         fprintf(stderr, "%ld total bad rows\n",
328                             (long) badfaxlines);
329                         fprintf(stderr, "%d max consecutive bad rows\n", badfaxrun);
330                 }
331                 if (compression_out == COMPRESSION_CCITTFAX3 &&
332                     mode == FAXMODE_CLASSF) {
333                         TIFFSetField(out, TIFFTAG_BADFAXLINES, badfaxlines);
334                         TIFFSetField(out, TIFFTAG_CLEANFAXDATA, badfaxlines ?
335                             CLEANFAXDATA_REGENERATED : CLEANFAXDATA_CLEAN);
336                         TIFFSetField(out, TIFFTAG_CONSECUTIVEBADFAXLINES, badfaxrun);
337                 }
338                 TIFFWriteDirectory(out);
339         }
340         TIFFClose(out);
341         _TIFFfree(rowbuf);
342         _TIFFfree(refbuf);
343         return (EXIT_SUCCESS);
344 }
345
346 int
347 copyFaxFile(TIFF* tifin, TIFF* tifout)
348 {
349         uint32 row;
350         uint32 linesize = TIFFhowmany8(xsize);
351         uint16 badrun;
352         int ok;
353
354         tifin->tif_rawdatasize = (tmsize_t)TIFFGetFileSize(tifin);
355         tifin->tif_rawdata = _TIFFmalloc(tifin->tif_rawdatasize);
356         if (tifin->tif_rawdata == NULL) {
357                 TIFFError(tifin->tif_name, "Not enough memory");
358                 return (0);
359         }
360         if (!ReadOK(tifin, tifin->tif_rawdata, tifin->tif_rawdatasize)) {
361                 TIFFError(tifin->tif_name, "Read error at scanline 0");
362                 return (0);
363         }
364         tifin->tif_rawcp = tifin->tif_rawdata;
365         tifin->tif_rawcc = tifin->tif_rawdatasize;
366
367         (*tifin->tif_setupdecode)(tifin);
368         (*tifin->tif_predecode)(tifin, (tsample_t) 0);
369         tifin->tif_row = 0;
370         badfaxlines = 0;
371         badfaxrun = 0;
372
373         _TIFFmemset(refbuf, 0, linesize);
374         row = 0;
375         badrun = 0;             /* current run of bad lines */
376         while (tifin->tif_rawcc > 0) {
377                 ok = (*tifin->tif_decoderow)(tifin, (tdata_t) rowbuf, 
378                                              linesize, 0);
379                 if (!ok) {
380                         badfaxlines++;
381                         badrun++;
382                         /* regenerate line from previous good line */
383                         _TIFFmemcpy(rowbuf, refbuf, linesize);
384                 } else {
385                         if (badrun > badfaxrun)
386                                 badfaxrun = badrun;
387                         badrun = 0;
388                         _TIFFmemcpy(refbuf, rowbuf, linesize);
389                 }
390                 tifin->tif_row++;
391
392                 if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
393                         fprintf(stderr, "%s: Write error at row %ld.\n",
394                             tifout->tif_name, (long) row);
395                         break;
396                 }
397                 row++;
398                 if (stretch) {
399                         if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
400                                 fprintf(stderr, "%s: Write error at row %ld.\n",
401                                     tifout->tif_name, (long) row);
402                                 break;
403                         }
404                         row++;
405                 }
406         }
407         if (badrun > badfaxrun)
408                 badfaxrun = badrun;
409         _TIFFfree(tifin->tif_rawdata);
410         return (row);
411 }
412
413 char* stuff[] = {
414 "usage: fax2tiff [options] input.raw...",
415 "where options are:",
416 " -3            input data is G3-encoded                [default]",
417 " -4            input data is G4-encoded",
418 " -U            input data is uncompressed (G3 or G4)",
419 " -1            input data is 1D-encoded (G3 only)      [default]",
420 " -2            input data is 2D-encoded (G3 only)",
421 " -P            input is not EOL-aligned (G3 only)      [default]",
422 " -A            input is EOL-aligned (G3 only)",
423 " -M            input data has MSB2LSB bit order",
424 " -L            input data has LSB2MSB bit order        [default]",
425 " -B            input data has min 0 means black",
426 " -W            input data has min 0 means white        [default]",
427 " -R #          input data has # resolution (lines/inch) [default is 196]",
428 " -X #          input data has # width                  [default is 1728]",
429 "",
430 " -o out.tif    write output to out.tif",
431 " -7            generate G3-encoded output              [default]",
432 " -8            generate G4-encoded output",
433 " -u            generate uncompressed output (G3 or G4)",
434 " -5            generate 1D-encoded output (G3 only)",
435 " -6            generate 2D-encoded output (G3 only)    [default]",
436 " -p            generate not EOL-aligned output (G3 only)",
437 " -a            generate EOL-aligned output (G3 only)   [default]",
438 " -c            generate \"classic\" TIFF format",
439 " -f            generate TIFF Class F (TIFF/F) format   [default]",
440 " -m            output fill order is MSB2LSB",
441 " -l            output fill order is LSB2MSB            [default]",
442 " -r #          make each strip have no more than # rows",
443 " -s            stretch image by duplicating scanlines",
444 " -v            print information about conversion work",
445 " -z            generate LZW compressed output",
446 NULL
447 };
448
449 static void
450 usage(void)
451 {
452         char buf[BUFSIZ];
453         int i;
454
455         setbuf(stderr, buf);
456         fprintf(stderr, "%s\n\n", TIFFGetVersion());
457         for (i = 0; stuff[i] != NULL; i++)
458                 fprintf(stderr, "%s\n", stuff[i]);
459         exit(EXIT_FAILURE);
460 }
461
462 /* vim: set ts=8 sts=8 sw=8 noet: */
463 /*
464  * Local Variables:
465  * mode: c
466  * c-basic-offset: 8
467  * fill-column: 78
468  * End:
469  */