Subject: | Broken BitsPerSample handling in TIFFs. |
Image::Info fails to get a valid BitsPerSample for a TIFF image with a SamplesPerPixel > 1.
The documentation claims that $info->{BitsPerSample} returns an arrayref with one element for each sample. In fact it returns a simple scalar when SamplesPerPixel == 1, and returns nothing when it is > 1 (ie for all colour TIFFs, as far as I know.)
Enabling the commented-out print statement in Image::Info::TIFF::process_ifds shows this (note lines 4/0 and 10/0)
1/0: tag: 254 (NewSubfileType), fieldtype: 4, count: 1, offset: 0 ()
2/0: tag: 256 (width), fieldtype: 4, count: 1, offset: 3531 (3531)
3/0: tag: 257 (height), fieldtype: 4, count: 1, offset: 3841 (3841)
4/0: tag: 258 (BitsPerSample), fieldtype: 3, count: 3, offset: 8 ()
5/0: tag: 259 (Compression), fieldtype: 3, count: 1, offset: 1 (PackBytes)
6/0: tag: 262 (PhotometricInterpretation), fieldtype: 3, count: 1, offset: 2 (RGB)
7/0: tag: 270 (ImageDescription), fieldtype: 2, count: 1, offset: 14 ()
8/0: tag: 273 (StripOffsets), fieldtype: 4, count: 3841, offset: 40677151 (ARRAY(0x3d9644))
9/0: tag: 274 (Orientation), fieldtype: 3, count: 1, offset: 1 (top_left)
10/0: tag: 277 (SamplesPerPixel), fieldtype: 3, count: 1, offset: 3 (3)
11/0: tag: 278 (RowsPerStrip), fieldtype: 4, count: 1, offset: 1 (1)
12/0: tag: 279 (StripByteCounts), fieldtype: 4, count: 3841, offset: 10593 (ARRAY(0x42c560))
13/0: tag: 282 (XResolution), fieldtype: 5, count: 1, offset: 15 (15748031/100000)
14/0: tag: 283 (YResolution), fieldtype: 5, count: 1, offset: 23 (15748031/100000)
15/0: tag: 296 (ResolutionUnit), fieldtype: 3, count: 1, offset: 3 (dpcm)
So it is failing when fieldtype == 3 and count != 1. This appears to be due to faulty logic. Further up you have the following code (contents of each block stripped for clarity):
if ($fieldtype == 3 && $count <= 1) {
} else { # fieldtype == 4
}
if ($fieldtype == 2) {
} elsif (($fieldtype == 3 || $fieldtype == 4) &&
$count == 1) {
} elsif ($fieldtype == 3 && $count == 2) {
} elsif ($fieldtype == 4 && $count > 1) {
} elsif ($fieldtype == 5 || $fieldtype == 10) {
}
So note you have two separate if statements here. The first has what seems to be a misleading comment, that the 'else' only deals with fieldtype 4. The second has a horrible mixture of tests, NO else clause, and hence nothing to catch conditions that you have failed to identify -- like for instance a fieldtype of 3 and a count of 3. It is simple to patch but I would respectfully suggest you might like to clean up this entire section... Especially:
if ($#{$val} == 0) {
$val = $$val[0];
}
I may be controversial here but I'd say it is not up to you to go changing the type of the returned variable from an arrayref to a plain scalar, meaning that the poor person using this module has to remember to check whether it's a ref or not every time. Your documentation says that BitsPerSample is an arrayref, so why not make it an arrayref every time instead of changing according to what sort of image you throw at it?