toff_t GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, int nPredictor, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata ) { toff_t nBaseDirOffset; toff_t nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */ TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if (panExtraSampleValues != NULL) { TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } if ( nCompressFlag == COMPRESSION_LZW || nCompressFlag == COMPRESSION_ADOBE_DEFLATE ) TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
/* * Write the contents of the current directory * to the specified file. This routine doesn't * handle overwriting a directory with auxiliary * storage that's been changed. */ static int _TIFFWriteDirectory(TIFF* tif, int done) { uint16 dircount; toff_t diroff; ttag_t tag; uint32 nfields; tsize_t dirsize; char* data; TIFFDirEntry* dir; TIFFDirectory* td; u_long b, fields[FIELD_SETLONGS]; int fi, nfi; if (tif->tif_mode == O_RDONLY) return (1); /* * Clear write state so that subsequent images with * different characteristics get the right buffers * setup for them. */ if (done) { if (tif->tif_flags & TIFF_POSTENCODE) { tif->tif_flags &= ~TIFF_POSTENCODE; if (!(*tif->tif_postencode)(tif)) { TIFFError(tif->tif_name, "Error post-encoding before directory write"); return (0); } } (*tif->tif_close)(tif); /* shutdown encoder */ /* * Flush any data that might have been written * by the compression close+cleanup routines. */ if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) { TIFFError(tif->tif_name, "Error flushing data before directory write"); return (0); } if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawcc = 0; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); } td = &tif->tif_dir; /* * Size the directory so that we can calculate * offsets for the data items that aren't kept * in-place in each field. */ nfields = 0; for (b = 0; b <= FIELD_LAST; b++) if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); nfields += td->td_customValueCount; dirsize = nfields * sizeof (TIFFDirEntry); data = (char*) _TIFFmalloc(dirsize); if (data == NULL) { TIFFError(tif->tif_name, "Cannot write directory, out of space"); return (0); } /* * Directory hasn't been placed yet, put * it at the end of the file and link it * into the existing directory structure. */ if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) goto bad; tif->tif_dataoff = (toff_t)( tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); if (tif->tif_dataoff & 1) tif->tif_dataoff++; (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); tif->tif_curdir++; dir = (TIFFDirEntry*) data; /* * Setup external form of directory * entries and write data items. */ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); /* * Write out ExtraSamples tag only if * extra samples are present in the data. */ if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { ResetFieldBit(fields, FIELD_EXTRASAMPLES); nfields--; dirsize -= sizeof (TIFFDirEntry); } /*XXX*/ for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; /* ** For custom fields, we test to see if the custom field ** is set or not. For normal fields, we just use the ** FieldSet test. */ if( fip->field_bit == FIELD_CUSTOM ) { int ci, is_set = FALSE; for( ci = 0; ci < td->td_customValueCount; ci++ ) is_set |= (td->td_customValues[ci].info == fip); if( !is_set ) continue; } else if (!FieldSet(fields, fip->field_bit)) continue; /* ** Handle other fields. */ switch (fip->field_bit) { case FIELD_STRIPOFFSETS: /* * We use one field bit for both strip and tile * offsets, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = isTiled(tif) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS; if (tag != fip->field_tag) continue; if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir, (uint32) td->td_nstrips, td->td_stripoffset)) goto bad; break; case FIELD_STRIPBYTECOUNTS: /* * We use one field bit for both strip and tile * byte counts, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = isTiled(tif) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS; if (tag != fip->field_tag) continue; if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir, (uint32) td->td_nstrips, td->td_stripbytecount)) goto bad; break; case FIELD_ROWSPERSTRIP: TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, dir, td->td_rowsperstrip); break; case FIELD_COLORMAP: if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, 3, td->td_colormap)) goto bad; break; case FIELD_IMAGEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, dir++, td->td_imagewidth); TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, dir, td->td_imagelength); break; case FIELD_TILEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, dir++, td->td_tilewidth); TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, dir, td->td_tilelength); break; case FIELD_COMPRESSION: TIFFSetupShort(tif, TIFFTAG_COMPRESSION, dir, td->td_compression); break; case FIELD_PHOTOMETRIC: TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, dir, td->td_photometric); break; case FIELD_POSITION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XPOSITION, td->td_xposition, TIFFTAG_YPOSITION, td->td_yposition); break; case FIELD_RESOLUTION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XRESOLUTION, td->td_xresolution, TIFFTAG_YRESOLUTION, td->td_yresolution); break; case FIELD_BITSPERSAMPLE: case FIELD_MINSAMPLEVALUE: case FIELD_MAXSAMPLEVALUE: case FIELD_SAMPLEFORMAT: if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) goto bad; break; case FIELD_SMINSAMPLEVALUE: case FIELD_SMAXSAMPLEVALUE: if (!TIFFWritePerSampleAnys(tif, _TIFFSampleToTagType(tif), fip->field_tag, dir)) goto bad; break; case FIELD_PAGENUMBER: case FIELD_HALFTONEHINTS: #ifdef YCBCR_SUPPORT case FIELD_YCBCRSUBSAMPLING: #endif #ifdef CMYK_SUPPORT case FIELD_DOTRANGE: #endif if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; break; #ifdef CMYK_SUPPORT case FIELD_INKNAMES: if (!TIFFWriteInkNames(tif, dir)) goto bad; break; #endif #ifdef COLORIMETRY_SUPPORT case FIELD_TRANSFERFUNCTION: if (!TIFFWriteTransferFunction(tif, dir)) goto bad; break; #endif #if SUBIFD_SUPPORT case FIELD_SUBIFD: if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; /* * Total hack: if this directory includes a SubIFD * tag then force the next <n> directories to be * written as ``sub directories'' of this one. This * is used to write things like thumbnails and * image masks that one wants to keep out of the * normal directory linkage access mechanism. */ if (dir->tdir_count > 0) { tif->tif_flags |= TIFF_INSUBIFD; tif->tif_nsubifd = (uint16) dir->tdir_count; if (dir->tdir_count > 1) tif->tif_subifdoff = dir->tdir_offset; else tif->tif_subifdoff = (uint32)( tif->tif_diroff + sizeof (uint16) + ((char*)&dir->tdir_offset-data)); } break; #endif default: if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; break; } dir++; if( fip->field_bit != FIELD_CUSTOM ) ResetFieldBit(fields, fip->field_bit); } /* * Write directory. */ dircount = (uint16) nfields; diroff = (uint32) tif->tif_nextdiroff; if (tif->tif_flags & TIFF_SWAB) { /* * The file's byte order is opposite to the * native machine architecture. We overwrite * the directory information with impunity * because it'll be released below after we * write it to the file. Note that all the * other tag construction routines assume that * we do this byte-swapping; i.e. they only * byte-swap indirect data. */ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { TIFFSwabArrayOfShort(&dir->tdir_tag, 2); TIFFSwabArrayOfLong(&dir->tdir_count, 2); } dircount = (uint16) nfields; TIFFSwabShort(&dircount); TIFFSwabLong(&diroff); } (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); if (!WriteOK(tif, &dircount, sizeof (dircount))) { TIFFError(tif->tif_name, "Error writing directory count"); goto bad; } if (!WriteOK(tif, data, dirsize)) { TIFFError(tif->tif_name, "Error writing directory contents"); goto bad; } if (!WriteOK(tif, &diroff, sizeof (diroff))) { TIFFError(tif->tif_name, "Error writing directory link"); goto bad; } if (done) { TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; (*tif->tif_cleanup)(tif); /* * Reset directory-related state for subsequent * directories. */ TIFFCreateDirectory(tif); } _TIFFfree(data); return (1); bad: _TIFFfree(data); return (0); }
CPL_C_END /************************************************************************/ /* GTIFFWriteDirectory() */ /* */ /* Create a new directory, without any image data for an overview */ /* or a mask */ /* Returns offset of newly created directory, but the */ /* current directory is reset to be the one in used when this */ /* function is called. */ /************************************************************************/ long GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata ) { toff_t nBaseDirOffset; toff_t nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */ TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if (panExtraSampleValues != NULL) { TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
toff_t GTIFFWriteDirectory( TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, int nPredictor, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata, const char* pszJPEGQuality, const char* pszJPEGTablesMode, const char* pszNoData, CPL_UNUSED const uint32* panLercAddCompressionAndVersion ) { const toff_t nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); // This is a bit of a hack to cause (*tif->tif_cleanup)(tif); to be called. // See https://trac.osgeo.org/gdal/ticket/2055 TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, COMPRESSION_NONE ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 // 3.8.0 TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else { TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); } TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if( panExtraSampleValues != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } if( nCompressFlag == COMPRESSION_LZW || nCompressFlag == COMPRESSION_ADOBE_DEFLATE || nCompressFlag == COMPRESSION_ZSTD ) TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write JPEG tables if needed. */ /* -------------------------------------------------------------------- */ if( nCompressFlag == COMPRESSION_JPEG ) { GTiffWriteJPEGTables( hTIFF, (nPhotometric == PHOTOMETRIC_RGB) ? "RGB" : (nPhotometric == PHOTOMETRIC_YCBCR) ? "YCBCR" : "MINISBLACK", pszJPEGQuality, pszJPEGTablesMode ); if( nPhotometric == PHOTOMETRIC_YCBCR ) { // Explicitly register the subsampling so that JPEGFixupTags // is a no-op (helps for cloud optimized geotiffs) TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, 2, 2 ); } } #ifdef HAVE_LERC if( nCompressFlag == COMPRESSION_LERC && panLercAddCompressionAndVersion ) { TIFFSetField(hTIFF, TIFFTAG_LERC_PARAMETERS, 2, panLercAddCompressionAndVersion); } #endif /* -------------------------------------------------------------------- */ /* Write no data value if we have one. */ /* -------------------------------------------------------------------- */ if( pszNoData != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, pszNoData ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, static_cast<tdir_t>(TIFFNumberOfDirectories(hTIFF) - 1) ); const toff_t nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int bUseSubIFDs, int nHorSubsampling, int nVerSubsampling ) { uint32 nBaseDirOffset; uint32 nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB ) { TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, nHorSubsampling, nVerSubsampling); /* TODO: also write YCbCrPositioning and YCbCrCoefficients tag identical to source IFD */ } /* TODO: add command-line parameter for selecting jpeg compression quality * that gets ignored when compression isn't jpeg */ /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ) == 0 ) return 0; TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
static uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize, int nBitsPerPixel, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int bUseSubIFDs ) { uint32 nBaseDirOffset; uint32 nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_SEPARATE ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ); TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, TIFFNumberOfDirectories(hTIFF)-1 ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
/* * Write the contents of the current directory * to the specified file. This routine doesn't * handle overwriting a directory with auxiliary * storage that's been changed. */ static int _TIFFWriteDirectory(TIFF* tif, int done) { uint64 dircount; /* 16-bit or 64-bit directory entry count */ toff_t diroff; /* 32-bit or 64-bit directory offset */ ttag_t tag; uint32 nfields; tsize_t dirsize; char* data; TIFFDirEntry* dir; TIFFDirectory* td; unsigned long b, fields[FIELD_SETLONGS]; int fi, nfi; if (tif->tif_mode == O_RDONLY) return (1); /* * Clear write state so that subsequent images with * different characteristics get the right buffers * setup for them. */ if (done) { if (tif->tif_flags & TIFF_POSTENCODE) { tif->tif_flags &= ~TIFF_POSTENCODE; if (!(*tif->tif_postencode)(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error post-encoding before directory write"); return (0); } } (*tif->tif_close)(tif); /* shutdown encoder */ /* * Flush any data that might have been written * by the compression close+cleanup routines. */ if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error flushing data before directory write"); return (0); } if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawcc = 0; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); } /* * Loop to allow retry in case transition to BigTIFF required */ while (1) { /* * Directory hasn't been placed yet, put * it at the end of the file and link it * into the existing directory structure. */ if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) goto bad2; td = &tif->tif_dir; /* * Size the directory so that we can calculate * offsets for the data items that aren't kept * in-place in each field. */ nfields = 0; for (b = 0; b <= FIELD_LAST; b++) if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); nfields += td->td_customValueCount; dirsize = nfields * TDIREntryLen(tif); data = (char*) _TIFFmalloc(dirsize); if (data == NULL) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Cannot write directory, out of space"); goto bad2; } _TIFFmemset(data, 0, dirsize); /* * Setup external form of directory * entries and write data items. */ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); /* * Write out ExtraSamples tag only if * extra samples are present in the data. */ if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { ResetFieldBit(fields, FIELD_EXTRASAMPLES); nfields--; dirsize -= TDIREntryLen(tif); } /*XXX*/ tif->tif_dataoff = tif->tif_diroff + TIFFDirCntLen(tif) + dirsize + TIFFDirOffLen(tif); (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); dir = (TIFFDirEntry*) data; for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; /* ** For custom fields, we test to see if the custom field ** is set or not. For normal fields, we just use the ** FieldSet test. */ if( fip->field_bit == FIELD_CUSTOM ) { int ci, is_set = FALSE; for( ci = 0; ci < td->td_customValueCount; ci++ ) is_set |= (td->td_customValues[ci].info == fip); if( !is_set ) continue; } else if (!FieldSet(fields, fip->field_bit)) continue; /* ** Handle other fields. */ switch (fip->field_bit) { case FIELD_STRIPOFFSETS: /* * We use one field bit for both strip and tile * offsets, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = (isTiled(tif) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS); if (tag != fip->field_tag) continue; dir->s.tdir_tag = (uint16) tag; TDIRSetEntryCount(tif,dir, (uint32) td->td_nstrips); /* * If file is BigTIFF strip/tile offsets are written as 64-bit, * else convert to array of 32-bit offsets. */ if (isBigTIFF(tif)) { dir->s.tdir_type = (uint16) TIFF_LONG8; if (!TIFFWriteLong8Array(tif, dir, td->td_stripoffset)) goto bad; } else { uint32 tdi; int status; uint32 *soff = _TIFFCheckMalloc(tif, td->td_nstrips, sizeof(uint32), "32-bit offset array"); dir->s.tdir_type = (uint16) TIFF_LONG; for (tdi = 0; tdi < td->td_nstrips; tdi++) soff[tdi] = (uint32) td->td_stripoffset[tdi]; status = TIFFWriteLongArray(tif, dir, soff); _TIFFfree(soff); if (!status) goto bad; } break; case FIELD_STRIPBYTECOUNTS: /* * We use one field bit for both strip and tile * byte counts, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = (isTiled(tif) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS); if (tag != fip->field_tag) continue; dir->s.tdir_tag = (uint16) tag; dir->s.tdir_type = (uint16) TIFF_LONG; TDIRSetEntryCount(tif,dir, (uint32) td->td_nstrips); if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount)) goto bad; break; case FIELD_ROWSPERSTRIP: TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, dir, td->td_rowsperstrip); break; case FIELD_COLORMAP: if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, 3, td->td_colormap)) goto bad; break; case FIELD_IMAGEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, dir, td->td_imagewidth); TDIREntryNext(tif,dir); TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, dir, td->td_imagelength); break; case FIELD_TILEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, dir, td->td_tilewidth); TDIREntryNext(tif,dir); TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, dir, td->td_tilelength); break; case FIELD_COMPRESSION: TIFFSetupShort(tif, TIFFTAG_COMPRESSION, dir, td->td_compression); break; case FIELD_PHOTOMETRIC: TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, dir, td->td_photometric); break; case FIELD_POSITION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XPOSITION, td->td_xposition, TIFFTAG_YPOSITION, td->td_yposition); break; case FIELD_RESOLUTION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XRESOLUTION, td->td_xresolution, TIFFTAG_YRESOLUTION, td->td_yresolution); break; case FIELD_BITSPERSAMPLE: case FIELD_MINSAMPLEVALUE: case FIELD_MAXSAMPLEVALUE: case FIELD_SAMPLEFORMAT: if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) goto bad; break; case FIELD_SMINSAMPLEVALUE: case FIELD_SMAXSAMPLEVALUE: if (!TIFFWritePerSampleAnys(tif, _TIFFSampleToTagType(tif), fip->field_tag, dir)) goto bad; break; case FIELD_PAGENUMBER: case FIELD_HALFTONEHINTS: case FIELD_YCBCRSUBSAMPLING: if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; break; case FIELD_INKNAMES: if (!TIFFWriteInkNames(tif, dir)) goto bad; break; case FIELD_TRANSFERFUNCTION: if (!TIFFWriteTransferFunction(tif, dir)) goto bad; break; case FIELD_SUBIFD: /* * Total hack: if this directory includes a SubIFD * tag then force the next <n> directories to be * written as ``sub directories'' of this one. This * is used to write things like thumbnails and * image masks that one wants to keep out of the * normal directory linkage access mechanism. * * If file is BigTIFF subdirectory offsets are written as 64-bit, * else as array of 32-bit offsets. At this point the actual * offset values are unknown (will be set in TIFFLinkDirectory). */ dir->s.tdir_tag = (uint16) fip->field_tag; TDIRSetEntryCount(tif,dir, (uint32) td->td_nsubifd); TDIRSetEntryOff(tif,dir, 0); if (td->td_nsubifd > 0) { tif->tif_flags |= TIFF_INSUBIFD; if (isBigTIFF(tif)) { toff_t *doff = _TIFFCheckMalloc(tif, td->td_nsubifd, sizeof(toff_t), "Allocate SubIFD offset array"); if (!doff) goto bad; _TIFFmemset(doff, 0, td->td_nsubifd * sizeof(toff_t)); dir->b.tdir_type = TIFF_IFD8; if (td->td_nsubifd > TIFFDirOffLen(tif) / sizeof(toff_t)) tif->tif_subifdoff = tif->tif_dataoff; else tif->tif_subifdoff = tif->tif_diroff + TIFFDirCntLen(tif) + (char*) &dir->b.tdir_offset - data; if (!TIFFWriteLong8Array(tif, dir, (toff_t*) doff)) goto bad; _TIFFfree(doff); } else { uint32 *doff = _TIFFCheckMalloc(tif, td->td_nsubifd, sizeof(uint32), "Allocate SubIFD offset array"); if (!doff) goto bad; _TIFFmemset(doff, 0, td->td_nsubifd * sizeof(uint32)); dir->b.tdir_type = TIFF_LONG; if (td->td_nsubifd > TIFFDirOffLen(tif) / sizeof(uint32)) tif->tif_subifdoff = tif->tif_dataoff; else tif->tif_subifdoff = tif->tif_diroff + TIFFDirCntLen(tif) + (char*) &dir->s.tdir_offset - data; if (!TIFFWriteLongArray(tif, dir, doff)) goto bad; _TIFFfree(doff); } } break; default: /* XXX: Should be fixed and removed. */ if (fip->field_tag == TIFFTAG_DOTRANGE) { if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; } else if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; break; } TDIREntryNext(tif,dir); if( fip->field_bit != FIELD_CUSTOM ) ResetFieldBit(fields, fip->field_bit); } /* * Check if BigTIFF now required based on data location. If so reset * data offset to overwrite already-written data for directory, then * convert file to BigTIFF and loop to recreate directory. */ if (isBigTIFF(tif) || !isBigOff(tif->tif_dataoff + sizeof(uint32))) break; _TIFFfree(data); tif->tif_dataoff = tif->tif_diroff; if (!TIFFMakeBigTIFF(tif)) goto bad2; tif->tif_diroff = 0; } /* bottom of BigTIFF retry loop */ /* * Write directory. */ tif->tif_curdir++; TIFFSetDirCnt(tif,dircount, (uint32) nfields); TIFFSetDirOff(tif,diroff,tif->tif_nextdiroff); if (tif->tif_flags & TIFF_SWAB) { /* * The file's byte order is opposite to the * native machine architecture. We overwrite * the directory information with impunity * because it'll be released below after we * write it to the file. Note that all the * other tag construction routines assume that * we do this byte-swapping; i.e. they only * byte-swap indirect data. */ uint32 di; for (dir = (TIFFDirEntry*) data, di = 0; di < nfields; TDIREntryNext(tif,dir), di++) { TIFFSwabShort(&dir->s.tdir_tag); TIFFSwabShort(&dir->s.tdir_type); TDIRSwabEntryCount(tif,dir); TDIRSwabEntryOff(tif,dir); } TIFFSwabDirCnt(tif,&dircount); TIFFSwabDirOff(tif,&diroff); } (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); if (!WriteOK(tif, &dircount, TIFFDirCntLen(tif))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory count (%d)", TIFFGetErrno(tif)); goto bad; } if (!WriteOK(tif, data, dirsize)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory contents (%d)", TIFFGetErrno(tif)); goto bad; } if (!WriteOK(tif, &diroff, TIFFDirOffLen(tif))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory link (%d)", TIFFGetErrno(tif)); goto bad; } if (done) { TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; (*tif->tif_cleanup)(tif); /* * Reset directory-related state for subsequent * directories. */ TIFFCreateDirectory(tif); } _TIFFfree(data); return (1); bad: _TIFFfree(data); bad2: return (0); }