📄 tif_dirread.c
字号:
MissingRequired(tif, "PlanarConfiguration");
goto bad;
}
/*
* Setup appropriate structures (by strip or by tile)
*/
if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
td->td_nstrips = TIFFNumberOfStrips(tif);
td->td_tilewidth = td->td_imagewidth;
td->td_tilelength = td->td_rowsperstrip;
td->td_tiledepth = td->td_imagedepth;
tif->tif_flags &= ~TIFF_ISTILED;
} else {
td->td_nstrips = TIFFNumberOfTiles(tif);
tif->tif_flags |= TIFF_ISTILED;
}
if (!td->td_nstrips) {
TIFFError(module, "%s: cannot handle zero number of %s",
tif->tif_name, isTiled(tif) ? "tiles" : "strips");
goto bad;
}
td->td_stripsperimage = td->td_nstrips;
if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
td->td_stripsperimage /= td->td_samplesperpixel;
if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
MissingRequired(tif,
isTiled(tif) ? "TileOffsets" : "StripOffsets");
goto bad;
}
/*
* Second pass: extract other information.
*/
for (dp = dir, n = dircount; n > 0; n--, dp++) {
if (dp->tdir_tag == IGNORE)
continue;
switch (dp->tdir_tag) {
case TIFFTAG_MINSAMPLEVALUE:
case TIFFTAG_MAXSAMPLEVALUE:
case TIFFTAG_BITSPERSAMPLE:
case TIFFTAG_DATATYPE:
case TIFFTAG_SAMPLEFORMAT:
/*
* The 5.0 spec says the Compression tag has
* one value, while earlier specs say it has
* one value per sample. Because of this, we
* accept the tag if one value is supplied.
*
* The MinSampleValue, MaxSampleValue, BitsPerSample
* DataType and SampleFormat tags are supposed to be
* written as one value/sample, but some vendors
* incorrectly write one value only -- so we accept
* that as well (yech). Other vendors write correct
* value for NumberOfSamples, but incorrect one for
* BitsPerSample and friends, and we will read this
* too.
*/
if (dp->tdir_count == 1) {
v = TIFFExtractData(tif,
dp->tdir_type, dp->tdir_offset);
if (!TIFFSetField(tif, dp->tdir_tag, (int)v))
goto bad;
} else {
if (!TIFFFetchPerSampleShorts(tif, dp, &iv) ||
!TIFFSetField(tif, dp->tdir_tag, iv))
goto bad;
}
break;
case TIFFTAG_SMINSAMPLEVALUE:
case TIFFTAG_SMAXSAMPLEVALUE:
if (!TIFFFetchPerSampleAnys(tif, dp, &dv) ||
!TIFFSetField(tif, dp->tdir_tag, dv))
goto bad;
break;
case TIFFTAG_STRIPOFFSETS:
case TIFFTAG_TILEOFFSETS:
if (!TIFFFetchStripThing(tif, dp,
td->td_nstrips, &td->td_stripoffset))
goto bad;
break;
case TIFFTAG_STRIPBYTECOUNTS:
case TIFFTAG_TILEBYTECOUNTS:
if (!TIFFFetchStripThing(tif, dp,
td->td_nstrips, &td->td_stripbytecount))
goto bad;
break;
case TIFFTAG_COLORMAP:
case TIFFTAG_TRANSFERFUNCTION:
/*
* TransferFunction can have either 1x or 3x data
* values; Colormap can have only 3x items.
*/
v = 1L<<td->td_bitspersample;
if (dp->tdir_tag == TIFFTAG_COLORMAP ||
dp->tdir_count != (uint32) v) {
if (!CheckDirCount(tif, dp, (uint32)(3*v)))
break;
}
v *= sizeof (uint16);
cp = CheckMalloc(tif, dp->tdir_count, sizeof (uint16),
"to read \"TransferFunction\" tag");
if (cp != NULL) {
if (TIFFFetchData(tif, dp, cp)) {
/*
* This deals with there being only
* one array to apply to all samples.
*/
uint32 c =
(uint32)1 << td->td_bitspersample;
if (dp->tdir_count == c)
v = 0;
TIFFSetField(tif, dp->tdir_tag,
cp, cp+v, cp+2*v);
}
_TIFFfree(cp);
}
break;
case TIFFTAG_PAGENUMBER:
case TIFFTAG_HALFTONEHINTS:
case TIFFTAG_YCBCRSUBSAMPLING:
case TIFFTAG_DOTRANGE:
(void) TIFFFetchShortPair(tif, dp);
break;
case TIFFTAG_REFERENCEBLACKWHITE:
(void) TIFFFetchRefBlackWhite(tif, dp);
break;
/* BEGIN REV 4.0 COMPATIBILITY */
case TIFFTAG_OSUBFILETYPE:
v = 0;
switch (TIFFExtractData(tif, dp->tdir_type,
dp->tdir_offset)) {
case OFILETYPE_REDUCEDIMAGE:
v = FILETYPE_REDUCEDIMAGE;
break;
case OFILETYPE_PAGE:
v = FILETYPE_PAGE;
break;
}
if (v)
(void) TIFFSetField(tif,
TIFFTAG_SUBFILETYPE, (int)v);
break;
/* END REV 4.0 COMPATIBILITY */
default:
(void) TIFFFetchNormalTag(tif, dp);
break;
}
}
/*
* Verify Palette image has a Colormap.
*/
if (td->td_photometric == PHOTOMETRIC_PALETTE &&
!TIFFFieldSet(tif, FIELD_COLORMAP)) {
MissingRequired(tif, "Colormap");
goto bad;
}
/*
* Attempt to deal with a missing StripByteCounts tag.
*/
if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) {
/*
* Some manufacturers violate the spec by not giving
* the size of the strips. In this case, assume there
* is one uncompressed strip of data.
*/
if ((td->td_planarconfig == PLANARCONFIG_CONTIG &&
td->td_nstrips > 1) ||
(td->td_planarconfig == PLANARCONFIG_SEPARATE &&
td->td_nstrips != td->td_samplesperpixel)) {
MissingRequired(tif, "StripByteCounts");
goto bad;
}
TIFFWarning(module,
"%s: TIFF directory is missing required "
"\"%s\" field, calculating from imagelength",
tif->tif_name,
_TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
if (EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
/*
* Assume we have wrong StripByteCount value (in case of single strip) in
* following cases:
* - it is equal to zero along with StripOffset;
* - it is larger than file itself (in case of uncompressed image).
*/
#define BYTECOUNTLOOKSBAD \
( (td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \
(td->td_compression == COMPRESSION_NONE && \
td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0]) )
} else if (td->td_nstrips == 1 && BYTECOUNTLOOKSBAD) {
/*
* Plexus (and others) sometimes give a value
* of zero for a tag when they don't know what
* the correct value is! Try and handle the
* simple case of estimating the size of a one
* strip image.
*/
TIFFWarning(module,
"%s: Bogus \"%s\" field, ignoring and calculating from imagelength",
tif->tif_name,
_TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
if(EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
}
if (dir) {
_TIFFfree((char *)dir);
dir = NULL;
}
if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
td->td_maxsamplevalue = (uint16)((1L<<td->td_bitspersample)-1);
/*
* Setup default compression scheme.
*/
/*
* XXX: We can optimize checking for the strip bounds using the sorted
* bytecounts array. See also comments for TIFFAppendToStrip()
* function in tif_write.c.
*/
if (td->td_nstrips > 1) {
tstrip_t strip;
td->td_stripbytecountsorted = 1;
for (strip = 1; strip < td->td_nstrips; strip++) {
if (td->td_stripoffset[strip - 1] >
td->td_stripoffset[strip]) {
td->td_stripbytecountsorted = 0;
break;
}
}
}
if (!TIFFFieldSet(tif, FIELD_COMPRESSION))
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
/*
* Some manufacturers make life difficult by writing
* large amounts of uncompressed data as a single strip.
* This is contrary to the recommendations of the spec.
* The following makes an attempt at breaking such images
* into strips closer to the recommended 8k bytes. A
* side effect, however, is that the RowsPerStrip tag
* value may be changed.
*/
if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE &&
(tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP)
ChopUpSingleUncompressedStrip(tif);
/*
* Reinitialize i/o since we are starting on a new directory.
*/
tif->tif_row = (uint32) -1;
tif->tif_curstrip = (tstrip_t) -1;
tif->tif_col = (uint32) -1;
tif->tif_curtile = (ttile_t) -1;
tif->tif_tilesize = (tsize_t) -1;
tif->tif_scanlinesize = TIFFScanlineSize(tif);
if (!tif->tif_scanlinesize) {
TIFFError(module, "%s: cannot handle zero scanline size",
tif->tif_name);
return (0);
}
if (isTiled(tif)) {
tif->tif_tilesize = TIFFTileSize(tif);
if (!tif->tif_tilesize) {
TIFFError(module, "%s: cannot handle zero tile size",
tif->tif_name);
return (0);
}
} else {
if (!TIFFStripSize(tif)) {
TIFFError(module, "%s: cannot handle zero strip size",
tif->tif_name);
return (0);
}
}
return (1);
bad:
if (dir)
_TIFFfree(dir);
return (0);
}
static int
EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
{
static const char module[] = "EstimateStripByteCounts";
register TIFFDirEntry *dp;
register TIFFDirectory *td = &tif->tif_dir;
uint16 i;
if (td->td_stripbytecount)
_TIFFfree(td->td_stripbytecount);
td->td_stripbytecount = (uint32*)
CheckMalloc(tif, td->td_nstrips, sizeof (uint32),
"for \"StripByteCounts\" array");
if (td->td_compression != COMPRESSION_NONE) {
uint32 space = (uint32)(sizeof (TIFFHeader)
+ sizeof (uint16)
+ (dircount * sizeof (TIFFDirEntry))
+ sizeof (uint32));
toff_t filesize = TIFFGetFileSize(tif);
uint16 n;
/* calculate amount of space used by indirect values */
for (dp = dir, n = dircount; n > 0; n--, dp++)
{
uint32 cc = TIFFDataWidth((TIFFDataType) dp->tdir_type);
if (cc == 0) {
TIFFError(module,
"%s: Cannot determine size of unknown tag type %d",
tif->tif_name, dp->tdir_type);
return -1;
}
cc = cc * dp->tdir_count;
if (cc > sizeof (uint32))
space += cc;
}
space = filesize - space;
if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
space /= td->td_samplesperpixel;
for (i = 0; i < td->td_nstrips; i++)
td->td_stripbytecount[i] = space;
/*
* This gross hack handles the case were the offset to
* the last strip is past the place where we think the strip
* should begin. Since a strip of data must be contiguous,
* it's safe to assume that we've overestimated the amount
* of data in the strip and trim this number back accordingly.
*/
i--;
if (((toff_t)(td->td_stripoffset[i]+td->td_stripbytecount[i]))
> filesize)
td->td_stripbytecount[i] =
filesize - td->td_stripoffset[i];
} else {
uint32 rowbytes = TIFFScanlineSize(tif);
uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage;
for (i = 0; i < td->td_nstrips; i++)
td->td_stripbytecount[i] = rowbytes*rowsperstrip;
}
TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
td->td_rowsperstrip = td->td_imagelength;
return 1;
}
static void
MissingRequired(TIFF* tif, const char* tagname)
{
static const char module[] = "MissingRequired";
TIFFError(module,
"%s: TIFF directory is missing required \"%s\" field",
tif->tif_name, tagname);
}
/*
* Check the count field of a directory
* entry against a known value. The caller
* is expected to skip/ignore the tag if
* there is a mismatch.
*/
static int
CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
{
if (count > dir->tdir_count) {
TIFFWarning(tif->tif_name,
"incorrect count for field \"%s\" (%lu, expecting %lu); tag ignored",
_TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
dir->tdir_count, count);
return (0);
} else if (count < dir->tdir_count) {
TIFFWarning(tif->tif_name,
"incorrect count for field \"%s\" (%lu, expecting %lu); tag trimmed",
_TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
dir->tdir_count, count);
return (1);
}
return (1);
}
/*
* Fetch a contiguous directory item.
*/
static tsize_t
TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
{
int w = TIFFDataWidth((TIFFDataType) dir->tdir_type);
tsize_t cc = dir->tdir_count * w;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -