Exemplo n.º 1
0
int
fax2tiffmain(char* inputfile, char* outputfile,int bitorder,int stretchit, int faxtype)
{
  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;
  
  if(stretchit)
    stretch = 1;
  else
    stretch = 0;


  /* 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);
	
  /* input is 2d-encoded */
  /*  if(faxtype == 32)
    TIFFSetField(faxTIFF,TIFFTAG_GROUP3OPTIONS, GROUP3OPT_2DENCODING);	
    */
  /* input has 0 mean black */
  /*		TIFFSetField(faxTIFF,
		TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);*/
  /* input has lsb-to-msb fillorder */

  if(bitorder == 1){

  /* input has lsb-to-msb fillorder */
    TIFFSetField(faxTIFF,
		 TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
  }
  else{

    /*input has msb-to-lsb fillorder*/

    TIFFSetField(faxTIFF,
		 TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
  }


  /* input resolution */
  /*			TIFFSetField(faxTIFF,
			TIFFTAG_YRESOLUTION, atof(optarg));*/
  /* input has 0 mean white */
  /*			TIFFSetField(faxTIFF,
			TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);*/
  /* output-related options */
  /* generate 1d-encoded output */
  /*			group3options &= ~GROUP3OPT_2DENCODING;*/
  /* generate g4-encoded output */
  /*			compression = COMPRESSION_CCITTFAX4;*/
  
  /* TODO CHECK THIS OUT !!! */

  /* generate "classic" g3 format */
  /*	mode = FAXMODE_CLASSIC;*/
  /* generate Class F format */
  /*		mode = FAXMODE_CLASSF;*/
  /* output's fillorder is msb-to-lsb */
  /*			fillorder = FILLORDER_MSB2LSB;*/


  out = TIFFOpen(outputfile, "w");
  if (out == NULL)
    return EXIT_FAILURE;

  /* zero pad output scanline EOLs */
  /*			group3options &= ~GROUP3OPT_FILLBITS;*/
  /* stretch image by dup'ng scanlines */
  /*			stretch = 1;*/
  /* undocumented -- for testing */
  /*			photometric = PHOTOMETRIC_MINISBLACK;*/
  /* undocumented -- for testing */
  /*			compression = COMPRESSION_LZW;*/


  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;*/ /* TODO ???????*/

  npages = 1;

  /* NB: this must be done after directory info is setup */
  
  
  if(faxtype == 4)
    TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
  else /* faxtype == 32 or 31 */
    TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  
  if (faxtype == 32)
    TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, GROUP3OPT_2DENCODING);  

  in = fopen(inputfile, "r" BINMODE);
  if (in == NULL) {
    fprintf(stderr,
	    "Can not open: %s\n", inputfile);
    return 1;

  }

  faxTIFF->tif_fd = fileno(in);
  faxTIFF->tif_clientdata = (thandle_t) faxTIFF->tif_fd;

  /* TODO IS THIS SAFE ??? BERND*/

  faxTIFF->tif_name = inputfile;
  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, "kfax");
  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 (!faxt2tiffverbose)
    whandler = TIFFSetWarningHandler(NULL);
  rows = copyFaxFile(faxTIFF, out);
  fclose(in);

  if (!faxt2tiffverbose)
    (void) TIFFSetWarningHandler(whandler);
  
  TIFFSetField(out, TIFFTAG_IMAGELENGTH, rows);
  
  if (faxt2tiffverbose) {
    fprintf(stderr, "%s:\n", inputfile);
    fprintf(stderr, "%d rows in input\n", rows);
    fprintf(stderr, "%ld total bad rows\n",
	    (long) 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);
}
Exemplo n.º 2
0
int
main(int argc, char* argv[])
{
    FILE *in;
    TIFF *out = NULL;
    TIFFErrorHandler whandler = NULL;
    int compression_in = COMPRESSION_CCITTFAX3;
    int compression_out = COMPRESSION_CCITTFAX3;
    int fillorder_in = FILLORDER_LSB2MSB;
    int fillorder_out = FILLORDER_LSB2MSB;
    uint32 group3options_in = 0;	/* 1d-encoded */
    uint32 group3options_out = 0;	/* 1d-encoded */
    uint32 group4options_in = 0;	/* compressed */
    uint32 group4options_out = 0;	/* compressed */
    uint32 defrowsperstrip = (uint32) 0;
    uint32 rowsperstrip;
    int photometric_in = PHOTOMETRIC_MINISWHITE;
    int photometric_out = PHOTOMETRIC_MINISWHITE;
    int mode = FAXMODE_CLASSF;
    int rows;
    int c;
    int pn, npages;
    float resY = 196.0;
    extern int optind;
    extern char* optarg;


    while ((c = getopt(argc, argv, "R:X:o:1234ABLMPUW5678abcflmprsuvwz?")) != -1)
        switch (c) {
        /* input-related options */
        case '3':		/* input is g3-encoded */
            compression_in = COMPRESSION_CCITTFAX3;
            break;
        case '4':		/* input is g4-encoded */
            compression_in = COMPRESSION_CCITTFAX4;
            break;
        case 'U':		/* input is uncompressed (g3 and g4) */
            group3options_in |= GROUP3OPT_UNCOMPRESSED;
            group4options_in |= GROUP4OPT_UNCOMPRESSED;
            break;
        case '1':		/* input is 1d-encoded (g3 only) */
            group3options_in &= ~GROUP3OPT_2DENCODING;
            break;
        case '2':		/* input is 2d-encoded (g3 only) */
            group3options_in |= GROUP3OPT_2DENCODING;
            break;
        case 'P':	/* input has not-aligned EOL (g3 only) */
            group3options_in &= ~GROUP3OPT_FILLBITS;
            break;
        case 'A':		/* input has aligned EOL (g3 only) */
            group3options_in |= GROUP3OPT_FILLBITS;
            break;
        case 'W':		/* input has 0 mean white */
            photometric_in = PHOTOMETRIC_MINISWHITE;
            break;
        case 'B':		/* input has 0 mean black */
            photometric_in = PHOTOMETRIC_MINISBLACK;
            break;
        case 'L':		/* input has lsb-to-msb fillorder */
            fillorder_in = FILLORDER_LSB2MSB;
            break;
        case 'M':		/* input has msb-to-lsb fillorder */
            fillorder_in = FILLORDER_MSB2LSB;
            break;
        case 'R':		/* input resolution */
            resY = (float) atof(optarg);
            break;
        case 'X':		/* input width */
            xsize = (uint32) atoi(optarg);
            break;

        /* output-related options */
        case '7':		/* generate g3-encoded output */
            compression_out = COMPRESSION_CCITTFAX3;
            break;
        case '8':		/* generate g4-encoded output */
            compression_out = COMPRESSION_CCITTFAX4;
            break;
        case 'u':	/* generate uncompressed output (g3 and g4) */
            group3options_out |= GROUP3OPT_UNCOMPRESSED;
            group4options_out |= GROUP4OPT_UNCOMPRESSED;
            break;
        case '5':	/* generate 1d-encoded output (g3 only) */
            group3options_out &= ~GROUP3OPT_2DENCODING;
            break;
        case '6':	/* generate 2d-encoded output (g3 only) */
            group3options_out |= GROUP3OPT_2DENCODING;
            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_out = FILLORDER_MSB2LSB;
            break;
        case 'l':		/* output's fillorder is lsb-to-msb */
            fillorder_out = FILLORDER_LSB2MSB;
            break;
        case 'o':
            out = TIFFOpen(optarg, "w");
            if (out == NULL) {
                fprintf(stderr,
                        "%s: Can not create or open %s\n",
                        argv[0], optarg);
                return EXIT_FAILURE;
            }
            break;
        case 'a':	/* generate EOL-aligned output (g3 only) */
            group3options_out |= GROUP3OPT_FILLBITS;
            break;
        case 'p':	/* generate not EOL-aligned output (g3 only) */
            group3options_out &= ~GROUP3OPT_FILLBITS;
            break;
        case 'r':		/* rows/strip */
            defrowsperstrip = atol(optarg);
            break;
        case 's':		/* stretch image by dup'ng scanlines */
            stretch = 1;
            break;
        case 'w':		/* undocumented -- for testing */
            photometric_out = PHOTOMETRIC_MINISWHITE;
            break;
        case 'b':		/* undocumented -- for testing */
            photometric_out = PHOTOMETRIC_MINISBLACK;
            break;
        case 'z':		/* undocumented -- for testing */
            compression_out = COMPRESSION_LZW;
            break;
        case 'v':		/* -v for info */
            verbose++;
            break;
        case '?':
            usage();
            /*NOTREACHED*/
        }
    npages = argc - optind;
    if (npages < 1)
        usage();

    rowbuf = _TIFFmalloc(TIFFhowmany8(xsize));
    refbuf = _TIFFmalloc(TIFFhowmany8(xsize));
    if (rowbuf == NULL || refbuf == NULL) {
        fprintf(stderr, "%s: Not enough memory\n", argv[0]);
        return (EXIT_FAILURE);
    }

    if (out == NULL) {
        out = TIFFOpen("fax.tif", "w");
        if (out == NULL) {
            fprintf(stderr, "%s: Can not create fax.tif\n",
                    argv[0]);
            return (EXIT_FAILURE);
        }
    }

    faxTIFF = TIFFClientOpen("(FakeInput)", "w",
                             /* TIFFClientOpen() fails if we don't set existing value here */
                             TIFFClientdata(out),
                             TIFFGetReadProc(out), TIFFGetWriteProc(out),
                             TIFFGetSeekProc(out), TIFFGetCloseProc(out),
                             TIFFGetSizeProc(out), TIFFGetMapFileProc(out),
                             TIFFGetUnmapFileProc(out));
    if (faxTIFF == NULL) {
        fprintf(stderr, "%s: Can not create fake input file\n",
                argv[0]);
        return (EXIT_FAILURE);
    }
    TIFFSetMode(faxTIFF, O_RDONLY);
    TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH,	xsize);
    TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL,	1);
    TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE,	1);
    TIFFSetField(faxTIFF, TIFFTAG_FILLORDER,	fillorder_in);
    TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG,	PLANARCONFIG_CONTIG);
    TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC,	photometric_in);
    TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION,	resY);
    TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT,	RESUNIT_INCH);

    /* NB: this must be done after directory info is setup */
    TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, compression_in);
    if (compression_in == COMPRESSION_CCITTFAX3)
        TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, group3options_in);
    else if (compression_in == COMPRESSION_CCITTFAX4)
        TIFFSetField(faxTIFF, TIFFTAG_GROUP4OPTIONS, group4options_in);
    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;
        }
