our
$VERSION
=
'2.047'
;
sub
new {
my
(
$class
,
$file
) =
@_
;
my
$self
= {};
bless
(
$self
,
$class
);
if
(
ref
(
$file
)) {
$self
->{
'fh'
} =
$file
;
seek
(
$self
->{
'fh'
}, 0, 0);
}
else
{
$self
->{
'fh'
} = IO::File->new();
open
(
$self
->{
'fh'
},
'<'
,
$file
) or
die
"$!: $file"
;
}
binmode
(
$self
->{
'fh'
},
':raw'
);
my
$fh
=
$self
->{
'fh'
};
$self
->{
'offset'
} = 0;
$fh
->
seek
(
$self
->{
'offset'
}, 0);
$fh
->
read
(
$self
->{
'byteOrder'
}, 2);
$self
->{
'byte'
} =
'C'
;
$self
->{
'short'
} = ((
$self
->{
'byteOrder'
} eq
'MM'
) ?
'n'
:
'v'
);
$self
->{
'long'
} = ((
$self
->{
'byteOrder'
} eq
'MM'
) ?
'N'
:
'V'
);
$self
->{
'rational'
} = ((
$self
->{
'byteOrder'
} eq
'MM'
) ?
'NN'
:
'VV'
);
$fh
->
read
(
$self
->{
'version'
}, 2);
$self
->{
'version'
} =
unpack
(
$self
->{
'short'
},
$self
->{
'version'
});
die
"Wrong TIFF Id '$self->{version}' (should be 42)."
if
$self
->{
'version'
} != 42;
$fh
->
read
(
$self
->{
'ifdOffset'
}, 4);
$self
->{
'ifdOffset'
} =
unpack
(
$self
->{
'long'
},
$self
->{
'ifdOffset'
});
$self
->readTags();
return
$self
;
}
sub
readTag {
my
$self
=
shift
();
my
$fh
=
$self
->{
'fh'
};
my
$buf
;
$fh
->
read
(
$buf
, 12);
my
$tag
=
unpack
(
$self
->{
'short'
},
substr
(
$buf
, 0, 2));
my
$type
=
unpack
(
$self
->{
'short'
},
substr
(
$buf
, 2, 2));
my
$count
=
unpack
(
$self
->{
'long'
},
substr
(
$buf
, 4, 4));
my
$len
= 0;
$len
= (
$type
== 1 ?
$count
:
$type
== 2 ?
$count
:
$type
== 3 ?
$count
* 2 :
$type
== 4 ?
$count
* 4 :
$type
== 5 ?
$count
* 8 :
$count
);
my
$off
=
substr
(
$buf
, 8, 4);
if
(
$len
> 4) {
$off
=
unpack
(
$self
->{
'long'
},
$off
);
}
else
{
$off
= (
$type
== 1 ?
unpack
(
$self
->{
'byte'
},
$off
) :
$type
== 2 ?
unpack
(
$self
->{
'long'
},
$off
) :
$type
== 3 ?
unpack
(
$self
->{
'short'
},
$off
) :
$type
== 4 ?
unpack
(
$self
->{
'long'
},
$off
) :
unpack
(
$self
->{
'short'
},
$off
));
}
return
(
$tag
,
$type
,
$count
,
$len
,
$off
);
}
sub
close
{
my
$self
=
shift
();
return
$self
->{
'fh'
}->
close
();
}
sub
readTags {
my
$self
=
shift
();
my
$fh
=
$self
->{
'fh'
};
$self
->{
'fillOrder'
} = 1;
$self
->{
'ifd'
} =
$self
->{
'ifdOffset'
};
while
(
$self
->{
'ifd'
} > 0) {
$fh
->
seek
(
$self
->{
'ifd'
}, 0);
$fh
->
read
(
$self
->{
'ifdNum'
}, 2);
$self
->{
'ifdNum'
} =
unpack
(
$self
->{
'short'
},
$self
->{
'ifdNum'
});
$self
->{
'bitsPerSample'
} = 1;
foreach
(1 ..
$self
->{
'ifdNum'
}) {
my
(
$valTag
,
$valType
,
$valCount
,
$valLen
,
$valOffset
) =
$self
->readTag();
if
(
$valTag
== 0) {
}
elsif
(
$valTag
== 256) {
$self
->{
'imageWidth'
} =
$valOffset
;
}
elsif
(
$valTag
== 257) {
$self
->{
'imageHeight'
} =
$valOffset
;
}
elsif
(
$valTag
== 258) {
if
(
$valCount
> 1) {
my
$here
=
$fh
->
tell
();
my
$val
;
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$val
, 2);
$self
->{
'bitsPerSample'
} =
unpack
(
$self
->{
'short'
},
$val
);
$fh
->
seek
(
$here
, 0);
}
else
{
$self
->{
'bitsPerSample'
} =
$valOffset
;
}
}
elsif
(
$valTag
== 259) {
$self
->{
'filter'
} =
$valOffset
;
if
(
$valOffset
== 1) {
delete
$self
->{
'filter'
};
}
elsif
(
$valOffset
== 3 ||
$valOffset
== 4) {
$self
->{
'filter'
} =
'CCITTFaxDecode'
;
$self
->{
'ccitt'
} =
$valOffset
;
}
elsif
(
$valOffset
== 5) {
$self
->{
'filter'
} =
'LZWDecode'
;
}
elsif
(
$valOffset
== 6 ||
$valOffset
== 7) {
$self
->{
'filter'
} =
'DCTDecode'
;
}
elsif
(
$valOffset
== 8 ||
$valOffset
== 0x80b2) {
$self
->{
'filter'
} =
'FlateDecode'
;
}
elsif
(
$valOffset
== 32773) {
$self
->{
'filter'
} =
'RunLengthDecode'
;
}
else
{
die
"unknown/unsupported TIFF compression method with id '$self->{filter}'."
;
}
}
elsif
(
$valTag
== 262) {
$self
->{
'colorSpace'
} =
$valOffset
;
if
(
$valOffset
== 0) {
$self
->{
'colorSpace'
} =
'DeviceGray'
;
$self
->{
'whiteIsZero'
} = 1;
}
elsif
(
$valOffset
== 1) {
$self
->{
'colorSpace'
} =
'DeviceGray'
;
$self
->{
'blackIsZero'
} = 1;
}
elsif
(
$valOffset
== 2) {
$self
->{
'colorSpace'
} =
'DeviceRGB'
;
}
elsif
(
$valOffset
== 3) {
$self
->{
'colorSpace'
} =
'Indexed'
;
}
elsif
(
$valOffset
== 5) {
$self
->{
'colorSpace'
} =
'DeviceCMYK'
;
}
elsif
(
$valOffset
== 6) {
$self
->{
'colorSpace'
} =
'DeviceRGB'
;
}
elsif
(
$valOffset
== 8) {
$self
->{
'colorSpace'
} =
'Lab'
;
}
else
{
die
"unknown/unsupported TIFF photometric interpretation with id '$self->{colorSpace}'."
;
}
}
elsif
(
$valTag
== 266) {
$self
->{
'fillOrder'
} =
$valOffset
;
}
elsif
(
$valTag
== 270) {
my
$here
=
$fh
->
tell
();
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$self
->{
'imageDescription'
},
$valLen
);
$fh
->
seek
(
$here
, 0);
}
elsif
(
$valTag
== 282) {
my
$here
=
$fh
->
tell
();
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$self
->{
'xRes'
},
$valLen
);
$fh
->
seek
(
$here
, 0);
$self
->{
'xRes'
} = [
unpack
(
$self
->{
'rational'
},
$self
->{
'xRes'
})];
$self
->{
'xRes'
} = (
$self
->{
'xRes'
}->[0] /
$self
->{
'xRes'
}->[1]);
}
elsif
(
$valTag
== 283) {
my
$here
=
$fh
->
tell
();
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$self
->{
'yRes'
},
$valLen
);
$fh
->
seek
(
$here
, 0);
$self
->{
'yRes'
} = [
unpack
(
$self
->{
'rational'
},
$self
->{
'yRes'
})];
$self
->{
'yRes'
} = (
$self
->{
'yRes'
}->[0] /
$self
->{
'yRes'
}->[1]);
}
elsif
(
$valTag
== 296) {
$self
->{
'resUnit'
} =
$valOffset
;
}
elsif
(
$valTag
== 273) {
if
(
$valCount
== 1) {
$self
->{
'imageOffset'
} =
$valOffset
;
}
else
{
my
$here
=
$fh
->
tell
();
my
$val
;
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$val
,
$valLen
);
$fh
->
seek
(
$here
, 0);
$self
->{
'imageOffset'
} = [
unpack
(
$self
->{
'long'
} .
'*'
,
$val
)];
}
}
elsif
(
$valTag
== 277) {
$self
->{
'samplesPerPixel'
} =
$valOffset
;
}
elsif
(
$valTag
== 278) {
$self
->{
'RowsPerStrip'
} =
$valOffset
;
}
elsif
(
$valTag
== 279) {
if
(
$valCount
== 1) {
$self
->{
'imageLength'
} =
$valOffset
;
}
else
{
my
$here
=
$fh
->
tell
();
my
$val
;
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$val
,
$valLen
);
$fh
->
seek
(
$here
, 0);
$self
->{
'imageLength'
} = [
unpack
(
$self
->{
'long'
} .
'*'
,
$val
)];
}
}
elsif
(
$valTag
== 292) {
$self
->{
'g3Options'
} =
$valOffset
;
}
elsif
(
$valTag
== 293) {
$self
->{
'g4Options'
} =
$valOffset
;
}
elsif
(
$valTag
== 320) {
$self
->{
'colorMapOffset'
} =
$valOffset
;
$self
->{
'colorMapSamples'
} =
$valCount
;
$self
->{
'colorMapLength'
} =
$valCount
* 2;
}
elsif
(
$valTag
== 317) {
$self
->{
'lzwPredictor'
} =
$valOffset
;
}
elsif
(
$valTag
== 0x800d) {
my
$here
=
$fh
->
tell
();
$fh
->
seek
(
$valOffset
, 0);
$fh
->
read
(
$self
->{
'imageId'
},
$valLen
);
$fh
->
seek
(
$here
, 0);
}
}
$fh
->
read
(
$self
->{
'ifd'
}, 4);
$self
->{
'ifd'
} =
unpack
(
$self
->{
'long'
},
$self
->{
'ifd'
});
}
return
$self
;
}
1;