summaryrefslogtreecommitdiff
path: root/tools/fax2tiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/fax2tiff.c')
-rw-r--r--tools/fax2tiff.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/tools/fax2tiff.c b/tools/fax2tiff.c
new file mode 100644
index 00000000..582ccb3a
--- /dev/null
+++ b/tools/fax2tiff.c
@@ -0,0 +1,361 @@
+/* $Header: /usr/people/sam/tiff/tools/RCS/fax2tiff.c,v 1.37 1995/07/17 01:36:52 sam Exp $ */
+
+/*
+ * Copyright (c) 1990-1995 Sam Leffler
+ * Copyright (c) 1991-1995 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * Convert a CCITT Group 3 FAX file to TIFF Group 3 format.
+ */
+#if defined(unix) || defined(__unix)
+#include "port.h"
+#else
+#include <stdio.h>
+#include <stdlib.h> /* should have atof & getopt */
+#endif
+#include "tiffiop.h"
+
+#ifndef BINMODE
+#define BINMODE
+#endif
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+TIFF *faxTIFF;
+#define XSIZE 1728
+u_char rowbuf[TIFFhowmany(XSIZE,8)];
+u_char refbuf[TIFFhowmany(XSIZE,8)];
+
+int verbose;
+int stretch;
+uint16 badfaxrun;
+uint32 badfaxlines;
+
+int copyFaxFile(TIFF* tifin, TIFF* tifout);
+static void usage(void);
+
+static tsize_t
+DummyReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ (void) fd; (void) buf; (void) size;
+ return (0);
+}
+
+static tsize_t
+DummyWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ (void) fd; (void) buf; (void) size;
+ return (size);
+}
+
+int
+main(int argc, char* argv[])
+{
+ FILE *in;
+ TIFF *out = NULL;
+ TIFFErrorHandler whandler;
+ int compression = COMPRESSION_CCITTFAX3;
+ int fillorder = FILLORDER_LSB2MSB;
+ uint32 group3options = GROUP3OPT_FILLBITS|GROUP3OPT_2DENCODING;
+ int photometric = PHOTOMETRIC_MINISWHITE;
+ int mode = FAXMODE_CLASSF;
+ int rows;
+ int c;
+ int pn, npages;
+ extern int optind;
+ extern char* optarg;
+
+ /* smuggle a descriptor out of the library */
+ faxTIFF = TIFFClientOpen("(FakeInput)", "w", (thandle_t) -1,
+ DummyReadProc, DummyWriteProc,
+ NULL, NULL, NULL, NULL, NULL);
+ if (faxTIFF == NULL)
+ return (EXIT_FAILURE);
+ faxTIFF->tif_mode = O_RDONLY;
+
+ TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH, XSIZE);
+ TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(faxTIFF, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
+ TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
+ TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION, 196.);
+ TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ /* NB: this is normally setup when a directory is read */
+ faxTIFF->tif_scanlinesize = TIFFScanlineSize(faxTIFF);
+
+ while ((c = getopt(argc, argv, "R:o:2BLMW14cflmpsvwz")) != -1)
+ switch (c) {
+ /* input-related options */
+ case '2': /* input is 2d-encoded */
+ TIFFSetField(faxTIFF,
+ TIFFTAG_GROUP3OPTIONS, GROUP3OPT_2DENCODING);
+ break;
+ case 'B': /* input has 0 mean black */
+ TIFFSetField(faxTIFF,
+ TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ break;
+ case 'L': /* input has lsb-to-msb fillorder */
+ TIFFSetField(faxTIFF,
+ TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
+ break;
+ case 'M': /* input has msb-to-lsb fillorder */
+ TIFFSetField(faxTIFF,
+ TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+ break;
+ case 'R': /* input resolution */
+ TIFFSetField(faxTIFF,
+ TIFFTAG_YRESOLUTION, atof(optarg));
+ break;
+ case 'W': /* input has 0 mean white */
+ TIFFSetField(faxTIFF,
+ TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
+ break;
+
+ /* output-related options */
+ case '1': /* generate 1d-encoded output */
+ group3options &= ~GROUP3OPT_2DENCODING;
+ break;
+ case '4': /* generate g4-encoded output */
+ compression = COMPRESSION_CCITTFAX4;
+ break;
+ case 'c': /* generate "classic" g3 format */
+ mode = FAXMODE_CLASSIC;
+ break;
+ case 'f': /* generate Class F format */
+ mode = FAXMODE_CLASSF;
+ break;
+ case 'm': /* output's fillorder is msb-to-lsb */
+ fillorder = FILLORDER_MSB2LSB;
+ break;
+ case 'o':
+ out = TIFFOpen(optarg, "w");
+ if (out == NULL)
+ return EXIT_FAILURE;
+ break;
+ case 'p': /* zero pad output scanline EOLs */
+ group3options &= ~GROUP3OPT_FILLBITS;
+ break;
+ case 's': /* stretch image by dup'ng scanlines */
+ stretch = 1;
+ break;
+ case 'w': /* undocumented -- for testing */
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+
+ case 'z': /* undocumented -- for testing */
+ compression = COMPRESSION_LZW;
+ break;
+
+ case 'v': /* -v for info */
+ verbose++;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (out == NULL) {
+ out = TIFFOpen("fax.tif", "w");
+ if (out == NULL)
+ return (EXIT_FAILURE);
+ }
+ faxTIFF->tif_readproc = out->tif_readproc; /* XXX */
+ faxTIFF->tif_writeproc = out->tif_writeproc; /* XXX */
+ faxTIFF->tif_seekproc = out->tif_seekproc; /* XXX */
+ faxTIFF->tif_closeproc = out->tif_closeproc; /* XXX */
+ faxTIFF->tif_sizeproc = out->tif_sizeproc; /* XXX */
+ faxTIFF->tif_mapproc = out->tif_mapproc; /* XXX */
+ faxTIFF->tif_unmapproc = out->tif_unmapproc; /* XXX */
+
+ npages = argc - optind;
+ if (npages < 1)
+ usage();
+
+ /* NB: this must be done after directory info is setup */
+ TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
+ for (pn = 0; optind < argc; pn++, optind++) {
+ in = fopen(argv[optind], "r" BINMODE);
+ if (in == NULL) {
+ fprintf(stderr,
+ "%s: %s: Can not open\n", argv[0], argv[optind]);
+ continue;
+ }
+ faxTIFF->tif_fd = fileno(in);
+ faxTIFF->tif_clientdata = (thandle_t) faxTIFF->tif_fd;
+ faxTIFF->tif_name = argv[optind];
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, XSIZE);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ if (compression == COMPRESSION_CCITTFAX3) {
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, group3options);
+ TIFFSetField(out, TIFFTAG_FAXMODE, mode);
+ }
+ if (compression == COMPRESSION_CCITTFAX3 ||
+ compression == COMPRESSION_CCITTFAX4)
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, -1L);
+ else
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, 0));
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, "fax2tiff");
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0);
+ if (!stretch) {
+ float yres;
+ TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &yres);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, yres);
+ } else
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.);
+ TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pn+1, npages);
+
+ if (!verbose)
+ whandler = TIFFSetWarningHandler(NULL);
+ rows = copyFaxFile(faxTIFF, out);
+ fclose(in);
+ if (!verbose)
+ (void) TIFFSetWarningHandler(whandler);
+
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, rows);
+
+ if (verbose) {
+ fprintf(stderr, "%s:\n", argv[optind]);
+ fprintf(stderr, "%d rows in input\n", rows);
+ fprintf(stderr, "%d total bad rows\n", badfaxlines);
+ fprintf(stderr, "%d max consecutive bad rows\n", badfaxrun);
+ }
+ if (compression == COMPRESSION_CCITTFAX3 &&
+ mode == FAXMODE_CLASSF) {
+ TIFFSetField(out, TIFFTAG_BADFAXLINES, badfaxlines);
+ TIFFSetField(out, TIFFTAG_CLEANFAXDATA, badfaxlines ?
+ CLEANFAXDATA_REGENERATED : CLEANFAXDATA_CLEAN);
+ TIFFSetField(out, TIFFTAG_CONSECUTIVEBADFAXLINES, badfaxrun);
+ }
+ TIFFWriteDirectory(out);
+ }
+ TIFFClose(out);
+ return (EXIT_SUCCESS);
+}
+
+int
+copyFaxFile(TIFF* tifin, TIFF* tifout)
+{
+ uint32 row;
+ uint16 badrun;
+ int ok;
+
+ tifin->tif_rawdatasize = TIFFGetFileSize(tifin);
+ tifin->tif_rawdata = _TIFFmalloc(tifin->tif_rawdatasize);
+ if (!ReadOK(tifin, tifin->tif_rawdata, tifin->tif_rawdatasize)) {
+ TIFFError(tifin->tif_name, "%s: Read error at scanline 0");
+ return (0);
+ }
+ tifin->tif_rawcp = tifin->tif_rawdata;
+ tifin->tif_rawcc = tifin->tif_rawdatasize;
+
+ (*tifin->tif_setupdecode)(tifin);
+ (*tifin->tif_predecode)(tifin, (tsample_t) 0);
+ tifin->tif_row = 0;
+ badfaxlines = 0;
+ badfaxrun = 0;
+
+ _TIFFmemset(refbuf, 0, sizeof (refbuf));
+ row = 0;
+ badrun = 0; /* current run of bad lines */
+ while (tifin->tif_rawcc > 0) {
+ ok = (*tifin->tif_decoderow)(tifin, rowbuf, sizeof (rowbuf), 0);
+ if (!ok) {
+ badfaxlines++;
+ badrun++;
+ /* regenerate line from previous good line */
+ _TIFFmemcpy(rowbuf, refbuf, sizeof (rowbuf));
+ } else {
+ if (badrun > badfaxrun)
+ badfaxrun = badrun;
+ badrun = 0;
+ _TIFFmemcpy(refbuf, rowbuf, sizeof (rowbuf));
+ }
+ tifin->tif_row++;
+
+ if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
+ fprintf(stderr, "%s: Write error at row %ld.\n",
+ tifout->tif_name, row);
+ break;
+ }
+ row++;
+ if (stretch) {
+ if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
+ fprintf(stderr, "%s: Write error at row %ld.\n",
+ tifout->tif_name, row);
+ break;
+ }
+ row++;
+ }
+ }
+ if (badrun > badfaxrun)
+ badfaxrun = badrun;
+ _TIFFfree(tifin->tif_rawdata);
+ return (row);
+}
+
+char* stuff[] = {
+"usage: fax2tiff [options] input.g3...",
+"where options are:",
+" -2 input data is 2d encoded",
+" -B input data has min 0 means black",
+" -L input data has LSB2MSB bit order (default)",
+" -M input data has MSB2LSB bit order",
+" -W input data has min 0 means white (default)",
+" -R # input data has # resolution (lines/inch) (default is 196)",
+"",
+" -o out.tif write output to out.tif",
+" -1 generate 1d-encoded output (default is G3 2d)",
+" -4 generate G4-encoded output (default is G3 2D)",
+" -c generate \"classic\" TIFF format (default is TIFF/F)",
+" -f generate TIFF Class F (TIFF/F) format (default)",
+" -m output fill order is MSB2LSB (default is LSB2MSB)",
+" -p do not byte-align EOL codes in output (default is byte-align)",
+" -s stretch image by duplicating scanlines",
+" -v print information about conversion work",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(EXIT_FAILURE);
+}