#if defined(_WIN32) && defined(USE_WIN32_FILEIO)
        TIFFSetClientdata(faxTIFF, (thandle_t)_get_osfhandle(fileno(in)));
#else
        TIFFSetClientdata(faxTIFF, (thandle_t)fileno(in));
#endif
        TIFFSetFileName(faxTIFF, (const char*)argv[optind]);
        TIFFSetField(out, TIFFTAG_IMAGEWIDTH, xsize);
        TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
        TIFFSetField(out, TIFFTAG_COMPRESSION, compression_out);
        TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric_out);
        TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
        TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
        switch (compression_out) {
        /* g3 */
        case COMPRESSION_CCITTFAX3:
            TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
                         group3options_out);
            TIFFSetField(out, TIFFTAG_FAXMODE, mode);
            rowsperstrip =
                (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
            break;

        /* g4 */
        case COMPRESSION_CCITTFAX4:
            TIFFSetField(out, TIFFTAG_GROUP4OPTIONS,
                         group4options_out);
            TIFFSetField(out, TIFFTAG_FAXMODE, mode);
            rowsperstrip =
                (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
            break;

        default:
            rowsperstrip = (defrowsperstrip) ?
                           defrowsperstrip : TIFFDefaultStripSize(out, 0);
        }
        TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
        TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
        TIFFSetField(out, TIFFTAG_FILLORDER, fillorder_out);
        TIFFSetField(out, TIFFTAG_SOFTWARE, "fax2tiff");
        TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0);
        if (!stretch) {
            TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &resY);
            TIFFSetField(out, TIFFTAG_YRESOLUTION, resY);
        } else
            TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.);
        TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
        TIFFSetField(out, TIFFTAG_PAGENUMBER, pn, 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, "%ld total bad rows\n",
                    (long) badfaxlines);
            fprintf(stderr, "%d max consecutive bad rows\n", badfaxrun);
        }
        if (compression_out == 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);
    _TIFFfree(rowbuf);
    _TIFFfree(refbuf);
    return (EXIT_SUCCESS);
}
Exemplo n.º 3
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
    TIFF *faxTIFF = NULL;
    FIBITMAP *dib = NULL;
    FIMEMORY *memory = NULL;

    //int verbose = 0;
    int stretch = 0;
    int rows;
    float resX = 204.0;
    float resY = 196.0;

    uint32 xsize = G3_DEFAULT_WIDTH;
    int compression_in = COMPRESSION_CCITTFAX3;
    int fillorder_in = FILLORDER_LSB2MSB;
    uint32 group3options_in = 0;    // 1d-encoded
    uint32 group4options_in = 0;    // compressed
    int photometric_in = PHOTOMETRIC_MINISWHITE;

    if(handle==NULL) return NULL;

    try {
        // set default load options

        compression_in = COMPRESSION_CCITTFAX3;         // input is g3-encoded
        group3options_in &= ~GROUP3OPT_2DENCODING;      // input is 1d-encoded (g3 only)
        fillorder_in = FILLORDER_MSB2LSB;               // input has msb-to-lsb fillorder

        /*
          Original input-related fax2tiff options

          while ((c = getopt(argc, argv, "R:X:o:1234ABLMPUW5678abcflmprsuvwz?")) != -1) {
          switch (c) {
          // input-related options
          case '3':       // input is g3-encoded
          compression_in = COMPRESSION_CCITTFAX3;
          break;
          case '4':       // input is g4-encoded
          compression_in = COMPRESSION_CCITTFAX4;
          break;
          case 'U':       // input is uncompressed (g3 and g4)
          group3options_in |= GROUP3OPT_UNCOMPRESSED;
          group4options_in |= GROUP4OPT_UNCOMPRESSED;
          break;
          case '1':       // input is 1d-encoded (g3 only)
          group3options_in &= ~GROUP3OPT_2DENCODING;
          break;
          case '2':       // input is 2d-encoded (g3 only)
          group3options_in |= GROUP3OPT_2DENCODING;
          break;
          case 'P':   // input has not-aligned EOL (g3 only)
          group3options_in &= ~GROUP3OPT_FILLBITS;
          break;
          case 'A':       // input has aligned EOL (g3 only)
          group3options_in |= GROUP3OPT_FILLBITS;
          break;
          case 'W':       // input has 0 mean white
          photometric_in = PHOTOMETRIC_MINISWHITE;
          break;
          case 'B':       // input has 0 mean black
          photometric_in = PHOTOMETRIC_MINISBLACK;
          break;
          case 'L':       // input has lsb-to-msb fillorder
          fillorder_in = FILLORDER_LSB2MSB;
          break;
          case 'M':       // input has msb-to-lsb fillorder
          fillorder_in = FILLORDER_MSB2LSB;
          break;
          case 'R':       // input resolution
          resY = (float) atof(optarg);
          break;
          case 'X':       // input width
          xsize = (uint32) atoi(optarg);
          break;

          // output-related options
          case 's':       // stretch image by dup'ng scanlines
          stretch = 1;
          break;
          case 'v':       // -v for info
          verbose++;
          break;
          }
          }

        */

        // open a temporary memory buffer to save decoded scanlines
        memory = FreeImage_OpenMemory();
        if(!memory) throw FI_MSG_ERROR_MEMORY;

        // wrap the raw fax file
        faxTIFF = TIFFClientOpen("(FakeInput)", "w",
                                 // TIFFClientOpen() fails if we don't set existing value here
                                 NULL,
                                 _g3ReadProc, _g3WriteProc,
                                 _g3SeekProc, _g3CloseProc,
                                 _g3SizeProc, _g3MapProc,
                                 _g3UnmapProc);

        if (faxTIFF == NULL) {
            throw "Can not create fake input file";
        }
        TIFFSetMode(faxTIFF, O_RDONLY);
        TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH, xsize);
        TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL, 1);
        TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE, 1);
        TIFFSetField(faxTIFF, TIFFTAG_FILLORDER, fillorder_in);
        TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
        TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC, photometric_in);
        TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION, resY);
        TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);

        // NB: this must be done after directory info is setup
        TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, compression_in);
        if (compression_in == COMPRESSION_CCITTFAX3)
            TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, group3options_in);
        else if (compression_in == COMPRESSION_CCITTFAX4)
            TIFFSetField(faxTIFF, TIFFTAG_GROUP4OPTIONS, group4options_in);

        resX = 204;
        if (!stretch) {
            TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &resY);
        } else {
            resY = 196;
        }

        // decode the raw fax data
        rows = copyFaxFile(io, handle, faxTIFF, xsize, stretch, memory);
        if(rows <= 0) throw "Error when decoding raw fax file : check the decoder options";


        // allocate the output dib
        dib = FreeImage_Allocate(xsize, rows, 1);
        unsigned pitch = FreeImage_GetPitch(dib);
        uint32 linesize = TIFFhowmany8(xsize);

        // fill the bitmap structure ...
        // ... palette
        RGBQUAD *pal = FreeImage_GetPalette(dib);
        if(photometric_in == PHOTOMETRIC_MINISWHITE) {
            pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255;
            pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 0;
        } else {
            pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
            pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
        }
        // ... resolution
        FreeImage_SetDotsPerMeterX(dib, (unsigned)(resX/0.0254000 + 0.5));
        FreeImage_SetDotsPerMeterY(dib, (unsigned)(resY/0.0254000 + 0.5));

        // read the decoded scanline and fill the bitmap data
        FreeImage_SeekMemory(memory, 0, SEEK_SET);
        BYTE *bits = FreeImage_GetScanLine(dib, rows - 1);
        for(int k = 0; k < rows; k++) {
            FreeImage_ReadMemory(bits, linesize, 1, memory);
            bits -= pitch;
        }

        // free the TIFF wrapper
        TIFFClose(faxTIFF);

        // free the memory buffer
        FreeImage_CloseMemory(memory);

    } catch(const char *message) {
        if(memory) FreeImage_CloseMemory(memory);
        if(faxTIFF) TIFFClose(faxTIFF);
        if(dib) FreeImage_Unload(dib);
        FreeImage_OutputMessageProc(s_format_id, message);
        return NULL;
    }

    return dib;

}