package
t::lib::Boot;
use
strict;
use
Carp;
$VERSION
= 0.11;
# revised 2015-03-21
#
# Copyright © 2004-2020 by William B. Birkett
#
# reads an ICC profile's profile header and tag table
# create bootstrap profile object
# parameters: (path_to_profile)
# returns: (ref_to_profile_object)
sub
new {
# get object class
my
$class
=
shift
();
# create empty profile object
my
$self
= [
{},
# object header
[],
# profile header
[]
# tag table
];
# if one parameter, a file path
if
(
@_
== 1 && !
ref
(
$_
[0]) && -f
$_
[0]) {
# read data from ICC profile
_readICCprofile(
$self
,
@_
) || croak(
"couldn't read profile: $_[0]\n"
);
}
# bless object
bless
(
$self
,
$class
);
# return object reference
return
(
$self
);
}
# get reference to profile header
# returns: (ref_to_profile_header_array)
sub
profile_header {
# get tag reference
my
$self
=
shift
();
# return reference to header
return
(
$self
->[1]);
}
# get reference to profile tag table
# returns: (ref_to_profile_tag_table_array)
sub
tag_table {
# get tag reference
my
$self
=
shift
();
# return reference to header
return
(
$self
->[2]);
}
# get file handle
# returns: (file_handle)
sub
fh {
# get tag reference
my
$self
=
shift
();
# return file handle
return
(
$self
->[3]);
}
# read data from ICC profile
# parameters: (ref_to_object, path_to_profile)
# returns: (success_flag)
sub
_readICCprofile {
# get parameters
my
(
$self
,
$path
) =
@_
;
# local variables
my
(
$fh
,
$buf
);
# open the profile file
open
(
$fh
,
$path
) ||
return
(0);
# set binary mode
binmode
(
$fh
);
# save file handle
$self
->[3] =
$fh
;
# seek to profile file signature
seek
(
$fh
, 36, 0);
# read profile file signature
read
(
$fh
,
$buf
, 4);
# return if not an ICC profile
(
$buf
eq
'acsp'
) ||
return
(0);
# read the header
_readICCheader(
$fh
,
$self
->[1]) ||
return
(0);
# read the tag table
_readICCtagtable(
$fh
,
$self
->[2]) ||
return
(0);
# return
return
(1);
}
# read ICC header
# parameters: (file_handle, ref_to_header_array)
# returns: (success_flag)
sub
_readICCheader {
# get parameters
my
(
$fh
,
$header
) =
@_
;
# local variables
my
(
$buf
,
$check
);
# seek to start of header
seek
(
$fh
, 0, 0);
# read the header (128 bytes)
(
read
(
$fh
,
$buf
, 128) == 128) ||
return
(0);
# unpack the header
@{
$header
} =
unpack
(
'N a4 H8 a4 a4 a4 n6 a4 a4 N a4 a4 N2 N N3 a4 H32 x28'
,
$buf
);
# return success if profile file signature verified
return
(
$header
->[12] eq
'acsp'
? 1 : 0);
}
# read ICC tag table
# parameters: (file_handle, ref_to_tag_table_array)
# returns: (success_flag)
sub
_readICCtagtable {
# get parameters
my
(
$fh
,
$tagtab
) =
@_
;
# local variables
my
(
$buf
,
$i
,
$n
);
# seek to start of tag table
seek
(
$fh
, 128, 0);
# read tag count (4 bytes)
(
read
(
$fh
,
$buf
, 4) == 4) ||
return
(0);
# unpack tag count
$n
=
unpack
(
'N'
,
$buf
);
# read tag entries
for
$i
(0 ..
$n
- 1) {
# read tag entry (12 bytes)
(
read
(
$fh
,
$buf
, 12) == 12) ||
return
(0) ;
# unpack tag entry
@{
$tagtab
->[
$i
]} =
unpack
(
'a4 N N'
,
$buf
);
}
# return
return
(1);
}
1;