/* * Return the number of bytes required to store a complete * decoded and packed raster scanline (as opposed to the * I/O size returned by TIFFScanlineSize which may be less * if data is store as separate planes). */ tsize_t TIFFRasterScanlineSize(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; tsize_t scanline; scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth, "TIFFRasterScanlineSize"); if (td->td_planarconfig == PLANARCONFIG_CONTIG) { scanline = multiply (tif, scanline, td->td_samplesperpixel, "TIFFRasterScanlineSize"); return ((tsize_t) TIFFhowmany8(scanline)); } else return ((tsize_t) multiply (tif, TIFFhowmany8(scanline), td->td_samplesperpixel, "TIFFRasterScanlineSize")); }
/* * Return the number of bytes to read/write in a call to * one of the scanline-oriented i/o routines. Note that * this number may be 1/samples-per-pixel if data is * stored as separate planes. */ tsize_t TIFFScanlineSize(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; tsize_t scanline; if (td->td_planarconfig == PLANARCONFIG_CONTIG) { if (td->td_photometric == PHOTOMETRIC_YCBCR && !isUpSampled(tif)) { uint16 ycbcrsubsampling[2]; TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, ycbcrsubsampling + 0, ycbcrsubsampling + 1); if (ycbcrsubsampling[0] == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); return 0; } scanline = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]); scanline = TIFFhowmany8(multiply(tif, scanline, td->td_bitspersample, "TIFFScanlineSize")); return ((tsize_t) summarize(tif, scanline, multiply(tif, 2, scanline / ycbcrsubsampling[0], "TIFFVStripSize"), "TIFFVStripSize")); } else { scanline = multiply(tif, td->td_imagewidth, td->td_samplesperpixel, "TIFFScanlineSize"); } } else scanline = td->td_imagewidth; return ((tsize_t) TIFFhowmany8(multiply(tif, scanline, td->td_bitspersample, "TIFFScanlineSize"))); }
/* * Compute the # bytes in a variable height, row-aligned strip. */ tsize_t TIFFVStripSize(TIFF* tif, uint32 nrows) { TIFFDirectory *td = &tif->tif_dir; if (nrows == (uint32) -1) nrows = td->td_imagelength; if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_photometric == PHOTOMETRIC_YCBCR && !isUpSampled(tif)) { /* * Packed YCbCr data contain one Cb+Cr for every * HorizontalSampling*VerticalSampling Y values. * Must also roundup width and height when calculating * since images that are not a multiple of the * horizontal/vertical subsampling area include * YCbCr data for the extended image. */ uint16 ycbcrsubsampling[2]; tsize_t w, scanline, samplingarea; ycbcrsubsampling[0] = 0; ycbcrsubsampling[1] = 0; TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, ycbcrsubsampling + 0, ycbcrsubsampling + 1 ); /* make sure we dont get division by 0 due to bad tiffs */ if (!ycbcrsubsampling[0]) ycbcrsubsampling[0] = 1; if (!ycbcrsubsampling[1]) ycbcrsubsampling[1] = 1; samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1]; if (samplingarea == 0) { _TIFFError(tif, tif->tif_name, "Invalid YCbCr subsampling"); return 0; } w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]); scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample, "TIFFVStripSize")); nrows = TIFFroundup(nrows, ycbcrsubsampling[1]); /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ scanline = multiply(tif, nrows, scanline, "TIFFVStripSize"); return ((tsize_t) summarize(tif, scanline, multiply(tif, 2, scanline / samplingarea, "TIFFVStripSize"), "TIFFVStripSize")); } else return ((tsize_t) multiply(tif, nrows, TIFFScanlineSize(tif), "TIFFVStripSize")); }
/* * Compute the # bytes in each row of a tile. */ tsize_t TIFFTileRowSize(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; tsize_t rowsize; if (td->td_tilelength == 0 || td->td_tilewidth == 0) return ((tsize_t) 0); rowsize = multiply(tif, td->td_bitspersample, td->td_tilewidth, "TIFFTileRowSize"); if (td->td_planarconfig == PLANARCONFIG_CONTIG) rowsize = multiply(tif, rowsize, td->td_samplesperpixel, "TIFFTileRowSize"); return ((tsize_t) TIFFhowmany8(rowsize)); }
/* * Compute the # bytes in a variable length, row-aligned tile. */ tsize_t TIFFVTileSize(TIFF* tif, uint32 nrows) { TIFFDirectory *td = &tif->tif_dir; tsize_t tilesize; if (td->td_tilelength == 0 || td->td_tilewidth == 0 || td->td_tiledepth == 0) return ((tsize_t) 0); if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_photometric == PHOTOMETRIC_YCBCR && !isUpSampled(tif)) { /* * Packed YCbCr data contain one Cb+Cr for every * HorizontalSampling*VerticalSampling Y values. * Must also roundup width and height when calculating * since images that are not a multiple of the * horizontal/vertical subsampling area include * YCbCr data for the extended image. */ tsize_t w = TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]); tsize_t rowsize = TIFFhowmany8(multiply(tif, w, td->td_bitspersample, "TIFFVTileSize")); tsize_t samplingarea = td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; if (samplingarea == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); return 0; } nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ tilesize = multiply(tif, nrows, rowsize, "TIFFVTileSize"); tilesize = summarize(tif, tilesize, multiply(tif, 2, tilesize / samplingarea, "TIFFVTileSize"), "TIFFVTileSize"); } else tilesize = multiply(tif, nrows, TIFFTileRowSize(tif), "TIFFVTileSize"); return ((tsize_t) multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize")); }
/* * Return nearest TIFFDataType to the sample type of an image. */ TIFFDataType _TIFFSampleToTagType(TIFF* tif) { uint32 bps = TIFFhowmany8(tif->tif_dir.td_bitspersample); switch (tif->tif_dir.td_sampleformat) { case SAMPLEFORMAT_IEEEFP: return (bps == 4 ? TIFF_FLOAT : TIFF_DOUBLE); case SAMPLEFORMAT_INT: return (bps <= 1 ? TIFF_SBYTE : bps <= 2 ? TIFF_SSHORT : TIFF_SLONG); case SAMPLEFORMAT_UINT: return (bps <= 1 ? TIFF_BYTE : bps <= 2 ? TIFF_SHORT : TIFF_LONG); case SAMPLEFORMAT_VOID: return (TIFF_UNDEFINED); } /*NOTREACHED*/ return (TIFF_UNDEFINED); }
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); }
int copyFaxFile(TIFF* tifin, TIFF* tifout) { uint32 row; uint32 linesize = TIFFhowmany8(xsize); uint16 badrun; int ok; tifin->tif_rawdatasize = TIFFGetFileSize(tifin); tifin->tif_rawdata = _TIFFmalloc(tifin->tif_rawdatasize); if (tifin->tif_rawdata == NULL) { TIFFError(tifin->tif_name, "Not enough memory"); return (0); } if (!ReadOK(tifin, tifin->tif_rawdata, tifin->tif_rawdatasize)) { TIFFError(tifin->tif_name, "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, linesize); row = 0; badrun = 0; /* current run of bad lines */ while (tifin->tif_rawcc > 0) { ok = (*tifin->tif_decoderow)(tifin, (tdata_t) rowbuf, linesize, 0); if (!ok) { badfaxlines++; badrun++; /* regenerate line from previous good line */ _TIFFmemcpy(rowbuf, refbuf, linesize); } else { if (badrun > badfaxrun) badfaxrun = badrun; badrun = 0; _TIFFmemcpy(refbuf, rowbuf, linesize); } tifin->tif_row++; if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) { fprintf(stderr, "%s: Write error at row %ld.\n", tifout->tif_name, (long) row); break; } row++; if (stretch) { if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) { fprintf(stderr, "%s: Write error at row %ld.\n", tifout->tif_name, (long) row); break; } row++; } } if (badrun > badfaxrun) badfaxrun = badrun; _TIFFfree(tifin->tif_rawdata); return (row); }
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; }
static int copyFaxFile(FreeImageIO *io, fi_handle handle, TIFF* tifin, uint32 xsize, int stretch, FIMEMORY *memory) { BYTE *rowbuf = NULL; BYTE *refbuf = NULL; uint32 row; uint16 badrun; uint16 badfaxrun; uint32 badfaxlines; int ok; try { uint32 linesize = TIFFhowmany8(xsize); rowbuf = (BYTE*) _TIFFmalloc(linesize); refbuf = (BYTE*) _TIFFmalloc(linesize); if (rowbuf == NULL || refbuf == NULL) { throw FI_MSG_ERROR_MEMORY; } tifin->tif_rawdatasize = G3GetFileSize(io, handle); tifin->tif_rawdata = (tidata_t) _TIFFmalloc(tifin->tif_rawdatasize); if (tifin->tif_rawdata == NULL) { throw FI_MSG_ERROR_MEMORY; } if(!G3ReadFile(io, handle, tifin->tif_rawdata, tifin->tif_rawdatasize)) { throw "Read error at scanline 0"; } tifin->tif_rawcp = tifin->tif_rawdata; tifin->tif_rawcc = tifin->tif_rawdatasize; (*tifin->tif_setupdecode)(tifin); (*tifin->tif_predecode)(tifin, (uint16) 0); tifin->tif_row = 0; badfaxlines = 0; badfaxrun = 0; _TIFFmemset(refbuf, 0, linesize); row = 0; badrun = 0; // current run of bad lines while (tifin->tif_rawcc > 0) { ok = (*tifin->tif_decoderow)(tifin, rowbuf, linesize, 0); if (!ok) { badfaxlines++; badrun++; // regenerate line from previous good line _TIFFmemcpy(rowbuf, refbuf, linesize); } else { if (badrun > badfaxrun) badfaxrun = badrun; badrun = 0; _TIFFmemcpy(refbuf, rowbuf, linesize); } tifin->tif_row++; FreeImage_WriteMemory(rowbuf, linesize, 1, memory); row++; if (stretch) { FreeImage_WriteMemory(rowbuf, linesize, 1, memory); row++; } } if (badrun > badfaxrun) badfaxrun = badrun; _TIFFfree(tifin->tif_rawdata); tifin->tif_rawdata = NULL; _TIFFfree(rowbuf); _TIFFfree(refbuf); /* if (verbose) { 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); } */ } catch(const char *message) { if(rowbuf) _TIFFfree(rowbuf); if(refbuf) _TIFFfree(refbuf); if(tifin->tif_rawdata) { _TIFFfree(tifin->tif_rawdata); tifin->tif_rawdata = NULL; } FreeImage_OutputMessageProc(s_format_id, message); return -1; } return (row); }
/* * Compute the # bytes in a variable height, row-aligned strip. */ tsize_t TIFFVStripSize(TIFF* tif, uint32 nrows) { TIFFDirectory *td = &tif->tif_dir; uint32 stripsize; if (nrows == (uint32) -1) nrows = td->td_imagelength; if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_photometric == PHOTOMETRIC_YCBCR && !isUpSampled(tif)) { /* * Packed YCbCr data contain one Cb+Cr for every * HorizontalSampling*VerticalSampling Y values. * Must also roundup width and height when calculating * since images that are not a multiple of the * horizontal/vertical subsampling area include * YCbCr data for the extended image. */ uint16 ycbcrsubsampling[2]; uint32 w, scanline, samplingarea; TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, ycbcrsubsampling + 0, ycbcrsubsampling + 1); samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1]; if (samplingarea == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); return 0; } w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]); scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample, "TIFFVStripSize")); nrows = TIFFroundup(nrows, ycbcrsubsampling[1]); /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ scanline = multiply(tif, nrows, scanline, "TIFFVStripSize"); /* a zero anywhere in here means overflow, must return zero */ if (scanline > 0) { uint32 extra = multiply(tif, 2, scanline / samplingarea, "TIFFVStripSize"); if (extra > 0) stripsize = summarize(tif, scanline, extra, "TIFFVStripSize"); else stripsize = 0; } else stripsize = 0; } else stripsize = multiply(tif, nrows, TIFFScanlineSize(tif), "TIFFVStripSize"); /* Because tsize_t is signed, we might have conversion overflow */ if (((tsize_t) stripsize) < 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", "TIFFVStripSize"); stripsize = 0; } return (tsize_t) stripsize; }