/* * Compute which tile an (x,y,z,s) value is in. */ ttile_t TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s) { TIFFDirectory *td = &tif->tif_dir; uint32 dx = td->td_tilewidth; uint32 dy = td->td_tilelength; uint32 dz = td->td_tiledepth; ttile_t tile = 1; if (td->td_imagedepth == 1) z = 0; if (dx == (uint32) -1) dx = td->td_imagewidth; if (dy == (uint32) -1) dy = td->td_imagelength; if (dz == (uint32) -1) dz = td->td_imagedepth; if (dx != 0 && dy != 0 && dz != 0) { uint32 xpt = TIFFhowmany(td->td_imagewidth, dx); uint32 ypt = TIFFhowmany(td->td_imagelength, dy); uint32 zpt = TIFFhowmany(td->td_imagedepth, dz); if (td->td_planarconfig == PLANARCONFIG_SEPARATE) tile = (xpt*ypt*zpt)*s + (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx; else tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx; } return (tile); }
/* * Set state to appear as if a * tile has just been read in. */ static int TIFFStartTile(TIFF* tif, ttile_t tile) { TIFFDirectory *td = &tif->tif_dir; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupdecode)(tif)) return (0); tif->tif_flags |= TIFF_CODERSETUP; } tif->tif_curtile = tile; tif->tif_row = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) * td->td_tilelength; tif->tif_col = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) * td->td_tilewidth; if (tif->tif_flags&TIFF_NOREADRAW) { tif->tif_rawcp = NULL; tif->tif_rawcc = 0; } else { tif->tif_rawcp = tif->tif_rawdata; tif->tif_rawcc = td->td_stripbytecount[tile]; } return ((*tif->tif_predecode)(tif, (tsample_t)(tile/td->td_stripsperimage))); }
/* * Compute how many tiles are in an image. */ ttile_t TIFFNumberOfTiles(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; uint32 dx = td->td_tilewidth; uint32 dy = td->td_tilelength; uint32 dz = td->td_tiledepth; ttile_t ntiles; if (dx == (uint32) -1) dx = td->td_imagewidth; if (dy == (uint32) -1) dy = td->td_imagelength; if (dz == (uint32) -1) dz = td->td_imagedepth; ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 : multiply(tif, multiply(tif, TIFFhowmany(td->td_imagewidth, dx), TIFFhowmany(td->td_imagelength, dy), "TIFFNumberOfTiles"), TIFFhowmany(td->td_imagedepth, dz), "TIFFNumberOfTiles"); if (td->td_planarconfig == PLANARCONFIG_SEPARATE) ntiles = multiply(tif, ntiles, td->td_samplesperpixel, "TIFFNumberOfTiles"); return (ntiles); }
tsize_t TIFFRasterScanlineSize(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; tsize_t scanline; scanline = td->td_bitspersample * td->td_imagewidth; if (td->td_planarconfig == PLANARCONFIG_CONTIG) { scanline *= td->td_samplesperpixel; return ((tsize_t) TIFFhowmany(scanline, 8)); } else return ((tsize_t) TIFFhowmany(scanline, 8)*td->td_samplesperpixel); }
/* * 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; #ifdef YCBCR_SUPPORT 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_imagewidth, td->td_ycbcrsubsampling[0]); tsize_t scanline = TIFFhowmany(w*td->td_bitspersample, 8); tsize_t samplingarea = td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ return ((tsize_t) (nrows*scanline + 2*(nrows*scanline / samplingarea))); } else #endif return ((tsize_t)(nrows * TIFFScanlineSize(tif))); }
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 = td->td_bitspersample * td->td_tilewidth; if (td->td_planarconfig == PLANARCONFIG_CONTIG) rowsize *= td->td_samplesperpixel; return ((tsize_t) TIFFhowmany(rowsize, 8)); }
tstrip_t TIFFNumberOfStrips(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; tstrip_t nstrips; nstrips = (td->td_rowsperstrip == (uint32) -1 ? (td->td_imagelength != 0 ? 1 : 0) : TIFFhowmany(td->td_imagelength, td->td_rowsperstrip)); if (td->td_planarconfig == PLANARCONFIG_SEPARATE) nstrips *= td->td_samplesperpixel; return (nstrips); }
/* * This routine maps a file into a private section. Note that this * method of accessing a file is by far the fastest under VMS. * The routine may fail (i.e. return 0) for several reasons, for * example: * - There is no more room for storing the info on sections. * - The process is out of open file quota, channels, ... * - fd does not describe an opened file. * - The file is already opened for write access by this process * or another process * - There is no free "hole" in virtual memory that fits the * size of the file */ static int _tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) { char name[256]; struct FAB fab; unsigned short channel; char *inadr[2], *retadr[2]; unsigned long status; long size; if (no_mapped >= MAX_MAPPED) return(0); /* * We cannot use a file descriptor, we * must open the file once more. */ if (getname((int)fd, name, 1) == NULL) return(0); /* prepare the FAB for a user file open */ fab = cc$rms_fab; fab.fab$l_fop |= FAB$V_UFO; fab.fab$b_fac = FAB$M_GET; fab.fab$b_shr = FAB$M_SHRGET; fab.fab$l_fna = name; fab.fab$b_fns = strlen(name); status = sys$open(&fab); /* open file & get channel number */ if ((status&1) == 0) return(0); channel = (unsigned short)fab.fab$l_stv; inadr[0] = inadr[1] = (char *)0; /* just an address in P0 space */ /* * Map the blocks of the file up to * the EOF block into virtual memory. */ size = _tiffSizeProc(fd); status = sys$crmpsc(inadr, retadr, 0, SEC$M_EXPREG, 0,0,0, channel, TIFFhowmany(size,512), 0,0,0); ddd if ((status&1) == 0) { sys$dassgn(channel); return(0); } *pbase = (tdata_t) retadr[0]; /* starting virtual address */ /* * Use the size of the file up to the * EOF mark for UNIX compatibility. */ *psize = (toff_t) size; /* Record the section in the table */ map_table[no_mapped].base = retadr[0]; map_table[no_mapped].top = retadr[1]; map_table[no_mapped].channel = channel; no_mapped++; return(1); }
/* * Write the supplied data to the specified strip. * * NB: Image length must be setup before writing. */ tsize_t TIFFWriteRawStrip(TIFF *tif, tstrip_t strip, tdata_t data, tsize_t cc) { static const char module[] = "TIFFWriteRawStrip"; TIFFDirectory *td = &tif->tif_dir; if (!WRITECHECKSTRIPS(tif, module)) return ((tsize_t) -1); /* * Check strip array to make sure there's space. * We don't support dynamically growing files that * have data organized in separate bitplanes because * it's too painful. In that case we require that * the imagelength be set properly before the first * write (so that the strips array will be fully * allocated above). */ if (strip >= td->td_nstrips) { if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not grow image by strips when using separate planes"); return ((tsize_t) -1); } /* * Watch out for a growing image. The value of * strips/image will initially be 1 (since it * can't be deduced until the imagelength is known). */ if (strip >= td->td_stripsperimage) td->td_stripsperimage = TIFFhowmany(td->td_imagelength, td->td_rowsperstrip); if (!TIFFGrowStrips(tif, 1, module)) return ((tsize_t) -1); } tif->tif_curstrip = strip; tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; return (TIFFAppendToStrip(tif, strip, (tidata_t) data, cc) ? cc : (tsize_t) -1); }
/* * Return nearest TIFFDataType to the sample type of an image. */ TIFFDataType _TIFFSampleToTagType(TIFF* tif) { int bps = (int) TIFFhowmany(tif->tif_dir.td_bitspersample, 8); 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); }
/* * 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]; TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, ycbcrsubsampling + 0, ycbcrsubsampling + 1); if (ycbcrsubsampling[0]*ycbcrsubsampling[1] == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); return 0; } /* number of sample clumps per line */ scanline = TIFFhowmany(td->td_imagewidth, ycbcrsubsampling[0]); /* number of samples per line */ scanline = multiply(tif, scanline, ycbcrsubsampling[0]*ycbcrsubsampling[1] + 2, "TIFFScanlineSize"); } 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"))); }
int TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) { static const char module[] = "TIFFWriteScanline"; register TIFFDirectory *td; int status, imagegrew = 0; tstrip_t strip; if (!WRITECHECKSTRIPS(tif, module)) return (-1); /* * Handle delayed allocation of data buffer. This * permits it to be sized more intelligently (using * directory information). */ if (!BUFFERCHECK(tif)) return (-1); td = &tif->tif_dir; /* * Extend image length if needed * (but only for PlanarConfig=1). */ if (row >= td->td_imagelength) { /* extend image */ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not change \"ImageLength\" when using separate planes"); return (-1); } td->td_imagelength = row+1; imagegrew = 1; } /* * Calculate strip and check for crossings. */ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { if (sample >= td->td_samplesperpixel) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%d: Sample out of range, max %d", sample, td->td_samplesperpixel); return (-1); } strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; } else strip = row / td->td_rowsperstrip; /* * Check strip array to make sure there's space. We don't support * dynamically growing files that have data organized in separate * bitplanes because it's too painful. In that case we require that * the imagelength be set properly before the first write (so that the * strips array will be fully allocated above). */ if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module)) return (-1); if (strip != tif->tif_curstrip) { /* * Changing strips -- flush any data present. */ if (!TIFFFlushData(tif)) return (-1); tif->tif_curstrip = strip; /* * Watch out for a growing image. The value of strips/image * will initially be 1 (since it can't be deduced until the * imagelength is known). */ if (strip >= td->td_stripsperimage && imagegrew) td->td_stripsperimage = TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupencode)(tif)) return (-1); tif->tif_flags |= TIFF_CODERSETUP; } tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; if( td->td_stripbytecount[strip] > 0 ) { /* if we are writing over existing tiles, zero length */ td->td_stripbytecount[strip] = 0; /* this forces TIFFAppendToStrip() to do a seek */ tif->tif_curoff = 0; } if (!(*tif->tif_preencode)(tif, sample)) return (-1); tif->tif_flags |= TIFF_POSTENCODE; } /* * Ensure the write is either sequential or at the * beginning of a strip (or that we can randomly * access the data -- i.e. no encoding). */ if (row != tif->tif_row) { if (row < tif->tif_row) { /* * Moving backwards within the same strip: * backup to the start and then decode * forward (below). */ tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; tif->tif_rawcp = tif->tif_rawdata; } /* * Seek forward to the desired row. */ if (!(*tif->tif_seek)(tif, row - tif->tif_row)) return (-1); tif->tif_row = row; } /* swab if needed - note that source buffer will be altered */ tif->tif_postdecode( tif, (tidata_t) buf, tif->tif_scanlinesize ); status = (*tif->tif_encoderow)(tif, (tidata_t) buf, tif->tif_scanlinesize, sample); /* we are now poised at the beginning of the next row */ tif->tif_row = row + 1; return (status); }
/* * Encode the supplied data and write it to the * specified tile. There must be space for the * data. The function clamps individual writes * to a tile to the tile size, but does not (and * can not) check that multiple writes to the same * tile do not write more than tile size data. * * NB: Image length must be setup before writing; this * interface does not support automatically growing * the image on each write (as TIFFWriteScanline does). */ tsize_t TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) { static const char module[] = "TIFFWriteEncodedTile"; TIFFDirectory *td; tsample_t sample; if (!WRITECHECKTILES(tif, module)) return ((tsize_t) -1); td = &tif->tif_dir; if (tile >= td->td_nstrips) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu", tif->tif_name, (unsigned long) tile, (unsigned long) td->td_nstrips); return ((tsize_t) -1); } /* * Handle delayed allocation of data buffer. This * permits it to be sized more intelligently (using * directory information). */ if (!BUFFERCHECK(tif)) return ((tsize_t) -1); tif->tif_curtile = tile; tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; if( td->td_stripbytecount[tile] > 0 ) { /* Force TIFFAppendToStrip() to consider placing data at end of file. */ tif->tif_curoff = 0; } /* * Compute tiles per row & per column to compute * current row and column */ tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) * td->td_tilelength; tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) * td->td_tilewidth; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupencode)(tif)) return ((tsize_t) -1); tif->tif_flags |= TIFF_CODERSETUP; } tif->tif_flags &= ~TIFF_POSTENCODE; sample = (tsample_t)(tile/td->td_stripsperimage); if (!(*tif->tif_preencode)(tif, sample)) return ((tsize_t) -1); /* * Clamp write amount to the tile size. This is mostly * done so that callers can pass in some large number * (e.g. -1) and have the tile size used instead. */ if ( cc < 1 || cc > tif->tif_tilesize) cc = tif->tif_tilesize; /* swab if needed - note that source buffer will be altered */ tif->tif_postdecode( tif, (tidata_t) data, cc ); if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample)) return ((tsize_t) 0); if (!(*tif->tif_postencode)(tif)) return ((tsize_t) -1); if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) TIFFReverseBits((unsigned char *)tif->tif_rawdata, tif->tif_rawcc); if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, tif->tif_rawdata, tif->tif_rawcc)) return ((tsize_t) -1); tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; return (cc); }
/* * Encode the supplied data and write it to the * specified strip. * * NB: Image length must be setup before writing. */ tsize_t TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) { static const char module[] = "TIFFWriteEncodedStrip"; TIFFDirectory *td = &tif->tif_dir; tsample_t sample; if (!WRITECHECKSTRIPS(tif, module)) return ((tsize_t) -1); /* * Check strip array to make sure there's space. * We don't support dynamically growing files that * have data organized in separate bitplanes because * it's too painful. In that case we require that * the imagelength be set properly before the first * write (so that the strips array will be fully * allocated above). */ if (strip >= td->td_nstrips) { if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not grow image by strips when using separate planes"); return ((tsize_t) -1); } if (!TIFFGrowStrips(tif, 1, module)) return ((tsize_t) -1); td->td_stripsperimage = TIFFhowmany(td->td_imagelength, td->td_rowsperstrip); } /* * Handle delayed allocation of data buffer. This * permits it to be sized according to the directory * info. */ if (!BUFFERCHECK(tif)) return ((tsize_t) -1); tif->tif_curstrip = strip; tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupencode)(tif)) return ((tsize_t) -1); tif->tif_flags |= TIFF_CODERSETUP; } tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; if( td->td_stripbytecount[strip] > 0 ) { /* Force TIFFAppendToStrip() to consider placing data at end of file. */ tif->tif_curoff = 0; } tif->tif_flags &= ~TIFF_POSTENCODE; sample = (tsample_t)(strip / td->td_stripsperimage); if (!(*tif->tif_preencode)(tif, sample)) return ((tsize_t) -1); /* swab if needed - note that source buffer will be altered */ tif->tif_postdecode( tif, (tidata_t) data, cc ); if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample)) return ((tsize_t) 0); if (!(*tif->tif_postencode)(tif)) return ((tsize_t) -1); if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc); if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc)) return ((tsize_t) -1); tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; return (cc); }
#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 char rowbuf[TIFFhowmany(XSIZE,8)]; char refbuf[TIFFhowmany(XSIZE,8)]; int faxt2tiffverbose; 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);
int main(int argc, char* argv[]) { FILE *in; TIFF *out = NULL; TIFFErrorHandler whandler; 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 */ 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:1234ABLMPUW5678abcflmpsuvwz?")) != -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 = atof(optarg); break; case 'X': /* input width */ xsize = atof(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 '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(TIFFhowmany(xsize,8)); refbuf = _TIFFmalloc(TIFFhowmany(xsize,8)); 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 */ out->tif_clientdata, out->tif_readproc, out->tif_writeproc, out->tif_seekproc, out->tif_closeproc, out->tif_sizeproc, out->tif_mapproc, out->tif_unmapproc); if (faxTIFF == NULL) { fprintf(stderr, "%s: Can not create fake input file\n", argv[0]); 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_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; } 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_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); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, -1L); break; /* g4 */ case COMPRESSION_CCITTFAX4: TIFFSetField(out, TIFFTAG_GROUP4OPTIONS, group4options_out); TIFFSetField(out, TIFFTAG_FAXMODE, mode); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, -1L); break; default: TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, 0)); } 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); }