Sponsoring The Perl Toolchain Summit 2025: Help make this important event another success Learn more

package t::lib::Boot;
use strict;
use Carp;
use vars qw(@ISA $VERSION);
$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;