| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package ICC::Support::Chart; |
|
2
|
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
85051
|
use strict; |
|
|
2
|
|
|
|
|
12
|
|
|
|
2
|
|
|
|
|
50
|
|
|
4
|
2
|
|
|
2
|
|
8
|
use Carp; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
114
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = 2.01; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# revised 2020-01-01 |
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# Copyright © 2004-2020 by William B. Birkett |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# inherit from Shared |
|
13
|
2
|
|
|
2
|
|
397
|
use parent qw(ICC::Shared); |
|
|
2
|
|
|
|
|
254
|
|
|
|
2
|
|
|
|
|
10
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# support modules |
|
16
|
2
|
|
|
2
|
|
93
|
use Config; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
65
|
|
|
17
|
2
|
|
|
2
|
|
510
|
use Encode; |
|
|
2
|
|
|
|
|
8822
|
|
|
|
2
|
|
|
|
|
126
|
|
|
18
|
2
|
|
|
2
|
|
14
|
use File::Glob; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
108
|
|
|
19
|
2
|
|
|
2
|
|
12
|
use POSIX (); |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
33
|
|
|
20
|
2
|
|
|
2
|
|
456
|
use Time::Piece; |
|
|
2
|
|
|
|
|
7851
|
|
|
|
2
|
|
|
|
|
11
|
|
|
21
|
2
|
|
|
2
|
|
690
|
use XML::LibXML; |
|
|
2
|
|
|
|
|
37166
|
|
|
|
2
|
|
|
|
|
14
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# enable static variables |
|
24
|
2
|
|
|
2
|
|
292
|
use feature 'state'; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
114930
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# create new chart object |
|
27
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
28
|
|
|
|
|
|
|
# parameters: (ref_to_data_array, [hash]) |
|
29
|
|
|
|
|
|
|
# parameters: (path_to_file, [hash]) |
|
30
|
|
|
|
|
|
|
# parameters: (path_to_folder, [hash]) |
|
31
|
|
|
|
|
|
|
# returns: (ref_to_chart_object) -or- (ref_to_chart_object, error_string) |
|
32
|
|
|
|
|
|
|
sub new { |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# get object class |
|
35
|
29
|
|
|
29
|
1
|
242529
|
my $class = shift(); |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# local variables |
|
38
|
29
|
|
|
|
|
71
|
my ($self, $hash, $array, $format, $offset, $path, $files, $result, $error); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# create empty chart object |
|
41
|
29
|
|
|
|
|
83
|
$self = [ |
|
42
|
|
|
|
|
|
|
{}, # object header |
|
43
|
|
|
|
|
|
|
[[]], # chart data |
|
44
|
|
|
|
|
|
|
[[]], # colorimetry data |
|
45
|
|
|
|
|
|
|
[], # header lines |
|
46
|
|
|
|
|
|
|
{}, # SAMPLE_ID hash |
|
47
|
|
|
|
|
|
|
]; |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# get optional hash |
|
50
|
29
|
100
|
|
|
|
96
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# if there are additional parameters |
|
53
|
29
|
100
|
|
|
|
73
|
if (@_) { |
|
|
|
50
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# if first parameter is an array or a Math::Matrix object |
|
56
|
22
|
100
|
66
|
|
|
238
|
if (ref($_[0]) eq 'ARRAY' || UNIVERSAL::isa($_[0], 'Math::Matrix')) { |
|
|
|
50
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# copy array/matrix and optional format |
|
59
|
1
|
|
|
|
|
11
|
add_cols($self, shift(), $hash->{'format'}); |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# if first parameter is a scalar |
|
62
|
|
|
|
|
|
|
} elsif (! ref($_[0])) { |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# get path |
|
65
|
21
|
|
|
|
|
38
|
$path = shift(); |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# save path in object header |
|
68
|
21
|
|
|
|
|
49
|
$self->[0]{'file_path'} = $path; |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# get file list |
|
71
|
21
|
|
|
|
|
62
|
$files = _files($path); |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# no files |
|
74
|
21
|
50
|
|
|
|
30
|
if (@{$files} == 0) { |
|
|
21
|
100
|
|
|
|
54
|
|
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# invalid path |
|
77
|
0
|
|
|
|
|
0
|
carp($error = "no files in path: $path\n"); |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# one file |
|
80
|
21
|
|
|
|
|
44
|
} elsif (@{$files} == 1) { |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# read chart |
|
83
|
19
|
50
|
|
|
|
64
|
($result = _readChart($self, $files->[0], $hash)) && carp($error = "chart $files->[0] $result\n"); |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# add colorimetric metadata |
|
86
|
19
|
|
|
|
|
53
|
_addColorMeta($self); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# multiple files |
|
89
|
|
|
|
|
|
|
} else { |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# get folder handling |
|
92
|
2
|
|
100
|
|
|
10
|
$self->[0]{'folder_handling'} = $hash->{'folder'} // 'AVG'; |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# if folder handling undefined or 'AVG' |
|
95
|
2
|
100
|
|
|
|
9
|
if ($self->[0]{'folder_handling'} eq 'AVG') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# read average chart |
|
98
|
1
|
50
|
|
|
|
6
|
_readChartAvg($self, $files, $hash) or carp($error = "no valid charts in path: $path\n"); |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# if folder handling 'APPEND' |
|
101
|
|
|
|
|
|
|
} elsif ($self->[0]{'folder_handling'} eq 'APPEND') { |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# read appended chart |
|
104
|
1
|
50
|
|
|
|
6
|
_readChartAppend($self, $files, $hash) or carp($error = "no valid charts in path: $path\n"); |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# if folder handling 'MERGE' |
|
107
|
|
|
|
|
|
|
} elsif ($self->[0]{'folder_handling'} eq 'MERGE') { |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# read appended chart |
|
110
|
0
|
0
|
|
|
|
0
|
_readChartMerge($self, $files, $hash) or carp($error = "no valid charts in path: $path\n"); |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
} else { |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# invalid folder handling |
|
115
|
0
|
|
|
|
|
0
|
carp($error = "invalid folder handling: $self->[0]{'folder_handling'}\n"); |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
} else { |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# invalid parameter(s) |
|
124
|
0
|
|
|
|
|
0
|
carp($error = "invalid parameter(s)"); |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# make SAMPLE_ID hash |
|
129
|
22
|
|
|
|
|
102
|
_makeSampleID($self); |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# if hash defined |
|
132
|
|
|
|
|
|
|
} elsif (defined($hash)) { |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# make patch set |
|
135
|
0
|
0
|
|
|
|
0
|
($result = _makePatchSet($self, $hash)) && carp($error = "failed making patch set - $result\n"); |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# add initial_size to object header |
|
140
|
29
|
|
|
|
|
69
|
$self->[0]{'initial_size'} = [$#{$self->[1]}, $#{$self->[1][0]} + 1]; |
|
|
29
|
|
|
|
|
51
|
|
|
|
29
|
|
|
|
|
91
|
|
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# bless object |
|
143
|
29
|
|
|
|
|
106
|
bless($self, $class); |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# return |
|
146
|
29
|
50
|
|
|
|
519
|
return(wantarray() ? ($self, $error) : $self); |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# get/set reference to header hash |
|
151
|
|
|
|
|
|
|
# parameters: ([ref_to_new_hash]) |
|
152
|
|
|
|
|
|
|
# returns: (ref_to_hash) |
|
153
|
|
|
|
|
|
|
sub header { |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# get object reference |
|
156
|
2
|
|
|
2
|
1
|
1528
|
my $self = shift(); |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# if there are parameters |
|
159
|
2
|
100
|
|
|
|
6
|
if (@_) { |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# if one parameter, a hash reference |
|
162
|
1
|
50
|
33
|
|
|
8
|
if (@_ == 1 && ref($_[0]) eq 'HASH') { |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# set header to copy of hash |
|
165
|
1
|
|
|
|
|
2
|
$self->[0] = {%{shift()}}; |
|
|
1
|
|
|
|
|
5
|
|
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} else { |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# error |
|
170
|
0
|
|
|
|
|
0
|
croak('parameter must be a hash reference'); |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# return reference |
|
177
|
2
|
|
|
|
|
7
|
return($self->[0]); |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# get/set reference to data array |
|
182
|
|
|
|
|
|
|
# note: row 0 contains the DATA_FORMAT field names |
|
183
|
|
|
|
|
|
|
# note: set updates the SAMPLE_ID hash and colorimetry array |
|
184
|
|
|
|
|
|
|
# parameters: ([ref_to_new_array]) |
|
185
|
|
|
|
|
|
|
# returns: (ref_to_array) |
|
186
|
|
|
|
|
|
|
sub array { |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# get object reference |
|
189
|
2
|
|
|
2
|
1
|
3
|
my $self = shift(); |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# if there are parameters |
|
192
|
2
|
100
|
|
|
|
5
|
if (@_) { |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# if one parameter, an array reference |
|
195
|
1
|
50
|
33
|
|
|
6
|
if (@_ == 1 && ref($_[0]) eq 'ARRAY') { |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# get array reference |
|
198
|
1
|
|
|
|
|
2
|
my $array = shift(); |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# initialize data array |
|
201
|
1
|
|
|
|
|
2
|
$self->[1] = []; |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# if array is not empty |
|
204
|
1
|
50
|
|
|
|
3
|
if (@{$array}) { |
|
|
1
|
|
|
|
|
4
|
|
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# for each row |
|
207
|
1
|
|
|
|
|
2
|
for my $i (0 .. $#{$array}) { |
|
|
1
|
|
|
|
|
4
|
|
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# copy to object |
|
210
|
4
|
|
|
|
|
5
|
$self->[1][$i] = [@{$array->[$i]}]; |
|
|
4
|
|
|
|
|
9
|
|
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# make SAMPLE_ID hash |
|
215
|
1
|
|
|
|
|
4
|
_makeSampleID($self); |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# add colorimetric metadata |
|
218
|
1
|
|
|
|
|
4
|
_addColorMeta($self); |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
} else { |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# error |
|
225
|
0
|
|
|
|
|
0
|
croak('parameter must be an array reference'); |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# return reference |
|
232
|
2
|
|
|
|
|
6
|
return($self->[1]); |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# get data array size |
|
237
|
|
|
|
|
|
|
# if flag is true, initial size is returned |
|
238
|
|
|
|
|
|
|
# parameters: ([flag]) |
|
239
|
|
|
|
|
|
|
# returns: (number_rows) |
|
240
|
|
|
|
|
|
|
# returns: (number_rows, number_columns) |
|
241
|
|
|
|
|
|
|
sub size { |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# get parameters |
|
244
|
0
|
|
|
0
|
1
|
0
|
my ($self, $flag) = @_; |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# if flag is true |
|
247
|
0
|
0
|
0
|
|
|
0
|
if ($flag && defined($self->[0]{'initial_size'})) { |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# return initial size, array or scalar |
|
250
|
0
|
0
|
|
|
|
0
|
return(wantarray ? @{$self->[0]{'initial_size'}} : $self->[0]{'initial_size'}->[0]); |
|
|
0
|
|
|
|
|
0
|
|
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
} else { |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# return current size, array or scalar |
|
255
|
0
|
0
|
|
|
|
0
|
return(wantarray ? ($#{$self->[1]}, $#{$self->[1][0]} + 1) : $#{$self->[1]}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# get data matrix size |
|
262
|
|
|
|
|
|
|
# returns: (number_rows) |
|
263
|
|
|
|
|
|
|
# returns: (number_rows, number_columns) |
|
264
|
|
|
|
|
|
|
sub matrix_size { |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# get object reference |
|
267
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# get row length |
|
270
|
0
|
|
0
|
|
|
0
|
my $rows = _getRowLength($self) || $#{$self->[1]}; |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# compute columns |
|
273
|
0
|
|
|
|
|
0
|
my $cols = POSIX::ceil($#{$self->[1]}/$rows); |
|
|
0
|
|
|
|
|
0
|
|
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# return array or scalar |
|
276
|
0
|
0
|
|
|
|
0
|
wantarray ? return($rows, $cols) : return($rows); |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# get row slice from SAMPLE_ID values |
|
281
|
|
|
|
|
|
|
# id_keys is a list of scalars and/or array references |
|
282
|
|
|
|
|
|
|
# row_slice is reference to an array of row indices |
|
283
|
|
|
|
|
|
|
# note: returns undef if any key is missing |
|
284
|
|
|
|
|
|
|
# parameters: (id_keys) |
|
285
|
|
|
|
|
|
|
# returns: (row_slice) |
|
286
|
|
|
|
|
|
|
sub rows { |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# get object reference |
|
289
|
3
|
|
|
3
|
1
|
942
|
my $self = shift(); |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# local variable |
|
292
|
3
|
|
|
|
|
6
|
my (@keys, @rows); |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# flatten id key list |
|
295
|
3
|
|
|
|
|
4
|
@keys = @{ICC::Shared::flatten(@_)}; |
|
|
3
|
|
|
|
|
9
|
|
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# get row list using SAMPLE_ID hash |
|
298
|
3
|
|
|
|
|
6
|
@rows = @{$self->[4]}{@keys}; |
|
|
3
|
|
|
|
|
9
|
|
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# return row slice or undef if any rows are missing |
|
301
|
3
|
100
|
|
|
|
6
|
return((grep {! defined()} @rows) ? undef : \@rows); |
|
|
12
|
|
|
|
|
30
|
|
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# get column slice from DATA_FORMAT keys |
|
306
|
|
|
|
|
|
|
# format_keys is a list of scalars and/or array references |
|
307
|
|
|
|
|
|
|
# column_slice is reference to an array of column indices |
|
308
|
|
|
|
|
|
|
# note: tries to match ignoring context if exact match fails |
|
309
|
|
|
|
|
|
|
# note: returns 'undef' if any column is missing |
|
310
|
|
|
|
|
|
|
# parameters: (format_keys) |
|
311
|
|
|
|
|
|
|
# returns: (column_slice) |
|
312
|
|
|
|
|
|
|
sub cols { |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# get object reference |
|
315
|
305
|
|
|
305
|
1
|
396
|
my $self = shift(); |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# local variables |
|
318
|
305
|
|
|
|
|
376
|
my (@keys, %fmt, @cols); |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# flatten format key list |
|
321
|
305
|
|
|
|
|
373
|
@keys = @{ICC::Shared::flatten(@_)}; |
|
|
305
|
|
|
|
|
633
|
|
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# make lookup hash |
|
324
|
305
|
50
|
|
|
|
513
|
%fmt = map {defined($self->[1][0][$_]) ? ($self->[1][0][$_], $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
8930
|
|
|
|
|
15125
|
|
|
|
305
|
|
|
|
|
657
|
|
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# lookup format keys in hash |
|
327
|
305
|
|
|
|
|
1062
|
@cols = @fmt{@keys}; |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# if any columns undefined |
|
330
|
305
|
100
|
|
|
|
395
|
if (grep {! defined()} @cols) { |
|
|
1105
|
|
|
|
|
1683
|
|
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# make lookup hash without context prefixes |
|
333
|
206
|
50
|
33
|
|
|
264
|
%fmt = map {(defined($self->[1][0][$_]) && $self->[1][0][$_] =~ m/^(.*?)\|?([^\|\n]*)$/) ? ($2, $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
6276
|
|
|
|
|
54247
|
|
|
|
206
|
|
|
|
|
371
|
|
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# lookup format keys in hash |
|
336
|
206
|
|
|
|
|
875
|
@cols = @fmt{@keys}; |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# return column slice or undef if any columns undefined |
|
341
|
305
|
100
|
|
|
|
394
|
return((grep {! defined()} @cols) ? undef : \@cols); |
|
|
1105
|
|
|
|
|
2386
|
|
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
} |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# get DATA_FORMAT keys from column slice |
|
346
|
|
|
|
|
|
|
# column_slice is a list of scalars and/or array references |
|
347
|
|
|
|
|
|
|
# format_keys is an array reference |
|
348
|
|
|
|
|
|
|
# parameters: ([column_slice]) |
|
349
|
|
|
|
|
|
|
# returns: (format_keys) |
|
350
|
|
|
|
|
|
|
sub fmt_keys { |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# get object reference |
|
353
|
6
|
|
|
6
|
1
|
14
|
my $self = shift(); |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# if no parameter -or- column slice an empty array reference ([]) |
|
356
|
6
|
100
|
33
|
|
|
30
|
if (@_ == 0 || (@_ == 1 && ref($_[0]) eq 'ARRAY' && @{$_[0]} == 0)) { |
|
|
0
|
|
33
|
|
|
0
|
|
|
|
|
|
66
|
|
|
|
|
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# return all format keys |
|
359
|
1
|
|
|
|
|
2
|
return([@{$self->[1][0]}]); |
|
|
1
|
|
|
|
|
9
|
|
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
} else { |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# return format keys slice |
|
364
|
5
|
|
|
|
|
6
|
return([@{$self->[1][0]}[@{ICC::Shared::flatten(@_)}]]); |
|
|
5
|
|
|
|
|
38
|
|
|
|
5
|
|
|
|
|
12
|
|
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
} |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# get/set context |
|
371
|
|
|
|
|
|
|
# 'undef' indicates no context (get or set) |
|
372
|
|
|
|
|
|
|
# returned context may be a scalar or an array |
|
373
|
|
|
|
|
|
|
# parameter: (column_slice) => returns: (context) |
|
374
|
|
|
|
|
|
|
# parameters: (column_slice, context) => returns: (modified_keys) |
|
375
|
|
|
|
|
|
|
sub context { |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# get object reference |
|
378
|
7
|
|
|
7
|
1
|
918
|
my $self = shift(); |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# local variables |
|
381
|
7
|
|
|
|
|
12
|
my ($cols, $context, @cx); |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# return if no parameters supplied |
|
384
|
7
|
50
|
|
|
|
16
|
return(undef) if (@_ == 0); |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# get column slice |
|
387
|
7
|
|
|
|
|
17
|
$cols = ICC::Shared::flatten(shift()); |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# use all columns if slice is empty |
|
390
|
7
|
50
|
|
|
|
9
|
$cols = [0 .. $#{$self->[1][0]}] if (@{$cols} == 0); |
|
|
0
|
|
|
|
|
0
|
|
|
|
7
|
|
|
|
|
15
|
|
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
# if no context parameter |
|
393
|
7
|
100
|
|
|
|
19
|
if (@_ == 0) { |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
# match contexts |
|
396
|
4
|
100
|
|
|
|
5
|
@cx = map {$self->[1][0][$_] =~ m/^(.*)\|/ ? $1 : undef} @{$cols}; |
|
|
16
|
|
|
|
|
55
|
|
|
|
4
|
|
|
|
|
8
|
|
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# return array if wanted |
|
399
|
4
|
100
|
|
|
|
24
|
return(@cx) if (wantarray); |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# warn if columns have different contexts |
|
402
|
2
|
100
|
66
|
|
|
5
|
(@cx == grep {(! defined($cx[0]) && ! defined($_)) || ($cx[0] eq $_)} @cx) || warn('columns have different contexts'); |
|
|
8
|
50
|
|
|
|
30
|
|
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# return context of first column |
|
405
|
2
|
|
|
|
|
11
|
return($cx[0]); |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
} else { |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# get context |
|
410
|
3
|
|
|
|
|
5
|
$context = shift(); |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# for each column |
|
413
|
3
|
|
|
|
|
6
|
for my $i (0 .. $#{$cols}) { |
|
|
3
|
|
|
|
|
8
|
|
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# if context is defined |
|
416
|
12
|
100
|
|
|
|
20
|
if (defined($context)) { |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
# replace current context |
|
419
|
8
|
|
|
|
|
43
|
$self->[1][0][$cols->[$i]] =~ s/^(?:.*\|)?(.*)$/$context\|$1/; |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# if context is 'undef' |
|
422
|
|
|
|
|
|
|
} else { |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# remove current context |
|
425
|
4
|
|
|
|
|
16
|
$self->[1][0][$cols->[$i]] =~ s/^.*\|//; |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# return modified keys |
|
432
|
3
|
|
|
|
|
4
|
return([@{$self->[1][0]}[@{$cols}]]); |
|
|
3
|
|
|
|
|
11
|
|
|
|
3
|
|
|
|
|
6
|
|
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
} |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# test for a specified data class |
|
439
|
|
|
|
|
|
|
# string format is '[context][|][class]' |
|
440
|
|
|
|
|
|
|
# 'class' - match class, any context |
|
441
|
|
|
|
|
|
|
# '|class' - match class, no context |
|
442
|
|
|
|
|
|
|
# 'context|class' - match context and class |
|
443
|
|
|
|
|
|
|
# 'context|' - match context, any class |
|
444
|
|
|
|
|
|
|
# returns list of matched indices or count |
|
445
|
|
|
|
|
|
|
# parameters: (string) |
|
446
|
|
|
|
|
|
|
# returns: (list -or- count) |
|
447
|
|
|
|
|
|
|
sub test { |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
# get parameters |
|
450
|
255
|
|
|
255
|
1
|
745
|
my ($self, $string) = @_; |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# local variables |
|
453
|
255
|
|
|
|
|
285
|
my (@w, $class, @fields); |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# hash of compiled regex |
|
456
|
255
|
|
|
|
|
310
|
state $regex = { |
|
457
|
|
|
|
|
|
|
'RGB' => qr/^(?:(.*)\|)?RGB_[RGB]$/, |
|
458
|
|
|
|
|
|
|
'CMYK' => qr/^(?:(.*)\|)?CMYK_[CMYK]$/, |
|
459
|
|
|
|
|
|
|
'XYZ' => qr/^(?:(.*)\|)?XYZ_[XYZ]$/, |
|
460
|
|
|
|
|
|
|
'XYY' => qr/^(?:(.*)\|)?XYY_(?:X|Y|CAPY)$/, |
|
461
|
|
|
|
|
|
|
'LAB' => qr/^(?:(.*)\|)?LAB_[LAB]$/, |
|
462
|
|
|
|
|
|
|
'LCH' => qr/^(?:(.*)\|)?LAB_[LCH]$/, |
|
463
|
|
|
|
|
|
|
'NCLR' => qr/^(?:(.*)\|)?(?:[2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/, |
|
464
|
|
|
|
|
|
|
'SPECTRAL' => qr/^(?:(.*)\|)?(?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)\d{3}$/, |
|
465
|
|
|
|
|
|
|
'SPOT' => qr/^(?:(.*)\|)?SPOT_\d+$/, |
|
466
|
|
|
|
|
|
|
'DENSITY' => qr/^(?:(.*)\|)?D_(?:RED|GREEN|BLUE|VIS)$/, |
|
467
|
|
|
|
|
|
|
'REFL' => qr/^(?:(.*)\|)?R_(?:RED|GREEN|BLUE|VIS)$/, |
|
468
|
|
|
|
|
|
|
'STDEVXYZ' => qr/^(?:(.*)\|)?STDEV_[XYZ]$/, |
|
469
|
|
|
|
|
|
|
'STDEVLAB' => qr/^(?:(.*)\|)?STDEV_[LAB]$/, |
|
470
|
|
|
|
|
|
|
'MEAN_DE' => qr/^(?:(.*)\|)?MEAN_DE$/, |
|
471
|
|
|
|
|
|
|
'ID' => qr/^(?:(.*)\|)?(?:SAMPLE_ID|SampleID)$/, |
|
472
|
|
|
|
|
|
|
'NAME' => qr/^(?:(.*)\|)?SAMPLE_NAME$/, |
|
473
|
|
|
|
|
|
|
'DEVICE' => qr/^(?:(.*)\|)?(?:RGB_[RGB]|CMYK_[CMYK]|[2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/, |
|
474
|
|
|
|
|
|
|
'ANY' => qr/^(?:(.*)\|)?/, |
|
475
|
|
|
|
|
|
|
}; |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# verify string parameter |
|
478
|
255
|
50
|
|
|
|
373
|
(! ref($string)) or croak('invalid string parameter'); |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# return, if null string |
|
481
|
255
|
0
|
33
|
|
|
648
|
return(wantarray() ? () : 0) if (! defined($string) || $string eq ''); |
|
|
|
50
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# split string on '|' character (string is '[context]|[class]') |
|
484
|
255
|
|
|
|
|
439
|
@w = split(/\|/, $string); |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
# set empty context, if array is empty (string is '|') |
|
487
|
255
|
50
|
|
|
|
391
|
@w = ('') if (! @w); |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
# add 'ANY' class, if string ends in '|' (string is '|' or 'context|') |
|
490
|
255
|
50
|
|
|
|
415
|
push(@w, 'ANY') if (substr($string, -1, 1) eq '|'); |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
# make class uppercase |
|
493
|
255
|
|
|
|
|
361
|
$class = uc($w[-1]); |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# verify class |
|
496
|
255
|
50
|
33
|
|
|
691
|
(! ref($class) && exists($regex->{$class})) or croak('invalid data class'); |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# if no '|' character |
|
499
|
255
|
100
|
|
|
|
409
|
if (@w == 1) { |
|
|
|
50
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# match format fields (any context) |
|
502
|
120
|
|
|
|
|
132
|
@fields = grep {$self->[1][0][$_] =~ /$regex->{$class}/} (0 .. $#{$self->[1][0]}); |
|
|
4005
|
|
|
|
|
10250
|
|
|
|
120
|
|
|
|
|
240
|
|
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# if single '|' character |
|
505
|
|
|
|
|
|
|
} elsif (@w == 2) { |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
# if empty context |
|
508
|
135
|
50
|
|
|
|
201
|
if ($w[0] eq '') { |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# match format fields (no context) |
|
511
|
0
|
0
|
|
|
|
0
|
@fields = grep {$self->[1][0][$_] =~ /$regex->{$class}/ && ! defined($1)} (0 .. $#{$self->[1][0]}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
} else { |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# match format fields (matching context and class) |
|
516
|
135
|
100
|
100
|
|
|
148
|
@fields = grep {$self->[1][0][$_] =~ /$regex->{$class}/ && defined($1) && ($1 eq $w[0])} (0 .. $#{$self->[1][0]}); |
|
|
4020
|
|
|
|
|
14524
|
|
|
|
135
|
|
|
|
|
258
|
|
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
} else { |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# error |
|
523
|
0
|
|
|
|
|
0
|
croak('data class contains multiple \'|\' characters'); |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# return (list -or- count) |
|
528
|
255
|
50
|
|
|
|
927
|
return(wantarray() ? @fields : scalar(@fields)); |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
# get/set keyword value(s) |
|
533
|
|
|
|
|
|
|
# CGATS ASCII file header lines are stored as an array in the object header |
|
534
|
|
|
|
|
|
|
# most lines contain a keyword followed by a value, which this methods gets/sets |
|
535
|
|
|
|
|
|
|
# a keyword may be used more than once, so the value parameter is an array |
|
536
|
|
|
|
|
|
|
# if the keyword doesn't exist, a new line is added when setting its value |
|
537
|
|
|
|
|
|
|
# if the keyword is enclosed by angle brackets, existing lines are removed |
|
538
|
|
|
|
|
|
|
# parameters: () => returns: (file_header_array_reference) |
|
539
|
|
|
|
|
|
|
# parameters: (keyword) => returns: (value_array) |
|
540
|
|
|
|
|
|
|
# parameters: (keyword, value_array) => returns: (original_value_array) |
|
541
|
|
|
|
|
|
|
sub keyword { |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# get parameters |
|
544
|
66
|
|
|
66
|
1
|
109
|
my ($self, $key, @values) = @_; |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# local variables |
|
547
|
66
|
|
|
|
|
88
|
my ($del, @ix, @current); |
|
548
|
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
# if no keyword, return file header array reference |
|
550
|
66
|
50
|
|
|
|
102
|
(defined($key)) || return($self->[3]); |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
# set delete flag, stripping angle brackets (if any) |
|
553
|
66
|
|
|
|
|
110
|
$del = ($key =~ s/^<(.*)>$/$1/); |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# get indices of existing keyword (if any) |
|
556
|
66
|
|
|
|
|
81
|
@ix = grep {$self->[3][$_][0] eq $key} (0 .. $#{$self->[3]}); |
|
|
734
|
|
|
|
|
1014
|
|
|
|
66
|
|
|
|
|
118
|
|
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
# get current values array (if any) |
|
559
|
66
|
|
|
|
|
105
|
@current = map {$self->[3][$_][1]} @ix; |
|
|
26
|
|
|
|
|
65
|
|
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# if delete flag set |
|
562
|
66
|
50
|
|
|
|
102
|
if ($del) { |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# while indices |
|
565
|
0
|
|
|
|
|
0
|
while (@ix) { |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# delete array element |
|
568
|
0
|
|
|
|
|
0
|
splice(@{$self->[3]}, pop(@ix), 1); |
|
|
0
|
|
|
|
|
0
|
|
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
# disable replacement if keyword is 'KEYWORD' |
|
575
|
66
|
50
|
|
|
|
96
|
@ix = () if ($key eq 'KEYWORD'); |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
# if there are supplied values |
|
578
|
66
|
50
|
|
|
|
105
|
if (@values) { |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
# for each value |
|
581
|
0
|
|
|
|
|
0
|
for (@values) { |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# if not a number or already quoted |
|
584
|
0
|
0
|
|
|
|
0
|
if (! m/^([\d.-]+|".*")$/) { |
|
585
|
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# remove any quotes |
|
587
|
0
|
|
|
|
|
0
|
s/"//g; |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
# enclose in quotes |
|
590
|
0
|
|
|
|
|
0
|
$_ = "\"$_\""; |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
} |
|
593
|
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
} |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
# while indices and values |
|
597
|
0
|
|
0
|
|
|
0
|
while (@ix && @values) { |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
# replace keyword/value entry |
|
600
|
0
|
|
|
|
|
0
|
$self->[3][shift(@ix)] = [$key, shift(@values)]; |
|
601
|
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
# for each remaining value (if any) |
|
605
|
0
|
|
|
|
|
0
|
for (@values) { |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# add keyword/value entry |
|
608
|
0
|
|
|
|
|
0
|
push(@{$self->[3]}, [$key, $_]); |
|
|
0
|
|
|
|
|
0
|
|
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
} |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
} |
|
613
|
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# return current values array, or scalar |
|
615
|
66
|
100
|
|
|
|
217
|
return(wantarray ? @current : $current[0]); |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
# get/set CREATED value |
|
620
|
|
|
|
|
|
|
# adds CREATED keyword when setting, if none |
|
621
|
|
|
|
|
|
|
# parameters: () # gets date/time from CREATED value |
|
622
|
|
|
|
|
|
|
# parameters: (string) # sets/adds CREATED keyword/value |
|
623
|
|
|
|
|
|
|
# parameters: (Time::Piece_object) # sets/adds CREATED keyword/value |
|
624
|
|
|
|
|
|
|
# returns: (Time::Piece_object) # default is localtime |
|
625
|
|
|
|
|
|
|
sub created { |
|
626
|
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
# get parameters |
|
628
|
0
|
|
|
0
|
1
|
0
|
my ($self, $t) = @_; |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
# local variables |
|
631
|
0
|
|
|
|
|
0
|
my (@ix, $datetime); |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# get indices of existing CREATED lines (if any) |
|
634
|
0
|
|
|
|
|
0
|
@ix = grep {$self->[3][$_][0] eq 'CREATED'} (0 .. $#{$self->[3]}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
# print warning if more than one CREATED line |
|
637
|
0
|
0
|
|
|
|
0
|
print "warning: more than one CREATED keyword\n" if (@ix > 1); |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
# if date/time parameter given |
|
640
|
0
|
0
|
|
|
|
0
|
if (defined($t)) { |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# make Time::Piece object if reference is a scalar |
|
643
|
0
|
0
|
|
|
|
0
|
$t = _makeTimePiece($t) if (! ref($t)); |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
# if not a Time::Piece object |
|
646
|
0
|
0
|
|
|
|
0
|
if (ref($t) ne 'Time::Piece') { |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
# print warning |
|
649
|
0
|
|
|
|
|
0
|
print "warning: invalid date/time parameter, using localtime instead\n"; |
|
650
|
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# use local time |
|
652
|
0
|
|
|
|
|
0
|
$t = localtime(); |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
} |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
# make ISO 8601 datetime string from Time::Piece object |
|
657
|
0
|
|
|
|
|
0
|
$datetime = sprintf("%s%+03d:00", $t->datetime, $t->tzoffset->hours); |
|
658
|
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
# if CREATED lines |
|
660
|
0
|
0
|
|
|
|
0
|
if (@ix) { |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# replace value in first CREATED line |
|
663
|
0
|
|
|
|
|
0
|
$self->[3][$ix[0]][1] = "\"$datetime\""; |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
} else { |
|
666
|
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
# if keyword lines exist |
|
668
|
0
|
0
|
|
|
|
0
|
if (@{$self->[3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
# insert CREATED line (as second line) |
|
671
|
0
|
|
|
|
|
0
|
splice(@{$self->[3]}, 1, 0, ['CREATED', "\"$datetime\""]); |
|
|
0
|
|
|
|
|
0
|
|
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
} else { |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
# add CREATED line |
|
676
|
0
|
|
|
|
|
0
|
$self->[3][0] = ['CREATED', "\"$datetime\""]; |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
} |
|
679
|
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
# no parameter |
|
683
|
|
|
|
|
|
|
} else { |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
# if CREATED lines |
|
686
|
0
|
0
|
|
|
|
0
|
if (@ix) { |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
# make Time::Piece object from first CREATED value |
|
689
|
0
|
|
|
|
|
0
|
$t = _makeTimePiece($self->[3][$ix[0]][1]); |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
} else { |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
# print warning |
|
694
|
0
|
|
|
|
|
0
|
print "warning: no CREATED keyword, returning localtime instead\n"; |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
# use local time |
|
697
|
0
|
|
|
|
|
0
|
$t = localtime(); |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
} |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
} |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# return Time::Piece object |
|
704
|
0
|
|
|
|
|
0
|
return($t); |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
} |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
# get/set data array slice |
|
709
|
|
|
|
|
|
|
# row_slice and column_slice may be either a scalar or array reference |
|
710
|
|
|
|
|
|
|
# replacement_data is reference to a 2-D array of replacement values |
|
711
|
|
|
|
|
|
|
# replacement data dimensions must match size of row_slice and column_slice |
|
712
|
|
|
|
|
|
|
# data_slice is reference to a 2-D array, selected by row_slice and column_slice |
|
713
|
|
|
|
|
|
|
# parameters: ([row_slice, [column_slice, [replacement_data]]]) |
|
714
|
|
|
|
|
|
|
# return: (data_slice) |
|
715
|
|
|
|
|
|
|
sub slice { |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
# get parameters |
|
718
|
5
|
|
|
5
|
1
|
18368
|
my ($self, $rows, $cols, $data) = @_; |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
# select all rows if row slice undefined |
|
721
|
5
|
100
|
|
|
|
15
|
$rows = [] if (! defined($rows)); |
|
722
|
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
# select all fields if column slice undefined |
|
724
|
5
|
100
|
|
|
|
10
|
$cols = [] if (! defined($cols)); |
|
725
|
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
# call get/set subroutine |
|
727
|
5
|
|
|
|
|
12
|
_getset($self, 1, $rows, $cols, $data); |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
} |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
# get/set colorimetry array slice |
|
732
|
|
|
|
|
|
|
# row_slice and column_slice may be either a scalar or array reference |
|
733
|
|
|
|
|
|
|
# replacement_data is reference to a 2-D array of replacement values |
|
734
|
|
|
|
|
|
|
# replacement data dimensions must match size of row_slice and column_slice |
|
735
|
|
|
|
|
|
|
# data_slice is reference to a 2-D array, selected by row_slice and column_slice |
|
736
|
|
|
|
|
|
|
# parameters: ([row_slice, [column_slice, [replacement_data]]]) |
|
737
|
|
|
|
|
|
|
# return: (data_slice) |
|
738
|
|
|
|
|
|
|
sub colorimetry { |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# get parameters |
|
741
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rows, $cols, $data) = @_; |
|
742
|
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
# flatten row slice |
|
744
|
0
|
0
|
|
|
|
0
|
$rows = defined($rows) ? ICC::Shared::flatten($rows) : []; |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
# select all rows if row slice empty |
|
747
|
0
|
0
|
|
|
|
0
|
$rows = [0 .. $#{$self->[2]}] if (@{$rows} == 0); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
748
|
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
# flatten column slice |
|
750
|
0
|
0
|
|
|
|
0
|
$cols = defined($cols) ? ICC::Shared::flatten($cols) : []; |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
# select all fields if column slice empty |
|
753
|
0
|
0
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}] if (@{$cols} == 0); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
# call get/set subroutine |
|
756
|
0
|
|
|
|
|
0
|
_getset($self, 2, $rows, $cols, $data); |
|
757
|
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
} |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
# get/set SAMPLE_ID data |
|
761
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
762
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
763
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
764
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
765
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
766
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
767
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
768
|
|
|
|
|
|
|
sub id { |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
# local variables |
|
771
|
23
|
|
|
23
|
1
|
40683
|
my ($hash, %fmt, $cols); |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# get optional hash |
|
774
|
23
|
100
|
|
|
|
72
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# get remaining parameters |
|
777
|
23
|
|
|
|
|
43
|
my ($self, $rows, $data) = @_; |
|
778
|
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
# make lookup hash (context| -or- '||' => column) |
|
780
|
23
|
50
|
|
|
|
33
|
%fmt = map {($self->[1][0][$_] =~ m/^(.*\|)?(?:SAMPLE_ID|SampleID|ID)$/) ? (defined($1) ? $1 : '||', $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
607
|
100
|
|
|
|
1366
|
|
|
|
23
|
|
|
|
|
65
|
|
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
# if context defined |
|
783
|
23
|
100
|
|
|
|
62
|
if (defined($hash->{'context'})) { |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
# get id column with context |
|
786
|
9
|
|
|
|
|
22
|
$cols = $fmt{"$hash->{'context'}|"}; |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
} else { |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# get id column without context |
|
791
|
14
|
|
|
|
|
20
|
$cols = $fmt{'||'}; |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
# if id column undefined |
|
794
|
14
|
100
|
|
|
|
34
|
if (! defined($cols)) { |
|
795
|
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
# make lookup hash ignoring context ('||' => column) |
|
797
|
4
|
50
|
|
|
|
5
|
%fmt = map {($self->[1][0][$_] =~ m/^(?:.*\|)?(?:SAMPLE_ID|SampleID|ID)$/) ? ('||', $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
128
|
|
|
|
|
263
|
|
|
|
4
|
|
|
|
|
10
|
|
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
# get id column |
|
800
|
4
|
|
|
|
|
8
|
$cols = $fmt{'||'}; |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
} |
|
803
|
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
} |
|
805
|
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
# call get/set subroutine |
|
807
|
23
|
|
|
|
|
61
|
_getset($self, 1, $rows, $cols, $data); |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
} |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
# get/set SAMPLE_NAME data |
|
812
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
813
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
814
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
815
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
816
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
817
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
818
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
819
|
|
|
|
|
|
|
sub name { |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
# local variables |
|
822
|
23
|
|
|
23
|
1
|
3975
|
my ($hash, $cols); |
|
823
|
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
# get optional hash |
|
825
|
23
|
100
|
|
|
|
54
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
# get remaining parameters |
|
828
|
23
|
|
|
|
|
31
|
my ($self, $rows, $data) = @_; |
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
831
|
23
|
100
|
|
|
|
74
|
$cols = cols($self, defined($hash->{'context'}) ? "$hash->{'context'}|SAMPLE_NAME" : 'SAMPLE_NAME'); |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
# call get/set subroutine |
|
834
|
23
|
|
|
|
|
54
|
_getset($self, 1, $rows, $cols, $data); |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
} |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
# get/set RGB data |
|
839
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
840
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
841
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
842
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
843
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
844
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
845
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
846
|
|
|
|
|
|
|
sub rgb { |
|
847
|
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
# local variables |
|
849
|
67
|
|
|
67
|
1
|
9475
|
my ($hash, $cols); |
|
850
|
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
# get optional hash |
|
852
|
67
|
100
|
|
|
|
131
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
# get remaining parameters |
|
855
|
67
|
|
|
|
|
127
|
my ($self, $rows, $data) = @_; |
|
856
|
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
858
|
67
|
100
|
|
|
|
94
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(RGB_R RGB_G RGB_B)); |
|
|
201
|
|
|
|
|
430
|
|
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
# call get/set subroutine |
|
861
|
67
|
|
|
|
|
153
|
_getset($self, 1, $rows, $cols, $data); |
|
862
|
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
# get/set CMYK data |
|
866
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
867
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
868
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
869
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
870
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
871
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
872
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
873
|
|
|
|
|
|
|
sub cmyk { |
|
874
|
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
# local variables |
|
876
|
67
|
|
|
67
|
1
|
28730
|
my ($hash, $cols); |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
# get optional hash |
|
879
|
67
|
100
|
|
|
|
149
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
880
|
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
# get remaining parameters |
|
882
|
67
|
|
|
|
|
97
|
my ($self, $rows, $data) = @_; |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
885
|
67
|
100
|
|
|
|
92
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(CMYK_C CMYK_M CMYK_Y CMYK_K)); |
|
|
268
|
|
|
|
|
521
|
|
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
# call get/set subroutine |
|
888
|
67
|
|
|
|
|
141
|
_getset($self, 1, $rows, $cols, $data); |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
} |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
# get/set 6CLR data |
|
893
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
894
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
895
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
896
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
897
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
898
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
899
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
900
|
|
|
|
|
|
|
sub hex { |
|
901
|
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
# local variables |
|
903
|
33
|
|
|
33
|
1
|
20630
|
my ($hash, $cols); |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
# get optional hash |
|
906
|
33
|
100
|
|
|
|
87
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
# get remaining parameters |
|
909
|
33
|
|
|
|
|
54
|
my ($self, $rows, $data) = @_; |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
912
|
33
|
100
|
|
|
|
57
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|6CLR_$_" : "6CLR_$_"} (1 .. 6)); # X-Rite notation |
|
|
198
|
|
|
|
|
442
|
|
|
913
|
33
|
100
|
66
|
|
|
96
|
$cols = $cols // cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|PC6_$_" : "PC6_$_"} (1 .. 6)); # Ekso notation |
|
|
84
|
|
|
|
|
180
|
|
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
# call get/set subroutine |
|
916
|
33
|
|
|
|
|
80
|
_getset($self, 1, $rows, $cols, $data); |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
} |
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
# get/set nCLR data |
|
921
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
922
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
923
|
|
|
|
|
|
|
# data_slice and replacement_data are 2-D array references |
|
924
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
925
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
926
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
927
|
|
|
|
|
|
|
sub nCLR { |
|
928
|
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
# local variables |
|
930
|
38
|
|
|
38
|
1
|
9205
|
my ($hash, $context, %fmt, %fmt2, $chan, @cols); |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
# get optional hash |
|
933
|
38
|
100
|
|
|
|
90
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
934
|
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
# get remaining parameters |
|
936
|
38
|
|
|
|
|
63
|
my ($self, $rows, $data) = @_; |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
# get the context |
|
939
|
38
|
|
|
|
|
67
|
$context = $hash->{'context'}; |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
# make lookup hash (key => column) |
|
942
|
38
|
100
|
|
|
|
94
|
%fmt = map {($self->[1][0][$_] =~ m/^(?:.*\|)?([2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/) ? ($self->[1][0][$_], $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
1333
|
|
|
|
|
3031
|
|
|
|
38
|
|
|
|
|
83
|
|
|
943
|
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
# make lookup hash (prefix -or- '||' => last key) |
|
945
|
38
|
100
|
|
|
|
84
|
%fmt2 = map {($self->[1][0][$_] =~ m/^(.*\|)?([2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/) ? (defined($1) ? ($1, $2) : ('||', $2)) : ()} (0 .. $#{$self->[1][0]}); |
|
|
1333
|
100
|
|
|
|
3032
|
|
|
|
38
|
|
|
|
|
73
|
|
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
# if context defined |
|
948
|
38
|
100
|
|
|
|
99
|
if (defined($context)) { |
|
949
|
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
# get the last key for this context |
|
951
|
21
|
100
|
|
|
|
92
|
($chan = $fmt2{"$context|"}) || return(); |
|
952
|
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
# remove the channel number |
|
954
|
7
|
|
|
|
|
12
|
chop($chan); |
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
# get column slice (selected from %fmt columns) |
|
957
|
7
|
|
|
|
|
16
|
@cols = grep {$self->[1][0][$_] =~ m/^$context\|$chan[1-9A-F]$/} values(%fmt); |
|
|
42
|
|
|
|
|
167
|
|
|
958
|
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
} else { |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
# if all keys have a context |
|
962
|
17
|
100
|
|
|
|
34
|
if (! defined($chan = $fmt2{'||'})) { |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
# make lookup hash ignoring context (key => column) |
|
965
|
8
|
100
|
|
|
|
12
|
%fmt = map {($self->[1][0][$_] =~ m/^(?:.*\|)?([2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/) ? ($1, $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
265
|
|
|
|
|
595
|
|
|
|
8
|
|
|
|
|
15
|
|
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
# make lookup hash ('||' => last key) |
|
968
|
8
|
100
|
|
|
|
14
|
%fmt2 = map {($self->[1][0][$_] =~ m/^(?:.*\|)?([2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/) ? ('||', $1) : ()} (0 .. $#{$self->[1][0]}); |
|
|
265
|
|
|
|
|
580
|
|
|
|
8
|
|
|
|
|
18
|
|
|
969
|
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
# get last key for any context |
|
971
|
8
|
100
|
|
|
|
33
|
($chan = $fmt2{'||'}) || return(); |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# remove the channel number |
|
974
|
2
|
|
|
|
|
4
|
chop($chan); |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
# get column slice (selected from %fmt columns) |
|
977
|
2
|
|
|
|
|
5
|
@cols = grep {$self->[1][0][$_] =~ m/^(?:.*\|)?$chan[1-9A-F]$/} values(%fmt); |
|
|
12
|
|
|
|
|
83
|
|
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
} else { |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
# remove the channel number |
|
982
|
9
|
|
|
|
|
15
|
chop($chan); |
|
983
|
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
# get column slice (selected from %fmt columns) |
|
985
|
9
|
|
|
|
|
20
|
@cols = grep {$self->[1][0][$_] =~ m/^$chan[1-9A-F]$/} values(%fmt); |
|
|
54
|
|
|
|
|
267
|
|
|
986
|
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
} |
|
988
|
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
# sort by color channel (1-9, A-F) |
|
992
|
18
|
|
|
|
|
58
|
@cols = sort {substr($self->[1][0][$a], -1) cmp substr($self->[1][0][$b], -1)} @cols; |
|
|
178
|
|
|
|
|
296
|
|
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
# match last format key |
|
995
|
18
|
|
|
|
|
78
|
$self->[1][0][$cols[-1]] =~ m/([2-9A-F])(?:CLR_|_)([1-9A-F])$/; |
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
# verify number of format keys |
|
998
|
18
|
50
|
33
|
|
|
111
|
(CORE::hex($1) == @cols && CORE::hex($2) == @cols) or croak('wrong number of nCLR keys'); |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# call get/set subroutine |
|
1001
|
18
|
|
|
|
|
54
|
_getset($self, 1, $rows, \@cols, $data); |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
} |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
# get/set spot color data |
|
1006
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1007
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1008
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1009
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1010
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1011
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1012
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1013
|
|
|
|
|
|
|
sub spot { |
|
1014
|
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
# local variables |
|
1016
|
6
|
|
|
6
|
1
|
10
|
my ($hash, $context, @cols); |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
# get optional hash |
|
1019
|
6
|
50
|
|
|
|
16
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1020
|
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
# get remaining parameters |
|
1022
|
6
|
|
|
|
|
14
|
my ($self, $rows, $data) = @_; |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
# if context defined |
|
1025
|
6
|
50
|
|
|
|
14
|
if (defined($context = $hash->{'context'})) { |
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
# select spot color columns with specified context |
|
1028
|
6
|
|
|
|
|
8
|
@cols = grep {$self->[1][0][$_] =~ m/^$context\|SPOT_[1-9A-F]$/} (0 .. $#{$self->[1][0]}); |
|
|
152
|
|
|
|
|
362
|
|
|
|
6
|
|
|
|
|
13
|
|
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
} else { |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
# if any spot colors, regardless of context |
|
1033
|
0
|
0
|
|
|
|
0
|
if (@cols = grep {$self->[1][0][$_] =~ m/SPOT_[1-9A-F]$/} (0 .. $#{$self->[1][0]})) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1034
|
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
# match context of last column |
|
1036
|
0
|
|
|
|
|
0
|
$self->[1][0][$cols[-1]] =~ m/^(.*\|)/; |
|
1037
|
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
# select columns with last context (could be none) |
|
1039
|
0
|
0
|
|
|
|
0
|
@cols = grep {defined($1) ? $self->[1][0][$_] =~ m/^$1/ : $self->[1][0][$_] !~ m/\|/} @cols; |
|
|
0
|
|
|
|
|
0
|
|
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
} |
|
1042
|
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# sort by format |
|
1046
|
6
|
|
|
|
|
17
|
@cols = sort {$self->[1][0][$a] cmp $self->[1][0][$b]} @cols; |
|
|
0
|
|
|
|
|
0
|
|
|
1047
|
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
# call get/set subroutine |
|
1049
|
6
|
50
|
|
|
|
18
|
_getset($self, 1, $rows, @cols ? \@cols : undef, $data); |
|
1050
|
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
} |
|
1052
|
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
# get/set device data |
|
1054
|
|
|
|
|
|
|
# device data is either RGB, CMYK or nCLR |
|
1055
|
|
|
|
|
|
|
# device values have range (0 - 1) |
|
1056
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1057
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1058
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1059
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1060
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1061
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1062
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1063
|
|
|
|
|
|
|
sub device { |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
# local variables |
|
1066
|
36
|
|
|
36
|
1
|
21722
|
my ($hash, $cols, $mult); |
|
1067
|
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
# get optional hash |
|
1069
|
36
|
100
|
|
|
|
91
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
# get remaining parameters |
|
1072
|
36
|
|
|
|
|
55
|
my ($self, $rows, $data) = @_; |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
# get column slice or return empty |
|
1075
|
36
|
|
100
|
|
|
65
|
$cols = rgb($self, $hash) || cmyk($self, $hash) || nCLR($self, $hash) || spot($self, $hash) || return(); |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
# set multiplier (255 if RGB, else 100) |
|
1078
|
30
|
100
|
|
|
|
121
|
$mult = ($self->[1][0][$cols->[0]] =~ m/RGB_R$/) ? 255 : 100; |
|
1079
|
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
# call get/set subroutine |
|
1081
|
30
|
50
|
|
18
|
|
148
|
_getset($self, 1, $rows, $cols, $data, sub {map {defined($_) ? $_/$mult : $_} @_}, sub {map {defined($_) ? $_ * $mult : $_} @_}); |
|
|
78
|
50
|
|
|
|
89
|
|
|
|
338
|
|
|
|
|
569
|
|
|
|
18
|
|
|
|
|
24
|
|
|
|
78
|
|
|
|
|
118
|
|
|
1082
|
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
} |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
# get/set CTV data |
|
1086
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1087
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1088
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1089
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1090
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1091
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1092
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1093
|
|
|
|
|
|
|
sub ctv { |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
# local variables |
|
1096
|
17
|
|
|
17
|
1
|
125
|
my ($hash, $cols); |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
# get optional hash |
|
1099
|
17
|
100
|
|
|
|
35
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1100
|
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
# get remaining parameters |
|
1102
|
17
|
|
|
|
|
29
|
my ($self, $rows, $data) = @_; |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
1105
|
17
|
100
|
|
|
|
23
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(CTV)); |
|
|
17
|
|
|
|
|
55
|
|
|
1106
|
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
# call get/set subroutine |
|
1108
|
17
|
|
|
|
|
50
|
_getset($self, 1, $rows, $cols, $data); |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
} |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
# get/set L*a*b* data |
|
1113
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1114
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1115
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1116
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1117
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1118
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1119
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1120
|
|
|
|
|
|
|
sub lab { |
|
1121
|
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
# local variables |
|
1123
|
29
|
|
|
29
|
1
|
9335
|
my ($hash, $cols); |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
# get optional hash |
|
1126
|
29
|
100
|
|
|
|
77
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1127
|
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
# get remaining parameters |
|
1129
|
29
|
|
|
|
|
45
|
my ($self, $rows, $data) = @_; |
|
1130
|
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
1132
|
29
|
100
|
|
|
|
48
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(LAB_L LAB_A LAB_B)); |
|
|
87
|
|
|
|
|
195
|
|
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
# call get/set subroutine |
|
1135
|
29
|
|
|
|
|
77
|
_getset($self, 1, $rows, $cols, $data, _lab_encoding($self, $hash)); |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
} |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
# get/set XYZ data |
|
1140
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1141
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1142
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1143
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1144
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1145
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1146
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1147
|
|
|
|
|
|
|
sub xyz { |
|
1148
|
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
# local variables |
|
1150
|
23
|
|
|
23
|
1
|
4472
|
my ($hash, $cols); |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
# get optional hash |
|
1153
|
23
|
100
|
|
|
|
54
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
# get remaining parameters |
|
1156
|
23
|
|
|
|
|
38
|
my ($self, $rows, $data) = @_; |
|
1157
|
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
1159
|
23
|
100
|
|
|
|
34
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)); |
|
|
69
|
|
|
|
|
172
|
|
|
1160
|
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
# call get/set subroutine |
|
1162
|
23
|
|
|
|
|
65
|
_getset($self, 1, $rows, $cols, $data, _xyz_encoding($self, $cols, $hash)); |
|
1163
|
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
} |
|
1165
|
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
# get/set density data |
|
1167
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1168
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1169
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1170
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1171
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1172
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1173
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1174
|
|
|
|
|
|
|
sub density { |
|
1175
|
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
# local variables |
|
1177
|
17
|
|
|
17
|
1
|
129
|
my ($hash, $cols); |
|
1178
|
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
# get optional hash |
|
1180
|
17
|
100
|
|
|
|
40
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1181
|
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
# get remaining parameters |
|
1183
|
17
|
|
|
|
|
28
|
my ($self, $rows, $data) = @_; |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# get column slice |
|
1186
|
17
|
100
|
|
|
|
27
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(D_RED D_GREEN D_BLUE D_VIS)); |
|
|
68
|
|
|
|
|
137
|
|
|
1187
|
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
# call get/set subroutine |
|
1189
|
17
|
|
|
|
|
44
|
_getset($self, 1, $rows, $cols, $data, _density_encoding($self, $hash)); |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
} |
|
1192
|
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
# get/set reflectance/transmittance data |
|
1194
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1195
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1196
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1197
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1198
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1199
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1200
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1201
|
|
|
|
|
|
|
sub rgbv { |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
# local variables |
|
1204
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $cols); |
|
1205
|
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
# get optional hash |
|
1207
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1208
|
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# get remaining parameters |
|
1210
|
0
|
|
|
|
|
0
|
my ($self, $rows, $data) = @_; |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
# get column slice |
|
1213
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(R_RED R_GREEN R_BLUE R_VIS)); |
|
|
0
|
|
|
|
|
0
|
|
|
1214
|
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
# call get/set subroutine |
|
1216
|
0
|
|
|
|
|
0
|
_getset($self, 1, $rows, $cols, $data, _rgbv_encoding($self, $hash)); |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
} |
|
1219
|
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
# get/set spectral data |
|
1221
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1222
|
|
|
|
|
|
|
# row_slice and column_slice are 1-D array references |
|
1223
|
|
|
|
|
|
|
# data_slice is a Math::Matrix object (2-D array) |
|
1224
|
|
|
|
|
|
|
# replacement_data is a Math::Matrix object or 2-D array |
|
1225
|
|
|
|
|
|
|
# parameters: ([hash]) => returns: (column_slice) |
|
1226
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) => returns: (data_slice) |
|
1227
|
|
|
|
|
|
|
# parameters: (row_slice, replacement_data, [hash]) => returns: (column_slice) |
|
1228
|
|
|
|
|
|
|
sub spectral { |
|
1229
|
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
# local variables |
|
1231
|
45
|
|
|
45
|
1
|
24976
|
my ($hash, $fields, $cols); |
|
1232
|
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
# get optional hash |
|
1234
|
45
|
100
|
|
|
|
113
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
1235
|
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
# get remaining parameters |
|
1237
|
45
|
|
|
|
|
94
|
my ($self, $rows, $data) = @_; |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
# get spectral fields array |
|
1240
|
45
|
|
|
|
|
120
|
$fields = _spectral($self, $hash->{'context'}); |
|
1241
|
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
# get column slice from spectral fields array |
|
1243
|
45
|
100
|
|
|
|
88
|
$cols = defined($fields) ? [map {$_->[0]} @{$fields}] : undef; |
|
|
1332
|
|
|
|
|
1424
|
|
|
|
37
|
|
|
|
|
57
|
|
|
1244
|
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
# call get/set subroutine |
|
1246
|
45
|
|
|
|
|
114
|
_getset($self, 1, $rows, $cols, $data); |
|
1247
|
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
} |
|
1249
|
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
# get spectral wavelength array |
|
1251
|
|
|
|
|
|
|
# array is sorted (low to high) |
|
1252
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1253
|
|
|
|
|
|
|
# returns: (ref_to_wavelength_array) |
|
1254
|
|
|
|
|
|
|
sub wavelength { |
|
1255
|
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
# get parameters |
|
1257
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
# get spectral fields array or return empty |
|
1260
|
0
|
|
0
|
|
|
0
|
my $fields = _spectral($self, $hash->{'context'}) || return(); |
|
1261
|
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
# return |
|
1263
|
0
|
|
|
|
|
0
|
return([map {$_->[1]} @{$fields}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1264
|
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
} |
|
1266
|
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
# get spectral wavelength range |
|
1268
|
|
|
|
|
|
|
# structure is [start_nm, end_nm, increment] |
|
1269
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1270
|
|
|
|
|
|
|
# returns: (range) |
|
1271
|
|
|
|
|
|
|
sub nm { |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
# get parameters |
|
1274
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1275
|
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
# local variables |
|
1277
|
0
|
|
|
|
|
0
|
my ($fields, $inc); |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
# get spectral fields array or return empty |
|
1280
|
0
|
|
0
|
|
|
0
|
$fields = _spectral($self, $hash->{'context'}) || return(); |
|
1281
|
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
# compute increment |
|
1283
|
0
|
|
|
|
|
0
|
$inc = $fields->[1][1] - $fields->[0][1]; |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
# verify wavelength increment |
|
1286
|
0
|
0
|
0
|
|
|
0
|
($inc > 0 && abs($#{$fields} * $inc - $fields->[-1][1] + $fields->[0][1]) < 1E-12) || warn('inconsistent wavelength values'); |
|
|
0
|
|
|
|
|
0
|
|
|
1287
|
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
# return range |
|
1289
|
0
|
|
|
|
|
0
|
return([$fields->[0][1], $fields->[-1][1], $inc]); |
|
1290
|
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
} |
|
1292
|
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
# get illuminant white point |
|
1294
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1295
|
|
|
|
|
|
|
# returns: (XYZ_vector) |
|
1296
|
|
|
|
|
|
|
sub iwtpt { |
|
1297
|
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
# get parameters |
|
1299
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1300
|
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
# local variables |
|
1302
|
0
|
|
|
|
|
0
|
my ($encode, $cols, $iwtpt, $get); |
|
1303
|
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
# extract encoding hash |
|
1305
|
0
|
|
|
|
|
0
|
$encode = {'encoding' => delete($hash->{'encoding'})}; |
|
1306
|
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
# get XYZ or L*a*b* column slice |
|
1308
|
0
|
0
|
0
|
|
|
0
|
$cols = xyz($self, $hash) || lab($self, $hash) or croak('illuminant white point XYZ or L*a*b* column slice undefined'); |
|
1309
|
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
# get illuminant white point |
|
1311
|
0
|
|
|
|
|
0
|
$iwtpt = _illumWP($self, $cols, $hash); |
|
1312
|
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
# get code reference |
|
1314
|
0
|
|
|
|
|
0
|
($get) = _xyz_encoding($self, $cols, $encode); |
|
1315
|
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
# return encoded XYZ vector |
|
1317
|
0
|
|
|
|
|
0
|
return([&$get(@{$iwtpt})]); |
|
|
0
|
|
|
|
|
0
|
|
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
} |
|
1320
|
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
# get media white point |
|
1322
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1323
|
|
|
|
|
|
|
# returns: (XYZ_vector) |
|
1324
|
|
|
|
|
|
|
sub wtpt { |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
# get parameters |
|
1327
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1328
|
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
# local variables |
|
1330
|
0
|
|
|
|
|
0
|
my ($encode, $cols, $get); |
|
1331
|
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
# extract encoding hash |
|
1333
|
0
|
|
|
|
|
0
|
$encode = {'encoding' => delete($hash->{'encoding'})}; |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
# get XYZ or L*a*b* column slice |
|
1336
|
0
|
0
|
0
|
|
|
0
|
$cols = xyz($self, $hash) || lab($self, $hash) or croak('white point XYZ or L*a*b* column slice undefined'); |
|
1337
|
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
# if media white point undefined in colorimetry array |
|
1339
|
0
|
0
|
|
|
|
0
|
if (! defined($self->[2][3][$cols->[0]])) { |
|
1340
|
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
# compute media white point or return undefined |
|
1342
|
0
|
0
|
|
|
|
0
|
(_mediaWP($self, $cols, $hash)) || return(); |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
} |
|
1345
|
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
# get code reference |
|
1347
|
0
|
|
|
|
|
0
|
($get) = _xyz_encoding($self, $cols, $encode); |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
# return encoded XYZ vector |
|
1350
|
0
|
|
|
|
|
0
|
return([&$get(@{$self->[2][3]}[@{$cols}])]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1351
|
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
} |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
# get media black point |
|
1355
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1356
|
|
|
|
|
|
|
# returns: (XYZ_vector) |
|
1357
|
|
|
|
|
|
|
sub bkpt { |
|
1358
|
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
# get parameters |
|
1360
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1361
|
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
# local variables |
|
1363
|
0
|
|
|
|
|
0
|
my ($encode, $cols, $get); |
|
1364
|
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
# extract encoding hash |
|
1366
|
0
|
|
|
|
|
0
|
$encode = {'encoding' => delete($hash->{'encoding'})}; |
|
1367
|
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
# get XYZ or L*a*b* column slice |
|
1369
|
0
|
0
|
0
|
|
|
0
|
$cols = xyz($self, $hash) || lab($self, $hash) or croak('black point XYZ or L*a*b* column slice undefined'); |
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
# if media black point undefined in colorimetry array |
|
1372
|
0
|
0
|
|
|
|
0
|
if (! defined($self->[2][4][$cols->[0]])) { |
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
# compute media black point or return undefined |
|
1375
|
0
|
0
|
|
|
|
0
|
(_mediaBP($self, $cols, $hash)) || return(); |
|
1376
|
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
} |
|
1378
|
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
# get code reference |
|
1380
|
0
|
|
|
|
|
0
|
($get) = _xyz_encoding($self, $cols, $encode); |
|
1381
|
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
# return encoded XYZ vector |
|
1383
|
0
|
|
|
|
|
0
|
return([&$get(@{$self->[2][4]}[@{$cols}])]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1384
|
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
} |
|
1386
|
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
# compute media OBA index |
|
1388
|
|
|
|
|
|
|
# requires M1 and M2 measurements |
|
1389
|
|
|
|
|
|
|
# requires device values -or- sample number |
|
1390
|
|
|
|
|
|
|
# optional hash keys are 'sample', 'device', and 'context' |
|
1391
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1392
|
|
|
|
|
|
|
# returns: (oba_index) |
|
1393
|
|
|
|
|
|
|
# returns: (M1_XYZ_vector, M2_XYZ_vector) |
|
1394
|
|
|
|
|
|
|
sub oba_index { |
|
1395
|
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
# get parameters |
|
1397
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1398
|
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
# local variables |
|
1400
|
0
|
|
|
|
|
0
|
my ($sample, $dev, $mwv, $wps, $wpdata, $context1, $context2, $m1, $m2, @xyz1, @xyz2, $nm, $color); |
|
1401
|
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
# if 'sample' defined |
|
1403
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'sample'})) { |
|
1404
|
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
# get sample from hash |
|
1406
|
0
|
|
|
|
|
0
|
$sample = $hash->{'sample'}; |
|
1407
|
|
|
|
|
|
|
|
|
1408
|
|
|
|
|
|
|
# if valid sample number |
|
1409
|
0
|
0
|
0
|
|
|
0
|
if (Scalar::Util::looks_like_number($sample) && $sample == int($sample) && $sample > 0 && $sample <= $#{$self->[1]}) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
|
|
0
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
# get sample data row |
|
1412
|
0
|
|
|
|
|
0
|
$wpdata = $self->[1][$sample]; |
|
1413
|
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
} else { |
|
1415
|
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
# warn |
|
1417
|
0
|
|
|
|
|
0
|
warn('invalid sample number'); |
|
1418
|
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
# return empty |
|
1420
|
0
|
|
|
|
|
0
|
return(); |
|
1421
|
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
} |
|
1423
|
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
} else { |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
# if device data (using 'device' context) |
|
1427
|
0
|
0
|
|
|
|
0
|
if ($dev = device($self, {'context' => $hash->{'device'}})) { |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
# set media white device value (1 if RGB, 0 otherwise) |
|
1430
|
0
|
0
|
|
|
|
0
|
$mwv = ($self->[1][0][$dev->[0]] =~ m/RGB_R$/) ? 255 : 0; |
|
1431
|
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
# find paper white samples |
|
1433
|
0
|
|
|
0
|
|
0
|
$wps = find($self, sub {@_ == grep {$_ == $mwv} @_}, [], $dev); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1434
|
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
# if samples found |
|
1436
|
0
|
0
|
|
|
|
0
|
if (@{$wps}) { |
|
|
0
|
|
|
|
|
0
|
|
|
1437
|
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
# add average paper white sample row |
|
1439
|
0
|
|
|
|
|
0
|
add_avg($self, $wps); |
|
1440
|
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
# get sample data row |
|
1442
|
0
|
|
|
|
|
0
|
$wpdata = pop(@{$self->[1]}); |
|
|
0
|
|
|
|
|
0
|
|
|
1443
|
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
} else { |
|
1445
|
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
# warn |
|
1447
|
0
|
|
|
|
|
0
|
warn('no paper white samples'); |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
# return empty |
|
1450
|
0
|
|
|
|
|
0
|
return(); |
|
1451
|
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
} |
|
1453
|
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
} else { |
|
1455
|
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
# warn |
|
1457
|
0
|
|
|
|
|
0
|
warn('no sample value or device data'); |
|
1458
|
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
# return empty |
|
1460
|
0
|
|
|
|
|
0
|
return(); |
|
1461
|
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
} |
|
1463
|
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
} |
|
1465
|
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
# if 'context' defined |
|
1467
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'context'})) { |
|
1468
|
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
# if context an array reference containing two scalars |
|
1470
|
0
|
0
|
0
|
|
|
0
|
if (ref($hash->{'context'}) eq 'ARRAY' && ! ref($hash->{'context'}->[0]) && ! ref($hash->{'context'}->[1])) { |
|
|
|
|
0
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
# get specified 'M1' context |
|
1473
|
0
|
|
|
|
|
0
|
$context1 = $hash->{'context'}->[0]; |
|
1474
|
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
# get specified 'M2' context |
|
1476
|
0
|
|
|
|
|
0
|
$context2 = $hash->{'context'}->[1]; |
|
1477
|
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
} else { |
|
1479
|
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
# warn |
|
1481
|
0
|
|
|
|
|
0
|
warn('OBA context is an array reference containing M1 and M2 contexts'); |
|
1482
|
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
# return empty |
|
1484
|
0
|
|
|
|
|
0
|
return(); |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
} |
|
1487
|
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
} else { |
|
1489
|
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
# use standard 'M1' context |
|
1491
|
0
|
|
|
|
|
0
|
$context1 = 'M1_Measurement'; |
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
# use standard 'M2' context |
|
1494
|
0
|
|
|
|
|
0
|
$context2 = 'M2_Measurement'; |
|
1495
|
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
} |
|
1497
|
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
# if M1 and M2 spectral data |
|
1499
|
0
|
0
|
0
|
|
|
0
|
if (($m1 = spectral($self, {'context' => $context1})) && ($m2 = spectral($self, {'context' => $context2}))) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
# get spectral range |
|
1502
|
0
|
|
|
|
|
0
|
$nm = nm($self, {'context' => $context1}); |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
# if increment is 10 or 20 nm |
|
1505
|
0
|
0
|
0
|
|
|
0
|
if ($nm->[2] == 10 || $nm->[2] == 20) { |
|
1506
|
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
# make ASTM color object |
|
1508
|
0
|
|
|
|
|
0
|
$color = ICC::Support::Color->new({'illuminant' => 'D50', 'increment' => $nm->[2]}); |
|
1509
|
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
} else { |
|
1511
|
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
# make CIE color object |
|
1513
|
0
|
|
|
|
|
0
|
$color = ICC::Support::Color->new({'illuminant' => ['CIE', 'D50'], 'increment' => $nm->[2]}); |
|
1514
|
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
} |
|
1516
|
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
# compute M1 and M2 XYZ values |
|
1518
|
0
|
|
|
|
|
0
|
@xyz1 = $color->transform(@{$wpdata}[@{$m1}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1519
|
0
|
|
|
|
|
0
|
@xyz2 = $color->transform(@{$wpdata}[@{$m2}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1520
|
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
# if M1 and M2 XYZ data |
|
1522
|
|
|
|
|
|
|
} elsif (($m1 = xyz($self, {'context' => $context1})) && ($m2 = xyz($self, {'context' => $context2}))) { |
|
1523
|
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
# get M1 and M2 XYZ values (assumes D50 illumination) |
|
1525
|
0
|
|
|
|
|
0
|
@xyz1 = @{$wpdata}[@{$m1}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1526
|
0
|
|
|
|
|
0
|
@xyz2 = @{$wpdata}[@{$m2}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1527
|
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
# if M1 and M2 L*a*b* data |
|
1529
|
|
|
|
|
|
|
} elsif (($m1 = lab($self, {'context' => $context1})) && ($m2 = lab($self, {'context' => $context2}))) { |
|
1530
|
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
# compute M1 and M2 XYZ values (D50 illumination) |
|
1532
|
0
|
|
|
|
|
0
|
@xyz1 = ICC::Shared::_Lab2XYZ(@{$wpdata}[@{$m1}], ICC::Shared::D50); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1533
|
0
|
|
|
|
|
0
|
@xyz2 = ICC::Shared::_Lab2XYZ(@{$wpdata}[@{$m2}], ICC::Shared::D50); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1534
|
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
} else { |
|
1536
|
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
# warn |
|
1538
|
0
|
|
|
|
|
0
|
warn('M1 and M2 data required for OBA index'); |
|
1539
|
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
# return empty |
|
1541
|
0
|
|
|
|
|
0
|
return(); |
|
1542
|
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
} |
|
1544
|
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
# return array (XYZ media white points) or scalar (OBA index) |
|
1546
|
0
|
0
|
|
|
|
0
|
return(wantarray ? (\@xyz1, \@xyz2) : ($xyz1[2] - $xyz2[2])/82.49); |
|
1547
|
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
} |
|
1549
|
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
# get chromatic adaptation transform (CAT) object |
|
1551
|
|
|
|
|
|
|
# a CAT is optionally created when adding XYZ data |
|
1552
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1553
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1554
|
|
|
|
|
|
|
# returns: (CAT_object) |
|
1555
|
|
|
|
|
|
|
sub cat { |
|
1556
|
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
# get parameters |
|
1558
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1559
|
|
|
|
|
|
|
|
|
1560
|
|
|
|
|
|
|
# local variables |
|
1561
|
0
|
|
|
|
|
0
|
my ($cols, $cat); |
|
1562
|
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
1564
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)); |
|
|
0
|
|
|
|
|
0
|
|
|
1565
|
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
# return if slice undefined |
|
1567
|
0
|
0
|
|
|
|
0
|
return() if (! defined($cols)); |
|
1568
|
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
# get CAT or illuminant |
|
1570
|
0
|
|
|
|
|
0
|
$cat = $self->[2][2][$cols->[0]]; |
|
1571
|
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
# return CAT if defined |
|
1573
|
0
|
0
|
0
|
|
|
0
|
return((defined($cat) && UNIVERSAL::isa($cat, 'ICC::Profile::matf')) ? $cat : ()); |
|
1574
|
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
} |
|
1576
|
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
# get Color object |
|
1578
|
|
|
|
|
|
|
# a Color object is created when adding XYZ data from spectral data |
|
1579
|
|
|
|
|
|
|
# optional hash contains supplementary parameters |
|
1580
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1581
|
|
|
|
|
|
|
# returns: (Color_object) |
|
1582
|
|
|
|
|
|
|
sub color { |
|
1583
|
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
# get parameters |
|
1585
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1586
|
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
# local variables |
|
1588
|
0
|
|
|
|
|
0
|
my ($cols, $color); |
|
1589
|
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
# get column slice, adding optional context prefix |
|
1591
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($hash->{'context'}) ? "$hash->{'context'}|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)); |
|
|
0
|
|
|
|
|
0
|
|
|
1592
|
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# return if slice undefined |
|
1594
|
0
|
0
|
|
|
|
0
|
return() if (! defined($cols)); |
|
1595
|
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
# get CAT or illuminant |
|
1597
|
0
|
|
|
|
|
0
|
$color = $self->[2][1][$cols->[0]]; |
|
1598
|
|
|
|
|
|
|
|
|
1599
|
|
|
|
|
|
|
# return CAT if defined |
|
1600
|
0
|
0
|
0
|
|
|
0
|
return((defined($color) && UNIVERSAL::isa($color, 'ICC::Support::Color')) ? $color : ()); |
|
1601
|
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
} |
|
1603
|
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
# append rows to data array |
|
1605
|
|
|
|
|
|
|
# data matrix is the 2-D array of data values to be appended |
|
1606
|
|
|
|
|
|
|
# column slice is a reference to an array of data matrix column indices |
|
1607
|
|
|
|
|
|
|
# parameters: (data_matrix, [column_slice]) |
|
1608
|
|
|
|
|
|
|
# returns: (row_slice) |
|
1609
|
|
|
|
|
|
|
sub add_rows { |
|
1610
|
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
# get parameters |
|
1612
|
0
|
|
|
0
|
1
|
0
|
my ($self, $matrix, $cols) = @_; |
|
1613
|
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
# if object contains data |
|
1615
|
0
|
0
|
0
|
|
|
0
|
if ($#{$self->[1]} || @{$self->[1][0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1616
|
|
|
|
|
|
|
|
|
1617
|
|
|
|
|
|
|
# set offset to upper index + 1 |
|
1618
|
0
|
|
|
|
|
0
|
my $offset = $#{$self->[1]} + 1; |
|
|
0
|
|
|
|
|
0
|
|
|
1619
|
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
# call 'splice_rows' |
|
1621
|
0
|
|
|
|
|
0
|
splice_rows($self, $offset, 0, $matrix, $cols); |
|
1622
|
|
|
|
|
|
|
|
|
1623
|
|
|
|
|
|
|
# return row slice |
|
1624
|
0
|
|
|
|
|
0
|
return([$offset .. ($offset + $#{$matrix})]); |
|
|
0
|
|
|
|
|
0
|
|
|
1625
|
|
|
|
|
|
|
|
|
1626
|
|
|
|
|
|
|
# new object |
|
1627
|
|
|
|
|
|
|
} else { |
|
1628
|
|
|
|
|
|
|
|
|
1629
|
|
|
|
|
|
|
# call 'splice_rows' (deleting first row) |
|
1630
|
0
|
|
|
|
|
0
|
splice_rows($self, 0, 1, $matrix, $cols); |
|
1631
|
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
# return row slice |
|
1633
|
0
|
|
|
|
|
0
|
return([0 .. $#{$matrix}]); |
|
|
0
|
|
|
|
|
0
|
|
|
1634
|
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
} |
|
1636
|
|
|
|
|
|
|
|
|
1637
|
|
|
|
|
|
|
} |
|
1638
|
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
# append columns to data array |
|
1640
|
|
|
|
|
|
|
# data matrix is the 2-D array of data values to be appended |
|
1641
|
|
|
|
|
|
|
# format is a reference to an array of DATA_FORMAT keywords |
|
1642
|
|
|
|
|
|
|
# parameters: (data_matrix, [format]) |
|
1643
|
|
|
|
|
|
|
# returns: (column_slice) |
|
1644
|
|
|
|
|
|
|
sub add_cols { |
|
1645
|
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
# get parameters |
|
1647
|
1
|
|
|
1
|
1
|
4
|
my ($self, $matrix, $format) = @_; |
|
1648
|
|
|
|
|
|
|
|
|
1649
|
|
|
|
|
|
|
# verify matrix a 2-D array or Math::Matrix object |
|
1650
|
1
|
50
|
33
|
|
|
8
|
(ref($matrix) eq 'ARRAY' && ref($matrix->[0]) eq 'ARRAY') || (UNIVERSAL::isa($matrix, 'Math::Matrix')) || croak ('invalid matrix parameter'); |
|
|
|
|
33
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
# if format supplied |
|
1653
|
1
|
50
|
|
|
|
4
|
if (defined($format)) { |
|
1654
|
|
|
|
|
|
|
|
|
1655
|
|
|
|
|
|
|
# verify format is 1-D array of scalars |
|
1656
|
0
|
0
|
0
|
|
|
0
|
(ref($format) eq 'ARRAY' && @{$format} == grep {! ref()} @{$format}) or croak('invalid format parameter'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1657
|
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
# verify format and matrix have same number of columns |
|
1659
|
0
|
0
|
|
|
|
0
|
(@{$format} == @{$matrix->[0]}) or croak('format and matrix have different number of columns'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1660
|
|
|
|
|
|
|
|
|
1661
|
|
|
|
|
|
|
# add format to matrix |
|
1662
|
0
|
|
|
|
|
0
|
$matrix = [$format, @{$matrix}]; |
|
|
0
|
|
|
|
|
0
|
|
|
1663
|
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
} |
|
1665
|
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
# if object contains data |
|
1667
|
1
|
50
|
33
|
|
|
1
|
if ($#{$self->[1]} || @{$self->[1][0]}) { |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
4
|
|
|
1668
|
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
# warn if matrix and object have different number of rows |
|
1670
|
0
|
0
|
|
|
|
0
|
(@{$matrix} == @{$self->[1]}) or carp('matrix and object have different number of rows'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1671
|
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
# set offset to upper index + 1 |
|
1673
|
0
|
|
|
|
|
0
|
my $offset = $#{$self->[1][0]} + 1; |
|
|
0
|
|
|
|
|
0
|
|
|
1674
|
|
|
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
# call 'splice_cols' |
|
1676
|
0
|
|
|
|
|
0
|
splice_cols($self, $offset, 0, $matrix); |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
# return column slice |
|
1679
|
0
|
|
|
|
|
0
|
return([$offset .. ($offset + $#{$matrix->[0]})]); |
|
|
0
|
|
|
|
|
0
|
|
|
1680
|
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
# new object |
|
1682
|
|
|
|
|
|
|
} else { |
|
1683
|
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
# call 'splice_rows' (deleting first row) |
|
1685
|
1
|
|
|
|
|
29
|
splice_rows($self, 0, 1, $matrix); |
|
1686
|
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
# return column slice |
|
1688
|
1
|
|
|
|
|
3
|
return([0 .. $#{$self->[1][0]}]); |
|
|
1
|
|
|
|
|
3
|
|
|
1689
|
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
} |
|
1691
|
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
} |
|
1693
|
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
# add average sample |
|
1695
|
|
|
|
|
|
|
# assumes device values (if any) are same for each sample |
|
1696
|
|
|
|
|
|
|
# averages measurement values - spectral, XYZ, L*a*b* or density |
|
1697
|
|
|
|
|
|
|
# L*a*b* values are converted to xyz for averaging, then back to L*a*b* |
|
1698
|
|
|
|
|
|
|
# density values are converted to reflectance for averaging, then back to density |
|
1699
|
|
|
|
|
|
|
# returns row slice of the appended average sample |
|
1700
|
|
|
|
|
|
|
# parameters: (row_slice, [hash]) |
|
1701
|
|
|
|
|
|
|
# returns: (row_slice) |
|
1702
|
|
|
|
|
|
|
sub add_avg { |
|
1703
|
|
|
|
|
|
|
|
|
1704
|
|
|
|
|
|
|
# get parameters |
|
1705
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rows, $hash) = @_; |
|
1706
|
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
# local variables |
|
1708
|
0
|
|
|
|
|
0
|
my ($c1, $c2, $c3, @id, @name); |
|
1709
|
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
# flatten row slice |
|
1711
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
1712
|
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
# resolve empty row slice |
|
1714
|
0
|
0
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}] if (@{$rows} == 0); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1715
|
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
# get averaging groups |
|
1717
|
0
|
|
|
|
|
0
|
($c1, $c2, $c3) = _avg_groups($self, $hash); |
|
1718
|
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
# for each format field |
|
1720
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1][0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
1721
|
|
|
|
|
|
|
|
|
1722
|
|
|
|
|
|
|
# add column if SAMPLE_ID field |
|
1723
|
0
|
0
|
|
|
|
0
|
push(@id, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?(?:SAMPLE_ID|SampleID)$/); |
|
1724
|
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
# add column if SAMPLE_NAME field |
|
1726
|
0
|
0
|
|
|
|
0
|
push(@name, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?SAMPLE_NAME$/); |
|
1727
|
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
} |
|
1729
|
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
# return average sample |
|
1731
|
0
|
|
|
|
|
0
|
return([_add_avg($self, $rows, $c1, $c2, $c3, \@id, \@name, $hash)]); |
|
1732
|
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
} |
|
1734
|
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
# add format keys |
|
1736
|
|
|
|
|
|
|
# keys are appended to row 0 of the data array |
|
1737
|
|
|
|
|
|
|
# note: format_keys is a list of scalars and/or array references |
|
1738
|
|
|
|
|
|
|
# note: format_keys are saved as given, with or without context |
|
1739
|
|
|
|
|
|
|
# parameters: (format_keys) |
|
1740
|
|
|
|
|
|
|
# returns: (column_slice) |
|
1741
|
|
|
|
|
|
|
sub add_fmt { |
|
1742
|
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
# get parameters |
|
1744
|
16
|
|
|
16
|
1
|
25
|
my $self = shift(); |
|
1745
|
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
# local variables |
|
1747
|
16
|
|
|
|
|
21
|
my (@keys, $i, %fmt); |
|
1748
|
|
|
|
|
|
|
|
|
1749
|
|
|
|
|
|
|
# flatten format key list |
|
1750
|
16
|
|
|
|
|
20
|
@keys = @{ICC::Shared::flatten(@_)}; |
|
|
16
|
|
|
|
|
51
|
|
|
1751
|
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
# get upper column index |
|
1753
|
16
|
|
|
|
|
31
|
$i = $#{$self->[1][0]}; |
|
|
16
|
|
|
|
|
30
|
|
|
1754
|
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
# make format lookup hash of existing keys |
|
1756
|
16
|
|
|
|
|
23
|
%fmt = map {$self->[1][0][$_], $_} (0 .. $#{$self->[1][0]}); |
|
|
34
|
|
|
|
|
75
|
|
|
|
16
|
|
|
|
|
30
|
|
|
1757
|
|
|
|
|
|
|
|
|
1758
|
|
|
|
|
|
|
# warn if duplicate keys |
|
1759
|
16
|
50
|
|
|
|
28
|
warn('adding duplicate format key(s)') if (grep {exists($fmt{$_})} @keys); |
|
|
256
|
|
|
|
|
356
|
|
|
1760
|
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
# push format keys onto format row |
|
1762
|
16
|
|
|
|
|
19
|
push(@{$self->[1][0]}, @keys); |
|
|
16
|
|
|
|
|
57
|
|
|
1763
|
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
# return slice array reference |
|
1765
|
16
|
|
|
|
|
28
|
return([$i + 1 .. $#{$self->[1][0]}]); |
|
|
16
|
|
|
|
|
70
|
|
|
1766
|
|
|
|
|
|
|
|
|
1767
|
|
|
|
|
|
|
} |
|
1768
|
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
# append CTV data to data array |
|
1770
|
|
|
|
|
|
|
# computed from L*a*b* data, XYZ data, or spectral data |
|
1771
|
|
|
|
|
|
|
# if CTV data already exists, return those slices |
|
1772
|
|
|
|
|
|
|
# adds L*a*b* data, and XYZ data if missing |
|
1773
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
1774
|
|
|
|
|
|
|
# returns: (column_slice) |
|
1775
|
|
|
|
|
|
|
sub add_ctv { |
|
1776
|
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
# get parameters |
|
1778
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1779
|
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
# local variables |
|
1781
|
0
|
|
|
|
|
0
|
my ($context, $added, $cf, $cols, $Lab, $color); |
|
1782
|
0
|
|
|
|
|
0
|
my ($iwtpt, $WPxyz, @wtpt, $dev, $mwv, $coef, @Ls); |
|
1783
|
0
|
|
|
|
|
0
|
my ($den, $a, $b, $c, $d, $e, $f, $mat); |
|
1784
|
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
# get base context |
|
1786
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}; |
|
1787
|
|
|
|
|
|
|
|
|
1788
|
|
|
|
|
|
|
# get added context |
|
1789
|
0
|
0
|
|
|
|
0
|
$added = defined($hash->{'added'}) ? $hash->{'added'} : $context; |
|
1790
|
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
# get colorimetry flag |
|
1792
|
0
|
|
0
|
|
|
0
|
$cf = defined($hash->{'illuminant'}) || defined($hash->{'observer'}) || defined($hash->{'cat'}); |
|
1793
|
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
# return column slice if no colorimetry and CTV data already exists |
|
1795
|
0
|
0
|
0
|
|
|
0
|
return($cols) if (! $cf && ($cols = _cols($self, map {defined($added) ? "$added|$_" : $_} qw(CTV)))); |
|
|
0
|
0
|
|
|
|
0
|
|
|
1796
|
|
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
# if L*a*b* exists, or is added |
|
1798
|
0
|
0
|
0
|
|
|
0
|
if ($Lab = (_cols($self, map {defined($context) ? "$context|$_" : $_} qw(LAB_L LAB_A LAB_B)) || add_lab($self, $hash))) { |
|
1799
|
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
# get L*a*b* colorimetry hash |
|
1801
|
0
|
|
|
|
|
0
|
$color = $self->[2][6][$Lab->[0]]; |
|
1802
|
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
# for each possible colorimetry key |
|
1804
|
0
|
|
|
|
|
0
|
for my $key (qw(illuminant observer increment bandpass cat)) { |
|
1805
|
|
|
|
|
|
|
|
|
1806
|
|
|
|
|
|
|
# if key is specified |
|
1807
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{$key})) { |
|
1808
|
|
|
|
|
|
|
|
|
1809
|
|
|
|
|
|
|
# if YAML strings differ |
|
1810
|
0
|
0
|
|
|
|
0
|
if (YAML::Tiny::Dump($hash->{$key}) ne YAML::Tiny::Dump($color->{$key})) { |
|
1811
|
|
|
|
|
|
|
|
|
1812
|
|
|
|
|
|
|
# print warning |
|
1813
|
0
|
|
|
|
|
0
|
warn("$key parameter differs from source"); |
|
1814
|
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
} |
|
1816
|
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
} |
|
1818
|
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
} |
|
1820
|
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
# if 'context' and 'added' keys are undefined, and L*a*b* source has context |
|
1822
|
0
|
0
|
0
|
|
|
0
|
if (! defined($added) && $self->[1][0][$Lab->[0]] =~ m/^(.*)\|/) { |
|
1823
|
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
# set 'added' to L*a*b* context |
|
1825
|
0
|
|
|
|
|
0
|
$added = $1; |
|
1826
|
|
|
|
|
|
|
|
|
1827
|
|
|
|
|
|
|
} |
|
1828
|
|
|
|
|
|
|
|
|
1829
|
|
|
|
|
|
|
# add CTV column slice |
|
1830
|
0
|
0
|
|
|
|
0
|
$cols = add_fmt($self, map {defined($added) ? "$added|$_" : $_} qw(CTV)); |
|
|
0
|
|
|
|
|
0
|
|
|
1831
|
|
|
|
|
|
|
|
|
1832
|
|
|
|
|
|
|
# get supplied illuminant white point |
|
1833
|
0
|
|
|
|
|
0
|
$iwtpt = $hash->{'iwtpt'}; |
|
1834
|
|
|
|
|
|
|
|
|
1835
|
|
|
|
|
|
|
# if supplied illuminant white point is valid |
|
1836
|
0
|
0
|
0
|
|
|
0
|
if (defined($iwtpt) && (3 == grep {defined() && ! ref() && $_ > 0} @{$iwtpt})) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
0
|
|
|
|
0
|
|
|
1837
|
|
|
|
|
|
|
|
|
1838
|
|
|
|
|
|
|
# use it |
|
1839
|
0
|
|
|
|
|
0
|
$WPxyz = $iwtpt; |
|
1840
|
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
# if XYZ illuminant white point is valid |
|
1842
|
0
|
0
|
0
|
|
|
0
|
} elsif (3 == grep {defined() && ! ref() && $_ > 0} @{$self->[2][2]}[@{$Lab}]) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1843
|
|
|
|
|
|
|
|
|
1844
|
|
|
|
|
|
|
# use it |
|
1845
|
0
|
|
|
|
|
0
|
$WPxyz = [@{$self->[2][2]}[@{$Lab}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1846
|
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
} else { |
|
1848
|
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
# use D50 |
|
1850
|
0
|
|
|
|
|
0
|
$WPxyz = ICC::Shared::D50; |
|
1851
|
|
|
|
|
|
|
|
|
1852
|
|
|
|
|
|
|
} |
|
1853
|
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
# if media white point undefined in colorimetry array |
|
1855
|
0
|
0
|
|
|
|
0
|
if (! defined($self->[2][3][$Lab->[0]])) { |
|
1856
|
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
# compute media white point or return undefined |
|
1858
|
0
|
0
|
|
|
|
0
|
(_mediaWP($self, $Lab, $hash)) || return(); |
|
1859
|
|
|
|
|
|
|
|
|
1860
|
|
|
|
|
|
|
} |
|
1861
|
|
|
|
|
|
|
|
|
1862
|
|
|
|
|
|
|
# get media white point (Lx, Ly, Lz) |
|
1863
|
0
|
|
|
|
|
0
|
@wtpt = ICC::Shared::_xyz2Lxyz($self->[2][3][$Lab->[0]]/$WPxyz->[0], $self->[2][3][$Lab->[1]]/$WPxyz->[1], $self->[2][3][$Lab->[2]]/$WPxyz->[2]); |
|
1864
|
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
# get device column slice |
|
1866
|
0
|
|
|
|
|
0
|
$dev = device($self, {'context' => $hash->{'device'}}); |
|
1867
|
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
# set media white device value (255 if RGB, 0 otherwise) |
|
1869
|
0
|
0
|
|
|
|
0
|
$mwv = ($self->[1][0][$dev->[0]] =~ m/RGB_R$/) ? 255 : 0; |
|
1870
|
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
# set origin |
|
1872
|
0
|
|
|
|
|
0
|
$self->[2][0][$cols->[0]] = $Lab; |
|
1873
|
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
# save media white CTV (0) |
|
1875
|
0
|
|
|
|
|
0
|
$self->[2][3][$cols->[0]] = 0; |
|
1876
|
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
# save colorimetry hash |
|
1878
|
0
|
|
|
|
|
0
|
@{$self->[2][6]}[$cols->[0]] = $color; |
|
|
0
|
|
|
|
|
0
|
|
|
1879
|
|
|
|
|
|
|
|
|
1880
|
|
|
|
|
|
|
# get coefficient array |
|
1881
|
0
|
0
|
|
|
|
0
|
$coef = defined($hash->{'coef'}) ? $hash->{'coef'} : [1, 1, 1, 0, 0, 0]; |
|
1882
|
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
# compute denominator |
|
1884
|
0
|
|
|
|
|
0
|
$den = $coef->[0]**2 + $coef->[1]**2 + $coef->[2]**2; |
|
1885
|
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
# compute matrix elements |
|
1887
|
0
|
|
|
|
|
0
|
$a = ($coef->[0]**2 + $coef->[4]**2 + $coef->[5]**2)/$den; |
|
1888
|
0
|
|
|
|
|
0
|
$b = ($coef->[1]**2 + $coef->[3]**2 + $coef->[5]**2)/$den; |
|
1889
|
0
|
|
|
|
|
0
|
$c = ($coef->[2]**2 + $coef->[3]**2 + $coef->[4]**2)/$den; |
|
1890
|
0
|
|
|
|
|
0
|
$d = -$coef->[5]**2/$den; |
|
1891
|
0
|
|
|
|
|
0
|
$e = -$coef->[4]**2/$den; |
|
1892
|
0
|
|
|
|
|
0
|
$f = -$coef->[3]**2/$den; |
|
1893
|
|
|
|
|
|
|
|
|
1894
|
|
|
|
|
|
|
# make Mahalanobis matrix |
|
1895
|
0
|
|
|
|
|
0
|
$mat = [ |
|
1896
|
|
|
|
|
|
|
[$a, $d, $e], |
|
1897
|
|
|
|
|
|
|
[$d, $b, $f], |
|
1898
|
|
|
|
|
|
|
[$e, $f, $c] |
|
1899
|
|
|
|
|
|
|
]; |
|
1900
|
|
|
|
|
|
|
|
|
1901
|
|
|
|
|
|
|
# bless the object |
|
1902
|
0
|
|
|
|
|
0
|
bless($mat, 'Math::Matrix'); |
|
1903
|
|
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
# for each sample |
|
1905
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
1906
|
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
# if all device channels are white |
|
1908
|
0
|
0
|
|
|
|
0
|
if (@{$dev} == grep {$_ == $mwv} @{$self->[1][$i]}[@{$dev}]) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1909
|
|
|
|
|
|
|
|
|
1910
|
|
|
|
|
|
|
# save CTV (0) |
|
1911
|
0
|
|
|
|
|
0
|
$self->[1][$i][$cols->[0]] = 0; |
|
1912
|
|
|
|
|
|
|
|
|
1913
|
|
|
|
|
|
|
} else { |
|
1914
|
|
|
|
|
|
|
|
|
1915
|
|
|
|
|
|
|
# compute sample Lx, Ly, Lz values |
|
1916
|
0
|
|
|
|
|
0
|
@Ls = ICC::Shared::_Lab2Lxyz(@{$self->[1][$i]}[@{$Lab}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1917
|
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
# save CTV (computed as Mahalanobis distance) |
|
1919
|
0
|
|
|
|
|
0
|
$self->[1][$i][$cols->[0]] = _mahal(\@wtpt, \@Ls, $mat); |
|
1920
|
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
} |
|
1922
|
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
} |
|
1924
|
|
|
|
|
|
|
|
|
1925
|
|
|
|
|
|
|
} else { |
|
1926
|
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
# warn |
|
1928
|
0
|
|
|
|
|
0
|
warn('spectral, XYZ or L*a*b* data is required'); |
|
1929
|
|
|
|
|
|
|
|
|
1930
|
|
|
|
|
|
|
# return empty |
|
1931
|
0
|
|
|
|
|
0
|
return(); |
|
1932
|
|
|
|
|
|
|
|
|
1933
|
|
|
|
|
|
|
} |
|
1934
|
|
|
|
|
|
|
|
|
1935
|
|
|
|
|
|
|
# return column slice |
|
1936
|
0
|
|
|
|
|
0
|
return($cols); |
|
1937
|
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
} |
|
1939
|
|
|
|
|
|
|
|
|
1940
|
|
|
|
|
|
|
# append L*a*b* data to data array |
|
1941
|
|
|
|
|
|
|
# computed from XYZ data or spectral data |
|
1942
|
|
|
|
|
|
|
# if L*a*b* data already exists, returns that slice |
|
1943
|
|
|
|
|
|
|
# adds XYZ data, if only spectral data exists |
|
1944
|
|
|
|
|
|
|
# parameter: ([hash]) |
|
1945
|
|
|
|
|
|
|
# returns: (column_slice) |
|
1946
|
|
|
|
|
|
|
sub add_lab { |
|
1947
|
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
# get parameters |
|
1949
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
1950
|
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
# local variables |
|
1952
|
0
|
|
|
|
|
0
|
my ($context, $added, $cf, $cols, $xyz, $color, $iwtpt, $WPxyz); |
|
1953
|
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
# get base context |
|
1955
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}; |
|
1956
|
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
# get added context |
|
1958
|
0
|
0
|
|
|
|
0
|
$added = defined($hash->{'added'}) ? $hash->{'added'} : $context; |
|
1959
|
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
# get colorimetry flag |
|
1961
|
0
|
|
0
|
|
|
0
|
$cf = defined($hash->{'illuminant'}) || defined($hash->{'observer'}) || defined($hash->{'cat'}); |
|
1962
|
|
|
|
|
|
|
|
|
1963
|
|
|
|
|
|
|
# return column slice if no colorimetry and L*a*b* data already exists |
|
1964
|
0
|
0
|
0
|
|
|
0
|
return($cols) if (! $cf && ($cols = _cols($self, map {defined($added) ? "$added|$_" : $_} qw(LAB_L LAB_A LAB_B)))); |
|
|
0
|
0
|
|
|
|
0
|
|
|
1965
|
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
# if XYZ data exists, or is added |
|
1967
|
0
|
0
|
0
|
|
|
0
|
if ($xyz = (_cols($self, map {defined($context) ? "$context|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)) || add_xyz($self, $hash))) { |
|
1968
|
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
# get XYZ colorimetry hash |
|
1970
|
0
|
|
|
|
|
0
|
$color = $self->[2][6][$xyz->[0]]; |
|
1971
|
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
# for each possible colorimetry key |
|
1973
|
0
|
|
|
|
|
0
|
for my $key (qw(illuminant observer increment bandpass cat)) { |
|
1974
|
|
|
|
|
|
|
|
|
1975
|
|
|
|
|
|
|
# if key is specified |
|
1976
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{$key})) { |
|
1977
|
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
# if YAML strings differ |
|
1979
|
0
|
0
|
|
|
|
0
|
if (YAML::Tiny::Dump($hash->{$key}) ne YAML::Tiny::Dump($color->{$key})) { |
|
1980
|
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
# print warning |
|
1982
|
0
|
|
|
|
|
0
|
warn("$key parameter differs from source"); |
|
1983
|
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
} |
|
1985
|
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
} |
|
1987
|
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
} |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
# if 'context' and 'added' keys are undefined, and XYZ source has context |
|
1991
|
0
|
0
|
0
|
|
|
0
|
if (! defined($added) && $self->[1][0][$xyz->[0]] =~ m/^(.*)\|/) { |
|
1992
|
|
|
|
|
|
|
|
|
1993
|
|
|
|
|
|
|
# set 'added' to XYZ context |
|
1994
|
0
|
|
|
|
|
0
|
$added = $1; |
|
1995
|
|
|
|
|
|
|
|
|
1996
|
|
|
|
|
|
|
} |
|
1997
|
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
# add L*a*b* columns slice |
|
1999
|
0
|
0
|
|
|
|
0
|
$cols = add_fmt($self, map {defined($added) ? "$added|$_" : $_} qw(LAB_L LAB_A LAB_B)); |
|
|
0
|
|
|
|
|
0
|
|
|
2000
|
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
# get supplied illuminant white point |
|
2002
|
0
|
|
|
|
|
0
|
$iwtpt = $hash->{'iwtpt'}; |
|
2003
|
|
|
|
|
|
|
|
|
2004
|
|
|
|
|
|
|
# if supplied illuminant white point is valid |
|
2005
|
0
|
0
|
0
|
|
|
0
|
if (defined($iwtpt) && (3 == grep {defined() && ! ref() && $_ > 0} @{$iwtpt})) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
0
|
|
|
|
0
|
|
|
2006
|
|
|
|
|
|
|
|
|
2007
|
|
|
|
|
|
|
# use it |
|
2008
|
0
|
|
|
|
|
0
|
$WPxyz = $iwtpt; |
|
2009
|
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
# if XYZ illuminant white point is valid |
|
2011
|
0
|
0
|
0
|
|
|
0
|
} elsif (3 == grep {defined() && ! ref() && $_ > 0} @{$self->[2][2]}[@{$xyz}]) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2012
|
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
# use it |
|
2014
|
0
|
|
|
|
|
0
|
$WPxyz = [@{$self->[2][2]}[@{$xyz}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2015
|
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
} else { |
|
2017
|
|
|
|
|
|
|
|
|
2018
|
|
|
|
|
|
|
# use D50 |
|
2019
|
0
|
|
|
|
|
0
|
$WPxyz = ICC::Shared::D50; |
|
2020
|
|
|
|
|
|
|
|
|
2021
|
|
|
|
|
|
|
} |
|
2022
|
|
|
|
|
|
|
|
|
2023
|
|
|
|
|
|
|
# set origin |
|
2024
|
0
|
|
|
|
|
0
|
@{$self->[2][0]}[@{$cols}] = ($xyz) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2025
|
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
# save illuminant white point |
|
2027
|
0
|
|
|
|
|
0
|
@{$self->[2][2]}[@{$cols}] = @{$WPxyz}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2028
|
|
|
|
|
|
|
|
|
2029
|
|
|
|
|
|
|
# save colorimetry hash |
|
2030
|
0
|
|
|
|
|
0
|
@{$self->[2][6]}[@{$cols}] = ($color) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2031
|
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
# for each sample |
|
2033
|
0
|
|
|
|
|
0
|
for my $s (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2034
|
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
# compute L*a*b* values from XYZ values |
|
2036
|
0
|
|
|
|
|
0
|
@{$self->[1][$s]}[@{$cols}] = ICC::Shared::_XYZ2Lab(@{$self->[1][$s]}[@{$xyz}], $WPxyz); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2037
|
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
} |
|
2039
|
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
} else { |
|
2041
|
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
# warn |
|
2043
|
0
|
|
|
|
|
0
|
warn('spectral or XYZ data is required'); |
|
2044
|
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
# return empty |
|
2046
|
0
|
|
|
|
|
0
|
return(); |
|
2047
|
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
} |
|
2049
|
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
# return column slice |
|
2051
|
0
|
|
|
|
|
0
|
return($cols); |
|
2052
|
|
|
|
|
|
|
|
|
2053
|
|
|
|
|
|
|
} |
|
2054
|
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
# append XYZ data to data array |
|
2056
|
|
|
|
|
|
|
# computed from spectral data or L*a*b* data |
|
2057
|
|
|
|
|
|
|
# if XYZ data already exists, returns that slice |
|
2058
|
|
|
|
|
|
|
# default colorimetry is D50, 2 degree observer |
|
2059
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
2060
|
|
|
|
|
|
|
# returns: (column_slice) |
|
2061
|
|
|
|
|
|
|
sub add_xyz { |
|
2062
|
|
|
|
|
|
|
|
|
2063
|
|
|
|
|
|
|
# get parameters |
|
2064
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
2065
|
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
# local variables |
|
2067
|
0
|
|
|
|
|
0
|
my ($oba, $spec1, $spec2, $context, $added, $cf); |
|
2068
|
0
|
|
|
|
|
0
|
my ($spec, $color, $illum, $specv, $nm, $cols); |
|
2069
|
0
|
|
|
|
|
0
|
my ($cat, $spectral, $xyz, $Lab, @WPlab, $WPxyz); |
|
2070
|
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
# if 'oba' defined |
|
2072
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'oba'})) { |
|
2073
|
|
|
|
|
|
|
|
|
2074
|
|
|
|
|
|
|
# get oba factor |
|
2075
|
0
|
|
|
|
|
0
|
$oba = $hash->{'oba'}; |
|
2076
|
|
|
|
|
|
|
|
|
2077
|
|
|
|
|
|
|
# if 'context' defined |
|
2078
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'context'})) { |
|
2079
|
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
# if context an array reference containing two scalars |
|
2081
|
0
|
0
|
0
|
|
|
0
|
if (ref($hash->{'context'}) eq 'ARRAY' && ! ref($hash->{'context'}->[0]) && ! ref($hash->{'context'}->[1])) { |
|
|
|
|
0
|
|
|
|
|
|
2082
|
|
|
|
|
|
|
|
|
2083
|
|
|
|
|
|
|
# get specified 'M1' spectral slice |
|
2084
|
0
|
|
|
|
|
0
|
$spec1 = spectral($self, {'context' => $hash->{'context'}->[0]}); |
|
2085
|
|
|
|
|
|
|
|
|
2086
|
|
|
|
|
|
|
# get specified 'M2' spectral slice |
|
2087
|
0
|
|
|
|
|
0
|
$spec2 = spectral($self, {'context' => $hash->{'context'}->[1]}); |
|
2088
|
|
|
|
|
|
|
|
|
2089
|
|
|
|
|
|
|
# use specified 'M2' context |
|
2090
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}->[1]; |
|
2091
|
|
|
|
|
|
|
|
|
2092
|
|
|
|
|
|
|
} else { |
|
2093
|
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
# warn |
|
2095
|
0
|
|
|
|
|
0
|
warn('OBA context is an array reference containing M1 and M2 contexts'); |
|
2096
|
|
|
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
# return empty |
|
2098
|
0
|
|
|
|
|
0
|
return(); |
|
2099
|
|
|
|
|
|
|
|
|
2100
|
|
|
|
|
|
|
} |
|
2101
|
|
|
|
|
|
|
|
|
2102
|
|
|
|
|
|
|
} else { |
|
2103
|
|
|
|
|
|
|
|
|
2104
|
|
|
|
|
|
|
# get spectral slice using standard 'M1' context |
|
2105
|
0
|
|
|
|
|
0
|
$spec1 = spectral($self, {'context' => 'M1_Measurement'}); |
|
2106
|
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
# get spectral slice using standard 'M2' context |
|
2108
|
0
|
|
|
|
|
0
|
$spec2 = spectral($self, {'context' => 'M2_Measurement'}); |
|
2109
|
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
# use standard 'M2' context |
|
2111
|
0
|
|
|
|
|
0
|
$context = 'M2_Measurement'; |
|
2112
|
|
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
} |
|
2114
|
|
|
|
|
|
|
|
|
2115
|
|
|
|
|
|
|
# verify spectral slices |
|
2116
|
0
|
0
|
0
|
|
|
0
|
if (! $spec1 || ! $spec2 || $#{$spec1} != $#{$spec2}) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2117
|
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
# warn |
|
2119
|
0
|
|
|
|
|
0
|
warn('M1 and M2 spectral data required for OBA effect'); |
|
2120
|
|
|
|
|
|
|
|
|
2121
|
|
|
|
|
|
|
# return empty |
|
2122
|
0
|
|
|
|
|
0
|
return(); |
|
2123
|
|
|
|
|
|
|
|
|
2124
|
|
|
|
|
|
|
} |
|
2125
|
|
|
|
|
|
|
|
|
2126
|
|
|
|
|
|
|
# get added context |
|
2127
|
0
|
0
|
|
|
|
0
|
$added = defined($hash->{'added'}) ? $hash->{'added'} : 'OBA'; |
|
2128
|
|
|
|
|
|
|
|
|
2129
|
|
|
|
|
|
|
} else { |
|
2130
|
|
|
|
|
|
|
|
|
2131
|
|
|
|
|
|
|
# get base context |
|
2132
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}; |
|
2133
|
|
|
|
|
|
|
|
|
2134
|
|
|
|
|
|
|
# get added context |
|
2135
|
0
|
0
|
|
|
|
0
|
$added = defined($hash->{'added'}) ? $hash->{'added'} : $context; |
|
2136
|
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
} |
|
2138
|
|
|
|
|
|
|
|
|
2139
|
|
|
|
|
|
|
# get colorimetry flag |
|
2140
|
0
|
|
0
|
|
|
0
|
$cf = defined($hash->{'illuminant'}) || defined($hash->{'observer'}) || defined($hash->{'cat'}); |
|
2141
|
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
# return column slice if no colorimetry and XYZ data already exists |
|
2143
|
0
|
0
|
0
|
|
|
0
|
return($cols) if (! $cf && ($cols = _cols($self, map {defined($added) ? "$added|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)))); |
|
|
0
|
0
|
|
|
|
0
|
|
|
2144
|
|
|
|
|
|
|
|
|
2145
|
|
|
|
|
|
|
# if spectral data exists |
|
2146
|
0
|
0
|
|
|
|
0
|
if (test($self, 'SPECTRAL', $context)) { |
|
|
|
0
|
|
|
|
|
|
|
2147
|
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
# get spectral slice |
|
2149
|
0
|
|
|
|
|
0
|
$spec = spectral($self, {'context' => $context}); |
|
2150
|
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
# add chart wavelength range to hash |
|
2152
|
0
|
|
|
|
|
0
|
$hash->{'range'} = nm($self, {'context' => $context}); |
|
2153
|
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
# make empty 'Color.pm' object |
|
2155
|
0
|
|
|
|
|
0
|
$color = ICC::Support::Color->new(); |
|
2156
|
|
|
|
|
|
|
|
|
2157
|
|
|
|
|
|
|
# if illuminant is defined, an array reference |
|
2158
|
0
|
0
|
0
|
|
|
0
|
if (defined($hash->{'illuminant'}) && ref($hash->{'illuminant'}) eq 'ARRAY') { |
|
2159
|
|
|
|
|
|
|
|
|
2160
|
|
|
|
|
|
|
# if illuminant is ['DATA'] (ProfileMaker convention) |
|
2161
|
0
|
0
|
0
|
|
|
0
|
if (defined($hash->{'illuminant'}->[0]) && $hash->{'illuminant'}->[0] eq 'DATA') { |
|
2162
|
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
# verify chart object contains illuminant data |
|
2164
|
0
|
0
|
0
|
|
|
0
|
(defined($self->[0]{'illuminant'}) && ref($self->[0]{'illuminant'}) eq 'ARRAY') or croak('no illuminant data'); |
|
2165
|
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
# make new chart object from illuminant data |
|
2167
|
0
|
|
|
|
|
0
|
$illum = ICC::Support::Chart->new($self->[0]{'illuminant'}); |
|
2168
|
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
# get spectral values |
|
2170
|
0
|
0
|
|
|
|
0
|
($specv = $illum->spectral([1])->[0]) or croak('illuminant chart has no spectral data'); |
|
2171
|
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
# get wavelength range |
|
2173
|
0
|
|
|
|
|
0
|
$nm = $illum->nm(); |
|
2174
|
|
|
|
|
|
|
|
|
2175
|
|
|
|
|
|
|
# update 'illuminant' value in hash |
|
2176
|
0
|
|
|
|
|
0
|
$hash->{'illuminant'} = [$nm, $specv]; |
|
2177
|
|
|
|
|
|
|
|
|
2178
|
|
|
|
|
|
|
} |
|
2179
|
|
|
|
|
|
|
|
|
2180
|
|
|
|
|
|
|
# initialize object for CIE method |
|
2181
|
0
|
|
|
|
|
0
|
ICC::Support::Color::_cie($color, $hash); |
|
2182
|
|
|
|
|
|
|
|
|
2183
|
|
|
|
|
|
|
} else { |
|
2184
|
|
|
|
|
|
|
|
|
2185
|
|
|
|
|
|
|
# initialize object for ASTM method |
|
2186
|
0
|
|
|
|
|
0
|
ICC::Support::Color::_astm($color, $hash); |
|
2187
|
|
|
|
|
|
|
|
|
2188
|
|
|
|
|
|
|
} |
|
2189
|
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
# if 'context' and 'added' keys are undefined, and spectral source has context |
|
2191
|
0
|
0
|
0
|
|
|
0
|
if (! defined($added) && $self->[1][0][$spec->[0]] =~ m/^(.*)\|/) { |
|
2192
|
|
|
|
|
|
|
|
|
2193
|
|
|
|
|
|
|
# set 'added' to spectral context |
|
2194
|
0
|
|
|
|
|
0
|
$added = $1; |
|
2195
|
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
} |
|
2197
|
|
|
|
|
|
|
|
|
2198
|
|
|
|
|
|
|
# add XYZ columns slice |
|
2199
|
0
|
0
|
|
|
|
0
|
$cols = add_fmt($self, map {defined($added) ? "$added|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)); |
|
|
0
|
|
|
|
|
0
|
|
|
2200
|
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
# set origin |
|
2202
|
0
|
|
|
|
|
0
|
@{$self->[2][0]}[@{$cols}] = ($spec) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2203
|
|
|
|
|
|
|
|
|
2204
|
|
|
|
|
|
|
# save reference to Color.pm object |
|
2205
|
0
|
|
|
|
|
0
|
@{$self->[2][1]}[@{$cols}] = ($color) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2206
|
|
|
|
|
|
|
|
|
2207
|
|
|
|
|
|
|
# if chromatic adaptation transform (cat) is specified |
|
2208
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'cat'})) { |
|
2209
|
|
|
|
|
|
|
|
|
2210
|
|
|
|
|
|
|
# if cat is 'matf' object |
|
2211
|
0
|
0
|
|
|
|
0
|
if (UNIVERSAL::isa($hash->{'cat'}, 'ICC::Profile::matf')) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
|
|
2213
|
|
|
|
|
|
|
# use it |
|
2214
|
0
|
|
|
|
|
0
|
$cat = $hash->{'cat'}; |
|
2215
|
|
|
|
|
|
|
|
|
2216
|
|
|
|
|
|
|
# if cat is 'bradford' |
|
2217
|
|
|
|
|
|
|
} elsif ($hash->{'cat'} eq 'bradford') { |
|
2218
|
|
|
|
|
|
|
|
|
2219
|
|
|
|
|
|
|
# make 'bradford' object |
|
2220
|
0
|
|
|
|
|
0
|
$cat = ICC::Profile::matf->bradford($color->iwtpt()); |
|
2221
|
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
# if cat is 'cat02' |
|
2223
|
|
|
|
|
|
|
} elsif ($hash->{'cat'} eq 'cat02') { |
|
2224
|
|
|
|
|
|
|
|
|
2225
|
|
|
|
|
|
|
# make 'cat02' object |
|
2226
|
0
|
|
|
|
|
0
|
$cat = ICC::Profile::matf->cat02($color->iwtpt()); |
|
2227
|
|
|
|
|
|
|
|
|
2228
|
|
|
|
|
|
|
# if cat is 'quasi' |
|
2229
|
|
|
|
|
|
|
} elsif ($hash->{'cat'} eq 'quasi') { |
|
2230
|
|
|
|
|
|
|
|
|
2231
|
|
|
|
|
|
|
# make 'quasi' object |
|
2232
|
0
|
|
|
|
|
0
|
$cat = ICC::Profile::matf->quasi($color->iwtpt()); |
|
2233
|
|
|
|
|
|
|
|
|
2234
|
|
|
|
|
|
|
} else { |
|
2235
|
|
|
|
|
|
|
|
|
2236
|
|
|
|
|
|
|
# warn |
|
2237
|
0
|
|
|
|
|
0
|
warn('invalid cat type'); |
|
2238
|
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
} |
|
2240
|
|
|
|
|
|
|
|
|
2241
|
|
|
|
|
|
|
} |
|
2242
|
|
|
|
|
|
|
|
|
2243
|
|
|
|
|
|
|
# if cat defined |
|
2244
|
0
|
0
|
|
|
|
0
|
if (defined($cat)) { |
|
2245
|
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
# save cat reference |
|
2247
|
0
|
|
|
|
|
0
|
@{$self->[2][2]}[@{$cols}] = ($cat) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2248
|
|
|
|
|
|
|
|
|
2249
|
|
|
|
|
|
|
} else { |
|
2250
|
|
|
|
|
|
|
|
|
2251
|
|
|
|
|
|
|
# save white point |
|
2252
|
0
|
|
|
|
|
0
|
@{$self->[2][2]}[@{$cols}] = @{$color->iwtpt()}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2253
|
|
|
|
|
|
|
|
|
2254
|
|
|
|
|
|
|
} |
|
2255
|
|
|
|
|
|
|
|
|
2256
|
|
|
|
|
|
|
# save colorimetry hash |
|
2257
|
0
|
0
|
|
|
|
0
|
@{$self->[2][6]}[@{$cols}] = ({map {defined($hash->{$_}) ? ($_, $hash->{$_}) : ()} qw(illuminant observer bandpass method ibandpass imethod oba cat increment range encoding)}) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2258
|
|
|
|
|
|
|
|
|
2259
|
|
|
|
|
|
|
# for each sample |
|
2260
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2261
|
|
|
|
|
|
|
|
|
2262
|
|
|
|
|
|
|
# get spectral slice |
|
2263
|
0
|
|
|
|
|
0
|
$spectral->[$i - 1] = [@{$self->[1][$i]}[@{$spec}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2264
|
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
} |
|
2266
|
|
|
|
|
|
|
|
|
2267
|
|
|
|
|
|
|
# transform to XYZ data (hash may contain 'encoding' key) |
|
2268
|
0
|
|
|
|
|
0
|
$xyz = ICC::Support::Color::_trans2($color, $spectral, $hash); |
|
2269
|
|
|
|
|
|
|
|
|
2270
|
|
|
|
|
|
|
# add OBA effect, if enabled |
|
2271
|
0
|
0
|
|
|
|
0
|
_add_oba($self, $spec1, $spec2, $xyz, $oba, $hash) if $oba; |
|
2272
|
|
|
|
|
|
|
|
|
2273
|
|
|
|
|
|
|
# for each sample |
|
2274
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2275
|
|
|
|
|
|
|
|
|
2276
|
|
|
|
|
|
|
# if cat defined |
|
2277
|
0
|
0
|
|
|
|
0
|
if (defined($cat)) { |
|
2278
|
|
|
|
|
|
|
|
|
2279
|
|
|
|
|
|
|
# set XYZ slice with cat |
|
2280
|
0
|
|
|
|
|
0
|
@{$self->[1][$i]}[@{$cols}] = ICC::Profile::matf::_trans0($cat, @{$xyz->[$i - 1]}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2281
|
|
|
|
|
|
|
|
|
2282
|
|
|
|
|
|
|
} else { |
|
2283
|
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
# set XYZ slice |
|
2285
|
0
|
|
|
|
|
0
|
@{$self->[1][$i]}[@{$cols}] = @{$xyz->[$i - 1]}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2286
|
|
|
|
|
|
|
|
|
2287
|
|
|
|
|
|
|
} |
|
2288
|
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
} |
|
2290
|
|
|
|
|
|
|
|
|
2291
|
|
|
|
|
|
|
# if L*a*b* data exists |
|
2292
|
|
|
|
|
|
|
} elsif (test($self, 'LAB', $context)) { |
|
2293
|
|
|
|
|
|
|
|
|
2294
|
|
|
|
|
|
|
# warn if illuminant is specified |
|
2295
|
0
|
0
|
|
|
|
0
|
(! defined($hash->{'illuminant'})) || warn('illuminant specified but no spectral data!'); |
|
2296
|
|
|
|
|
|
|
|
|
2297
|
|
|
|
|
|
|
# get L*a*b* slice |
|
2298
|
0
|
0
|
|
|
|
0
|
$Lab = cols($self, map {defined($context) ? "$context|$_" : $_} qw(LAB_L LAB_A LAB_B)); |
|
|
0
|
|
|
|
|
0
|
|
|
2299
|
|
|
|
|
|
|
|
|
2300
|
|
|
|
|
|
|
# if 'context' and 'added' keys are undefined, and L*a*b* source has context |
|
2301
|
0
|
0
|
0
|
|
|
0
|
if (! defined($added) && $self->[1][0][$Lab->[0]] =~ m/^(.*)\|/) { |
|
2302
|
|
|
|
|
|
|
|
|
2303
|
|
|
|
|
|
|
# set 'added' to L*a*b* context |
|
2304
|
0
|
|
|
|
|
0
|
$added = $1; |
|
2305
|
|
|
|
|
|
|
|
|
2306
|
|
|
|
|
|
|
} |
|
2307
|
|
|
|
|
|
|
|
|
2308
|
|
|
|
|
|
|
# get L*a*b* white point values |
|
2309
|
0
|
|
|
|
|
0
|
@WPlab = @{$self->[2][2]}[@{$Lab}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2310
|
|
|
|
|
|
|
|
|
2311
|
|
|
|
|
|
|
# use scalar values or D50 |
|
2312
|
0
|
0
|
0
|
|
|
0
|
$WPxyz = (3 == grep {defined() && ! ref() && $_ > 0} @WPlab) ? [@WPlab] : ICC::Shared::D50; |
|
|
0
|
0
|
|
|
|
0
|
|
|
2313
|
|
|
|
|
|
|
|
|
2314
|
|
|
|
|
|
|
# add XYZ columns slice |
|
2315
|
0
|
0
|
|
|
|
0
|
$cols = add_fmt($self, map {defined($added) ? "$added|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)); |
|
|
0
|
|
|
|
|
0
|
|
|
2316
|
|
|
|
|
|
|
|
|
2317
|
|
|
|
|
|
|
# set origin |
|
2318
|
0
|
|
|
|
|
0
|
@{$self->[2][0]}[@{$cols}] = ($Lab) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2319
|
|
|
|
|
|
|
|
|
2320
|
|
|
|
|
|
|
# save illuminant white point |
|
2321
|
0
|
|
|
|
|
0
|
@{$self->[2][2]}[@{$cols}] = @{$WPxyz}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2322
|
|
|
|
|
|
|
|
|
2323
|
|
|
|
|
|
|
# for each sample |
|
2324
|
0
|
|
|
|
|
0
|
for my $s (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2325
|
|
|
|
|
|
|
|
|
2326
|
|
|
|
|
|
|
# compute XYZ values from L*a*b* values |
|
2327
|
0
|
|
|
|
|
0
|
@{$self->[1][$s]}[@{$cols}] = ICC::Shared::_Lab2XYZ(@{$self->[1][$s]}[@{$Lab}], $WPxyz); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2328
|
|
|
|
|
|
|
|
|
2329
|
|
|
|
|
|
|
} |
|
2330
|
|
|
|
|
|
|
|
|
2331
|
|
|
|
|
|
|
} else { |
|
2332
|
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
# warn |
|
2334
|
0
|
|
|
|
|
0
|
warn('spectral or L*a*b* data is required'); |
|
2335
|
|
|
|
|
|
|
|
|
2336
|
|
|
|
|
|
|
# return empty |
|
2337
|
0
|
|
|
|
|
0
|
return(); |
|
2338
|
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
} |
|
2340
|
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
# return column slice |
|
2342
|
0
|
|
|
|
|
0
|
return($cols); |
|
2343
|
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
} |
|
2345
|
|
|
|
|
|
|
|
|
2346
|
|
|
|
|
|
|
# append ISO 5-3 density data to data array |
|
2347
|
|
|
|
|
|
|
# computed from spectral data only |
|
2348
|
|
|
|
|
|
|
# if density data already exists, return that slice |
|
2349
|
|
|
|
|
|
|
# default status is 'T', encoding is 'density' |
|
2350
|
|
|
|
|
|
|
# parameters: ([hash]) |
|
2351
|
|
|
|
|
|
|
# returns: (column_slice) |
|
2352
|
|
|
|
|
|
|
sub add_density { |
|
2353
|
|
|
|
|
|
|
|
|
2354
|
|
|
|
|
|
|
# get parameters |
|
2355
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
2356
|
|
|
|
|
|
|
|
|
2357
|
|
|
|
|
|
|
# local variables |
|
2358
|
0
|
|
|
|
|
0
|
my ($oba, $spec1, $spec2, $context, $added); |
|
2359
|
0
|
|
|
|
|
0
|
my ($encode, $fp, $cols); |
|
2360
|
0
|
|
|
|
|
0
|
my ($spec, $temp, $color, $spectral, $rgbv); |
|
2361
|
|
|
|
|
|
|
|
|
2362
|
|
|
|
|
|
|
# if 'oba' defined |
|
2363
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'oba'})) { |
|
2364
|
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
# get oba factor |
|
2366
|
0
|
|
|
|
|
0
|
$oba = $hash->{'oba'}; |
|
2367
|
|
|
|
|
|
|
|
|
2368
|
|
|
|
|
|
|
# if 'context' defined |
|
2369
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'context'})) { |
|
2370
|
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
# if context an array reference containing two scalars |
|
2372
|
0
|
0
|
0
|
|
|
0
|
if (ref($hash->{'context'}) eq 'ARRAY' && ! ref($hash->{'context'}->[0]) && ! ref($hash->{'context'}->[1])) { |
|
|
|
|
0
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
|
|
2374
|
|
|
|
|
|
|
# get specified 'M1' spectral slice |
|
2375
|
0
|
|
|
|
|
0
|
$spec1 = spectral($self, {'context' => $hash->{'context'}->[0]}); |
|
2376
|
|
|
|
|
|
|
|
|
2377
|
|
|
|
|
|
|
# get specified 'M2' spectral slice |
|
2378
|
0
|
|
|
|
|
0
|
$spec2 = spectral($self, {'context' => $hash->{'context'}->[1]}); |
|
2379
|
|
|
|
|
|
|
|
|
2380
|
|
|
|
|
|
|
# use specified 'M2' context |
|
2381
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}->[1]; |
|
2382
|
|
|
|
|
|
|
|
|
2383
|
|
|
|
|
|
|
} else { |
|
2384
|
|
|
|
|
|
|
|
|
2385
|
|
|
|
|
|
|
# warn |
|
2386
|
0
|
|
|
|
|
0
|
warn('OBA context is an array reference containing M1 and M2 contexts'); |
|
2387
|
|
|
|
|
|
|
|
|
2388
|
|
|
|
|
|
|
# return empty |
|
2389
|
0
|
|
|
|
|
0
|
return(); |
|
2390
|
|
|
|
|
|
|
|
|
2391
|
|
|
|
|
|
|
} |
|
2392
|
|
|
|
|
|
|
|
|
2393
|
|
|
|
|
|
|
} else { |
|
2394
|
|
|
|
|
|
|
|
|
2395
|
|
|
|
|
|
|
# get spectral slice using standard 'M1' context |
|
2396
|
0
|
|
|
|
|
0
|
$spec1 = spectral($self, {'context' => 'M1_Measurement'}); |
|
2397
|
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
# get spectral slice using standard 'M2' context |
|
2399
|
0
|
|
|
|
|
0
|
$spec2 = spectral($self, {'context' => 'M2_Measurement'}); |
|
2400
|
|
|
|
|
|
|
|
|
2401
|
|
|
|
|
|
|
# use standard 'M2' context |
|
2402
|
0
|
|
|
|
|
0
|
$context = 'M2_Measurement'; |
|
2403
|
|
|
|
|
|
|
|
|
2404
|
|
|
|
|
|
|
} |
|
2405
|
|
|
|
|
|
|
|
|
2406
|
|
|
|
|
|
|
# verify spectral slices |
|
2407
|
0
|
0
|
0
|
|
|
0
|
if (! $spec1 || ! $spec2 || $#{$spec1} != $#{$spec2}) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2408
|
|
|
|
|
|
|
|
|
2409
|
|
|
|
|
|
|
# warn |
|
2410
|
0
|
|
|
|
|
0
|
warn('M1 and M2 spectral data required for OBA effect'); |
|
2411
|
|
|
|
|
|
|
|
|
2412
|
|
|
|
|
|
|
# return empty |
|
2413
|
0
|
|
|
|
|
0
|
return(); |
|
2414
|
|
|
|
|
|
|
|
|
2415
|
|
|
|
|
|
|
} |
|
2416
|
|
|
|
|
|
|
|
|
2417
|
|
|
|
|
|
|
# get added context |
|
2418
|
0
|
0
|
|
|
|
0
|
$added = defined($hash->{'added'}) ? $hash->{'added'} : 'OBA'; |
|
2419
|
|
|
|
|
|
|
|
|
2420
|
|
|
|
|
|
|
} else { |
|
2421
|
|
|
|
|
|
|
|
|
2422
|
|
|
|
|
|
|
# get base context |
|
2423
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}; |
|
2424
|
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
# get added context |
|
2426
|
0
|
0
|
|
|
|
0
|
$added = defined($hash->{'added'}) ? $hash->{'added'} : $context; |
|
2427
|
|
|
|
|
|
|
|
|
2428
|
|
|
|
|
|
|
} |
|
2429
|
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
# get encoding |
|
2431
|
0
|
|
0
|
|
|
0
|
$encode = $hash->{'encoding'} // 'density'; |
|
2432
|
|
|
|
|
|
|
|
|
2433
|
|
|
|
|
|
|
# if invalid encoding |
|
2434
|
0
|
0
|
0
|
|
|
0
|
if ($encode ne 'density' && $encode ne 'linear') { |
|
2435
|
|
|
|
|
|
|
|
|
2436
|
|
|
|
|
|
|
# warn |
|
2437
|
0
|
|
|
|
|
0
|
warn('invalid density encoding, using \'density\''); |
|
2438
|
|
|
|
|
|
|
|
|
2439
|
|
|
|
|
|
|
# set encoding |
|
2440
|
0
|
|
|
|
|
0
|
$encode = 'density'; |
|
2441
|
|
|
|
|
|
|
|
|
2442
|
|
|
|
|
|
|
} |
|
2443
|
|
|
|
|
|
|
|
|
2444
|
|
|
|
|
|
|
# set format prefix |
|
2445
|
0
|
0
|
|
|
|
0
|
$fp = $encode eq 'density' ? 'D' : 'R'; |
|
2446
|
|
|
|
|
|
|
|
|
2447
|
|
|
|
|
|
|
# return column slice if density/reflectance data already exists |
|
2448
|
0
|
0
|
|
|
|
0
|
return($cols) if ($cols = cols($self, map {defined($added) ? "$added|$fp$_" : "$fp$_"} qw(_RED _GREEN _BLUE _VIS))); |
|
|
0
|
0
|
|
|
|
0
|
|
|
2449
|
|
|
|
|
|
|
|
|
2450
|
|
|
|
|
|
|
# if spectral data |
|
2451
|
0
|
0
|
|
|
|
0
|
if (test($self, 'SPECTRAL', $context)) { |
|
2452
|
|
|
|
|
|
|
|
|
2453
|
|
|
|
|
|
|
# get spectral slice |
|
2454
|
0
|
|
|
|
|
0
|
$spec = spectral($self, $hash); |
|
2455
|
|
|
|
|
|
|
|
|
2456
|
|
|
|
|
|
|
# make copy of hash |
|
2457
|
0
|
|
|
|
|
0
|
$temp = Storable::dclone($hash); |
|
2458
|
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
# add chart wavelength range to hash |
|
2460
|
0
|
|
|
|
|
0
|
$temp->{'range'} = nm($self, $hash); |
|
2461
|
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
# make empty 'Color.pm' object |
|
2463
|
0
|
|
|
|
|
0
|
$color = ICC::Support::Color->new(); |
|
2464
|
|
|
|
|
|
|
|
|
2465
|
|
|
|
|
|
|
# initialize object for ISO 5-3 method |
|
2466
|
0
|
|
|
|
|
0
|
ICC::Support::Color::_iso($color, $temp); |
|
2467
|
|
|
|
|
|
|
|
|
2468
|
|
|
|
|
|
|
# if 'context' and 'added' keys are undefined, and spectral source has context |
|
2469
|
0
|
0
|
0
|
|
|
0
|
if (! defined($added) && $self->[1][0][$spec->[0]] =~ m/^(.*)\|/) { |
|
2470
|
|
|
|
|
|
|
|
|
2471
|
|
|
|
|
|
|
# set 'added' to spectral context |
|
2472
|
0
|
|
|
|
|
0
|
$added = $1; |
|
2473
|
|
|
|
|
|
|
|
|
2474
|
|
|
|
|
|
|
} |
|
2475
|
|
|
|
|
|
|
|
|
2476
|
|
|
|
|
|
|
# add density/reflectance columns slice |
|
2477
|
0
|
0
|
|
|
|
0
|
$cols = add_fmt($self, map {defined($added) ? "$added|$fp$_" : "$fp$_"} qw(_RED _GREEN _BLUE _VIS)); |
|
|
0
|
|
|
|
|
0
|
|
|
2478
|
|
|
|
|
|
|
|
|
2479
|
|
|
|
|
|
|
# set origin |
|
2480
|
0
|
|
|
|
|
0
|
@{$self->[2][0]}[@{$cols}] = ($spec) x 4; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2481
|
|
|
|
|
|
|
|
|
2482
|
|
|
|
|
|
|
# save reference to Color.pm object |
|
2483
|
0
|
|
|
|
|
0
|
@{$self->[2][1]}[@{$cols}] = ($color) x 4; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2484
|
|
|
|
|
|
|
|
|
2485
|
|
|
|
|
|
|
# save colorimetry hash |
|
2486
|
0
|
0
|
|
|
|
0
|
@{$self->[2][6]}[@{$cols}] = ({map {defined($temp->{$_}) ? ($_, $temp->{$_}) : ()} qw(status increment range encoding)}) x 4; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2487
|
|
|
|
|
|
|
|
|
2488
|
|
|
|
|
|
|
# for each sample |
|
2489
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2490
|
|
|
|
|
|
|
|
|
2491
|
|
|
|
|
|
|
# if oba defined |
|
2492
|
0
|
0
|
|
|
|
0
|
if (defined($oba)) { |
|
2493
|
|
|
|
|
|
|
|
|
2494
|
|
|
|
|
|
|
# for each wavelength |
|
2495
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$spec1}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2496
|
|
|
|
|
|
|
|
|
2497
|
|
|
|
|
|
|
# compute blended spectral value |
|
2498
|
0
|
|
|
|
|
0
|
$spectral->[$i - 1][$j] = $oba * $self->[1][$i][$spec1->[$j]] + (1 - $oba) * $self->[1][$i][$spec2->[$j]]; |
|
2499
|
|
|
|
|
|
|
|
|
2500
|
|
|
|
|
|
|
} |
|
2501
|
|
|
|
|
|
|
|
|
2502
|
|
|
|
|
|
|
} else { |
|
2503
|
|
|
|
|
|
|
|
|
2504
|
|
|
|
|
|
|
# get spectral slice |
|
2505
|
0
|
|
|
|
|
0
|
$spectral->[$i - 1] = [@{$self->[1][$i]}[@{$spec}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2506
|
|
|
|
|
|
|
|
|
2507
|
|
|
|
|
|
|
} |
|
2508
|
|
|
|
|
|
|
|
|
2509
|
|
|
|
|
|
|
} |
|
2510
|
|
|
|
|
|
|
|
|
2511
|
|
|
|
|
|
|
# set encoding |
|
2512
|
0
|
|
|
|
|
0
|
$temp->{'encoding'} = $encode; |
|
2513
|
|
|
|
|
|
|
|
|
2514
|
|
|
|
|
|
|
# transform to density/reflectance data (per encoding) |
|
2515
|
0
|
|
|
|
|
0
|
$rgbv = ICC::Support::Color::_trans2($color, $spectral, $temp); |
|
2516
|
|
|
|
|
|
|
|
|
2517
|
|
|
|
|
|
|
# for each sample |
|
2518
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2519
|
|
|
|
|
|
|
|
|
2520
|
|
|
|
|
|
|
# set data values |
|
2521
|
0
|
|
|
|
|
0
|
@{$self->[1][$i]}[@{$cols}] = @{$rgbv->[$i - 1]}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2522
|
|
|
|
|
|
|
|
|
2523
|
|
|
|
|
|
|
} |
|
2524
|
|
|
|
|
|
|
|
|
2525
|
|
|
|
|
|
|
} else { |
|
2526
|
|
|
|
|
|
|
|
|
2527
|
|
|
|
|
|
|
# warn |
|
2528
|
0
|
|
|
|
|
0
|
warn('spectral data is required'); |
|
2529
|
|
|
|
|
|
|
|
|
2530
|
|
|
|
|
|
|
# return empty |
|
2531
|
0
|
|
|
|
|
0
|
return(); |
|
2532
|
|
|
|
|
|
|
|
|
2533
|
|
|
|
|
|
|
} |
|
2534
|
|
|
|
|
|
|
|
|
2535
|
|
|
|
|
|
|
# return column slice |
|
2536
|
0
|
|
|
|
|
0
|
return($cols); |
|
2537
|
|
|
|
|
|
|
|
|
2538
|
|
|
|
|
|
|
} |
|
2539
|
|
|
|
|
|
|
|
|
2540
|
|
|
|
|
|
|
# add computed values to data array |
|
2541
|
|
|
|
|
|
|
# processing is done by a user-defined function (udf) |
|
2542
|
|
|
|
|
|
|
# data groups are defined by one or more column slice(s) |
|
2543
|
|
|
|
|
|
|
# supported hash keys: 'element', 'sample', 'device', 'rows', 'start', 'added' |
|
2544
|
|
|
|
|
|
|
# either an 'element' udf or a 'sample' udf are required, but not both |
|
2545
|
|
|
|
|
|
|
# an 'element' udf computes a single value from single slice value(s) |
|
2546
|
|
|
|
|
|
|
# a 'sample' udf computes all values at once from slice value array(s) |
|
2547
|
|
|
|
|
|
|
# setting the 'device' flag converts RGB/CMYK/nCLR values to device values |
|
2548
|
|
|
|
|
|
|
# the 'rows' parameter is the row slice computed, default is all rows |
|
2549
|
|
|
|
|
|
|
# the 'start' parameter is the first column computed, default is to append |
|
2550
|
|
|
|
|
|
|
# the 'added' parameter may be a scalar or an array reference |
|
2551
|
|
|
|
|
|
|
# an 'added' scalar will be used as a context prefix |
|
2552
|
|
|
|
|
|
|
# an 'added' array must be the same size as the columns added |
|
2553
|
|
|
|
|
|
|
# parameters: (column_slice_0, column_slice_1, ... hash) |
|
2554
|
|
|
|
|
|
|
# returns: (added_column_slice) |
|
2555
|
|
|
|
|
|
|
sub add_udf { |
|
2556
|
|
|
|
|
|
|
|
|
2557
|
|
|
|
|
|
|
# local variables |
|
2558
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash, @cs, $rows, $m, $n, @div, $udfe, $udfs); |
|
2559
|
0
|
|
|
|
|
0
|
my (@p, @u, @s, $cx, $added); |
|
2560
|
|
|
|
|
|
|
|
|
2561
|
|
|
|
|
|
|
# get object reference |
|
2562
|
0
|
|
|
|
|
0
|
$self = shift(); |
|
2563
|
|
|
|
|
|
|
|
|
2564
|
|
|
|
|
|
|
# get parameter hash |
|
2565
|
0
|
|
|
|
|
0
|
$hash = pop(); |
|
2566
|
|
|
|
|
|
|
|
|
2567
|
|
|
|
|
|
|
# verify a hash reference |
|
2568
|
0
|
0
|
|
|
|
0
|
(ref($hash) eq 'HASH') or croak('last parameter must be a hash reference'); |
|
2569
|
|
|
|
|
|
|
|
|
2570
|
|
|
|
|
|
|
# verify number of slices |
|
2571
|
0
|
0
|
|
|
|
0
|
(@cs = @_) or croak('one or more column slices are required'); |
|
2572
|
|
|
|
|
|
|
|
|
2573
|
|
|
|
|
|
|
# get row slice, all rows by default |
|
2574
|
0
|
0
|
|
|
|
0
|
$rows = defined($hash->{'rows'}) ? $hash->{'rows'} : []; |
|
2575
|
|
|
|
|
|
|
|
|
2576
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
2577
|
0
|
0
|
0
|
|
|
0
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
2578
|
|
|
|
|
|
|
|
|
2579
|
|
|
|
|
|
|
# use all rows |
|
2580
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
2581
|
|
|
|
|
|
|
|
|
2582
|
|
|
|
|
|
|
} else { |
|
2583
|
|
|
|
|
|
|
|
|
2584
|
|
|
|
|
|
|
# flatten row slice |
|
2585
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
2586
|
|
|
|
|
|
|
|
|
2587
|
|
|
|
|
|
|
# verify row slice contents |
|
2588
|
0
|
0
|
0
|
|
|
0
|
(@{$rows} == grep {Scalar::Util::looks_like_number($_) && int($_) == $_ && $_ > 0 && $_ <= $#{$self->[1]}} @{$rows}) or croak('invalid row slice'); |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2589
|
|
|
|
|
|
|
|
|
2590
|
|
|
|
|
|
|
} |
|
2591
|
|
|
|
|
|
|
|
|
2592
|
|
|
|
|
|
|
# get starting column, append by default |
|
2593
|
0
|
0
|
|
|
|
0
|
$n = defined($hash->{'start'}) ? $hash->{'start'} : $#{$self->[1][0]} + 1; |
|
|
0
|
|
|
|
|
0
|
|
|
2594
|
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
# if an array reference (slice), use the first value |
|
2596
|
0
|
0
|
|
|
|
0
|
$n = $n->[0] if (ref($n) eq 'ARRAY'); |
|
2597
|
|
|
|
|
|
|
|
|
2598
|
|
|
|
|
|
|
# verify starting column |
|
2599
|
0
|
0
|
0
|
|
|
0
|
(Scalar::Util::looks_like_number($n) && int($n) eq $n && $n >= 0) or croak('invalid \'start\' parameter'); |
|
|
|
|
0
|
|
|
|
|
|
2600
|
|
|
|
|
|
|
|
|
2601
|
|
|
|
|
|
|
# if 'device' flag |
|
2602
|
0
|
0
|
|
|
|
0
|
if ($hash->{'device'}) { |
|
2603
|
|
|
|
|
|
|
|
|
2604
|
|
|
|
|
|
|
# for each data format |
|
2605
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1][0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2606
|
|
|
|
|
|
|
|
|
2607
|
|
|
|
|
|
|
# set divisor to 255 for RGB data |
|
2608
|
0
|
0
|
|
|
|
0
|
$div[$i] = 255 if ($self->[1][0][$i] =~ m/RGB_[RGB]$/); |
|
2609
|
|
|
|
|
|
|
|
|
2610
|
|
|
|
|
|
|
# set divisor to 100 for CMYK data |
|
2611
|
0
|
0
|
|
|
|
0
|
$div[$i] = 100 if ($self->[1][0][$i] =~ m/CMYK_[CMYK]$/); |
|
2612
|
|
|
|
|
|
|
|
|
2613
|
|
|
|
|
|
|
# set divisor to 100 for nCLR data |
|
2614
|
0
|
0
|
|
|
|
0
|
$div[$i] = 100 if ($self->[1][0][$i] =~ m/(?:[2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/); |
|
2615
|
|
|
|
|
|
|
} |
|
2616
|
|
|
|
|
|
|
|
|
2617
|
|
|
|
|
|
|
} |
|
2618
|
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
# get udf CODE refs |
|
2620
|
0
|
|
|
|
|
0
|
$udfe = $hash->{'element'}; |
|
2621
|
0
|
|
|
|
|
0
|
$udfs = $hash->{'sample'}; |
|
2622
|
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
# if both udfs defined |
|
2624
|
0
|
0
|
0
|
|
|
0
|
if (defined($udfe) && defined($udfs)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
|
|
2626
|
|
|
|
|
|
|
# error |
|
2627
|
0
|
|
|
|
|
0
|
croak('both \'element\' and \'sample\' udfs are defined'); |
|
2628
|
|
|
|
|
|
|
|
|
2629
|
|
|
|
|
|
|
# if 'element' udf defined |
|
2630
|
|
|
|
|
|
|
} elsif (defined($udfe)) { |
|
2631
|
|
|
|
|
|
|
|
|
2632
|
|
|
|
|
|
|
# verify udf is a code reference |
|
2633
|
0
|
0
|
|
|
|
0
|
(ref($udfe) eq 'CODE') or croak('\'element\' udf is not a CODE reference'); |
|
2634
|
|
|
|
|
|
|
|
|
2635
|
|
|
|
|
|
|
# for each parameter |
|
2636
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#cs) { |
|
2637
|
|
|
|
|
|
|
|
|
2638
|
|
|
|
|
|
|
# if an array reference |
|
2639
|
0
|
0
|
|
|
|
0
|
if (ref($cs[$i]) eq 'ARRAY') { |
|
|
|
0
|
|
|
|
|
|
|
2640
|
|
|
|
|
|
|
|
|
2641
|
|
|
|
|
|
|
# if first slice |
|
2642
|
0
|
0
|
|
|
|
0
|
if (! defined($m)) { |
|
2643
|
|
|
|
|
|
|
|
|
2644
|
|
|
|
|
|
|
# get upper index |
|
2645
|
0
|
|
|
|
|
0
|
$m = $#{$cs[0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
2646
|
|
|
|
|
|
|
|
|
2647
|
|
|
|
|
|
|
# compute added slice |
|
2648
|
0
|
|
|
|
|
0
|
@s = ($n .. $n + $m); |
|
2649
|
|
|
|
|
|
|
|
|
2650
|
|
|
|
|
|
|
} else { |
|
2651
|
|
|
|
|
|
|
|
|
2652
|
|
|
|
|
|
|
# verify slice size |
|
2653
|
0
|
0
|
|
|
|
0
|
($#{$cs[$i]} == $m) or croak('column slices are different sizes'); |
|
|
0
|
|
|
|
|
0
|
|
|
2654
|
|
|
|
|
|
|
|
|
2655
|
|
|
|
|
|
|
} |
|
2656
|
|
|
|
|
|
|
|
|
2657
|
|
|
|
|
|
|
# verify a valid column slice |
|
2658
|
0
|
0
|
0
|
|
|
0
|
(ref($cs[$i]) eq 'ARRAY' || @{$cs[$i]} == grep {Scalar::Util::looks_like_number($_) && int($_) == $_ && $_ >= 0 && $_ <= $#{$self->[1][0]}} @{$cs[$i]}) or croak('invalid column slice'); |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2659
|
|
|
|
|
|
|
|
|
2660
|
|
|
|
|
|
|
# if a scalar |
|
2661
|
|
|
|
|
|
|
} elsif (! ref($cs[$i])) { |
|
2662
|
|
|
|
|
|
|
|
|
2663
|
|
|
|
|
|
|
# verify a valid column index |
|
2664
|
0
|
0
|
0
|
|
|
0
|
(Scalar::Util::looks_like_number($cs[$i]) && int($cs[$i]) == $cs[$i] && $cs[$i] >= 0 && $cs[$i] <= $#{$self->[1][0]}) or croak('invalid column index'); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
|
|
0
|
|
|
|
|
|
2665
|
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
} else { |
|
2667
|
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
# error |
|
2669
|
0
|
|
|
|
|
0
|
croak('parameter must be a scalar or an array reference'); |
|
2670
|
|
|
|
|
|
|
|
|
2671
|
|
|
|
|
|
|
} |
|
2672
|
|
|
|
|
|
|
|
|
2673
|
|
|
|
|
|
|
} |
|
2674
|
|
|
|
|
|
|
|
|
2675
|
|
|
|
|
|
|
# verify at least one column slice parameter |
|
2676
|
0
|
0
|
|
|
|
0
|
(defined($m)) or croak('at least one column slice is required'); |
|
2677
|
|
|
|
|
|
|
|
|
2678
|
|
|
|
|
|
|
# for each sample |
|
2679
|
0
|
|
|
|
|
0
|
for my $i (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2680
|
|
|
|
|
|
|
|
|
2681
|
|
|
|
|
|
|
# for each column index |
|
2682
|
0
|
|
|
|
|
0
|
for my $j (0 .. $m) { |
|
2683
|
|
|
|
|
|
|
|
|
2684
|
|
|
|
|
|
|
# for each parameter |
|
2685
|
0
|
|
|
|
|
0
|
for my $k (0 .. $#cs) { |
|
2686
|
|
|
|
|
|
|
|
|
2687
|
|
|
|
|
|
|
# get column index (slice -or- scalar) |
|
2688
|
0
|
0
|
|
|
|
0
|
$cx = (ref($cs[$k]) eq 'ARRAY') ? $cs[$k][$j] : $cs[$k]; |
|
2689
|
|
|
|
|
|
|
|
|
2690
|
|
|
|
|
|
|
# get parameter value |
|
2691
|
0
|
|
|
|
|
0
|
$p[$k] = $self->[1][$i][$cx]; |
|
2692
|
|
|
|
|
|
|
|
|
2693
|
|
|
|
|
|
|
# adjust device values, if divisor defined |
|
2694
|
0
|
0
|
|
|
|
0
|
$p[$k] /= $div[$cx] if defined($div[$cx]); |
|
2695
|
|
|
|
|
|
|
|
|
2696
|
|
|
|
|
|
|
} |
|
2697
|
|
|
|
|
|
|
|
|
2698
|
|
|
|
|
|
|
# call 'element' udf |
|
2699
|
0
|
|
|
|
|
0
|
$self->[1][$i][$n + $j] = &$udfe(@p, $j); |
|
2700
|
|
|
|
|
|
|
|
|
2701
|
|
|
|
|
|
|
} |
|
2702
|
|
|
|
|
|
|
|
|
2703
|
|
|
|
|
|
|
} |
|
2704
|
|
|
|
|
|
|
|
|
2705
|
|
|
|
|
|
|
# if 'sample' udf defined |
|
2706
|
|
|
|
|
|
|
} elsif (defined($udfs)) { |
|
2707
|
|
|
|
|
|
|
|
|
2708
|
|
|
|
|
|
|
# verify udf is a code reference |
|
2709
|
0
|
0
|
|
|
|
0
|
(ref($udfs) eq 'CODE') or croak('\'sample\' udf is not a CODE reference'); |
|
2710
|
|
|
|
|
|
|
|
|
2711
|
|
|
|
|
|
|
# for each parameter |
|
2712
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#cs) { |
|
2713
|
|
|
|
|
|
|
|
|
2714
|
|
|
|
|
|
|
# verify a valid column slice |
|
2715
|
0
|
0
|
0
|
|
|
0
|
(ref($cs[$i]) eq 'ARRAY' || @{$cs[$i]} == grep {Scalar::Util::looks_like_number($_) && int($_) == $_ && $_ >= 0 && $_ <= $#{$self->[1][0]}} @{$cs[$i]}) or croak('invalid column slice'); |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2716
|
|
|
|
|
|
|
|
|
2717
|
|
|
|
|
|
|
} |
|
2718
|
|
|
|
|
|
|
|
|
2719
|
|
|
|
|
|
|
# verify at least one parameter |
|
2720
|
0
|
0
|
|
|
|
0
|
(@cs) or croak('at least one column slice is required'); |
|
2721
|
|
|
|
|
|
|
|
|
2722
|
|
|
|
|
|
|
# for each sample |
|
2723
|
0
|
|
|
|
|
0
|
for my $i (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2724
|
|
|
|
|
|
|
|
|
2725
|
|
|
|
|
|
|
# for each column slice |
|
2726
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#cs) { |
|
2727
|
|
|
|
|
|
|
|
|
2728
|
|
|
|
|
|
|
# for each slice element |
|
2729
|
0
|
|
|
|
|
0
|
for my $k (0 .. $#{$cs[$j]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2730
|
|
|
|
|
|
|
|
|
2731
|
|
|
|
|
|
|
# get column index |
|
2732
|
0
|
|
|
|
|
0
|
$cx = $cs[$j][$k]; |
|
2733
|
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
# get parameter value |
|
2735
|
0
|
|
|
|
|
0
|
$p[$j][$k] = $self->[1][$i][$cx]; |
|
2736
|
|
|
|
|
|
|
|
|
2737
|
|
|
|
|
|
|
# adjust device values, if divisor defined |
|
2738
|
0
|
0
|
|
|
|
0
|
$p[$j][$k] /= $div[$cx] if defined($div[$cx]); |
|
2739
|
|
|
|
|
|
|
|
|
2740
|
|
|
|
|
|
|
} |
|
2741
|
|
|
|
|
|
|
|
|
2742
|
|
|
|
|
|
|
} |
|
2743
|
|
|
|
|
|
|
|
|
2744
|
|
|
|
|
|
|
# if first sample |
|
2745
|
0
|
0
|
|
|
|
0
|
if (! defined($m)) { |
|
2746
|
|
|
|
|
|
|
|
|
2747
|
|
|
|
|
|
|
# call 'sample' udf |
|
2748
|
0
|
|
|
|
|
0
|
@u = &$udfs(@p); |
|
2749
|
|
|
|
|
|
|
|
|
2750
|
|
|
|
|
|
|
# get upper index |
|
2751
|
0
|
|
|
|
|
0
|
$m = $#u; |
|
2752
|
|
|
|
|
|
|
|
|
2753
|
|
|
|
|
|
|
# compute added slice |
|
2754
|
0
|
|
|
|
|
0
|
@s = ($n .. $n + $m); |
|
2755
|
|
|
|
|
|
|
|
|
2756
|
|
|
|
|
|
|
# copy values to object |
|
2757
|
0
|
|
|
|
|
0
|
@{$self->[1][$i]}[@s] = @u; |
|
|
0
|
|
|
|
|
0
|
|
|
2758
|
|
|
|
|
|
|
|
|
2759
|
|
|
|
|
|
|
} else { |
|
2760
|
|
|
|
|
|
|
|
|
2761
|
|
|
|
|
|
|
# call 'sample' udf |
|
2762
|
0
|
|
|
|
|
0
|
@{$self->[1][$i]}[@s] = &$udfs(@p); |
|
|
0
|
|
|
|
|
0
|
|
|
2763
|
|
|
|
|
|
|
|
|
2764
|
|
|
|
|
|
|
} |
|
2765
|
|
|
|
|
|
|
|
|
2766
|
|
|
|
|
|
|
} |
|
2767
|
|
|
|
|
|
|
|
|
2768
|
|
|
|
|
|
|
} else { |
|
2769
|
|
|
|
|
|
|
|
|
2770
|
|
|
|
|
|
|
# error |
|
2771
|
0
|
|
|
|
|
0
|
croak('no udf is defined'); |
|
2772
|
|
|
|
|
|
|
|
|
2773
|
|
|
|
|
|
|
} |
|
2774
|
|
|
|
|
|
|
|
|
2775
|
|
|
|
|
|
|
# get 'added' parameter, default is 'udf', could be undefined |
|
2776
|
0
|
0
|
|
|
|
0
|
$added = exists($hash->{'added'}) ? $hash->{'added'} : 'udf'; |
|
2777
|
|
|
|
|
|
|
|
|
2778
|
|
|
|
|
|
|
# if 'added' is undefined |
|
2779
|
0
|
0
|
0
|
|
|
0
|
if (! defined($added)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
|
|
2781
|
|
|
|
|
|
|
# if 'element' udf -or- size of first column slice equals number of added columns |
|
2782
|
0
|
0
|
0
|
|
|
0
|
if (defined($udfe) || @{$cs[0]} == @s) { |
|
|
0
|
|
|
|
|
0
|
|
|
2783
|
|
|
|
|
|
|
|
|
2784
|
|
|
|
|
|
|
# add data format stripping context from first column slice |
|
2785
|
0
|
|
|
|
|
0
|
@{$self->[1][0]}[@s] = map {m/^(?:.*\|)?(.*)$/; $1} @{$self->[1][0]}[@{$cs[0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2786
|
|
|
|
|
|
|
|
|
2787
|
|
|
|
|
|
|
} else { |
|
2788
|
|
|
|
|
|
|
|
|
2789
|
|
|
|
|
|
|
# add data format as 'colxxx' |
|
2790
|
0
|
|
|
|
|
0
|
@{$self->[1][0]}[@s] = map {"col$_"} @s; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2791
|
|
|
|
|
|
|
|
|
2792
|
|
|
|
|
|
|
} |
|
2793
|
|
|
|
|
|
|
|
|
2794
|
|
|
|
|
|
|
# if 'added' a scalar |
|
2795
|
|
|
|
|
|
|
} elsif (! ref($added)) { |
|
2796
|
|
|
|
|
|
|
|
|
2797
|
|
|
|
|
|
|
# if 'element' udf -or- size of first column slice equals number of added columns |
|
2798
|
0
|
0
|
0
|
|
|
0
|
if (defined($udfe) || @{$cs[0]} == @s) { |
|
|
0
|
|
|
|
|
0
|
|
|
2799
|
|
|
|
|
|
|
|
|
2800
|
|
|
|
|
|
|
# add data format using 'added' as context with first column slice format keys |
|
2801
|
0
|
|
|
|
|
0
|
@{$self->[1][0]}[@s] = map {m/^(?:.*\|)?(.*)$/; "$added|$1"} @{$self->[1][0]}[@{$cs[0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2802
|
|
|
|
|
|
|
|
|
2803
|
|
|
|
|
|
|
} else { |
|
2804
|
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
# add data format using 'added' as context to 'colxxx' |
|
2806
|
0
|
|
|
|
|
0
|
@{$self->[1][0]}[@s] = map {"$added|col$_"} @s; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2807
|
|
|
|
|
|
|
|
|
2808
|
|
|
|
|
|
|
} |
|
2809
|
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
# if 'added' is an array ref and size equals number of added columns |
|
2811
|
0
|
|
|
|
|
0
|
} elsif (ref($added) eq 'ARRAY' && @{$added} == @s) { |
|
2812
|
|
|
|
|
|
|
|
|
2813
|
|
|
|
|
|
|
# add data format using 'added' as array |
|
2814
|
0
|
|
|
|
|
0
|
@{$self->[1][0]}[@s] = @{$added}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2815
|
|
|
|
|
|
|
|
|
2816
|
|
|
|
|
|
|
} else { |
|
2817
|
|
|
|
|
|
|
|
|
2818
|
|
|
|
|
|
|
# error |
|
2819
|
0
|
|
|
|
|
0
|
croak('invalid \'added\' parameter'); |
|
2820
|
|
|
|
|
|
|
|
|
2821
|
|
|
|
|
|
|
} |
|
2822
|
|
|
|
|
|
|
|
|
2823
|
|
|
|
|
|
|
# return added column slice |
|
2824
|
0
|
|
|
|
|
0
|
return([@s]); |
|
2825
|
|
|
|
|
|
|
|
|
2826
|
|
|
|
|
|
|
} |
|
2827
|
|
|
|
|
|
|
|
|
2828
|
|
|
|
|
|
|
# append date column to data array |
|
2829
|
|
|
|
|
|
|
# adds same date/time to each sample |
|
2830
|
|
|
|
|
|
|
# supported hash keys: 'date', 'format', 'added' |
|
2831
|
|
|
|
|
|
|
# parameter: ([hash]) |
|
2832
|
|
|
|
|
|
|
# returns: (column_slice) |
|
2833
|
|
|
|
|
|
|
sub add_date { |
|
2834
|
|
|
|
|
|
|
|
|
2835
|
|
|
|
|
|
|
# get parameters |
|
2836
|
0
|
|
|
0
|
1
|
0
|
my ($self, $hash) = @_; |
|
2837
|
|
|
|
|
|
|
|
|
2838
|
|
|
|
|
|
|
# local variables |
|
2839
|
0
|
|
|
|
|
0
|
my ($cols, $added, $date, $fmt, $str); |
|
2840
|
|
|
|
|
|
|
|
|
2841
|
|
|
|
|
|
|
# get added context |
|
2842
|
0
|
|
|
|
|
0
|
$added = $hash->{'added'}; |
|
2843
|
|
|
|
|
|
|
|
|
2844
|
|
|
|
|
|
|
# return column slice if date column already exists |
|
2845
|
0
|
0
|
|
|
|
0
|
return($cols) if ($cols = _cols($self, defined($added) ? "$added|CREATED" : 'CREATED')); |
|
|
|
0
|
|
|
|
|
|
|
2846
|
|
|
|
|
|
|
|
|
2847
|
|
|
|
|
|
|
# add date column slice |
|
2848
|
0
|
0
|
|
|
|
0
|
$cols = add_fmt($self, defined($added) ? "$added|CREATED" : 'CREATED'); |
|
2849
|
|
|
|
|
|
|
|
|
2850
|
|
|
|
|
|
|
# if date supplied |
|
2851
|
0
|
0
|
|
|
|
0
|
if (defined($date = $hash->{'date'})) { |
|
2852
|
|
|
|
|
|
|
|
|
2853
|
|
|
|
|
|
|
# if date is a number |
|
2854
|
0
|
0
|
|
|
|
0
|
if (Scalar::Util::looks_like_number($date)) { |
|
|
|
0
|
|
|
|
|
|
|
2855
|
|
|
|
|
|
|
|
|
2856
|
|
|
|
|
|
|
# make Time::Piece object |
|
2857
|
0
|
|
|
|
|
0
|
$date = localtime($date); |
|
2858
|
|
|
|
|
|
|
|
|
2859
|
|
|
|
|
|
|
# if date not a Time::Piece object |
|
2860
|
|
|
|
|
|
|
} elsif (ref($date) ne 'Time::Piece') { |
|
2861
|
|
|
|
|
|
|
|
|
2862
|
|
|
|
|
|
|
# error |
|
2863
|
0
|
|
|
|
|
0
|
croak('invalid date parameter'); |
|
2864
|
|
|
|
|
|
|
} |
|
2865
|
|
|
|
|
|
|
|
|
2866
|
|
|
|
|
|
|
} else { |
|
2867
|
|
|
|
|
|
|
|
|
2868
|
|
|
|
|
|
|
# use 'CREATED' value from chart |
|
2869
|
0
|
|
|
|
|
0
|
$date = created($self); |
|
2870
|
|
|
|
|
|
|
|
|
2871
|
|
|
|
|
|
|
} |
|
2872
|
|
|
|
|
|
|
|
|
2873
|
|
|
|
|
|
|
# compute the date/time string (same for each sample) |
|
2874
|
0
|
0
|
|
|
|
0
|
$str = defined($fmt = $hash->{'format'}) ? $date->strftime($fmt) : $date->epoch(); |
|
2875
|
|
|
|
|
|
|
|
|
2876
|
|
|
|
|
|
|
# for each row |
|
2877
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
2878
|
|
|
|
|
|
|
|
|
2879
|
|
|
|
|
|
|
# set the date time string |
|
2880
|
0
|
|
|
|
|
0
|
$self->[1][$i][$cols->[0]] = $str; |
|
2881
|
|
|
|
|
|
|
|
|
2882
|
|
|
|
|
|
|
} |
|
2883
|
|
|
|
|
|
|
|
|
2884
|
|
|
|
|
|
|
# return column slice |
|
2885
|
0
|
|
|
|
|
0
|
return($cols); |
|
2886
|
|
|
|
|
|
|
|
|
2887
|
|
|
|
|
|
|
} |
|
2888
|
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
# splice rows into data array |
|
2890
|
|
|
|
|
|
|
# offset and length are as used by Perl's 'splice' function |
|
2891
|
|
|
|
|
|
|
# data matrix is the 2-D array of data values to be spliced |
|
2892
|
|
|
|
|
|
|
# column slice is a reference to an array of data matrix column indices |
|
2893
|
|
|
|
|
|
|
# parameters: ([offset, [length, [data_matrix, [column_slice]]]]) |
|
2894
|
|
|
|
|
|
|
# returns: (removed_data_matrix) |
|
2895
|
|
|
|
|
|
|
sub splice_rows { |
|
2896
|
|
|
|
|
|
|
|
|
2897
|
|
|
|
|
|
|
# get parameters |
|
2898
|
1
|
|
|
1
|
1
|
3
|
my ($self, $offset, $length, $matrix, $cols) = @_; |
|
2899
|
|
|
|
|
|
|
|
|
2900
|
|
|
|
|
|
|
# local variables |
|
2901
|
1
|
|
|
|
|
16
|
my (@ix, @list, @s, $removed); |
|
2902
|
|
|
|
|
|
|
|
|
2903
|
|
|
|
|
|
|
# if offset supplied |
|
2904
|
1
|
50
|
|
|
|
5
|
if (defined($offset)) { |
|
2905
|
|
|
|
|
|
|
|
|
2906
|
|
|
|
|
|
|
# verify offset a scalar |
|
2907
|
1
|
50
|
33
|
|
|
7
|
(! ref($offset) && (int($offset) == $offset)) or croak('invalid offset parameter'); |
|
2908
|
|
|
|
|
|
|
|
|
2909
|
|
|
|
|
|
|
} |
|
2910
|
|
|
|
|
|
|
|
|
2911
|
|
|
|
|
|
|
# if length supplied |
|
2912
|
1
|
50
|
|
|
|
2
|
if (defined($length)) { |
|
2913
|
|
|
|
|
|
|
|
|
2914
|
|
|
|
|
|
|
# verify length an integer scalar |
|
2915
|
1
|
50
|
33
|
|
|
5
|
(! ref($length) && int($length) == $length) or croak('invalid length parameter'); |
|
2916
|
|
|
|
|
|
|
|
|
2917
|
|
|
|
|
|
|
} |
|
2918
|
|
|
|
|
|
|
|
|
2919
|
|
|
|
|
|
|
# if matrix supplied |
|
2920
|
1
|
50
|
|
|
|
2
|
if (defined($matrix)) { |
|
2921
|
|
|
|
|
|
|
|
|
2922
|
|
|
|
|
|
|
# verify matrix a 2-D array or Math::Matrix object |
|
2923
|
1
|
50
|
33
|
|
|
9
|
(ref($matrix) eq 'ARRAY' && ref($matrix->[0]) eq 'ARRAY') || (UNIVERSAL::isa($matrix, 'Math::Matrix')) || croak ('invalid matrix parameter'); |
|
|
|
|
33
|
|
|
|
|
|
2924
|
|
|
|
|
|
|
|
|
2925
|
|
|
|
|
|
|
} |
|
2926
|
|
|
|
|
|
|
|
|
2927
|
|
|
|
|
|
|
# if column slice supplied |
|
2928
|
1
|
50
|
|
|
|
3
|
if (defined($cols)) { |
|
2929
|
|
|
|
|
|
|
|
|
2930
|
|
|
|
|
|
|
# verify column slice an array reference |
|
2931
|
0
|
0
|
|
|
|
0
|
(ref($cols) eq 'ARRAY') or croak('invalid cols parameter'); |
|
2932
|
|
|
|
|
|
|
|
|
2933
|
|
|
|
|
|
|
# verify length, offset and matrix supplied |
|
2934
|
0
|
0
|
0
|
|
|
0
|
(defined($length) && defined($offset) && defined($matrix)) or croak('cols requires length, offset and matrix'); |
|
|
|
|
0
|
|
|
|
|
|
2935
|
|
|
|
|
|
|
|
|
2936
|
|
|
|
|
|
|
# flatten column slice |
|
2937
|
0
|
|
|
|
|
0
|
@ix = @{ICC::Shared::flatten($cols)}; |
|
|
0
|
|
|
|
|
0
|
|
|
2938
|
|
|
|
|
|
|
|
|
2939
|
|
|
|
|
|
|
# make splice list using column slice |
|
2940
|
0
|
|
|
|
|
0
|
@list = map {@s[@ix] = @{$_}; [@s]} @{$matrix}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2941
|
|
|
|
|
|
|
|
|
2942
|
|
|
|
|
|
|
# splice the data |
|
2943
|
0
|
|
|
|
|
0
|
$removed = [splice(@{$self->[1]}, $offset, $length, @list)]; |
|
|
0
|
|
|
|
|
0
|
|
|
2944
|
|
|
|
|
|
|
|
|
2945
|
|
|
|
|
|
|
} else { |
|
2946
|
|
|
|
|
|
|
|
|
2947
|
|
|
|
|
|
|
# if matrix supplied |
|
2948
|
1
|
50
|
|
|
|
2
|
if (defined($matrix)) { |
|
2949
|
|
|
|
|
|
|
|
|
2950
|
|
|
|
|
|
|
# verify length, offset |
|
2951
|
1
|
50
|
33
|
|
|
5
|
(defined($length) && defined($offset)) or croak('matrix requires length and offset'); |
|
2952
|
|
|
|
|
|
|
|
|
2953
|
|
|
|
|
|
|
# make splice list from full matrix |
|
2954
|
1
|
|
|
|
|
1
|
@list = map {[@{$_}]} @{$matrix}; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
9
|
|
|
|
1
|
|
|
|
|
2
|
|
|
2955
|
|
|
|
|
|
|
|
|
2956
|
|
|
|
|
|
|
# splice the data |
|
2957
|
1
|
|
|
|
|
2
|
$removed = [splice(@{$self->[1]}, $offset, $length, @list)]; |
|
|
1
|
|
|
|
|
3
|
|
|
2958
|
|
|
|
|
|
|
|
|
2959
|
|
|
|
|
|
|
} else { |
|
2960
|
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
# if length supplied |
|
2962
|
0
|
0
|
|
|
|
0
|
if (defined($length)) { |
|
2963
|
|
|
|
|
|
|
|
|
2964
|
|
|
|
|
|
|
# verify offset supplied |
|
2965
|
0
|
0
|
|
|
|
0
|
(defined($offset)) or croak('length requires offset'); |
|
2966
|
|
|
|
|
|
|
|
|
2967
|
|
|
|
|
|
|
# splice the data |
|
2968
|
0
|
|
|
|
|
0
|
$removed = [splice(@{$self->[1]}, $offset, $length)]; |
|
|
0
|
|
|
|
|
0
|
|
|
2969
|
|
|
|
|
|
|
|
|
2970
|
|
|
|
|
|
|
} else { |
|
2971
|
|
|
|
|
|
|
|
|
2972
|
|
|
|
|
|
|
# if offset supplied |
|
2973
|
0
|
0
|
|
|
|
0
|
if (defined($offset)) { |
|
2974
|
|
|
|
|
|
|
|
|
2975
|
|
|
|
|
|
|
# splice the data |
|
2976
|
0
|
|
|
|
|
0
|
$removed = [splice(@{$self->[1]}, $offset)]; |
|
|
0
|
|
|
|
|
0
|
|
|
2977
|
|
|
|
|
|
|
|
|
2978
|
|
|
|
|
|
|
} else { |
|
2979
|
|
|
|
|
|
|
|
|
2980
|
|
|
|
|
|
|
# get data array reference |
|
2981
|
0
|
|
|
|
|
0
|
$removed = $self->[1]; |
|
2982
|
|
|
|
|
|
|
|
|
2983
|
|
|
|
|
|
|
# init data array |
|
2984
|
0
|
|
|
|
|
0
|
$self->[1] = [[]]; |
|
2985
|
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
# init colorimetry array |
|
2987
|
0
|
|
|
|
|
0
|
$self->[2] = [[]]; |
|
2988
|
|
|
|
|
|
|
|
|
2989
|
|
|
|
|
|
|
} |
|
2990
|
|
|
|
|
|
|
|
|
2991
|
|
|
|
|
|
|
} |
|
2992
|
|
|
|
|
|
|
|
|
2993
|
|
|
|
|
|
|
} |
|
2994
|
|
|
|
|
|
|
|
|
2995
|
|
|
|
|
|
|
} |
|
2996
|
|
|
|
|
|
|
|
|
2997
|
|
|
|
|
|
|
# update the SAMPLE_ID hash |
|
2998
|
1
|
|
|
|
|
4
|
_makeSampleID($self); |
|
2999
|
|
|
|
|
|
|
|
|
3000
|
|
|
|
|
|
|
# return removed data |
|
3001
|
1
|
|
|
|
|
8
|
return(bless($removed, 'Math::Matrix')); |
|
3002
|
|
|
|
|
|
|
|
|
3003
|
|
|
|
|
|
|
} |
|
3004
|
|
|
|
|
|
|
|
|
3005
|
|
|
|
|
|
|
# splice columns into data array |
|
3006
|
|
|
|
|
|
|
# offset and length are as used by Perl's 'splice' function |
|
3007
|
|
|
|
|
|
|
# data matrix is the 2-D array of data values to be spliced |
|
3008
|
|
|
|
|
|
|
# row slice is a reference to an array of data matrix row indices |
|
3009
|
|
|
|
|
|
|
# parameters: ([offset, [length, [data_matrix, [row_slice]]]]) |
|
3010
|
|
|
|
|
|
|
# returns: (removed_data_matrix) |
|
3011
|
|
|
|
|
|
|
sub splice_cols { |
|
3012
|
|
|
|
|
|
|
|
|
3013
|
|
|
|
|
|
|
# get parameters |
|
3014
|
0
|
|
|
0
|
1
|
0
|
my ($self, $offset, $length, $matrix, $rows) = @_; |
|
3015
|
|
|
|
|
|
|
|
|
3016
|
|
|
|
|
|
|
# local variables |
|
3017
|
0
|
|
|
|
|
0
|
my (@ix, @s, @filler, $removed); |
|
3018
|
|
|
|
|
|
|
|
|
3019
|
|
|
|
|
|
|
# if offset supplied |
|
3020
|
0
|
0
|
|
|
|
0
|
if (defined($offset)) { |
|
3021
|
|
|
|
|
|
|
|
|
3022
|
|
|
|
|
|
|
# verify offset a scalar |
|
3023
|
0
|
0
|
0
|
|
|
0
|
(! ref($offset) && (int($offset) == $offset)) or croak('invalid offset parameter'); |
|
3024
|
|
|
|
|
|
|
|
|
3025
|
|
|
|
|
|
|
} |
|
3026
|
|
|
|
|
|
|
|
|
3027
|
|
|
|
|
|
|
# if length supplied |
|
3028
|
0
|
0
|
|
|
|
0
|
if (defined($length)) { |
|
3029
|
|
|
|
|
|
|
|
|
3030
|
|
|
|
|
|
|
# verify length an integer scalar |
|
3031
|
0
|
0
|
0
|
|
|
0
|
(! ref($length) && int($length) == $length) or croak('invalid length parameter'); |
|
3032
|
|
|
|
|
|
|
|
|
3033
|
|
|
|
|
|
|
} |
|
3034
|
|
|
|
|
|
|
|
|
3035
|
|
|
|
|
|
|
# if matrix supplied |
|
3036
|
0
|
0
|
|
|
|
0
|
if (defined($matrix)) { |
|
3037
|
|
|
|
|
|
|
|
|
3038
|
|
|
|
|
|
|
# verify matrix a 2-D array or Math::Matrix object |
|
3039
|
0
|
0
|
0
|
|
|
0
|
(ref($matrix) eq 'ARRAY' && ref($matrix->[0]) eq 'ARRAY') || (UNIVERSAL::isa($matrix, 'Math::Matrix')) || croak ('invalid matrix parameter'); |
|
|
|
|
0
|
|
|
|
|
|
3040
|
|
|
|
|
|
|
|
|
3041
|
|
|
|
|
|
|
} |
|
3042
|
|
|
|
|
|
|
|
|
3043
|
|
|
|
|
|
|
# if row slice supplied |
|
3044
|
0
|
0
|
|
|
|
0
|
if (defined($rows)) { |
|
3045
|
|
|
|
|
|
|
|
|
3046
|
|
|
|
|
|
|
# verify row slice an array reference |
|
3047
|
0
|
0
|
|
|
|
0
|
(ref($rows) eq 'ARRAY') or croak('invalid cols parameter'); |
|
3048
|
|
|
|
|
|
|
|
|
3049
|
|
|
|
|
|
|
# verify length, offset and matrix supplied |
|
3050
|
0
|
0
|
0
|
|
|
0
|
(defined($length) && defined($offset) && defined($matrix)) or croak('rows requires length, offset and matrix'); |
|
|
|
|
0
|
|
|
|
|
|
3051
|
|
|
|
|
|
|
|
|
3052
|
|
|
|
|
|
|
# flatten row slice |
|
3053
|
0
|
|
|
|
|
0
|
@ix = @{ICC::Shared::flatten($rows)}; |
|
|
0
|
|
|
|
|
0
|
|
|
3054
|
|
|
|
|
|
|
|
|
3055
|
|
|
|
|
|
|
# make list of matrix row refs |
|
3056
|
0
|
|
|
|
|
0
|
@s[@ix] = @{$matrix}; |
|
|
0
|
|
|
|
|
0
|
|
|
3057
|
|
|
|
|
|
|
|
|
3058
|
|
|
|
|
|
|
# make filler data |
|
3059
|
0
|
|
|
|
|
0
|
@filler = (undef) x @{$matrix->[0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
3060
|
|
|
|
|
|
|
|
|
3061
|
|
|
|
|
|
|
# for each data row |
|
3062
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3063
|
|
|
|
|
|
|
|
|
3064
|
|
|
|
|
|
|
# if matrix data defined |
|
3065
|
0
|
0
|
|
|
|
0
|
if (defined($s[$i])) { |
|
3066
|
|
|
|
|
|
|
|
|
3067
|
|
|
|
|
|
|
# splice matrix data |
|
3068
|
0
|
|
|
|
|
0
|
$removed->[$i] = [splice(@{$self->[1][$i]}, $offset, $length, @{$s[$i]})]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3069
|
|
|
|
|
|
|
|
|
3070
|
|
|
|
|
|
|
} else { |
|
3071
|
|
|
|
|
|
|
|
|
3072
|
|
|
|
|
|
|
# splice filler data |
|
3073
|
0
|
|
|
|
|
0
|
$removed->[$i] = [splice(@{$self->[1][$i]}, $offset, $length, @filler)]; |
|
|
0
|
|
|
|
|
0
|
|
|
3074
|
|
|
|
|
|
|
|
|
3075
|
|
|
|
|
|
|
} |
|
3076
|
|
|
|
|
|
|
|
|
3077
|
|
|
|
|
|
|
} |
|
3078
|
|
|
|
|
|
|
|
|
3079
|
|
|
|
|
|
|
# for each colorimetry row |
|
3080
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[2]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3081
|
|
|
|
|
|
|
|
|
3082
|
|
|
|
|
|
|
# splice filler data |
|
3083
|
0
|
0
|
|
|
|
0
|
splice(@{$self->[2][$i]}, $offset, $length, @filler) if (defined($self->[2][$i][$offset])); |
|
|
0
|
|
|
|
|
0
|
|
|
3084
|
|
|
|
|
|
|
|
|
3085
|
|
|
|
|
|
|
} |
|
3086
|
|
|
|
|
|
|
|
|
3087
|
|
|
|
|
|
|
} else { |
|
3088
|
|
|
|
|
|
|
|
|
3089
|
|
|
|
|
|
|
# if matrix supplied |
|
3090
|
0
|
0
|
|
|
|
0
|
if (defined($matrix)) { |
|
3091
|
|
|
|
|
|
|
|
|
3092
|
|
|
|
|
|
|
# verify length, offset |
|
3093
|
0
|
0
|
0
|
|
|
0
|
(defined($length) && defined($offset)) or croak('matrix requires length and offset'); |
|
3094
|
|
|
|
|
|
|
|
|
3095
|
|
|
|
|
|
|
# make filler data |
|
3096
|
0
|
|
|
|
|
0
|
@filler = (undef) x @{$matrix->[0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
3097
|
|
|
|
|
|
|
|
|
3098
|
|
|
|
|
|
|
# for each data row |
|
3099
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3100
|
|
|
|
|
|
|
|
|
3101
|
|
|
|
|
|
|
# if matrix data defined |
|
3102
|
0
|
0
|
|
|
|
0
|
if (defined($matrix->[$i])) { |
|
3103
|
|
|
|
|
|
|
|
|
3104
|
|
|
|
|
|
|
# splice matrix data |
|
3105
|
0
|
|
|
|
|
0
|
$removed->[$i] = [splice(@{$self->[1][$i]}, $offset, $length, @{$matrix->[$i]})]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3106
|
|
|
|
|
|
|
|
|
3107
|
|
|
|
|
|
|
} else { |
|
3108
|
|
|
|
|
|
|
|
|
3109
|
|
|
|
|
|
|
# splice filler data |
|
3110
|
0
|
|
|
|
|
0
|
$removed->[$i] = [splice(@{$self->[1][$i]}, $offset, $length, @filler)]; |
|
|
0
|
|
|
|
|
0
|
|
|
3111
|
|
|
|
|
|
|
|
|
3112
|
|
|
|
|
|
|
} |
|
3113
|
|
|
|
|
|
|
|
|
3114
|
|
|
|
|
|
|
} |
|
3115
|
|
|
|
|
|
|
|
|
3116
|
|
|
|
|
|
|
# for each colorimetry row |
|
3117
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[2]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3118
|
|
|
|
|
|
|
|
|
3119
|
|
|
|
|
|
|
# splice filler data |
|
3120
|
0
|
0
|
|
|
|
0
|
splice(@{$self->[2][$i]}, $offset, $length, @filler) if (defined($self->[2][$i][$offset])); |
|
|
0
|
|
|
|
|
0
|
|
|
3121
|
|
|
|
|
|
|
|
|
3122
|
|
|
|
|
|
|
} |
|
3123
|
|
|
|
|
|
|
|
|
3124
|
|
|
|
|
|
|
} else { |
|
3125
|
|
|
|
|
|
|
|
|
3126
|
|
|
|
|
|
|
# if length supplied |
|
3127
|
0
|
0
|
|
|
|
0
|
if (defined($length)) { |
|
3128
|
|
|
|
|
|
|
|
|
3129
|
|
|
|
|
|
|
# verify offset supplied |
|
3130
|
0
|
0
|
|
|
|
0
|
(defined($offset)) or croak('length requires offset'); |
|
3131
|
|
|
|
|
|
|
|
|
3132
|
|
|
|
|
|
|
# for each data row |
|
3133
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3134
|
|
|
|
|
|
|
|
|
3135
|
|
|
|
|
|
|
# splice the data |
|
3136
|
0
|
|
|
|
|
0
|
$removed->[$i] = [splice(@{$self->[1][$i]}, $offset, $length)]; |
|
|
0
|
|
|
|
|
0
|
|
|
3137
|
|
|
|
|
|
|
|
|
3138
|
|
|
|
|
|
|
} |
|
3139
|
|
|
|
|
|
|
|
|
3140
|
|
|
|
|
|
|
# for each colorimetry row |
|
3141
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[2]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3142
|
|
|
|
|
|
|
|
|
3143
|
|
|
|
|
|
|
# splice filler data |
|
3144
|
0
|
0
|
|
|
|
0
|
splice(@{$self->[2][$i]}, $offset, $length) if (defined($self->[2][$i][$offset])); |
|
|
0
|
|
|
|
|
0
|
|
|
3145
|
|
|
|
|
|
|
|
|
3146
|
|
|
|
|
|
|
} |
|
3147
|
|
|
|
|
|
|
|
|
3148
|
|
|
|
|
|
|
} else { |
|
3149
|
|
|
|
|
|
|
|
|
3150
|
|
|
|
|
|
|
# if offset supplied |
|
3151
|
0
|
0
|
|
|
|
0
|
if (defined($offset)) { |
|
3152
|
|
|
|
|
|
|
|
|
3153
|
|
|
|
|
|
|
# for each data row |
|
3154
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3155
|
|
|
|
|
|
|
|
|
3156
|
|
|
|
|
|
|
# splice the data |
|
3157
|
0
|
|
|
|
|
0
|
$removed->[$i] = [splice(@{$self->[1][$i]}, $offset)]; |
|
|
0
|
|
|
|
|
0
|
|
|
3158
|
|
|
|
|
|
|
|
|
3159
|
|
|
|
|
|
|
} |
|
3160
|
|
|
|
|
|
|
|
|
3161
|
|
|
|
|
|
|
# for each colorimetry row |
|
3162
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[2]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3163
|
|
|
|
|
|
|
|
|
3164
|
|
|
|
|
|
|
# splice filler data |
|
3165
|
0
|
0
|
|
|
|
0
|
splice(@{$self->[2][$i]}, $offset) if (defined($self->[2][$i][$offset])); |
|
|
0
|
|
|
|
|
0
|
|
|
3166
|
|
|
|
|
|
|
|
|
3167
|
|
|
|
|
|
|
} |
|
3168
|
|
|
|
|
|
|
|
|
3169
|
|
|
|
|
|
|
} else { |
|
3170
|
|
|
|
|
|
|
|
|
3171
|
|
|
|
|
|
|
# get data array reference |
|
3172
|
0
|
|
|
|
|
0
|
$removed = $self->[1]; |
|
3173
|
|
|
|
|
|
|
|
|
3174
|
|
|
|
|
|
|
# init data array |
|
3175
|
0
|
|
|
|
|
0
|
$self->[1] = [[]]; |
|
3176
|
|
|
|
|
|
|
|
|
3177
|
|
|
|
|
|
|
# init colorimetry array |
|
3178
|
0
|
|
|
|
|
0
|
$self->[2] = [[]]; |
|
3179
|
|
|
|
|
|
|
|
|
3180
|
|
|
|
|
|
|
} |
|
3181
|
|
|
|
|
|
|
|
|
3182
|
|
|
|
|
|
|
} |
|
3183
|
|
|
|
|
|
|
|
|
3184
|
|
|
|
|
|
|
} |
|
3185
|
|
|
|
|
|
|
|
|
3186
|
|
|
|
|
|
|
} |
|
3187
|
|
|
|
|
|
|
|
|
3188
|
|
|
|
|
|
|
# initialize SAMPLE_ID hash if no SAMPLE_ID field |
|
3189
|
0
|
0
|
|
|
|
0
|
$self->[4] = {} if (0 == test($self, 'ID')); |
|
3190
|
|
|
|
|
|
|
|
|
3191
|
|
|
|
|
|
|
# return removed data |
|
3192
|
0
|
|
|
|
|
0
|
return(bless($removed, 'Math::Matrix')); |
|
3193
|
|
|
|
|
|
|
|
|
3194
|
|
|
|
|
|
|
} |
|
3195
|
|
|
|
|
|
|
|
|
3196
|
|
|
|
|
|
|
# remove rows from data array |
|
3197
|
|
|
|
|
|
|
# parameters: (row_slice) |
|
3198
|
|
|
|
|
|
|
# returns: (removed_data_matrix) |
|
3199
|
|
|
|
|
|
|
sub remove_rows { |
|
3200
|
|
|
|
|
|
|
|
|
3201
|
|
|
|
|
|
|
# get parameters |
|
3202
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rows) = @_; |
|
3203
|
|
|
|
|
|
|
|
|
3204
|
|
|
|
|
|
|
# local variables |
|
3205
|
0
|
|
|
|
|
0
|
my ($f, $up, @r, @s, $removed); |
|
3206
|
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
# return empty matrix if row slice undefined |
|
3208
|
0
|
0
|
|
|
|
0
|
return(bless([[]], 'Math::Matrix')) if (! defined($rows)); |
|
3209
|
|
|
|
|
|
|
|
|
3210
|
|
|
|
|
|
|
# flatten row slice |
|
3211
|
0
|
|
|
|
|
0
|
$f = ICC::Shared::flatten($rows); |
|
3212
|
|
|
|
|
|
|
|
|
3213
|
|
|
|
|
|
|
# if row slice is empty |
|
3214
|
0
|
0
|
|
|
|
0
|
if (! defined($f->[0])) { |
|
3215
|
|
|
|
|
|
|
|
|
3216
|
|
|
|
|
|
|
# remove all rows, except row 0 (DATA_FORMAT) |
|
3217
|
0
|
|
|
|
|
0
|
$removed = [splice(@{$self->[1]}, 1)]; |
|
|
0
|
|
|
|
|
0
|
|
|
3218
|
|
|
|
|
|
|
|
|
3219
|
|
|
|
|
|
|
# clear SAMPLE_ID hash |
|
3220
|
0
|
|
|
|
|
0
|
$self->[4] = {}; |
|
3221
|
|
|
|
|
|
|
|
|
3222
|
|
|
|
|
|
|
# return removed data |
|
3223
|
0
|
|
|
|
|
0
|
return(bless($removed, 'Math::Matrix')); |
|
3224
|
|
|
|
|
|
|
|
|
3225
|
|
|
|
|
|
|
} |
|
3226
|
|
|
|
|
|
|
|
|
3227
|
|
|
|
|
|
|
# get upper row index |
|
3228
|
0
|
|
|
|
|
0
|
$up = $#{$self->[1]}; |
|
|
0
|
|
|
|
|
0
|
|
|
3229
|
|
|
|
|
|
|
|
|
3230
|
|
|
|
|
|
|
# verify row slice |
|
3231
|
0
|
0
|
0
|
|
|
0
|
(grep {$_ != int($_) || $_ < 1 || $_ > $up} @{$f}) && carp('row slice contains invalid index value(s)'); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3232
|
|
|
|
|
|
|
|
|
3233
|
|
|
|
|
|
|
# initialize slice (always keep row 0) |
|
3234
|
0
|
|
|
|
|
0
|
@s = (0); |
|
3235
|
|
|
|
|
|
|
|
|
3236
|
|
|
|
|
|
|
# for each row |
|
3237
|
0
|
|
|
|
|
0
|
for my $i (1 .. $up) { |
|
3238
|
|
|
|
|
|
|
|
|
3239
|
|
|
|
|
|
|
# if index contained in row slice |
|
3240
|
0
|
0
|
|
|
|
0
|
if (grep {$i == $_} @{$f}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3241
|
|
|
|
|
|
|
|
|
3242
|
|
|
|
|
|
|
# add to slice (remove) |
|
3243
|
0
|
|
|
|
|
0
|
push(@r, $i); |
|
3244
|
|
|
|
|
|
|
|
|
3245
|
|
|
|
|
|
|
} else { |
|
3246
|
|
|
|
|
|
|
|
|
3247
|
|
|
|
|
|
|
# add to slice (keep) |
|
3248
|
0
|
|
|
|
|
0
|
push(@s, $i) |
|
3249
|
|
|
|
|
|
|
|
|
3250
|
|
|
|
|
|
|
} |
|
3251
|
|
|
|
|
|
|
|
|
3252
|
|
|
|
|
|
|
} |
|
3253
|
|
|
|
|
|
|
|
|
3254
|
|
|
|
|
|
|
# if rows to remove |
|
3255
|
0
|
0
|
|
|
|
0
|
if (@r) { |
|
3256
|
|
|
|
|
|
|
|
|
3257
|
|
|
|
|
|
|
# set removed data (@r) |
|
3258
|
0
|
|
|
|
|
0
|
$removed = [@{$self->[1]}[@r]]; |
|
|
0
|
|
|
|
|
0
|
|
|
3259
|
|
|
|
|
|
|
|
|
3260
|
|
|
|
|
|
|
# set kept data (@s) |
|
3261
|
0
|
|
|
|
|
0
|
$self->[1] = [@{$self->[1]}[@s]]; |
|
|
0
|
|
|
|
|
0
|
|
|
3262
|
|
|
|
|
|
|
|
|
3263
|
|
|
|
|
|
|
# update the SAMPLE_ID hash |
|
3264
|
0
|
|
|
|
|
0
|
_makeSampleID($self); |
|
3265
|
|
|
|
|
|
|
|
|
3266
|
|
|
|
|
|
|
} else { |
|
3267
|
|
|
|
|
|
|
|
|
3268
|
|
|
|
|
|
|
# set removed data (none) |
|
3269
|
0
|
|
|
|
|
0
|
$removed = [[]]; |
|
3270
|
|
|
|
|
|
|
|
|
3271
|
|
|
|
|
|
|
} |
|
3272
|
|
|
|
|
|
|
|
|
3273
|
|
|
|
|
|
|
# return removed data |
|
3274
|
0
|
|
|
|
|
0
|
return(bless($removed, 'Math::Matrix')); |
|
3275
|
|
|
|
|
|
|
|
|
3276
|
|
|
|
|
|
|
} |
|
3277
|
|
|
|
|
|
|
|
|
3278
|
|
|
|
|
|
|
# remove columns from data array |
|
3279
|
|
|
|
|
|
|
# parameters: (column_slice) |
|
3280
|
|
|
|
|
|
|
# returns: (removed_data_matrix) |
|
3281
|
|
|
|
|
|
|
sub remove_cols { |
|
3282
|
|
|
|
|
|
|
|
|
3283
|
|
|
|
|
|
|
# get parameters |
|
3284
|
0
|
|
|
0
|
1
|
0
|
my ($self, $cols) = @_; |
|
3285
|
|
|
|
|
|
|
|
|
3286
|
|
|
|
|
|
|
# local variables |
|
3287
|
0
|
|
|
|
|
0
|
my ($f, $up, @r, @s, $removed, $kept, $color); |
|
3288
|
|
|
|
|
|
|
|
|
3289
|
|
|
|
|
|
|
# return empty matrix if column slice undefined |
|
3290
|
0
|
0
|
|
|
|
0
|
return(bless([[]], 'Math::Matrix')) if (! defined($cols)); |
|
3291
|
|
|
|
|
|
|
|
|
3292
|
|
|
|
|
|
|
# flatten column slice |
|
3293
|
0
|
|
|
|
|
0
|
$f = ICC::Shared::flatten($cols); |
|
3294
|
|
|
|
|
|
|
|
|
3295
|
|
|
|
|
|
|
# map column slice, converting non-numeric values with 'test' method |
|
3296
|
0
|
0
|
|
|
|
0
|
@{$f} = map {Scalar::Util::looks_like_number($_) ? $_ : $self->test($_)} @{$f}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3297
|
|
|
|
|
|
|
|
|
3298
|
|
|
|
|
|
|
# if columns slice is empty |
|
3299
|
0
|
0
|
|
|
|
0
|
if (! defined($f->[0])) { |
|
3300
|
|
|
|
|
|
|
|
|
3301
|
|
|
|
|
|
|
# copy all rows |
|
3302
|
0
|
|
|
|
|
0
|
$removed = [@{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
3303
|
|
|
|
|
|
|
|
|
3304
|
|
|
|
|
|
|
# clear data array |
|
3305
|
0
|
|
|
|
|
0
|
$self->[1] =[[]]; |
|
3306
|
|
|
|
|
|
|
|
|
3307
|
|
|
|
|
|
|
# clear colorimetry array |
|
3308
|
0
|
|
|
|
|
0
|
$self->[2] = [[]]; |
|
3309
|
|
|
|
|
|
|
|
|
3310
|
|
|
|
|
|
|
# clear SAMPLE_ID hash |
|
3311
|
0
|
|
|
|
|
0
|
$self->[4] = {}; |
|
3312
|
|
|
|
|
|
|
|
|
3313
|
|
|
|
|
|
|
# return removed data |
|
3314
|
0
|
|
|
|
|
0
|
return(bless($removed, 'Math::Matrix')); |
|
3315
|
|
|
|
|
|
|
|
|
3316
|
|
|
|
|
|
|
} |
|
3317
|
|
|
|
|
|
|
|
|
3318
|
|
|
|
|
|
|
# get upper column index |
|
3319
|
0
|
|
|
|
|
0
|
$up = $#{$self->[1][0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
3320
|
|
|
|
|
|
|
|
|
3321
|
|
|
|
|
|
|
# verify column slice |
|
3322
|
0
|
0
|
0
|
|
|
0
|
(grep {$_ != int($_) || $_ < 0 || $_ > $up} @{$f}) && carp('column slice contains invalid index value(s)'); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3323
|
|
|
|
|
|
|
|
|
3324
|
|
|
|
|
|
|
# for each column |
|
3325
|
0
|
|
|
|
|
0
|
for my $i (0 .. $up) { |
|
3326
|
|
|
|
|
|
|
|
|
3327
|
|
|
|
|
|
|
# if index contained in column slice |
|
3328
|
0
|
0
|
|
|
|
0
|
if (grep {$i == $_} @{$f}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3329
|
|
|
|
|
|
|
|
|
3330
|
|
|
|
|
|
|
# add to slice (remove) |
|
3331
|
0
|
|
|
|
|
0
|
push(@r, $i); |
|
3332
|
|
|
|
|
|
|
|
|
3333
|
|
|
|
|
|
|
} else { |
|
3334
|
|
|
|
|
|
|
|
|
3335
|
|
|
|
|
|
|
# add to slice (keep) |
|
3336
|
0
|
|
|
|
|
0
|
push(@s, $i) |
|
3337
|
|
|
|
|
|
|
|
|
3338
|
|
|
|
|
|
|
} |
|
3339
|
|
|
|
|
|
|
|
|
3340
|
|
|
|
|
|
|
} |
|
3341
|
|
|
|
|
|
|
|
|
3342
|
|
|
|
|
|
|
# if columns to remove |
|
3343
|
0
|
0
|
|
|
|
0
|
if (@r) { |
|
3344
|
|
|
|
|
|
|
|
|
3345
|
|
|
|
|
|
|
# for each data row |
|
3346
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3347
|
|
|
|
|
|
|
|
|
3348
|
|
|
|
|
|
|
# set removed data (@r) |
|
3349
|
0
|
|
|
|
|
0
|
$removed->[$i] = [@{$self->[1][$i]}[@r]]; |
|
|
0
|
|
|
|
|
0
|
|
|
3350
|
|
|
|
|
|
|
|
|
3351
|
|
|
|
|
|
|
# set kept data (@s) |
|
3352
|
0
|
|
|
|
|
0
|
$kept->[$i] = [@{$self->[1][$i]}[@s]]; |
|
|
0
|
|
|
|
|
0
|
|
|
3353
|
|
|
|
|
|
|
|
|
3354
|
|
|
|
|
|
|
} |
|
3355
|
|
|
|
|
|
|
|
|
3356
|
|
|
|
|
|
|
# update object data |
|
3357
|
0
|
|
|
|
|
0
|
$self->[1] = $kept; |
|
3358
|
|
|
|
|
|
|
|
|
3359
|
|
|
|
|
|
|
# for each colorimetry row |
|
3360
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[2]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
3361
|
|
|
|
|
|
|
|
|
3362
|
|
|
|
|
|
|
# set kept colorimetry (@s) |
|
3363
|
0
|
|
|
|
|
0
|
$color->[$i] = [@{$self->[2][$i]}[@s]]; |
|
|
0
|
|
|
|
|
0
|
|
|
3364
|
|
|
|
|
|
|
|
|
3365
|
|
|
|
|
|
|
} |
|
3366
|
|
|
|
|
|
|
|
|
3367
|
|
|
|
|
|
|
# update colorimetry data |
|
3368
|
0
|
|
|
|
|
0
|
$self->[2] = $color; |
|
3369
|
|
|
|
|
|
|
|
|
3370
|
|
|
|
|
|
|
# initialize SAMPLE_ID hash if no SAMPLE_ID field |
|
3371
|
0
|
0
|
|
|
|
0
|
$self->[4] = {} if (0 == test($self, 'ID')); |
|
3372
|
|
|
|
|
|
|
|
|
3373
|
|
|
|
|
|
|
} else { |
|
3374
|
|
|
|
|
|
|
|
|
3375
|
|
|
|
|
|
|
# set removed data (none) |
|
3376
|
0
|
|
|
|
|
0
|
$removed = [[]]; |
|
3377
|
|
|
|
|
|
|
|
|
3378
|
|
|
|
|
|
|
} |
|
3379
|
|
|
|
|
|
|
|
|
3380
|
|
|
|
|
|
|
# return removed data |
|
3381
|
0
|
|
|
|
|
0
|
return(bless($removed, 'Math::Matrix')); |
|
3382
|
|
|
|
|
|
|
|
|
3383
|
|
|
|
|
|
|
} |
|
3384
|
|
|
|
|
|
|
|
|
3385
|
|
|
|
|
|
|
# get sample selection using tokens |
|
3386
|
|
|
|
|
|
|
# tokens are provided as a text string |
|
3387
|
|
|
|
|
|
|
# supported hash keys: 'A2B', 'B2A', 'sort', 'ink_map', 'invert_rgb' |
|
3388
|
|
|
|
|
|
|
# sample slice is sorted, duplicates are removed |
|
3389
|
|
|
|
|
|
|
# context may be specified with parameter hash |
|
3390
|
|
|
|
|
|
|
# parameters: (token_string, [hash]) |
|
3391
|
|
|
|
|
|
|
# returns: (sample_slice) |
|
3392
|
|
|
|
|
|
|
sub select_token { |
|
3393
|
|
|
|
|
|
|
|
|
3394
|
|
|
|
|
|
|
# get parameters |
|
3395
|
0
|
|
|
0
|
1
|
0
|
my ($self, $select, $hash) = @_; |
|
3396
|
|
|
|
|
|
|
|
|
3397
|
|
|
|
|
|
|
# local variables |
|
3398
|
0
|
|
|
|
|
0
|
my ($ctx, $n, $sub, $sort, $row_length, $sz, $nx); |
|
3399
|
0
|
|
|
|
|
0
|
my ($map, @m, @ms, @mx, @sp, @si); |
|
3400
|
0
|
|
|
|
|
0
|
my ($sel, @nr, @samples, $token, @p); |
|
3401
|
0
|
|
|
|
|
0
|
my ($mat, @dev, @cmy, $c, $my, $lim, %it8, @Lab, $A2B, $B2A, $pcs, $ci); |
|
3402
|
0
|
|
|
|
|
0
|
my (%unique, $code, $dev, @sn, %minus, @max, $fnk, $fns, $fnb); |
|
3403
|
|
|
|
|
|
|
|
|
3404
|
|
|
|
|
|
|
# get context prefix |
|
3405
|
0
|
0
|
|
|
|
0
|
$ctx = defined($hash->{'context'}) ? "$hash->{'context'}|" : ''; |
|
3406
|
|
|
|
|
|
|
|
|
3407
|
|
|
|
|
|
|
# verify chart has device data |
|
3408
|
0
|
0
|
|
|
|
0
|
($n = test($self, $ctx . 'DEVICE')) or croak("device data is required for 'select_token' method"); |
|
3409
|
|
|
|
|
|
|
|
|
3410
|
|
|
|
|
|
|
# get substrate device value (1 if RGB, otherwise 0) |
|
3411
|
0
|
0
|
|
|
|
0
|
$sub = test($self, $ctx . 'RGB') ? 1 : 0; |
|
3412
|
|
|
|
|
|
|
|
|
3413
|
|
|
|
|
|
|
# get sort vector from hash |
|
3414
|
0
|
|
|
|
|
0
|
$sort = $hash->{'sort'}; |
|
3415
|
|
|
|
|
|
|
|
|
3416
|
|
|
|
|
|
|
# get row length, if specified in chart |
|
3417
|
0
|
|
|
|
|
0
|
$row_length = _getRowLength($self, {'undef' => 1}); |
|
3418
|
|
|
|
|
|
|
|
|
3419
|
|
|
|
|
|
|
# get initial chart size |
|
3420
|
0
|
|
|
|
|
0
|
$sz = size($self, 1); |
|
3421
|
|
|
|
|
|
|
|
|
3422
|
|
|
|
|
|
|
# device upper index |
|
3423
|
0
|
|
|
|
|
0
|
$nx = $n - 1; |
|
3424
|
|
|
|
|
|
|
|
|
3425
|
|
|
|
|
|
|
# the map slice (@m) contains the device indices for (C, M, Y, K, extra colors) |
|
3426
|
|
|
|
|
|
|
# by default, @m = (0, 1, 2, 3, ... N - 1), where N is the number of ink channels |
|
3427
|
|
|
|
|
|
|
# when there is ink mapping, the process colors may be arranged differently |
|
3428
|
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
# if ink map provided |
|
3430
|
0
|
0
|
|
|
|
0
|
if (defined($map = $hash->{'ink_map'})) { |
|
3431
|
|
|
|
|
|
|
|
|
3432
|
|
|
|
|
|
|
# verify ink map |
|
3433
|
0
|
0
|
|
|
|
0
|
($n == @{$map}) or croak("ink map is wrong sized"); |
|
|
0
|
|
|
|
|
0
|
|
|
3434
|
|
|
|
|
|
|
|
|
3435
|
|
|
|
|
|
|
# make profile mapping slices from ink map |
|
3436
|
0
|
0
|
|
|
|
0
|
@sp = grep {$map->[$_] =~ m/^(\d+)$/ && push(@si, $1)} (0 .. $#{$map}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3437
|
|
|
|
|
|
|
|
|
3438
|
|
|
|
|
|
|
# make inverted map slice |
|
3439
|
0
|
|
|
|
|
0
|
@m = @{_invert_ink_map($map)}; |
|
|
0
|
|
|
|
|
0
|
|
|
3440
|
|
|
|
|
|
|
|
|
3441
|
|
|
|
|
|
|
} else { |
|
3442
|
|
|
|
|
|
|
|
|
3443
|
|
|
|
|
|
|
# make default map slice |
|
3444
|
0
|
|
|
|
|
0
|
@m = (0 .. $nx); |
|
3445
|
|
|
|
|
|
|
|
|
3446
|
|
|
|
|
|
|
} |
|
3447
|
|
|
|
|
|
|
|
|
3448
|
|
|
|
|
|
|
# parse token string |
|
3449
|
0
|
|
|
|
|
0
|
$sel = ICC::Shared::parse_tokens($select); |
|
3450
|
|
|
|
|
|
|
|
|
3451
|
|
|
|
|
|
|
# if 'nr' token(s) |
|
3452
|
0
|
0
|
|
|
|
0
|
if (@nr = grep {$sel->[$_] eq 'nr'} (0 .. $#{$sel})) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3453
|
|
|
|
|
|
|
|
|
3454
|
|
|
|
|
|
|
# move first 'nr' token and parameter to beginning of array |
|
3455
|
0
|
|
|
|
|
0
|
unshift(@{$sel}, splice(@{$sel}, $nr[0], 2)); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3456
|
|
|
|
|
|
|
|
|
3457
|
|
|
|
|
|
|
# warn if more than one 'nr' token |
|
3458
|
0
|
0
|
|
|
|
0
|
print "multiple 'nr' selection tokens\n" if (@nr > 1); |
|
3459
|
|
|
|
|
|
|
|
|
3460
|
|
|
|
|
|
|
} |
|
3461
|
|
|
|
|
|
|
|
|
3462
|
|
|
|
|
|
|
# initialize sample slice |
|
3463
|
0
|
|
|
|
|
0
|
@samples = (); |
|
3464
|
|
|
|
|
|
|
|
|
3465
|
|
|
|
|
|
|
# for each selection token |
|
3466
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i <= $#{$sel}; $i++) { |
|
|
0
|
|
|
|
|
0
|
|
|
3467
|
|
|
|
|
|
|
|
|
3468
|
|
|
|
|
|
|
# get the lowercase value of current token |
|
3469
|
0
|
|
|
|
|
0
|
$token = lc($sel->[$i]); |
|
3470
|
|
|
|
|
|
|
|
|
3471
|
|
|
|
|
|
|
# set parameter array, filtering out non-numeric elements |
|
3472
|
0
|
0
|
|
|
|
0
|
@p = (ref($sel->[$i + 1]) eq 'ARRAY') ? grep {Scalar::Util::looks_like_number($_)} @{$sel->[++$i]} : (); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3473
|
|
|
|
|
|
|
|
|
3474
|
|
|
|
|
|
|
# if 'all' |
|
3475
|
0
|
0
|
|
|
|
0
|
if ($token eq 'all') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3476
|
|
|
|
|
|
|
|
|
3477
|
|
|
|
|
|
|
# select all samples |
|
3478
|
0
|
|
|
|
|
0
|
@samples = (1 .. $sz); |
|
3479
|
|
|
|
|
|
|
|
|
3480
|
|
|
|
|
|
|
# if 'sort' |
|
3481
|
|
|
|
|
|
|
} elsif ($token eq 'sort') { |
|
3482
|
|
|
|
|
|
|
|
|
3483
|
|
|
|
|
|
|
# if numeric parameters |
|
3484
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3485
|
|
|
|
|
|
|
|
|
3486
|
|
|
|
|
|
|
# set the sort vector |
|
3487
|
0
|
|
|
|
|
0
|
$sort = [@p]; |
|
3488
|
|
|
|
|
|
|
|
|
3489
|
|
|
|
|
|
|
} else { |
|
3490
|
|
|
|
|
|
|
|
|
3491
|
|
|
|
|
|
|
# print warning |
|
3492
|
0
|
|
|
|
|
0
|
print "selection token 'sort' requires numeric parameter(s)\n"; |
|
3493
|
|
|
|
|
|
|
|
|
3494
|
|
|
|
|
|
|
} |
|
3495
|
|
|
|
|
|
|
|
|
3496
|
|
|
|
|
|
|
# if 'rows' |
|
3497
|
|
|
|
|
|
|
} elsif ($token eq 'rows') { |
|
3498
|
|
|
|
|
|
|
|
|
3499
|
|
|
|
|
|
|
# if numeric parameters |
|
3500
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3501
|
|
|
|
|
|
|
|
|
3502
|
|
|
|
|
|
|
# if row length defined |
|
3503
|
0
|
0
|
|
|
|
0
|
if (defined($row_length)) { |
|
3504
|
|
|
|
|
|
|
|
|
3505
|
|
|
|
|
|
|
# for each row |
|
3506
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#p) { |
|
3507
|
|
|
|
|
|
|
|
|
3508
|
|
|
|
|
|
|
# add row samples |
|
3509
|
0
|
|
|
|
|
0
|
push(@samples, grep {($_ - 1) % $row_length == ($p[$i] - 1)} (1 .. $sz)); |
|
|
0
|
|
|
|
|
0
|
|
|
3510
|
|
|
|
|
|
|
|
|
3511
|
|
|
|
|
|
|
} |
|
3512
|
|
|
|
|
|
|
|
|
3513
|
|
|
|
|
|
|
} else { |
|
3514
|
|
|
|
|
|
|
|
|
3515
|
|
|
|
|
|
|
# print warning |
|
3516
|
0
|
|
|
|
|
0
|
print "selection token 'rows' requires row length (use 'nr' token)\n"; |
|
3517
|
|
|
|
|
|
|
|
|
3518
|
|
|
|
|
|
|
} |
|
3519
|
|
|
|
|
|
|
|
|
3520
|
|
|
|
|
|
|
} else { |
|
3521
|
|
|
|
|
|
|
|
|
3522
|
|
|
|
|
|
|
# print warning |
|
3523
|
0
|
|
|
|
|
0
|
print "selection token 'rows' requires numeric parameter(s)\n"; |
|
3524
|
|
|
|
|
|
|
|
|
3525
|
|
|
|
|
|
|
} |
|
3526
|
|
|
|
|
|
|
|
|
3527
|
|
|
|
|
|
|
# if 'cols' |
|
3528
|
|
|
|
|
|
|
} elsif ($token eq 'cols') { |
|
3529
|
|
|
|
|
|
|
|
|
3530
|
|
|
|
|
|
|
# if numeric parameters |
|
3531
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3532
|
|
|
|
|
|
|
|
|
3533
|
|
|
|
|
|
|
# if row length defined |
|
3534
|
0
|
0
|
|
|
|
0
|
if (defined($row_length)) { |
|
3535
|
|
|
|
|
|
|
|
|
3536
|
|
|
|
|
|
|
# for each column |
|
3537
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#p) { |
|
3538
|
|
|
|
|
|
|
|
|
3539
|
|
|
|
|
|
|
# add column samples |
|
3540
|
0
|
|
|
|
|
0
|
push(@samples, map {$row_length * ($p[$i] - 1) + $_} (1 .. $row_length)); |
|
|
0
|
|
|
|
|
0
|
|
|
3541
|
|
|
|
|
|
|
|
|
3542
|
|
|
|
|
|
|
} |
|
3543
|
|
|
|
|
|
|
|
|
3544
|
|
|
|
|
|
|
} else { |
|
3545
|
|
|
|
|
|
|
|
|
3546
|
|
|
|
|
|
|
# print warning |
|
3547
|
0
|
|
|
|
|
0
|
print "selection token 'cols' requires row length (use 'nr' token)\n"; |
|
3548
|
|
|
|
|
|
|
|
|
3549
|
|
|
|
|
|
|
} |
|
3550
|
|
|
|
|
|
|
|
|
3551
|
|
|
|
|
|
|
} else { |
|
3552
|
|
|
|
|
|
|
|
|
3553
|
|
|
|
|
|
|
# print warning |
|
3554
|
0
|
|
|
|
|
0
|
print "selection token 'cols' requires numeric parameter(s)\n"; |
|
3555
|
|
|
|
|
|
|
|
|
3556
|
|
|
|
|
|
|
} |
|
3557
|
|
|
|
|
|
|
|
|
3558
|
|
|
|
|
|
|
# if 'rect' |
|
3559
|
|
|
|
|
|
|
} elsif ($token eq 'rect') { |
|
3560
|
|
|
|
|
|
|
|
|
3561
|
|
|
|
|
|
|
# if 4 numeric parameters |
|
3562
|
0
|
0
|
|
|
|
0
|
if (@p == 4) { |
|
3563
|
|
|
|
|
|
|
|
|
3564
|
|
|
|
|
|
|
# if row length defined |
|
3565
|
0
|
0
|
|
|
|
0
|
if (defined($row_length)) { |
|
3566
|
|
|
|
|
|
|
|
|
3567
|
|
|
|
|
|
|
# get samples |
|
3568
|
0
|
|
|
|
|
0
|
$mat = select_matrix($self, @p, $row_length); |
|
3569
|
|
|
|
|
|
|
|
|
3570
|
|
|
|
|
|
|
# add column samples (flatten matrix) |
|
3571
|
0
|
|
|
|
|
0
|
push(@samples, map {@{$_}} @{$mat}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3572
|
|
|
|
|
|
|
|
|
3573
|
|
|
|
|
|
|
} else { |
|
3574
|
|
|
|
|
|
|
|
|
3575
|
|
|
|
|
|
|
# print warning |
|
3576
|
0
|
|
|
|
|
0
|
print "selection token 'rect' requires row length (use 'nr' token)\n"; |
|
3577
|
|
|
|
|
|
|
|
|
3578
|
|
|
|
|
|
|
} |
|
3579
|
|
|
|
|
|
|
|
|
3580
|
|
|
|
|
|
|
} else { |
|
3581
|
|
|
|
|
|
|
|
|
3582
|
|
|
|
|
|
|
# print warning |
|
3583
|
0
|
|
|
|
|
0
|
print "selection token 'rect' requires 4 numeric parameters\n"; |
|
3584
|
|
|
|
|
|
|
|
|
3585
|
|
|
|
|
|
|
} |
|
3586
|
|
|
|
|
|
|
|
|
3587
|
|
|
|
|
|
|
# if 'nr' |
|
3588
|
|
|
|
|
|
|
} elsif ($token eq 'nr') { |
|
3589
|
|
|
|
|
|
|
|
|
3590
|
|
|
|
|
|
|
# if numeric parameters |
|
3591
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3592
|
|
|
|
|
|
|
|
|
3593
|
|
|
|
|
|
|
# set the number of rows |
|
3594
|
0
|
|
|
|
|
0
|
$row_length = $p[0]; |
|
3595
|
|
|
|
|
|
|
|
|
3596
|
|
|
|
|
|
|
} else { |
|
3597
|
|
|
|
|
|
|
|
|
3598
|
|
|
|
|
|
|
# print warning |
|
3599
|
0
|
|
|
|
|
0
|
print "selection token 'nr' requires a numeric parameter\n"; |
|
3600
|
|
|
|
|
|
|
|
|
3601
|
|
|
|
|
|
|
} |
|
3602
|
|
|
|
|
|
|
|
|
3603
|
|
|
|
|
|
|
# if 'iso' |
|
3604
|
|
|
|
|
|
|
} elsif ($token eq 'iso') { |
|
3605
|
|
|
|
|
|
|
|
|
3606
|
|
|
|
|
|
|
# if CMY channels defined |
|
3607
|
0
|
0
|
|
|
|
0
|
if (3 == grep {defined($m[$_])} (0 .. 2)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3608
|
|
|
|
|
|
|
|
|
3609
|
|
|
|
|
|
|
# get cmy limit value |
|
3610
|
0
|
|
0
|
|
|
0
|
$lim = ($p[0] // 100)/100; |
|
3611
|
|
|
|
|
|
|
|
|
3612
|
|
|
|
|
|
|
# add isometric samples (C == M == Y, all other channels == 0) and CMY ≤ limit |
|
3613
|
0
|
0
|
0
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@cmy = @_[@m[0 .. 2]]; $cmy[0] == $cmy[1] && $cmy[1] == $cmy[2] && $cmy[0] <= $lim && (0 == grep {$_} @_[@m[3 .. $nx]])}, $hash)}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3614
|
|
|
|
|
|
|
|
|
3615
|
|
|
|
|
|
|
} else { |
|
3616
|
|
|
|
|
|
|
|
|
3617
|
|
|
|
|
|
|
# print warning |
|
3618
|
0
|
|
|
|
|
0
|
print "selection token 'iso', missing ink channel(s)\n"; |
|
3619
|
|
|
|
|
|
|
|
|
3620
|
|
|
|
|
|
|
} |
|
3621
|
|
|
|
|
|
|
|
|
3622
|
|
|
|
|
|
|
# if 'g7' |
|
3623
|
|
|
|
|
|
|
} elsif ($token eq 'g7') { |
|
3624
|
|
|
|
|
|
|
|
|
3625
|
|
|
|
|
|
|
# if CMY channels defined |
|
3626
|
0
|
0
|
|
|
|
0
|
if (3 == grep {defined($m[$_])} (0 .. 2)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3627
|
|
|
|
|
|
|
|
|
3628
|
|
|
|
|
|
|
# get cyan limit value |
|
3629
|
0
|
|
0
|
|
|
0
|
$lim = ($p[0] // 100)/100; |
|
3630
|
|
|
|
|
|
|
|
|
3631
|
|
|
|
|
|
|
# add gray cmy samples, using TR015 formula |
|
3632
|
0
|
0
|
0
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {$c = $_[$m[0]]; $my = 0.747 * $c - 0.041 * $c**2 + 0.294 * $c**3; @cmy = @_[@m[0 .. 2]]; $cmy[0] <= $lim && abs($cmy[1] - $my) <= 0.002 && $cmy[2] == $cmy[1] && (0 == grep {$_} @_[@m[3 .. $nx]])}, $hash)}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3633
|
|
|
|
|
|
|
|
|
3634
|
|
|
|
|
|
|
} else { |
|
3635
|
|
|
|
|
|
|
|
|
3636
|
|
|
|
|
|
|
# print warning |
|
3637
|
0
|
|
|
|
|
0
|
print "selection token 'g7', missing ink channel(s)\n"; |
|
3638
|
|
|
|
|
|
|
|
|
3639
|
|
|
|
|
|
|
} |
|
3640
|
|
|
|
|
|
|
|
|
3641
|
|
|
|
|
|
|
# if 'it8' |
|
3642
|
|
|
|
|
|
|
} elsif ($token eq 'it8') { |
|
3643
|
|
|
|
|
|
|
|
|
3644
|
|
|
|
|
|
|
# if CMY channels defined |
|
3645
|
0
|
0
|
|
|
|
0
|
if (3 == grep {defined($m[$_])} (0 .. 2)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3646
|
|
|
|
|
|
|
|
|
3647
|
|
|
|
|
|
|
# make gray balance hash, as used in IT8.7/3, IT8.7/4, IT8.7/5 charts |
|
3648
|
0
|
|
|
|
|
0
|
%it8 = (0, 0, 5, 3, 10, 6, 20, 12, 40, 27, 60, 45, 80, 65, 100, 85); |
|
3649
|
|
|
|
|
|
|
|
|
3650
|
|
|
|
|
|
|
# get cyan limit value |
|
3651
|
0
|
|
0
|
|
|
0
|
$lim = ($p[0] // 100)/100; |
|
3652
|
|
|
|
|
|
|
|
|
3653
|
|
|
|
|
|
|
# add gray cmy samples |
|
3654
|
0
|
0
|
0
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@cmy = @_[@m[0 .. 2]]; $c = int(100 * $cmy[0] + 0.5); $cmy[0] <= $lim && exists($it8{$c}) && abs($it8{$c}/100 - $cmy[1]) < 0.002 && $cmy[1] == $cmy[2] && (0 == grep {$_} @_[@m[3 .. $nx]])}, $hash)}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3655
|
|
|
|
|
|
|
|
|
3656
|
|
|
|
|
|
|
} else { |
|
3657
|
|
|
|
|
|
|
|
|
3658
|
|
|
|
|
|
|
# print warning |
|
3659
|
0
|
|
|
|
|
0
|
print "selection token 'it8', missing ink channel(s)\n"; |
|
3660
|
|
|
|
|
|
|
|
|
3661
|
|
|
|
|
|
|
} |
|
3662
|
|
|
|
|
|
|
|
|
3663
|
|
|
|
|
|
|
# if 'cmy' |
|
3664
|
|
|
|
|
|
|
} elsif ($token eq 'cmy') { |
|
3665
|
|
|
|
|
|
|
|
|
3666
|
|
|
|
|
|
|
# if CMY channels defined |
|
3667
|
0
|
0
|
|
|
|
0
|
if (3 == grep {defined($m[$_])} (0 .. 2)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3668
|
|
|
|
|
|
|
|
|
3669
|
|
|
|
|
|
|
# get cmy limit value |
|
3670
|
0
|
|
0
|
|
|
0
|
$lim = ($p[0] // 0)/100; |
|
3671
|
|
|
|
|
|
|
|
|
3672
|
|
|
|
|
|
|
# add cmy ramp samples with value ≥ limit |
|
3673
|
0
|
0
|
0
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@cmy = @_[@m[0 .. 2]]; (1 >= grep {$_} @cmy) && (! $lim || (1 == grep {$_ >= $lim} @cmy)) && (0 == grep {$_} @_[@m[3 .. $nx]])}, $hash)}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3674
|
|
|
|
|
|
|
|
|
3675
|
|
|
|
|
|
|
} else { |
|
3676
|
|
|
|
|
|
|
|
|
3677
|
|
|
|
|
|
|
# print warning |
|
3678
|
0
|
|
|
|
|
0
|
print "selection token 'cmy', missing ink channel(s)\n"; |
|
3679
|
|
|
|
|
|
|
|
|
3680
|
|
|
|
|
|
|
} |
|
3681
|
|
|
|
|
|
|
|
|
3682
|
|
|
|
|
|
|
# if 'c+m+y' |
|
3683
|
|
|
|
|
|
|
} elsif ($token eq 'c+m+y') { |
|
3684
|
|
|
|
|
|
|
|
|
3685
|
|
|
|
|
|
|
# if CMY channels defined |
|
3686
|
0
|
0
|
|
|
|
0
|
if (3 == grep {defined($m[$_])} (0 .. 2)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3687
|
|
|
|
|
|
|
|
|
3688
|
|
|
|
|
|
|
# if numeric parameters |
|
3689
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3690
|
|
|
|
|
|
|
|
|
3691
|
|
|
|
|
|
|
# add samples with c+m+y ≤ limit |
|
3692
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {100 * ($_[$m[0]] + $_[$m[1]] + $_[$m[2]]) <= $p[0]}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3693
|
|
|
|
|
|
|
|
|
3694
|
|
|
|
|
|
|
} else { |
|
3695
|
|
|
|
|
|
|
|
|
3696
|
|
|
|
|
|
|
# print warning |
|
3697
|
0
|
|
|
|
|
0
|
print "selection token 'c+m+y' requires a numeric parameter\n"; |
|
3698
|
|
|
|
|
|
|
|
|
3699
|
|
|
|
|
|
|
} |
|
3700
|
|
|
|
|
|
|
|
|
3701
|
|
|
|
|
|
|
} else { |
|
3702
|
|
|
|
|
|
|
|
|
3703
|
|
|
|
|
|
|
# print warning |
|
3704
|
0
|
|
|
|
|
0
|
print "selection token 'c+m+y', missing ink channel(s)\n"; |
|
3705
|
|
|
|
|
|
|
|
|
3706
|
|
|
|
|
|
|
} |
|
3707
|
|
|
|
|
|
|
|
|
3708
|
|
|
|
|
|
|
# if 'tac' |
|
3709
|
|
|
|
|
|
|
} elsif ($token eq 'tac') { |
|
3710
|
|
|
|
|
|
|
|
|
3711
|
|
|
|
|
|
|
# if numeric parameters |
|
3712
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3713
|
|
|
|
|
|
|
|
|
3714
|
|
|
|
|
|
|
# add samples with TAC ≤ limit |
|
3715
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {100 * List::Util::sum(@_) <= $p[0]}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3716
|
|
|
|
|
|
|
|
|
3717
|
|
|
|
|
|
|
} else { |
|
3718
|
|
|
|
|
|
|
|
|
3719
|
|
|
|
|
|
|
# print warning |
|
3720
|
0
|
|
|
|
|
0
|
print "selection token 'tac' requires a numeric parameter\n"; |
|
3721
|
|
|
|
|
|
|
|
|
3722
|
|
|
|
|
|
|
} |
|
3723
|
|
|
|
|
|
|
|
|
3724
|
|
|
|
|
|
|
# if 'gray' |
|
3725
|
|
|
|
|
|
|
} elsif ($token eq 'gray') { |
|
3726
|
|
|
|
|
|
|
|
|
3727
|
|
|
|
|
|
|
# if CMY channels defined |
|
3728
|
0
|
0
|
|
|
|
0
|
if (3 == grep {defined($m[$_])} (0 .. 2)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3729
|
|
|
|
|
|
|
|
|
3730
|
|
|
|
|
|
|
# if the A2B tag is supplied in hash |
|
3731
|
0
|
0
|
|
|
|
0
|
if (defined($A2B = $hash->{'A2B'})) { |
|
3732
|
|
|
|
|
|
|
|
|
3733
|
|
|
|
|
|
|
# make PCS object (profile to L*a*b*, relative colorimetric) |
|
3734
|
0
|
|
|
|
|
0
|
$pcs = ICC::Support::PCS->new([$A2B->pcs], [3]); |
|
3735
|
|
|
|
|
|
|
|
|
3736
|
|
|
|
|
|
|
# get number of input channels |
|
3737
|
0
|
0
|
|
|
|
0
|
$ci = $A2B->cin if (defined($map)); |
|
3738
|
|
|
|
|
|
|
|
|
3739
|
|
|
|
|
|
|
# if one parameter (C* limit) |
|
3740
|
0
|
0
|
|
|
|
0
|
if (@p == 1) { |
|
|
|
0
|
|
|
|
|
|
|
3741
|
|
|
|
|
|
|
|
|
3742
|
|
|
|
|
|
|
# add gray samples (cmy samples only) |
|
3743
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@Lab = $pcs->transform($A2B->transform(_map_array($ci, \@sp, \@si, @_))); sqrt($Lab[1]**2 + $Lab[2]**2) <= $p[0] && (0 == grep {$_} @_[@m[3 .. $nx]])}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3744
|
|
|
|
|
|
|
|
|
3745
|
|
|
|
|
|
|
# if two parameters (C* and L* limits) |
|
3746
|
|
|
|
|
|
|
} elsif (@p) { |
|
3747
|
|
|
|
|
|
|
|
|
3748
|
|
|
|
|
|
|
# add gray samples (cmy samples only) |
|
3749
|
0
|
0
|
0
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@Lab = $pcs->transform($A2B->transform(_map_array($ci, \@sp, \@si, @_))); sqrt($Lab[1]**2 + $Lab[2]**2) <= $p[0] && $Lab[0] >= $p[1] && (0 == grep {$_} @_[@m[3 .. $nx]])}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3750
|
|
|
|
|
|
|
|
|
3751
|
|
|
|
|
|
|
} else { |
|
3752
|
|
|
|
|
|
|
|
|
3753
|
|
|
|
|
|
|
# print warning |
|
3754
|
0
|
|
|
|
|
0
|
print "selection token 'gray' requires numeric parameter(s)\n"; |
|
3755
|
|
|
|
|
|
|
|
|
3756
|
|
|
|
|
|
|
} |
|
3757
|
|
|
|
|
|
|
|
|
3758
|
|
|
|
|
|
|
} else { |
|
3759
|
|
|
|
|
|
|
|
|
3760
|
|
|
|
|
|
|
# print warning |
|
3761
|
0
|
|
|
|
|
0
|
print "selection token 'gray' requires A2B profile tag in hash\n"; |
|
3762
|
|
|
|
|
|
|
|
|
3763
|
|
|
|
|
|
|
} |
|
3764
|
|
|
|
|
|
|
|
|
3765
|
|
|
|
|
|
|
} else { |
|
3766
|
|
|
|
|
|
|
|
|
3767
|
|
|
|
|
|
|
# print warning |
|
3768
|
0
|
|
|
|
|
0
|
print "selection token 'gray', missing ink channel(s)\n"; |
|
3769
|
|
|
|
|
|
|
|
|
3770
|
|
|
|
|
|
|
} |
|
3771
|
|
|
|
|
|
|
|
|
3772
|
|
|
|
|
|
|
# if 'rt' |
|
3773
|
|
|
|
|
|
|
} elsif ($token eq 'rt') { |
|
3774
|
|
|
|
|
|
|
|
|
3775
|
|
|
|
|
|
|
# if CMYK channels defined |
|
3776
|
0
|
0
|
|
|
|
0
|
if (4 == grep {defined($m[$_])} (0 .. 3)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3777
|
|
|
|
|
|
|
|
|
3778
|
|
|
|
|
|
|
# if the A2B and B2A tags are supplied in hash |
|
3779
|
0
|
0
|
0
|
|
|
0
|
if (defined($A2B = $hash->{'A2B'}) && defined($B2A = $hash->{'B2A'})) { |
|
3780
|
|
|
|
|
|
|
|
|
3781
|
|
|
|
|
|
|
# get number of input channels |
|
3782
|
0
|
0
|
|
|
|
0
|
$ci = $A2B->cin if (defined($map)); |
|
3783
|
|
|
|
|
|
|
|
|
3784
|
|
|
|
|
|
|
# if numeric parameters |
|
3785
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3786
|
|
|
|
|
|
|
|
|
3787
|
|
|
|
|
|
|
# add samples with round-trip black change less than the limit |
|
3788
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@dev = $B2A->transform($A2B->transform(_map_array($ci, \@sp, \@si, @_))); 100 * abs($_[$m[3]] - $dev[3]) <= $p[0]}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3789
|
|
|
|
|
|
|
|
|
3790
|
|
|
|
|
|
|
} else { |
|
3791
|
|
|
|
|
|
|
|
|
3792
|
|
|
|
|
|
|
# print warning |
|
3793
|
0
|
|
|
|
|
0
|
print "selection token 'rt' requires a numeric parameter\n"; |
|
3794
|
|
|
|
|
|
|
|
|
3795
|
|
|
|
|
|
|
} |
|
3796
|
|
|
|
|
|
|
|
|
3797
|
|
|
|
|
|
|
} else { |
|
3798
|
|
|
|
|
|
|
|
|
3799
|
|
|
|
|
|
|
# print warning |
|
3800
|
0
|
|
|
|
|
0
|
print "selection token 'rt' requires A2B and B2A profile tags in hash\n"; |
|
3801
|
|
|
|
|
|
|
|
|
3802
|
|
|
|
|
|
|
} |
|
3803
|
|
|
|
|
|
|
|
|
3804
|
|
|
|
|
|
|
} else { |
|
3805
|
|
|
|
|
|
|
|
|
3806
|
|
|
|
|
|
|
# print warning |
|
3807
|
0
|
|
|
|
|
0
|
print "selection token 'rt', missing ink channel(s)\n"; |
|
3808
|
|
|
|
|
|
|
|
|
3809
|
|
|
|
|
|
|
} |
|
3810
|
|
|
|
|
|
|
|
|
3811
|
|
|
|
|
|
|
# if 'c' |
|
3812
|
|
|
|
|
|
|
} elsif ($token eq 'c') { |
|
3813
|
|
|
|
|
|
|
|
|
3814
|
|
|
|
|
|
|
# if cyan channel defined |
|
3815
|
0
|
0
|
|
|
|
0
|
if (defined($m[0])) { |
|
3816
|
|
|
|
|
|
|
|
|
3817
|
|
|
|
|
|
|
# add cyan-only samples |
|
3818
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {$_[$m[0]] = 0; 0 == grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3819
|
|
|
|
|
|
|
|
|
3820
|
|
|
|
|
|
|
} else { |
|
3821
|
|
|
|
|
|
|
|
|
3822
|
|
|
|
|
|
|
# print warning |
|
3823
|
0
|
|
|
|
|
0
|
print "selection token 'c', missing ink channel(s)\n"; |
|
3824
|
|
|
|
|
|
|
|
|
3825
|
|
|
|
|
|
|
} |
|
3826
|
|
|
|
|
|
|
|
|
3827
|
|
|
|
|
|
|
# if 'm' |
|
3828
|
|
|
|
|
|
|
} elsif ($token eq 'm') { |
|
3829
|
|
|
|
|
|
|
|
|
3830
|
|
|
|
|
|
|
# if magenta channel defined |
|
3831
|
0
|
0
|
|
|
|
0
|
if (defined($m[1])) { |
|
3832
|
|
|
|
|
|
|
|
|
3833
|
|
|
|
|
|
|
# add magenta-only samples |
|
3834
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {$_[$m[1]] = 0; 0 == grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3835
|
|
|
|
|
|
|
|
|
3836
|
|
|
|
|
|
|
} else { |
|
3837
|
|
|
|
|
|
|
|
|
3838
|
|
|
|
|
|
|
# print warning |
|
3839
|
0
|
|
|
|
|
0
|
print "selection token 'm', missing ink channel(s)\n"; |
|
3840
|
|
|
|
|
|
|
|
|
3841
|
|
|
|
|
|
|
} |
|
3842
|
|
|
|
|
|
|
|
|
3843
|
|
|
|
|
|
|
# if 'y' |
|
3844
|
|
|
|
|
|
|
} elsif ($token eq 'y') { |
|
3845
|
|
|
|
|
|
|
|
|
3846
|
|
|
|
|
|
|
# if yellow channel defined |
|
3847
|
0
|
0
|
|
|
|
0
|
if (defined($m[2])) { |
|
3848
|
|
|
|
|
|
|
|
|
3849
|
|
|
|
|
|
|
# add yellow-only samples |
|
3850
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {$_[$m[2]] = 0; 0 == grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3851
|
|
|
|
|
|
|
|
|
3852
|
|
|
|
|
|
|
} else { |
|
3853
|
|
|
|
|
|
|
|
|
3854
|
|
|
|
|
|
|
# print warning |
|
3855
|
0
|
|
|
|
|
0
|
print "selection token 'y', missing ink channel(s)\n"; |
|
3856
|
|
|
|
|
|
|
|
|
3857
|
|
|
|
|
|
|
} |
|
3858
|
|
|
|
|
|
|
|
|
3859
|
|
|
|
|
|
|
# if 'k' |
|
3860
|
|
|
|
|
|
|
} elsif ($token eq 'k') { |
|
3861
|
|
|
|
|
|
|
|
|
3862
|
|
|
|
|
|
|
# if black channel defined |
|
3863
|
0
|
0
|
|
|
|
0
|
if (defined($m[3])) { |
|
3864
|
|
|
|
|
|
|
|
|
3865
|
|
|
|
|
|
|
# add black-only samples |
|
3866
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {$_[$m[3]] = 0; 0 == grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3867
|
|
|
|
|
|
|
|
|
3868
|
|
|
|
|
|
|
} else { |
|
3869
|
|
|
|
|
|
|
|
|
3870
|
|
|
|
|
|
|
# print warning |
|
3871
|
0
|
|
|
|
|
0
|
print "selection token 'k', missing ink channel(s)\n"; |
|
3872
|
|
|
|
|
|
|
|
|
3873
|
|
|
|
|
|
|
} |
|
3874
|
|
|
|
|
|
|
|
|
3875
|
|
|
|
|
|
|
# if 'cmyk' |
|
3876
|
|
|
|
|
|
|
} elsif ($token eq 'cmyk') { |
|
3877
|
|
|
|
|
|
|
|
|
3878
|
|
|
|
|
|
|
# if CMYK channels defined |
|
3879
|
0
|
0
|
|
|
|
0
|
if (4 == grep {defined($m[$_])} (0 .. 3)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3880
|
|
|
|
|
|
|
|
|
3881
|
|
|
|
|
|
|
# add cmyk ramps (number of non-zero CMYK channels ≤ 1, all extra channels == 0) |
|
3882
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {(1 >= grep {$_} @_[@m[0 .. 3]]) && (0 == grep {$_} @_[@m[4 .. $nx]])}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3883
|
|
|
|
|
|
|
|
|
3884
|
|
|
|
|
|
|
} else { |
|
3885
|
|
|
|
|
|
|
|
|
3886
|
|
|
|
|
|
|
# print warning |
|
3887
|
0
|
|
|
|
|
0
|
print "selection token 'cmyk', missing ink channel(s)\n"; |
|
3888
|
|
|
|
|
|
|
|
|
3889
|
|
|
|
|
|
|
} |
|
3890
|
|
|
|
|
|
|
|
|
3891
|
|
|
|
|
|
|
# if 'ramps' |
|
3892
|
|
|
|
|
|
|
} elsif ($token eq 'ramps') { |
|
3893
|
|
|
|
|
|
|
|
|
3894
|
|
|
|
|
|
|
# if numeric parameters |
|
3895
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3896
|
|
|
|
|
|
|
|
|
3897
|
|
|
|
|
|
|
# for each parameter |
|
3898
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#p) { |
|
3899
|
|
|
|
|
|
|
|
|
3900
|
|
|
|
|
|
|
# if parameter a valid ink channel |
|
3901
|
0
|
0
|
0
|
|
|
0
|
if ($p[$i] == int($p[$i]) && $p[$i] > 0 && $p[$i] <= $n) { |
|
|
|
|
0
|
|
|
|
|
|
3902
|
|
|
|
|
|
|
|
|
3903
|
|
|
|
|
|
|
# add ramp($i) |
|
3904
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {$_[$p[$i] - 1] = 0; 0 == grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3905
|
|
|
|
|
|
|
|
|
3906
|
|
|
|
|
|
|
} else { |
|
3907
|
|
|
|
|
|
|
|
|
3908
|
|
|
|
|
|
|
# print warning |
|
3909
|
0
|
|
|
|
|
0
|
print "selection token 'ramps', channel $p[$i] is invalid\n"; |
|
3910
|
|
|
|
|
|
|
|
|
3911
|
|
|
|
|
|
|
} |
|
3912
|
|
|
|
|
|
|
|
|
3913
|
|
|
|
|
|
|
} |
|
3914
|
|
|
|
|
|
|
|
|
3915
|
|
|
|
|
|
|
} else { |
|
3916
|
|
|
|
|
|
|
|
|
3917
|
|
|
|
|
|
|
# add all device ramps (number of non-zero channels ≤ 1) |
|
3918
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {1 >= grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3919
|
|
|
|
|
|
|
|
|
3920
|
|
|
|
|
|
|
} |
|
3921
|
|
|
|
|
|
|
|
|
3922
|
|
|
|
|
|
|
# if 'inks' |
|
3923
|
|
|
|
|
|
|
} elsif ($token eq 'inks') { |
|
3924
|
|
|
|
|
|
|
|
|
3925
|
|
|
|
|
|
|
# if numeric parameters |
|
3926
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
3927
|
|
|
|
|
|
|
|
|
3928
|
|
|
|
|
|
|
# if valid ink channels |
|
3929
|
0
|
0
|
0
|
|
|
0
|
if (@p == grep {$_ == int($_) && $_ > 0 && $_ <= $n} @p) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
3930
|
|
|
|
|
|
|
|
|
3931
|
|
|
|
|
|
|
# convert ink channels to array indices |
|
3932
|
0
|
|
|
|
|
0
|
@p = map {$_ - 1} @p; |
|
|
0
|
|
|
|
|
0
|
|
|
3933
|
|
|
|
|
|
|
|
|
3934
|
|
|
|
|
|
|
# add samples containing these inks |
|
3935
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@_[@p] = ((0) x @p); 0 == grep {$_} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3936
|
|
|
|
|
|
|
|
|
3937
|
|
|
|
|
|
|
} else { |
|
3938
|
|
|
|
|
|
|
|
|
3939
|
|
|
|
|
|
|
# print warning |
|
3940
|
0
|
|
|
|
|
0
|
print "selection token 'inks', invalid ink channel(s)\n"; |
|
3941
|
|
|
|
|
|
|
|
|
3942
|
|
|
|
|
|
|
} |
|
3943
|
|
|
|
|
|
|
|
|
3944
|
|
|
|
|
|
|
} else { |
|
3945
|
|
|
|
|
|
|
|
|
3946
|
|
|
|
|
|
|
# print warning |
|
3947
|
0
|
|
|
|
|
0
|
print "selection token 'inks' requires numeric parameter(s)\n"; |
|
3948
|
|
|
|
|
|
|
|
|
3949
|
|
|
|
|
|
|
} |
|
3950
|
|
|
|
|
|
|
|
|
3951
|
|
|
|
|
|
|
# if 'binary' |
|
3952
|
|
|
|
|
|
|
} elsif ($token eq 'binary') { |
|
3953
|
|
|
|
|
|
|
|
|
3954
|
|
|
|
|
|
|
# add binary samples (device value ≈ 0 or 1) |
|
3955
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@_ == grep {abs($_) < 1E-9 || abs($_ - 1) < 1E-9} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3956
|
|
|
|
|
|
|
|
|
3957
|
|
|
|
|
|
|
# if 'solid' |
|
3958
|
|
|
|
|
|
|
} elsif ($token eq 'solid') { |
|
3959
|
|
|
|
|
|
|
|
|
3960
|
|
|
|
|
|
|
# add solid ink samples (one device value == 1, all others == 0) |
|
3961
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {(1 == grep {$_ == 1} @_) && (@_ - 1 == grep {$_ == 0} @_)}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3962
|
|
|
|
|
|
|
|
|
3963
|
|
|
|
|
|
|
# if 'sub' |
|
3964
|
|
|
|
|
|
|
} elsif ($token eq 'sub') { |
|
3965
|
|
|
|
|
|
|
|
|
3966
|
|
|
|
|
|
|
# add substrate samples (all device values == 0) |
|
3967
|
0
|
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@_ == grep {$_ == 0} @_}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3968
|
|
|
|
|
|
|
|
|
3969
|
|
|
|
|
|
|
# if 'acro' |
|
3970
|
|
|
|
|
|
|
} elsif ($token eq 'acro') { |
|
3971
|
|
|
|
|
|
|
|
|
3972
|
|
|
|
|
|
|
# if CMYK channels defined |
|
3973
|
0
|
0
|
|
|
|
0
|
if (4 == grep {defined($m[$_])} (0 .. 3)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3974
|
|
|
|
|
|
|
|
|
3975
|
|
|
|
|
|
|
# add achromatic samples (one or more cmy channels == 0, all extra channels == 0) |
|
3976
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {(1 <= grep {$_ == 0} @_[@m[0 .. 2]]) && (0 == grep {$_} @_[@m[4 .. $nx]])}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3977
|
|
|
|
|
|
|
|
|
3978
|
|
|
|
|
|
|
} else { |
|
3979
|
|
|
|
|
|
|
|
|
3980
|
|
|
|
|
|
|
# print warning |
|
3981
|
0
|
|
|
|
|
0
|
print "selection token 'acro', missing ink channel(s)\n"; |
|
3982
|
|
|
|
|
|
|
|
|
3983
|
|
|
|
|
|
|
} |
|
3984
|
|
|
|
|
|
|
|
|
3985
|
|
|
|
|
|
|
# if 'gamut' |
|
3986
|
|
|
|
|
|
|
} elsif ($token eq 'gamut') { |
|
3987
|
|
|
|
|
|
|
|
|
3988
|
|
|
|
|
|
|
# if CMYK channels defined |
|
3989
|
0
|
0
|
|
|
|
0
|
if (4 == grep {defined($m[$_])} (0 .. 3)) { |
|
|
0
|
|
|
|
|
0
|
|
|
3990
|
|
|
|
|
|
|
|
|
3991
|
|
|
|
|
|
|
# add gamut samples (k == 0) |
|
3992
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@cmy = @_[@m[0 .. 2]]; $_[$m[3]] == 0 && 0 < grep {$_ == 0} @cmy}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3993
|
|
|
|
|
|
|
|
|
3994
|
|
|
|
|
|
|
# add gamut samples (k == 1) |
|
3995
|
0
|
0
|
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@cmy = @_[@m[0 .. 2]]; $_[$m[3]] == 1 && 0 < grep {$_ == 1} @cmy}, $hash)}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3996
|
|
|
|
|
|
|
|
|
3997
|
|
|
|
|
|
|
# add gamut samples (0 < k < 1) |
|
3998
|
0
|
0
|
0
|
0
|
|
0
|
push(@samples, @{ramp($self, sub {@cmy = @_[@m[0 .. 2]]; $_[$m[3]] > 0 && $_[$m[3]] < 1 && (0 < grep {$_ == 0} @cmy) && (0 < grep {$_ == 1} @cmy)}, $hash)}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3999
|
|
|
|
|
|
|
|
|
4000
|
|
|
|
|
|
|
} else { |
|
4001
|
|
|
|
|
|
|
|
|
4002
|
|
|
|
|
|
|
# print warning |
|
4003
|
0
|
|
|
|
|
0
|
print "selection token 'gamut', missing ink channel(s)\n"; |
|
4004
|
|
|
|
|
|
|
|
|
4005
|
|
|
|
|
|
|
} |
|
4006
|
|
|
|
|
|
|
|
|
4007
|
|
|
|
|
|
|
# if 'plus' |
|
4008
|
|
|
|
|
|
|
} elsif ($token eq 'plus') { |
|
4009
|
|
|
|
|
|
|
|
|
4010
|
|
|
|
|
|
|
# if numeric parameters |
|
4011
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
4012
|
|
|
|
|
|
|
|
|
4013
|
|
|
|
|
|
|
# select valid sample numbers |
|
4014
|
0
|
0
|
0
|
|
|
0
|
@sn = grep {$_ == int($_) && $_ >= 1 && $_ <= $sz} @p; |
|
|
0
|
|
|
|
|
0
|
|
|
4015
|
|
|
|
|
|
|
|
|
4016
|
|
|
|
|
|
|
# print warning if invalid sample numbers |
|
4017
|
0
|
0
|
|
|
|
0
|
print "selection token 'plus' has invalid sample numbers\n" if (@sn != @p); |
|
4018
|
|
|
|
|
|
|
|
|
4019
|
|
|
|
|
|
|
# add samples |
|
4020
|
0
|
|
|
|
|
0
|
push(@samples, @sn); |
|
4021
|
|
|
|
|
|
|
|
|
4022
|
|
|
|
|
|
|
} else { |
|
4023
|
|
|
|
|
|
|
|
|
4024
|
|
|
|
|
|
|
# print warning |
|
4025
|
0
|
|
|
|
|
0
|
print "selection token 'plus' requires numeric parameter(s)\n"; |
|
4026
|
|
|
|
|
|
|
|
|
4027
|
|
|
|
|
|
|
} |
|
4028
|
|
|
|
|
|
|
|
|
4029
|
|
|
|
|
|
|
# if 'minus' |
|
4030
|
|
|
|
|
|
|
} elsif ($token eq 'minus') { |
|
4031
|
|
|
|
|
|
|
|
|
4032
|
|
|
|
|
|
|
# if numeric parameters |
|
4033
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
4034
|
|
|
|
|
|
|
|
|
4035
|
|
|
|
|
|
|
# select valid sample numbers, and add to hash |
|
4036
|
0
|
0
|
0
|
|
|
0
|
@sn = grep {$_ == int($_) && $_ >= 1 && $_ <= $sz && ($minus{$_} = 1)} @p; |
|
|
0
|
|
0
|
|
|
0
|
|
|
4037
|
|
|
|
|
|
|
|
|
4038
|
|
|
|
|
|
|
# print warning if invalid sample numbers |
|
4039
|
0
|
0
|
|
|
|
0
|
print "selection token 'minus' has invalid sample numbers\n" if (@sn != @p); |
|
4040
|
|
|
|
|
|
|
|
|
4041
|
|
|
|
|
|
|
} else { |
|
4042
|
|
|
|
|
|
|
|
|
4043
|
|
|
|
|
|
|
# print warning |
|
4044
|
0
|
|
|
|
|
0
|
print "selection token 'minus' requires numeric parameter(s)\n"; |
|
4045
|
|
|
|
|
|
|
|
|
4046
|
|
|
|
|
|
|
} |
|
4047
|
|
|
|
|
|
|
|
|
4048
|
|
|
|
|
|
|
# if 'max' |
|
4049
|
|
|
|
|
|
|
} elsif ($token eq 'max') { |
|
4050
|
|
|
|
|
|
|
|
|
4051
|
|
|
|
|
|
|
# if numeric parameters |
|
4052
|
0
|
0
|
|
|
|
0
|
if (@p) { |
|
4053
|
|
|
|
|
|
|
|
|
4054
|
|
|
|
|
|
|
# verify ink limits |
|
4055
|
0
|
0
|
0
|
|
|
0
|
@max = map {$_/100} grep {Scalar::Util::looks_like_number($_) && $_ >= 0 && $_ <= 100} @p; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4056
|
|
|
|
|
|
|
|
|
4057
|
|
|
|
|
|
|
# if ink limit(s) invalid |
|
4058
|
0
|
0
|
|
|
|
0
|
if (@max != @p) { |
|
|
|
0
|
|
|
|
|
|
|
4059
|
|
|
|
|
|
|
|
|
4060
|
|
|
|
|
|
|
# print warning if invalid ink limits |
|
4061
|
0
|
|
|
|
|
0
|
print "selection token 'max' has invalid ink limit(s)\n"; |
|
4062
|
|
|
|
|
|
|
|
|
4063
|
|
|
|
|
|
|
# if wrong number of values |
|
4064
|
|
|
|
|
|
|
} elsif (@max != $n) { |
|
4065
|
|
|
|
|
|
|
|
|
4066
|
|
|
|
|
|
|
# print warning if wrong number of values |
|
4067
|
0
|
|
|
|
|
0
|
print "selection token 'max' has wrong number of values\n"; |
|
4068
|
|
|
|
|
|
|
|
|
4069
|
|
|
|
|
|
|
} |
|
4070
|
|
|
|
|
|
|
|
|
4071
|
|
|
|
|
|
|
} else { |
|
4072
|
|
|
|
|
|
|
|
|
4073
|
|
|
|
|
|
|
# print warning |
|
4074
|
0
|
|
|
|
|
0
|
print "selection token 'max' requires numeric parameter(s)\n"; |
|
4075
|
|
|
|
|
|
|
|
|
4076
|
|
|
|
|
|
|
} |
|
4077
|
|
|
|
|
|
|
|
|
4078
|
|
|
|
|
|
|
# if 'nok' (no samples containing black) |
|
4079
|
|
|
|
|
|
|
} elsif ($token eq 'nok') { |
|
4080
|
|
|
|
|
|
|
|
|
4081
|
|
|
|
|
|
|
# set flag |
|
4082
|
0
|
|
|
|
|
0
|
$fnk = 1; |
|
4083
|
|
|
|
|
|
|
|
|
4084
|
|
|
|
|
|
|
# if 'nosub' (no substrate samples) |
|
4085
|
|
|
|
|
|
|
} elsif ($token eq 'nosub') { |
|
4086
|
|
|
|
|
|
|
|
|
4087
|
|
|
|
|
|
|
# set flag |
|
4088
|
0
|
|
|
|
|
0
|
$fns = 1; |
|
4089
|
|
|
|
|
|
|
|
|
4090
|
|
|
|
|
|
|
# if 'nobin' (no binary samples) |
|
4091
|
|
|
|
|
|
|
} elsif ($token eq 'nobin') { |
|
4092
|
|
|
|
|
|
|
|
|
4093
|
|
|
|
|
|
|
# set flag |
|
4094
|
0
|
|
|
|
|
0
|
$fnb = 1; |
|
4095
|
|
|
|
|
|
|
|
|
4096
|
|
|
|
|
|
|
} else { |
|
4097
|
|
|
|
|
|
|
|
|
4098
|
|
|
|
|
|
|
# print warning |
|
4099
|
0
|
|
|
|
|
0
|
printf "selection token '%s' not recognized\n", $token; |
|
4100
|
|
|
|
|
|
|
|
|
4101
|
|
|
|
|
|
|
} |
|
4102
|
|
|
|
|
|
|
|
|
4103
|
|
|
|
|
|
|
} |
|
4104
|
|
|
|
|
|
|
|
|
4105
|
|
|
|
|
|
|
# initialize hash |
|
4106
|
0
|
|
|
|
|
0
|
%unique = (); |
|
4107
|
|
|
|
|
|
|
|
|
4108
|
|
|
|
|
|
|
# remove duplicates and sort |
|
4109
|
0
|
0
|
0
|
|
|
0
|
@samples = sort {$a <=> $b} grep {$_ >= 1 && $_ <= $sz && ++$unique{$_} == 1} @samples; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4110
|
|
|
|
|
|
|
|
|
4111
|
|
|
|
|
|
|
# remove 'minus' samples |
|
4112
|
0
|
|
|
|
|
0
|
@samples = grep {! exists($minus{$_})} @samples; |
|
|
0
|
|
|
|
|
0
|
|
|
4113
|
|
|
|
|
|
|
|
|
4114
|
|
|
|
|
|
|
# remove samples containing black, if flag set |
|
4115
|
0
|
0
|
0
|
0
|
|
0
|
@samples = @{ramp($self, sub {abs($_[$m[3]]) < 1E-9}, \@samples, $hash)} if (@samples && $fnk && defined($m[3])); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4116
|
|
|
|
|
|
|
|
|
4117
|
|
|
|
|
|
|
# remove substrate samples, if flag set |
|
4118
|
0
|
0
|
0
|
0
|
|
0
|
@samples = @{ramp($self, sub {grep {abs($_ - $sub) >= 1E-9} @_}, \@samples, $hash)} if (@samples && $fns); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4119
|
|
|
|
|
|
|
|
|
4120
|
|
|
|
|
|
|
# remove binary samples, if flag set |
|
4121
|
0
|
0
|
0
|
0
|
|
0
|
@samples = @{ramp($self, sub {grep {abs($_) >= 1E-9 && abs($_ - 1) >= 1E-9} @_}, \@samples, $hash)} if (@samples && $fnb); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4122
|
|
|
|
|
|
|
|
|
4123
|
|
|
|
|
|
|
# remove max samples, if max array defined |
|
4124
|
0
|
0
|
0
|
0
|
|
0
|
@samples = @{ramp($self, sub {! grep {$_[$_] > $max[$_]} (0 .. $nx)}, \@samples, $hash)} if (@samples && @max); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4125
|
|
|
|
|
|
|
|
|
4126
|
|
|
|
|
|
|
# sort samples by device values, if sort vector provided (in hash or as a token) |
|
4127
|
0
|
0
|
0
|
|
|
0
|
@samples = @{ICC::Support::Chart::sort($self, \@samples, $sort)} if (@samples && $sort); |
|
|
0
|
|
|
|
|
0
|
|
|
4128
|
|
|
|
|
|
|
|
|
4129
|
|
|
|
|
|
|
# return |
|
4130
|
0
|
|
|
|
|
0
|
return(\@samples); |
|
4131
|
|
|
|
|
|
|
|
|
4132
|
|
|
|
|
|
|
} |
|
4133
|
|
|
|
|
|
|
|
|
4134
|
|
|
|
|
|
|
# get sample selection based on 2-D location |
|
4135
|
|
|
|
|
|
|
# indices are one-based, with origin at the upper left |
|
4136
|
|
|
|
|
|
|
# row matrix slice may contain indices of undefined rows |
|
4137
|
|
|
|
|
|
|
# entire chart is used when the row and column indices are omitted |
|
4138
|
|
|
|
|
|
|
# chart row length is provided as a parameter, or obtained from the data |
|
4139
|
|
|
|
|
|
|
# parameters: ([upper_row_index, lower_row_index, left_column_index, right_column_index], [chart_row_length]) |
|
4140
|
|
|
|
|
|
|
# returns: (row_matrix_slice) |
|
4141
|
|
|
|
|
|
|
sub select_matrix { |
|
4142
|
|
|
|
|
|
|
|
|
4143
|
|
|
|
|
|
|
# get object reference |
|
4144
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
4145
|
|
|
|
|
|
|
|
|
4146
|
|
|
|
|
|
|
# local variables |
|
4147
|
0
|
|
|
|
|
0
|
my ($sn, $cmax, @rows, @cols, $matrix); |
|
4148
|
0
|
|
|
|
|
0
|
my ($row_length, $upper, $lower, $left, $right); |
|
4149
|
|
|
|
|
|
|
|
|
4150
|
|
|
|
|
|
|
# get number of samples |
|
4151
|
0
|
|
|
|
|
0
|
$sn = $#{$self->[1]}; |
|
|
0
|
|
|
|
|
0
|
|
|
4152
|
|
|
|
|
|
|
|
|
4153
|
|
|
|
|
|
|
# if 0 or 4 parameters |
|
4154
|
0
|
0
|
0
|
|
|
0
|
if (@_ == 0 || @_ == 4) { |
|
|
|
0
|
0
|
|
|
|
|
|
4155
|
|
|
|
|
|
|
|
|
4156
|
|
|
|
|
|
|
# get row length from data |
|
4157
|
0
|
|
|
|
|
0
|
$row_length = _getRowLength($self); |
|
4158
|
|
|
|
|
|
|
|
|
4159
|
|
|
|
|
|
|
# if 1 or 5 parameters |
|
4160
|
|
|
|
|
|
|
} elsif (@_ == 1 || @_ == 5) { |
|
4161
|
|
|
|
|
|
|
|
|
4162
|
|
|
|
|
|
|
# get row length |
|
4163
|
0
|
|
|
|
|
0
|
$row_length = pop(); |
|
4164
|
|
|
|
|
|
|
|
|
4165
|
|
|
|
|
|
|
# verify row length |
|
4166
|
0
|
0
|
0
|
|
|
0
|
(Scalar::Util::looks_like_number($row_length) && $row_length == int($row_length) && $row_length > 0) or croak('invalid chart row length'); |
|
|
|
|
0
|
|
|
|
|
|
4167
|
|
|
|
|
|
|
|
|
4168
|
|
|
|
|
|
|
} else { |
|
4169
|
|
|
|
|
|
|
|
|
4170
|
|
|
|
|
|
|
# error |
|
4171
|
0
|
|
|
|
|
0
|
croak('wrong number of parameters'); |
|
4172
|
|
|
|
|
|
|
|
|
4173
|
|
|
|
|
|
|
} |
|
4174
|
|
|
|
|
|
|
|
|
4175
|
|
|
|
|
|
|
# if row and column parameters provided |
|
4176
|
0
|
0
|
|
|
|
0
|
if (@_) { |
|
4177
|
|
|
|
|
|
|
|
|
4178
|
|
|
|
|
|
|
# get row and column parameters |
|
4179
|
0
|
|
|
|
|
0
|
($upper, $lower, $left, $right) = @_; |
|
4180
|
|
|
|
|
|
|
|
|
4181
|
|
|
|
|
|
|
# verify upper and lower indices |
|
4182
|
0
|
0
|
0
|
|
|
0
|
(! ref($upper) && $upper == int($upper) && $upper > 0 && $upper <= $row_length) || warn('invalid upper row index'); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
4183
|
0
|
0
|
0
|
|
|
0
|
(! ref($lower) && $lower == int($lower) && $lower > 0 && $lower <= $row_length) || warn('invalid lower row index'); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
4184
|
|
|
|
|
|
|
|
|
4185
|
|
|
|
|
|
|
# get maximum column index |
|
4186
|
0
|
0
|
|
|
|
0
|
$cmax = $sn % $row_length ? int($sn/$row_length) + 1 : int($sn/$row_length); |
|
4187
|
|
|
|
|
|
|
|
|
4188
|
|
|
|
|
|
|
# verify left and right indices |
|
4189
|
0
|
0
|
0
|
|
|
0
|
(! ref($left) && $left == int($left) && $left > 0 && $left <= $cmax) || warn('invalid left column index'); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
4190
|
0
|
0
|
0
|
|
|
0
|
(! ref($right) && $right == int($right) && $right > 0 && $right <= $cmax) || warn('invalid right column index'); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
4191
|
|
|
|
|
|
|
|
|
4192
|
|
|
|
|
|
|
# if upper index < lower index |
|
4193
|
0
|
0
|
|
|
|
0
|
if ($upper < $lower) { |
|
4194
|
|
|
|
|
|
|
|
|
4195
|
|
|
|
|
|
|
# make rows array |
|
4196
|
0
|
|
|
|
|
0
|
@rows = ($upper .. $lower); |
|
4197
|
|
|
|
|
|
|
|
|
4198
|
|
|
|
|
|
|
} else { |
|
4199
|
|
|
|
|
|
|
|
|
4200
|
|
|
|
|
|
|
# make rows array |
|
4201
|
0
|
|
|
|
|
0
|
@rows = reverse($lower .. $upper); |
|
4202
|
|
|
|
|
|
|
|
|
4203
|
|
|
|
|
|
|
} |
|
4204
|
|
|
|
|
|
|
|
|
4205
|
|
|
|
|
|
|
# if left index < right index |
|
4206
|
0
|
0
|
|
|
|
0
|
if ($left < $right) { |
|
4207
|
|
|
|
|
|
|
|
|
4208
|
|
|
|
|
|
|
# make columns array |
|
4209
|
0
|
|
|
|
|
0
|
@cols = ($left .. $right); |
|
4210
|
|
|
|
|
|
|
|
|
4211
|
|
|
|
|
|
|
} else { |
|
4212
|
|
|
|
|
|
|
|
|
4213
|
|
|
|
|
|
|
# make columns array |
|
4214
|
0
|
|
|
|
|
0
|
@cols = reverse($right .. $left); |
|
4215
|
|
|
|
|
|
|
|
|
4216
|
|
|
|
|
|
|
} |
|
4217
|
|
|
|
|
|
|
|
|
4218
|
|
|
|
|
|
|
# use entire chart |
|
4219
|
|
|
|
|
|
|
} else { |
|
4220
|
|
|
|
|
|
|
|
|
4221
|
|
|
|
|
|
|
# make rows array |
|
4222
|
0
|
|
|
|
|
0
|
@rows = (1 .. $row_length); |
|
4223
|
|
|
|
|
|
|
|
|
4224
|
|
|
|
|
|
|
# if chart is rectangular |
|
4225
|
0
|
0
|
|
|
|
0
|
if ($sn % $row_length == 0) { |
|
4226
|
|
|
|
|
|
|
|
|
4227
|
|
|
|
|
|
|
# make columns array |
|
4228
|
0
|
|
|
|
|
0
|
@cols = (1 .. $sn/$row_length); |
|
4229
|
|
|
|
|
|
|
|
|
4230
|
|
|
|
|
|
|
} else { |
|
4231
|
|
|
|
|
|
|
|
|
4232
|
|
|
|
|
|
|
# warning |
|
4233
|
0
|
|
|
|
|
0
|
warn('chart is not rectangular'); |
|
4234
|
|
|
|
|
|
|
|
|
4235
|
|
|
|
|
|
|
# make columns array |
|
4236
|
0
|
|
|
|
|
0
|
@cols = (1 .. int($sn/$row_length) + 1); |
|
4237
|
|
|
|
|
|
|
|
|
4238
|
|
|
|
|
|
|
} |
|
4239
|
|
|
|
|
|
|
|
|
4240
|
|
|
|
|
|
|
} |
|
4241
|
|
|
|
|
|
|
|
|
4242
|
|
|
|
|
|
|
# for each row |
|
4243
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#rows) { |
|
4244
|
|
|
|
|
|
|
|
|
4245
|
|
|
|
|
|
|
# for each column |
|
4246
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#cols) { |
|
4247
|
|
|
|
|
|
|
|
|
4248
|
|
|
|
|
|
|
# set matrix element |
|
4249
|
0
|
|
|
|
|
0
|
$matrix->[$j][$i] = ($cols[$j] - 1) * $row_length + $rows[$i]; |
|
4250
|
|
|
|
|
|
|
|
|
4251
|
|
|
|
|
|
|
} |
|
4252
|
|
|
|
|
|
|
|
|
4253
|
|
|
|
|
|
|
} |
|
4254
|
|
|
|
|
|
|
|
|
4255
|
|
|
|
|
|
|
# return row matrix slice |
|
4256
|
0
|
|
|
|
|
0
|
return(bless($matrix, 'Math::Matrix')); |
|
4257
|
|
|
|
|
|
|
|
|
4258
|
|
|
|
|
|
|
} |
|
4259
|
|
|
|
|
|
|
|
|
4260
|
|
|
|
|
|
|
# get sample selection using template |
|
4261
|
|
|
|
|
|
|
# samples are matched by their device values |
|
4262
|
|
|
|
|
|
|
# supported hash keys: 'dups', 'rows', 'context', 'template_context', 'sid_context', 'method', 'copy' |
|
4263
|
|
|
|
|
|
|
# duplicate handling: 0 - sample average (default), 1 - FIFO, 2 - LIFO, 3 - first sample, 4 - last sample |
|
4264
|
|
|
|
|
|
|
# parameters: (template_chart_object, [hash]) |
|
4265
|
|
|
|
|
|
|
# returns: (row_matrix_slice, [sid_matrix_slice]) |
|
4266
|
|
|
|
|
|
|
sub select_template { |
|
4267
|
|
|
|
|
|
|
|
|
4268
|
|
|
|
|
|
|
# get parameters |
|
4269
|
0
|
|
|
0
|
1
|
0
|
my ($self, $template, $hash) = @_; |
|
4270
|
|
|
|
|
|
|
|
|
4271
|
|
|
|
|
|
|
# local variables |
|
4272
|
0
|
|
|
|
|
0
|
my ($row_length, $dups, $copys, $copyt); |
|
4273
|
0
|
|
|
|
|
0
|
my ($devcs, $devct, $devs, $devt); |
|
4274
|
0
|
|
|
|
|
0
|
my ($sx, $c1, $c2, $c3, $n, @src, $cmp); |
|
4275
|
0
|
|
|
|
|
0
|
my ($target, $low, $high, $interval, @m, $nomatch); |
|
4276
|
0
|
|
|
|
|
0
|
my ($rows, $avg, $matrix, $devp, $sidt, $sid); |
|
4277
|
|
|
|
|
|
|
|
|
4278
|
|
|
|
|
|
|
# verify template is a chart object |
|
4279
|
0
|
0
|
|
|
|
0
|
(UNIVERSAL::isa($template, 'ICC::Support::Chart')) or croak('template not an ICC::Support::Chart object'); |
|
4280
|
|
|
|
|
|
|
|
|
4281
|
|
|
|
|
|
|
# get template row length |
|
4282
|
0
|
|
|
|
|
0
|
$row_length = _getRowLength($template, $hash); |
|
4283
|
|
|
|
|
|
|
|
|
4284
|
|
|
|
|
|
|
# set duplicate handling |
|
4285
|
0
|
0
|
|
|
|
0
|
$dups = defined($hash->{'dups'}) ? $hash->{'dups'} : 0; |
|
4286
|
|
|
|
|
|
|
|
|
4287
|
|
|
|
|
|
|
# if copy slice is defined |
|
4288
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'copy'})) { |
|
4289
|
|
|
|
|
|
|
|
|
4290
|
|
|
|
|
|
|
# flatten the copy slice |
|
4291
|
0
|
|
|
|
|
0
|
$copys = ICC::Shared::flatten($hash->{'copy'}); |
|
4292
|
|
|
|
|
|
|
|
|
4293
|
|
|
|
|
|
|
# add copied fields to template |
|
4294
|
0
|
|
|
|
|
0
|
$copyt = add_fmt($template, @{$self->[1][0]}[@{$copys}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4295
|
|
|
|
|
|
|
|
|
4296
|
|
|
|
|
|
|
} |
|
4297
|
|
|
|
|
|
|
|
|
4298
|
|
|
|
|
|
|
# verify parameters |
|
4299
|
0
|
0
|
0
|
|
|
0
|
(! ref($row_length) && $row_length == int($row_length) && $row_length > 0) or croak('invalid chart_row_length parameter'); |
|
|
|
|
0
|
|
|
|
|
|
4300
|
0
|
0
|
0
|
|
|
0
|
($dups == int($dups) && $dups >= 0 && $dups <= 4) or croak('invalid duplicate_handling parameter'); |
|
|
|
|
0
|
|
|
|
|
|
4301
|
|
|
|
|
|
|
|
|
4302
|
|
|
|
|
|
|
# get object device column slice |
|
4303
|
0
|
|
|
|
|
0
|
$devcs = device($self, $hash); |
|
4304
|
|
|
|
|
|
|
|
|
4305
|
|
|
|
|
|
|
# get template device column slice |
|
4306
|
0
|
|
|
|
|
0
|
$devct = device($template, {'context' => $hash->{'template_context'}}); |
|
4307
|
|
|
|
|
|
|
|
|
4308
|
|
|
|
|
|
|
# verify object and template column slices |
|
4309
|
0
|
0
|
|
|
|
0
|
(defined($devcs)) || croak ('object device data missing'); |
|
4310
|
0
|
0
|
|
|
|
0
|
(defined($devct)) || croak ('template device data missing'); |
|
4311
|
0
|
0
|
|
|
|
0
|
($#{$devcs} == $#{$devct}) or croak('object and template have different number of channels'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4312
|
|
|
|
|
|
|
|
|
4313
|
|
|
|
|
|
|
# get object device values |
|
4314
|
0
|
|
|
|
|
0
|
$devs = device($self, [], $hash); |
|
4315
|
|
|
|
|
|
|
|
|
4316
|
|
|
|
|
|
|
# get template device values |
|
4317
|
0
|
|
|
|
|
0
|
$devt = device($template, [], {'context' => $hash->{'template_context'}}); |
|
4318
|
|
|
|
|
|
|
|
|
4319
|
|
|
|
|
|
|
# get index of next object sample |
|
4320
|
0
|
|
|
|
|
0
|
$sx = $#{$self->[1]} + 1; |
|
|
0
|
|
|
|
|
0
|
|
|
4321
|
|
|
|
|
|
|
|
|
4322
|
|
|
|
|
|
|
# get averaging groups if duplicates are averaged |
|
4323
|
0
|
0
|
|
|
|
0
|
($c1, $c2, $c3) = _avg_groups($self, $hash) if ($dups == 0); |
|
4324
|
|
|
|
|
|
|
|
|
4325
|
|
|
|
|
|
|
# get number of channels |
|
4326
|
0
|
|
|
|
|
0
|
$n = @{$devcs}; |
|
|
0
|
|
|
|
|
0
|
|
|
4327
|
|
|
|
|
|
|
|
|
4328
|
|
|
|
|
|
|
# initialize sample list |
|
4329
|
0
|
|
|
|
|
0
|
@src = (); |
|
4330
|
|
|
|
|
|
|
|
|
4331
|
|
|
|
|
|
|
# for each sample |
|
4332
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$devs}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4333
|
|
|
|
|
|
|
|
|
4334
|
|
|
|
|
|
|
# if all device values defined |
|
4335
|
0
|
0
|
|
|
|
0
|
if ($n == grep {defined()} @{$devs->[$i]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4336
|
|
|
|
|
|
|
|
|
4337
|
|
|
|
|
|
|
# add sample to source list |
|
4338
|
0
|
|
|
|
|
0
|
push(@src, [@{$devs->[$i]}, $i + 1]); |
|
|
0
|
|
|
|
|
0
|
|
|
4339
|
|
|
|
|
|
|
|
|
4340
|
|
|
|
|
|
|
} |
|
4341
|
|
|
|
|
|
|
|
|
4342
|
|
|
|
|
|
|
} |
|
4343
|
|
|
|
|
|
|
|
|
4344
|
|
|
|
|
|
|
# sort object device values |
|
4345
|
|
|
|
|
|
|
@src = sort { |
|
4346
|
|
|
|
|
|
|
|
|
4347
|
|
|
|
|
|
|
# for each channel |
|
4348
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$a}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4349
|
|
|
|
|
|
|
|
|
4350
|
|
|
|
|
|
|
# quit loop if device values are unequal |
|
4351
|
0
|
0
|
|
|
|
0
|
last if ($cmp = $a->[$i] <=> $b->[$i]) |
|
4352
|
|
|
|
|
|
|
|
|
4353
|
|
|
|
|
|
|
# use last comparison for sort test |
|
4354
|
|
|
|
|
|
|
} $cmp |
|
4355
|
|
|
|
|
|
|
|
|
4356
|
|
|
|
|
|
|
} @src; |
|
4357
|
|
|
|
|
|
|
|
|
4358
|
|
|
|
|
|
|
# for each template sample |
|
4359
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$devt}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4360
|
|
|
|
|
|
|
|
|
4361
|
|
|
|
|
|
|
# initialize search indices |
|
4362
|
0
|
|
|
|
|
0
|
$low = 0; |
|
4363
|
0
|
|
|
|
|
0
|
$high = $#src; |
|
4364
|
|
|
|
|
|
|
|
|
4365
|
|
|
|
|
|
|
# initialize no match flag |
|
4366
|
0
|
|
|
|
|
0
|
$nomatch = 0; |
|
4367
|
|
|
|
|
|
|
|
|
4368
|
|
|
|
|
|
|
# for each channel |
|
4369
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$devt->[0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4370
|
|
|
|
|
|
|
|
|
4371
|
|
|
|
|
|
|
# get the target value |
|
4372
|
0
|
|
|
|
|
0
|
$target = $devt->[$i][$j]; |
|
4373
|
|
|
|
|
|
|
|
|
4374
|
|
|
|
|
|
|
# locate interval containing or bounding the target value |
|
4375
|
0
|
|
|
|
|
0
|
$interval = _bin_search(\@src, $target, $j, $low, $high); |
|
4376
|
|
|
|
|
|
|
|
|
4377
|
|
|
|
|
|
|
# find indices matching the target value |
|
4378
|
0
|
|
|
|
|
0
|
@m = grep {$src[$_][$j] == $target} @{$interval}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4379
|
|
|
|
|
|
|
|
|
4380
|
|
|
|
|
|
|
# if no object values exactly match the target value |
|
4381
|
0
|
0
|
|
|
|
0
|
if (@m == 0) { |
|
4382
|
|
|
|
|
|
|
|
|
4383
|
|
|
|
|
|
|
# sort interval indices by distance to target value |
|
4384
|
0
|
|
|
|
|
0
|
@m = sort {$a->[1] <=> $b->[1]} map {[$_, abs($src[$_][$j] - $target)]} @{$interval}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4385
|
|
|
|
|
|
|
|
|
4386
|
|
|
|
|
|
|
# if distance to closest object value > 0.00201 |
|
4387
|
0
|
0
|
|
|
|
0
|
if (abs($target - $src[$m[0][0]][$j]) > 0.00201) { |
|
4388
|
|
|
|
|
|
|
|
|
4389
|
|
|
|
|
|
|
# print warning |
|
4390
|
0
|
|
|
|
|
0
|
print "no match to template sample $i\n"; |
|
4391
|
0
|
|
|
|
|
0
|
print "device values: @{$devt->[$i]}\n"; |
|
|
0
|
|
|
|
|
0
|
|
|
4392
|
|
|
|
|
|
|
|
|
4393
|
|
|
|
|
|
|
# set no match flag |
|
4394
|
0
|
|
|
|
|
0
|
$nomatch = 1; |
|
4395
|
|
|
|
|
|
|
|
|
4396
|
|
|
|
|
|
|
# quit channel loop |
|
4397
|
0
|
|
|
|
|
0
|
last; |
|
4398
|
|
|
|
|
|
|
|
|
4399
|
|
|
|
|
|
|
} |
|
4400
|
|
|
|
|
|
|
|
|
4401
|
|
|
|
|
|
|
# set target to closest object value |
|
4402
|
0
|
|
|
|
|
0
|
$target = $src[$m[0][0]][$j]; |
|
4403
|
|
|
|
|
|
|
|
|
4404
|
|
|
|
|
|
|
# locate interval containing the target value |
|
4405
|
0
|
|
|
|
|
0
|
$interval = _bin_search(\@src, $target, $j, $low, $high); |
|
4406
|
|
|
|
|
|
|
|
|
4407
|
|
|
|
|
|
|
# find indices matching the target value |
|
4408
|
0
|
|
|
|
|
0
|
@m = grep {$src[$_][$j] == $target} @{$interval}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4409
|
|
|
|
|
|
|
|
|
4410
|
|
|
|
|
|
|
} |
|
4411
|
|
|
|
|
|
|
|
|
4412
|
|
|
|
|
|
|
# update interval |
|
4413
|
0
|
|
|
|
|
0
|
$low = $m[0]; |
|
4414
|
0
|
|
|
|
|
0
|
$high = $m[-1]; |
|
4415
|
|
|
|
|
|
|
|
|
4416
|
|
|
|
|
|
|
} |
|
4417
|
|
|
|
|
|
|
|
|
4418
|
|
|
|
|
|
|
# if no match found |
|
4419
|
0
|
0
|
|
|
|
0
|
if ($nomatch) { |
|
4420
|
|
|
|
|
|
|
|
|
4421
|
|
|
|
|
|
|
# locate nearest object sample(s) using linear search |
|
4422
|
0
|
|
|
|
|
0
|
($low, $high) = _lin_search(\@src, $devt->[$i]); |
|
4423
|
|
|
|
|
|
|
|
|
4424
|
|
|
|
|
|
|
# print message |
|
4425
|
0
|
|
|
|
|
0
|
print "closest match is object sample $src[$low][-1]\n"; |
|
4426
|
0
|
|
|
|
|
0
|
print "device values @{$src[$low]}[0 .. $#{$devt->[0]}]\n"; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4427
|
|
|
|
|
|
|
|
|
4428
|
|
|
|
|
|
|
} |
|
4429
|
|
|
|
|
|
|
|
|
4430
|
|
|
|
|
|
|
# single sample |
|
4431
|
0
|
0
|
|
|
|
0
|
if ($low == $high) { |
|
4432
|
|
|
|
|
|
|
|
|
4433
|
|
|
|
|
|
|
# set matrix element to first row matching object sample |
|
4434
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = $src[$low][-1]; |
|
4435
|
|
|
|
|
|
|
|
|
4436
|
|
|
|
|
|
|
# duplicate samples |
|
4437
|
|
|
|
|
|
|
} else { |
|
4438
|
|
|
|
|
|
|
|
|
4439
|
|
|
|
|
|
|
# duplicates are averaged |
|
4440
|
0
|
0
|
|
|
|
0
|
if ($dups == 0) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4441
|
|
|
|
|
|
|
|
|
4442
|
|
|
|
|
|
|
# for each appended avg sample |
|
4443
|
0
|
|
|
|
|
0
|
for my $j ($sx .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4444
|
|
|
|
|
|
|
|
|
4445
|
|
|
|
|
|
|
# set avg |
|
4446
|
0
|
|
|
|
|
0
|
$avg = $j; |
|
4447
|
|
|
|
|
|
|
|
|
4448
|
|
|
|
|
|
|
# get device values |
|
4449
|
0
|
|
|
|
|
0
|
$devp = $self->device([$j]); |
|
4450
|
|
|
|
|
|
|
|
|
4451
|
|
|
|
|
|
|
# for each channel |
|
4452
|
0
|
|
|
|
|
0
|
for my $k (0 .. $#{$devp->[0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4453
|
|
|
|
|
|
|
|
|
4454
|
|
|
|
|
|
|
# clear avg if device values differ |
|
4455
|
0
|
0
|
|
|
|
0
|
$avg = 0 if ($devp->[0][$k] != $devt->[$i][$k]); |
|
4456
|
|
|
|
|
|
|
|
|
4457
|
|
|
|
|
|
|
} |
|
4458
|
|
|
|
|
|
|
|
|
4459
|
|
|
|
|
|
|
# quit loop if device values match |
|
4460
|
0
|
0
|
|
|
|
0
|
last if ($avg); |
|
4461
|
|
|
|
|
|
|
|
|
4462
|
|
|
|
|
|
|
} |
|
4463
|
|
|
|
|
|
|
|
|
4464
|
|
|
|
|
|
|
# if existing avg sample found |
|
4465
|
0
|
0
|
|
|
|
0
|
if ($avg) { |
|
4466
|
|
|
|
|
|
|
|
|
4467
|
|
|
|
|
|
|
# set matrix element to existing avg sample |
|
4468
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = $avg; |
|
4469
|
|
|
|
|
|
|
|
|
4470
|
|
|
|
|
|
|
} else { |
|
4471
|
|
|
|
|
|
|
|
|
4472
|
|
|
|
|
|
|
# make row slice of duplicate samples |
|
4473
|
0
|
|
|
|
|
0
|
$rows = [map {$src[$_][-1]} ($low .. $high)]; |
|
|
0
|
|
|
|
|
0
|
|
|
4474
|
|
|
|
|
|
|
|
|
4475
|
|
|
|
|
|
|
# set matrix element to new avg sample |
|
4476
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = _add_avg($self, $rows, $c1, $c2, $c3); |
|
4477
|
|
|
|
|
|
|
|
|
4478
|
|
|
|
|
|
|
} |
|
4479
|
|
|
|
|
|
|
|
|
4480
|
|
|
|
|
|
|
# use FIFO sample |
|
4481
|
|
|
|
|
|
|
} elsif ($dups == 1) { |
|
4482
|
|
|
|
|
|
|
|
|
4483
|
|
|
|
|
|
|
# from low to high |
|
4484
|
0
|
|
|
|
|
0
|
for my $j ($low .. $high) { |
|
4485
|
|
|
|
|
|
|
|
|
4486
|
|
|
|
|
|
|
# if index > 0 |
|
4487
|
0
|
0
|
|
|
|
0
|
if ($src[$j][-1] > 0) { |
|
4488
|
|
|
|
|
|
|
|
|
4489
|
|
|
|
|
|
|
# set matrix element to object sample index |
|
4490
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = $src[$j][-1]; |
|
4491
|
|
|
|
|
|
|
|
|
4492
|
|
|
|
|
|
|
# invert sample index to indicate it was used |
|
4493
|
0
|
|
|
|
|
0
|
$src[$j][-1] = - $src[$j][-1]; |
|
4494
|
|
|
|
|
|
|
|
|
4495
|
|
|
|
|
|
|
# quit loop |
|
4496
|
0
|
|
|
|
|
0
|
last; |
|
4497
|
|
|
|
|
|
|
|
|
4498
|
|
|
|
|
|
|
} |
|
4499
|
|
|
|
|
|
|
|
|
4500
|
|
|
|
|
|
|
} |
|
4501
|
|
|
|
|
|
|
|
|
4502
|
|
|
|
|
|
|
# if matrix element undefined |
|
4503
|
0
|
0
|
|
|
|
0
|
if (! defined($matrix->[$i/$row_length][$i % $row_length])) { |
|
4504
|
|
|
|
|
|
|
|
|
4505
|
|
|
|
|
|
|
# print message |
|
4506
|
0
|
|
|
|
|
0
|
print "FIFO stack empty for @{$devt->[$i]}\n"; |
|
|
0
|
|
|
|
|
0
|
|
|
4507
|
0
|
|
|
|
|
0
|
print "using last stack sample\n"; |
|
4508
|
|
|
|
|
|
|
|
|
4509
|
|
|
|
|
|
|
# set matrix element to last row matching object sample |
|
4510
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = - $src[$high][-1]; |
|
4511
|
|
|
|
|
|
|
|
|
4512
|
|
|
|
|
|
|
} |
|
4513
|
|
|
|
|
|
|
|
|
4514
|
|
|
|
|
|
|
# use LIFO sample |
|
4515
|
|
|
|
|
|
|
} elsif ($dups == 2) { |
|
4516
|
|
|
|
|
|
|
|
|
4517
|
|
|
|
|
|
|
# from high to low |
|
4518
|
0
|
|
|
|
|
0
|
for my $j (reverse($low .. $high)) { |
|
4519
|
|
|
|
|
|
|
|
|
4520
|
|
|
|
|
|
|
# if index > 0 |
|
4521
|
0
|
0
|
|
|
|
0
|
if ($src[$j][-1] > 0) { |
|
4522
|
|
|
|
|
|
|
|
|
4523
|
|
|
|
|
|
|
# set matrix element to object sample index |
|
4524
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = $src[$j][-1]; |
|
4525
|
|
|
|
|
|
|
|
|
4526
|
|
|
|
|
|
|
# invert sample index to indicate it was used |
|
4527
|
0
|
|
|
|
|
0
|
$src[$j][-1] = - $src[$j][-1]; |
|
4528
|
|
|
|
|
|
|
|
|
4529
|
|
|
|
|
|
|
# quit loop |
|
4530
|
0
|
|
|
|
|
0
|
last; |
|
4531
|
|
|
|
|
|
|
|
|
4532
|
|
|
|
|
|
|
} |
|
4533
|
|
|
|
|
|
|
|
|
4534
|
|
|
|
|
|
|
} |
|
4535
|
|
|
|
|
|
|
|
|
4536
|
|
|
|
|
|
|
# if matrix element undefined |
|
4537
|
0
|
0
|
|
|
|
0
|
if (! defined($matrix->[$i/$row_length][$i % $row_length])) { |
|
4538
|
|
|
|
|
|
|
|
|
4539
|
|
|
|
|
|
|
# print message |
|
4540
|
0
|
|
|
|
|
0
|
print "LIFO stack empty for @{$devt->[$i]}\n"; |
|
|
0
|
|
|
|
|
0
|
|
|
4541
|
0
|
|
|
|
|
0
|
print "using last stack sample\n"; |
|
4542
|
|
|
|
|
|
|
|
|
4543
|
|
|
|
|
|
|
# set matrix element to first row matching object sample |
|
4544
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = - $src[$low][-1]; |
|
4545
|
|
|
|
|
|
|
|
|
4546
|
|
|
|
|
|
|
} |
|
4547
|
|
|
|
|
|
|
|
|
4548
|
|
|
|
|
|
|
# use first duplicate sample |
|
4549
|
|
|
|
|
|
|
} elsif ($dups == 3) { |
|
4550
|
|
|
|
|
|
|
|
|
4551
|
|
|
|
|
|
|
# set matrix element to first row matching object sample |
|
4552
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = $src[$low][-1]; |
|
4553
|
|
|
|
|
|
|
|
|
4554
|
|
|
|
|
|
|
# use last duplicate sample |
|
4555
|
|
|
|
|
|
|
} elsif ($dups == 4) { |
|
4556
|
|
|
|
|
|
|
|
|
4557
|
|
|
|
|
|
|
# set matrix element to last row matching object sample |
|
4558
|
0
|
|
|
|
|
0
|
$matrix->[$i/$row_length][$i % $row_length] = $src[$high][-1]; |
|
4559
|
|
|
|
|
|
|
|
|
4560
|
|
|
|
|
|
|
} else { |
|
4561
|
|
|
|
|
|
|
|
|
4562
|
|
|
|
|
|
|
# error |
|
4563
|
0
|
|
|
|
|
0
|
croak('invalid duplicate handling'); |
|
4564
|
|
|
|
|
|
|
|
|
4565
|
|
|
|
|
|
|
} |
|
4566
|
|
|
|
|
|
|
|
|
4567
|
|
|
|
|
|
|
} |
|
4568
|
|
|
|
|
|
|
|
|
4569
|
|
|
|
|
|
|
# if 'copy' slice defined |
|
4570
|
0
|
0
|
|
|
|
0
|
if (defined($copys)) { |
|
4571
|
|
|
|
|
|
|
|
|
4572
|
|
|
|
|
|
|
# get the object row |
|
4573
|
0
|
|
|
|
|
0
|
$n = $matrix->[$i/$row_length][$i % $row_length]; |
|
4574
|
|
|
|
|
|
|
|
|
4575
|
|
|
|
|
|
|
# copy selected values from object to template |
|
4576
|
0
|
|
|
|
|
0
|
@{$template->[1][$i + 1]}[@{$copyt}] = @{$self->[1][$n]}[@{$copys}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4577
|
|
|
|
|
|
|
|
|
4578
|
|
|
|
|
|
|
# if device values differ |
|
4579
|
0
|
0
|
|
|
|
0
|
if ($nomatch) { |
|
4580
|
|
|
|
|
|
|
|
|
4581
|
|
|
|
|
|
|
# copy device values from object to template |
|
4582
|
0
|
|
|
|
|
0
|
@{$template->[1][$i + 1]}[@{$devct}] = @{$self->[1][$n]}[@{$devcs}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4583
|
|
|
|
|
|
|
|
|
4584
|
|
|
|
|
|
|
} |
|
4585
|
|
|
|
|
|
|
|
|
4586
|
|
|
|
|
|
|
} |
|
4587
|
|
|
|
|
|
|
|
|
4588
|
|
|
|
|
|
|
} |
|
4589
|
|
|
|
|
|
|
|
|
4590
|
|
|
|
|
|
|
# if sid-matrix is wanted and template has sid values |
|
4591
|
0
|
0
|
0
|
|
|
0
|
if (wantarray() && ($sidt = id($template, [], {'context' => $hash->{'sid_context'}}))) { |
|
4592
|
|
|
|
|
|
|
|
|
4593
|
|
|
|
|
|
|
# for each template sample |
|
4594
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$sidt}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4595
|
|
|
|
|
|
|
|
|
4596
|
|
|
|
|
|
|
# set sid matrix element to sid slice value |
|
4597
|
0
|
|
|
|
|
0
|
$sid->[$i/$row_length][$i % $row_length] = $sidt->[$i][0]; |
|
4598
|
|
|
|
|
|
|
|
|
4599
|
|
|
|
|
|
|
} |
|
4600
|
|
|
|
|
|
|
|
|
4601
|
|
|
|
|
|
|
# return row matrix slice and sid matrix slice |
|
4602
|
0
|
|
|
|
|
0
|
return(bless($matrix, 'Math::Matrix'), bless($sid, 'Math::Matrix')); |
|
4603
|
|
|
|
|
|
|
|
|
4604
|
|
|
|
|
|
|
} else { |
|
4605
|
|
|
|
|
|
|
|
|
4606
|
|
|
|
|
|
|
# return row matrix slice |
|
4607
|
0
|
|
|
|
|
0
|
return(bless($matrix, 'Math::Matrix')); |
|
4608
|
|
|
|
|
|
|
|
|
4609
|
|
|
|
|
|
|
} |
|
4610
|
|
|
|
|
|
|
|
|
4611
|
|
|
|
|
|
|
} |
|
4612
|
|
|
|
|
|
|
|
|
4613
|
|
|
|
|
|
|
# get sample selection |
|
4614
|
|
|
|
|
|
|
# array of data values is supplied to code block |
|
4615
|
|
|
|
|
|
|
# sample is included if code block returns 'true' value |
|
4616
|
|
|
|
|
|
|
# default row_slice is all samples |
|
4617
|
|
|
|
|
|
|
# default column_slice is all columns |
|
4618
|
|
|
|
|
|
|
# parameters: (code_reference, row_slice, column_slice) |
|
4619
|
|
|
|
|
|
|
# returns: (row_slice) |
|
4620
|
|
|
|
|
|
|
sub find { |
|
4621
|
|
|
|
|
|
|
|
|
4622
|
|
|
|
|
|
|
# get parameters |
|
4623
|
0
|
|
|
0
|
1
|
0
|
my ($self, $code, $rows, $cols) = @_; |
|
4624
|
|
|
|
|
|
|
|
|
4625
|
|
|
|
|
|
|
# verify code reference |
|
4626
|
0
|
0
|
|
|
|
0
|
(ref($code) eq 'CODE') or croak('selection parameter must be a code reference'); |
|
4627
|
|
|
|
|
|
|
|
|
4628
|
|
|
|
|
|
|
# if row slice undefined or empty |
|
4629
|
0
|
0
|
0
|
|
|
0
|
if (! defined($rows) || (ref($rows) eq 'ARRAY' && @{$rows} == 0)) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
4630
|
|
|
|
|
|
|
|
|
4631
|
|
|
|
|
|
|
# use all rows |
|
4632
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
4633
|
|
|
|
|
|
|
|
|
4634
|
|
|
|
|
|
|
} else { |
|
4635
|
|
|
|
|
|
|
|
|
4636
|
|
|
|
|
|
|
# flatten slice |
|
4637
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
4638
|
|
|
|
|
|
|
|
|
4639
|
|
|
|
|
|
|
} |
|
4640
|
|
|
|
|
|
|
|
|
4641
|
|
|
|
|
|
|
# if column slice undefined or empty |
|
4642
|
0
|
0
|
0
|
|
|
0
|
if (! defined($cols) || (ref($cols) eq 'ARRAY' && @{$cols} == 0)) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
4643
|
|
|
|
|
|
|
|
|
4644
|
|
|
|
|
|
|
# use all columns |
|
4645
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
4646
|
|
|
|
|
|
|
|
|
4647
|
|
|
|
|
|
|
} else { |
|
4648
|
|
|
|
|
|
|
|
|
4649
|
|
|
|
|
|
|
# flatten slice |
|
4650
|
0
|
|
|
|
|
0
|
$cols = ICC::Shared::flatten($cols); |
|
4651
|
|
|
|
|
|
|
|
|
4652
|
|
|
|
|
|
|
} |
|
4653
|
|
|
|
|
|
|
|
|
4654
|
|
|
|
|
|
|
# return selection slice |
|
4655
|
0
|
|
|
|
|
0
|
return([grep {&$code(@{$self->[1][$_]}[@{$cols}])} @{$rows}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4656
|
|
|
|
|
|
|
|
|
4657
|
|
|
|
|
|
|
} |
|
4658
|
|
|
|
|
|
|
|
|
4659
|
|
|
|
|
|
|
# get sample selection based on device values |
|
4660
|
|
|
|
|
|
|
# array of device values is supplied to code block |
|
4661
|
|
|
|
|
|
|
# sample is included if code block returns 'true' value |
|
4662
|
|
|
|
|
|
|
# default row_slice is all samples |
|
4663
|
|
|
|
|
|
|
# context may be specified with parameter hash |
|
4664
|
|
|
|
|
|
|
# parameters: (code_reference, [row_slice], [hash]) |
|
4665
|
|
|
|
|
|
|
# returns: (row_slice) |
|
4666
|
|
|
|
|
|
|
sub ramp { |
|
4667
|
|
|
|
|
|
|
|
|
4668
|
|
|
|
|
|
|
# local variables |
|
4669
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $cols, $mult); |
|
4670
|
|
|
|
|
|
|
|
|
4671
|
|
|
|
|
|
|
# get optional hash |
|
4672
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
4673
|
|
|
|
|
|
|
|
|
4674
|
|
|
|
|
|
|
# get remaining parameters |
|
4675
|
0
|
|
|
|
|
0
|
my ($self, $code, $rows) = @_; |
|
4676
|
|
|
|
|
|
|
|
|
4677
|
|
|
|
|
|
|
# verify code reference |
|
4678
|
0
|
0
|
|
|
|
0
|
(ref($code) eq 'CODE') or croak('selection parameter must be a code reference'); |
|
4679
|
|
|
|
|
|
|
|
|
4680
|
|
|
|
|
|
|
# if row slice undefined or empty |
|
4681
|
0
|
0
|
0
|
|
|
0
|
if (! defined($rows) || (ref($rows) eq 'ARRAY' && @{$rows} == 0)) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
4682
|
|
|
|
|
|
|
|
|
4683
|
|
|
|
|
|
|
# use all rows |
|
4684
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
4685
|
|
|
|
|
|
|
|
|
4686
|
|
|
|
|
|
|
} else { |
|
4687
|
|
|
|
|
|
|
|
|
4688
|
|
|
|
|
|
|
# flatten slice |
|
4689
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
4690
|
|
|
|
|
|
|
|
|
4691
|
|
|
|
|
|
|
} |
|
4692
|
|
|
|
|
|
|
|
|
4693
|
|
|
|
|
|
|
# get device column slice |
|
4694
|
0
|
0
|
|
|
|
0
|
(defined($cols = device($self, $hash))) or croak('device values required'); |
|
4695
|
|
|
|
|
|
|
|
|
4696
|
|
|
|
|
|
|
# set multiplier (255 if RGB, otherwise 100) |
|
4697
|
0
|
0
|
|
|
|
0
|
$mult = ($self->[1][0][$cols->[0]] =~ m/RGB_R$/) ? 255 : 100; |
|
4698
|
|
|
|
|
|
|
|
|
4699
|
|
|
|
|
|
|
# if RGB data -and- 'invert_rgb' flag |
|
4700
|
0
|
0
|
0
|
|
|
0
|
if ($mult == 255 && $hash->{'invert_rgb'}) { |
|
4701
|
|
|
|
|
|
|
|
|
4702
|
|
|
|
|
|
|
# return selection slice |
|
4703
|
0
|
|
|
|
|
0
|
return([grep {&$code(map {1 - $_/$mult} @{$self->[1][$_]}[@{$cols}])} @{$rows}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4704
|
|
|
|
|
|
|
|
|
4705
|
|
|
|
|
|
|
} else { |
|
4706
|
|
|
|
|
|
|
|
|
4707
|
|
|
|
|
|
|
# return selection slice |
|
4708
|
0
|
|
|
|
|
0
|
return([grep {&$code(map {$_/$mult} @{$self->[1][$_]}[@{$cols}])} @{$rows}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4709
|
|
|
|
|
|
|
|
|
4710
|
|
|
|
|
|
|
} |
|
4711
|
|
|
|
|
|
|
|
|
4712
|
|
|
|
|
|
|
} |
|
4713
|
|
|
|
|
|
|
|
|
4714
|
|
|
|
|
|
|
# get sample selection based on L*a*b* values |
|
4715
|
|
|
|
|
|
|
# array of L*a*b* values is supplied to code block |
|
4716
|
|
|
|
|
|
|
# sample is included if code block returns 'true' value |
|
4717
|
|
|
|
|
|
|
# default row_slice is all samples |
|
4718
|
|
|
|
|
|
|
# context may be specified with parameter hash |
|
4719
|
|
|
|
|
|
|
# parameters: (code_reference, [row_slice], [hash]) |
|
4720
|
|
|
|
|
|
|
# returns: (row_slice) |
|
4721
|
|
|
|
|
|
|
sub range { |
|
4722
|
|
|
|
|
|
|
|
|
4723
|
|
|
|
|
|
|
# local variables |
|
4724
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $cols); |
|
4725
|
|
|
|
|
|
|
|
|
4726
|
|
|
|
|
|
|
# get optional hash |
|
4727
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
4728
|
|
|
|
|
|
|
|
|
4729
|
|
|
|
|
|
|
# get remaining parameters |
|
4730
|
0
|
|
|
|
|
0
|
my ($self, $code, $rows) = @_; |
|
4731
|
|
|
|
|
|
|
|
|
4732
|
|
|
|
|
|
|
# verify code reference |
|
4733
|
0
|
0
|
|
|
|
0
|
(ref($code) eq 'CODE') or croak('selection parameter must be a code reference'); |
|
4734
|
|
|
|
|
|
|
|
|
4735
|
|
|
|
|
|
|
# if row slice undefined or empty |
|
4736
|
0
|
0
|
0
|
|
|
0
|
if (! defined($rows) || (ref($rows) eq 'ARRAY' && @{$rows} == 0)) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
4737
|
|
|
|
|
|
|
|
|
4738
|
|
|
|
|
|
|
# use all rows |
|
4739
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
4740
|
|
|
|
|
|
|
|
|
4741
|
|
|
|
|
|
|
} else { |
|
4742
|
|
|
|
|
|
|
|
|
4743
|
|
|
|
|
|
|
# flatten slice |
|
4744
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
4745
|
|
|
|
|
|
|
|
|
4746
|
|
|
|
|
|
|
} |
|
4747
|
|
|
|
|
|
|
|
|
4748
|
|
|
|
|
|
|
# get L*a*b* column slice |
|
4749
|
0
|
0
|
|
|
|
0
|
(defined($cols = lab($self, $hash))) or croak('L*a*b* values required'); |
|
4750
|
|
|
|
|
|
|
|
|
4751
|
|
|
|
|
|
|
# return selection slice |
|
4752
|
0
|
|
|
|
|
0
|
return([grep {&$code(@{$self->[1][$_]}[@{$cols}])} @{$rows}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4753
|
|
|
|
|
|
|
|
|
4754
|
|
|
|
|
|
|
} |
|
4755
|
|
|
|
|
|
|
|
|
4756
|
|
|
|
|
|
|
# generate randomized sample slice |
|
4757
|
|
|
|
|
|
|
# parameter: ([row_slice]) |
|
4758
|
|
|
|
|
|
|
# returns: (row_slice) |
|
4759
|
|
|
|
|
|
|
sub randomize { |
|
4760
|
|
|
|
|
|
|
|
|
4761
|
|
|
|
|
|
|
# get parameters |
|
4762
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rows) = @_; |
|
4763
|
|
|
|
|
|
|
|
|
4764
|
|
|
|
|
|
|
# if row slice undefined -or- an empty array reference |
|
4765
|
0
|
0
|
0
|
|
|
0
|
if (! defined($rows) || (ref($rows) eq 'ARRAY' && @{$rows} == 0)) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
4766
|
|
|
|
|
|
|
|
|
4767
|
|
|
|
|
|
|
# use all rows |
|
4768
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
4769
|
|
|
|
|
|
|
|
|
4770
|
|
|
|
|
|
|
} else { |
|
4771
|
|
|
|
|
|
|
|
|
4772
|
|
|
|
|
|
|
# flatten row slice |
|
4773
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
4774
|
|
|
|
|
|
|
|
|
4775
|
|
|
|
|
|
|
# verify row slice contents |
|
4776
|
0
|
0
|
0
|
|
|
0
|
(@{$rows} == grep {! ref() && $_ == int($_) && $_ >= 0} @{$rows}) or croak('invalid row slice'); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4777
|
|
|
|
|
|
|
|
|
4778
|
|
|
|
|
|
|
} |
|
4779
|
|
|
|
|
|
|
|
|
4780
|
|
|
|
|
|
|
# return row slice, randomized |
|
4781
|
0
|
|
|
|
|
0
|
return([List::Util::shuffle(@{$rows})]); |
|
|
0
|
|
|
|
|
0
|
|
|
4782
|
|
|
|
|
|
|
|
|
4783
|
|
|
|
|
|
|
} |
|
4784
|
|
|
|
|
|
|
|
|
4785
|
|
|
|
|
|
|
# sort sample slice by device values |
|
4786
|
|
|
|
|
|
|
# note: returns undef if no device values |
|
4787
|
|
|
|
|
|
|
# parameters: ([row_slice, sort_vector]) |
|
4788
|
|
|
|
|
|
|
# returns: (sorted_row_slice) |
|
4789
|
|
|
|
|
|
|
# returns: (sorted_row_slice, sorted_device_values) |
|
4790
|
|
|
|
|
|
|
sub sort { |
|
4791
|
|
|
|
|
|
|
|
|
4792
|
|
|
|
|
|
|
# get parameters |
|
4793
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rows, $sort) = @_; |
|
4794
|
|
|
|
|
|
|
|
|
4795
|
|
|
|
|
|
|
# local variables |
|
4796
|
0
|
|
|
|
|
0
|
my ($dev, $n, $code, $sorted); |
|
4797
|
|
|
|
|
|
|
|
|
4798
|
|
|
|
|
|
|
# if row slice undefined -or- an empty array reference |
|
4799
|
0
|
0
|
0
|
|
|
0
|
if (! defined($rows) || (ref($rows) eq 'ARRAY' && @{$rows} == 0)) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
4800
|
|
|
|
|
|
|
|
|
4801
|
|
|
|
|
|
|
# use all rows |
|
4802
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
4803
|
|
|
|
|
|
|
|
|
4804
|
|
|
|
|
|
|
} else { |
|
4805
|
|
|
|
|
|
|
|
|
4806
|
|
|
|
|
|
|
# flatten row slice |
|
4807
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
4808
|
|
|
|
|
|
|
|
|
4809
|
|
|
|
|
|
|
# verify row slice contents |
|
4810
|
0
|
0
|
0
|
|
|
0
|
(@{$rows} == grep {! ref() && $_ == int($_) && $_ >= 0} @{$rows}) or croak('invalid row slice'); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4811
|
|
|
|
|
|
|
|
|
4812
|
|
|
|
|
|
|
} |
|
4813
|
|
|
|
|
|
|
|
|
4814
|
|
|
|
|
|
|
# get device values |
|
4815
|
0
|
0
|
|
|
|
0
|
if (! ($dev = device($self, $rows))) { |
|
4816
|
|
|
|
|
|
|
|
|
4817
|
|
|
|
|
|
|
# display warning |
|
4818
|
0
|
|
|
|
|
0
|
carp("no device values, sorting failed\n"); |
|
4819
|
|
|
|
|
|
|
|
|
4820
|
|
|
|
|
|
|
# return |
|
4821
|
0
|
|
|
|
|
0
|
return(); |
|
4822
|
|
|
|
|
|
|
|
|
4823
|
|
|
|
|
|
|
} |
|
4824
|
|
|
|
|
|
|
|
|
4825
|
|
|
|
|
|
|
# get number of device channels |
|
4826
|
0
|
|
|
|
|
0
|
$n = @{device($self)}; |
|
|
0
|
|
|
|
|
0
|
|
|
4827
|
|
|
|
|
|
|
|
|
4828
|
|
|
|
|
|
|
# default sort vector, e.g. [4, 3, 2, 1] |
|
4829
|
0
|
0
|
|
|
|
0
|
$sort = [reverse(1 .. $n)] if (! defined($sort)); |
|
4830
|
|
|
|
|
|
|
|
|
4831
|
|
|
|
|
|
|
# verify sort parameter |
|
4832
|
0
|
0
|
0
|
|
|
0
|
if (ICC::Shared::is_num_vector($sort) && @{$sort} == grep {$_ && $_ == int($_) && abs($_) <= $n} @{$sort}) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4833
|
|
|
|
|
|
|
|
|
4834
|
|
|
|
|
|
|
# for each sample |
|
4835
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$dev}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4836
|
|
|
|
|
|
|
|
|
4837
|
|
|
|
|
|
|
# insert sample number |
|
4838
|
0
|
|
0
|
|
|
0
|
unshift(@{$dev->[$i]}, $rows->[$i] // $i + 1); |
|
|
0
|
|
|
|
|
0
|
|
|
4839
|
|
|
|
|
|
|
|
|
4840
|
|
|
|
|
|
|
} |
|
4841
|
|
|
|
|
|
|
|
|
4842
|
|
|
|
|
|
|
# make sort code fragment |
|
4843
|
0
|
0
|
|
|
|
0
|
$code = '@{$dev} = sort {' . join(' || ', map {my $dir = m/-/; my $col = abs($_); $dir ? "\$b->[$col] <=> \$a->[$col]" : "\$a->[$col] <=> \$b->[$col]"} @{$sort}) . '} @{$dev}'; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4844
|
|
|
|
|
|
|
|
|
4845
|
|
|
|
|
|
|
# evaluate code fragment |
|
4846
|
0
|
|
|
|
|
0
|
eval($code); |
|
4847
|
|
|
|
|
|
|
|
|
4848
|
|
|
|
|
|
|
# for each sample |
|
4849
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$dev}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4850
|
|
|
|
|
|
|
|
|
4851
|
|
|
|
|
|
|
# extract sample number |
|
4852
|
0
|
|
|
|
|
0
|
$sorted->[$i] = shift(@{$dev->[$i]}); |
|
|
0
|
|
|
|
|
0
|
|
|
4853
|
|
|
|
|
|
|
|
|
4854
|
|
|
|
|
|
|
} |
|
4855
|
|
|
|
|
|
|
|
|
4856
|
|
|
|
|
|
|
} else { |
|
4857
|
|
|
|
|
|
|
|
|
4858
|
|
|
|
|
|
|
# display warning |
|
4859
|
0
|
|
|
|
|
0
|
carp("invalid sort parameter, sorting failed\n"); |
|
4860
|
|
|
|
|
|
|
|
|
4861
|
|
|
|
|
|
|
} |
|
4862
|
|
|
|
|
|
|
|
|
4863
|
|
|
|
|
|
|
# return, array or scalar |
|
4864
|
0
|
0
|
|
|
|
0
|
return(wantarray ? ($sorted, $dev) : $sorted); |
|
4865
|
|
|
|
|
|
|
|
|
4866
|
|
|
|
|
|
|
} |
|
4867
|
|
|
|
|
|
|
|
|
4868
|
|
|
|
|
|
|
# analyze chart device values |
|
4869
|
|
|
|
|
|
|
# creates an array structure with an element for each device channel. |
|
4870
|
|
|
|
|
|
|
# each element contains a hash, a keys array, and a ramp array. |
|
4871
|
|
|
|
|
|
|
# hash keys are device values, and hash values are arrays of samples. |
|
4872
|
|
|
|
|
|
|
# if row-slice is omitted, all samples are used. |
|
4873
|
|
|
|
|
|
|
# if the dup_flag is false (default), a new sample is added |
|
4874
|
|
|
|
|
|
|
# containing average measurement values, and the new sample |
|
4875
|
|
|
|
|
|
|
# is substituted for the anonymous array of duplicates. |
|
4876
|
|
|
|
|
|
|
# if the dup_flag is true, duplicate samples are included in |
|
4877
|
|
|
|
|
|
|
# array of samples grouped within anonymous arrays. |
|
4878
|
|
|
|
|
|
|
# dup_flag and/or device context are specified with parameter hash |
|
4879
|
|
|
|
|
|
|
# parameters: ([row_slice], [hash]) |
|
4880
|
|
|
|
|
|
|
# returns: (ref_to_structure) |
|
4881
|
|
|
|
|
|
|
sub analyze { |
|
4882
|
|
|
|
|
|
|
|
|
4883
|
|
|
|
|
|
|
# get object reference |
|
4884
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
4885
|
|
|
|
|
|
|
|
|
4886
|
|
|
|
|
|
|
# local variables |
|
4887
|
0
|
|
|
|
|
0
|
my ($hash, $rows, $dup, $ramp, $dev, $c1, $c2, $c3, @id, @name, $mult); |
|
4888
|
0
|
|
|
|
|
0
|
my (@d, %dev_hash, $key, $avg, $value, $struct); |
|
4889
|
|
|
|
|
|
|
|
|
4890
|
|
|
|
|
|
|
# get optional hash |
|
4891
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
4892
|
|
|
|
|
|
|
|
|
4893
|
|
|
|
|
|
|
# get device column slice |
|
4894
|
0
|
0
|
|
|
|
0
|
($dev = device($self, $hash)) or croak('chart has no device values'); |
|
4895
|
|
|
|
|
|
|
|
|
4896
|
|
|
|
|
|
|
# get row slice |
|
4897
|
0
|
0
|
|
|
|
0
|
$rows = shift() if (ref($_[0]) eq 'ARRAY'); |
|
4898
|
|
|
|
|
|
|
|
|
4899
|
|
|
|
|
|
|
# flatten row slice |
|
4900
|
0
|
0
|
|
|
|
0
|
$rows = $rows ? ICC::Shared::flatten($rows) : []; |
|
4901
|
|
|
|
|
|
|
|
|
4902
|
|
|
|
|
|
|
# use all samples if slice is empty |
|
4903
|
0
|
0
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}] if (@{$rows} == 0); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4904
|
|
|
|
|
|
|
|
|
4905
|
|
|
|
|
|
|
# get dup flag |
|
4906
|
0
|
0
|
|
|
|
0
|
$dup = defined($hash->{'dups'}) ? $hash->{'dups'} : 0; |
|
4907
|
|
|
|
|
|
|
|
|
4908
|
|
|
|
|
|
|
# get ramp value |
|
4909
|
0
|
0
|
|
|
|
0
|
$ramp = defined($hash->{'ramp'}) ? $hash->{'ramp'} : 0; |
|
4910
|
|
|
|
|
|
|
|
|
4911
|
|
|
|
|
|
|
# get averaging groups |
|
4912
|
0
|
|
|
|
|
0
|
($c1, $c2, $c3) = _avg_groups($self, $hash); |
|
4913
|
|
|
|
|
|
|
|
|
4914
|
|
|
|
|
|
|
# for each column |
|
4915
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1][0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4916
|
|
|
|
|
|
|
|
|
4917
|
|
|
|
|
|
|
# add column if SAMPLE_ID field |
|
4918
|
0
|
0
|
|
|
|
0
|
push(@id, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?(?:SAMPLE_ID|SampleID)$/); |
|
4919
|
|
|
|
|
|
|
|
|
4920
|
|
|
|
|
|
|
# add column if SAMPLE_NAME field |
|
4921
|
0
|
0
|
|
|
|
0
|
push(@name, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?SAMPLE_NAME$/); |
|
4922
|
|
|
|
|
|
|
|
|
4923
|
|
|
|
|
|
|
} |
|
4924
|
|
|
|
|
|
|
|
|
4925
|
|
|
|
|
|
|
# set device multiplier (255 for RGB values, otherwise 100) |
|
4926
|
0
|
0
|
|
|
|
0
|
$mult = ($self->[1][0][$dev->[0]] =~ m/^(?:.*\|)?RGB_[RGB]$/) ? 255 : 100; |
|
4927
|
|
|
|
|
|
|
|
|
4928
|
|
|
|
|
|
|
# for each sample |
|
4929
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
4930
|
|
|
|
|
|
|
|
|
4931
|
|
|
|
|
|
|
# get device values |
|
4932
|
0
|
|
|
|
|
0
|
@d = @{$self->[1][$rows->[$i]]}[@{$dev}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4933
|
|
|
|
|
|
|
|
|
4934
|
|
|
|
|
|
|
# divide by multiplier (setting -0 to 0) |
|
4935
|
0
|
0
|
|
|
|
0
|
@d = map {$_ == 0 ? 0 : $_/$mult} @d; |
|
|
0
|
|
|
|
|
0
|
|
|
4936
|
|
|
|
|
|
|
|
|
4937
|
|
|
|
|
|
|
# make device value key |
|
4938
|
0
|
|
|
|
|
0
|
$key = join(':', @d); |
|
4939
|
|
|
|
|
|
|
|
|
4940
|
|
|
|
|
|
|
# if key exists |
|
4941
|
0
|
0
|
|
|
|
0
|
if (exists($dev_hash{$key})) { |
|
4942
|
|
|
|
|
|
|
|
|
4943
|
|
|
|
|
|
|
# add sample to existing hash entry |
|
4944
|
0
|
|
|
|
|
0
|
push(@{$dev_hash{$key}}, $rows->[$i]); |
|
|
0
|
|
|
|
|
0
|
|
|
4945
|
|
|
|
|
|
|
|
|
4946
|
|
|
|
|
|
|
} else { |
|
4947
|
|
|
|
|
|
|
|
|
4948
|
|
|
|
|
|
|
# add device hash entry |
|
4949
|
0
|
|
|
|
|
0
|
$dev_hash{$key} = [$rows->[$i]]; |
|
4950
|
|
|
|
|
|
|
|
|
4951
|
|
|
|
|
|
|
} |
|
4952
|
|
|
|
|
|
|
|
|
4953
|
|
|
|
|
|
|
} |
|
4954
|
|
|
|
|
|
|
|
|
4955
|
|
|
|
|
|
|
# if dup flag is not set |
|
4956
|
0
|
0
|
|
|
|
0
|
if (! $dup) { |
|
4957
|
|
|
|
|
|
|
|
|
4958
|
|
|
|
|
|
|
# for each key |
|
4959
|
0
|
|
|
|
|
0
|
for my $key (keys(%dev_hash)) { |
|
4960
|
|
|
|
|
|
|
|
|
4961
|
|
|
|
|
|
|
# if duplicate samples |
|
4962
|
0
|
0
|
|
|
|
0
|
if (@{$dev_hash{$key}} > 1) { |
|
|
0
|
|
|
|
|
0
|
|
|
4963
|
|
|
|
|
|
|
|
|
4964
|
|
|
|
|
|
|
# if measurement data |
|
4965
|
0
|
0
|
0
|
|
|
0
|
if (@{$c1} || @{$c2} || @{$c3}) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4966
|
|
|
|
|
|
|
|
|
4967
|
|
|
|
|
|
|
# add average sample |
|
4968
|
0
|
|
|
|
|
0
|
$avg = _add_avg($self, $dev_hash{$key}, $c1, $c2, $c3, \@id, \@name); |
|
4969
|
|
|
|
|
|
|
|
|
4970
|
|
|
|
|
|
|
# update hash to average sample |
|
4971
|
0
|
|
|
|
|
0
|
$dev_hash{$key} = [$avg]; |
|
4972
|
|
|
|
|
|
|
|
|
4973
|
|
|
|
|
|
|
} else { |
|
4974
|
|
|
|
|
|
|
|
|
4975
|
|
|
|
|
|
|
# update hash to first sample |
|
4976
|
0
|
|
|
|
|
0
|
$dev_hash{$key} = [$dev_hash{$key}[0]]; |
|
4977
|
|
|
|
|
|
|
|
|
4978
|
|
|
|
|
|
|
} |
|
4979
|
|
|
|
|
|
|
|
|
4980
|
|
|
|
|
|
|
} |
|
4981
|
|
|
|
|
|
|
|
|
4982
|
|
|
|
|
|
|
} |
|
4983
|
|
|
|
|
|
|
|
|
4984
|
|
|
|
|
|
|
# update the SAMPLE_ID hash |
|
4985
|
0
|
|
|
|
|
0
|
_makeSampleID($self); |
|
4986
|
|
|
|
|
|
|
|
|
4987
|
|
|
|
|
|
|
} |
|
4988
|
|
|
|
|
|
|
|
|
4989
|
|
|
|
|
|
|
# make empty structure |
|
4990
|
0
|
|
|
|
|
0
|
$struct = [map {[{}, [], []]} (0 .. $#{$dev})]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4991
|
|
|
|
|
|
|
|
|
4992
|
|
|
|
|
|
|
# for each key |
|
4993
|
0
|
|
|
|
|
0
|
for my $key (keys(%dev_hash)) { |
|
4994
|
|
|
|
|
|
|
|
|
4995
|
|
|
|
|
|
|
# split key to device values |
|
4996
|
0
|
|
|
|
|
0
|
@d = split(/:/, $key); |
|
4997
|
|
|
|
|
|
|
|
|
4998
|
|
|
|
|
|
|
# get value |
|
4999
|
0
|
|
|
|
|
0
|
$value = $dev_hash{$key}; |
|
5000
|
|
|
|
|
|
|
|
|
5001
|
|
|
|
|
|
|
# resolve single value to scalar |
|
5002
|
0
|
0
|
|
|
|
0
|
$value = $value->[0] if (@{$value} == 1); |
|
|
0
|
|
|
|
|
0
|
|
|
5003
|
|
|
|
|
|
|
|
|
5004
|
|
|
|
|
|
|
# for each device channel |
|
5005
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#d) { |
|
5006
|
|
|
|
|
|
|
|
|
5007
|
|
|
|
|
|
|
# if key exists |
|
5008
|
0
|
0
|
|
|
|
0
|
if (exists($struct->[$i][0]{$d[$i]})) { |
|
5009
|
|
|
|
|
|
|
|
|
5010
|
|
|
|
|
|
|
# add sample to hash entry |
|
5011
|
0
|
|
|
|
|
0
|
push(@{$struct->[$i][0]{$d[$i]}}, $value); |
|
|
0
|
|
|
|
|
0
|
|
|
5012
|
|
|
|
|
|
|
|
|
5013
|
|
|
|
|
|
|
} else { |
|
5014
|
|
|
|
|
|
|
|
|
5015
|
|
|
|
|
|
|
# add hash entry |
|
5016
|
0
|
|
|
|
|
0
|
$struct->[$i][0]{$d[$i]} = [$value]; |
|
5017
|
|
|
|
|
|
|
|
|
5018
|
|
|
|
|
|
|
# add device value to keys array |
|
5019
|
0
|
|
|
|
|
0
|
push(@{$struct->[$i][1]}, $d[$i]); |
|
|
0
|
|
|
|
|
0
|
|
|
5020
|
|
|
|
|
|
|
|
|
5021
|
|
|
|
|
|
|
} |
|
5022
|
|
|
|
|
|
|
|
|
5023
|
|
|
|
|
|
|
# if all other device values equal ramp value |
|
5024
|
0
|
0
|
|
|
|
0
|
if (@d == grep {$_ == $i || $d[$_] == $ramp} (0 .. $#d)) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
5025
|
|
|
|
|
|
|
|
|
5026
|
|
|
|
|
|
|
# add sample to ramp array |
|
5027
|
0
|
|
|
|
|
0
|
push(@{$struct->[$i][2]}, $value); |
|
|
0
|
|
|
|
|
0
|
|
|
5028
|
|
|
|
|
|
|
|
|
5029
|
|
|
|
|
|
|
} |
|
5030
|
|
|
|
|
|
|
|
|
5031
|
|
|
|
|
|
|
} |
|
5032
|
|
|
|
|
|
|
|
|
5033
|
|
|
|
|
|
|
} |
|
5034
|
|
|
|
|
|
|
|
|
5035
|
|
|
|
|
|
|
# for each device channel |
|
5036
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$dev}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5037
|
|
|
|
|
|
|
|
|
5038
|
|
|
|
|
|
|
# sort keys array (decreasing frequency) |
|
5039
|
0
|
|
|
|
|
0
|
$struct->[$i][1] = [sort {@{$struct->[$i][0]{$b}} <=> @{$struct->[$i][0]{$a}}} @{$struct->[$i][1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5040
|
|
|
|
|
|
|
|
|
5041
|
|
|
|
|
|
|
# sort ramp array (increasing values) |
|
5042
|
0
|
0
|
|
|
|
0
|
$struct->[$i][2] = [sort {$self->[1][(! ref($a) ? $a : $a->[0])][$dev->[$i]] <=> $self->[1][(! ref($b) ? $b : $b->[0])][$dev->[$i]]} @{$struct->[$i][2]}]; |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5043
|
|
|
|
|
|
|
|
|
5044
|
|
|
|
|
|
|
} |
|
5045
|
|
|
|
|
|
|
|
|
5046
|
|
|
|
|
|
|
# return |
|
5047
|
0
|
|
|
|
|
0
|
return($struct); |
|
5048
|
|
|
|
|
|
|
|
|
5049
|
|
|
|
|
|
|
} |
|
5050
|
|
|
|
|
|
|
|
|
5051
|
|
|
|
|
|
|
# chart signature |
|
5052
|
|
|
|
|
|
|
# signature is a 32 character hex string computed from device values |
|
5053
|
|
|
|
|
|
|
# returns undef if no device values |
|
5054
|
|
|
|
|
|
|
# parameter: ([row_slice]) |
|
5055
|
|
|
|
|
|
|
# returns: (signature) |
|
5056
|
|
|
|
|
|
|
sub signature { |
|
5057
|
|
|
|
|
|
|
|
|
5058
|
|
|
|
|
|
|
# get parameters |
|
5059
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rows) = @_; |
|
5060
|
|
|
|
|
|
|
|
|
5061
|
|
|
|
|
|
|
# local variables |
|
5062
|
0
|
|
|
|
|
0
|
my ($dev, $str, $val); |
|
5063
|
|
|
|
|
|
|
|
|
5064
|
|
|
|
|
|
|
# if chart contains device values |
|
5065
|
0
|
0
|
|
|
|
0
|
if ($dev = device($self)) { |
|
5066
|
|
|
|
|
|
|
|
|
5067
|
|
|
|
|
|
|
# initialize string |
|
5068
|
0
|
|
|
|
|
0
|
$str = ''; |
|
5069
|
|
|
|
|
|
|
|
|
5070
|
|
|
|
|
|
|
# get default row slice, if undefined |
|
5071
|
0
|
0
|
|
|
|
0
|
$rows = [1 .. size($self, 1)] if (! defined($rows)); |
|
5072
|
|
|
|
|
|
|
|
|
5073
|
|
|
|
|
|
|
# for each row |
|
5074
|
0
|
|
|
|
|
0
|
for my $i (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5075
|
|
|
|
|
|
|
|
|
5076
|
|
|
|
|
|
|
# for each device value |
|
5077
|
0
|
|
|
|
|
0
|
for my $j (@{$dev}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5078
|
|
|
|
|
|
|
|
|
5079
|
|
|
|
|
|
|
# get device value |
|
5080
|
0
|
|
|
|
|
0
|
$val = $self->[1][$i][$j]; |
|
5081
|
|
|
|
|
|
|
|
|
5082
|
|
|
|
|
|
|
# if value starts with 99.9 (P2P targets) |
|
5083
|
0
|
0
|
|
|
|
0
|
if ($val =~ m/^99\.9/) { |
|
5084
|
|
|
|
|
|
|
|
|
5085
|
|
|
|
|
|
|
# add '100' |
|
5086
|
0
|
|
|
|
|
0
|
$str .= '100'; |
|
5087
|
|
|
|
|
|
|
|
|
5088
|
|
|
|
|
|
|
} else { |
|
5089
|
|
|
|
|
|
|
|
|
5090
|
|
|
|
|
|
|
# add integer value (e.g. 50% adds '050') |
|
5091
|
0
|
|
|
|
|
0
|
$str .= sprintf('%03s', int($self->[1][$i][$j])); |
|
5092
|
|
|
|
|
|
|
|
|
5093
|
|
|
|
|
|
|
} |
|
5094
|
|
|
|
|
|
|
|
|
5095
|
|
|
|
|
|
|
} |
|
5096
|
|
|
|
|
|
|
|
|
5097
|
|
|
|
|
|
|
} |
|
5098
|
|
|
|
|
|
|
|
|
5099
|
|
|
|
|
|
|
# return MD5 hex digest |
|
5100
|
0
|
|
|
|
|
0
|
return(Digest::MD5::md5_hex($str)); |
|
5101
|
|
|
|
|
|
|
|
|
5102
|
|
|
|
|
|
|
} |
|
5103
|
|
|
|
|
|
|
|
|
5104
|
|
|
|
|
|
|
# return |
|
5105
|
0
|
|
|
|
|
0
|
return(); |
|
5106
|
|
|
|
|
|
|
|
|
5107
|
|
|
|
|
|
|
} |
|
5108
|
|
|
|
|
|
|
|
|
5109
|
|
|
|
|
|
|
# identify chart format from device values |
|
5110
|
|
|
|
|
|
|
# returns an array reference containing the chart name and nominal size |
|
5111
|
|
|
|
|
|
|
# returns undef if format unknown |
|
5112
|
|
|
|
|
|
|
# returns: (identity) |
|
5113
|
|
|
|
|
|
|
sub identity { |
|
5114
|
|
|
|
|
|
|
|
|
5115
|
|
|
|
|
|
|
# get object reference |
|
5116
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
5117
|
|
|
|
|
|
|
|
|
5118
|
|
|
|
|
|
|
# local variables |
|
5119
|
0
|
|
|
|
|
0
|
my ($dev, $sorted); |
|
5120
|
|
|
|
|
|
|
|
|
5121
|
|
|
|
|
|
|
# verify device values |
|
5122
|
0
|
0
|
|
|
|
0
|
(test($self, 'DEVICE')) or return(); |
|
5123
|
|
|
|
|
|
|
|
|
5124
|
|
|
|
|
|
|
# signature table (sorted, no white samples) |
|
5125
|
0
|
|
|
|
|
0
|
state $table = { |
|
5126
|
|
|
|
|
|
|
# CMYK charts |
|
5127
|
|
|
|
|
|
|
'8b5b7006b31df16eeb0e3d3ced60051f' => ['IT8.7/3', 928], |
|
5128
|
|
|
|
|
|
|
'b9c1f31582d682c23983aab1f1b75b4f' => ['IT8.7/4', 1617], |
|
5129
|
|
|
|
|
|
|
'15aa45ec6118dea7daddeb4ef2b54386' => ['IT8.7/5', 1617], |
|
5130
|
|
|
|
|
|
|
'aba61c4d5774da33b67b582cdb7b073c' => ['ECI2002', 1485], |
|
5131
|
|
|
|
|
|
|
'de55394b26fb64635db213042e3a5d28' => ['TC3.5', 432], |
|
5132
|
|
|
|
|
|
|
'7a1fda1429838505eadf492249ad630c' => ['TC3.5+Cal', 520], |
|
5133
|
|
|
|
|
|
|
'6c5d838867d23a76132fc1108d93c272' => ['PressCal5', 125], |
|
5134
|
|
|
|
|
|
|
'1eb64d5eba56285f124dc60065bf431e' => ['PressCalG5', 125], |
|
5135
|
|
|
|
|
|
|
'06469a5bb67ef64f0f03563e79a42992' => ['PressCal8', 225], |
|
5136
|
|
|
|
|
|
|
'41eb5955ed2abb9c7a0f6fecc5bba7fd' => ['PressCalF', 475], |
|
5137
|
|
|
|
|
|
|
'dc9d5a6302ccb62f2be359dd916a0c1f' => ['PressCalG', 475], |
|
5138
|
|
|
|
|
|
|
'48cf188554c85df6685cff6e71e360ed' => ['PressCalX', 400], |
|
5139
|
|
|
|
|
|
|
'd176de53229117268a2eb956380369e4' => ['PressCalY', 475], |
|
5140
|
|
|
|
|
|
|
'a5facefa8dc2c30f471aecdabbea6bb9' => ['PressCalZ', 625], |
|
5141
|
|
|
|
|
|
|
'4657c95764bc3fb9209f77395b658bd4' => ['P2P25', 300], |
|
5142
|
|
|
|
|
|
|
'87e9c04c2d804d87dd6127d99efb95c0' => ['P2P51', 300], |
|
5143
|
|
|
|
|
|
|
'63f4daa1011e14bc04cbd11ac7b89849' => ['P2P53', 300], |
|
5144
|
|
|
|
|
|
|
'75af26579af3b3c0cce93b09d95c0fed' => ['microP2P', 96], |
|
5145
|
|
|
|
|
|
|
'c442e077c30e1918338da856d2b6168b' => ['miniP2P', 125], |
|
5146
|
|
|
|
|
|
|
'8545bb6b881e3b2864753c87f8439e5a' => ['miniP2P53', 125], |
|
5147
|
|
|
|
|
|
|
'f11fae3e797b2e0c5a2ab9fc1788597d' => ['G7 Verifier', 56], |
|
5148
|
|
|
|
|
|
|
'905aecb1bfd469ecf6e6b7cec210460a' => ['LimitFinder', 460], |
|
5149
|
|
|
|
|
|
|
'e60bf0937c637a2b97d95961a3f650a2' => ['TC1617', 1617], |
|
5150
|
|
|
|
|
|
|
'da6a16373eeb868bac2c9682f7fb206f' => ['HC2052F', 2052], |
|
5151
|
|
|
|
|
|
|
'1671b192dc8a9f4219662bff28378ff9' => ['Curve OneRun', 1807], |
|
5152
|
|
|
|
|
|
|
'c27b03ad4289e7769dbef8f7a57330e1' => ['UGRA/FOGRA MediaWedge v2', 46], |
|
5153
|
|
|
|
|
|
|
'7915773af8e52e03924421a09ed9a104' => ['UGRA/FOGRA MediaWedge v3', 72], |
|
5154
|
|
|
|
|
|
|
'58e02386295caf078fa1b851cb5393dd' => ['Idealliance 12647-7 2009', 54], |
|
5155
|
|
|
|
|
|
|
'a06de1b8592e0b7e959a085fc7bd8086' => ['Idealliance 12647-7 2013', 84], |
|
5156
|
|
|
|
|
|
|
'a9b9bb266227df349c7630643beb1f38' => ['SpotOn Control Strip', 33], |
|
5157
|
|
|
|
|
|
|
'758d9fcec64ad9d3a7ca4562cb274e82' => ['Japan Color Control Strip', 54], |
|
5158
|
|
|
|
|
|
|
'18792374fb80709dfae611dfeeaf6bcf' => ['EFI Color Verifier US', 32], |
|
5159
|
|
|
|
|
|
|
'2207946e9fea7acf3ae990df8f49e1eb' => ['EFI Color Verifier', 15], |
|
5160
|
|
|
|
|
|
|
'cfc0196dbb05985261ba51fb91f9eccc' => ['FieryColorBar', 26], |
|
5161
|
|
|
|
|
|
|
'33bda2f014f4d99939c4ff15ceacff30' => ['Monaco CMYK 378', 378], |
|
5162
|
|
|
|
|
|
|
'9ba653e395b1199ef1d4375026a0303c' => ['Monaco CMYK 530', 530], |
|
5163
|
|
|
|
|
|
|
'd6a584f1b30c245fc48b578738bb8c18' => ['Monaco CMYK 917', 917], |
|
5164
|
|
|
|
|
|
|
'3346663bf34bca87ec09762a31bf84e2' => ['Monaco CMYK 1379', 1379], |
|
5165
|
|
|
|
|
|
|
'24b08a49124eabf0aa871987391a3e11' => ['Monaco CMYK 2989', 2989], |
|
5166
|
|
|
|
|
|
|
|
|
5167
|
|
|
|
|
|
|
# RGB charts |
|
5168
|
|
|
|
|
|
|
'7f80a2d564d0ec66fd751cbc122d0090' => ['TC2.83', 283], |
|
5169
|
|
|
|
|
|
|
'fe57e61b61ab53456082d3b9df984357' => ['TC9.18', 918], |
|
5170
|
|
|
|
|
|
|
'26113f02441add8f0b483c860b887023' => ['TC1331', 1331], |
|
5171
|
|
|
|
|
|
|
'faf68027b76bd5f9d65020c0dae5e25a' => ['Monaco RGB 343', 343], |
|
5172
|
|
|
|
|
|
|
'd2e094757c363969f5fbf2557b3b05b0' => ['Monaco RGB 729', 729], |
|
5173
|
|
|
|
|
|
|
'e44b07f1cc89876d488d3559b8a44488' => ['Monaco RGB 1728', 1728], |
|
5174
|
|
|
|
|
|
|
}; |
|
5175
|
|
|
|
|
|
|
|
|
5176
|
|
|
|
|
|
|
# make chart object containing device values only |
|
5177
|
0
|
|
|
|
|
0
|
$dev = ICC::Support::Chart->new(slice($self, [0 .. $#{$self->[1]}], device($self))); |
|
|
0
|
|
|
|
|
0
|
|
|
5178
|
|
|
|
|
|
|
|
|
5179
|
|
|
|
|
|
|
# for each row |
|
5180
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$dev->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5181
|
|
|
|
|
|
|
|
|
5182
|
|
|
|
|
|
|
# change any 99.9xx% values to 100% (P2P charts!) |
|
5183
|
0
|
0
|
|
|
|
0
|
@{$dev->[1][$i]} = map {m/^99.9/ ? 100 : $_} @{$dev->[1][$i]}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5184
|
|
|
|
|
|
|
|
|
5185
|
|
|
|
|
|
|
} |
|
5186
|
|
|
|
|
|
|
|
|
5187
|
|
|
|
|
|
|
# get sorted samples |
|
5188
|
0
|
|
|
|
|
0
|
$sorted = ICC::Support::Chart::sort($dev); |
|
5189
|
|
|
|
|
|
|
|
|
5190
|
|
|
|
|
|
|
# if RGB device values |
|
5191
|
0
|
0
|
|
|
|
0
|
if ($dev->[1][0][0] =~ m/RGB_R$/) { |
|
5192
|
|
|
|
|
|
|
|
|
5193
|
|
|
|
|
|
|
# remove white samples (RGB) |
|
5194
|
0
|
|
|
|
|
0
|
@{$sorted} = grep {grep {$_ != 255} @{$dev->[1][$_]}} @{$sorted}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5195
|
|
|
|
|
|
|
|
|
5196
|
|
|
|
|
|
|
} else { |
|
5197
|
|
|
|
|
|
|
|
|
5198
|
|
|
|
|
|
|
# remove white samples (non-RGB) |
|
5199
|
0
|
|
|
|
|
0
|
@{$sorted} = grep {grep {$_ != 0} @{$dev->[1][$_]}} @{$sorted}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5200
|
|
|
|
|
|
|
|
|
5201
|
|
|
|
|
|
|
} |
|
5202
|
|
|
|
|
|
|
|
|
5203
|
|
|
|
|
|
|
# return chart identity, undefined if hash lookup fails |
|
5204
|
0
|
|
|
|
|
0
|
return($table->{signature($dev, $sorted)}); |
|
5205
|
|
|
|
|
|
|
|
|
5206
|
|
|
|
|
|
|
} |
|
5207
|
|
|
|
|
|
|
|
|
5208
|
|
|
|
|
|
|
# write chart to ISO 28178 (CGATS.17) ASCII file |
|
5209
|
|
|
|
|
|
|
# optional slice parameters are either scalars, array references or 'Math::Matrix' objects |
|
5210
|
|
|
|
|
|
|
# optional hash parameter keys: 'sid', 'append', 'standard' |
|
5211
|
|
|
|
|
|
|
# parameters: (path_to_file, [row_slice, [column_slice]], [hash]) |
|
5212
|
|
|
|
|
|
|
sub write { |
|
5213
|
|
|
|
|
|
|
|
|
5214
|
|
|
|
|
|
|
# local variables |
|
5215
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $row_length, $m, $n, $sid, $fh, $rs, @fields); |
|
5216
|
0
|
|
|
|
|
0
|
my (%cspec, %keys, $keyword, $value, $source, $std_key, @s, $sidx, $append); |
|
5217
|
0
|
|
|
|
|
0
|
my ($null, $undef); |
|
5218
|
|
|
|
|
|
|
|
|
5219
|
|
|
|
|
|
|
# get optional hash parameter |
|
5220
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
5221
|
|
|
|
|
|
|
|
|
5222
|
|
|
|
|
|
|
# get remaining parameters |
|
5223
|
0
|
|
|
|
|
0
|
my ($self, $path, $rows, $cols) = @_; |
|
5224
|
|
|
|
|
|
|
|
|
5225
|
|
|
|
|
|
|
# if row slice defined |
|
5226
|
0
|
0
|
|
|
|
0
|
if (defined($rows)) { |
|
5227
|
|
|
|
|
|
|
|
|
5228
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
5229
|
0
|
0
|
0
|
|
|
0
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5230
|
|
|
|
|
|
|
|
|
5231
|
|
|
|
|
|
|
# use all rows |
|
5232
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5233
|
|
|
|
|
|
|
|
|
5234
|
|
|
|
|
|
|
} else { |
|
5235
|
|
|
|
|
|
|
|
|
5236
|
|
|
|
|
|
|
# get row length if row slice is Math::Matrix object |
|
5237
|
0
|
0
|
|
|
|
0
|
$row_length = @{$rows->[0]} if (UNIVERSAL::isa($rows, 'Math::Matrix')); |
|
|
0
|
|
|
|
|
0
|
|
|
5238
|
|
|
|
|
|
|
|
|
5239
|
|
|
|
|
|
|
# flatten row slice |
|
5240
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
5241
|
|
|
|
|
|
|
|
|
5242
|
|
|
|
|
|
|
} |
|
5243
|
|
|
|
|
|
|
|
|
5244
|
|
|
|
|
|
|
} else { |
|
5245
|
|
|
|
|
|
|
|
|
5246
|
|
|
|
|
|
|
# use all rows |
|
5247
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5248
|
|
|
|
|
|
|
|
|
5249
|
|
|
|
|
|
|
} |
|
5250
|
|
|
|
|
|
|
|
|
5251
|
|
|
|
|
|
|
# get number of rows |
|
5252
|
0
|
|
|
|
|
0
|
$m = @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
5253
|
|
|
|
|
|
|
|
|
5254
|
|
|
|
|
|
|
# warn if invalid samples |
|
5255
|
0
|
0
|
0
|
|
|
0
|
(@{$rows} == grep {$_ == int($_) && $_ != 0 && defined($self->[1][$_])} @{$rows})|| warn('row slice contains invalid samples'); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5256
|
|
|
|
|
|
|
|
|
5257
|
|
|
|
|
|
|
# if column slice defined |
|
5258
|
0
|
0
|
|
|
|
0
|
if (defined($cols)) { |
|
5259
|
|
|
|
|
|
|
|
|
5260
|
|
|
|
|
|
|
# if column slice an empty array reference |
|
5261
|
0
|
0
|
0
|
|
|
0
|
if (ref($cols) eq 'ARRAY' && @{$cols} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5262
|
|
|
|
|
|
|
|
|
5263
|
|
|
|
|
|
|
# use all columns |
|
5264
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5265
|
|
|
|
|
|
|
|
|
5266
|
|
|
|
|
|
|
} else { |
|
5267
|
|
|
|
|
|
|
|
|
5268
|
|
|
|
|
|
|
# flatten column slice |
|
5269
|
0
|
|
|
|
|
0
|
$cols = ICC::Shared::flatten($cols); |
|
5270
|
|
|
|
|
|
|
|
|
5271
|
|
|
|
|
|
|
} |
|
5272
|
|
|
|
|
|
|
|
|
5273
|
|
|
|
|
|
|
} else { |
|
5274
|
|
|
|
|
|
|
|
|
5275
|
|
|
|
|
|
|
# use all columns |
|
5276
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5277
|
|
|
|
|
|
|
|
|
5278
|
|
|
|
|
|
|
} |
|
5279
|
|
|
|
|
|
|
|
|
5280
|
|
|
|
|
|
|
# map column slice, converting non-numeric values with 'test' method |
|
5281
|
0
|
0
|
|
|
|
0
|
@{$cols} = map {Scalar::Util::looks_like_number($_) ? $_ : $self->test($_)} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5282
|
|
|
|
|
|
|
|
|
5283
|
|
|
|
|
|
|
# get number of columns |
|
5284
|
0
|
|
|
|
|
0
|
$n = @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
5285
|
|
|
|
|
|
|
|
|
5286
|
|
|
|
|
|
|
# filter column slice |
|
5287
|
0
|
0
|
|
|
|
0
|
@{$cols} = grep {$_ == int($_) && defined($self->[1][0][$_])} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5288
|
|
|
|
|
|
|
|
|
5289
|
|
|
|
|
|
|
# warn if invalid fields |
|
5290
|
0
|
0
|
|
|
|
0
|
($n == @{$cols}) || warn('column slice contains invalid fields'); |
|
|
0
|
|
|
|
|
0
|
|
|
5291
|
|
|
|
|
|
|
|
|
5292
|
|
|
|
|
|
|
# if 'sid' hash value defined |
|
5293
|
0
|
0
|
|
|
|
0
|
if (defined($sid = $hash->{'sid'})) { |
|
5294
|
|
|
|
|
|
|
|
|
5295
|
|
|
|
|
|
|
# if array reference or Math::Matrix object |
|
5296
|
0
|
0
|
0
|
|
|
0
|
if (ref($sid) eq 'ARRAY' || UNIVERSAL::isa($sid, 'Math::Matrix')) { |
|
|
|
0
|
|
|
|
|
|
|
5297
|
|
|
|
|
|
|
|
|
5298
|
|
|
|
|
|
|
# flatten 'sid' slice |
|
5299
|
0
|
|
|
|
|
0
|
$sid = ICC::Shared::flatten($sid); |
|
5300
|
|
|
|
|
|
|
|
|
5301
|
|
|
|
|
|
|
# warn row slice and sid slice are different sizes |
|
5302
|
0
|
0
|
|
|
|
0
|
($m == @{$sid}) || warn('row slice and sid slice are different sizes'); |
|
|
0
|
|
|
|
|
0
|
|
|
5303
|
|
|
|
|
|
|
|
|
5304
|
|
|
|
|
|
|
} elsif ($sid eq 'row') { |
|
5305
|
|
|
|
|
|
|
|
|
5306
|
|
|
|
|
|
|
# use sequential row list |
|
5307
|
0
|
|
|
|
|
0
|
$sid = [1 .. $m]; |
|
5308
|
|
|
|
|
|
|
|
|
5309
|
|
|
|
|
|
|
} else { |
|
5310
|
|
|
|
|
|
|
|
|
5311
|
|
|
|
|
|
|
# error |
|
5312
|
0
|
|
|
|
|
0
|
croak('invalid \'sid\' hash value'); |
|
5313
|
|
|
|
|
|
|
|
|
5314
|
|
|
|
|
|
|
} |
|
5315
|
|
|
|
|
|
|
|
|
5316
|
|
|
|
|
|
|
} |
|
5317
|
|
|
|
|
|
|
|
|
5318
|
|
|
|
|
|
|
# filter path |
|
5319
|
0
|
|
|
|
|
0
|
ICC::Shared::filterPath($path); |
|
5320
|
|
|
|
|
|
|
|
|
5321
|
|
|
|
|
|
|
# open the file |
|
5322
|
0
|
0
|
|
|
|
0
|
open($fh, '>', $path) or croak("can't open $path: $!"); |
|
5323
|
|
|
|
|
|
|
|
|
5324
|
|
|
|
|
|
|
# disable :crlf translation |
|
5325
|
0
|
|
|
|
|
0
|
binmode($fh); |
|
5326
|
|
|
|
|
|
|
|
|
5327
|
|
|
|
|
|
|
# get the record separator |
|
5328
|
0
|
|
0
|
|
|
0
|
$rs = $self->[0]{'write_rs'} || $self->[0]{'read_rs'} || "\n"; |
|
5329
|
|
|
|
|
|
|
|
|
5330
|
|
|
|
|
|
|
# print the standard, if defined in hash |
|
5331
|
0
|
0
|
|
|
|
0
|
print $fh $hash->{'standard'}, $rs if defined($hash->{'standard'}); |
|
5332
|
|
|
|
|
|
|
|
|
5333
|
|
|
|
|
|
|
# print LGOROWLENGTH, if row length defined |
|
5334
|
0
|
0
|
|
|
|
0
|
printf $fh "LGOROWLENGTH\t%d$rs", $row_length if (defined($row_length)); |
|
5335
|
|
|
|
|
|
|
|
|
5336
|
|
|
|
|
|
|
# initialize color specification hash |
|
5337
|
|
|
|
|
|
|
# so lines with 'FileInformation' source are printed |
|
5338
|
0
|
|
|
|
|
0
|
%cspec = ('FileInformation' => 1); |
|
5339
|
|
|
|
|
|
|
|
|
5340
|
|
|
|
|
|
|
# add referenced sources to color specification hash |
|
5341
|
0
|
0
|
|
|
|
0
|
for (@{$self->[2][5]}[@{$cols}]) {$cspec{$_}++ if defined()}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5342
|
|
|
|
|
|
|
|
|
5343
|
|
|
|
|
|
|
# make hash of quoted keywords |
|
5344
|
0
|
|
|
|
|
0
|
for (@{$self->[3]}) {$keys{"\"$_->[0]\""}++} |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5345
|
|
|
|
|
|
|
|
|
5346
|
|
|
|
|
|
|
# for each header line |
|
5347
|
0
|
|
|
|
|
0
|
for (@{$self->[3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5348
|
|
|
|
|
|
|
|
|
5349
|
|
|
|
|
|
|
# get keyword, value and source |
|
5350
|
0
|
|
|
|
|
0
|
($keyword, $value, $source) = @{$_}; |
|
|
0
|
|
|
|
|
0
|
|
|
5351
|
|
|
|
|
|
|
|
|
5352
|
|
|
|
|
|
|
# if keyword defined and length > 0 |
|
5353
|
0
|
0
|
0
|
|
|
0
|
if (defined($keyword) && length($keyword)) { |
|
5354
|
|
|
|
|
|
|
|
|
5355
|
|
|
|
|
|
|
# make uppercase |
|
5356
|
0
|
|
|
|
|
0
|
$keyword = uc($keyword); |
|
5357
|
|
|
|
|
|
|
|
|
5358
|
|
|
|
|
|
|
# skip certain keywords |
|
5359
|
0
|
0
|
|
|
|
0
|
next if ($keyword =~ m/NUMBER_OF_FIELDS|NUMBER_OF_SETS/); # these are output later |
|
5360
|
0
|
0
|
0
|
|
|
0
|
next if ($keyword =~ m/LGOROWLENGTH/ && defined($row_length)); # row length already output |
|
5361
|
0
|
0
|
0
|
|
|
0
|
next if ($keyword eq 'KEYWORD' && ! exists($keys{$value})); # skip unused 'KEYWORD' entries |
|
5362
|
|
|
|
|
|
|
|
|
5363
|
|
|
|
|
|
|
# if no source or referenced source |
|
5364
|
0
|
0
|
0
|
|
|
0
|
if (! defined($source) || $cspec{$source}) { |
|
5365
|
|
|
|
|
|
|
|
|
5366
|
|
|
|
|
|
|
# if value defined and length > 0 |
|
5367
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && length($value)) { |
|
5368
|
|
|
|
|
|
|
|
|
5369
|
|
|
|
|
|
|
# print keyword/value |
|
5370
|
0
|
|
|
|
|
0
|
print $fh "$keyword\t$value$rs"; |
|
5371
|
|
|
|
|
|
|
|
|
5372
|
|
|
|
|
|
|
} else { |
|
5373
|
|
|
|
|
|
|
|
|
5374
|
|
|
|
|
|
|
# print keyword only |
|
5375
|
0
|
|
|
|
|
0
|
print $fh "$keyword$rs"; |
|
5376
|
|
|
|
|
|
|
|
|
5377
|
|
|
|
|
|
|
} |
|
5378
|
|
|
|
|
|
|
|
|
5379
|
|
|
|
|
|
|
} |
|
5380
|
|
|
|
|
|
|
|
|
5381
|
|
|
|
|
|
|
} else { |
|
5382
|
|
|
|
|
|
|
|
|
5383
|
|
|
|
|
|
|
# print empty line |
|
5384
|
0
|
|
|
|
|
0
|
print $fh "$rs"; |
|
5385
|
|
|
|
|
|
|
|
|
5386
|
|
|
|
|
|
|
} |
|
5387
|
|
|
|
|
|
|
|
|
5388
|
|
|
|
|
|
|
} |
|
5389
|
|
|
|
|
|
|
|
|
5390
|
|
|
|
|
|
|
# get format fields |
|
5391
|
0
|
|
|
|
|
0
|
@fields = @{$self->[1][0]}[@{$cols}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5392
|
|
|
|
|
|
|
|
|
5393
|
|
|
|
|
|
|
# remove any context, trim leading and trailing white space, and replace spaces with underscores |
|
5394
|
0
|
|
|
|
|
0
|
for (@fields) {s/^.*\|//; s/^\s*(.*?)\s*$/$1/; s/ /_/g} |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5395
|
|
|
|
|
|
|
|
|
5396
|
|
|
|
|
|
|
# make standard format keyword regex (per ISO 28178 and common usage) |
|
5397
|
0
|
|
|
|
|
0
|
$std_key = '^(?:' . join('|', qw(SAMPLE_ID SAMPLE_NO STRING RGB_[RGB] CMYK_[CMYK] [2-9A-F]CLR_[1-9A-F] PC\d+_\d+ SPOT_\d+ |
|
5398
|
|
|
|
|
|
|
(?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)\d{3} D_(?:RED|GREEN|BLUE|VIS|MAJOR_FILTER) XYZ_[XYZ] XYY_(?:X|Y|CAPY) |
|
5399
|
|
|
|
|
|
|
LAB_[LABCH] LAB_DE LAB_DE_94 LAB_DE_CMC LAB_DE_2000 MEAN_DE STDDEV_[XYZ] STDDEV_[LAB] CHI_SQD_PAR)) . ')$'; |
|
5400
|
|
|
|
|
|
|
|
|
5401
|
|
|
|
|
|
|
# for each format field |
|
5402
|
0
|
|
|
|
|
0
|
for (@fields) { |
|
5403
|
|
|
|
|
|
|
|
|
5404
|
|
|
|
|
|
|
# if not a standard keyword |
|
5405
|
0
|
0
|
|
|
|
0
|
if (! /$std_key/) { |
|
5406
|
|
|
|
|
|
|
|
|
5407
|
|
|
|
|
|
|
# print KEYWORD |
|
5408
|
0
|
|
|
|
|
0
|
printf $fh "KEYWORD\t%s$rs", $_; |
|
5409
|
|
|
|
|
|
|
|
|
5410
|
|
|
|
|
|
|
} |
|
5411
|
|
|
|
|
|
|
|
|
5412
|
|
|
|
|
|
|
} |
|
5413
|
|
|
|
|
|
|
|
|
5414
|
|
|
|
|
|
|
# if 'sid' slice defined |
|
5415
|
0
|
0
|
|
|
|
0
|
if (defined($sid)) { |
|
5416
|
|
|
|
|
|
|
|
|
5417
|
|
|
|
|
|
|
# if 'SAMPLE_ID' keyword(s) |
|
5418
|
0
|
0
|
|
|
|
0
|
if (@s = grep {uc($fields[$_]) eq 'SAMPLE_ID'} (0 .. $#fields)) { |
|
|
0
|
|
|
|
|
0
|
|
|
5419
|
|
|
|
|
|
|
|
|
5420
|
|
|
|
|
|
|
# save index of first match |
|
5421
|
0
|
|
|
|
|
0
|
$sidx = $s[0]; |
|
5422
|
|
|
|
|
|
|
|
|
5423
|
|
|
|
|
|
|
} else { |
|
5424
|
|
|
|
|
|
|
|
|
5425
|
|
|
|
|
|
|
# insert 'SAMPLE_ID' keyword |
|
5426
|
0
|
|
|
|
|
0
|
unshift(@fields, 'SAMPLE_ID'); |
|
5427
|
|
|
|
|
|
|
|
|
5428
|
|
|
|
|
|
|
} |
|
5429
|
|
|
|
|
|
|
|
|
5430
|
|
|
|
|
|
|
} |
|
5431
|
|
|
|
|
|
|
|
|
5432
|
|
|
|
|
|
|
# print NUMBER_OF_FIELDS |
|
5433
|
0
|
|
|
|
|
0
|
printf $fh "NUMBER_OF_FIELDS\t%d$rs", scalar(@fields); |
|
5434
|
|
|
|
|
|
|
|
|
5435
|
|
|
|
|
|
|
# print BEGIN_DATA_FORMAT |
|
5436
|
0
|
|
|
|
|
0
|
print $fh 'BEGIN_DATA_FORMAT', $rs; |
|
5437
|
|
|
|
|
|
|
|
|
5438
|
|
|
|
|
|
|
# print format string (if any) |
|
5439
|
0
|
0
|
|
|
|
0
|
print $fh join("\t", @fields), $rs if (@fields); |
|
5440
|
|
|
|
|
|
|
|
|
5441
|
|
|
|
|
|
|
# print END_DATA_FORMAT |
|
5442
|
0
|
|
|
|
|
0
|
print $fh 'END_DATA_FORMAT', $rs; |
|
5443
|
|
|
|
|
|
|
|
|
5444
|
|
|
|
|
|
|
# print NUMBER_OF_SETS |
|
5445
|
0
|
|
|
|
|
0
|
printf $fh "NUMBER_OF_SETS\t%d$rs", scalar(@{$rows}); |
|
|
0
|
|
|
|
|
0
|
|
|
5446
|
|
|
|
|
|
|
|
|
5447
|
|
|
|
|
|
|
# print BEGIN_DATA |
|
5448
|
0
|
|
|
|
|
0
|
print $fh 'BEGIN_DATA', $rs; |
|
5449
|
|
|
|
|
|
|
|
|
5450
|
|
|
|
|
|
|
# get null replacement value |
|
5451
|
0
|
|
0
|
|
|
0
|
$null = $hash->{'null'} // 'null'; |
|
5452
|
|
|
|
|
|
|
|
|
5453
|
|
|
|
|
|
|
# get undef replacement value |
|
5454
|
0
|
|
0
|
|
|
0
|
$undef = $hash->{'undef'} // 'undef'; |
|
5455
|
|
|
|
|
|
|
|
|
5456
|
|
|
|
|
|
|
# for each row |
|
5457
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5458
|
|
|
|
|
|
|
|
|
5459
|
|
|
|
|
|
|
# get data fields, replacing null and undefined values |
|
5460
|
0
|
0
|
|
|
|
0
|
@fields = map {defined() ? length() ? $_ : $null : $undef} @{$self->[1][$rows->[$i]]}[@{$cols}]; |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5461
|
|
|
|
|
|
|
|
|
5462
|
|
|
|
|
|
|
# trim leading and trailing white space, and replace spaces with underscores |
|
5463
|
0
|
|
|
|
|
0
|
for (@fields) {s/^\s*(.*?)\s*$/$1/; s/ /_/g}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5464
|
|
|
|
|
|
|
|
|
5465
|
|
|
|
|
|
|
# if 'sid' slice defined |
|
5466
|
0
|
0
|
|
|
|
0
|
if (defined($sid)) { |
|
5467
|
|
|
|
|
|
|
|
|
5468
|
|
|
|
|
|
|
# if 'sid' index defined |
|
5469
|
0
|
0
|
|
|
|
0
|
if (defined($sidx)) { |
|
5470
|
|
|
|
|
|
|
|
|
5471
|
|
|
|
|
|
|
# replace 'sid' value |
|
5472
|
0
|
|
|
|
|
0
|
$fields[$sidx] = $sid->[$i]; |
|
5473
|
|
|
|
|
|
|
|
|
5474
|
|
|
|
|
|
|
} else { |
|
5475
|
|
|
|
|
|
|
|
|
5476
|
|
|
|
|
|
|
# insert 'sid' value |
|
5477
|
0
|
|
|
|
|
0
|
unshift(@fields, $sid->[$i]); |
|
5478
|
|
|
|
|
|
|
} |
|
5479
|
|
|
|
|
|
|
|
|
5480
|
|
|
|
|
|
|
} |
|
5481
|
|
|
|
|
|
|
|
|
5482
|
|
|
|
|
|
|
# print the data record |
|
5483
|
0
|
|
|
|
|
0
|
print $fh join("\t", @fields), $rs; |
|
5484
|
|
|
|
|
|
|
|
|
5485
|
|
|
|
|
|
|
} |
|
5486
|
|
|
|
|
|
|
|
|
5487
|
|
|
|
|
|
|
# print END_DATA |
|
5488
|
0
|
|
|
|
|
0
|
print $fh 'END_DATA', $rs; |
|
5489
|
|
|
|
|
|
|
|
|
5490
|
|
|
|
|
|
|
# if 'append' hash value defined |
|
5491
|
0
|
0
|
|
|
|
0
|
if (defined($append = $hash->{'append'})) { |
|
5492
|
|
|
|
|
|
|
|
|
5493
|
|
|
|
|
|
|
# replace line endings, if any |
|
5494
|
0
|
|
|
|
|
0
|
$append =~ s/\n/$rs/g; |
|
5495
|
|
|
|
|
|
|
|
|
5496
|
|
|
|
|
|
|
# print appended data |
|
5497
|
0
|
|
|
|
|
0
|
print $fh $append; |
|
5498
|
|
|
|
|
|
|
|
|
5499
|
|
|
|
|
|
|
} |
|
5500
|
|
|
|
|
|
|
|
|
5501
|
|
|
|
|
|
|
# close the file |
|
5502
|
0
|
|
|
|
|
0
|
close($fh); |
|
5503
|
|
|
|
|
|
|
|
|
5504
|
|
|
|
|
|
|
} |
|
5505
|
|
|
|
|
|
|
|
|
5506
|
|
|
|
|
|
|
# write chart to CxF3 file |
|
5507
|
|
|
|
|
|
|
# optional slice parameters are either scalars, array references or 'Math::Matrix' objects |
|
5508
|
|
|
|
|
|
|
# optional hash parameter keys: 'cc:FileInformation' |
|
5509
|
|
|
|
|
|
|
# parameters: (path_to_file, [row_slice, [column_slice]], [hash]) |
|
5510
|
|
|
|
|
|
|
sub writeCxF3 { |
|
5511
|
|
|
|
|
|
|
|
|
5512
|
|
|
|
|
|
|
# local variables |
|
5513
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $row_length, $n); |
|
5514
|
0
|
|
|
|
|
0
|
my ($dom, $root, $ns, $nsURI, $xpc); |
|
5515
|
0
|
|
|
|
|
0
|
my ($datetime, $id, $ops, $objcol); |
|
5516
|
0
|
|
|
|
|
0
|
my ($prefix, $nid, $obj, $xpath, $node); |
|
5517
|
0
|
|
|
|
|
0
|
my (%lookup, @data, $sub, $spot); |
|
5518
|
|
|
|
|
|
|
|
|
5519
|
|
|
|
|
|
|
# get optional hash parameter |
|
5520
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
5521
|
|
|
|
|
|
|
|
|
5522
|
|
|
|
|
|
|
# get remaining parameters |
|
5523
|
0
|
|
|
|
|
0
|
my ($self, $path, $rows, $cols) = @_; |
|
5524
|
|
|
|
|
|
|
|
|
5525
|
|
|
|
|
|
|
# if row slice defined |
|
5526
|
0
|
0
|
|
|
|
0
|
if (defined($rows)) { |
|
5527
|
|
|
|
|
|
|
|
|
5528
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
5529
|
0
|
0
|
0
|
|
|
0
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5530
|
|
|
|
|
|
|
|
|
5531
|
|
|
|
|
|
|
# use all rows |
|
5532
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5533
|
|
|
|
|
|
|
|
|
5534
|
|
|
|
|
|
|
} else { |
|
5535
|
|
|
|
|
|
|
|
|
5536
|
|
|
|
|
|
|
# get row length if row slice is Math::Matrix object |
|
5537
|
0
|
0
|
|
|
|
0
|
$row_length = @{$rows->[0]} if (UNIVERSAL::isa($rows, 'Math::Matrix')); |
|
|
0
|
|
|
|
|
0
|
|
|
5538
|
|
|
|
|
|
|
|
|
5539
|
|
|
|
|
|
|
# flatten row slice |
|
5540
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
5541
|
|
|
|
|
|
|
|
|
5542
|
|
|
|
|
|
|
} |
|
5543
|
|
|
|
|
|
|
|
|
5544
|
|
|
|
|
|
|
} else { |
|
5545
|
|
|
|
|
|
|
|
|
5546
|
|
|
|
|
|
|
# set array reference to all rows |
|
5547
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5548
|
|
|
|
|
|
|
|
|
5549
|
|
|
|
|
|
|
} |
|
5550
|
|
|
|
|
|
|
|
|
5551
|
|
|
|
|
|
|
# get number of rows |
|
5552
|
0
|
|
|
|
|
0
|
$n = @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
5553
|
|
|
|
|
|
|
|
|
5554
|
|
|
|
|
|
|
# filter row slice |
|
5555
|
0
|
0
|
0
|
|
|
0
|
@{$rows} = grep {$_ == int($_) && $_ != 0 && defined($self->[1][$_])} @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5556
|
|
|
|
|
|
|
|
|
5557
|
|
|
|
|
|
|
# warn if invalid samples |
|
5558
|
0
|
0
|
|
|
|
0
|
($n == @{$rows}) || warn('row slice contains invalid samples'); |
|
|
0
|
|
|
|
|
0
|
|
|
5559
|
|
|
|
|
|
|
|
|
5560
|
|
|
|
|
|
|
# open CxF3 template |
|
5561
|
0
|
0
|
|
|
|
0
|
eval {$dom = XML::LibXML->load_xml('location' => ICC::Shared::getICCPath('Templates/CxF3_template.xml'))} or croak('can\'t load CxF3 template'); |
|
|
0
|
|
|
|
|
0
|
|
|
5562
|
|
|
|
|
|
|
|
|
5563
|
|
|
|
|
|
|
# get the root element |
|
5564
|
0
|
|
|
|
|
0
|
$root = $dom->documentElement(); |
|
5565
|
|
|
|
|
|
|
|
|
5566
|
|
|
|
|
|
|
# get the namespace prefix and URI |
|
5567
|
0
|
|
|
|
|
0
|
$ns = $root->prefix(); |
|
5568
|
0
|
|
|
|
|
0
|
$nsURI = $root->namespaceURI(); |
|
5569
|
|
|
|
|
|
|
|
|
5570
|
|
|
|
|
|
|
# make XPathContext object |
|
5571
|
0
|
|
|
|
|
0
|
$xpc = XML::LibXML::XPathContext->new($root); |
|
5572
|
|
|
|
|
|
|
|
|
5573
|
|
|
|
|
|
|
# write 'FileInformation' nodes |
|
5574
|
0
|
|
|
|
|
0
|
$datetime = _writeCxF3fileinfo($self, $xpc, $ns, $nsURI, $hash); |
|
5575
|
|
|
|
|
|
|
|
|
5576
|
|
|
|
|
|
|
# make write operations array from column slice |
|
5577
|
|
|
|
|
|
|
# array structure: [[[class, prefix, XPath, [sub_paths], [columns], {attributes}, sort_order], ...], ...] |
|
5578
|
0
|
|
|
|
|
0
|
$ops = _makeCxF3writeops($self, $ns, $cols); |
|
5579
|
|
|
|
|
|
|
|
|
5580
|
|
|
|
|
|
|
# write 'ColorSpecification' nodes |
|
5581
|
0
|
|
|
|
|
0
|
_writeCxF3colorspec($self, $xpc, $ns, $nsURI, $ops); |
|
5582
|
|
|
|
|
|
|
|
|
5583
|
|
|
|
|
|
|
# get the 'ObjectCollection' node |
|
5584
|
0
|
|
|
|
|
0
|
($objcol) = $xpc->findnodes("$ns:Resources/$ns:ObjectCollection"); |
|
5585
|
|
|
|
|
|
|
|
|
5586
|
|
|
|
|
|
|
# init object Id index |
|
5587
|
0
|
|
|
|
|
0
|
$id = 1; |
|
5588
|
|
|
|
|
|
|
|
|
5589
|
|
|
|
|
|
|
# for each group of operations |
|
5590
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$ops}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5591
|
|
|
|
|
|
|
|
|
5592
|
|
|
|
|
|
|
# get prefix (ObjectType) |
|
5593
|
0
|
|
|
|
|
0
|
$prefix = $ops->[$i][0][1]; |
|
5594
|
|
|
|
|
|
|
|
|
5595
|
|
|
|
|
|
|
# initialize name Id |
|
5596
|
0
|
|
|
|
|
0
|
$nid = 0; |
|
5597
|
|
|
|
|
|
|
|
|
5598
|
|
|
|
|
|
|
# for each row in slice |
|
5599
|
0
|
|
|
|
|
0
|
for my $j (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5600
|
|
|
|
|
|
|
|
|
5601
|
|
|
|
|
|
|
# increment name Id |
|
5602
|
0
|
|
|
|
|
0
|
$nid++; |
|
5603
|
|
|
|
|
|
|
|
|
5604
|
|
|
|
|
|
|
# add 'Object' node |
|
5605
|
0
|
|
|
|
|
0
|
$obj = $objcol->appendChild(XML::LibXML::Element->new("$ns:Object")); |
|
5606
|
0
|
|
|
|
|
0
|
$obj->setAttribute('ObjectType', $prefix); |
|
5607
|
0
|
|
|
|
|
0
|
$obj->setAttribute('Name', "$prefix$nid"); |
|
5608
|
0
|
|
|
|
|
0
|
$obj->setAttribute('Id', "c$id"); |
|
5609
|
0
|
|
|
|
|
0
|
$obj->setNamespace($nsURI, $ns); |
|
5610
|
|
|
|
|
|
|
|
|
5611
|
|
|
|
|
|
|
# add 'CreationDate' node |
|
5612
|
0
|
|
|
|
|
0
|
$node = $obj->appendChild(XML::LibXML::Element->new("$ns:CreationDate")); |
|
5613
|
0
|
|
|
|
|
0
|
$node->appendText($datetime); |
|
5614
|
0
|
|
|
|
|
0
|
$node->setNamespace($nsURI, $ns); |
|
5615
|
|
|
|
|
|
|
|
|
5616
|
|
|
|
|
|
|
# init XPath node hash |
|
5617
|
0
|
|
|
|
|
0
|
%lookup = (); |
|
5618
|
|
|
|
|
|
|
|
|
5619
|
|
|
|
|
|
|
# for each operation in the group |
|
5620
|
0
|
|
|
|
|
0
|
for my $k (0 .. $#{$ops->[$i]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5621
|
|
|
|
|
|
|
|
|
5622
|
|
|
|
|
|
|
# set current node to Object |
|
5623
|
0
|
|
|
|
|
0
|
$node = $obj; |
|
5624
|
|
|
|
|
|
|
|
|
5625
|
|
|
|
|
|
|
# initialize XPath |
|
5626
|
0
|
|
|
|
|
0
|
$xpath = undef; |
|
5627
|
|
|
|
|
|
|
|
|
5628
|
|
|
|
|
|
|
# for each XPath segment |
|
5629
|
0
|
|
|
|
|
0
|
for (split(/\//, $ops->[$i][$k][2])) { |
|
5630
|
|
|
|
|
|
|
|
|
5631
|
|
|
|
|
|
|
# add segment to XPath |
|
5632
|
0
|
0
|
|
|
|
0
|
$xpath = defined($xpath) ? "$xpath/$_" : $_; |
|
5633
|
|
|
|
|
|
|
|
|
5634
|
|
|
|
|
|
|
# if segment exists |
|
5635
|
0
|
0
|
|
|
|
0
|
if (exists($lookup{$xpath})) { |
|
5636
|
|
|
|
|
|
|
|
|
5637
|
|
|
|
|
|
|
# use node |
|
5638
|
0
|
|
|
|
|
0
|
$node = $lookup{$xpath}; |
|
5639
|
|
|
|
|
|
|
|
|
5640
|
|
|
|
|
|
|
} else { |
|
5641
|
|
|
|
|
|
|
|
|
5642
|
|
|
|
|
|
|
# add node |
|
5643
|
0
|
|
|
|
|
0
|
$node = $node->appendChild(XML::LibXML::Element->new($_)); |
|
5644
|
0
|
|
|
|
|
0
|
$node->setNamespace($nsURI, $ns); |
|
5645
|
|
|
|
|
|
|
|
|
5646
|
|
|
|
|
|
|
# add hash entry (except Tag elements) |
|
5647
|
0
|
0
|
|
|
|
0
|
$lookup{$xpath} = $node if ($_ ne "$ns:Tag"); |
|
5648
|
|
|
|
|
|
|
|
|
5649
|
|
|
|
|
|
|
} |
|
5650
|
|
|
|
|
|
|
|
|
5651
|
|
|
|
|
|
|
} |
|
5652
|
|
|
|
|
|
|
|
|
5653
|
|
|
|
|
|
|
# for each attribute key (if any) |
|
5654
|
0
|
|
|
|
|
0
|
for (keys(%{$ops->[$i][$k][5]})) { |
|
|
0
|
|
|
|
|
0
|
|
|
5655
|
|
|
|
|
|
|
|
|
5656
|
|
|
|
|
|
|
# set node attribute using either data element or hash value |
|
5657
|
0
|
0
|
|
|
|
0
|
$node->setAttribute($_, (ref($ops->[$i][$k][5]{$_}) eq 'ARRAY') ? $self->[1][$j][$ops->[$i][$k][5]{$_}[0]] : $ops->[$i][$k][5]{$_}); |
|
5658
|
|
|
|
|
|
|
|
|
5659
|
|
|
|
|
|
|
} |
|
5660
|
|
|
|
|
|
|
|
|
5661
|
|
|
|
|
|
|
# get data |
|
5662
|
0
|
|
|
|
|
0
|
@data = @{$self->[1][$j]}[@{$ops->[$i][$k][4]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5663
|
|
|
|
|
|
|
|
|
5664
|
|
|
|
|
|
|
# warn on undefined data |
|
5665
|
0
|
0
|
|
|
|
0
|
(@data == grep {defined()} @data) || warn("undefined data in sample $j when writing CxF3 file"); |
|
|
0
|
|
|
|
|
0
|
|
|
5666
|
|
|
|
|
|
|
|
|
5667
|
|
|
|
|
|
|
# if subpaths |
|
5668
|
0
|
0
|
|
|
|
0
|
if (@{$ops->[$i][$k][3]}) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
5669
|
|
|
|
|
|
|
|
|
5670
|
|
|
|
|
|
|
# for each subpath |
|
5671
|
0
|
|
|
|
|
0
|
for my $s (0 .. $#{$ops->[$i][$k][3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5672
|
|
|
|
|
|
|
|
|
5673
|
|
|
|
|
|
|
# add node |
|
5674
|
|
|
|
|
|
|
# CxF3 schema requires integer values for RGB data |
|
5675
|
0
|
|
|
|
|
0
|
$sub = $node->appendChild(XML::LibXML::Element->new($ops->[$i][$k][3][$s])); |
|
5676
|
0
|
0
|
|
|
|
0
|
$sub->appendText($ops->[$i][$k][0] eq 'RGB' ? int($data[$s] + 0.5) : $data[$s]); |
|
5677
|
0
|
|
|
|
|
0
|
$sub->setNamespace($nsURI, $ns); |
|
5678
|
|
|
|
|
|
|
|
|
5679
|
|
|
|
|
|
|
} |
|
5680
|
|
|
|
|
|
|
|
|
5681
|
|
|
|
|
|
|
# if NCLR class |
|
5682
|
0
|
0
|
|
|
|
0
|
if ($ops->[$i][$k][0] eq 'NCLR') { |
|
5683
|
|
|
|
|
|
|
|
|
5684
|
|
|
|
|
|
|
# for each spot color |
|
5685
|
0
|
|
|
|
|
0
|
for my $s (4 .. $#data) { |
|
5686
|
|
|
|
|
|
|
|
|
5687
|
|
|
|
|
|
|
# add SpotColor elements |
|
5688
|
0
|
|
|
|
|
0
|
$spot = $node->appendChild(XML::LibXML::Element->new("$ns:SpotColor")); |
|
5689
|
0
|
|
|
|
|
0
|
$spot->setNamespace($nsURI, $ns); |
|
5690
|
0
|
|
|
|
|
0
|
$sub = $spot->appendChild(XML::LibXML::Element->new("$ns:Name")); |
|
5691
|
0
|
|
|
|
|
0
|
$sub->appendText('Spot' . ($s + 1)); |
|
5692
|
0
|
|
|
|
|
0
|
$sub->setNamespace($nsURI, $ns); |
|
5693
|
0
|
|
|
|
|
0
|
$sub = $spot->appendChild(XML::LibXML::Element->new("$ns:Percentage")); |
|
5694
|
0
|
|
|
|
|
0
|
$sub->appendText($data[$s]); |
|
5695
|
0
|
|
|
|
|
0
|
$sub->setNamespace($nsURI, $ns); |
|
5696
|
|
|
|
|
|
|
|
|
5697
|
|
|
|
|
|
|
} |
|
5698
|
|
|
|
|
|
|
|
|
5699
|
|
|
|
|
|
|
} |
|
5700
|
|
|
|
|
|
|
|
|
5701
|
|
|
|
|
|
|
# no subpaths and one data value |
|
5702
|
|
|
|
|
|
|
} elsif (@data == 1) { |
|
5703
|
|
|
|
|
|
|
|
|
5704
|
|
|
|
|
|
|
# add data as text content |
|
5705
|
0
|
|
|
|
|
0
|
$node->appendText($data[0]); |
|
5706
|
|
|
|
|
|
|
|
|
5707
|
|
|
|
|
|
|
# no subpaths and multiple data values |
|
5708
|
|
|
|
|
|
|
} elsif (@data > 1) { |
|
5709
|
|
|
|
|
|
|
|
|
5710
|
|
|
|
|
|
|
# if DENSITY class |
|
5711
|
0
|
0
|
|
|
|
0
|
if ($ops->[$i][$k][0] eq 'DENSITY') { |
|
5712
|
|
|
|
|
|
|
|
|
5713
|
|
|
|
|
|
|
##### to be done |
|
5714
|
|
|
|
|
|
|
|
|
5715
|
|
|
|
|
|
|
} else { |
|
5716
|
|
|
|
|
|
|
|
|
5717
|
|
|
|
|
|
|
# join data and add as text content |
|
5718
|
0
|
|
|
|
|
0
|
$node->appendText(join(' ', @data)); |
|
5719
|
|
|
|
|
|
|
|
|
5720
|
|
|
|
|
|
|
} |
|
5721
|
|
|
|
|
|
|
|
|
5722
|
|
|
|
|
|
|
} |
|
5723
|
|
|
|
|
|
|
|
|
5724
|
|
|
|
|
|
|
} |
|
5725
|
|
|
|
|
|
|
|
|
5726
|
|
|
|
|
|
|
# add Name attribute to TagCollection element |
|
5727
|
0
|
0
|
|
|
|
0
|
$lookup{"$ns:TagCollection"}->setAttribute('Name', 'Location') if exists($lookup{"$ns:TagCollection"}); |
|
5728
|
|
|
|
|
|
|
|
|
5729
|
|
|
|
|
|
|
# if nothing was added to Object |
|
5730
|
0
|
0
|
|
|
|
0
|
if ($node->isSameNode($obj)) { |
|
5731
|
|
|
|
|
|
|
|
|
5732
|
|
|
|
|
|
|
# unbind the node |
|
5733
|
0
|
|
|
|
|
0
|
$node->unbindNode(); |
|
5734
|
|
|
|
|
|
|
|
|
5735
|
|
|
|
|
|
|
} else { |
|
5736
|
|
|
|
|
|
|
|
|
5737
|
|
|
|
|
|
|
# increment Object Id |
|
5738
|
0
|
|
|
|
|
0
|
$id++; |
|
5739
|
|
|
|
|
|
|
|
|
5740
|
|
|
|
|
|
|
} |
|
5741
|
|
|
|
|
|
|
|
|
5742
|
|
|
|
|
|
|
} |
|
5743
|
|
|
|
|
|
|
|
|
5744
|
|
|
|
|
|
|
} |
|
5745
|
|
|
|
|
|
|
|
|
5746
|
|
|
|
|
|
|
# write CxF3 CustomResources nodes |
|
5747
|
0
|
|
|
|
|
0
|
_writeCxF3customres($self, $xpc, $ns); |
|
5748
|
|
|
|
|
|
|
|
|
5749
|
|
|
|
|
|
|
# validate the CxF3 document |
|
5750
|
0
|
0
|
0
|
|
|
0
|
_validateCxF3($dom) if (defined($hash->{'validate'}) && $hash->{'validate'}); |
|
5751
|
|
|
|
|
|
|
|
|
5752
|
|
|
|
|
|
|
# filter path |
|
5753
|
0
|
|
|
|
|
0
|
ICC::Shared::filterPath($path); |
|
5754
|
|
|
|
|
|
|
|
|
5755
|
|
|
|
|
|
|
# write CxF3 file |
|
5756
|
0
|
|
|
|
|
0
|
$dom->toFile($path, 1); |
|
5757
|
|
|
|
|
|
|
|
|
5758
|
|
|
|
|
|
|
} |
|
5759
|
|
|
|
|
|
|
|
|
5760
|
|
|
|
|
|
|
# write chart data array as delimited ASCII file (for Excel, R, MATLAB, etc.) |
|
5761
|
|
|
|
|
|
|
# optional slice parameters are either scalars, array references or 'Math::Matrix' objects |
|
5762
|
|
|
|
|
|
|
# optional hash parameter keys: 'header', 'sep', 'eol', and 'undef' |
|
5763
|
|
|
|
|
|
|
# parameters: (path_to_file, [row_slice, [column_slice]], [hash]) |
|
5764
|
|
|
|
|
|
|
sub writeASCII { |
|
5765
|
|
|
|
|
|
|
|
|
5766
|
|
|
|
|
|
|
# local variables |
|
5767
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $row_length, $n, $fh); |
|
5768
|
0
|
|
|
|
|
0
|
my ($fs, $rs, $undef, $hdr, @fields); |
|
5769
|
|
|
|
|
|
|
|
|
5770
|
|
|
|
|
|
|
# get optional hash parameter |
|
5771
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
5772
|
|
|
|
|
|
|
|
|
5773
|
|
|
|
|
|
|
# get remaining parameters |
|
5774
|
0
|
|
|
|
|
0
|
my ($self, $path, $rows, $cols) = @_; |
|
5775
|
|
|
|
|
|
|
|
|
5776
|
|
|
|
|
|
|
# if row slice defined |
|
5777
|
0
|
0
|
|
|
|
0
|
if (defined($rows)) { |
|
5778
|
|
|
|
|
|
|
|
|
5779
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
5780
|
0
|
0
|
0
|
|
|
0
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5781
|
|
|
|
|
|
|
|
|
5782
|
|
|
|
|
|
|
# use all rows |
|
5783
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5784
|
|
|
|
|
|
|
|
|
5785
|
|
|
|
|
|
|
} else { |
|
5786
|
|
|
|
|
|
|
|
|
5787
|
|
|
|
|
|
|
# get row length if row slice is Math::Matrix object |
|
5788
|
0
|
0
|
|
|
|
0
|
$row_length = @{$rows->[0]} if (UNIVERSAL::isa($rows, 'Math::Matrix')); |
|
|
0
|
|
|
|
|
0
|
|
|
5789
|
|
|
|
|
|
|
|
|
5790
|
|
|
|
|
|
|
# flatten row slice |
|
5791
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
5792
|
|
|
|
|
|
|
|
|
5793
|
|
|
|
|
|
|
} |
|
5794
|
|
|
|
|
|
|
|
|
5795
|
|
|
|
|
|
|
} else { |
|
5796
|
|
|
|
|
|
|
|
|
5797
|
|
|
|
|
|
|
# use all rows |
|
5798
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5799
|
|
|
|
|
|
|
|
|
5800
|
|
|
|
|
|
|
} |
|
5801
|
|
|
|
|
|
|
|
|
5802
|
|
|
|
|
|
|
# get number of rows |
|
5803
|
0
|
|
|
|
|
0
|
$n = @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
5804
|
|
|
|
|
|
|
|
|
5805
|
|
|
|
|
|
|
# filter row slice |
|
5806
|
0
|
0
|
0
|
|
|
0
|
@{$rows} = grep {$_ == int($_) && $_ != 0 && defined($self->[1][$_])} @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5807
|
|
|
|
|
|
|
|
|
5808
|
|
|
|
|
|
|
# warn if invalid samples |
|
5809
|
0
|
0
|
|
|
|
0
|
($n == @{$rows}) || warn('row slice contains invalid samples'); |
|
|
0
|
|
|
|
|
0
|
|
|
5810
|
|
|
|
|
|
|
|
|
5811
|
|
|
|
|
|
|
# if column slice defined |
|
5812
|
0
|
0
|
|
|
|
0
|
if (defined($cols)) { |
|
5813
|
|
|
|
|
|
|
|
|
5814
|
|
|
|
|
|
|
# if column slice an empty array reference |
|
5815
|
0
|
0
|
0
|
|
|
0
|
if (ref($cols) eq 'ARRAY' && @{$cols} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5816
|
|
|
|
|
|
|
|
|
5817
|
|
|
|
|
|
|
# use all columns |
|
5818
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5819
|
|
|
|
|
|
|
|
|
5820
|
|
|
|
|
|
|
} else { |
|
5821
|
|
|
|
|
|
|
|
|
5822
|
|
|
|
|
|
|
# flatten column slice |
|
5823
|
0
|
|
|
|
|
0
|
$cols = ICC::Shared::flatten($cols); |
|
5824
|
|
|
|
|
|
|
|
|
5825
|
|
|
|
|
|
|
} |
|
5826
|
|
|
|
|
|
|
|
|
5827
|
|
|
|
|
|
|
} else { |
|
5828
|
|
|
|
|
|
|
|
|
5829
|
|
|
|
|
|
|
# use all columns |
|
5830
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5831
|
|
|
|
|
|
|
|
|
5832
|
|
|
|
|
|
|
} |
|
5833
|
|
|
|
|
|
|
|
|
5834
|
|
|
|
|
|
|
# map column slice, converting non-numeric values with 'test' method |
|
5835
|
0
|
0
|
|
|
|
0
|
@{$cols} = map {Scalar::Util::looks_like_number($_) ? $_ : $self->test($_)} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5836
|
|
|
|
|
|
|
|
|
5837
|
|
|
|
|
|
|
# get number of columns |
|
5838
|
0
|
|
|
|
|
0
|
$n = @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
5839
|
|
|
|
|
|
|
|
|
5840
|
|
|
|
|
|
|
# filter column slice |
|
5841
|
0
|
0
|
|
|
|
0
|
@{$cols} = grep {$_ == int($_) && defined($self->[1][0][$_])} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5842
|
|
|
|
|
|
|
|
|
5843
|
|
|
|
|
|
|
# warn if invalid fields |
|
5844
|
0
|
0
|
|
|
|
0
|
($n == @{$cols}) || warn('column slice contains invalid fields'); |
|
|
0
|
|
|
|
|
0
|
|
|
5845
|
|
|
|
|
|
|
|
|
5846
|
|
|
|
|
|
|
# filter path |
|
5847
|
0
|
|
|
|
|
0
|
ICC::Shared::filterPath($path); |
|
5848
|
|
|
|
|
|
|
|
|
5849
|
|
|
|
|
|
|
# open the file |
|
5850
|
0
|
0
|
|
|
|
0
|
open($fh, '>', $path) or croak("can't open $path: $!"); |
|
5851
|
|
|
|
|
|
|
|
|
5852
|
|
|
|
|
|
|
# disable :crlf translation |
|
5853
|
0
|
|
|
|
|
0
|
binmode($fh); |
|
5854
|
|
|
|
|
|
|
|
|
5855
|
|
|
|
|
|
|
# get header mode |
|
5856
|
0
|
|
0
|
|
|
0
|
$hdr = $hash->{'header'} || 1; |
|
5857
|
|
|
|
|
|
|
|
|
5858
|
|
|
|
|
|
|
# get the field separator |
|
5859
|
0
|
|
0
|
|
|
0
|
$fs = $hash->{'sep'} || "\t"; |
|
5860
|
|
|
|
|
|
|
|
|
5861
|
|
|
|
|
|
|
# get the record separator |
|
5862
|
0
|
|
0
|
|
|
0
|
$rs = $hash->{'eol'} || "\n"; |
|
5863
|
|
|
|
|
|
|
|
|
5864
|
|
|
|
|
|
|
# get the undefined string |
|
5865
|
0
|
|
0
|
|
|
0
|
$undef = $hash->{'undef'} || ''; |
|
5866
|
|
|
|
|
|
|
|
|
5867
|
|
|
|
|
|
|
# if header enabled |
|
5868
|
0
|
0
|
|
|
|
0
|
if ($hdr) { |
|
5869
|
|
|
|
|
|
|
|
|
5870
|
|
|
|
|
|
|
# if format fields, replacing undefined values |
|
5871
|
0
|
0
|
|
|
|
0
|
if (@fields = map {defined() ? $_ : $undef} @{$self->[1][0]}[@{$cols}]) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5872
|
|
|
|
|
|
|
|
|
5873
|
|
|
|
|
|
|
# if header mode 2, remove contexts |
|
5874
|
0
|
0
|
|
|
|
0
|
if ($hdr == 2) {for (@fields) {s/^.*\|//}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5875
|
|
|
|
|
|
|
|
|
5876
|
|
|
|
|
|
|
# trim leading and trailing white space, and replace spaces with underscores |
|
5877
|
0
|
|
|
|
|
0
|
for (@fields) {s/^\s*(.*?)\s*$/$1/; s/ /_/g}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5878
|
|
|
|
|
|
|
|
|
5879
|
|
|
|
|
|
|
# print format record |
|
5880
|
0
|
|
|
|
|
0
|
print $fh join($fs, @fields), $rs; |
|
5881
|
|
|
|
|
|
|
|
|
5882
|
|
|
|
|
|
|
} |
|
5883
|
|
|
|
|
|
|
|
|
5884
|
|
|
|
|
|
|
} |
|
5885
|
|
|
|
|
|
|
|
|
5886
|
|
|
|
|
|
|
# for each row |
|
5887
|
0
|
|
|
|
|
0
|
for my $i (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5888
|
|
|
|
|
|
|
|
|
5889
|
|
|
|
|
|
|
# get data fields, replacing undefined values |
|
5890
|
0
|
0
|
|
|
|
0
|
@fields = map {defined() ? $_ : $undef} @{$self->[1][$i]}[@{$cols}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5891
|
|
|
|
|
|
|
|
|
5892
|
|
|
|
|
|
|
# trim leading and trailing white space, and replace spaces with underscores |
|
5893
|
0
|
|
|
|
|
0
|
for (@fields) {s/^\s*(.*?)\s*$/$1/; s/ /_/g}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5894
|
|
|
|
|
|
|
|
|
5895
|
|
|
|
|
|
|
# print the data record |
|
5896
|
0
|
|
|
|
|
0
|
print $fh join($fs, @fields), $rs; |
|
5897
|
|
|
|
|
|
|
|
|
5898
|
|
|
|
|
|
|
} |
|
5899
|
|
|
|
|
|
|
|
|
5900
|
|
|
|
|
|
|
# close the file |
|
5901
|
0
|
|
|
|
|
0
|
close($fh); |
|
5902
|
|
|
|
|
|
|
|
|
5903
|
|
|
|
|
|
|
} |
|
5904
|
|
|
|
|
|
|
|
|
5905
|
|
|
|
|
|
|
# write TIFF file |
|
5906
|
|
|
|
|
|
|
# RGB, CMYK, and CIE L*a*b* color spaces supported |
|
5907
|
|
|
|
|
|
|
# 8-bit, 16-bit or 32-bit, Intel or Motorola byte order supported |
|
5908
|
|
|
|
|
|
|
# alpha and spot channels in RGB and CMYK files supported |
|
5909
|
|
|
|
|
|
|
# supported hash keys: 'width', 'height', 'gap', 'left', 'right', 'rows', 'bits', 'dither', 'endian', 'xres', 'yres', 'unit' |
|
5910
|
|
|
|
|
|
|
# parameters: (path_to_file, [row_slice, [column_slice]], [hash]) |
|
5911
|
|
|
|
|
|
|
sub writeTIFF { |
|
5912
|
|
|
|
|
|
|
|
|
5913
|
|
|
|
|
|
|
# local variables |
|
5914
|
0
|
|
|
0
|
1
|
0
|
my ($hash, $trows, $tcols, $n, $fh); |
|
5915
|
0
|
|
|
|
|
0
|
my ($base, $cs, %fields, @alpha, $pi, $rcols, $fmt, $mult, $mab, $samples); |
|
5916
|
0
|
|
|
|
|
0
|
my ($width, $height, $gap, $left, $right, $bits, $xres, $yres, $unit); |
|
5917
|
0
|
|
|
|
|
0
|
my ($le, $short, $long, $fp, $max, $minab, $maxab); |
|
5918
|
0
|
|
|
|
|
0
|
my ($tags, $imagewidth, $bytecount, $stripsize); |
|
5919
|
0
|
|
|
|
|
0
|
my ($ifd, $data, @cmyk, @spot); |
|
5920
|
|
|
|
|
|
|
|
|
5921
|
|
|
|
|
|
|
# get optional hash |
|
5922
|
0
|
0
|
|
|
|
0
|
$hash = pop() if (ref($_[-1]) eq 'HASH'); |
|
5923
|
|
|
|
|
|
|
|
|
5924
|
|
|
|
|
|
|
# get remaining parameters |
|
5925
|
0
|
|
|
|
|
0
|
my ($self, $path, $rows, $cols) = @_; |
|
5926
|
|
|
|
|
|
|
|
|
5927
|
|
|
|
|
|
|
# if row slice defined |
|
5928
|
0
|
0
|
|
|
|
0
|
if (defined($rows)) { |
|
5929
|
|
|
|
|
|
|
|
|
5930
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
5931
|
0
|
0
|
0
|
|
|
0
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5932
|
|
|
|
|
|
|
|
|
5933
|
|
|
|
|
|
|
# use all rows |
|
5934
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5935
|
|
|
|
|
|
|
|
|
5936
|
|
|
|
|
|
|
} else { |
|
5937
|
|
|
|
|
|
|
|
|
5938
|
|
|
|
|
|
|
# get row length if row slice is Math::Matrix object |
|
5939
|
0
|
0
|
|
|
|
0
|
$trows = @{$rows->[0]} if (UNIVERSAL::isa($rows, 'Math::Matrix')); |
|
|
0
|
|
|
|
|
0
|
|
|
5940
|
|
|
|
|
|
|
|
|
5941
|
|
|
|
|
|
|
# flatten row slice |
|
5942
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
5943
|
|
|
|
|
|
|
|
|
5944
|
|
|
|
|
|
|
} |
|
5945
|
|
|
|
|
|
|
|
|
5946
|
|
|
|
|
|
|
} else { |
|
5947
|
|
|
|
|
|
|
|
|
5948
|
|
|
|
|
|
|
# use all rows |
|
5949
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5950
|
|
|
|
|
|
|
|
|
5951
|
|
|
|
|
|
|
} |
|
5952
|
|
|
|
|
|
|
|
|
5953
|
|
|
|
|
|
|
# get number of rows |
|
5954
|
0
|
|
|
|
|
0
|
$n = @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
5955
|
|
|
|
|
|
|
|
|
5956
|
|
|
|
|
|
|
# filter row slice |
|
5957
|
0
|
0
|
0
|
|
|
0
|
@{$rows} = grep {$_ == int($_) && $_ != 0 && defined($self->[1][$_])} @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5958
|
|
|
|
|
|
|
|
|
5959
|
|
|
|
|
|
|
# warn if invalid samples |
|
5960
|
0
|
0
|
|
|
|
0
|
($n == @{$rows}) || warn('row slice contains invalid samples'); |
|
|
0
|
|
|
|
|
0
|
|
|
5961
|
|
|
|
|
|
|
|
|
5962
|
|
|
|
|
|
|
# get target row length, if not defined by row matrix |
|
5963
|
0
|
0
|
|
|
|
0
|
$trows = _getRowLength($self, $hash) if (! defined($trows)); |
|
5964
|
|
|
|
|
|
|
|
|
5965
|
|
|
|
|
|
|
# limit to number of samples |
|
5966
|
0
|
0
|
|
|
|
0
|
$trows = $trows > $n ? $n : $trows; |
|
5967
|
|
|
|
|
|
|
|
|
5968
|
|
|
|
|
|
|
# verify row length |
|
5969
|
0
|
0
|
0
|
|
|
0
|
($trows == int($trows) && $trows > 0) or croak('invalid row length, stopped'); |
|
5970
|
|
|
|
|
|
|
|
|
5971
|
|
|
|
|
|
|
# compute target columns |
|
5972
|
0
|
0
|
|
|
|
0
|
$tcols = int($n/$trows) + ($n % $trows ? 1 : 0); |
|
5973
|
|
|
|
|
|
|
|
|
5974
|
|
|
|
|
|
|
# if column slice defined |
|
5975
|
0
|
0
|
|
|
|
0
|
if (defined($cols)) { |
|
5976
|
|
|
|
|
|
|
|
|
5977
|
|
|
|
|
|
|
# if column slice an empty array reference |
|
5978
|
0
|
0
|
0
|
|
|
0
|
if (ref($cols) eq 'ARRAY' && @{$cols} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
5979
|
|
|
|
|
|
|
|
|
5980
|
|
|
|
|
|
|
# use all columns |
|
5981
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5982
|
|
|
|
|
|
|
|
|
5983
|
|
|
|
|
|
|
} else { |
|
5984
|
|
|
|
|
|
|
|
|
5985
|
|
|
|
|
|
|
# flatten column slice |
|
5986
|
0
|
|
|
|
|
0
|
$cols = ICC::Shared::flatten($cols); |
|
5987
|
|
|
|
|
|
|
|
|
5988
|
|
|
|
|
|
|
} |
|
5989
|
|
|
|
|
|
|
|
|
5990
|
|
|
|
|
|
|
} else { |
|
5991
|
|
|
|
|
|
|
|
|
5992
|
|
|
|
|
|
|
# use all columns |
|
5993
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
5994
|
|
|
|
|
|
|
|
|
5995
|
|
|
|
|
|
|
} |
|
5996
|
|
|
|
|
|
|
|
|
5997
|
|
|
|
|
|
|
# map column slice, converting non-numeric values with 'test' method |
|
5998
|
0
|
0
|
|
|
|
0
|
@{$cols} = map {Scalar::Util::looks_like_number($_) ? $_ : $self->test($_)} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5999
|
|
|
|
|
|
|
|
|
6000
|
|
|
|
|
|
|
# get number of columns |
|
6001
|
0
|
|
|
|
|
0
|
$n = @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
6002
|
|
|
|
|
|
|
|
|
6003
|
|
|
|
|
|
|
# filter column slice |
|
6004
|
0
|
0
|
|
|
|
0
|
@{$cols} = grep {$_ == int($_) && defined($self->[1][0][$_])} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6005
|
|
|
|
|
|
|
|
|
6006
|
|
|
|
|
|
|
# warn if invalid fields |
|
6007
|
0
|
0
|
|
|
|
0
|
($n == @{$cols}) || warn('column slice contains invalid fields'); |
|
|
0
|
|
|
|
|
0
|
|
|
6008
|
|
|
|
|
|
|
|
|
6009
|
|
|
|
|
|
|
# for each column in slice |
|
6010
|
0
|
|
|
|
|
0
|
for (@{$self->[1][0]}[@{$cols}]) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6011
|
|
|
|
|
|
|
|
|
6012
|
|
|
|
|
|
|
# if a supported color space |
|
6013
|
0
|
0
|
|
|
|
0
|
if (m/^((?:.*\|)?(RGB|CMYK|[4-9A-F]CLR|LAB)_)/) { |
|
6014
|
|
|
|
|
|
|
|
|
6015
|
|
|
|
|
|
|
# set base and color space |
|
6016
|
0
|
|
|
|
|
0
|
$base = $1; |
|
6017
|
0
|
|
|
|
|
0
|
$cs = $2; |
|
6018
|
|
|
|
|
|
|
|
|
6019
|
|
|
|
|
|
|
# quit loop |
|
6020
|
0
|
|
|
|
|
0
|
last(); |
|
6021
|
|
|
|
|
|
|
|
|
6022
|
|
|
|
|
|
|
} |
|
6023
|
|
|
|
|
|
|
|
|
6024
|
|
|
|
|
|
|
} |
|
6025
|
|
|
|
|
|
|
|
|
6026
|
|
|
|
|
|
|
# verify color space |
|
6027
|
0
|
0
|
|
|
|
0
|
(defined($cs)) or croak('column slice does not contain a supported color space, stopped'); |
|
6028
|
|
|
|
|
|
|
|
|
6029
|
|
|
|
|
|
|
# get bits per sample and verify |
|
6030
|
0
|
0
|
|
|
|
0
|
$bits = defined($hash->{'bits'}) ? $hash->{'bits'} : 16; |
|
6031
|
0
|
0
|
0
|
|
|
0
|
($bits == 8 || $bits == 16 || $bits == 32) or croak('invalid \'bits\' parameter, stopped'); |
|
|
|
|
0
|
|
|
|
|
|
6032
|
|
|
|
|
|
|
|
|
6033
|
|
|
|
|
|
|
# set little-endian flag from system config |
|
6034
|
0
|
|
|
|
|
0
|
$le = ($Config{'byteorder'} =~ m/1234/); |
|
6035
|
|
|
|
|
|
|
|
|
6036
|
|
|
|
|
|
|
# if endian parameter provided |
|
6037
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'endian'})) { |
|
6038
|
|
|
|
|
|
|
|
|
6039
|
|
|
|
|
|
|
# if little-endian |
|
6040
|
0
|
0
|
|
|
|
0
|
if ($hash->{'endian'} eq 'little') { |
|
|
|
0
|
|
|
|
|
|
|
6041
|
|
|
|
|
|
|
|
|
6042
|
|
|
|
|
|
|
# set flag |
|
6043
|
0
|
|
|
|
|
0
|
$le = 1; |
|
6044
|
|
|
|
|
|
|
|
|
6045
|
|
|
|
|
|
|
# if big-endian |
|
6046
|
|
|
|
|
|
|
} elsif ($hash->{'endian'} eq 'big') { |
|
6047
|
|
|
|
|
|
|
|
|
6048
|
|
|
|
|
|
|
# clear flag |
|
6049
|
0
|
|
|
|
|
0
|
$le = 0; |
|
6050
|
|
|
|
|
|
|
|
|
6051
|
|
|
|
|
|
|
} else { |
|
6052
|
|
|
|
|
|
|
|
|
6053
|
|
|
|
|
|
|
# warn |
|
6054
|
0
|
|
|
|
|
0
|
warn('invalid \'endian\' parameter'); |
|
6055
|
|
|
|
|
|
|
|
|
6056
|
|
|
|
|
|
|
} |
|
6057
|
|
|
|
|
|
|
|
|
6058
|
|
|
|
|
|
|
} |
|
6059
|
|
|
|
|
|
|
|
|
6060
|
|
|
|
|
|
|
# if little-endian |
|
6061
|
0
|
0
|
|
|
|
0
|
if ($le) { |
|
6062
|
|
|
|
|
|
|
|
|
6063
|
|
|
|
|
|
|
# set 'pack' formats |
|
6064
|
0
|
|
|
|
|
0
|
$short = 'v'; |
|
6065
|
0
|
|
|
|
|
0
|
$long = 'V'; |
|
6066
|
0
|
|
|
|
|
0
|
$fp = 'f<'; |
|
6067
|
|
|
|
|
|
|
|
|
6068
|
|
|
|
|
|
|
} else { |
|
6069
|
|
|
|
|
|
|
|
|
6070
|
|
|
|
|
|
|
# set 'pack' formats |
|
6071
|
0
|
|
|
|
|
0
|
$short = 'n'; |
|
6072
|
0
|
|
|
|
|
0
|
$long = 'N'; |
|
6073
|
0
|
|
|
|
|
0
|
$fp = 'f>'; |
|
6074
|
|
|
|
|
|
|
|
|
6075
|
|
|
|
|
|
|
} |
|
6076
|
|
|
|
|
|
|
|
|
6077
|
|
|
|
|
|
|
# make lookup hash of column slice fields |
|
6078
|
0
|
0
|
|
|
|
0
|
%fields = map {defined($self->[1][0][$_]) ? ($self->[1][0][$_], $_) : ()} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6079
|
|
|
|
|
|
|
|
|
6080
|
|
|
|
|
|
|
# if color space is RGB |
|
6081
|
0
|
0
|
0
|
|
|
0
|
if ($cs eq 'RGB') { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6082
|
|
|
|
|
|
|
|
|
6083
|
|
|
|
|
|
|
# set photometric interpretation |
|
6084
|
0
|
|
|
|
|
0
|
$pi = 2; |
|
6085
|
|
|
|
|
|
|
|
|
6086
|
|
|
|
|
|
|
# get alpha channels (if any) |
|
6087
|
0
|
0
|
|
|
|
0
|
@alpha = map {defined($fields{"$base$_"}) ? $fields{"$base$_"} : ()} ('A', 'A0' .. 'A9'); |
|
|
0
|
|
|
|
|
0
|
|
|
6088
|
|
|
|
|
|
|
|
|
6089
|
|
|
|
|
|
|
# get refined column slice (including alpha channels) |
|
6090
|
0
|
|
|
|
|
0
|
$rcols = [(map {$fields{"$base$_"}} qw(R G B)), @alpha]; |
|
|
0
|
|
|
|
|
0
|
|
|
6091
|
|
|
|
|
|
|
|
|
6092
|
|
|
|
|
|
|
# set pack format (8, 16 or 32 bits) |
|
6093
|
0
|
0
|
|
|
|
0
|
$fmt = ($bits == 8) ? 'C*' : ($bits == 16) ? "$short*" : "$fp*"; |
|
|
|
0
|
|
|
|
|
|
|
6094
|
|
|
|
|
|
|
|
|
6095
|
|
|
|
|
|
|
# set multiplier (8, 16 or 32 bits) |
|
6096
|
0
|
0
|
|
|
|
0
|
$mult = ($bits == 8) ? 1 : ($bits == 16) ? 257 : 1/255; |
|
|
|
0
|
|
|
|
|
|
|
6097
|
|
|
|
|
|
|
|
|
6098
|
|
|
|
|
|
|
# if color space is CMYK (8 or 16 bits) |
|
6099
|
|
|
|
|
|
|
} elsif ($cs eq 'CMYK' && $bits != 32) { |
|
6100
|
|
|
|
|
|
|
|
|
6101
|
|
|
|
|
|
|
# set photometric interpretation |
|
6102
|
0
|
|
|
|
|
0
|
$pi = 5; |
|
6103
|
|
|
|
|
|
|
|
|
6104
|
|
|
|
|
|
|
# get refined column slice |
|
6105
|
0
|
|
|
|
|
0
|
$rcols = [map {$fields{"$base$_"}} qw(C M Y K)]; |
|
|
0
|
|
|
|
|
0
|
|
|
6106
|
|
|
|
|
|
|
|
|
6107
|
|
|
|
|
|
|
# set pack format (8 or 16 bits) |
|
6108
|
0
|
0
|
|
|
|
0
|
$fmt = ($bits == 8) ? 'C*' : "$short*"; |
|
6109
|
|
|
|
|
|
|
|
|
6110
|
|
|
|
|
|
|
# set multiplier (8 or 16 bits) |
|
6111
|
0
|
0
|
|
|
|
0
|
$mult = ($bits == 8) ? 2.55 : 655.35; |
|
6112
|
|
|
|
|
|
|
|
|
6113
|
|
|
|
|
|
|
# if color space is nCLR (8 or 16 bits) |
|
6114
|
|
|
|
|
|
|
} elsif ($cs =~ m/^([4-9A-F])CLR$/ && $bits != 32) { |
|
6115
|
|
|
|
|
|
|
|
|
6116
|
|
|
|
|
|
|
# set photometric interpretation |
|
6117
|
0
|
|
|
|
|
0
|
$pi = 5; |
|
6118
|
|
|
|
|
|
|
|
|
6119
|
|
|
|
|
|
|
# get refined column slice |
|
6120
|
0
|
|
|
|
|
0
|
$rcols = [map {$fields{sprintf('%s%x', $base, $_)}} (1 .. CORE::hex($1))]; |
|
|
0
|
|
|
|
|
0
|
|
|
6121
|
|
|
|
|
|
|
|
|
6122
|
|
|
|
|
|
|
# set pack format (8 or 16 bits) |
|
6123
|
0
|
0
|
|
|
|
0
|
$fmt = ($bits == 8) ? 'C*' : "$short*"; |
|
6124
|
|
|
|
|
|
|
|
|
6125
|
|
|
|
|
|
|
# set multiplier (8 or 16 bits) |
|
6126
|
0
|
0
|
|
|
|
0
|
$mult = ($bits == 8) ? 2.55 : 655.35; |
|
6127
|
|
|
|
|
|
|
|
|
6128
|
|
|
|
|
|
|
# if color space if L*a*b* (8 or 16 bits) |
|
6129
|
|
|
|
|
|
|
} elsif ($cs eq 'LAB' && $bits != 32) { |
|
6130
|
|
|
|
|
|
|
|
|
6131
|
|
|
|
|
|
|
# set photometric interpretation |
|
6132
|
0
|
|
|
|
|
0
|
$pi = 8; |
|
6133
|
|
|
|
|
|
|
|
|
6134
|
|
|
|
|
|
|
# get refined column slice |
|
6135
|
0
|
|
|
|
|
0
|
$rcols = [map {$fields{"$base$_"}} qw(L A B)]; |
|
|
0
|
|
|
|
|
0
|
|
|
6136
|
|
|
|
|
|
|
|
|
6137
|
|
|
|
|
|
|
# set pack format (8 or 16 bits) |
|
6138
|
0
|
0
|
|
|
|
0
|
$fmt = ($bits == 8) ? '(Ccc)*' : "$short*"; |
|
6139
|
|
|
|
|
|
|
|
|
6140
|
|
|
|
|
|
|
# set multipliers (8 or 16 bits) |
|
6141
|
0
|
0
|
|
|
|
0
|
$mult = ($bits == 8) ? 2.55 : 655.35; # L* |
|
6142
|
0
|
0
|
|
|
|
0
|
$mab = ($bits == 8) ? 1 : 256; # a* and b* |
|
6143
|
|
|
|
|
|
|
|
|
6144
|
|
|
|
|
|
|
} else { |
|
6145
|
|
|
|
|
|
|
|
|
6146
|
|
|
|
|
|
|
# error |
|
6147
|
0
|
|
|
|
|
0
|
croak('invalid TIFF format'); |
|
6148
|
|
|
|
|
|
|
|
|
6149
|
|
|
|
|
|
|
} |
|
6150
|
|
|
|
|
|
|
|
|
6151
|
|
|
|
|
|
|
# verify all fields defined |
|
6152
|
0
|
0
|
|
|
|
0
|
(@{$rcols} == grep {defined()} @{$rcols}) or croak('column slice has missing fields, stopped'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6153
|
|
|
|
|
|
|
|
|
6154
|
|
|
|
|
|
|
# set number of samples |
|
6155
|
0
|
|
|
|
|
0
|
$samples = @{$rcols}; |
|
|
0
|
|
|
|
|
0
|
|
|
6156
|
|
|
|
|
|
|
|
|
6157
|
|
|
|
|
|
|
# get the sample patch width and verify |
|
6158
|
0
|
0
|
|
|
|
0
|
$width = defined($hash->{'width'}) ? $hash->{'width'} : 1; |
|
6159
|
0
|
0
|
0
|
|
|
0
|
($width == int($width) && $width > 0) or croak('invalid \'width\' parameter, stopped'); |
|
6160
|
|
|
|
|
|
|
|
|
6161
|
|
|
|
|
|
|
# get the sample patch height and verify |
|
6162
|
0
|
0
|
|
|
|
0
|
$height = defined($hash->{'height'}) ? $hash->{'height'} : 1; |
|
6163
|
0
|
0
|
0
|
|
|
0
|
($height == int($height) && $height > 0) or croak('invalid \'height\' parameter, stopped'); |
|
6164
|
|
|
|
|
|
|
|
|
6165
|
|
|
|
|
|
|
# get the sample patch gap and verify |
|
6166
|
0
|
0
|
|
|
|
0
|
$gap = defined($hash->{'gap'}) ? $hash->{'gap'} : 0; |
|
6167
|
0
|
0
|
0
|
|
|
0
|
($gap == int($gap) && $gap >= 0) or croak('invalid \'gap\' parameter, stopped'); |
|
6168
|
|
|
|
|
|
|
|
|
6169
|
|
|
|
|
|
|
# get the left edge width and verify |
|
6170
|
0
|
0
|
|
|
|
0
|
$left = defined($hash->{'left'}) ? $hash->{'left'} : 0; |
|
6171
|
0
|
0
|
0
|
|
|
0
|
($left =~ m/^([0-9]+)(?:\.([0-9]+))?$/ && (! defined($2) || $1 >= $2)) or croak('invalid \'left\' parameter, stopped'); |
|
|
|
|
0
|
|
|
|
|
|
6172
|
0
|
0
|
|
|
|
0
|
$left = [$1, defined($2) ? $2 : 0]; |
|
6173
|
|
|
|
|
|
|
|
|
6174
|
|
|
|
|
|
|
# get the right edge width and verify |
|
6175
|
0
|
0
|
|
|
|
0
|
$right = defined($hash->{'right'}) ? $hash->{'right'} : 0; |
|
6176
|
0
|
0
|
0
|
|
|
0
|
($right =~ m/^([0-9]+)(?:\.([0-9]+))?$/ && (! defined($2) || $1 >= $2)) or croak('invalid \'right\' parameter, stopped'); |
|
|
|
|
0
|
|
|
|
|
|
6177
|
0
|
0
|
|
|
|
0
|
$right = [$1, defined($2) ? $2 : 0]; |
|
6178
|
|
|
|
|
|
|
|
|
6179
|
|
|
|
|
|
|
# get the x-resolution and verify |
|
6180
|
0
|
0
|
|
|
|
0
|
$xres = defined($hash->{'xres'}) ? $hash->{'xres'} : 72; |
|
6181
|
0
|
0
|
0
|
|
|
0
|
($xres > 0 && $xres <= 4E4) or croak('invalid \'xres\' parameter, stopped'); |
|
6182
|
|
|
|
|
|
|
|
|
6183
|
|
|
|
|
|
|
# get the y-resolution and verify |
|
6184
|
0
|
0
|
|
|
|
0
|
$yres = defined($hash->{'yres'}) ? $hash->{'yres'} : 72; |
|
6185
|
0
|
0
|
0
|
|
|
0
|
($yres > 0 && $yres <= 4E4) or croak('invalid \'yres\' parameter, stopped'); |
|
6186
|
|
|
|
|
|
|
|
|
6187
|
|
|
|
|
|
|
# get the resolution unit and verify |
|
6188
|
0
|
0
|
|
|
|
0
|
$unit = defined($hash->{'unit'}) ? $hash->{'unit'} : 2; |
|
6189
|
0
|
0
|
0
|
|
|
0
|
($unit == 1 || $unit == 2 || $unit == 3) or croak('invalid \'unit\' parameter, stopped'); |
|
|
|
|
0
|
|
|
|
|
|
6190
|
|
|
|
|
|
|
|
|
6191
|
|
|
|
|
|
|
# compute image width |
|
6192
|
0
|
|
|
|
|
0
|
$imagewidth = $tcols * $width + ($tcols - 1) * $gap + $left->[0] - $left->[1] + $right->[0] - $right->[1]; |
|
6193
|
|
|
|
|
|
|
|
|
6194
|
|
|
|
|
|
|
# compute strip byte count |
|
6195
|
0
|
|
|
|
|
0
|
$bytecount = $imagewidth * $height * $samples * $bits/8; |
|
6196
|
|
|
|
|
|
|
|
|
6197
|
|
|
|
|
|
|
# compute strip size (strips must begin on word boundary) |
|
6198
|
0
|
|
|
|
|
0
|
$stripsize = $bytecount + $bytecount % 2; |
|
6199
|
|
|
|
|
|
|
|
|
6200
|
|
|
|
|
|
|
# set image tags [type, data] |
|
6201
|
0
|
|
|
|
|
0
|
$tags->{'256'} = [3, $imagewidth]; # ImageWidth |
|
6202
|
0
|
|
|
|
|
0
|
$tags->{'257'} = [3, $trows * $height]; # ImageLength |
|
6203
|
0
|
|
|
|
|
0
|
$tags->{'258'} = [3, ($bits) x $samples]; # BitsPerSample |
|
6204
|
0
|
|
|
|
|
0
|
$tags->{'259'} = [3, 1]; # Compression |
|
6205
|
0
|
|
|
|
|
0
|
$tags->{'262'} = [3, $pi]; # PhotometricInterpretation |
|
6206
|
0
|
|
|
|
|
0
|
$tags->{'273'} = [4, map {$_ * $stripsize + 8} (0 .. $trows - 1)]; # StripOffsets |
|
|
0
|
|
|
|
|
0
|
|
|
6207
|
0
|
|
|
|
|
0
|
$tags->{'277'} = [3, $samples]; # SamplesPerPixel |
|
6208
|
0
|
|
|
|
|
0
|
$tags->{'278'} = [3, $height]; # RowsPerStrip |
|
6209
|
0
|
|
|
|
|
0
|
$tags->{'279'} = [4, ($bytecount) x $trows]; # StripByteCounts |
|
6210
|
0
|
|
|
|
|
0
|
$tags->{'282'} = [5, $xres * 1E4, 1E4]; # XResolution |
|
6211
|
0
|
|
|
|
|
0
|
$tags->{'283'} = [5, $yres * 1E4, 1E4]; # YResolution |
|
6212
|
0
|
|
|
|
|
0
|
$tags->{'296'} = [3, $unit]; # ResolutionUnit |
|
6213
|
0
|
0
|
|
|
|
0
|
$tags->{'339'} = [3, (3) x $samples] if ($bits == 32); # SampleFormat |
|
6214
|
|
|
|
|
|
|
|
|
6215
|
|
|
|
|
|
|
# filter path |
|
6216
|
0
|
|
|
|
|
0
|
ICC::Shared::filterPath($path); |
|
6217
|
|
|
|
|
|
|
|
|
6218
|
|
|
|
|
|
|
# open the file |
|
6219
|
0
|
0
|
|
|
|
0
|
open($fh, '>', $path) or croak("can't open $path: $!"); |
|
6220
|
|
|
|
|
|
|
|
|
6221
|
|
|
|
|
|
|
# set binary mode |
|
6222
|
0
|
|
|
|
|
0
|
binmode($fh); |
|
6223
|
|
|
|
|
|
|
|
|
6224
|
|
|
|
|
|
|
# write TIFF header |
|
6225
|
0
|
0
|
|
|
|
0
|
print $fh pack("A2$short$long", $le ? 'II' : 'MM', 42, $ifd = $trows * $stripsize + 8); |
|
6226
|
|
|
|
|
|
|
|
|
6227
|
|
|
|
|
|
|
# set min/max values |
|
6228
|
0
|
0
|
|
|
|
0
|
$max = ($bits == 8) ? 255 : ($bits == 16) ? 65535 : 1; |
|
|
|
0
|
|
|
|
|
|
|
6229
|
0
|
0
|
|
|
|
0
|
$minab = ($bits == 8) ? -128 : -32768; |
|
6230
|
0
|
0
|
|
|
|
0
|
$maxab = ($bits == 8) ? 127 : 32767; |
|
6231
|
|
|
|
|
|
|
|
|
6232
|
|
|
|
|
|
|
# for each strip |
|
6233
|
0
|
|
|
|
|
0
|
for my $i (0 .. $trows - 1) { |
|
6234
|
|
|
|
|
|
|
|
|
6235
|
|
|
|
|
|
|
# for each patch in strip |
|
6236
|
0
|
|
|
|
|
0
|
for my $j (0 .. $tcols - 1) { |
|
6237
|
|
|
|
|
|
|
|
|
6238
|
|
|
|
|
|
|
# if patch in row slice |
|
6239
|
0
|
0
|
|
|
|
0
|
if (defined($rows->[$trows * $j + $i])) { |
|
6240
|
|
|
|
|
|
|
|
|
6241
|
|
|
|
|
|
|
# if L*a*b* data |
|
6242
|
0
|
0
|
0
|
|
|
0
|
if ($pi == 8) { |
|
|
|
0
|
|
|
|
|
|
|
6243
|
|
|
|
|
|
|
|
|
6244
|
|
|
|
|
|
|
# get the data |
|
6245
|
0
|
|
|
|
|
0
|
$data->[$j][0] = $mult * $self->[1][$rows->[$trows * $j + $i]][$rcols->[0]]; |
|
6246
|
0
|
|
|
|
|
0
|
$data->[$j][1] = $mab * $self->[1][$rows->[$trows * $j + $i]][$rcols->[1]]; |
|
6247
|
0
|
|
|
|
|
0
|
$data->[$j][2] = $mab * $self->[1][$rows->[$trows * $j + $i]][$rcols->[2]]; |
|
6248
|
|
|
|
|
|
|
|
|
6249
|
|
|
|
|
|
|
# limit the data |
|
6250
|
0
|
0
|
|
|
|
0
|
$data->[$j][0] = $data->[$j][0] < 0 ? 0 : ($data->[$j][0] > $max ? $max : $data->[$j][0]); |
|
|
|
0
|
|
|
|
|
|
|
6251
|
0
|
0
|
|
|
|
0
|
$data->[$j][1] = $data->[$j][1] < $minab ? $minab : ($data->[$j][1] > $maxab ? $maxab : $data->[$j][1]); |
|
|
|
0
|
|
|
|
|
|
|
6252
|
0
|
0
|
|
|
|
0
|
$data->[$j][2] = $data->[$j][2] < $minab ? $minab : ($data->[$j][2] > $maxab ? $maxab : $data->[$j][2]); |
|
|
|
0
|
|
|
|
|
|
|
6253
|
|
|
|
|
|
|
|
|
6254
|
|
|
|
|
|
|
# if CMYK + spot data |
|
6255
|
0
|
|
|
|
|
0
|
} elsif ($pi == 5 && @{$rcols} > 4) { |
|
6256
|
|
|
|
|
|
|
|
|
6257
|
|
|
|
|
|
|
# get CMYK values |
|
6258
|
0
|
|
|
|
|
0
|
@cmyk = @{$self->[1][$rows->[$trows * $j + $i]]}[@{$rcols}[0 .. 3]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6259
|
|
|
|
|
|
|
|
|
6260
|
|
|
|
|
|
|
# get spot values |
|
6261
|
0
|
|
|
|
|
0
|
@spot = @{$self->[1][$rows->[$trows * $j + $i]]}[@{$rcols}[4 .. $#{$rcols}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6262
|
|
|
|
|
|
|
|
|
6263
|
|
|
|
|
|
|
# get the data (spot channels are inverted) |
|
6264
|
0
|
|
|
|
|
0
|
$data->[$j] = [(map {$_ * $mult} @cmyk), (map {(100 - $_) * $mult} @spot)]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6265
|
|
|
|
|
|
|
|
|
6266
|
|
|
|
|
|
|
# limit the data |
|
6267
|
0
|
0
|
|
|
|
0
|
@{$data->[$j]} = map {$_ < 0 ? 0 : ($_ > $max ? $max : $_)} @{$data->[$j]}; |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6268
|
|
|
|
|
|
|
|
|
6269
|
|
|
|
|
|
|
# RGB data |
|
6270
|
|
|
|
|
|
|
} else { |
|
6271
|
|
|
|
|
|
|
|
|
6272
|
|
|
|
|
|
|
# get the data |
|
6273
|
0
|
|
|
|
|
0
|
$data->[$j] = [map {$_ * $mult} @{$self->[1][$rows->[$trows * $j + $i]]}[@{$rcols}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6274
|
|
|
|
|
|
|
|
|
6275
|
|
|
|
|
|
|
# limit the data (8 or 16 bits) |
|
6276
|
0
|
0
|
|
|
|
0
|
@{$data->[$j]} = map {$_ < 0 ? 0 : ($_ > $max ? $max : $_)} @{$data->[$j]} if ($bits != 32); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6277
|
|
|
|
|
|
|
|
|
6278
|
|
|
|
|
|
|
} |
|
6279
|
|
|
|
|
|
|
|
|
6280
|
|
|
|
|
|
|
# patch undefined |
|
6281
|
|
|
|
|
|
|
} else { |
|
6282
|
|
|
|
|
|
|
|
|
6283
|
|
|
|
|
|
|
# if L*a*b* data |
|
6284
|
0
|
0
|
|
|
|
0
|
if ($pi == 8) { |
|
|
|
0
|
|
|
|
|
|
|
6285
|
|
|
|
|
|
|
|
|
6286
|
|
|
|
|
|
|
# if last patch |
|
6287
|
0
|
0
|
0
|
|
|
0
|
if ($i == ($trows - 1) && $j == ($tcols - 1)) { |
|
6288
|
|
|
|
|
|
|
|
|
6289
|
|
|
|
|
|
|
# set gray value |
|
6290
|
0
|
|
|
|
|
0
|
$data->[$j] = [$max * 0.7, 0, 0]; |
|
6291
|
|
|
|
|
|
|
|
|
6292
|
|
|
|
|
|
|
} else { |
|
6293
|
|
|
|
|
|
|
|
|
6294
|
|
|
|
|
|
|
# set white value |
|
6295
|
0
|
|
|
|
|
0
|
$data->[$j] = [$max, 0, 0]; |
|
6296
|
|
|
|
|
|
|
|
|
6297
|
|
|
|
|
|
|
} |
|
6298
|
|
|
|
|
|
|
|
|
6299
|
|
|
|
|
|
|
# if CMYK + spot data |
|
6300
|
|
|
|
|
|
|
} elsif ($pi == 5) { |
|
6301
|
|
|
|
|
|
|
|
|
6302
|
|
|
|
|
|
|
# if last patch |
|
6303
|
0
|
0
|
0
|
|
|
0
|
if ($i == ($trows - 1) && $j == ($tcols - 1)) { |
|
6304
|
|
|
|
|
|
|
|
|
6305
|
|
|
|
|
|
|
# set gray value |
|
6306
|
0
|
|
|
|
|
0
|
$data->[$j] = [0, 0, 0, $max * 0.4, ($max) x ($samples - 4)]; |
|
6307
|
|
|
|
|
|
|
|
|
6308
|
|
|
|
|
|
|
} else { |
|
6309
|
|
|
|
|
|
|
|
|
6310
|
|
|
|
|
|
|
# set white value |
|
6311
|
0
|
|
|
|
|
0
|
$data->[$j] = [0, 0, 0, 0, ($max) x ($samples - 4)]; |
|
6312
|
|
|
|
|
|
|
|
|
6313
|
|
|
|
|
|
|
} |
|
6314
|
|
|
|
|
|
|
|
|
6315
|
|
|
|
|
|
|
# RGB data |
|
6316
|
|
|
|
|
|
|
} else { |
|
6317
|
|
|
|
|
|
|
|
|
6318
|
|
|
|
|
|
|
# if last patch |
|
6319
|
0
|
0
|
0
|
|
|
0
|
if ($i == ($trows - 1) && $j == ($tcols - 1)) { |
|
6320
|
|
|
|
|
|
|
|
|
6321
|
|
|
|
|
|
|
# set gray value |
|
6322
|
0
|
|
|
|
|
0
|
$data->[$j] = [($max * 0.7) x $samples]; |
|
6323
|
|
|
|
|
|
|
|
|
6324
|
|
|
|
|
|
|
} else { |
|
6325
|
|
|
|
|
|
|
|
|
6326
|
|
|
|
|
|
|
# set white value |
|
6327
|
0
|
|
|
|
|
0
|
$data->[$j] = [($max) x $samples]; |
|
6328
|
|
|
|
|
|
|
|
|
6329
|
|
|
|
|
|
|
} |
|
6330
|
|
|
|
|
|
|
|
|
6331
|
|
|
|
|
|
|
} |
|
6332
|
|
|
|
|
|
|
|
|
6333
|
|
|
|
|
|
|
} |
|
6334
|
|
|
|
|
|
|
|
|
6335
|
|
|
|
|
|
|
} |
|
6336
|
|
|
|
|
|
|
|
|
6337
|
|
|
|
|
|
|
# write TIFF strip |
|
6338
|
0
|
|
|
|
|
0
|
_writeTIFFstrip($fh, $tags, $width, $gap, $left, $right, $i, $data, $fmt, $hash->{'dither'}); |
|
6339
|
|
|
|
|
|
|
|
|
6340
|
|
|
|
|
|
|
} |
|
6341
|
|
|
|
|
|
|
|
|
6342
|
|
|
|
|
|
|
# write TIFF IFD |
|
6343
|
0
|
|
|
|
|
0
|
_writeTIFFdir($fh, $ifd, $short, $long, $tags); |
|
6344
|
|
|
|
|
|
|
|
|
6345
|
|
|
|
|
|
|
# close file |
|
6346
|
0
|
|
|
|
|
0
|
close($fh); |
|
6347
|
|
|
|
|
|
|
|
|
6348
|
|
|
|
|
|
|
} |
|
6349
|
|
|
|
|
|
|
|
|
6350
|
|
|
|
|
|
|
# write chart to Adobe Swatch Exchange (.ase) file |
|
6351
|
|
|
|
|
|
|
# column slice must be CMYK, RGB or L*a*b* |
|
6352
|
|
|
|
|
|
|
# color type: 0 - global, 1 - spot, 2 - normal (default) |
|
6353
|
|
|
|
|
|
|
# parameters: (path_to_file, row_slice, column_slice, [color_type]) |
|
6354
|
|
|
|
|
|
|
sub writeASE { |
|
6355
|
|
|
|
|
|
|
|
|
6356
|
|
|
|
|
|
|
# get parameters |
|
6357
|
0
|
|
|
0
|
1
|
0
|
my ($self, $path, $rows, $cols, $type) = @_; |
|
6358
|
|
|
|
|
|
|
|
|
6359
|
|
|
|
|
|
|
# local variables |
|
6360
|
0
|
|
|
|
|
0
|
my ($n, @fmt, $cs, $le, $sn, $fh); |
|
6361
|
0
|
|
|
|
|
0
|
my ($name, $slen, $blen); |
|
6362
|
0
|
|
|
|
|
0
|
my ($cmyk, $rgb, $Lab, $val); |
|
6363
|
|
|
|
|
|
|
|
|
6364
|
|
|
|
|
|
|
# verify row_slice and column_slice are supplied |
|
6365
|
0
|
0
|
0
|
|
|
0
|
(defined($rows) && defined($cols)) or croak('missing parameters'); |
|
6366
|
|
|
|
|
|
|
|
|
6367
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
6368
|
0
|
0
|
0
|
|
|
0
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
6369
|
|
|
|
|
|
|
|
|
6370
|
|
|
|
|
|
|
# use all rows |
|
6371
|
0
|
|
|
|
|
0
|
$rows = [1 .. $#{$self->[1]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
6372
|
|
|
|
|
|
|
|
|
6373
|
|
|
|
|
|
|
} else { |
|
6374
|
|
|
|
|
|
|
|
|
6375
|
|
|
|
|
|
|
# flatten row slice |
|
6376
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($rows); |
|
6377
|
|
|
|
|
|
|
|
|
6378
|
|
|
|
|
|
|
} |
|
6379
|
|
|
|
|
|
|
|
|
6380
|
|
|
|
|
|
|
# get number of rows |
|
6381
|
0
|
|
|
|
|
0
|
$n = @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
6382
|
|
|
|
|
|
|
|
|
6383
|
|
|
|
|
|
|
# filter row slice |
|
6384
|
0
|
0
|
0
|
|
|
0
|
@{$rows} = grep {$_ == int($_) && $_ != 0 && defined($self->[1][$_])} @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6385
|
|
|
|
|
|
|
|
|
6386
|
|
|
|
|
|
|
# warn if invalid samples |
|
6387
|
0
|
0
|
|
|
|
0
|
($n == @{$rows}) || warn('row slice contains invalid samples'); |
|
|
0
|
|
|
|
|
0
|
|
|
6388
|
|
|
|
|
|
|
|
|
6389
|
|
|
|
|
|
|
# map column slice, converting non-numeric values with 'test' method |
|
6390
|
0
|
0
|
|
|
|
0
|
@{$cols} = map {Scalar::Util::looks_like_number($_) ? $_ : $self->test($_)} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6391
|
|
|
|
|
|
|
|
|
6392
|
|
|
|
|
|
|
# get format array |
|
6393
|
0
|
|
|
|
|
0
|
@fmt = @{$self->[1][0]}[@{$cols}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6394
|
|
|
|
|
|
|
|
|
6395
|
|
|
|
|
|
|
# if column slice is CMYK |
|
6396
|
0
|
0
|
0
|
|
|
0
|
if (4 == @fmt && 4 == grep {m/^(?:.*\|)?CMYK_[CMYK]$/} @fmt) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
|
0
|
0
|
|
|
|
|
|
6397
|
|
|
|
|
|
|
|
|
6398
|
|
|
|
|
|
|
# set color space |
|
6399
|
0
|
|
|
|
|
0
|
$cs = 'CMYK'; |
|
6400
|
|
|
|
|
|
|
|
|
6401
|
|
|
|
|
|
|
# if column slice is RGB |
|
6402
|
0
|
|
|
|
|
0
|
} elsif (3 == @fmt && 3 == grep {m/^(?:.*\|)?RGB_[RGB]$/} @fmt) { |
|
6403
|
|
|
|
|
|
|
|
|
6404
|
|
|
|
|
|
|
# set color space |
|
6405
|
0
|
|
|
|
|
0
|
$cs = 'RGB '; |
|
6406
|
|
|
|
|
|
|
|
|
6407
|
|
|
|
|
|
|
# if column slice is L*a*b* |
|
6408
|
0
|
|
|
|
|
0
|
} elsif (3 == @fmt && 3 == grep {m/^(?:.*\|)?LAB_[LAB]$/} @fmt) { |
|
6409
|
|
|
|
|
|
|
|
|
6410
|
|
|
|
|
|
|
# set color space |
|
6411
|
0
|
|
|
|
|
0
|
$cs = 'LAB '; |
|
6412
|
|
|
|
|
|
|
|
|
6413
|
|
|
|
|
|
|
} else { |
|
6414
|
|
|
|
|
|
|
|
|
6415
|
|
|
|
|
|
|
# error |
|
6416
|
0
|
|
|
|
|
0
|
croak('invalid column slice'); |
|
6417
|
|
|
|
|
|
|
|
|
6418
|
|
|
|
|
|
|
} |
|
6419
|
|
|
|
|
|
|
|
|
6420
|
|
|
|
|
|
|
# if color type is undefined, set default (2 - normal) |
|
6421
|
0
|
0
|
|
|
|
0
|
$type = 2 if (! defined($type)); |
|
6422
|
|
|
|
|
|
|
|
|
6423
|
|
|
|
|
|
|
# verify color type |
|
6424
|
0
|
0
|
0
|
|
|
0
|
($type == int($type) && $type >= 0 && $type <= 2) or croak('invalid ASE color type'); |
|
|
|
|
0
|
|
|
|
|
|
6425
|
|
|
|
|
|
|
|
|
6426
|
|
|
|
|
|
|
# get little-endian flag |
|
6427
|
0
|
|
|
|
|
0
|
$le = ($Config{'byteorder'} =~ m/1234/); |
|
6428
|
|
|
|
|
|
|
|
|
6429
|
|
|
|
|
|
|
# get sample name slice (could be undefined) |
|
6430
|
0
|
|
|
|
|
0
|
$sn = $self->name; |
|
6431
|
|
|
|
|
|
|
|
|
6432
|
|
|
|
|
|
|
# filter path |
|
6433
|
0
|
|
|
|
|
0
|
ICC::Shared::filterPath($path); |
|
6434
|
|
|
|
|
|
|
|
|
6435
|
|
|
|
|
|
|
# open the file |
|
6436
|
0
|
0
|
|
|
|
0
|
open($fh, '>', $path) or croak("can't open $path: $!"); |
|
6437
|
|
|
|
|
|
|
|
|
6438
|
|
|
|
|
|
|
# set binary mode |
|
6439
|
0
|
|
|
|
|
0
|
binmode($fh); |
|
6440
|
|
|
|
|
|
|
|
|
6441
|
|
|
|
|
|
|
# print header (file signature, version, number of blocks) |
|
6442
|
0
|
|
|
|
|
0
|
print $fh pack('A4nnN', 'ASEF', 1, 0, scalar(@{$rows})); |
|
|
0
|
|
|
|
|
0
|
|
|
6443
|
|
|
|
|
|
|
|
|
6444
|
|
|
|
|
|
|
# for each sample |
|
6445
|
0
|
|
|
|
|
0
|
for my $s (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6446
|
|
|
|
|
|
|
|
|
6447
|
|
|
|
|
|
|
# if color space is CMYK |
|
6448
|
0
|
0
|
|
|
|
0
|
if ($cs eq 'CMYK') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6449
|
|
|
|
|
|
|
|
|
6450
|
|
|
|
|
|
|
# get the CMYK values |
|
6451
|
0
|
|
|
|
|
0
|
$cmyk = $self->slice([$s], $cols); |
|
6452
|
|
|
|
|
|
|
|
|
6453
|
|
|
|
|
|
|
# if SAMPLE_NAME is defined |
|
6454
|
0
|
0
|
|
|
|
0
|
if (defined($sn)) { |
|
6455
|
|
|
|
|
|
|
|
|
6456
|
|
|
|
|
|
|
# get color name |
|
6457
|
0
|
|
|
|
|
0
|
$name = $self->[1][$s][$sn->[0]]; |
|
6458
|
|
|
|
|
|
|
|
|
6459
|
|
|
|
|
|
|
# replace underscores with spaces |
|
6460
|
0
|
|
|
|
|
0
|
$name =~ s/_/ /g; |
|
6461
|
|
|
|
|
|
|
|
|
6462
|
|
|
|
|
|
|
} else { |
|
6463
|
|
|
|
|
|
|
|
|
6464
|
|
|
|
|
|
|
# build color name from CMYK values |
|
6465
|
0
|
|
|
|
|
0
|
$name = sprintf('C=%d M=%d Y=%d K=%d', @{$cmyk->[0]}); |
|
|
0
|
|
|
|
|
0
|
|
|
6466
|
|
|
|
|
|
|
|
|
6467
|
|
|
|
|
|
|
} |
|
6468
|
|
|
|
|
|
|
|
|
6469
|
|
|
|
|
|
|
# compute string length |
|
6470
|
0
|
|
|
|
|
0
|
$slen = length($name) + 1; |
|
6471
|
|
|
|
|
|
|
|
|
6472
|
|
|
|
|
|
|
# compute block length |
|
6473
|
0
|
|
|
|
|
0
|
$blen = 2 * $slen + 24; |
|
6474
|
|
|
|
|
|
|
|
|
6475
|
|
|
|
|
|
|
# print block |
|
6476
|
0
|
|
|
|
|
0
|
print $fh pack('nNn', 1, $blen, $slen); |
|
6477
|
0
|
|
|
|
|
0
|
print $fh encode('UTF-16BE', $name . "\x00"); |
|
6478
|
0
|
|
|
|
|
0
|
print $fh pack('A4', 'CMYK'); |
|
6479
|
|
|
|
|
|
|
|
|
6480
|
|
|
|
|
|
|
# for each CMYK value |
|
6481
|
0
|
|
|
|
|
0
|
for my $i (0 .. 3) { |
|
6482
|
|
|
|
|
|
|
|
|
6483
|
|
|
|
|
|
|
# convert to floating point |
|
6484
|
0
|
|
|
|
|
0
|
$val = pack('f', $cmyk->[0][$i]/100); |
|
6485
|
|
|
|
|
|
|
|
|
6486
|
|
|
|
|
|
|
# reverse if little-endian system |
|
6487
|
0
|
0
|
|
|
|
0
|
$val = reverse($val) if ($le); |
|
6488
|
|
|
|
|
|
|
|
|
6489
|
|
|
|
|
|
|
# print value |
|
6490
|
0
|
|
|
|
|
0
|
print $fh $val; |
|
6491
|
|
|
|
|
|
|
|
|
6492
|
|
|
|
|
|
|
} |
|
6493
|
|
|
|
|
|
|
|
|
6494
|
|
|
|
|
|
|
# print color type |
|
6495
|
0
|
|
|
|
|
0
|
print $fh pack('n', $type); |
|
6496
|
|
|
|
|
|
|
|
|
6497
|
|
|
|
|
|
|
# if color space is RGB |
|
6498
|
|
|
|
|
|
|
} elsif ($cs eq 'RGB ') { |
|
6499
|
|
|
|
|
|
|
|
|
6500
|
|
|
|
|
|
|
# get the RGB values |
|
6501
|
0
|
|
|
|
|
0
|
$rgb = $self->slice([$s], $cols); |
|
6502
|
|
|
|
|
|
|
|
|
6503
|
|
|
|
|
|
|
# if SAMPLE_NAME is defined |
|
6504
|
0
|
0
|
|
|
|
0
|
if (defined($sn)) { |
|
6505
|
|
|
|
|
|
|
|
|
6506
|
|
|
|
|
|
|
# get color name |
|
6507
|
0
|
|
|
|
|
0
|
$name = $self->[1][$s][$sn->[0]]; |
|
6508
|
|
|
|
|
|
|
|
|
6509
|
|
|
|
|
|
|
# replace underscores with spaces |
|
6510
|
0
|
|
|
|
|
0
|
$name =~ s/_/ /g; |
|
6511
|
|
|
|
|
|
|
|
|
6512
|
|
|
|
|
|
|
} else { |
|
6513
|
|
|
|
|
|
|
|
|
6514
|
|
|
|
|
|
|
# build color name from RGB values |
|
6515
|
0
|
|
|
|
|
0
|
$name = sprintf('R=%d G=%d B=%d', @{$rgb->[0]}); |
|
|
0
|
|
|
|
|
0
|
|
|
6516
|
|
|
|
|
|
|
|
|
6517
|
|
|
|
|
|
|
} |
|
6518
|
|
|
|
|
|
|
|
|
6519
|
|
|
|
|
|
|
# compute string length |
|
6520
|
0
|
|
|
|
|
0
|
$slen = length($name) + 1; |
|
6521
|
|
|
|
|
|
|
|
|
6522
|
|
|
|
|
|
|
# compute block length |
|
6523
|
0
|
|
|
|
|
0
|
$blen = 2 * $slen + 20; |
|
6524
|
|
|
|
|
|
|
|
|
6525
|
|
|
|
|
|
|
# print block |
|
6526
|
0
|
|
|
|
|
0
|
print $fh pack('nNn', 1, $blen, $slen); |
|
6527
|
0
|
|
|
|
|
0
|
print $fh encode('UTF-16BE', $name . "\x00"); |
|
6528
|
0
|
|
|
|
|
0
|
print $fh pack('A4', 'RGB '); |
|
6529
|
|
|
|
|
|
|
|
|
6530
|
|
|
|
|
|
|
# for each RGB value |
|
6531
|
0
|
|
|
|
|
0
|
for my $i (0 .. 2) { |
|
6532
|
|
|
|
|
|
|
|
|
6533
|
|
|
|
|
|
|
# convert to floating point |
|
6534
|
0
|
|
|
|
|
0
|
$val = pack('f', $rgb->[0][$i]/255); |
|
6535
|
|
|
|
|
|
|
|
|
6536
|
|
|
|
|
|
|
# reverse if little-endian system |
|
6537
|
0
|
0
|
|
|
|
0
|
$val = reverse($val) if ($le); |
|
6538
|
|
|
|
|
|
|
|
|
6539
|
|
|
|
|
|
|
# print value |
|
6540
|
0
|
|
|
|
|
0
|
print $fh $val; |
|
6541
|
|
|
|
|
|
|
|
|
6542
|
|
|
|
|
|
|
} |
|
6543
|
|
|
|
|
|
|
|
|
6544
|
|
|
|
|
|
|
# print color type |
|
6545
|
0
|
|
|
|
|
0
|
print $fh pack('n', $type); |
|
6546
|
|
|
|
|
|
|
|
|
6547
|
|
|
|
|
|
|
# if color space is L*a*b* |
|
6548
|
|
|
|
|
|
|
} elsif ($cs eq 'LAB ') { |
|
6549
|
|
|
|
|
|
|
|
|
6550
|
|
|
|
|
|
|
# get the L*a*b* values |
|
6551
|
0
|
|
|
|
|
0
|
$Lab = $self->slice([$s], $cols); |
|
6552
|
|
|
|
|
|
|
|
|
6553
|
|
|
|
|
|
|
# if SAMPLE_NAME is defined |
|
6554
|
0
|
0
|
|
|
|
0
|
if (defined($sn)) { |
|
6555
|
|
|
|
|
|
|
|
|
6556
|
|
|
|
|
|
|
# get color name |
|
6557
|
0
|
|
|
|
|
0
|
$name = $self->[1][$s][$sn->[0]]; |
|
6558
|
|
|
|
|
|
|
|
|
6559
|
|
|
|
|
|
|
# replace underscores with spaces |
|
6560
|
0
|
|
|
|
|
0
|
$name =~ s/_/ /g; |
|
6561
|
|
|
|
|
|
|
|
|
6562
|
|
|
|
|
|
|
} else { |
|
6563
|
|
|
|
|
|
|
|
|
6564
|
|
|
|
|
|
|
# build color name from L*a*b* values |
|
6565
|
0
|
|
|
|
|
0
|
$name = sprintf('L=%d a=%d b=%d', @{$Lab->[0]}); |
|
|
0
|
|
|
|
|
0
|
|
|
6566
|
|
|
|
|
|
|
|
|
6567
|
|
|
|
|
|
|
} |
|
6568
|
|
|
|
|
|
|
|
|
6569
|
|
|
|
|
|
|
# compute string length |
|
6570
|
0
|
|
|
|
|
0
|
$slen = length($name) + 1; |
|
6571
|
|
|
|
|
|
|
|
|
6572
|
|
|
|
|
|
|
# compute block length |
|
6573
|
0
|
|
|
|
|
0
|
$blen = 2 * $slen + 20; |
|
6574
|
|
|
|
|
|
|
|
|
6575
|
|
|
|
|
|
|
# print block |
|
6576
|
0
|
|
|
|
|
0
|
print $fh pack('nNn', 1, $blen, $slen); |
|
6577
|
0
|
|
|
|
|
0
|
print $fh encode('UTF-16BE', $name . "\x00"); |
|
6578
|
0
|
|
|
|
|
0
|
print $fh pack('A4', 'LAB '); |
|
6579
|
|
|
|
|
|
|
|
|
6580
|
|
|
|
|
|
|
# modify L* value |
|
6581
|
0
|
|
|
|
|
0
|
$Lab->[0][0] /= 100; |
|
6582
|
|
|
|
|
|
|
|
|
6583
|
|
|
|
|
|
|
# for each L*a*b* value |
|
6584
|
0
|
|
|
|
|
0
|
for my $i (0 .. 2) { |
|
6585
|
|
|
|
|
|
|
|
|
6586
|
|
|
|
|
|
|
# convert to floating point |
|
6587
|
0
|
|
|
|
|
0
|
$val = pack('f', $Lab->[0][$i]); |
|
6588
|
|
|
|
|
|
|
|
|
6589
|
|
|
|
|
|
|
# reverse if little-endian system |
|
6590
|
0
|
0
|
|
|
|
0
|
$val = reverse($val) if ($le); |
|
6591
|
|
|
|
|
|
|
|
|
6592
|
|
|
|
|
|
|
# print value |
|
6593
|
0
|
|
|
|
|
0
|
print $fh $val; |
|
6594
|
|
|
|
|
|
|
|
|
6595
|
|
|
|
|
|
|
} |
|
6596
|
|
|
|
|
|
|
|
|
6597
|
|
|
|
|
|
|
# print color type |
|
6598
|
0
|
|
|
|
|
0
|
print $fh pack('n', $type); |
|
6599
|
|
|
|
|
|
|
|
|
6600
|
|
|
|
|
|
|
} |
|
6601
|
|
|
|
|
|
|
|
|
6602
|
|
|
|
|
|
|
} |
|
6603
|
|
|
|
|
|
|
|
|
6604
|
|
|
|
|
|
|
# close file |
|
6605
|
0
|
|
|
|
|
0
|
close($fh); |
|
6606
|
|
|
|
|
|
|
|
|
6607
|
|
|
|
|
|
|
} |
|
6608
|
|
|
|
|
|
|
|
|
6609
|
|
|
|
|
|
|
# print object contents to string |
|
6610
|
|
|
|
|
|
|
# format is an array structure |
|
6611
|
|
|
|
|
|
|
# parameter: ([format]) |
|
6612
|
|
|
|
|
|
|
# returns: (string) |
|
6613
|
|
|
|
|
|
|
sub sdump { |
|
6614
|
|
|
|
|
|
|
|
|
6615
|
|
|
|
|
|
|
# get parameters |
|
6616
|
0
|
|
|
0
|
1
|
0
|
my ($self, $p) = @_; |
|
6617
|
|
|
|
|
|
|
|
|
6618
|
|
|
|
|
|
|
# local variables |
|
6619
|
0
|
|
|
|
|
0
|
my ($s, $fmt); |
|
6620
|
|
|
|
|
|
|
|
|
6621
|
|
|
|
|
|
|
# resolve parameter to an array reference |
|
6622
|
0
|
0
|
|
|
|
0
|
$p = defined($p) ? ref($p) eq 'ARRAY' ? $p : [$p] : []; |
|
|
|
0
|
|
|
|
|
|
|
6623
|
|
|
|
|
|
|
|
|
6624
|
|
|
|
|
|
|
# get format string |
|
6625
|
0
|
0
|
0
|
|
|
0
|
$fmt = defined($p->[0]) && ! ref($p->[0]) ? $p->[0] : 'undef'; |
|
6626
|
|
|
|
|
|
|
|
|
6627
|
|
|
|
|
|
|
# set string to object ID |
|
6628
|
0
|
|
|
|
|
0
|
$s = sprintf("'%s' object, (0x%x)\n", ref($self), $self); |
|
6629
|
|
|
|
|
|
|
|
|
6630
|
|
|
|
|
|
|
# return |
|
6631
|
0
|
|
|
|
|
0
|
return($s); |
|
6632
|
|
|
|
|
|
|
|
|
6633
|
|
|
|
|
|
|
} |
|
6634
|
|
|
|
|
|
|
|
|
6635
|
|
|
|
|
|
|
# get column slice from DATA_FORMAT keys |
|
6636
|
|
|
|
|
|
|
# format_keys is a list of keys with optional context |
|
6637
|
|
|
|
|
|
|
# column_slice is reference to an array of column indices |
|
6638
|
|
|
|
|
|
|
# note: returns 'undef' if any column is missing |
|
6639
|
|
|
|
|
|
|
# parameters: (format_keys) |
|
6640
|
|
|
|
|
|
|
# returns: (column_slice) |
|
6641
|
|
|
|
|
|
|
sub _cols { |
|
6642
|
|
|
|
|
|
|
|
|
6643
|
|
|
|
|
|
|
# get object reference |
|
6644
|
0
|
|
|
0
|
|
0
|
my $self = shift(); |
|
6645
|
|
|
|
|
|
|
|
|
6646
|
|
|
|
|
|
|
# local variables |
|
6647
|
0
|
|
|
|
|
0
|
my (%fmt, @cols); |
|
6648
|
|
|
|
|
|
|
|
|
6649
|
|
|
|
|
|
|
# make lookup hash of DATA_FORMAT keys |
|
6650
|
0
|
0
|
|
|
|
0
|
%fmt = map {defined($self->[1][0][$_]) ? ($self->[1][0][$_], $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6651
|
|
|
|
|
|
|
|
|
6652
|
|
|
|
|
|
|
# lookup format keys in hash |
|
6653
|
0
|
|
|
|
|
0
|
@cols = @fmt{@_}; |
|
6654
|
|
|
|
|
|
|
|
|
6655
|
|
|
|
|
|
|
# return column slice or undef if any columns undefined |
|
6656
|
0
|
0
|
|
|
|
0
|
return((grep {! defined()} @cols) ? undef : \@cols); |
|
|
0
|
|
|
|
|
0
|
|
|
6657
|
|
|
|
|
|
|
|
|
6658
|
|
|
|
|
|
|
} |
|
6659
|
|
|
|
|
|
|
|
|
6660
|
|
|
|
|
|
|
# get spectral fields array |
|
6661
|
|
|
|
|
|
|
# array contains column indices and wavelength |
|
6662
|
|
|
|
|
|
|
# and is sorted by wavelength (low to high) |
|
6663
|
|
|
|
|
|
|
# parameters: (object_reference, [context]) |
|
6664
|
|
|
|
|
|
|
# returns: (array_reference) |
|
6665
|
|
|
|
|
|
|
sub _spectral { |
|
6666
|
|
|
|
|
|
|
|
|
6667
|
|
|
|
|
|
|
# get parameters |
|
6668
|
45
|
|
|
45
|
|
100
|
my ($self, $context) = @_; |
|
6669
|
|
|
|
|
|
|
|
|
6670
|
|
|
|
|
|
|
# local variables |
|
6671
|
45
|
|
|
|
|
58
|
my (%fmt, @fields); |
|
6672
|
|
|
|
|
|
|
|
|
6673
|
|
|
|
|
|
|
# make lookup hash (context|wavelength -or- wavelength => column) |
|
6674
|
45
|
100
|
|
|
|
56
|
%fmt = map {($self->[1][0][$_] =~ m/^(.*\|)?(?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)(\d{3})$/) ? (defined($1) ? "$1$2" : $2, $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
1679
|
100
|
|
|
|
6406
|
|
|
|
45
|
|
|
|
|
111
|
|
|
6675
|
|
|
|
|
|
|
|
|
6676
|
|
|
|
|
|
|
# if context defined |
|
6677
|
45
|
100
|
|
|
|
187
|
if (defined($context)) { |
|
6678
|
|
|
|
|
|
|
|
|
6679
|
|
|
|
|
|
|
# make list of matching fields |
|
6680
|
18
|
100
|
|
|
|
107
|
@fields = map {m/^$context\|(\d{3})$/ ? [$fmt{$_}, $1] : ()} keys(%fmt); |
|
|
540
|
|
|
|
|
1991
|
|
|
6681
|
|
|
|
|
|
|
|
|
6682
|
|
|
|
|
|
|
} else { |
|
6683
|
|
|
|
|
|
|
|
|
6684
|
|
|
|
|
|
|
# make list of matching fields |
|
6685
|
27
|
100
|
|
|
|
139
|
@fields = map {m/^(\d{3})$/ ? [$fmt{$_}, $1] : ()} keys(%fmt); |
|
|
900
|
|
|
|
|
1851
|
|
|
6686
|
|
|
|
|
|
|
|
|
6687
|
|
|
|
|
|
|
# if no matching fields |
|
6688
|
27
|
100
|
|
|
|
104
|
if (@fields == 0) { |
|
6689
|
|
|
|
|
|
|
|
|
6690
|
|
|
|
|
|
|
# make lookup hash (wavelength => column) |
|
6691
|
14
|
100
|
|
|
|
19
|
%fmt = map {($self->[1][0][$_] =~ m/^(?:.*\|)?(?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)(\d{3})$/) ? ($1, $_) : ()} (0 .. $#{$self->[1][0]}); |
|
|
503
|
|
|
|
|
1631
|
|
|
|
14
|
|
|
|
|
33
|
|
|
6692
|
|
|
|
|
|
|
|
|
6693
|
|
|
|
|
|
|
# make list of fields |
|
6694
|
14
|
|
|
|
|
93
|
@fields = map {[$fmt{$_}, $_]} keys(%fmt); |
|
|
432
|
|
|
|
|
631
|
|
|
6695
|
|
|
|
|
|
|
|
|
6696
|
|
|
|
|
|
|
} |
|
6697
|
|
|
|
|
|
|
|
|
6698
|
|
|
|
|
|
|
} |
|
6699
|
|
|
|
|
|
|
|
|
6700
|
|
|
|
|
|
|
# return undef if no match |
|
6701
|
45
|
100
|
|
|
|
152
|
return() if (@fields == 0); |
|
6702
|
|
|
|
|
|
|
|
|
6703
|
|
|
|
|
|
|
# sort by wavelength |
|
6704
|
37
|
|
|
|
|
126
|
@fields = sort {$a->[1] <=> $b->[1]} @fields; |
|
|
5315
|
|
|
|
|
5638
|
|
|
6705
|
|
|
|
|
|
|
|
|
6706
|
|
|
|
|
|
|
# return array reference |
|
6707
|
37
|
|
|
|
|
194
|
return(\@fields); |
|
6708
|
|
|
|
|
|
|
|
|
6709
|
|
|
|
|
|
|
} |
|
6710
|
|
|
|
|
|
|
|
|
6711
|
|
|
|
|
|
|
# fix incorrectly scaled (X-Rite) data |
|
6712
|
|
|
|
|
|
|
# checks spectral, XYZ and xyY data |
|
6713
|
|
|
|
|
|
|
# parameters: (object_ref) |
|
6714
|
|
|
|
|
|
|
sub _scale_check { |
|
6715
|
|
|
|
|
|
|
|
|
6716
|
|
|
|
|
|
|
# get object reference |
|
6717
|
19
|
|
|
19
|
|
24
|
my $self = shift(); |
|
6718
|
|
|
|
|
|
|
|
|
6719
|
|
|
|
|
|
|
# local variables |
|
6720
|
19
|
|
|
|
|
30
|
my (@s, $pct, $cie); |
|
6721
|
|
|
|
|
|
|
|
|
6722
|
|
|
|
|
|
|
# get indices of suspect spectral values |
|
6723
|
19
|
|
|
|
|
31
|
@s = grep {$self->[1][0][$_] =~ /^SPECTRAL_(NM)?\d{3}$/} (0 .. $#{$self->[1][0]}); |
|
|
410
|
|
|
|
|
532
|
|
|
|
19
|
|
|
|
|
46
|
|
|
6724
|
|
|
|
|
|
|
|
|
6725
|
|
|
|
|
|
|
# if format found |
|
6726
|
19
|
50
|
|
|
|
41
|
if (@s) { |
|
6727
|
|
|
|
|
|
|
|
|
6728
|
|
|
|
|
|
|
# for each sample |
|
6729
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6730
|
|
|
|
|
|
|
|
|
6731
|
|
|
|
|
|
|
# if average value > 2 (must be %-values) |
|
6732
|
0
|
0
|
|
|
|
0
|
if (List::Util::sum(@{$self->[1][$i]}[@s])/@s > 2) { |
|
|
0
|
|
|
|
|
0
|
|
|
6733
|
|
|
|
|
|
|
|
|
6734
|
|
|
|
|
|
|
# set %-value flag |
|
6735
|
0
|
|
|
|
|
0
|
$pct = 1; |
|
6736
|
|
|
|
|
|
|
|
|
6737
|
0
|
|
|
|
|
0
|
last; |
|
6738
|
|
|
|
|
|
|
|
|
6739
|
|
|
|
|
|
|
} |
|
6740
|
|
|
|
|
|
|
|
|
6741
|
|
|
|
|
|
|
} |
|
6742
|
|
|
|
|
|
|
|
|
6743
|
|
|
|
|
|
|
# if %-values |
|
6744
|
0
|
0
|
|
|
|
0
|
if ($pct) { |
|
6745
|
|
|
|
|
|
|
|
|
6746
|
|
|
|
|
|
|
# for each sample |
|
6747
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6748
|
|
|
|
|
|
|
|
|
6749
|
|
|
|
|
|
|
# for each spectral value |
|
6750
|
0
|
|
|
|
|
0
|
for my $j (@s) { |
|
6751
|
|
|
|
|
|
|
|
|
6752
|
|
|
|
|
|
|
# fix value |
|
6753
|
0
|
|
|
|
|
0
|
$self->[1][$i][$j] /= 100; |
|
6754
|
|
|
|
|
|
|
|
|
6755
|
|
|
|
|
|
|
} |
|
6756
|
|
|
|
|
|
|
|
|
6757
|
|
|
|
|
|
|
} |
|
6758
|
|
|
|
|
|
|
|
|
6759
|
|
|
|
|
|
|
} |
|
6760
|
|
|
|
|
|
|
|
|
6761
|
|
|
|
|
|
|
} |
|
6762
|
|
|
|
|
|
|
|
|
6763
|
|
|
|
|
|
|
# get indices of XYZ or XYY values |
|
6764
|
19
|
|
|
|
|
30
|
@s = grep {$self->[1][0][$_] =~ /^(XYZ_[XYZ]|XYY_CAPY)$/} (0 .. $#{$self->[1][0]}); |
|
|
410
|
|
|
|
|
679
|
|
|
|
19
|
|
|
|
|
36
|
|
|
6765
|
|
|
|
|
|
|
|
|
6766
|
|
|
|
|
|
|
# if format found |
|
6767
|
19
|
100
|
|
|
|
45
|
if (@s) { |
|
6768
|
|
|
|
|
|
|
|
|
6769
|
|
|
|
|
|
|
# for each sample |
|
6770
|
13
|
|
|
|
|
18
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
13
|
|
|
|
|
36
|
|
|
6771
|
|
|
|
|
|
|
|
|
6772
|
|
|
|
|
|
|
# if average value > 2 (must be CIE values) |
|
6773
|
13
|
50
|
|
|
|
16
|
if (List::Util::sum(@{$self->[1][$i]}[@s])/@s > 2) { |
|
|
13
|
|
|
|
|
91
|
|
|
6774
|
|
|
|
|
|
|
|
|
6775
|
|
|
|
|
|
|
# set CIE flag |
|
6776
|
13
|
|
|
|
|
17
|
$cie = 1; |
|
6777
|
|
|
|
|
|
|
|
|
6778
|
13
|
|
|
|
|
21
|
last; |
|
6779
|
|
|
|
|
|
|
|
|
6780
|
|
|
|
|
|
|
} |
|
6781
|
|
|
|
|
|
|
|
|
6782
|
|
|
|
|
|
|
} |
|
6783
|
|
|
|
|
|
|
|
|
6784
|
|
|
|
|
|
|
# if not CIE values |
|
6785
|
13
|
50
|
|
|
|
31
|
if (! $cie) { |
|
6786
|
|
|
|
|
|
|
|
|
6787
|
|
|
|
|
|
|
# for each sample |
|
6788
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6789
|
|
|
|
|
|
|
|
|
6790
|
|
|
|
|
|
|
# for each value |
|
6791
|
0
|
|
|
|
|
0
|
for my $j (@s) { |
|
6792
|
|
|
|
|
|
|
|
|
6793
|
|
|
|
|
|
|
# fix value |
|
6794
|
0
|
|
|
|
|
0
|
$self->[1][$i][$j] *= 100; |
|
6795
|
|
|
|
|
|
|
|
|
6796
|
|
|
|
|
|
|
} |
|
6797
|
|
|
|
|
|
|
|
|
6798
|
|
|
|
|
|
|
} |
|
6799
|
|
|
|
|
|
|
|
|
6800
|
|
|
|
|
|
|
} |
|
6801
|
|
|
|
|
|
|
|
|
6802
|
|
|
|
|
|
|
} |
|
6803
|
|
|
|
|
|
|
|
|
6804
|
|
|
|
|
|
|
} |
|
6805
|
|
|
|
|
|
|
|
|
6806
|
|
|
|
|
|
|
# binary search |
|
6807
|
|
|
|
|
|
|
# locates the interval containing or bounding the target value |
|
6808
|
|
|
|
|
|
|
# returns an array of four index values, which indicate upper and lower transitions |
|
6809
|
|
|
|
|
|
|
# parameters: (source_array, target_value, channel_index, low_index, high_index) |
|
6810
|
|
|
|
|
|
|
# returns: (interval_index_array) |
|
6811
|
|
|
|
|
|
|
sub _bin_search { |
|
6812
|
|
|
|
|
|
|
|
|
6813
|
|
|
|
|
|
|
# get parameters |
|
6814
|
0
|
|
|
0
|
|
0
|
my ($source, $target, $channel, $low, $high) = @_; |
|
6815
|
|
|
|
|
|
|
|
|
6816
|
|
|
|
|
|
|
# local variables |
|
6817
|
0
|
|
|
|
|
0
|
my ($k, $interval); |
|
6818
|
|
|
|
|
|
|
|
|
6819
|
|
|
|
|
|
|
# copy low and high indices |
|
6820
|
0
|
|
|
|
|
0
|
$interval->[0] = $low; |
|
6821
|
0
|
|
|
|
|
0
|
$interval->[1] = $high; |
|
6822
|
|
|
|
|
|
|
|
|
6823
|
|
|
|
|
|
|
# while interval is open |
|
6824
|
0
|
|
|
|
|
0
|
while ($interval->[1] - $interval->[0] > 1) { |
|
6825
|
|
|
|
|
|
|
|
|
6826
|
|
|
|
|
|
|
# compute the midpoint |
|
6827
|
0
|
|
|
|
|
0
|
$k = int(($interval->[1] + $interval->[0])/2); |
|
6828
|
|
|
|
|
|
|
|
|
6829
|
|
|
|
|
|
|
# if midpoint value >= target value |
|
6830
|
0
|
0
|
|
|
|
0
|
if ($source->[$k][$channel] >= $target) { |
|
6831
|
|
|
|
|
|
|
|
|
6832
|
|
|
|
|
|
|
# set higher index to midpoint |
|
6833
|
0
|
|
|
|
|
0
|
$interval->[1] = $k; |
|
6834
|
|
|
|
|
|
|
|
|
6835
|
|
|
|
|
|
|
} else { |
|
6836
|
|
|
|
|
|
|
|
|
6837
|
|
|
|
|
|
|
# set lower index to midpoint |
|
6838
|
0
|
|
|
|
|
0
|
$interval->[0] = $k; |
|
6839
|
|
|
|
|
|
|
|
|
6840
|
|
|
|
|
|
|
} |
|
6841
|
|
|
|
|
|
|
|
|
6842
|
|
|
|
|
|
|
} |
|
6843
|
|
|
|
|
|
|
|
|
6844
|
|
|
|
|
|
|
# copy low and high indices |
|
6845
|
0
|
|
|
|
|
0
|
$interval->[2] = $low; |
|
6846
|
0
|
|
|
|
|
0
|
$interval->[3] = $high; |
|
6847
|
|
|
|
|
|
|
|
|
6848
|
|
|
|
|
|
|
# while interval is open |
|
6849
|
0
|
|
|
|
|
0
|
while ($interval->[3] - $interval->[2] > 1) { |
|
6850
|
|
|
|
|
|
|
|
|
6851
|
|
|
|
|
|
|
# compute the midpoint |
|
6852
|
0
|
|
|
|
|
0
|
$k = int(($interval->[3] + $interval->[2])/2); |
|
6853
|
|
|
|
|
|
|
|
|
6854
|
|
|
|
|
|
|
# if midpoint value > target value |
|
6855
|
0
|
0
|
|
|
|
0
|
if ($source->[$k][$channel] > $target) { |
|
6856
|
|
|
|
|
|
|
|
|
6857
|
|
|
|
|
|
|
# set higher index to midpoint |
|
6858
|
0
|
|
|
|
|
0
|
$interval->[3] = $k; |
|
6859
|
|
|
|
|
|
|
|
|
6860
|
|
|
|
|
|
|
} else { |
|
6861
|
|
|
|
|
|
|
|
|
6862
|
|
|
|
|
|
|
# set lower index to midpoint |
|
6863
|
0
|
|
|
|
|
0
|
$interval->[2] = $k; |
|
6864
|
|
|
|
|
|
|
|
|
6865
|
|
|
|
|
|
|
} |
|
6866
|
|
|
|
|
|
|
|
|
6867
|
|
|
|
|
|
|
} |
|
6868
|
|
|
|
|
|
|
|
|
6869
|
|
|
|
|
|
|
# return interval array |
|
6870
|
0
|
|
|
|
|
0
|
return($interval); |
|
6871
|
|
|
|
|
|
|
|
|
6872
|
|
|
|
|
|
|
} |
|
6873
|
|
|
|
|
|
|
|
|
6874
|
|
|
|
|
|
|
# linear search |
|
6875
|
|
|
|
|
|
|
# locates the closest source sample based on Manhattan distance |
|
6876
|
|
|
|
|
|
|
# parameters: (source_array, target_vector) |
|
6877
|
|
|
|
|
|
|
# returns: (low_index, high_index) |
|
6878
|
|
|
|
|
|
|
sub _lin_search { |
|
6879
|
|
|
|
|
|
|
|
|
6880
|
|
|
|
|
|
|
# get parameters |
|
6881
|
0
|
|
|
0
|
|
0
|
my ($source, $target) = @_; |
|
6882
|
|
|
|
|
|
|
|
|
6883
|
|
|
|
|
|
|
# local variables |
|
6884
|
0
|
|
|
|
|
0
|
my ($d0, $d1, $d2, $low, $high); |
|
6885
|
|
|
|
|
|
|
|
|
6886
|
|
|
|
|
|
|
# set initial difference |
|
6887
|
0
|
|
|
|
|
0
|
$d0 = @{$target}; |
|
|
0
|
|
|
|
|
0
|
|
|
6888
|
|
|
|
|
|
|
|
|
6889
|
|
|
|
|
|
|
# for each source sample |
|
6890
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$source}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6891
|
|
|
|
|
|
|
|
|
6892
|
|
|
|
|
|
|
# clear differences |
|
6893
|
0
|
|
|
|
|
0
|
$d1 = $d2 = 0; |
|
6894
|
|
|
|
|
|
|
|
|
6895
|
|
|
|
|
|
|
# for each channel |
|
6896
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$target}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6897
|
|
|
|
|
|
|
|
|
6898
|
|
|
|
|
|
|
# add difference to target sample |
|
6899
|
0
|
|
|
|
|
0
|
$d1 += abs($source->[$i][$j] - $target->[$j]); |
|
6900
|
|
|
|
|
|
|
|
|
6901
|
|
|
|
|
|
|
# add difference to previous sample |
|
6902
|
0
|
0
|
|
|
|
0
|
$d2 += abs($source->[$i][$j] - $source->[$i - 1][$j]) if ($i > 0); |
|
6903
|
|
|
|
|
|
|
|
|
6904
|
|
|
|
|
|
|
} |
|
6905
|
|
|
|
|
|
|
|
|
6906
|
|
|
|
|
|
|
# if new difference less |
|
6907
|
0
|
0
|
|
|
|
0
|
if ($d1 < $d0) { |
|
6908
|
|
|
|
|
|
|
|
|
6909
|
|
|
|
|
|
|
# save index |
|
6910
|
0
|
|
|
|
|
0
|
$low = $high = $i; |
|
6911
|
|
|
|
|
|
|
|
|
6912
|
|
|
|
|
|
|
# update difference |
|
6913
|
0
|
|
|
|
|
0
|
$d0 = $d1; |
|
6914
|
|
|
|
|
|
|
|
|
6915
|
|
|
|
|
|
|
} |
|
6916
|
|
|
|
|
|
|
|
|
6917
|
|
|
|
|
|
|
# if duplicate sample |
|
6918
|
0
|
0
|
0
|
|
|
0
|
if ($d0 == $d1 && $d2 == 0) { |
|
6919
|
|
|
|
|
|
|
|
|
6920
|
|
|
|
|
|
|
# save index |
|
6921
|
0
|
|
|
|
|
0
|
$high = $i; |
|
6922
|
|
|
|
|
|
|
|
|
6923
|
|
|
|
|
|
|
} |
|
6924
|
|
|
|
|
|
|
|
|
6925
|
|
|
|
|
|
|
} |
|
6926
|
|
|
|
|
|
|
|
|
6927
|
|
|
|
|
|
|
# return |
|
6928
|
0
|
|
|
|
|
0
|
return($low, $high); |
|
6929
|
|
|
|
|
|
|
|
|
6930
|
|
|
|
|
|
|
} |
|
6931
|
|
|
|
|
|
|
|
|
6932
|
|
|
|
|
|
|
# add average sample |
|
6933
|
|
|
|
|
|
|
# assumes device values (if any) are same for each sample |
|
6934
|
|
|
|
|
|
|
# averages measurements values - spectral, XYZ, L*a*b*, or density |
|
6935
|
|
|
|
|
|
|
# L*a*b* values are converted to xyz for averaging, then back to L*a*b* |
|
6936
|
|
|
|
|
|
|
# density values are converted to reflectance for averaging, then back to density |
|
6937
|
|
|
|
|
|
|
# parameters: (object_reference, row_slice, linear_slice, L*a*b*_slice, density_slice, id_slice, name_slice, hash) |
|
6938
|
|
|
|
|
|
|
# returns: (average_sample_index) |
|
6939
|
|
|
|
|
|
|
sub _add_avg { |
|
6940
|
|
|
|
|
|
|
|
|
6941
|
|
|
|
|
|
|
# get parameters |
|
6942
|
0
|
|
|
0
|
|
0
|
my ($self, $rows, $c1, $c2, $c3, $id, $name, $hash) = @_; |
|
6943
|
|
|
|
|
|
|
|
|
6944
|
|
|
|
|
|
|
# local variables |
|
6945
|
0
|
|
|
|
|
0
|
my ($n, $next, @xyz, $sid, $sn); |
|
6946
|
|
|
|
|
|
|
|
|
6947
|
|
|
|
|
|
|
# get number of samples |
|
6948
|
0
|
|
|
|
|
0
|
$n = @{$rows}; |
|
|
0
|
|
|
|
|
0
|
|
|
6949
|
|
|
|
|
|
|
|
|
6950
|
|
|
|
|
|
|
# get index of next data row |
|
6951
|
0
|
|
|
|
|
0
|
$next = $#{$self->[1]} + 1; |
|
|
0
|
|
|
|
|
0
|
|
|
6952
|
|
|
|
|
|
|
|
|
6953
|
|
|
|
|
|
|
# copy first sample |
|
6954
|
0
|
|
|
|
|
0
|
$self->[1][$next] = [@{$self->[1][shift(@{$rows})]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6955
|
|
|
|
|
|
|
|
|
6956
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
6957
|
0
|
|
|
|
|
0
|
for (my $j = 0; $j < @{$c2}; $j += 3) { |
|
|
0
|
|
|
|
|
0
|
|
|
6958
|
|
|
|
|
|
|
|
|
6959
|
|
|
|
|
|
|
# convert to L*a*b* values to xyz |
|
6960
|
0
|
|
|
|
|
0
|
@{$self->[1][$next]}[@{$c2}[$j .. $j + 2]] = ICC::Shared::_Lab2xyz(@{$self->[1][$next]}[@{$c2}[$j .. $j + 2]]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6961
|
|
|
|
|
|
|
|
|
6962
|
|
|
|
|
|
|
} |
|
6963
|
|
|
|
|
|
|
|
|
6964
|
|
|
|
|
|
|
# for each density column |
|
6965
|
0
|
|
|
|
|
0
|
for my $j (@{$c3}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6966
|
|
|
|
|
|
|
|
|
6967
|
|
|
|
|
|
|
# convert to density to reflectance |
|
6968
|
0
|
|
|
|
|
0
|
$self->[1][$next][$j] = POSIX::pow(10, -$self->[1][$next][$j]); |
|
6969
|
|
|
|
|
|
|
|
|
6970
|
|
|
|
|
|
|
} |
|
6971
|
|
|
|
|
|
|
|
|
6972
|
|
|
|
|
|
|
# for remaining samples |
|
6973
|
0
|
|
|
|
|
0
|
for my $i (@{$rows}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6974
|
|
|
|
|
|
|
|
|
6975
|
|
|
|
|
|
|
# for each linear column |
|
6976
|
0
|
|
|
|
|
0
|
for my $j (@{$c1}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6977
|
|
|
|
|
|
|
|
|
6978
|
|
|
|
|
|
|
# add value |
|
6979
|
0
|
|
|
|
|
0
|
$self->[1][$next][$j] += $self->[1][$i][$j]; |
|
6980
|
|
|
|
|
|
|
|
|
6981
|
|
|
|
|
|
|
} |
|
6982
|
|
|
|
|
|
|
|
|
6983
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
6984
|
0
|
|
|
|
|
0
|
for (my $j = 0; $j < @{$c2}; $j += 3) { |
|
|
0
|
|
|
|
|
0
|
|
|
6985
|
|
|
|
|
|
|
|
|
6986
|
|
|
|
|
|
|
# get xyz values |
|
6987
|
0
|
|
|
|
|
0
|
@xyz = ICC::Shared::_Lab2xyz(@{$self->[1][$i]}[@{$c2}[$j .. $j + 2]]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6988
|
|
|
|
|
|
|
|
|
6989
|
|
|
|
|
|
|
# add to self |
|
6990
|
0
|
|
|
|
|
0
|
$self->[1][$next][$c2->[$j]] += $xyz[0]; |
|
6991
|
0
|
|
|
|
|
0
|
$self->[1][$next][$c2->[$j + 1]] += $xyz[1]; |
|
6992
|
0
|
|
|
|
|
0
|
$self->[1][$next][$c2->[$j + 2]] += $xyz[2]; |
|
6993
|
|
|
|
|
|
|
|
|
6994
|
|
|
|
|
|
|
} |
|
6995
|
|
|
|
|
|
|
|
|
6996
|
|
|
|
|
|
|
# for each density column |
|
6997
|
0
|
|
|
|
|
0
|
for my $j (@{$c3}) { |
|
|
0
|
|
|
|
|
0
|
|
|
6998
|
|
|
|
|
|
|
|
|
6999
|
|
|
|
|
|
|
# add temp reflectance |
|
7000
|
0
|
|
|
|
|
0
|
$self->[1][$next][$j] += POSIX::pow(10, -$self->[1][$i][$j]); |
|
7001
|
|
|
|
|
|
|
|
|
7002
|
|
|
|
|
|
|
} |
|
7003
|
|
|
|
|
|
|
|
|
7004
|
|
|
|
|
|
|
} |
|
7005
|
|
|
|
|
|
|
|
|
7006
|
|
|
|
|
|
|
# for each measurement column |
|
7007
|
0
|
|
|
|
|
0
|
for my $j (@{$c1}, @{$c2}, @{$c3}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7008
|
|
|
|
|
|
|
|
|
7009
|
|
|
|
|
|
|
# divide by number of samples |
|
7010
|
0
|
|
|
|
|
0
|
$self->[1][$next][$j] /= $n; |
|
7011
|
|
|
|
|
|
|
|
|
7012
|
|
|
|
|
|
|
} |
|
7013
|
|
|
|
|
|
|
|
|
7014
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
7015
|
0
|
|
|
|
|
0
|
for (my $j = 0; $j < @{$c2}; $j += 3) { |
|
|
0
|
|
|
|
|
0
|
|
|
7016
|
|
|
|
|
|
|
|
|
7017
|
|
|
|
|
|
|
# convert to xyz values to L*a*b* |
|
7018
|
0
|
|
|
|
|
0
|
@{$self->[1][$next]}[@{$c2}[$j .. $j + 2]] = ICC::Shared::_xyz2Lab(@{$self->[1][$next]}[@{$c2}[$j .. $j + 2]]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7019
|
|
|
|
|
|
|
|
|
7020
|
|
|
|
|
|
|
} |
|
7021
|
|
|
|
|
|
|
|
|
7022
|
|
|
|
|
|
|
# for each density column |
|
7023
|
0
|
|
|
|
|
0
|
for my $j (@{$c3}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7024
|
|
|
|
|
|
|
|
|
7025
|
|
|
|
|
|
|
# convert to reflectance to density |
|
7026
|
0
|
|
|
|
|
0
|
$self->[1][$next][$j] = -POSIX::log10($self->[1][$next][$j]); |
|
7027
|
|
|
|
|
|
|
|
|
7028
|
|
|
|
|
|
|
} |
|
7029
|
|
|
|
|
|
|
|
|
7030
|
|
|
|
|
|
|
# get SAMPLE_ID value from hash |
|
7031
|
0
|
|
|
|
|
0
|
$sid = $hash->{'id'}; |
|
7032
|
|
|
|
|
|
|
|
|
7033
|
|
|
|
|
|
|
# for each SAMPLE_ID column |
|
7034
|
0
|
|
|
|
|
0
|
for my $i (@{$id}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7035
|
|
|
|
|
|
|
|
|
7036
|
|
|
|
|
|
|
# if SAMPLE_ID defined |
|
7037
|
0
|
0
|
|
|
|
0
|
if (defined($sid)) { |
|
7038
|
|
|
|
|
|
|
|
|
7039
|
|
|
|
|
|
|
# set to hash value |
|
7040
|
0
|
|
|
|
|
0
|
$self->[1][$next][$i] = $sid; |
|
7041
|
|
|
|
|
|
|
|
|
7042
|
|
|
|
|
|
|
} else { |
|
7043
|
|
|
|
|
|
|
|
|
7044
|
|
|
|
|
|
|
# set to row index |
|
7045
|
0
|
|
|
|
|
0
|
$self->[1][$next][$i] = $next; |
|
7046
|
|
|
|
|
|
|
|
|
7047
|
|
|
|
|
|
|
} |
|
7048
|
|
|
|
|
|
|
|
|
7049
|
|
|
|
|
|
|
} |
|
7050
|
|
|
|
|
|
|
|
|
7051
|
|
|
|
|
|
|
# get SAMPLE_NAME value from hash |
|
7052
|
0
|
|
|
|
|
0
|
$sn = $hash->{'name'}; |
|
7053
|
|
|
|
|
|
|
|
|
7054
|
|
|
|
|
|
|
# for each SAMPLE_NAME column |
|
7055
|
0
|
|
|
|
|
0
|
for my $i (@{$name}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7056
|
|
|
|
|
|
|
|
|
7057
|
|
|
|
|
|
|
# if SAMPLE_NAME defined |
|
7058
|
0
|
0
|
|
|
|
0
|
if (defined($sn)) { |
|
7059
|
|
|
|
|
|
|
|
|
7060
|
|
|
|
|
|
|
# set to hash value |
|
7061
|
0
|
|
|
|
|
0
|
$self->[1][$next][$i] = $sn; |
|
7062
|
|
|
|
|
|
|
|
|
7063
|
|
|
|
|
|
|
} else { |
|
7064
|
|
|
|
|
|
|
|
|
7065
|
|
|
|
|
|
|
# append '_AVG' to existing value |
|
7066
|
0
|
|
|
|
|
0
|
$self->[1][$next][$i] .= '_AVG'; |
|
7067
|
|
|
|
|
|
|
|
|
7068
|
|
|
|
|
|
|
} |
|
7069
|
|
|
|
|
|
|
|
|
7070
|
|
|
|
|
|
|
} |
|
7071
|
|
|
|
|
|
|
|
|
7072
|
|
|
|
|
|
|
# return row |
|
7073
|
0
|
|
|
|
|
0
|
return($next); |
|
7074
|
|
|
|
|
|
|
|
|
7075
|
|
|
|
|
|
|
} |
|
7076
|
|
|
|
|
|
|
|
|
7077
|
|
|
|
|
|
|
# get averaging groups |
|
7078
|
|
|
|
|
|
|
# returns column slices for each averaging method |
|
7079
|
|
|
|
|
|
|
# parameters: (object_reference, hash) |
|
7080
|
|
|
|
|
|
|
# returns: (linear_slice, L*a*b*_slice, density_slice) |
|
7081
|
|
|
|
|
|
|
sub _avg_groups { |
|
7082
|
|
|
|
|
|
|
|
|
7083
|
|
|
|
|
|
|
# get parameters |
|
7084
|
1
|
|
|
1
|
|
2
|
my ($self, $hash) = @_; |
|
7085
|
|
|
|
|
|
|
|
|
7086
|
|
|
|
|
|
|
# local variables |
|
7087
|
1
|
|
|
|
|
3
|
my (@c1, @c2, @c3, @cs); |
|
7088
|
|
|
|
|
|
|
|
|
7089
|
|
|
|
|
|
|
# for each format field |
|
7090
|
1
|
|
|
|
|
2
|
for my $i (0 .. $#{$self->[1][0]}) { |
|
|
1
|
|
|
|
|
4
|
|
|
7091
|
|
|
|
|
|
|
|
|
7092
|
|
|
|
|
|
|
# add column if XYZ or spectral field |
|
7093
|
12
|
100
|
|
|
|
30
|
push(@c1, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?(?:XYZ_[XYZ]|(?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)\d{3})$/); |
|
7094
|
|
|
|
|
|
|
|
|
7095
|
|
|
|
|
|
|
# add column if L*a*b* field |
|
7096
|
12
|
100
|
|
|
|
24
|
push(@c2, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?LAB_[LAB]$/); |
|
7097
|
|
|
|
|
|
|
|
|
7098
|
|
|
|
|
|
|
# add column if density field |
|
7099
|
12
|
50
|
|
|
|
23
|
push(@c3, $i) if ($self->[1][0][$i] =~ m/^(?:.*\|)?D_(?:RED|GREEN|BLUE|VIS)$/); |
|
7100
|
|
|
|
|
|
|
|
|
7101
|
|
|
|
|
|
|
} |
|
7102
|
|
|
|
|
|
|
|
|
7103
|
|
|
|
|
|
|
# linear averaging method (L*a*b* values are converted to xyz, density values are converted to reflectance) |
|
7104
|
1
|
50
|
33
|
|
|
6
|
if (! defined($hash->{'method'}) || $hash->{'method'} eq 'LINEAR') { |
|
|
|
0
|
0
|
|
|
|
|
|
7105
|
|
|
|
|
|
|
|
|
7106
|
|
|
|
|
|
|
# verify number of L*a*b* fields |
|
7107
|
1
|
50
|
|
|
|
4
|
(@c2 % 3 == 0) or croak('wrong number of L*a*b* fields'); |
|
7108
|
|
|
|
|
|
|
|
|
7109
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
7110
|
1
|
|
|
|
|
4
|
for (my $j = 0; $j < @c2; $j += 3) { |
|
7111
|
|
|
|
|
|
|
|
|
7112
|
|
|
|
|
|
|
# sort by field name |
|
7113
|
1
|
|
|
|
|
9
|
@cs = sort {$self->[1][0][$a] cmp $self->[1][0][$b]} @c2[$j .. $j + 2]; |
|
|
3
|
|
|
|
|
9
|
|
|
7114
|
|
|
|
|
|
|
|
|
7115
|
|
|
|
|
|
|
# verify field consistency |
|
7116
|
1
|
50
|
|
|
|
3
|
(join('', map {substr($_, -1, 1)} @{$self->[1][0]}[@cs]) eq 'ABL') or croak('L*a*b* field inconsistency'); |
|
|
3
|
|
|
|
|
9
|
|
|
|
1
|
|
|
|
|
3
|
|
|
7117
|
|
|
|
|
|
|
|
|
7118
|
|
|
|
|
|
|
# save columns in LAB order |
|
7119
|
1
|
|
|
|
|
5
|
@c2[$j .. $j + 2] = @cs[2, 0, 1]; |
|
7120
|
|
|
|
|
|
|
|
|
7121
|
|
|
|
|
|
|
} |
|
7122
|
|
|
|
|
|
|
|
|
7123
|
|
|
|
|
|
|
# if simple averaging method |
|
7124
|
|
|
|
|
|
|
} elsif (defined($hash->{'method'}) && $hash->{'method'} eq 'SIMPLE') { |
|
7125
|
|
|
|
|
|
|
|
|
7126
|
|
|
|
|
|
|
# copy L*a*b* and density columns to XYZ or spectral array |
|
7127
|
0
|
|
|
|
|
0
|
push(@c1, @c2, @c3); |
|
7128
|
|
|
|
|
|
|
|
|
7129
|
|
|
|
|
|
|
# clear L*a*b* and density arrays |
|
7130
|
0
|
|
|
|
|
0
|
@c2 = (); |
|
7131
|
0
|
|
|
|
|
0
|
@c3 = (); |
|
7132
|
|
|
|
|
|
|
|
|
7133
|
|
|
|
|
|
|
} else { |
|
7134
|
|
|
|
|
|
|
|
|
7135
|
|
|
|
|
|
|
# error |
|
7136
|
0
|
|
|
|
|
0
|
croak('unsupported averaging method'); |
|
7137
|
|
|
|
|
|
|
|
|
7138
|
|
|
|
|
|
|
} |
|
7139
|
|
|
|
|
|
|
|
|
7140
|
|
|
|
|
|
|
# return slices |
|
7141
|
1
|
|
|
|
|
3
|
return(\@c1, \@c2, \@c3); |
|
7142
|
|
|
|
|
|
|
|
|
7143
|
|
|
|
|
|
|
} |
|
7144
|
|
|
|
|
|
|
|
|
7145
|
|
|
|
|
|
|
# add OBA effect to XYZ array |
|
7146
|
|
|
|
|
|
|
# parameters: (chart_object, M1_slice, M2_slice, XYZ_array, oba_factor, hash) |
|
7147
|
|
|
|
|
|
|
sub _add_oba { |
|
7148
|
|
|
|
|
|
|
|
|
7149
|
|
|
|
|
|
|
# get parameters |
|
7150
|
0
|
|
|
0
|
|
0
|
my ($self, $spec1, $spec2, $xyz, $oba, $hash) = @_; |
|
7151
|
|
|
|
|
|
|
|
|
7152
|
|
|
|
|
|
|
# local variables |
|
7153
|
0
|
|
|
|
|
0
|
my ($color, $illum, @m1, @m2, $spectral, $xyzoba); |
|
7154
|
|
|
|
|
|
|
|
|
7155
|
|
|
|
|
|
|
# save illuminant |
|
7156
|
0
|
|
|
|
|
0
|
$illum = $hash->{'illuminant'}; |
|
7157
|
|
|
|
|
|
|
|
|
7158
|
|
|
|
|
|
|
# if illuminant an array reference |
|
7159
|
0
|
0
|
0
|
|
|
0
|
if (defined($hash->{'illuminant'}) && ref($hash->{'illuminant'}) eq 'ARRAY') { |
|
7160
|
|
|
|
|
|
|
|
|
7161
|
|
|
|
|
|
|
# set illuminant to CIE D50 |
|
7162
|
0
|
|
|
|
|
0
|
$hash->{'illuminant'} = ['CIE', 'D50']; |
|
7163
|
|
|
|
|
|
|
|
|
7164
|
|
|
|
|
|
|
} else { |
|
7165
|
|
|
|
|
|
|
|
|
7166
|
|
|
|
|
|
|
# set illuminant to ASTM D50 |
|
7167
|
0
|
|
|
|
|
0
|
$hash->{'illuminant'} = 'D50'; |
|
7168
|
|
|
|
|
|
|
|
|
7169
|
|
|
|
|
|
|
} |
|
7170
|
|
|
|
|
|
|
|
|
7171
|
|
|
|
|
|
|
# make 'Color.pm' object (D50 illuminant) |
|
7172
|
0
|
|
|
|
|
0
|
$color = ICC::Support::Color->new($hash); |
|
7173
|
|
|
|
|
|
|
|
|
7174
|
|
|
|
|
|
|
# restore illuminant |
|
7175
|
0
|
|
|
|
|
0
|
$hash->{'illuminant'} = $illum; |
|
7176
|
|
|
|
|
|
|
|
|
7177
|
|
|
|
|
|
|
# for each sample |
|
7178
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7179
|
|
|
|
|
|
|
|
|
7180
|
|
|
|
|
|
|
# get M1 spectral values |
|
7181
|
0
|
|
|
|
|
0
|
@m1 = @{$self->[1][$i]}[@{$spec1}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7182
|
|
|
|
|
|
|
|
|
7183
|
|
|
|
|
|
|
# get M2 spectral values |
|
7184
|
0
|
|
|
|
|
0
|
@m2 = @{$self->[1][$i]}[@{$spec2}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7185
|
|
|
|
|
|
|
|
|
7186
|
|
|
|
|
|
|
# compute (M1 - M2) spectral values |
|
7187
|
0
|
|
|
|
|
0
|
$spectral->[$i - 1] = [map {$m1[$_] - $m2[$_]} (0 .. $#m1)]; |
|
|
0
|
|
|
|
|
0
|
|
|
7188
|
|
|
|
|
|
|
|
|
7189
|
|
|
|
|
|
|
} |
|
7190
|
|
|
|
|
|
|
|
|
7191
|
|
|
|
|
|
|
# transform (M1 - M2) spectral to D50 XYZ (hash may contain 'encoding' key) |
|
7192
|
0
|
|
|
|
|
0
|
$xyzoba = ICC::Support::Color::_trans2($color, $spectral, $hash); |
|
7193
|
|
|
|
|
|
|
|
|
7194
|
|
|
|
|
|
|
# for each sample |
|
7195
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$xyz}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7196
|
|
|
|
|
|
|
|
|
7197
|
|
|
|
|
|
|
# for each XYZ |
|
7198
|
0
|
|
|
|
|
0
|
for my $j (0 .. 2) { |
|
7199
|
|
|
|
|
|
|
|
|
7200
|
|
|
|
|
|
|
# add scaled OBA effect |
|
7201
|
0
|
|
|
|
|
0
|
$xyz->[$i][$j] += $xyzoba->[$i][$j] * $oba; |
|
7202
|
|
|
|
|
|
|
|
|
7203
|
|
|
|
|
|
|
} |
|
7204
|
|
|
|
|
|
|
|
|
7205
|
|
|
|
|
|
|
} |
|
7206
|
|
|
|
|
|
|
|
|
7207
|
|
|
|
|
|
|
} |
|
7208
|
|
|
|
|
|
|
|
|
7209
|
|
|
|
|
|
|
# get/set data |
|
7210
|
|
|
|
|
|
|
# common routine called by get/set methods |
|
7211
|
|
|
|
|
|
|
# row_slice and column_slice may be either a scalar or array reference |
|
7212
|
|
|
|
|
|
|
# an empty array reference indicates all samples or fields |
|
7213
|
|
|
|
|
|
|
# replacement_data is reference to a 2-D array of replacement values |
|
7214
|
|
|
|
|
|
|
# array dimensions must match size of row_slice and column_slice |
|
7215
|
|
|
|
|
|
|
# data_slice is Math::Matrix object, defined by row_slice and column_slice |
|
7216
|
|
|
|
|
|
|
# get_code_ref and set_code_ref transform the data when getting and setting |
|
7217
|
|
|
|
|
|
|
# parameters: (object_ref, object_index, row_slice, column_slice, replacement_data, get_code_ref, set_code_ref) |
|
7218
|
|
|
|
|
|
|
# if column_slice undefined, returns: () |
|
7219
|
|
|
|
|
|
|
# if row_slice undefined, returns: (column_slice) |
|
7220
|
|
|
|
|
|
|
# if replacement_data undefined, returns: (data_slice) |
|
7221
|
|
|
|
|
|
|
# otherwise, sets replacement data and returns: (column_slice) |
|
7222
|
|
|
|
|
|
|
sub _getset { |
|
7223
|
|
|
|
|
|
|
|
|
7224
|
|
|
|
|
|
|
# get parameters |
|
7225
|
403
|
|
|
403
|
|
710
|
my ($self, $ix, $rows, $cols, $data, $get, $set) = @_; |
|
7226
|
|
|
|
|
|
|
|
|
7227
|
|
|
|
|
|
|
# return empty if no column slice |
|
7228
|
403
|
100
|
|
|
|
941
|
defined($cols) || return(); |
|
7229
|
|
|
|
|
|
|
|
|
7230
|
|
|
|
|
|
|
# if column slice an empty array reference |
|
7231
|
217
|
100
|
100
|
|
|
481
|
if (ref($cols) eq 'ARRAY' && @{$cols} == 0) { |
|
|
207
|
|
|
|
|
475
|
|
|
7232
|
|
|
|
|
|
|
|
|
7233
|
|
|
|
|
|
|
# use all columns |
|
7234
|
2
|
|
|
|
|
3
|
$cols = [0 .. $#{$self->[$ix][0]}]; |
|
|
2
|
|
|
|
|
6
|
|
|
7235
|
|
|
|
|
|
|
|
|
7236
|
|
|
|
|
|
|
} else { |
|
7237
|
|
|
|
|
|
|
|
|
7238
|
|
|
|
|
|
|
# flatten column slice |
|
7239
|
215
|
|
|
|
|
439
|
$cols = ICC::Shared::flatten($cols); |
|
7240
|
|
|
|
|
|
|
|
|
7241
|
|
|
|
|
|
|
# verify column slice contents |
|
7242
|
215
|
50
|
33
|
|
|
246
|
(@{$cols} == grep {! ref() && $_ == int($_) && $_ >= 0} @{$cols}) or croak('invalid column slice'); |
|
|
215
|
50
|
|
|
|
286
|
|
|
|
2017
|
|
|
|
|
5773
|
|
|
|
215
|
|
|
|
|
295
|
|
|
7243
|
|
|
|
|
|
|
|
|
7244
|
|
|
|
|
|
|
} |
|
7245
|
|
|
|
|
|
|
|
|
7246
|
|
|
|
|
|
|
# return columns slice if no row slice |
|
7247
|
217
|
100
|
|
|
|
814
|
defined($rows) || return($cols); |
|
7248
|
|
|
|
|
|
|
|
|
7249
|
|
|
|
|
|
|
# if row slice an empty array reference |
|
7250
|
96
|
100
|
66
|
|
|
180
|
if (ref($rows) eq 'ARRAY' && @{$rows} == 0) { |
|
|
96
|
|
|
|
|
204
|
|
|
7251
|
|
|
|
|
|
|
|
|
7252
|
|
|
|
|
|
|
# use all rows |
|
7253
|
35
|
|
|
|
|
46
|
$rows = [1 .. $#{$self->[$ix]}]; |
|
|
35
|
|
|
|
|
78
|
|
|
7254
|
|
|
|
|
|
|
|
|
7255
|
|
|
|
|
|
|
} else { |
|
7256
|
|
|
|
|
|
|
|
|
7257
|
|
|
|
|
|
|
# flatten row slice |
|
7258
|
61
|
|
|
|
|
108
|
$rows = ICC::Shared::flatten($rows); |
|
7259
|
|
|
|
|
|
|
|
|
7260
|
|
|
|
|
|
|
# verify row slice contents |
|
7261
|
61
|
50
|
33
|
|
|
74
|
(@{$rows} == grep {! ref() && $_ == int($_) && $_ >= 0} @{$rows}) or croak('invalid row slice'); |
|
|
61
|
50
|
|
|
|
98
|
|
|
|
201
|
|
|
|
|
623
|
|
|
|
61
|
|
|
|
|
76
|
|
|
7262
|
|
|
|
|
|
|
|
|
7263
|
|
|
|
|
|
|
} |
|
7264
|
|
|
|
|
|
|
|
|
7265
|
|
|
|
|
|
|
# no replacement data (get) |
|
7266
|
96
|
100
|
|
|
|
186
|
if (! defined($data)) { |
|
7267
|
|
|
|
|
|
|
|
|
7268
|
|
|
|
|
|
|
# verify 'get' code ref, or use identity function |
|
7269
|
71
|
100
|
66
|
339
|
|
445
|
$get = (defined($get) && ref($get) eq 'CODE') ? $get : sub {@_}; |
|
|
339
|
|
|
|
|
926
|
|
|
7270
|
|
|
|
|
|
|
|
|
7271
|
|
|
|
|
|
|
# for each row |
|
7272
|
71
|
|
|
|
|
94
|
for my $i (0 .. $#{$rows}) { |
|
|
71
|
|
|
|
|
146
|
|
|
7273
|
|
|
|
|
|
|
|
|
7274
|
|
|
|
|
|
|
# get transformed data row |
|
7275
|
476
|
|
|
|
|
499
|
@{$data->[$i]} = &$get(@{$self->[$ix][$rows->[$i]]}[@{$cols}]); |
|
|
476
|
|
|
|
|
906
|
|
|
|
476
|
|
|
|
|
829
|
|
|
|
476
|
|
|
|
|
510
|
|
|
7276
|
|
|
|
|
|
|
|
|
7277
|
|
|
|
|
|
|
} |
|
7278
|
|
|
|
|
|
|
|
|
7279
|
|
|
|
|
|
|
# return data slice as a Math::Matrix object |
|
7280
|
71
|
|
|
|
|
633
|
return(bless($data, 'Math::Matrix')); |
|
7281
|
|
|
|
|
|
|
|
|
7282
|
|
|
|
|
|
|
# with replacement data (set) |
|
7283
|
|
|
|
|
|
|
} else { |
|
7284
|
|
|
|
|
|
|
|
|
7285
|
|
|
|
|
|
|
# verify replacement data is 2-D array or Math::Matrix object |
|
7286
|
25
|
50
|
33
|
|
|
94
|
((ref($data) eq 'ARRAY' || UNIVERSAL::isa($data, 'Math::Matrix')) && ref($data->[0]) eq 'ARRAY') or croak('replacement data not a 2-D array reference'); |
|
|
|
|
33
|
|
|
|
|
|
7287
|
|
|
|
|
|
|
|
|
7288
|
|
|
|
|
|
|
# verify replacement data size |
|
7289
|
25
|
50
|
33
|
|
|
32
|
($#{$data} == $#{$rows} && $#{$data->[0]} == $#{$cols}) or croak('replacement data is wrong sized'); |
|
|
25
|
|
|
|
|
30
|
|
|
|
25
|
|
|
|
|
47
|
|
|
|
25
|
|
|
|
|
40
|
|
|
|
25
|
|
|
|
|
48
|
|
|
7290
|
|
|
|
|
|
|
|
|
7291
|
|
|
|
|
|
|
# verify 'set' code ref, or use identity function |
|
7292
|
25
|
100
|
66
|
48
|
|
97
|
$set = (defined($set) && ref($set) eq 'CODE') ? $set : sub {@_}; |
|
|
48
|
|
|
|
|
115
|
|
|
7293
|
|
|
|
|
|
|
|
|
7294
|
|
|
|
|
|
|
# for each row |
|
7295
|
25
|
|
|
|
|
35
|
for my $i (0 .. $#{$rows}) { |
|
|
25
|
|
|
|
|
51
|
|
|
7296
|
|
|
|
|
|
|
|
|
7297
|
|
|
|
|
|
|
# set transformed data row |
|
7298
|
75
|
|
|
|
|
80
|
@{$self->[$ix][$rows->[$i]]}[@{$cols}] = &$set(@{$data->[$i]}); |
|
|
75
|
|
|
|
|
249
|
|
|
|
75
|
|
|
|
|
81
|
|
|
|
75
|
|
|
|
|
120
|
|
|
7299
|
|
|
|
|
|
|
|
|
7300
|
|
|
|
|
|
|
} |
|
7301
|
|
|
|
|
|
|
|
|
7302
|
|
|
|
|
|
|
# return column slice |
|
7303
|
25
|
|
|
|
|
132
|
return($cols); |
|
7304
|
|
|
|
|
|
|
|
|
7305
|
|
|
|
|
|
|
} |
|
7306
|
|
|
|
|
|
|
|
|
7307
|
|
|
|
|
|
|
} |
|
7308
|
|
|
|
|
|
|
|
|
7309
|
|
|
|
|
|
|
# get accumulated sample values |
|
7310
|
|
|
|
|
|
|
# sample dimensions are in pixels |
|
7311
|
|
|
|
|
|
|
# used by _readChartTIFF to extract samples from a data stripe |
|
7312
|
|
|
|
|
|
|
# parameters: (reference_to_data, sample_offset, sample_width, number_channels) |
|
7313
|
|
|
|
|
|
|
# returns: (accumulated_sample_values) |
|
7314
|
|
|
|
|
|
|
sub _getSample { |
|
7315
|
|
|
|
|
|
|
|
|
7316
|
|
|
|
|
|
|
# get parameters |
|
7317
|
0
|
|
|
0
|
|
0
|
my ($data, $so, $sx, $c) = @_; |
|
7318
|
|
|
|
|
|
|
|
|
7319
|
|
|
|
|
|
|
# initialize sample values |
|
7320
|
0
|
|
|
|
|
0
|
my @sv = (0) x $c; |
|
7321
|
|
|
|
|
|
|
|
|
7322
|
|
|
|
|
|
|
# for each row |
|
7323
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$data}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7324
|
|
|
|
|
|
|
|
|
7325
|
|
|
|
|
|
|
# for each pixel |
|
7326
|
0
|
|
|
|
|
0
|
for my $j (0 .. $sx - 1) { |
|
7327
|
|
|
|
|
|
|
|
|
7328
|
|
|
|
|
|
|
# for each channel |
|
7329
|
0
|
|
|
|
|
0
|
for my $k (0 .. $c - 1) { |
|
7330
|
|
|
|
|
|
|
|
|
7331
|
|
|
|
|
|
|
# accumulate sample value |
|
7332
|
0
|
|
|
|
|
0
|
$sv[$k] += $data->[$i][($so + $j) * $c + $k]; |
|
7333
|
|
|
|
|
|
|
|
|
7334
|
|
|
|
|
|
|
} |
|
7335
|
|
|
|
|
|
|
|
|
7336
|
|
|
|
|
|
|
} |
|
7337
|
|
|
|
|
|
|
|
|
7338
|
|
|
|
|
|
|
} |
|
7339
|
|
|
|
|
|
|
|
|
7340
|
|
|
|
|
|
|
# return sample values |
|
7341
|
0
|
|
|
|
|
0
|
return(@sv); |
|
7342
|
|
|
|
|
|
|
|
|
7343
|
|
|
|
|
|
|
} |
|
7344
|
|
|
|
|
|
|
|
|
7345
|
|
|
|
|
|
|
# get row length |
|
7346
|
|
|
|
|
|
|
# hash keys: 'except', 'rows', 'undef' |
|
7347
|
|
|
|
|
|
|
# parameters: (object_reference, hash) |
|
7348
|
|
|
|
|
|
|
# returns: (row_length) |
|
7349
|
|
|
|
|
|
|
sub _getRowLength { |
|
7350
|
|
|
|
|
|
|
|
|
7351
|
|
|
|
|
|
|
# get parameters |
|
7352
|
0
|
|
|
0
|
|
0
|
my ($self, $hash) = @_; |
|
7353
|
|
|
|
|
|
|
|
|
7354
|
|
|
|
|
|
|
# local variables |
|
7355
|
0
|
|
|
|
|
0
|
my ($rows, $pages, $n, $square); |
|
7356
|
|
|
|
|
|
|
|
|
7357
|
|
|
|
|
|
|
# row length exceptions |
|
7358
|
0
|
|
|
|
|
0
|
state $exc = { |
|
7359
|
|
|
|
|
|
|
'a541a1dbe0ad9b9641fa14c1105426ee' => 4, # microP2P |
|
7360
|
|
|
|
|
|
|
'911c1ff09e25eaa835a3d83292dddc4c' => 5, # miniP2P |
|
7361
|
|
|
|
|
|
|
'751fb2709976713309acbd832a6c28ba' => 5, # miniP2P53 |
|
7362
|
|
|
|
|
|
|
'4dcb109fa2f8b2332c7d3860cccf0bbe' => 2, # G7 verifier |
|
7363
|
|
|
|
|
|
|
'7af45f1bc56c2e46042c7ee524bca773' => 25, # P2P25 |
|
7364
|
|
|
|
|
|
|
'288da8bd79a209f3cb222ec6fd4eb195' => 12, # P2P51H |
|
7365
|
|
|
|
|
|
|
'b7045af5a40dbe3f8d8d5a93f3a14f42' => 25, # P2P51 |
|
7366
|
|
|
|
|
|
|
'79c4aab9771a9eb40c69168b5bb3c619' => 12, # P2P53 |
|
7367
|
|
|
|
|
|
|
}; |
|
7368
|
|
|
|
|
|
|
|
|
7369
|
|
|
|
|
|
|
# return if chart found in exception table |
|
7370
|
0
|
0
|
0
|
|
|
0
|
return($rows) if ($hash->{'except'} && defined($rows = $exc->{signature($self)})); |
|
7371
|
|
|
|
|
|
|
|
|
7372
|
|
|
|
|
|
|
# if 'rows' hash key is defined |
|
7373
|
0
|
0
|
|
|
|
0
|
if (defined($rows = $hash->{'rows'})) { |
|
7374
|
|
|
|
|
|
|
|
|
7375
|
|
|
|
|
|
|
# if valid row length |
|
7376
|
0
|
0
|
0
|
|
|
0
|
if (Scalar::Util::looks_like_number($rows) && $rows > 0 && $rows == int($rows)) { |
|
|
|
|
0
|
|
|
|
|
|
7377
|
|
|
|
|
|
|
|
|
7378
|
|
|
|
|
|
|
# return |
|
7379
|
0
|
|
|
|
|
0
|
return($rows); |
|
7380
|
|
|
|
|
|
|
|
|
7381
|
|
|
|
|
|
|
} else { |
|
7382
|
|
|
|
|
|
|
|
|
7383
|
|
|
|
|
|
|
# warn |
|
7384
|
0
|
|
|
|
|
0
|
warn('invalid \'rows\' parameter'); |
|
7385
|
|
|
|
|
|
|
|
|
7386
|
|
|
|
|
|
|
} |
|
7387
|
|
|
|
|
|
|
|
|
7388
|
|
|
|
|
|
|
} |
|
7389
|
|
|
|
|
|
|
|
|
7390
|
|
|
|
|
|
|
# if LGOROWLENGTH keyword (ProfileMaker notation) |
|
7391
|
0
|
0
|
|
|
|
0
|
if (defined($rows = keyword($self, 'LGOROWLENGTH'))) { |
|
7392
|
|
|
|
|
|
|
|
|
7393
|
|
|
|
|
|
|
# if valid row length |
|
7394
|
0
|
0
|
0
|
|
|
0
|
if (Scalar::Util::looks_like_number($rows) && $rows > 0 && $rows == int($rows)) { |
|
|
|
|
0
|
|
|
|
|
|
7395
|
|
|
|
|
|
|
|
|
7396
|
|
|
|
|
|
|
# return |
|
7397
|
0
|
|
|
|
|
0
|
return($rows); |
|
7398
|
|
|
|
|
|
|
|
|
7399
|
|
|
|
|
|
|
} else { |
|
7400
|
|
|
|
|
|
|
|
|
7401
|
|
|
|
|
|
|
# warn |
|
7402
|
0
|
|
|
|
|
0
|
warn('invalid \'LGOROWLENGTH\' value'); |
|
7403
|
|
|
|
|
|
|
|
|
7404
|
|
|
|
|
|
|
} |
|
7405
|
|
|
|
|
|
|
|
|
7406
|
|
|
|
|
|
|
} |
|
7407
|
|
|
|
|
|
|
|
|
7408
|
|
|
|
|
|
|
# if NUMBER_OF_STRIPS keyword (EFI notation) |
|
7409
|
0
|
0
|
|
|
|
0
|
if (defined($rows = keyword($self, 'NUMBER_OF_STRIPS'))) { |
|
7410
|
|
|
|
|
|
|
|
|
7411
|
|
|
|
|
|
|
# if valid row length |
|
7412
|
0
|
0
|
0
|
|
|
0
|
if (Scalar::Util::looks_like_number($rows) && $rows > 0 && $rows == int($rows)) { |
|
|
|
|
0
|
|
|
|
|
|
7413
|
|
|
|
|
|
|
|
|
7414
|
|
|
|
|
|
|
# return |
|
7415
|
0
|
|
|
|
|
0
|
return($rows); |
|
7416
|
|
|
|
|
|
|
|
|
7417
|
|
|
|
|
|
|
} else { |
|
7418
|
|
|
|
|
|
|
|
|
7419
|
|
|
|
|
|
|
# warn |
|
7420
|
0
|
|
|
|
|
0
|
warn('invalid \'NUMBER_OF_STRIPS\' value'); |
|
7421
|
|
|
|
|
|
|
|
|
7422
|
|
|
|
|
|
|
} |
|
7423
|
|
|
|
|
|
|
|
|
7424
|
|
|
|
|
|
|
} |
|
7425
|
|
|
|
|
|
|
|
|
7426
|
|
|
|
|
|
|
# if 'NumberPatchRows' key (i1profiler CxF3) |
|
7427
|
0
|
0
|
|
|
|
0
|
if (defined($rows = $self->[0]{'xrp:CustomAttributes'}{'NumberPatchRows'})) { |
|
7428
|
|
|
|
|
|
|
|
|
7429
|
|
|
|
|
|
|
# get 'NumberPatchPages' value |
|
7430
|
0
|
|
0
|
|
|
0
|
$pages = $self->[0]{'xrp:CustomAttributes'}{'NumberPatchPages'} // 1; |
|
7431
|
|
|
|
|
|
|
|
|
7432
|
|
|
|
|
|
|
# if valid row length |
|
7433
|
0
|
0
|
0
|
|
|
0
|
if (Scalar::Util::looks_like_number($rows) && $rows > 0 && $rows == int($rows)) { |
|
|
|
|
0
|
|
|
|
|
|
7434
|
|
|
|
|
|
|
|
|
7435
|
|
|
|
|
|
|
# return |
|
7436
|
0
|
|
|
|
|
0
|
return($rows * $pages); |
|
7437
|
|
|
|
|
|
|
|
|
7438
|
|
|
|
|
|
|
} else { |
|
7439
|
|
|
|
|
|
|
|
|
7440
|
|
|
|
|
|
|
# warn |
|
7441
|
0
|
|
|
|
|
0
|
warn('invalid \'NumberPatchRows\' attribute'); |
|
7442
|
|
|
|
|
|
|
|
|
7443
|
|
|
|
|
|
|
} |
|
7444
|
|
|
|
|
|
|
|
|
7445
|
|
|
|
|
|
|
} |
|
7446
|
|
|
|
|
|
|
|
|
7447
|
|
|
|
|
|
|
# return, if 'undef' hash key |
|
7448
|
0
|
0
|
|
|
|
0
|
return(undef) if ($hash->{'undef'}); |
|
7449
|
|
|
|
|
|
|
|
|
7450
|
|
|
|
|
|
|
# get number of samples |
|
7451
|
0
|
|
|
|
|
0
|
$n = $#{$self->[1]}; |
|
|
0
|
|
|
|
|
0
|
|
|
7452
|
|
|
|
|
|
|
|
|
7453
|
|
|
|
|
|
|
# return if 0 |
|
7454
|
0
|
0
|
|
|
|
0
|
return(0) if ($n == 0); |
|
7455
|
|
|
|
|
|
|
|
|
7456
|
|
|
|
|
|
|
# return if 1 or 2 |
|
7457
|
0
|
0
|
|
|
|
0
|
return(1) if ($n < 3); |
|
7458
|
|
|
|
|
|
|
|
|
7459
|
|
|
|
|
|
|
# compute size of square chart |
|
7460
|
0
|
|
|
|
|
0
|
$square = POSIX::ceil(sqrt($n)); |
|
7461
|
|
|
|
|
|
|
|
|
7462
|
|
|
|
|
|
|
# return if chart is square |
|
7463
|
0
|
0
|
|
|
|
0
|
return($square) if ($n == $square**2); |
|
7464
|
|
|
|
|
|
|
|
|
7465
|
|
|
|
|
|
|
# set row length one less than square chart |
|
7466
|
0
|
|
|
|
|
0
|
$rows = $square - 1; |
|
7467
|
|
|
|
|
|
|
|
|
7468
|
|
|
|
|
|
|
# while modulus is non-zero, decrement row length |
|
7469
|
0
|
|
|
|
|
0
|
while ($n % $rows) {$rows--} |
|
|
0
|
|
|
|
|
0
|
|
|
7470
|
|
|
|
|
|
|
|
|
7471
|
|
|
|
|
|
|
# return row length, choosing full rectangle if possible |
|
7472
|
0
|
0
|
|
|
|
0
|
return($rows > $square/2 ? $rows : $square); |
|
7473
|
|
|
|
|
|
|
|
|
7474
|
|
|
|
|
|
|
} |
|
7475
|
|
|
|
|
|
|
|
|
7476
|
|
|
|
|
|
|
# invert ink map |
|
7477
|
|
|
|
|
|
|
# fills the ink map, then inverts it |
|
7478
|
|
|
|
|
|
|
# parameter: (ink_map_vector) |
|
7479
|
|
|
|
|
|
|
# returns: (inverted_ink_map, [filled_ink_map, missing_process_channels]) |
|
7480
|
|
|
|
|
|
|
sub _invert_ink_map { |
|
7481
|
|
|
|
|
|
|
|
|
7482
|
|
|
|
|
|
|
# get parameters |
|
7483
|
0
|
|
|
0
|
|
0
|
my ($map) = @_; |
|
7484
|
|
|
|
|
|
|
|
|
7485
|
|
|
|
|
|
|
# local variables |
|
7486
|
0
|
|
|
|
|
0
|
my ($ix, @ms, @mp, @all, @inv); |
|
7487
|
|
|
|
|
|
|
|
|
7488
|
|
|
|
|
|
|
# get upper index |
|
7489
|
0
|
|
|
|
|
0
|
$ix = $#{$map}; |
|
|
0
|
|
|
|
|
0
|
|
|
7490
|
|
|
|
|
|
|
|
|
7491
|
|
|
|
|
|
|
# get missing channels |
|
7492
|
0
|
|
|
|
|
0
|
@ms = grep {my $i = $_; ! grep {$_ eq $i} @{$map}} (0 .. $ix); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7493
|
|
|
|
|
|
|
|
|
7494
|
|
|
|
|
|
|
# filter missing CMYK channels |
|
7495
|
0
|
|
|
|
|
0
|
@mp = grep {$_ < 4} @ms; |
|
|
0
|
|
|
|
|
0
|
|
|
7496
|
|
|
|
|
|
|
|
|
7497
|
|
|
|
|
|
|
# assign stationary missing channels |
|
7498
|
0
|
0
|
0
|
|
|
0
|
@all = map {my $i = $_; ($map->[$i] !~ m/^\d+$/ && grep {$_ == $i} @ms) ? $i : $map->[$i]} (0 .. $ix); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7499
|
|
|
|
|
|
|
|
|
7500
|
|
|
|
|
|
|
# get missing channels |
|
7501
|
0
|
|
|
|
|
0
|
@ms = grep {my $i = $_; ! grep {$_ eq $i} @all} (0 .. $ix); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7502
|
|
|
|
|
|
|
|
|
7503
|
|
|
|
|
|
|
# assign remaining missing channels |
|
7504
|
0
|
0
|
|
|
|
0
|
@all = map {! m/^\d+$/ ? shift(@ms) : int($_)} @all if (@ms); |
|
|
0
|
0
|
|
|
|
0
|
|
|
7505
|
|
|
|
|
|
|
|
|
7506
|
|
|
|
|
|
|
# invert filled map |
|
7507
|
0
|
|
|
|
|
0
|
@inv = map {my $i = $_; grep {$all[$_] == $i} (0 .. $ix)} (0 .. $ix); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7508
|
|
|
|
|
|
|
|
|
7509
|
|
|
|
|
|
|
# return |
|
7510
|
0
|
0
|
|
|
|
0
|
return(wantarray ? (\@inv, \@all, \@mp) : \@inv); |
|
7511
|
|
|
|
|
|
|
|
|
7512
|
|
|
|
|
|
|
} |
|
7513
|
|
|
|
|
|
|
|
|
7514
|
|
|
|
|
|
|
# map array values |
|
7515
|
|
|
|
|
|
|
# returns input_array, if output_size is undefined |
|
7516
|
|
|
|
|
|
|
# parameters: (output_size, input_slice, output_slice, input_array) |
|
7517
|
|
|
|
|
|
|
# returns: (output_array) |
|
7518
|
|
|
|
|
|
|
sub _map_array { |
|
7519
|
|
|
|
|
|
|
|
|
7520
|
|
|
|
|
|
|
# get parameters |
|
7521
|
0
|
|
|
0
|
|
0
|
my ($size, $si, $so) = splice(@_, 0, 3); |
|
7522
|
|
|
|
|
|
|
|
|
7523
|
|
|
|
|
|
|
# return if size undefined |
|
7524
|
0
|
0
|
|
|
|
0
|
return(@_) if (! defined($size)); |
|
7525
|
|
|
|
|
|
|
|
|
7526
|
|
|
|
|
|
|
# make output array |
|
7527
|
0
|
|
|
|
|
0
|
my @out = (0) x $size; |
|
7528
|
|
|
|
|
|
|
|
|
7529
|
|
|
|
|
|
|
# map values |
|
7530
|
0
|
|
|
|
|
0
|
@out[@{$so}] = @_[@{$si}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7531
|
|
|
|
|
|
|
|
|
7532
|
|
|
|
|
|
|
# return output array |
|
7533
|
0
|
|
|
|
|
0
|
return(@out); |
|
7534
|
|
|
|
|
|
|
|
|
7535
|
|
|
|
|
|
|
} |
|
7536
|
|
|
|
|
|
|
|
|
7537
|
|
|
|
|
|
|
# get illuminant white point |
|
7538
|
|
|
|
|
|
|
# returns XYZ vector from colorimetry array |
|
7539
|
|
|
|
|
|
|
# returns D50 if CAT or undefined |
|
7540
|
|
|
|
|
|
|
# parameter: (object_reference, column_slice, [hash]) |
|
7541
|
|
|
|
|
|
|
# returns: (XYZ_vector) |
|
7542
|
|
|
|
|
|
|
sub _illumWP { |
|
7543
|
|
|
|
|
|
|
|
|
7544
|
|
|
|
|
|
|
# get parameters |
|
7545
|
0
|
|
|
0
|
|
0
|
my ($self, $cols, $hash) = @_; |
|
7546
|
|
|
|
|
|
|
|
|
7547
|
|
|
|
|
|
|
# if XYZ values are valid |
|
7548
|
0
|
0
|
0
|
|
|
0
|
if (3 == grep {defined() && ! ref() && $_ > 0} @{$self->[2][2]}[@{$cols}]) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7549
|
|
|
|
|
|
|
|
|
7550
|
|
|
|
|
|
|
# return XYZ vector |
|
7551
|
0
|
|
|
|
|
0
|
return([@{$self->[2][2]}[@{$cols}]]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7552
|
|
|
|
|
|
|
|
|
7553
|
|
|
|
|
|
|
} else { |
|
7554
|
|
|
|
|
|
|
|
|
7555
|
|
|
|
|
|
|
# return D50 vector |
|
7556
|
0
|
|
|
|
|
0
|
return(ICC::Shared::D50); |
|
7557
|
|
|
|
|
|
|
|
|
7558
|
|
|
|
|
|
|
} |
|
7559
|
|
|
|
|
|
|
|
|
7560
|
|
|
|
|
|
|
} |
|
7561
|
|
|
|
|
|
|
|
|
7562
|
|
|
|
|
|
|
# compute media white point |
|
7563
|
|
|
|
|
|
|
# multiple samples are averaged |
|
7564
|
|
|
|
|
|
|
# result also stored in colorimetry array |
|
7565
|
|
|
|
|
|
|
# parameter: (object_reference, column_slice, [hash]) |
|
7566
|
|
|
|
|
|
|
# returns: (XYZ_vector) |
|
7567
|
|
|
|
|
|
|
sub _mediaWP { |
|
7568
|
|
|
|
|
|
|
|
|
7569
|
|
|
|
|
|
|
# get parameters |
|
7570
|
0
|
|
|
0
|
|
0
|
my ($self, $cols, $hash) = @_; |
|
7571
|
|
|
|
|
|
|
|
|
7572
|
|
|
|
|
|
|
# local variables |
|
7573
|
0
|
|
|
|
|
0
|
my ($WPxyz, $dev, $mwv, $n, @XYZ, @XYZs); |
|
7574
|
|
|
|
|
|
|
|
|
7575
|
|
|
|
|
|
|
# if column slice is L*a*b* |
|
7576
|
0
|
0
|
|
|
|
0
|
if ((3 == grep {$self->[1][0][$_] =~ m/LAB_[LAB]$/} @{$cols})) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7577
|
|
|
|
|
|
|
|
|
7578
|
|
|
|
|
|
|
# get illuminant white point |
|
7579
|
0
|
0
|
|
|
|
0
|
$WPxyz = defined($self->[2][2][$cols->[0]]) ? [@{$self->[2][2]}[@{$cols}]] : ICC::Shared::D50; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7580
|
|
|
|
|
|
|
|
|
7581
|
|
|
|
|
|
|
# if column slice is not XYZ |
|
7582
|
0
|
|
|
|
|
0
|
} elsif ((3 != grep {$self->[1][0][$_] =~ m/XYZ_[XYZ]$/} @{$cols})) { |
|
|
0
|
|
|
|
|
0
|
|
|
7583
|
|
|
|
|
|
|
|
|
7584
|
|
|
|
|
|
|
# warning |
|
7585
|
0
|
|
|
|
|
0
|
warn('column slice not XYZ or L*a*b* data'); |
|
7586
|
|
|
|
|
|
|
|
|
7587
|
|
|
|
|
|
|
# return empty |
|
7588
|
0
|
|
|
|
|
0
|
return(); |
|
7589
|
|
|
|
|
|
|
|
|
7590
|
|
|
|
|
|
|
} |
|
7591
|
|
|
|
|
|
|
|
|
7592
|
|
|
|
|
|
|
# if no device data (using 'device' context) |
|
7593
|
0
|
0
|
|
|
|
0
|
if (! ($dev = device($self, {'context' => $hash->{'device'}}))) { |
|
7594
|
|
|
|
|
|
|
|
|
7595
|
|
|
|
|
|
|
# warning |
|
7596
|
0
|
|
|
|
|
0
|
warn('no device data'); |
|
7597
|
|
|
|
|
|
|
|
|
7598
|
|
|
|
|
|
|
# return empty |
|
7599
|
0
|
|
|
|
|
0
|
return(); |
|
7600
|
|
|
|
|
|
|
|
|
7601
|
|
|
|
|
|
|
} |
|
7602
|
|
|
|
|
|
|
|
|
7603
|
|
|
|
|
|
|
# set media white device value (255 if RGB, 0 otherwise) |
|
7604
|
0
|
0
|
|
|
|
0
|
$mwv = ($self->[1][0][$dev->[0]] =~ m/RGB_R$/) ? 255 : 0; |
|
7605
|
|
|
|
|
|
|
|
|
7606
|
|
|
|
|
|
|
# for each sample |
|
7607
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7608
|
|
|
|
|
|
|
|
|
7609
|
|
|
|
|
|
|
# if all device channels are white |
|
7610
|
0
|
0
|
|
|
|
0
|
if (@{$dev} == grep {$_ == $mwv} @{$self->[1][$i]}[@{$dev}]) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7611
|
|
|
|
|
|
|
|
|
7612
|
|
|
|
|
|
|
# if L*a*b* data |
|
7613
|
0
|
0
|
|
|
|
0
|
if ($WPxyz) { |
|
7614
|
|
|
|
|
|
|
|
|
7615
|
|
|
|
|
|
|
# convert L*a*b* values to XYZ |
|
7616
|
0
|
|
|
|
|
0
|
@XYZs = ICC::Shared::_Lab2XYZ(@{$self->[1][$i]}[@{$cols}], $WPxyz); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7617
|
|
|
|
|
|
|
|
|
7618
|
|
|
|
|
|
|
# accumulate XYZ values |
|
7619
|
0
|
|
|
|
|
0
|
$XYZ[0] += $XYZs[0]; |
|
7620
|
0
|
|
|
|
|
0
|
$XYZ[1] += $XYZs[1]; |
|
7621
|
0
|
|
|
|
|
0
|
$XYZ[2] += $XYZs[2]; |
|
7622
|
|
|
|
|
|
|
|
|
7623
|
|
|
|
|
|
|
# if XYZ data |
|
7624
|
|
|
|
|
|
|
} else { |
|
7625
|
|
|
|
|
|
|
|
|
7626
|
|
|
|
|
|
|
# accumulate XYZ values |
|
7627
|
0
|
|
|
|
|
0
|
$XYZ[0] += $self->[1][$i][$cols->[0]]; |
|
7628
|
0
|
|
|
|
|
0
|
$XYZ[1] += $self->[1][$i][$cols->[1]]; |
|
7629
|
0
|
|
|
|
|
0
|
$XYZ[2] += $self->[1][$i][$cols->[2]]; |
|
7630
|
|
|
|
|
|
|
|
|
7631
|
|
|
|
|
|
|
} |
|
7632
|
|
|
|
|
|
|
|
|
7633
|
|
|
|
|
|
|
# increment count |
|
7634
|
0
|
|
|
|
|
0
|
$n++; |
|
7635
|
|
|
|
|
|
|
|
|
7636
|
|
|
|
|
|
|
} |
|
7637
|
|
|
|
|
|
|
|
|
7638
|
|
|
|
|
|
|
} |
|
7639
|
|
|
|
|
|
|
|
|
7640
|
|
|
|
|
|
|
# if media white sample(s) |
|
7641
|
0
|
0
|
|
|
|
0
|
if ($n) { |
|
7642
|
|
|
|
|
|
|
|
|
7643
|
|
|
|
|
|
|
# store average XYZ values in colorimetry array, and return XYZ vector |
|
7644
|
0
|
|
|
|
|
0
|
return([@{$self->[2][3]}[@{$cols}] = map {$_/$n} @XYZ]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7645
|
|
|
|
|
|
|
|
|
7646
|
|
|
|
|
|
|
} else { |
|
7647
|
|
|
|
|
|
|
|
|
7648
|
|
|
|
|
|
|
# warning |
|
7649
|
0
|
|
|
|
|
0
|
warn('no media white sample found'); |
|
7650
|
|
|
|
|
|
|
|
|
7651
|
|
|
|
|
|
|
# return empty |
|
7652
|
0
|
|
|
|
|
0
|
return(); |
|
7653
|
|
|
|
|
|
|
|
|
7654
|
|
|
|
|
|
|
} |
|
7655
|
|
|
|
|
|
|
|
|
7656
|
|
|
|
|
|
|
} |
|
7657
|
|
|
|
|
|
|
|
|
7658
|
|
|
|
|
|
|
# compute media black point |
|
7659
|
|
|
|
|
|
|
# multiple samples are averaged |
|
7660
|
|
|
|
|
|
|
# result also stored in colorimetry array |
|
7661
|
|
|
|
|
|
|
# parameter: (object_reference, column_slice, [hash]) |
|
7662
|
|
|
|
|
|
|
# returns: (XYZ_vector) |
|
7663
|
|
|
|
|
|
|
sub _mediaBP { |
|
7664
|
|
|
|
|
|
|
|
|
7665
|
|
|
|
|
|
|
# get parameters |
|
7666
|
0
|
|
|
0
|
|
0
|
my ($self, $cols, $hash) = @_; |
|
7667
|
|
|
|
|
|
|
|
|
7668
|
|
|
|
|
|
|
# local variables |
|
7669
|
0
|
|
|
|
|
0
|
my ($WPxyz, $dev, $mbv, $n, @XYZ, @XYZs); |
|
7670
|
|
|
|
|
|
|
|
|
7671
|
|
|
|
|
|
|
# if column slice is L*a*b* |
|
7672
|
0
|
0
|
|
|
|
0
|
if ((3 == grep {$self->[1][0][$_] =~ m/LAB_[LAB]$/} @{$cols})) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7673
|
|
|
|
|
|
|
|
|
7674
|
|
|
|
|
|
|
# get illuminant white point |
|
7675
|
0
|
0
|
|
|
|
0
|
$WPxyz = defined($self->[2][2][$cols->[0]]) ? [@{$self->[2][2]}[@{$cols}]] : ICC::Shared::D50; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7676
|
|
|
|
|
|
|
|
|
7677
|
|
|
|
|
|
|
# if column slice is not XYZ |
|
7678
|
0
|
|
|
|
|
0
|
} elsif ((3 != grep {$self->[1][0][$_] =~ m/XYZ_[XYZ]$/} @{$cols})) { |
|
|
0
|
|
|
|
|
0
|
|
|
7679
|
|
|
|
|
|
|
|
|
7680
|
|
|
|
|
|
|
# warning |
|
7681
|
0
|
|
|
|
|
0
|
warn('column slice not XYZ or L*a*b* data'); |
|
7682
|
|
|
|
|
|
|
|
|
7683
|
|
|
|
|
|
|
# return empty |
|
7684
|
0
|
|
|
|
|
0
|
return(); |
|
7685
|
|
|
|
|
|
|
|
|
7686
|
|
|
|
|
|
|
} |
|
7687
|
|
|
|
|
|
|
|
|
7688
|
|
|
|
|
|
|
# if no device data (using 'device' context) |
|
7689
|
0
|
0
|
|
|
|
0
|
if (! ($dev = device($self, {'context' => $hash->{'device'}}))) { |
|
7690
|
|
|
|
|
|
|
|
|
7691
|
|
|
|
|
|
|
# warning |
|
7692
|
0
|
|
|
|
|
0
|
warn('no device data'); |
|
7693
|
|
|
|
|
|
|
|
|
7694
|
|
|
|
|
|
|
# return empty |
|
7695
|
0
|
|
|
|
|
0
|
return(); |
|
7696
|
|
|
|
|
|
|
|
|
7697
|
|
|
|
|
|
|
} |
|
7698
|
|
|
|
|
|
|
|
|
7699
|
|
|
|
|
|
|
# set media black device value (0 if RGB, 100 otherwise) |
|
7700
|
0
|
0
|
|
|
|
0
|
$mbv = ($self->[1][0][$dev->[0]] =~ m/RGB_R$/) ? 1 : 100; |
|
7701
|
|
|
|
|
|
|
|
|
7702
|
|
|
|
|
|
|
# for each sample |
|
7703
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
7704
|
|
|
|
|
|
|
|
|
7705
|
|
|
|
|
|
|
# if all device channels are black |
|
7706
|
0
|
0
|
|
|
|
0
|
if (@{$dev} == grep {$_ == $mbv} @{$self->[1][$i]}[@{$dev}]) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7707
|
|
|
|
|
|
|
|
|
7708
|
|
|
|
|
|
|
# increment count |
|
7709
|
0
|
|
|
|
|
0
|
$n++; |
|
7710
|
|
|
|
|
|
|
|
|
7711
|
|
|
|
|
|
|
# if L*a*b* data |
|
7712
|
0
|
0
|
|
|
|
0
|
if ($WPxyz) { |
|
7713
|
|
|
|
|
|
|
|
|
7714
|
|
|
|
|
|
|
# convert L*a*b* values to XYZ |
|
7715
|
0
|
|
|
|
|
0
|
@XYZs = ICC::Shared::_Lab2XYZ(@{$self->[1][$i]}[@{$cols}], $WPxyz); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7716
|
|
|
|
|
|
|
|
|
7717
|
|
|
|
|
|
|
# accumulate XYZ values |
|
7718
|
0
|
|
|
|
|
0
|
$XYZ[0] += $XYZs[0]; |
|
7719
|
0
|
|
|
|
|
0
|
$XYZ[1] += $XYZs[1]; |
|
7720
|
0
|
|
|
|
|
0
|
$XYZ[2] += $XYZs[2]; |
|
7721
|
|
|
|
|
|
|
|
|
7722
|
|
|
|
|
|
|
# if XYZ data |
|
7723
|
|
|
|
|
|
|
} else { |
|
7724
|
|
|
|
|
|
|
|
|
7725
|
|
|
|
|
|
|
# accumulate XYZ values |
|
7726
|
0
|
|
|
|
|
0
|
$XYZ[0] += $self->[1][$i][$cols->[0]]; |
|
7727
|
0
|
|
|
|
|
0
|
$XYZ[1] += $self->[1][$i][$cols->[1]]; |
|
7728
|
0
|
|
|
|
|
0
|
$XYZ[2] += $self->[1][$i][$cols->[2]]; |
|
7729
|
|
|
|
|
|
|
|
|
7730
|
|
|
|
|
|
|
} |
|
7731
|
|
|
|
|
|
|
|
|
7732
|
|
|
|
|
|
|
} |
|
7733
|
|
|
|
|
|
|
|
|
7734
|
|
|
|
|
|
|
} |
|
7735
|
|
|
|
|
|
|
|
|
7736
|
|
|
|
|
|
|
# if media black sample(s) |
|
7737
|
0
|
0
|
|
|
|
0
|
if ($n) { |
|
7738
|
|
|
|
|
|
|
|
|
7739
|
|
|
|
|
|
|
# store average XYZ values in colorimetry array, and return XYZ vector |
|
7740
|
0
|
|
|
|
|
0
|
return([@{$self->[2][4]}[@{$cols}] = map {$_/$n} @XYZ]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7741
|
|
|
|
|
|
|
|
|
7742
|
|
|
|
|
|
|
} else { |
|
7743
|
|
|
|
|
|
|
|
|
7744
|
|
|
|
|
|
|
# warning |
|
7745
|
0
|
|
|
|
|
0
|
warn('no media black sample found'); |
|
7746
|
|
|
|
|
|
|
|
|
7747
|
|
|
|
|
|
|
# return empty |
|
7748
|
0
|
|
|
|
|
0
|
return(); |
|
7749
|
|
|
|
|
|
|
|
|
7750
|
|
|
|
|
|
|
} |
|
7751
|
|
|
|
|
|
|
|
|
7752
|
|
|
|
|
|
|
} |
|
7753
|
|
|
|
|
|
|
|
|
7754
|
|
|
|
|
|
|
# make SAMPLE_ID hash |
|
7755
|
|
|
|
|
|
|
# if no SAMPLE_ID field, hash is initialized |
|
7756
|
|
|
|
|
|
|
# parameter: (object_reference) |
|
7757
|
|
|
|
|
|
|
sub _makeSampleID { |
|
7758
|
|
|
|
|
|
|
|
|
7759
|
|
|
|
|
|
|
# get object reference |
|
7760
|
24
|
|
|
24
|
|
38
|
my $self = shift(); |
|
7761
|
|
|
|
|
|
|
|
|
7762
|
|
|
|
|
|
|
# if SAMPLE_ID column(s) exist |
|
7763
|
24
|
100
|
|
|
|
43
|
if (my @id = grep {$self->[1][0][$_] =~ m/^(?:.*\|)?(?:SAMPLE_ID|SampleID)$/} (0 .. $#{$self->[1][0]})) { |
|
|
609
|
|
|
|
|
920
|
|
|
|
24
|
|
|
|
|
56
|
|
|
7764
|
|
|
|
|
|
|
|
|
7765
|
|
|
|
|
|
|
# make the SAMPLE_ID hash, omitting undefined ID values |
|
7766
|
16
|
50
|
|
|
|
22
|
$self->[4] = {map {defined($self->[1][$_][$id[0]]) ? ($self->[1][$_][$id[0]], $_) : ()} (1 .. $#{$self->[1]})}; |
|
|
169
|
|
|
|
|
368
|
|
|
|
16
|
|
|
|
|
29
|
|
|
7767
|
|
|
|
|
|
|
|
|
7768
|
|
|
|
|
|
|
} else { |
|
7769
|
|
|
|
|
|
|
|
|
7770
|
|
|
|
|
|
|
# initialize the hash |
|
7771
|
8
|
|
|
|
|
21
|
$self->[4] = {}; |
|
7772
|
|
|
|
|
|
|
|
|
7773
|
|
|
|
|
|
|
} |
|
7774
|
|
|
|
|
|
|
|
|
7775
|
|
|
|
|
|
|
} |
|
7776
|
|
|
|
|
|
|
|
|
7777
|
|
|
|
|
|
|
# add colorimetry metadata |
|
7778
|
|
|
|
|
|
|
# called when creating a new object |
|
7779
|
|
|
|
|
|
|
# parameter: (object_reference) |
|
7780
|
|
|
|
|
|
|
sub _addColorMeta { |
|
7781
|
|
|
|
|
|
|
|
|
7782
|
|
|
|
|
|
|
# get object reference |
|
7783
|
22
|
|
|
22
|
|
36
|
my $self = shift(); |
|
7784
|
|
|
|
|
|
|
|
|
7785
|
|
|
|
|
|
|
# local variables |
|
7786
|
22
|
|
|
|
|
46
|
my (@cols, $hash, $illum, $spec, $nm, $str, $color, $WPxyz, @values); |
|
7787
|
|
|
|
|
|
|
|
|
7788
|
|
|
|
|
|
|
# if object contains colorimetric data |
|
7789
|
22
|
100
|
|
|
|
36
|
if (@cols = grep {$self->[1][0][$_] =~ m/^(?:(.*)\|)?(?:LAB_[LAB]|XYZ_[XYZ]|STDEV_[LABXYZ]|MEAN_DE|STDEV_DE|CHI_SQD_PAR)$/} (0 .. $#{$self->[1][0]})) { |
|
|
599
|
|
|
|
|
1432
|
|
|
|
22
|
|
|
|
|
61
|
|
|
7790
|
|
|
|
|
|
|
|
|
7791
|
|
|
|
|
|
|
# set default hash values |
|
7792
|
9
|
|
|
|
|
32
|
$hash = {'illuminant' => 'D50', 'observer' => '2'}; |
|
7793
|
|
|
|
|
|
|
|
|
7794
|
|
|
|
|
|
|
# if CxF3 'TristimulusSpec' node |
|
7795
|
9
|
50
|
100
|
|
|
43
|
if (defined($self->[0]{'CxF3_dom'}) && 0) { |
|
|
|
100
|
|
|
|
|
|
|
7796
|
|
|
|
|
|
|
|
|
7797
|
|
|
|
|
|
|
##### to be implemented ##### |
|
7798
|
|
|
|
|
|
|
|
|
7799
|
|
|
|
|
|
|
# if 'WEIGHTING_FUNCTION' keyword(s) |
|
7800
|
|
|
|
|
|
|
} elsif (@values = keyword($self, 'WEIGHTING_FUNCTION')) { |
|
7801
|
|
|
|
|
|
|
|
|
7802
|
|
|
|
|
|
|
# join values into string |
|
7803
|
7
|
|
|
|
|
16
|
$str = join(';', @values); |
|
7804
|
|
|
|
|
|
|
|
|
7805
|
|
|
|
|
|
|
# match illuminant and save in hash |
|
7806
|
7
|
50
|
|
|
|
20
|
$hash->{'illuminant'} = $1 if ($str =~ m/ILLUMINANT\s*,\s*(\w+)"/); |
|
7807
|
|
|
|
|
|
|
|
|
7808
|
|
|
|
|
|
|
# match observer and save in hash |
|
7809
|
7
|
50
|
|
|
|
17
|
$hash->{'observer'} = $1 if ($str =~ m/OBSERVER\s*,\s*(\d+).*"/); |
|
7810
|
|
|
|
|
|
|
|
|
7811
|
|
|
|
|
|
|
} |
|
7812
|
|
|
|
|
|
|
|
|
7813
|
|
|
|
|
|
|
# if non-standard illuminant |
|
7814
|
9
|
50
|
33
|
|
|
42
|
if ($hash->{'illuminant'} ne 'D50' || $hash->{'observer'} ne '2') { |
|
7815
|
|
|
|
|
|
|
|
|
7816
|
|
|
|
|
|
|
# make an empty 'Color.pm' object |
|
7817
|
0
|
|
|
|
|
0
|
$color = ICC::Support::Color->new(); |
|
7818
|
|
|
|
|
|
|
|
|
7819
|
|
|
|
|
|
|
# if illuminant is an ARRAY reference |
|
7820
|
0
|
0
|
|
|
|
0
|
if (ref($hash->{'illuminant'}) eq 'ARRAY') { |
|
7821
|
|
|
|
|
|
|
|
|
7822
|
|
|
|
|
|
|
# initialize object for CIE method |
|
7823
|
0
|
|
|
|
|
0
|
ICC::Support::Color::_cie($color, $hash); |
|
7824
|
|
|
|
|
|
|
|
|
7825
|
|
|
|
|
|
|
} else { |
|
7826
|
|
|
|
|
|
|
|
|
7827
|
|
|
|
|
|
|
# initialize object for ASTM method |
|
7828
|
0
|
|
|
|
|
0
|
ICC::Support::Color::_astm($color, $hash); |
|
7829
|
|
|
|
|
|
|
|
|
7830
|
|
|
|
|
|
|
} |
|
7831
|
|
|
|
|
|
|
|
|
7832
|
|
|
|
|
|
|
# use computed white point |
|
7833
|
0
|
|
|
|
|
0
|
$WPxyz = $color->iwtpt(); |
|
7834
|
|
|
|
|
|
|
|
|
7835
|
|
|
|
|
|
|
} else { |
|
7836
|
|
|
|
|
|
|
|
|
7837
|
|
|
|
|
|
|
# use D50 |
|
7838
|
9
|
|
|
|
|
12
|
$WPxyz = ICC::Shared::D50; |
|
7839
|
|
|
|
|
|
|
|
|
7840
|
|
|
|
|
|
|
} |
|
7841
|
|
|
|
|
|
|
|
|
7842
|
|
|
|
|
|
|
# for each colorimetric field |
|
7843
|
9
|
|
|
|
|
19
|
for my $i (@cols) { |
|
7844
|
|
|
|
|
|
|
|
|
7845
|
|
|
|
|
|
|
# if field name ends in L or X |
|
7846
|
48
|
100
|
|
|
|
152
|
if ($self->[1][0][$i] =~ m/[LX]$/) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
7847
|
|
|
|
|
|
|
|
|
7848
|
|
|
|
|
|
|
# save WP X-value |
|
7849
|
16
|
|
|
|
|
36
|
$self->[2][2][$i] = $WPxyz->[0]; |
|
7850
|
|
|
|
|
|
|
|
|
7851
|
|
|
|
|
|
|
# if field name ends in A or Y |
|
7852
|
|
|
|
|
|
|
} elsif ($self->[1][0][$i] =~ m/[AY]$/) { |
|
7853
|
|
|
|
|
|
|
|
|
7854
|
|
|
|
|
|
|
# save WP Y-value |
|
7855
|
16
|
|
|
|
|
28
|
$self->[2][2][$i] = $WPxyz->[1]; |
|
7856
|
|
|
|
|
|
|
|
|
7857
|
|
|
|
|
|
|
# if field name ends in B or Z |
|
7858
|
|
|
|
|
|
|
} elsif ($self->[1][0][$i] =~ m/[BZ]$/) { |
|
7859
|
|
|
|
|
|
|
|
|
7860
|
|
|
|
|
|
|
# save WP Z-value |
|
7861
|
16
|
|
|
|
|
55
|
$self->[2][2][$i] = $WPxyz->[2]; |
|
7862
|
|
|
|
|
|
|
|
|
7863
|
|
|
|
|
|
|
} |
|
7864
|
|
|
|
|
|
|
|
|
7865
|
|
|
|
|
|
|
} |
|
7866
|
|
|
|
|
|
|
|
|
7867
|
|
|
|
|
|
|
} |
|
7868
|
|
|
|
|
|
|
|
|
7869
|
|
|
|
|
|
|
} |
|
7870
|
|
|
|
|
|
|
|
|
7871
|
|
|
|
|
|
|
# read chart from list of data files |
|
7872
|
|
|
|
|
|
|
# averages color measurement data (spectral, XYZ, L*a*b* or density) |
|
7873
|
|
|
|
|
|
|
# files must have identical structure (rows and cols) |
|
7874
|
|
|
|
|
|
|
# parameters: (object_reference, ref_to_file_list, hash) |
|
7875
|
|
|
|
|
|
|
# returns: (number_of_files_averaged) |
|
7876
|
|
|
|
|
|
|
sub _readChartAvg { |
|
7877
|
|
|
|
|
|
|
|
|
7878
|
|
|
|
|
|
|
# get parameters |
|
7879
|
1
|
|
|
1
|
|
4
|
my ($self, $list, $hash) = @_; |
|
7880
|
|
|
|
|
|
|
|
|
7881
|
|
|
|
|
|
|
# local variables |
|
7882
|
1
|
|
|
|
|
4
|
my ($n, $result, $c1, $c2, $c3, $keys, $temp, @xyz); |
|
7883
|
1
|
|
|
|
|
0
|
my ($charts, $fstat, @ctx1, @ctx2, $add_hash); |
|
7884
|
|
|
|
|
|
|
|
|
7885
|
|
|
|
|
|
|
# initialize file count |
|
7886
|
1
|
|
|
|
|
1
|
$n = 0; |
|
7887
|
|
|
|
|
|
|
|
|
7888
|
|
|
|
|
|
|
# if hash is defined |
|
7889
|
1
|
50
|
|
|
|
3
|
if (defined($hash)) { |
|
7890
|
|
|
|
|
|
|
|
|
7891
|
|
|
|
|
|
|
# for each hash key |
|
7892
|
1
|
|
|
|
|
2
|
for (keys(%{$hash})) { |
|
|
1
|
|
|
|
|
4
|
|
|
7893
|
|
|
|
|
|
|
|
|
7894
|
|
|
|
|
|
|
# if XYZ based stat requested |
|
7895
|
0
|
0
|
|
|
|
0
|
if (m/^STDEV_XYZ$/) { |
|
|
|
0
|
|
|
|
|
|
|
7896
|
|
|
|
|
|
|
|
|
7897
|
|
|
|
|
|
|
# if value is a scalar |
|
7898
|
0
|
0
|
|
|
|
0
|
if (! ref($hash->{$_})) { |
|
|
|
0
|
|
|
|
|
|
|
7899
|
|
|
|
|
|
|
|
|
7900
|
|
|
|
|
|
|
# save XYZ context |
|
7901
|
0
|
|
|
|
|
0
|
push(@ctx1, $hash->{$_}); |
|
7902
|
|
|
|
|
|
|
|
|
7903
|
|
|
|
|
|
|
} elsif (ref($hash->{$_}) eq 'ARRAY') { |
|
7904
|
|
|
|
|
|
|
|
|
7905
|
|
|
|
|
|
|
# save XYZ contexts |
|
7906
|
0
|
|
|
|
|
0
|
push(@ctx1, @{$hash->{$_}}); |
|
|
0
|
|
|
|
|
0
|
|
|
7907
|
|
|
|
|
|
|
|
|
7908
|
|
|
|
|
|
|
} |
|
7909
|
|
|
|
|
|
|
|
|
7910
|
|
|
|
|
|
|
# increment flag |
|
7911
|
0
|
|
|
|
|
0
|
$fstat++; |
|
7912
|
|
|
|
|
|
|
|
|
7913
|
|
|
|
|
|
|
# if L*a*b* based stat requested |
|
7914
|
|
|
|
|
|
|
} elsif (m/^(MEAN_DE|STDEV_LAB|CHI_SQD_PAR)$/) { |
|
7915
|
|
|
|
|
|
|
|
|
7916
|
|
|
|
|
|
|
# if value is a scalar |
|
7917
|
0
|
0
|
|
|
|
0
|
if (! ref($hash->{$_})) { |
|
|
|
0
|
|
|
|
|
|
|
7918
|
|
|
|
|
|
|
|
|
7919
|
|
|
|
|
|
|
# save L*a*b* context |
|
7920
|
0
|
|
|
|
|
0
|
push(@ctx2, $hash->{$_}); |
|
7921
|
|
|
|
|
|
|
|
|
7922
|
|
|
|
|
|
|
} elsif (ref($hash->{$_}) eq 'ARRAY') { |
|
7923
|
|
|
|
|
|
|
|
|
7924
|
|
|
|
|
|
|
# save L*a*b* contexts |
|
7925
|
0
|
|
|
|
|
0
|
push(@ctx2, @{$hash->{$_}}); |
|
|
0
|
|
|
|
|
0
|
|
|
7926
|
|
|
|
|
|
|
|
|
7927
|
|
|
|
|
|
|
} |
|
7928
|
|
|
|
|
|
|
|
|
7929
|
|
|
|
|
|
|
# increment flag |
|
7930
|
0
|
|
|
|
|
0
|
$fstat++; |
|
7931
|
|
|
|
|
|
|
|
|
7932
|
|
|
|
|
|
|
} |
|
7933
|
|
|
|
|
|
|
|
|
7934
|
|
|
|
|
|
|
} |
|
7935
|
|
|
|
|
|
|
|
|
7936
|
|
|
|
|
|
|
} |
|
7937
|
|
|
|
|
|
|
|
|
7938
|
|
|
|
|
|
|
# for each file |
|
7939
|
1
|
|
|
|
|
2
|
for my $file (@{$list}) { |
|
|
1
|
|
|
|
|
4
|
|
|
7940
|
|
|
|
|
|
|
|
|
7941
|
|
|
|
|
|
|
# if first file |
|
7942
|
4
|
100
|
|
|
|
9
|
if ($n == 0) { |
|
7943
|
|
|
|
|
|
|
|
|
7944
|
|
|
|
|
|
|
# if file read successfully |
|
7945
|
1
|
50
|
|
|
|
4
|
if (! ($result = _readChart($self, $file, $hash))) { |
|
7946
|
|
|
|
|
|
|
|
|
7947
|
|
|
|
|
|
|
# add colorimetric metadata |
|
7948
|
1
|
|
|
|
|
4
|
_addColorMeta($self); |
|
7949
|
|
|
|
|
|
|
|
|
7950
|
|
|
|
|
|
|
# make format key string |
|
7951
|
1
|
50
|
|
|
|
2
|
$keys = join(':', map {defined() ? $_ : '-'} @{$self->[1][0]}); |
|
|
12
|
|
|
|
|
21
|
|
|
|
1
|
|
|
|
|
3
|
|
|
7952
|
|
|
|
|
|
|
|
|
7953
|
|
|
|
|
|
|
# for each XYZ context |
|
7954
|
1
|
|
|
|
|
2
|
for my $ctx (@ctx1) { |
|
7955
|
|
|
|
|
|
|
|
|
7956
|
|
|
|
|
|
|
# copy the hash |
|
7957
|
0
|
|
|
|
|
0
|
$add_hash = Storable::dclone($hash); |
|
7958
|
|
|
|
|
|
|
|
|
7959
|
|
|
|
|
|
|
# set the context (undef for no context) |
|
7960
|
0
|
0
|
0
|
|
|
0
|
$add_hash->{'context'} = defined($ctx) && length($ctx) ? $ctx : undef; |
|
7961
|
|
|
|
|
|
|
|
|
7962
|
|
|
|
|
|
|
# delete the 'added' context |
|
7963
|
0
|
|
|
|
|
0
|
delete($add_hash->{'added'}); |
|
7964
|
|
|
|
|
|
|
|
|
7965
|
|
|
|
|
|
|
# add the XYZ values |
|
7966
|
0
|
|
|
|
|
0
|
add_xyz($self, $add_hash); |
|
7967
|
|
|
|
|
|
|
|
|
7968
|
|
|
|
|
|
|
} |
|
7969
|
|
|
|
|
|
|
|
|
7970
|
|
|
|
|
|
|
# for each L*a*b* context |
|
7971
|
1
|
|
|
|
|
3
|
for my $ctx (@ctx2) { |
|
7972
|
|
|
|
|
|
|
|
|
7973
|
|
|
|
|
|
|
# copy the hash |
|
7974
|
0
|
|
|
|
|
0
|
$add_hash = Storable::dclone($hash); |
|
7975
|
|
|
|
|
|
|
|
|
7976
|
|
|
|
|
|
|
# set the context (undef for no context) |
|
7977
|
0
|
0
|
0
|
|
|
0
|
$add_hash->{'context'} = defined($ctx) && length($ctx) ? $ctx : undef; |
|
7978
|
|
|
|
|
|
|
|
|
7979
|
|
|
|
|
|
|
# delete the 'added' context |
|
7980
|
0
|
|
|
|
|
0
|
delete($add_hash->{'added'}); |
|
7981
|
|
|
|
|
|
|
|
|
7982
|
|
|
|
|
|
|
# add the L*a*b* values |
|
7983
|
0
|
|
|
|
|
0
|
add_lab($self, $add_hash); |
|
7984
|
|
|
|
|
|
|
|
|
7985
|
|
|
|
|
|
|
} |
|
7986
|
|
|
|
|
|
|
|
|
7987
|
|
|
|
|
|
|
# save copy of chart data, if needed for stats |
|
7988
|
1
|
50
|
|
|
|
3
|
$charts->[0] = Storable::dclone($self->[1]) if ($fstat); |
|
7989
|
|
|
|
|
|
|
|
|
7990
|
|
|
|
|
|
|
# get averaging groups |
|
7991
|
1
|
|
|
|
|
5
|
($c1, $c2, $c3) = _avg_groups($self, $hash); |
|
7992
|
|
|
|
|
|
|
|
|
7993
|
|
|
|
|
|
|
# if there are L*a*b* or density groups |
|
7994
|
1
|
50
|
33
|
|
|
2
|
if (@{$c2} || @{$c3}) { |
|
|
1
|
|
|
|
|
4
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7995
|
|
|
|
|
|
|
|
|
7996
|
|
|
|
|
|
|
# for each sample |
|
7997
|
1
|
|
|
|
|
1
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
1
|
|
|
|
|
4
|
|
|
7998
|
|
|
|
|
|
|
|
|
7999
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
8000
|
10
|
|
|
|
|
12
|
for (my $j = 0; $j < @{$c2}; $j += 3) { |
|
|
20
|
|
|
|
|
29
|
|
|
8001
|
|
|
|
|
|
|
|
|
8002
|
|
|
|
|
|
|
# convert to L*a*b* values to xyz |
|
8003
|
10
|
|
|
|
|
14
|
@{$self->[1][$i]}[@{$c2}[$j .. $j + 2]] = ICC::Shared::_Lab2xyz(@{$self->[1][$i]}[@{$c2}[$j .. $j + 2]]); |
|
|
10
|
|
|
|
|
24
|
|
|
|
10
|
|
|
|
|
13
|
|
|
|
10
|
|
|
|
|
20
|
|
|
|
10
|
|
|
|
|
12
|
|
|
8004
|
|
|
|
|
|
|
|
|
8005
|
|
|
|
|
|
|
} |
|
8006
|
|
|
|
|
|
|
|
|
8007
|
|
|
|
|
|
|
# for each density column |
|
8008
|
10
|
|
|
|
|
11
|
for my $j (@{$c3}) { |
|
|
10
|
|
|
|
|
18
|
|
|
8009
|
|
|
|
|
|
|
|
|
8010
|
|
|
|
|
|
|
# convert to density to reflectance |
|
8011
|
0
|
|
|
|
|
0
|
$self->[1][$i][$j] = POSIX::pow(10, -$self->[1][$i][$j]); |
|
8012
|
|
|
|
|
|
|
|
|
8013
|
|
|
|
|
|
|
} |
|
8014
|
|
|
|
|
|
|
|
|
8015
|
|
|
|
|
|
|
} |
|
8016
|
|
|
|
|
|
|
|
|
8017
|
|
|
|
|
|
|
} |
|
8018
|
|
|
|
|
|
|
|
|
8019
|
|
|
|
|
|
|
# increment file count |
|
8020
|
1
|
|
|
|
|
3
|
$n++; |
|
8021
|
|
|
|
|
|
|
|
|
8022
|
|
|
|
|
|
|
} else { |
|
8023
|
|
|
|
|
|
|
|
|
8024
|
|
|
|
|
|
|
# print warning |
|
8025
|
0
|
|
|
|
|
0
|
warn("chart $file $result, ignored\n"); |
|
8026
|
|
|
|
|
|
|
|
|
8027
|
|
|
|
|
|
|
} |
|
8028
|
|
|
|
|
|
|
|
|
8029
|
|
|
|
|
|
|
} else { |
|
8030
|
|
|
|
|
|
|
|
|
8031
|
|
|
|
|
|
|
# make temporary Chart object |
|
8032
|
3
|
|
|
|
|
18
|
$temp = ICC::Support::Chart->new(); |
|
8033
|
|
|
|
|
|
|
|
|
8034
|
|
|
|
|
|
|
# if file read successfully |
|
8035
|
3
|
50
|
|
|
|
6
|
if (! ($result = _readChart($temp, $file, $hash))) { |
|
8036
|
|
|
|
|
|
|
|
|
8037
|
|
|
|
|
|
|
# if charts have same structure (rows and cols) |
|
8038
|
3
|
50
|
33
|
|
|
5
|
if ($#{$self->[1]} == $#{$temp->[1]} && $keys eq join(':', map {defined() ? $_ : '-'} @{$temp->[1][0]})) { |
|
|
3
|
50
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
9
|
|
|
|
36
|
|
|
|
|
64
|
|
|
|
3
|
|
|
|
|
7
|
|
|
8039
|
|
|
|
|
|
|
|
|
8040
|
|
|
|
|
|
|
# for each XYZ context |
|
8041
|
3
|
|
|
|
|
6
|
for my $ctx (@ctx1) { |
|
8042
|
|
|
|
|
|
|
|
|
8043
|
|
|
|
|
|
|
# copy the hash |
|
8044
|
0
|
|
|
|
|
0
|
$add_hash = Storable::dclone($hash); |
|
8045
|
|
|
|
|
|
|
|
|
8046
|
|
|
|
|
|
|
# set the context (undef for no context) |
|
8047
|
0
|
0
|
0
|
|
|
0
|
$add_hash->{'context'} = defined($ctx) && length($ctx) ? $ctx : undef; |
|
8048
|
|
|
|
|
|
|
|
|
8049
|
|
|
|
|
|
|
# delete the 'added' context |
|
8050
|
0
|
|
|
|
|
0
|
delete($add_hash->{'added'}); |
|
8051
|
|
|
|
|
|
|
|
|
8052
|
|
|
|
|
|
|
# add the XYZ values |
|
8053
|
0
|
|
|
|
|
0
|
add_xyz($temp, $add_hash); |
|
8054
|
|
|
|
|
|
|
|
|
8055
|
|
|
|
|
|
|
} |
|
8056
|
|
|
|
|
|
|
|
|
8057
|
|
|
|
|
|
|
# for each L*a*b* context |
|
8058
|
3
|
|
|
|
|
4
|
for my $ctx (@ctx2) { |
|
8059
|
|
|
|
|
|
|
|
|
8060
|
|
|
|
|
|
|
# copy the hash |
|
8061
|
0
|
|
|
|
|
0
|
$add_hash = Storable::dclone($hash); |
|
8062
|
|
|
|
|
|
|
|
|
8063
|
|
|
|
|
|
|
# set the context (undef for no context) |
|
8064
|
0
|
0
|
0
|
|
|
0
|
$add_hash->{'context'} = defined($ctx) && length($ctx) ? $ctx : undef; |
|
8065
|
|
|
|
|
|
|
|
|
8066
|
|
|
|
|
|
|
# delete the 'added' context |
|
8067
|
0
|
|
|
|
|
0
|
delete($add_hash->{'added'}); |
|
8068
|
|
|
|
|
|
|
|
|
8069
|
|
|
|
|
|
|
# add the L*a*b* values |
|
8070
|
0
|
|
|
|
|
0
|
add_lab($temp, $add_hash); |
|
8071
|
|
|
|
|
|
|
|
|
8072
|
|
|
|
|
|
|
} |
|
8073
|
|
|
|
|
|
|
|
|
8074
|
|
|
|
|
|
|
# save copy of chart data, if needed for stats |
|
8075
|
3
|
50
|
|
|
|
8
|
$charts->[$n] = $temp->[1] if ($fstat); |
|
8076
|
|
|
|
|
|
|
|
|
8077
|
|
|
|
|
|
|
# for each sample |
|
8078
|
3
|
|
|
|
|
5
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
3
|
|
|
|
|
8
|
|
|
8079
|
|
|
|
|
|
|
|
|
8080
|
|
|
|
|
|
|
# for each linear column |
|
8081
|
30
|
|
|
|
|
31
|
for my $j (@{$c1}) { |
|
|
30
|
|
|
|
|
36
|
|
|
8082
|
|
|
|
|
|
|
|
|
8083
|
|
|
|
|
|
|
# add temp value |
|
8084
|
90
|
|
|
|
|
143
|
$self->[1][$i][$j] += $temp->[1][$i][$j]; |
|
8085
|
|
|
|
|
|
|
|
|
8086
|
|
|
|
|
|
|
} |
|
8087
|
|
|
|
|
|
|
|
|
8088
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
8089
|
30
|
|
|
|
|
36
|
for (my $j = 0; $j < @{$c2}; $j += 3) { |
|
|
60
|
|
|
|
|
94
|
|
|
8090
|
|
|
|
|
|
|
|
|
8091
|
|
|
|
|
|
|
# get temp xyz values |
|
8092
|
30
|
|
|
|
|
32
|
@xyz = ICC::Shared::_Lab2xyz(@{$temp->[1][$i]}[@{$c2}[$j .. $j + 2]]); |
|
|
30
|
|
|
|
|
51
|
|
|
|
30
|
|
|
|
|
32
|
|
|
8093
|
|
|
|
|
|
|
|
|
8094
|
|
|
|
|
|
|
# add to self |
|
8095
|
30
|
|
|
|
|
43
|
$self->[1][$i][$c2->[$j]] += $xyz[0]; |
|
8096
|
30
|
|
|
|
|
37
|
$self->[1][$i][$c2->[$j + 1]] += $xyz[1]; |
|
8097
|
30
|
|
|
|
|
43
|
$self->[1][$i][$c2->[$j + 2]] += $xyz[2]; |
|
8098
|
|
|
|
|
|
|
|
|
8099
|
|
|
|
|
|
|
} |
|
8100
|
|
|
|
|
|
|
|
|
8101
|
|
|
|
|
|
|
# for each density column |
|
8102
|
30
|
|
|
|
|
33
|
for my $j (@{$c3}) { |
|
|
30
|
|
|
|
|
39
|
|
|
8103
|
|
|
|
|
|
|
|
|
8104
|
|
|
|
|
|
|
# add temp reflectance |
|
8105
|
0
|
|
|
|
|
0
|
$self->[1][$i][$j] += POSIX::pow(10, -$temp->[1][$i][$j]); |
|
8106
|
|
|
|
|
|
|
|
|
8107
|
|
|
|
|
|
|
} |
|
8108
|
|
|
|
|
|
|
|
|
8109
|
|
|
|
|
|
|
} |
|
8110
|
|
|
|
|
|
|
|
|
8111
|
|
|
|
|
|
|
# increment file count |
|
8112
|
3
|
|
|
|
|
10
|
$n++; |
|
8113
|
|
|
|
|
|
|
|
|
8114
|
|
|
|
|
|
|
} else { |
|
8115
|
|
|
|
|
|
|
|
|
8116
|
|
|
|
|
|
|
# print warning |
|
8117
|
0
|
|
|
|
|
0
|
warn("chart $file has different structure, ignored\n"); |
|
8118
|
|
|
|
|
|
|
|
|
8119
|
|
|
|
|
|
|
} |
|
8120
|
|
|
|
|
|
|
|
|
8121
|
|
|
|
|
|
|
} else { |
|
8122
|
|
|
|
|
|
|
|
|
8123
|
|
|
|
|
|
|
# print warning |
|
8124
|
0
|
|
|
|
|
0
|
warn("chart $file $result, ignored\n"); |
|
8125
|
|
|
|
|
|
|
|
|
8126
|
|
|
|
|
|
|
} |
|
8127
|
|
|
|
|
|
|
|
|
8128
|
|
|
|
|
|
|
} |
|
8129
|
|
|
|
|
|
|
|
|
8130
|
|
|
|
|
|
|
} |
|
8131
|
|
|
|
|
|
|
|
|
8132
|
|
|
|
|
|
|
# if any files were read |
|
8133
|
1
|
50
|
|
|
|
4
|
if ($n) { |
|
8134
|
|
|
|
|
|
|
|
|
8135
|
|
|
|
|
|
|
# if there are measurement values |
|
8136
|
1
|
0
|
33
|
|
|
2
|
if (@{$c1} || @{$c2} || @{$c3}) { |
|
|
1
|
|
33
|
|
|
4
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8137
|
|
|
|
|
|
|
|
|
8138
|
|
|
|
|
|
|
# for each sample |
|
8139
|
1
|
|
|
|
|
1
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
1
|
|
|
|
|
3
|
|
|
8140
|
|
|
|
|
|
|
|
|
8141
|
|
|
|
|
|
|
# for each measurement column |
|
8142
|
10
|
|
|
|
|
10
|
for my $j (@{$c1}, @{$c2}, @{$c3}) { |
|
|
10
|
|
|
|
|
11
|
|
|
|
10
|
|
|
|
|
12
|
|
|
|
10
|
|
|
|
|
13
|
|
|
8143
|
|
|
|
|
|
|
|
|
8144
|
|
|
|
|
|
|
# divide by n |
|
8145
|
60
|
|
|
|
|
67
|
$self->[1][$i][$j] /= $n; |
|
8146
|
|
|
|
|
|
|
|
|
8147
|
|
|
|
|
|
|
} |
|
8148
|
|
|
|
|
|
|
|
|
8149
|
|
|
|
|
|
|
# for each group of L*a*b* columns |
|
8150
|
10
|
|
|
|
|
12
|
for (my $j = 0; $j < @{$c2}; $j += 3) { |
|
|
20
|
|
|
|
|
31
|
|
|
8151
|
|
|
|
|
|
|
|
|
8152
|
|
|
|
|
|
|
# convert to xyz values to L*a*b* |
|
8153
|
10
|
|
|
|
|
14
|
@{$self->[1][$i]}[@{$c2}[$j .. $j + 2]] = ICC::Shared::_xyz2Lab(@{$self->[1][$i]}[@{$c2}[$j .. $j + 2]]); |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
14
|
|
|
|
10
|
|
|
|
|
20
|
|
|
|
10
|
|
|
|
|
11
|
|
|
8154
|
|
|
|
|
|
|
|
|
8155
|
|
|
|
|
|
|
} |
|
8156
|
|
|
|
|
|
|
|
|
8157
|
|
|
|
|
|
|
# for each density column |
|
8158
|
10
|
|
|
|
|
11
|
for my $j (@{$c3}) { |
|
|
10
|
|
|
|
|
15
|
|
|
8159
|
|
|
|
|
|
|
|
|
8160
|
|
|
|
|
|
|
# convert reflectance to density |
|
8161
|
0
|
|
|
|
|
0
|
$self->[1][$i][$j] = -POSIX::log10($self->[1][$i][$j]); |
|
8162
|
|
|
|
|
|
|
|
|
8163
|
|
|
|
|
|
|
} |
|
8164
|
|
|
|
|
|
|
|
|
8165
|
|
|
|
|
|
|
} |
|
8166
|
|
|
|
|
|
|
|
|
8167
|
|
|
|
|
|
|
} |
|
8168
|
|
|
|
|
|
|
|
|
8169
|
|
|
|
|
|
|
# add ISO statistics, if requested |
|
8170
|
1
|
50
|
|
|
|
3
|
_addStats($self, $charts, $hash) if ($fstat); |
|
8171
|
|
|
|
|
|
|
|
|
8172
|
|
|
|
|
|
|
# print message |
|
8173
|
1
|
|
|
|
|
53
|
print "$n files read in directory $self->[0]{'file_path'}\n\n"; |
|
8174
|
|
|
|
|
|
|
|
|
8175
|
|
|
|
|
|
|
# save number of files read |
|
8176
|
1
|
|
|
|
|
6
|
$self->[0]{'files_read'} = $n; |
|
8177
|
|
|
|
|
|
|
|
|
8178
|
|
|
|
|
|
|
} |
|
8179
|
|
|
|
|
|
|
|
|
8180
|
|
|
|
|
|
|
# return |
|
8181
|
1
|
|
|
|
|
17
|
return($n); |
|
8182
|
|
|
|
|
|
|
|
|
8183
|
|
|
|
|
|
|
} |
|
8184
|
|
|
|
|
|
|
|
|
8185
|
|
|
|
|
|
|
# add ISO statistics |
|
8186
|
|
|
|
|
|
|
# the object_reference contains the mean values |
|
8187
|
|
|
|
|
|
|
# the individual charts are in the array_of_chart_objects |
|
8188
|
|
|
|
|
|
|
# parameters: (object_reference, array_of_chart_objects, hash) |
|
8189
|
|
|
|
|
|
|
sub _addStats { |
|
8190
|
|
|
|
|
|
|
|
|
8191
|
|
|
|
|
|
|
# get parameters |
|
8192
|
0
|
|
|
0
|
|
0
|
my ($self, $charts, $hash) = @_; |
|
8193
|
|
|
|
|
|
|
|
|
8194
|
|
|
|
|
|
|
# local variables |
|
8195
|
0
|
|
|
|
|
0
|
my (@ctx, $cols, $scols); |
|
8196
|
|
|
|
|
|
|
|
|
8197
|
|
|
|
|
|
|
# for each hash key |
|
8198
|
0
|
|
|
|
|
0
|
for (keys(%{$hash})) { |
|
|
0
|
|
|
|
|
0
|
|
|
8199
|
|
|
|
|
|
|
|
|
8200
|
|
|
|
|
|
|
# if value is a scalar |
|
8201
|
0
|
0
|
|
|
|
0
|
if (! ref($hash->{$_})) { |
|
|
|
0
|
|
|
|
|
|
|
8202
|
|
|
|
|
|
|
|
|
8203
|
|
|
|
|
|
|
# save context value |
|
8204
|
0
|
|
|
|
|
0
|
@ctx = ($hash->{$_}); |
|
8205
|
|
|
|
|
|
|
|
|
8206
|
|
|
|
|
|
|
} elsif (ref($hash->{$_}) eq 'ARRAY') { |
|
8207
|
|
|
|
|
|
|
|
|
8208
|
|
|
|
|
|
|
# save context values |
|
8209
|
0
|
|
|
|
|
0
|
@ctx = @{$hash->{$_}}; |
|
|
0
|
|
|
|
|
0
|
|
|
8210
|
|
|
|
|
|
|
|
|
8211
|
|
|
|
|
|
|
} |
|
8212
|
|
|
|
|
|
|
|
|
8213
|
|
|
|
|
|
|
# if 'STDEV_XYZ' |
|
8214
|
0
|
0
|
|
|
|
0
|
if (m/^STDEV_XYZ$/) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
8215
|
|
|
|
|
|
|
|
|
8216
|
|
|
|
|
|
|
# for each context |
|
8217
|
0
|
|
|
|
|
0
|
for my $context (@ctx) { |
|
8218
|
|
|
|
|
|
|
|
|
8219
|
|
|
|
|
|
|
# resolve context value |
|
8220
|
0
|
0
|
0
|
|
|
0
|
$context = defined($context) && length($context) ? $context : undef; |
|
8221
|
|
|
|
|
|
|
|
|
8222
|
|
|
|
|
|
|
# if no STDEV_XYZ columns with context |
|
8223
|
0
|
0
|
|
|
|
0
|
if (! test($self, 'STDEVXYZ', $context)) { |
|
8224
|
|
|
|
|
|
|
|
|
8225
|
|
|
|
|
|
|
# get XYZ columns |
|
8226
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($context) ? "$context|$_" : $_} qw(XYZ_X XYZ_Y XYZ_Z)); |
|
|
0
|
|
|
|
|
0
|
|
|
8227
|
|
|
|
|
|
|
|
|
8228
|
|
|
|
|
|
|
# add STDEV_XYZ columns |
|
8229
|
0
|
0
|
|
|
|
0
|
$scols = add_fmt($self, map {defined($context) ? "$context|$_" : $_} qw(STDEV_X STDEV_Y STDEV_Z)); |
|
|
0
|
|
|
|
|
0
|
|
|
8230
|
|
|
|
|
|
|
|
|
8231
|
|
|
|
|
|
|
# for each XYZ |
|
8232
|
0
|
|
|
|
|
0
|
for my $i (0 .. 2) { |
|
8233
|
|
|
|
|
|
|
|
|
8234
|
|
|
|
|
|
|
# add STDEV_XYZ values |
|
8235
|
0
|
|
|
|
|
0
|
_addStdDevCol($self, $charts, $cols->[$i], $scols->[$i]); |
|
8236
|
|
|
|
|
|
|
|
|
8237
|
|
|
|
|
|
|
} |
|
8238
|
|
|
|
|
|
|
|
|
8239
|
|
|
|
|
|
|
} |
|
8240
|
|
|
|
|
|
|
|
|
8241
|
|
|
|
|
|
|
# set origin |
|
8242
|
0
|
|
|
|
|
0
|
@{$self->[2][0]}[@{$scols}] = ($cols) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8243
|
|
|
|
|
|
|
|
|
8244
|
|
|
|
|
|
|
# save illuminant white point |
|
8245
|
0
|
|
|
|
|
0
|
@{$self->[2][2]}[@{$scols}] = @{$self->[2][2]}[@{$cols}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8246
|
|
|
|
|
|
|
|
|
8247
|
|
|
|
|
|
|
} |
|
8248
|
|
|
|
|
|
|
|
|
8249
|
|
|
|
|
|
|
# if 'STDEV_LAB' or 'CHI_SQD_PAR' |
|
8250
|
|
|
|
|
|
|
} elsif (m/^(STDEV_LAB|CHI_SQD_PAR)$/) { |
|
8251
|
|
|
|
|
|
|
|
|
8252
|
|
|
|
|
|
|
# for each context |
|
8253
|
0
|
|
|
|
|
0
|
for my $context (@ctx) { |
|
8254
|
|
|
|
|
|
|
|
|
8255
|
|
|
|
|
|
|
# resolve context value |
|
8256
|
0
|
0
|
0
|
|
|
0
|
$context = defined($context) && length($context) ? $context : undef; |
|
8257
|
|
|
|
|
|
|
|
|
8258
|
|
|
|
|
|
|
# if no STDEV_LAB columns with context |
|
8259
|
0
|
0
|
|
|
|
0
|
if (! test($self, 'STDEVLAB', $context)) { |
|
8260
|
|
|
|
|
|
|
|
|
8261
|
|
|
|
|
|
|
# get L*a*b* columns |
|
8262
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($context) ? "$context|$_" : $_} qw(LAB_L LAB_A LAB_B)); |
|
|
0
|
|
|
|
|
0
|
|
|
8263
|
|
|
|
|
|
|
|
|
8264
|
|
|
|
|
|
|
# add STDEV_LAB columns |
|
8265
|
0
|
0
|
|
|
|
0
|
$scols = add_fmt($self, map {defined($context) ? "$context|$_" : $_} qw(STDEV_L STDEV_A STDEV_B)); |
|
|
0
|
|
|
|
|
0
|
|
|
8266
|
|
|
|
|
|
|
|
|
8267
|
|
|
|
|
|
|
# for each L*a*b* |
|
8268
|
0
|
|
|
|
|
0
|
for my $i (0 .. 2) { |
|
8269
|
|
|
|
|
|
|
|
|
8270
|
|
|
|
|
|
|
# add STDEV_LAB values |
|
8271
|
0
|
|
|
|
|
0
|
_addStdDevCol($self, $charts, $cols->[$i], $scols->[$i]); |
|
8272
|
|
|
|
|
|
|
|
|
8273
|
|
|
|
|
|
|
} |
|
8274
|
|
|
|
|
|
|
|
|
8275
|
|
|
|
|
|
|
# set origin |
|
8276
|
0
|
|
|
|
|
0
|
@{$self->[2][0]}[@{$scols}] = ($cols) x 3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8277
|
|
|
|
|
|
|
|
|
8278
|
|
|
|
|
|
|
# save illuminant white point |
|
8279
|
0
|
|
|
|
|
0
|
@{$self->[2][2]}[@{$scols}] = @{$self->[2][2]}[@{$cols}]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8280
|
|
|
|
|
|
|
|
|
8281
|
|
|
|
|
|
|
} |
|
8282
|
|
|
|
|
|
|
|
|
8283
|
|
|
|
|
|
|
# if 'CHI_SQD_PAR' |
|
8284
|
0
|
0
|
|
|
|
0
|
if ($1 eq 'CHI_SQD_PAR') { |
|
8285
|
|
|
|
|
|
|
|
|
8286
|
|
|
|
|
|
|
# get STDEV_LAB columns |
|
8287
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($context) ? "$context|$_" : $_} qw(STDEV_L STDEV_A STDEV_B)); |
|
|
0
|
|
|
|
|
0
|
|
|
8288
|
|
|
|
|
|
|
|
|
8289
|
|
|
|
|
|
|
# add CHI_SQD_PAR column |
|
8290
|
0
|
0
|
|
|
|
0
|
$scols = add_fmt($self, map {defined($context) ? "$context|$_" : $_} qw(CHI_SQD_PAR)); |
|
|
0
|
|
|
|
|
0
|
|
|
8291
|
|
|
|
|
|
|
|
|
8292
|
|
|
|
|
|
|
# for each sample |
|
8293
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8294
|
|
|
|
|
|
|
|
|
8295
|
|
|
|
|
|
|
# set CHI_SQD_PAR value (average of L*a*b* standard deviations) |
|
8296
|
0
|
|
|
|
|
0
|
$self->[1][$i][$scols->[0]] = List::Util::sum(@{$self->[1][$i]}[@{$cols}])/3; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8297
|
|
|
|
|
|
|
|
|
8298
|
|
|
|
|
|
|
} |
|
8299
|
|
|
|
|
|
|
|
|
8300
|
|
|
|
|
|
|
# set origin |
|
8301
|
0
|
|
|
|
|
0
|
$self->[2][0][$scols->[0]] = $cols; |
|
8302
|
|
|
|
|
|
|
|
|
8303
|
|
|
|
|
|
|
} |
|
8304
|
|
|
|
|
|
|
|
|
8305
|
|
|
|
|
|
|
} |
|
8306
|
|
|
|
|
|
|
|
|
8307
|
|
|
|
|
|
|
# if 'MEAN_DE' |
|
8308
|
|
|
|
|
|
|
} elsif (m/^MEAN_DE$/) { |
|
8309
|
|
|
|
|
|
|
|
|
8310
|
|
|
|
|
|
|
# for each context |
|
8311
|
0
|
|
|
|
|
0
|
for my $context (@ctx) { |
|
8312
|
|
|
|
|
|
|
|
|
8313
|
|
|
|
|
|
|
# resolve context value |
|
8314
|
0
|
0
|
0
|
|
|
0
|
$context = defined($context) && length($context) ? $context : undef; |
|
8315
|
|
|
|
|
|
|
|
|
8316
|
|
|
|
|
|
|
# if no MEAN_DE columns with context |
|
8317
|
0
|
0
|
|
|
|
0
|
if (! test($self, 'MEAN_DE', $context)) { |
|
8318
|
|
|
|
|
|
|
|
|
8319
|
|
|
|
|
|
|
# get L*a*b* columns |
|
8320
|
0
|
0
|
|
|
|
0
|
$cols = cols($self, map {defined($context) ? "$context|$_" : $_} qw(LAB_L LAB_A LAB_B)); |
|
|
0
|
|
|
|
|
0
|
|
|
8321
|
|
|
|
|
|
|
|
|
8322
|
|
|
|
|
|
|
# add MEAN_DE column |
|
8323
|
0
|
0
|
|
|
|
0
|
$scols = add_fmt($self, map {defined($context) ? "$context|$_" : $_} qw(MEAN_DE)); |
|
|
0
|
|
|
|
|
0
|
|
|
8324
|
|
|
|
|
|
|
|
|
8325
|
|
|
|
|
|
|
# add MEAN_DE values |
|
8326
|
0
|
|
|
|
|
0
|
_addMeanDECol($self, $charts, $cols, $scols->[0]); |
|
8327
|
|
|
|
|
|
|
|
|
8328
|
|
|
|
|
|
|
# set origin |
|
8329
|
0
|
|
|
|
|
0
|
$self->[2][0][$scols->[0]] = $cols; |
|
8330
|
|
|
|
|
|
|
|
|
8331
|
|
|
|
|
|
|
} |
|
8332
|
|
|
|
|
|
|
|
|
8333
|
|
|
|
|
|
|
} |
|
8334
|
|
|
|
|
|
|
|
|
8335
|
|
|
|
|
|
|
} |
|
8336
|
|
|
|
|
|
|
|
|
8337
|
|
|
|
|
|
|
} |
|
8338
|
|
|
|
|
|
|
|
|
8339
|
|
|
|
|
|
|
} |
|
8340
|
|
|
|
|
|
|
|
|
8341
|
|
|
|
|
|
|
# add standard deviation column |
|
8342
|
|
|
|
|
|
|
# the object_reference contains the mean values |
|
8343
|
|
|
|
|
|
|
# the individual charts are in the array_of_chart_objects |
|
8344
|
|
|
|
|
|
|
# parameters: (object_reference, array_of_chart_objects, mean_column, std_dev_column) |
|
8345
|
|
|
|
|
|
|
sub _addStdDevCol { |
|
8346
|
|
|
|
|
|
|
|
|
8347
|
|
|
|
|
|
|
# get parameters |
|
8348
|
0
|
|
|
0
|
|
0
|
my ($self, $charts, $m, $s) = @_; |
|
8349
|
|
|
|
|
|
|
|
|
8350
|
|
|
|
|
|
|
# local variables |
|
8351
|
0
|
|
|
|
|
0
|
my ($n); |
|
8352
|
|
|
|
|
|
|
|
|
8353
|
|
|
|
|
|
|
# get number of charts |
|
8354
|
0
|
|
|
|
|
0
|
$n = @{$charts}; |
|
|
0
|
|
|
|
|
0
|
|
|
8355
|
|
|
|
|
|
|
|
|
8356
|
|
|
|
|
|
|
# for each sample |
|
8357
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8358
|
|
|
|
|
|
|
|
|
8359
|
|
|
|
|
|
|
# initialize value |
|
8360
|
0
|
|
|
|
|
0
|
$self->[1][$i][$s] = 0; |
|
8361
|
|
|
|
|
|
|
|
|
8362
|
|
|
|
|
|
|
# if number of charts > 0 |
|
8363
|
0
|
0
|
|
|
|
0
|
if ($n) { |
|
8364
|
|
|
|
|
|
|
|
|
8365
|
|
|
|
|
|
|
# for each chart |
|
8366
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$charts}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8367
|
|
|
|
|
|
|
|
|
8368
|
|
|
|
|
|
|
# add squared difference |
|
8369
|
0
|
|
|
|
|
0
|
$self->[1][$i][$s] += ($charts->[$j][$i][$m] - $self->[1][$i][$m])**2; |
|
8370
|
|
|
|
|
|
|
|
|
8371
|
|
|
|
|
|
|
} |
|
8372
|
|
|
|
|
|
|
|
|
8373
|
|
|
|
|
|
|
# complete calculation |
|
8374
|
0
|
|
|
|
|
0
|
$self->[1][$i][$s] = sqrt($self->[1][$i][$s]/$n); |
|
8375
|
|
|
|
|
|
|
|
|
8376
|
|
|
|
|
|
|
} else { |
|
8377
|
|
|
|
|
|
|
|
|
8378
|
|
|
|
|
|
|
# error |
|
8379
|
0
|
|
|
|
|
0
|
croak('can\'t compute standard deviation with zero samples'); |
|
8380
|
|
|
|
|
|
|
|
|
8381
|
|
|
|
|
|
|
} |
|
8382
|
|
|
|
|
|
|
|
|
8383
|
|
|
|
|
|
|
} |
|
8384
|
|
|
|
|
|
|
|
|
8385
|
|
|
|
|
|
|
} |
|
8386
|
|
|
|
|
|
|
|
|
8387
|
|
|
|
|
|
|
# add mean dEab column |
|
8388
|
|
|
|
|
|
|
# the object_reference contains the mean values |
|
8389
|
|
|
|
|
|
|
# the individual charts are in the array_of_chart_objects |
|
8390
|
|
|
|
|
|
|
# parameters: (object_reference, array_of_chart_objects, mean_L*a*b*_columns, mean_dE_column) |
|
8391
|
|
|
|
|
|
|
sub _addMeanDECol { |
|
8392
|
|
|
|
|
|
|
|
|
8393
|
|
|
|
|
|
|
# get parameters |
|
8394
|
0
|
|
|
0
|
|
0
|
my ($self, $charts, $m, $s) = @_; |
|
8395
|
|
|
|
|
|
|
|
|
8396
|
|
|
|
|
|
|
# local variables |
|
8397
|
0
|
|
|
|
|
0
|
my ($n, $dE); |
|
8398
|
|
|
|
|
|
|
|
|
8399
|
|
|
|
|
|
|
# get number of charts |
|
8400
|
0
|
|
|
|
|
0
|
$n = @{$charts}; |
|
|
0
|
|
|
|
|
0
|
|
|
8401
|
|
|
|
|
|
|
|
|
8402
|
|
|
|
|
|
|
# for each sample |
|
8403
|
0
|
|
|
|
|
0
|
for my $i (1 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8404
|
|
|
|
|
|
|
|
|
8405
|
|
|
|
|
|
|
# initialize value |
|
8406
|
0
|
|
|
|
|
0
|
$self->[1][$i][$s] = 0; |
|
8407
|
|
|
|
|
|
|
|
|
8408
|
|
|
|
|
|
|
# if number of charts > 0 |
|
8409
|
0
|
0
|
|
|
|
0
|
if ($n) { |
|
8410
|
|
|
|
|
|
|
|
|
8411
|
|
|
|
|
|
|
# for each chart |
|
8412
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$charts}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8413
|
|
|
|
|
|
|
|
|
8414
|
|
|
|
|
|
|
# initialize dE |
|
8415
|
0
|
|
|
|
|
0
|
$dE = 0; |
|
8416
|
|
|
|
|
|
|
|
|
8417
|
|
|
|
|
|
|
# for each L*a*b* |
|
8418
|
0
|
|
|
|
|
0
|
for my $k (0 .. 2) { |
|
8419
|
|
|
|
|
|
|
|
|
8420
|
|
|
|
|
|
|
# add squared difference |
|
8421
|
0
|
|
|
|
|
0
|
$dE += ($self->[1][$i][$m->[$k]] - $charts->[$j][$i][$m->[$k]])**2; |
|
8422
|
|
|
|
|
|
|
|
|
8423
|
|
|
|
|
|
|
} |
|
8424
|
|
|
|
|
|
|
|
|
8425
|
|
|
|
|
|
|
# add dE for this chart |
|
8426
|
0
|
|
|
|
|
0
|
$self->[1][$i][$s] += sqrt($dE); |
|
8427
|
|
|
|
|
|
|
|
|
8428
|
|
|
|
|
|
|
} |
|
8429
|
|
|
|
|
|
|
|
|
8430
|
|
|
|
|
|
|
# complete calculation |
|
8431
|
0
|
|
|
|
|
0
|
$self->[1][$i][$s] /= $n; |
|
8432
|
|
|
|
|
|
|
|
|
8433
|
|
|
|
|
|
|
} else { |
|
8434
|
|
|
|
|
|
|
|
|
8435
|
|
|
|
|
|
|
# error |
|
8436
|
0
|
|
|
|
|
0
|
croak('can\'t compute mean dE with zero samples'); |
|
8437
|
|
|
|
|
|
|
|
|
8438
|
|
|
|
|
|
|
} |
|
8439
|
|
|
|
|
|
|
|
|
8440
|
|
|
|
|
|
|
} |
|
8441
|
|
|
|
|
|
|
|
|
8442
|
|
|
|
|
|
|
} |
|
8443
|
|
|
|
|
|
|
|
|
8444
|
|
|
|
|
|
|
# read chart from list of data files |
|
8445
|
|
|
|
|
|
|
# reads first chart, then appends other charts |
|
8446
|
|
|
|
|
|
|
# files must have identical structure (cols) |
|
8447
|
|
|
|
|
|
|
# parameters: (object_reference, ref_to_file_list, hash) |
|
8448
|
|
|
|
|
|
|
# returns: (number_of_files_appended) |
|
8449
|
|
|
|
|
|
|
sub _readChartAppend { |
|
8450
|
|
|
|
|
|
|
|
|
8451
|
|
|
|
|
|
|
# get parameters |
|
8452
|
1
|
|
|
1
|
|
4
|
my ($self, $list, $hash) = @_; |
|
8453
|
|
|
|
|
|
|
|
|
8454
|
|
|
|
|
|
|
# local variables |
|
8455
|
1
|
|
|
|
|
2
|
my ($n, $result, $keys, $temp); |
|
8456
|
|
|
|
|
|
|
|
|
8457
|
|
|
|
|
|
|
# initialize file counter |
|
8458
|
1
|
|
|
|
|
3
|
$n = 0; |
|
8459
|
|
|
|
|
|
|
|
|
8460
|
|
|
|
|
|
|
# for each file |
|
8461
|
1
|
|
|
|
|
2
|
for my $file (@{$list}) { |
|
|
1
|
|
|
|
|
2
|
|
|
8462
|
|
|
|
|
|
|
|
|
8463
|
|
|
|
|
|
|
# if first file |
|
8464
|
4
|
100
|
|
|
|
8
|
if ($n == 0) { |
|
8465
|
|
|
|
|
|
|
|
|
8466
|
|
|
|
|
|
|
# if file read successfully |
|
8467
|
1
|
50
|
|
|
|
3
|
if (! ($result = _readChart($self, $file, $hash))) { |
|
8468
|
|
|
|
|
|
|
|
|
8469
|
|
|
|
|
|
|
# add colorimetric metadata |
|
8470
|
1
|
|
|
|
|
4
|
_addColorMeta($self); |
|
8471
|
|
|
|
|
|
|
|
|
8472
|
|
|
|
|
|
|
# make format key string |
|
8473
|
1
|
50
|
|
|
|
2
|
$keys = join(':', map {defined() ? $_ : '-'} @{$self->[1][0]}); |
|
|
12
|
|
|
|
|
19
|
|
|
|
1
|
|
|
|
|
3
|
|
|
8474
|
|
|
|
|
|
|
|
|
8475
|
|
|
|
|
|
|
# increment counter |
|
8476
|
1
|
|
|
|
|
3
|
$n++; |
|
8477
|
|
|
|
|
|
|
|
|
8478
|
|
|
|
|
|
|
} else { |
|
8479
|
|
|
|
|
|
|
|
|
8480
|
|
|
|
|
|
|
# print warning |
|
8481
|
0
|
|
|
|
|
0
|
warn("chart $file $result, ignored\n"); |
|
8482
|
|
|
|
|
|
|
|
|
8483
|
|
|
|
|
|
|
} |
|
8484
|
|
|
|
|
|
|
|
|
8485
|
|
|
|
|
|
|
} else { |
|
8486
|
|
|
|
|
|
|
|
|
8487
|
|
|
|
|
|
|
# make temporary Chart object |
|
8488
|
3
|
|
|
|
|
15
|
$temp = ICC::Support::Chart->new(); |
|
8489
|
|
|
|
|
|
|
|
|
8490
|
|
|
|
|
|
|
# if file read successfully |
|
8491
|
3
|
50
|
|
|
|
8
|
if (! ($result = _readChart($temp, $file, $hash))) { |
|
8492
|
|
|
|
|
|
|
|
|
8493
|
|
|
|
|
|
|
# if charts have same structure (cols) |
|
8494
|
3
|
50
|
|
|
|
5
|
if ($keys eq join(':', map {defined() ? $_ : '-'} @{$temp->[1][0]})) { |
|
|
36
|
50
|
|
|
|
58
|
|
|
|
3
|
|
|
|
|
6
|
|
|
8495
|
|
|
|
|
|
|
|
|
8496
|
|
|
|
|
|
|
# append temp samples |
|
8497
|
3
|
|
|
|
|
4
|
push(@{$self->[1]}, @{$temp->[1]}[1 .. $#{$temp->[1]}]); |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
5
|
|
|
8498
|
|
|
|
|
|
|
|
|
8499
|
|
|
|
|
|
|
# increment counter |
|
8500
|
3
|
|
|
|
|
10
|
$n++; |
|
8501
|
|
|
|
|
|
|
|
|
8502
|
|
|
|
|
|
|
} else { |
|
8503
|
|
|
|
|
|
|
|
|
8504
|
|
|
|
|
|
|
# print warning |
|
8505
|
0
|
|
|
|
|
0
|
warn("chart $file has different structure, ignored\n"); |
|
8506
|
|
|
|
|
|
|
|
|
8507
|
|
|
|
|
|
|
} |
|
8508
|
|
|
|
|
|
|
|
|
8509
|
|
|
|
|
|
|
} else { |
|
8510
|
|
|
|
|
|
|
|
|
8511
|
|
|
|
|
|
|
# print warning |
|
8512
|
0
|
|
|
|
|
0
|
warn("chart $file $result, ignored\n"); |
|
8513
|
|
|
|
|
|
|
|
|
8514
|
|
|
|
|
|
|
} |
|
8515
|
|
|
|
|
|
|
|
|
8516
|
|
|
|
|
|
|
} |
|
8517
|
|
|
|
|
|
|
|
|
8518
|
|
|
|
|
|
|
} |
|
8519
|
|
|
|
|
|
|
|
|
8520
|
|
|
|
|
|
|
# print message if any files were read |
|
8521
|
1
|
50
|
|
|
|
37
|
print "$n files read in directory $self->[0]{'file_path'}\n\n" if ($n); |
|
8522
|
|
|
|
|
|
|
|
|
8523
|
|
|
|
|
|
|
# save number of files read |
|
8524
|
1
|
|
|
|
|
5
|
$self->[0]{'files_read'} = $n; |
|
8525
|
|
|
|
|
|
|
|
|
8526
|
|
|
|
|
|
|
# return |
|
8527
|
1
|
|
|
|
|
11
|
return($n); |
|
8528
|
|
|
|
|
|
|
|
|
8529
|
|
|
|
|
|
|
} |
|
8530
|
|
|
|
|
|
|
|
|
8531
|
|
|
|
|
|
|
# read chart from list of data files |
|
8532
|
|
|
|
|
|
|
# assumes charts are M0, M1, M2 or M3 measurement conditions |
|
8533
|
|
|
|
|
|
|
# reads first chart, then merges other charts, adding contexts |
|
8534
|
|
|
|
|
|
|
# files must have identical structure (rows and cols) |
|
8535
|
|
|
|
|
|
|
# parameters: (object_reference, ref_to_file_list, hash) |
|
8536
|
|
|
|
|
|
|
# returns: (number_of_files_merged) |
|
8537
|
|
|
|
|
|
|
sub _readChartMerge { |
|
8538
|
|
|
|
|
|
|
|
|
8539
|
|
|
|
|
|
|
# get parameters |
|
8540
|
0
|
|
|
0
|
|
0
|
my ($self, $list, $hash) = @_; |
|
8541
|
|
|
|
|
|
|
|
|
8542
|
|
|
|
|
|
|
# local variables |
|
8543
|
0
|
|
|
|
|
0
|
my ($n, $ctx, $result, $keys, $sig, @cols, $temp); |
|
8544
|
|
|
|
|
|
|
|
|
8545
|
|
|
|
|
|
|
# initialize file counter |
|
8546
|
0
|
|
|
|
|
0
|
$n = 0; |
|
8547
|
|
|
|
|
|
|
|
|
8548
|
|
|
|
|
|
|
# for each file |
|
8549
|
0
|
|
|
|
|
0
|
for my $file (@{$list}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8550
|
|
|
|
|
|
|
|
|
8551
|
|
|
|
|
|
|
# if first file |
|
8552
|
0
|
0
|
|
|
|
0
|
if ($n == 0) { |
|
8553
|
|
|
|
|
|
|
|
|
8554
|
|
|
|
|
|
|
# if file read successfully |
|
8555
|
0
|
0
|
|
|
|
0
|
if (! ($result = _readChart($self, $file, $hash))) { |
|
8556
|
|
|
|
|
|
|
|
|
8557
|
|
|
|
|
|
|
# add colorimetric metadata |
|
8558
|
0
|
|
|
|
|
0
|
_addColorMeta($self); |
|
8559
|
|
|
|
|
|
|
|
|
8560
|
|
|
|
|
|
|
# make format key string (removing contexts) |
|
8561
|
0
|
0
|
|
|
|
0
|
$keys = join(':', map {s/^.*\|// if defined(); defined() ? $_ : '-'} @{$self->[1][0]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8562
|
|
|
|
|
|
|
|
|
8563
|
|
|
|
|
|
|
# make signature |
|
8564
|
0
|
|
|
|
|
0
|
$sig = signature($self); |
|
8565
|
|
|
|
|
|
|
|
|
8566
|
|
|
|
|
|
|
# get column slice (spectral, XYZ, or L*a*b* data) |
|
8567
|
0
|
0
|
|
|
|
0
|
@cols = grep {defined($self->[1][0][$_]) && $self->[1][0][$_] =~ m/((?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)\d{3}|XYZ_[XYZ]|LAB_[LAB])$/} (0 .. $#{$self->[1][0]}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8568
|
|
|
|
|
|
|
|
|
8569
|
|
|
|
|
|
|
# if format keys lack context (not a CxF3 file) |
|
8570
|
0
|
0
|
|
|
|
0
|
if ($self->[1][0][$cols[0]] !~ m/^M[0-3]_Measurement\|/) { |
|
8571
|
|
|
|
|
|
|
|
|
8572
|
|
|
|
|
|
|
# get measurement condition from file name (very loose match) |
|
8573
|
0
|
0
|
|
|
|
0
|
if ($file =~ m/.*(M[0-3])/) { |
|
8574
|
|
|
|
|
|
|
|
|
8575
|
|
|
|
|
|
|
# make context string |
|
8576
|
0
|
|
|
|
|
0
|
$ctx = $1 . '_Measurement|'; |
|
8577
|
|
|
|
|
|
|
|
|
8578
|
|
|
|
|
|
|
# for each column |
|
8579
|
0
|
|
|
|
|
0
|
for my $i (@cols) { |
|
8580
|
|
|
|
|
|
|
|
|
8581
|
|
|
|
|
|
|
# remove current context (if any) |
|
8582
|
0
|
|
|
|
|
0
|
$self->[1][0][$i] =~ s/^.*\|//; |
|
8583
|
|
|
|
|
|
|
|
|
8584
|
|
|
|
|
|
|
# add derived context |
|
8585
|
0
|
|
|
|
|
0
|
$self->[1][0][$i] = $ctx . $self->[1][0][$i]; |
|
8586
|
|
|
|
|
|
|
|
|
8587
|
|
|
|
|
|
|
} |
|
8588
|
|
|
|
|
|
|
|
|
8589
|
|
|
|
|
|
|
} else { |
|
8590
|
|
|
|
|
|
|
|
|
8591
|
|
|
|
|
|
|
# print warning |
|
8592
|
0
|
|
|
|
|
0
|
warn("can't determine context of chart $file\n"); |
|
8593
|
|
|
|
|
|
|
|
|
8594
|
|
|
|
|
|
|
} |
|
8595
|
|
|
|
|
|
|
|
|
8596
|
|
|
|
|
|
|
} |
|
8597
|
|
|
|
|
|
|
|
|
8598
|
|
|
|
|
|
|
# increment counter |
|
8599
|
0
|
|
|
|
|
0
|
$n++; |
|
8600
|
|
|
|
|
|
|
|
|
8601
|
|
|
|
|
|
|
} else { |
|
8602
|
|
|
|
|
|
|
|
|
8603
|
|
|
|
|
|
|
# print warning |
|
8604
|
0
|
|
|
|
|
0
|
warn("chart $file $result, ignored\n"); |
|
8605
|
|
|
|
|
|
|
|
|
8606
|
|
|
|
|
|
|
} |
|
8607
|
|
|
|
|
|
|
|
|
8608
|
|
|
|
|
|
|
} else { |
|
8609
|
|
|
|
|
|
|
|
|
8610
|
|
|
|
|
|
|
# make temporary Chart object |
|
8611
|
0
|
|
|
|
|
0
|
$temp = ICC::Support::Chart->new(); |
|
8612
|
|
|
|
|
|
|
|
|
8613
|
|
|
|
|
|
|
# if file read successfully |
|
8614
|
0
|
0
|
|
|
|
0
|
if (! ($result = _readChart($temp, $file, $hash))) { |
|
8615
|
|
|
|
|
|
|
|
|
8616
|
|
|
|
|
|
|
# if charts have same structure (rows and cols) |
|
8617
|
0
|
0
|
0
|
|
|
0
|
if ((defined($sig) && $sig eq signature($temp) || $#{$self->[1]} == $#{$temp->[1]}) && $keys eq join(':', map {s/^.*\|// if defined(); defined() ? $_ : '-'} @{$temp->[1][0]})) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8618
|
|
|
|
|
|
|
|
|
8619
|
|
|
|
|
|
|
# if format keys lack context (not a CxF3 file) |
|
8620
|
0
|
0
|
|
|
|
0
|
if ($temp->[1][0][$cols[0]] !~ m/^M[0-3]_Measurement\|/) { |
|
8621
|
|
|
|
|
|
|
|
|
8622
|
|
|
|
|
|
|
# get measurement condition from file name (very loose match) |
|
8623
|
0
|
0
|
|
|
|
0
|
if ($file =~ m/.*(M[0-3])/) { |
|
8624
|
|
|
|
|
|
|
|
|
8625
|
|
|
|
|
|
|
# make context string |
|
8626
|
0
|
|
|
|
|
0
|
$ctx = $1 . '_Measurement|'; |
|
8627
|
|
|
|
|
|
|
|
|
8628
|
|
|
|
|
|
|
# for each column |
|
8629
|
0
|
|
|
|
|
0
|
for my $i (@cols) { |
|
8630
|
|
|
|
|
|
|
|
|
8631
|
|
|
|
|
|
|
# remove current context (if any) |
|
8632
|
0
|
|
|
|
|
0
|
$temp->[1][0][$i] =~ s/^.*\|//; |
|
8633
|
|
|
|
|
|
|
|
|
8634
|
|
|
|
|
|
|
# add derived context |
|
8635
|
0
|
|
|
|
|
0
|
$temp->[1][0][$i] = $ctx . $temp->[1][0][$i]; |
|
8636
|
|
|
|
|
|
|
|
|
8637
|
|
|
|
|
|
|
} |
|
8638
|
|
|
|
|
|
|
|
|
8639
|
|
|
|
|
|
|
} else { |
|
8640
|
|
|
|
|
|
|
|
|
8641
|
|
|
|
|
|
|
# print warning |
|
8642
|
0
|
|
|
|
|
0
|
warn("can't determine context of chart $file\n"); |
|
8643
|
|
|
|
|
|
|
|
|
8644
|
|
|
|
|
|
|
} |
|
8645
|
|
|
|
|
|
|
|
|
8646
|
|
|
|
|
|
|
} |
|
8647
|
|
|
|
|
|
|
|
|
8648
|
|
|
|
|
|
|
# for each row |
|
8649
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$self->[1]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
8650
|
|
|
|
|
|
|
|
|
8651
|
|
|
|
|
|
|
# append temp data |
|
8652
|
0
|
|
|
|
|
0
|
push(@{$self->[1][$i]}, @{$temp->[1][$i]}[@cols]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8653
|
|
|
|
|
|
|
|
|
8654
|
|
|
|
|
|
|
} |
|
8655
|
|
|
|
|
|
|
|
|
8656
|
|
|
|
|
|
|
# increment counter |
|
8657
|
0
|
|
|
|
|
0
|
$n++; |
|
8658
|
|
|
|
|
|
|
|
|
8659
|
|
|
|
|
|
|
} else { |
|
8660
|
|
|
|
|
|
|
|
|
8661
|
|
|
|
|
|
|
# print warning |
|
8662
|
0
|
|
|
|
|
0
|
warn("chart $file has different structure, ignored\n"); |
|
8663
|
|
|
|
|
|
|
|
|
8664
|
|
|
|
|
|
|
} |
|
8665
|
|
|
|
|
|
|
|
|
8666
|
|
|
|
|
|
|
} else { |
|
8667
|
|
|
|
|
|
|
|
|
8668
|
|
|
|
|
|
|
# print warning |
|
8669
|
0
|
|
|
|
|
0
|
warn("chart $file $result, ignored\n"); |
|
8670
|
|
|
|
|
|
|
|
|
8671
|
|
|
|
|
|
|
} |
|
8672
|
|
|
|
|
|
|
|
|
8673
|
|
|
|
|
|
|
} |
|
8674
|
|
|
|
|
|
|
|
|
8675
|
|
|
|
|
|
|
} |
|
8676
|
|
|
|
|
|
|
|
|
8677
|
|
|
|
|
|
|
# print message if any files were read |
|
8678
|
0
|
0
|
|
|
|
0
|
print "$n files read in directory $self->[0]{'file_path'}\n\n" if ($n); |
|
8679
|
|
|
|
|
|
|
|
|
8680
|
|
|
|
|
|
|
# save number of files read |
|
8681
|
0
|
|
|
|
|
0
|
$self->[0]{'files_read'} = $n; |
|
8682
|
|
|
|
|
|
|
|
|
8683
|
|
|
|
|
|
|
# return |
|
8684
|
0
|
|
|
|
|
0
|
return($n); |
|
8685
|
|
|
|
|
|
|
|
|
8686
|
|
|
|
|
|
|
} |
|
8687
|
|
|
|
|
|
|
|
|
8688
|
|
|
|
|
|
|
# read chart |
|
8689
|
|
|
|
|
|
|
# parameters: (object_reference, path_to_file, hash) |
|
8690
|
|
|
|
|
|
|
# returns: (result) |
|
8691
|
|
|
|
|
|
|
sub _readChart { |
|
8692
|
|
|
|
|
|
|
|
|
8693
|
|
|
|
|
|
|
# get parameters |
|
8694
|
27
|
|
|
27
|
|
54
|
my ($self, $path, $hash) = @_; |
|
8695
|
|
|
|
|
|
|
|
|
8696
|
|
|
|
|
|
|
# local variables |
|
8697
|
27
|
|
|
|
|
44
|
my ($fh, $buf, $result); |
|
8698
|
|
|
|
|
|
|
|
|
8699
|
|
|
|
|
|
|
# open the file (read-only) |
|
8700
|
27
|
50
|
|
|
|
937
|
open($fh, '<', $path) || return("$! when opening file"); |
|
8701
|
|
|
|
|
|
|
|
|
8702
|
|
|
|
|
|
|
# set binary mode |
|
8703
|
27
|
|
|
|
|
100
|
binmode($fh); |
|
8704
|
|
|
|
|
|
|
|
|
8705
|
|
|
|
|
|
|
# read start of file |
|
8706
|
27
|
50
|
|
|
|
773
|
read($fh, $buf, 1024) || return("is zero length"); |
|
8707
|
|
|
|
|
|
|
|
|
8708
|
|
|
|
|
|
|
# reset file pointer |
|
8709
|
27
|
|
|
|
|
283
|
seek($fh, 0, 0); |
|
8710
|
|
|
|
|
|
|
|
|
8711
|
|
|
|
|
|
|
# if an ASE file |
|
8712
|
27
|
50
|
33
|
|
|
346
|
if ($buf =~ m/^ASEF/) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
8713
|
|
|
|
|
|
|
|
|
8714
|
|
|
|
|
|
|
# save file type |
|
8715
|
0
|
|
|
|
|
0
|
$self->[0]{'file_type'} = 'ASEF'; |
|
8716
|
|
|
|
|
|
|
|
|
8717
|
|
|
|
|
|
|
# read ASE file |
|
8718
|
0
|
|
|
|
|
0
|
$result = _readChartASE($self, $fh, $hash); |
|
8719
|
|
|
|
|
|
|
|
|
8720
|
|
|
|
|
|
|
# if a TIFF file |
|
8721
|
|
|
|
|
|
|
} elsif ($buf =~ m/^(II\*\x00|MM\x00\*)/) { |
|
8722
|
|
|
|
|
|
|
|
|
8723
|
|
|
|
|
|
|
# save file type |
|
8724
|
0
|
|
|
|
|
0
|
$self->[0]{'file_type'} = 'TIFF'; |
|
8725
|
|
|
|
|
|
|
|
|
8726
|
|
|
|
|
|
|
# read TIFF file |
|
8727
|
0
|
|
|
|
|
0
|
$result = _readChartTIFF($self, $fh, $hash); |
|
8728
|
|
|
|
|
|
|
|
|
8729
|
|
|
|
|
|
|
# if an ICC profile |
|
8730
|
|
|
|
|
|
|
} elsif (substr($buf, 36, 4) eq 'acsp') { |
|
8731
|
|
|
|
|
|
|
|
|
8732
|
|
|
|
|
|
|
# save file type |
|
8733
|
0
|
|
|
|
|
0
|
$self->[0]{'file_type'} = 'prof'; |
|
8734
|
|
|
|
|
|
|
|
|
8735
|
|
|
|
|
|
|
# read ICC file |
|
8736
|
0
|
|
|
|
|
0
|
$result = _readChartICC($self, $fh, $hash); |
|
8737
|
|
|
|
|
|
|
|
|
8738
|
|
|
|
|
|
|
# if a CxF3 file |
|
8739
|
|
|
|
|
|
|
} elsif ($buf =~ m/http:\/\/colorexchangeformat.com\/CxF3-core/) { |
|
8740
|
|
|
|
|
|
|
|
|
8741
|
|
|
|
|
|
|
# save file type |
|
8742
|
8
|
|
|
|
|
27
|
$self->[0]{'file_type'} = 'CXFX'; |
|
8743
|
|
|
|
|
|
|
|
|
8744
|
|
|
|
|
|
|
# read CxF3 file |
|
8745
|
8
|
|
|
|
|
33
|
$result = _readChartCxF3($self, $fh, $hash); |
|
8746
|
|
|
|
|
|
|
|
|
8747
|
|
|
|
|
|
|
# if an SS3 file |
|
8748
|
|
|
|
|
|
|
} elsif (substr($buf, 0, 4) eq "\x00\x20\x00\x00" || substr($buf, 0, 4) eq "\x00\x32\x00\x00") { |
|
8749
|
|
|
|
|
|
|
|
|
8750
|
|
|
|
|
|
|
# save file type |
|
8751
|
0
|
|
|
|
|
0
|
$self->[0]{'file_type'} = 'SS3'; |
|
8752
|
|
|
|
|
|
|
|
|
8753
|
|
|
|
|
|
|
# read SS3 file |
|
8754
|
0
|
|
|
|
|
0
|
$result = _readChartSS3($self, $fh, $hash); |
|
8755
|
|
|
|
|
|
|
|
|
8756
|
|
|
|
|
|
|
# must be a text file |
|
8757
|
|
|
|
|
|
|
} else { |
|
8758
|
|
|
|
|
|
|
|
|
8759
|
|
|
|
|
|
|
# save file type |
|
8760
|
19
|
|
|
|
|
57
|
$self->[0]{'file_type'} = 'TEXT'; |
|
8761
|
|
|
|
|
|
|
|
|
8762
|
|
|
|
|
|
|
# read ASCII file |
|
8763
|
19
|
|
|
|
|
47
|
$result = _readChartASCII($self, $fh, $hash); |
|
8764
|
|
|
|
|
|
|
|
|
8765
|
|
|
|
|
|
|
} |
|
8766
|
|
|
|
|
|
|
|
|
8767
|
|
|
|
|
|
|
# close the file |
|
8768
|
27
|
|
|
|
|
1364
|
close($fh); |
|
8769
|
|
|
|
|
|
|
|
|
8770
|
|
|
|
|
|
|
# return |
|
8771
|
27
|
|
|
|
|
176
|
return($result); |
|
8772
|
|
|
|
|
|
|
|
|
8773
|
|
|
|
|
|
|
} |
|
8774
|
|
|
|
|
|
|
|
|
8775
|
|
|
|
|
|
|
# read chart from ISO 28178 ASCII data file |
|
8776
|
|
|
|
|
|
|
# parameters: (object_reference, file_handle, hash) |
|
8777
|
|
|
|
|
|
|
# returns: (result) |
|
8778
|
|
|
|
|
|
|
sub _readChartASCII { |
|
8779
|
|
|
|
|
|
|
|
|
8780
|
|
|
|
|
|
|
# get parameters |
|
8781
|
19
|
|
|
19
|
|
40
|
my ($self, $fh, $hash) = @_; |
|
8782
|
|
|
|
|
|
|
|
|
8783
|
|
|
|
|
|
|
# local variables |
|
8784
|
19
|
|
|
|
|
44
|
my ($buf, $state, $iflag, $eflag, $index); |
|
8785
|
19
|
|
|
|
|
0
|
my (@fields, $illum, $append); |
|
8786
|
|
|
|
|
|
|
|
|
8787
|
|
|
|
|
|
|
# read start of file |
|
8788
|
19
|
50
|
|
|
|
176
|
read($fh, $buf, 1024) || return("is zero length"); |
|
8789
|
|
|
|
|
|
|
|
|
8790
|
|
|
|
|
|
|
# reset file pointer |
|
8791
|
19
|
|
|
|
|
175
|
seek($fh, 0, 0); |
|
8792
|
|
|
|
|
|
|
|
|
8793
|
|
|
|
|
|
|
# check for CR-LF (DOS/Windows) |
|
8794
|
19
|
100
|
|
|
|
105
|
if ($buf =~ m/\015\012/) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
8795
|
|
|
|
|
|
|
|
|
8796
|
|
|
|
|
|
|
# set record separator |
|
8797
|
1
|
|
|
|
|
3
|
$self->[0]{'read_rs'} = "\015\012"; |
|
8798
|
|
|
|
|
|
|
|
|
8799
|
|
|
|
|
|
|
# check for LF (Unix/OSX) |
|
8800
|
|
|
|
|
|
|
} elsif ($buf =~ m/\012/) { |
|
8801
|
|
|
|
|
|
|
|
|
8802
|
|
|
|
|
|
|
# set record separator |
|
8803
|
17
|
|
|
|
|
46
|
$self->[0]{'read_rs'} = "\012"; |
|
8804
|
|
|
|
|
|
|
|
|
8805
|
|
|
|
|
|
|
# check for CR (Mac) |
|
8806
|
|
|
|
|
|
|
} elsif ($buf =~ m/\015/) { |
|
8807
|
|
|
|
|
|
|
|
|
8808
|
|
|
|
|
|
|
# set record separator |
|
8809
|
1
|
|
|
|
|
4
|
$self->[0]{'read_rs'} = "\015"; |
|
8810
|
|
|
|
|
|
|
|
|
8811
|
|
|
|
|
|
|
# not a text file |
|
8812
|
|
|
|
|
|
|
} else { |
|
8813
|
|
|
|
|
|
|
|
|
8814
|
|
|
|
|
|
|
# close the file |
|
8815
|
0
|
|
|
|
|
0
|
close($fh); |
|
8816
|
|
|
|
|
|
|
|
|
8817
|
|
|
|
|
|
|
# return |
|
8818
|
0
|
|
|
|
|
0
|
return('unknown file type'); |
|
8819
|
|
|
|
|
|
|
|
|
8820
|
|
|
|
|
|
|
} |
|
8821
|
|
|
|
|
|
|
|
|
8822
|
|
|
|
|
|
|
# localize input record separator |
|
8823
|
19
|
|
|
|
|
87
|
local $/ = $self->[0]{'read_rs'}; |
|
8824
|
|
|
|
|
|
|
|
|
8825
|
|
|
|
|
|
|
# localize loop variable |
|
8826
|
19
|
|
|
|
|
29
|
local $_; |
|
8827
|
|
|
|
|
|
|
|
|
8828
|
|
|
|
|
|
|
# initialize variables |
|
8829
|
19
|
|
|
|
|
52
|
$self->[1] = [[]]; |
|
8830
|
19
|
|
|
|
|
154
|
$illum = [[]]; |
|
8831
|
19
|
|
|
|
|
32
|
$index = 1; |
|
8832
|
19
|
|
|
|
|
23
|
$state = 0; |
|
8833
|
19
|
|
|
|
|
21
|
$iflag = 0; |
|
8834
|
|
|
|
|
|
|
|
|
8835
|
|
|
|
|
|
|
# read the file, line by line |
|
8836
|
19
|
|
|
|
|
260
|
while (<$fh>) { |
|
8837
|
|
|
|
|
|
|
|
|
8838
|
|
|
|
|
|
|
# add appended text, as is |
|
8839
|
497
|
50
|
|
|
|
789
|
$append .= $_ if ($state == 4); |
|
8840
|
|
|
|
|
|
|
|
|
8841
|
|
|
|
|
|
|
# remove leading spaces/tabs and trailing whitespace |
|
8842
|
497
|
|
|
|
|
4142
|
s/^[\ \t]*(.*?)[\s,]*$/$1/; |
|
8843
|
|
|
|
|
|
|
|
|
8844
|
|
|
|
|
|
|
# if normal comment line (all comments are removed) |
|
8845
|
497
|
100
|
66
|
|
|
1086
|
if (s/#\s*(.*)// && $state == 0) { |
|
8846
|
|
|
|
|
|
|
|
|
8847
|
|
|
|
|
|
|
# if remaining line blank |
|
8848
|
32
|
100
|
|
|
|
58
|
if (length() == 0) { |
|
8849
|
|
|
|
|
|
|
|
|
8850
|
|
|
|
|
|
|
# add comment to header array |
|
8851
|
26
|
|
|
|
|
35
|
push(@{$self->[3]}, ['#', $1]); |
|
|
26
|
|
|
|
|
72
|
|
|
8852
|
|
|
|
|
|
|
|
|
8853
|
|
|
|
|
|
|
} else { |
|
8854
|
|
|
|
|
|
|
|
|
8855
|
|
|
|
|
|
|
# restore comment to header line |
|
8856
|
|
|
|
|
|
|
# preserves time in ProfileMaker 'CREATED' lines |
|
8857
|
6
|
|
|
|
|
15
|
$_ .= "# $1"; |
|
8858
|
|
|
|
|
|
|
|
|
8859
|
|
|
|
|
|
|
} |
|
8860
|
|
|
|
|
|
|
|
|
8861
|
|
|
|
|
|
|
} |
|
8862
|
|
|
|
|
|
|
|
|
8863
|
|
|
|
|
|
|
# skip blank lines |
|
8864
|
497
|
100
|
|
|
|
743
|
next if (length() == 0); |
|
8865
|
|
|
|
|
|
|
|
|
8866
|
|
|
|
|
|
|
# begin data format |
|
8867
|
471
|
100
|
|
|
|
1241
|
if (m/^BEGIN_DATA_FORMAT$/) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
8868
|
|
|
|
|
|
|
|
|
8869
|
|
|
|
|
|
|
# set state |
|
8870
|
19
|
|
|
|
|
48
|
$state = 1; |
|
8871
|
|
|
|
|
|
|
|
|
8872
|
|
|
|
|
|
|
# end data format |
|
8873
|
|
|
|
|
|
|
} elsif (m/^END_DATA_FORMAT$/) { |
|
8874
|
|
|
|
|
|
|
|
|
8875
|
|
|
|
|
|
|
# set state |
|
8876
|
19
|
|
|
|
|
44
|
$state = 2; |
|
8877
|
|
|
|
|
|
|
|
|
8878
|
|
|
|
|
|
|
# begin data |
|
8879
|
|
|
|
|
|
|
} elsif (m/^BEGIN_DATA$/) { |
|
8880
|
|
|
|
|
|
|
|
|
8881
|
|
|
|
|
|
|
# set state |
|
8882
|
19
|
|
|
|
|
41
|
$state = 3; |
|
8883
|
|
|
|
|
|
|
|
|
8884
|
|
|
|
|
|
|
# end data |
|
8885
|
|
|
|
|
|
|
} elsif (m/^END_DATA$/) { |
|
8886
|
|
|
|
|
|
|
|
|
8887
|
|
|
|
|
|
|
# set state |
|
8888
|
19
|
|
|
|
|
53
|
$state = 4; |
|
8889
|
|
|
|
|
|
|
|
|
8890
|
|
|
|
|
|
|
# begin ProfileMaker illuminant section |
|
8891
|
|
|
|
|
|
|
} elsif (m/^BEGIN_DATA_EMISSION$/) { |
|
8892
|
|
|
|
|
|
|
|
|
8893
|
|
|
|
|
|
|
# set illuminant flag |
|
8894
|
0
|
|
|
|
|
0
|
$iflag = 1; |
|
8895
|
|
|
|
|
|
|
|
|
8896
|
|
|
|
|
|
|
# reset index |
|
8897
|
0
|
|
|
|
|
0
|
$index = 1; |
|
8898
|
|
|
|
|
|
|
|
|
8899
|
|
|
|
|
|
|
# end ProfileMaker illuminant section |
|
8900
|
|
|
|
|
|
|
} elsif (m/^END_DATA_EMISSION$/) { |
|
8901
|
|
|
|
|
|
|
|
|
8902
|
|
|
|
|
|
|
# clear illuminant flag |
|
8903
|
0
|
|
|
|
|
0
|
$iflag = 0; |
|
8904
|
|
|
|
|
|
|
|
|
8905
|
|
|
|
|
|
|
# reset appended data |
|
8906
|
0
|
|
|
|
|
0
|
$append = ''; |
|
8907
|
|
|
|
|
|
|
|
|
8908
|
|
|
|
|
|
|
# anything else |
|
8909
|
|
|
|
|
|
|
} else { |
|
8910
|
|
|
|
|
|
|
|
|
8911
|
|
|
|
|
|
|
# format |
|
8912
|
395
|
100
|
66
|
|
|
1730
|
if ($iflag == 0 && $state == 1) { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
8913
|
|
|
|
|
|
|
|
|
8914
|
|
|
|
|
|
|
# change 'SampleID' to 'SAMPLE_ID' |
|
8915
|
|
|
|
|
|
|
# non-standard notation used by ProfileMaker |
|
8916
|
19
|
|
|
|
|
47
|
s/SampleID/SAMPLE_ID/; |
|
8917
|
|
|
|
|
|
|
|
|
8918
|
|
|
|
|
|
|
# parse and save format keys |
|
8919
|
19
|
|
|
|
|
30
|
push(@{$self->[1][0]}, split(/[\s,]+/)); |
|
|
19
|
|
|
|
|
274
|
|
|
8920
|
|
|
|
|
|
|
|
|
8921
|
|
|
|
|
|
|
# data |
|
8922
|
|
|
|
|
|
|
} elsif ($iflag == 0 && $state == 3) { |
|
8923
|
|
|
|
|
|
|
|
|
8924
|
|
|
|
|
|
|
# if Euro flag not defined |
|
8925
|
190
|
100
|
|
|
|
291
|
if (! defined($eflag)) { |
|
8926
|
|
|
|
|
|
|
|
|
8927
|
|
|
|
|
|
|
# split data |
|
8928
|
19
|
|
|
|
|
189
|
@fields = split(/[\s,]+/); |
|
8929
|
|
|
|
|
|
|
|
|
8930
|
|
|
|
|
|
|
# set flag for Euro decimal notation (e.g. 6,3 becomes 6.3) |
|
8931
|
19
|
|
33
|
|
|
49
|
$eflag = m/,/ && @fields > (@{$self->[1][0]} || 0); |
|
8932
|
|
|
|
|
|
|
|
|
8933
|
|
|
|
|
|
|
} |
|
8934
|
|
|
|
|
|
|
|
|
8935
|
|
|
|
|
|
|
# fix Euro decimal notation (e.g. 6,3 becomes 6.3) |
|
8936
|
190
|
50
|
|
|
|
252
|
s/(\d),(\d)/$1.$2/g if ($eflag); |
|
8937
|
|
|
|
|
|
|
|
|
8938
|
|
|
|
|
|
|
# parse and save data |
|
8939
|
190
|
|
|
|
|
2577
|
$self->[1][$index++] = [split(/[\s,]+/)]; |
|
8940
|
|
|
|
|
|
|
|
|
8941
|
|
|
|
|
|
|
# illuminant format |
|
8942
|
|
|
|
|
|
|
# may be different from data format |
|
8943
|
|
|
|
|
|
|
} elsif ($iflag == 1 && $state == 1) { |
|
8944
|
|
|
|
|
|
|
|
|
8945
|
|
|
|
|
|
|
# change 'SampleID' to 'SAMPLE_ID' |
|
8946
|
|
|
|
|
|
|
# non-standard notation used by ProfileMaker |
|
8947
|
0
|
|
|
|
|
0
|
s/SampleID/SAMPLE_ID/; |
|
8948
|
|
|
|
|
|
|
|
|
8949
|
|
|
|
|
|
|
# parse and save illuminant format keys |
|
8950
|
0
|
|
|
|
|
0
|
push(@{$illum->[0]}, split(/[\s,]+/)); |
|
|
0
|
|
|
|
|
0
|
|
|
8951
|
|
|
|
|
|
|
|
|
8952
|
|
|
|
|
|
|
# illuminant data |
|
8953
|
|
|
|
|
|
|
} elsif ($iflag == 1 && $state == 3) { |
|
8954
|
|
|
|
|
|
|
|
|
8955
|
|
|
|
|
|
|
# fix Euro decimal notation (e.g. 6,3 becomes 6.3) |
|
8956
|
0
|
0
|
|
|
|
0
|
s/(\d),(\d)/$1.$2/g if ($eflag); |
|
8957
|
|
|
|
|
|
|
|
|
8958
|
|
|
|
|
|
|
# parse and save illuminant data |
|
8959
|
0
|
|
|
|
|
0
|
$illum->[$index++] = [split(/[\s,]+/)]; |
|
8960
|
|
|
|
|
|
|
|
|
8961
|
|
|
|
|
|
|
# header lines |
|
8962
|
|
|
|
|
|
|
} elsif ($iflag == 0 && ($state == 0 || $state == 2)) { |
|
8963
|
|
|
|
|
|
|
|
|
8964
|
|
|
|
|
|
|
# match keyword/value |
|
8965
|
186
|
|
|
|
|
523
|
m/^([^\s,]*)[\s,]*(.*?)$/; |
|
8966
|
|
|
|
|
|
|
|
|
8967
|
|
|
|
|
|
|
# add to header array |
|
8968
|
186
|
50
|
|
|
|
326
|
push(@{$self->[3]}, [$1, $2]) if (length($1)); |
|
|
186
|
|
|
|
|
766
|
|
|
8969
|
|
|
|
|
|
|
|
|
8970
|
|
|
|
|
|
|
} |
|
8971
|
|
|
|
|
|
|
|
|
8972
|
|
|
|
|
|
|
} |
|
8973
|
|
|
|
|
|
|
|
|
8974
|
|
|
|
|
|
|
} |
|
8975
|
|
|
|
|
|
|
|
|
8976
|
|
|
|
|
|
|
# save illuminant data, if any |
|
8977
|
19
|
50
|
|
|
|
46
|
$self->[0]{'illuminant'} = $illum if defined($illum->[1]); |
|
8978
|
|
|
|
|
|
|
|
|
8979
|
|
|
|
|
|
|
# save appended data, if any |
|
8980
|
19
|
50
|
|
|
|
32
|
$self->[0]{'append'} = $append if (defined($append)); |
|
8981
|
|
|
|
|
|
|
|
|
8982
|
|
|
|
|
|
|
# apply rotation/flip (special keywords) |
|
8983
|
19
|
|
|
|
|
44
|
_rotateChartASCII($self); |
|
8984
|
|
|
|
|
|
|
|
|
8985
|
|
|
|
|
|
|
# check spectral data |
|
8986
|
19
|
|
|
|
|
60
|
_scale_check($self); |
|
8987
|
|
|
|
|
|
|
|
|
8988
|
|
|
|
|
|
|
# return success flag |
|
8989
|
19
|
50
|
|
|
|
106
|
return($state == 4 ? () : "ASCII read failed with state $state"); |
|
8990
|
|
|
|
|
|
|
|
|
8991
|
|
|
|
|
|
|
} |
|
8992
|
|
|
|
|
|
|
|
|
8993
|
|
|
|
|
|
|
# apply rotation/flip to ASCII chart data |
|
8994
|
|
|
|
|
|
|
# if LGOROWLENGTH and (DPLGROTATE or DPLGFLIP) keywords are present |
|
8995
|
|
|
|
|
|
|
# parameter: (object_reference) |
|
8996
|
|
|
|
|
|
|
sub _rotateChartASCII { |
|
8997
|
|
|
|
|
|
|
|
|
8998
|
|
|
|
|
|
|
# get object reference |
|
8999
|
19
|
|
|
19
|
|
30
|
my $self = shift(); |
|
9000
|
|
|
|
|
|
|
|
|
9001
|
|
|
|
|
|
|
# local variables |
|
9002
|
19
|
|
|
|
|
27
|
my ($rot, $flip, $mat, $rows); |
|
9003
|
|
|
|
|
|
|
|
|
9004
|
|
|
|
|
|
|
# get the rotation and flip values |
|
9005
|
19
|
|
|
|
|
52
|
$rot = keyword($self, 'DPLGROTATE'); |
|
9006
|
19
|
|
|
|
|
34
|
$flip = keyword($self, 'DPLGFLIP'); |
|
9007
|
|
|
|
|
|
|
|
|
9008
|
|
|
|
|
|
|
# if LGOROWLENGTH and (DPLGROTATE or DPLGFLIP) keywords |
|
9009
|
19
|
50
|
33
|
|
|
29
|
if (keyword($self, 'LGOROWLENGTH') && ($rot || $flip)) { |
|
|
|
|
33
|
|
|
|
|
|
9010
|
|
|
|
|
|
|
|
|
9011
|
|
|
|
|
|
|
# get selection matrix |
|
9012
|
0
|
|
|
|
|
0
|
$mat = select_matrix($self)->rotate($rot)->flip($flip); |
|
9013
|
|
|
|
|
|
|
|
|
9014
|
|
|
|
|
|
|
# flatten matrix |
|
9015
|
0
|
|
|
|
|
0
|
$rows = ICC::Shared::flatten($mat); |
|
9016
|
|
|
|
|
|
|
|
|
9017
|
|
|
|
|
|
|
# prepend DATA_FORMAT row index (0) |
|
9018
|
0
|
|
|
|
|
0
|
unshift(@{$rows}, 0); |
|
|
0
|
|
|
|
|
0
|
|
|
9019
|
|
|
|
|
|
|
|
|
9020
|
|
|
|
|
|
|
# rearrange chart data |
|
9021
|
0
|
|
|
|
|
0
|
$self->[1] = [@{$self->[1]}[@{$rows}]]; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9022
|
|
|
|
|
|
|
|
|
9023
|
|
|
|
|
|
|
# update LGOROWLENGTH |
|
9024
|
0
|
|
|
|
|
0
|
keyword($self, 'LGOROWLENGTH', scalar(@{$mat->[0]})); |
|
|
0
|
|
|
|
|
0
|
|
|
9025
|
|
|
|
|
|
|
|
|
9026
|
|
|
|
|
|
|
} |
|
9027
|
|
|
|
|
|
|
|
|
9028
|
|
|
|
|
|
|
} |
|
9029
|
|
|
|
|
|
|
|
|
9030
|
|
|
|
|
|
|
# read chart from Adobe Swatch Exchange (.ase) file |
|
9031
|
|
|
|
|
|
|
# optional hash key: 'colorspace' |
|
9032
|
|
|
|
|
|
|
# 'colorspace' values: 'CMYK', 'LAB ', 'RGB ' or 'Gray' |
|
9033
|
|
|
|
|
|
|
# 'Gray' swatches are mapped to CMYK values |
|
9034
|
|
|
|
|
|
|
# parameters: (object_reference, file_handle, hash) |
|
9035
|
|
|
|
|
|
|
# returns: (result) |
|
9036
|
|
|
|
|
|
|
sub _readChartASE { |
|
9037
|
|
|
|
|
|
|
|
|
9038
|
|
|
|
|
|
|
# get parameters |
|
9039
|
0
|
|
|
0
|
|
0
|
my ($self, $fh, $hash) = @_; |
|
9040
|
|
|
|
|
|
|
|
|
9041
|
|
|
|
|
|
|
# local variables |
|
9042
|
0
|
|
|
|
|
0
|
my ($cs, $le, $buf, @header, $sn); |
|
9043
|
0
|
|
|
|
|
0
|
my ($mark, $type, $blen, $slen); |
|
9044
|
0
|
|
|
|
|
0
|
my ($name, $space, $cmyk, $rgb, $Lab, $dev); |
|
9045
|
|
|
|
|
|
|
|
|
9046
|
|
|
|
|
|
|
# set colorspace selector |
|
9047
|
0
|
0
|
|
|
|
0
|
$cs = $hash->{'colorspace'} if defined($hash->{'colorspace'}); |
|
9048
|
|
|
|
|
|
|
|
|
9049
|
|
|
|
|
|
|
# get little-endian flag |
|
9050
|
0
|
|
|
|
|
0
|
$le = ($Config{'byteorder'} =~ m/1234/); |
|
9051
|
|
|
|
|
|
|
|
|
9052
|
|
|
|
|
|
|
# read header (file signature, version, number of blocks) |
|
9053
|
0
|
|
|
|
|
0
|
read($fh, $buf, 12); |
|
9054
|
|
|
|
|
|
|
|
|
9055
|
|
|
|
|
|
|
# unpack buffer |
|
9056
|
0
|
|
|
|
|
0
|
@header = unpack('A4nnN', $buf); |
|
9057
|
|
|
|
|
|
|
|
|
9058
|
|
|
|
|
|
|
# verify file signature |
|
9059
|
0
|
0
|
|
|
|
0
|
($header[0] eq 'ASEF') || return('not a valid ASE file'); |
|
9060
|
|
|
|
|
|
|
|
|
9061
|
|
|
|
|
|
|
# add SAMPLE_NAME field |
|
9062
|
0
|
|
|
|
|
0
|
$sn = add_fmt($self, 'SAMPLE_NAME'); |
|
9063
|
|
|
|
|
|
|
|
|
9064
|
|
|
|
|
|
|
# set file pointer |
|
9065
|
0
|
|
|
|
|
0
|
$mark = 12; |
|
9066
|
|
|
|
|
|
|
|
|
9067
|
|
|
|
|
|
|
# for each block |
|
9068
|
0
|
|
|
|
|
0
|
for my $s (1 .. $header[3]) { |
|
9069
|
|
|
|
|
|
|
|
|
9070
|
|
|
|
|
|
|
# read block type, block length, and string length |
|
9071
|
0
|
|
|
|
|
0
|
read($fh, $buf, 8); |
|
9072
|
|
|
|
|
|
|
|
|
9073
|
|
|
|
|
|
|
# unpack buffer |
|
9074
|
0
|
|
|
|
|
0
|
($type, $blen, $slen) = unpack('nNn', $buf); |
|
9075
|
|
|
|
|
|
|
|
|
9076
|
|
|
|
|
|
|
# if color entry type |
|
9077
|
0
|
0
|
|
|
|
0
|
if ($type == 1) { |
|
9078
|
|
|
|
|
|
|
|
|
9079
|
|
|
|
|
|
|
# read color name |
|
9080
|
0
|
|
|
|
|
0
|
read($fh, $buf, 2 * $slen); |
|
9081
|
|
|
|
|
|
|
|
|
9082
|
|
|
|
|
|
|
# decode color name |
|
9083
|
0
|
|
|
|
|
0
|
$name = decode('UTF-16BE', $buf); |
|
9084
|
|
|
|
|
|
|
|
|
9085
|
|
|
|
|
|
|
# trim trailing '0' |
|
9086
|
0
|
|
|
|
|
0
|
$name =~ s/\x00$//; |
|
9087
|
|
|
|
|
|
|
|
|
9088
|
|
|
|
|
|
|
# change spaces to underscores |
|
9089
|
0
|
|
|
|
|
0
|
$name =~ s/\s/_/g; |
|
9090
|
|
|
|
|
|
|
|
|
9091
|
|
|
|
|
|
|
# read color space |
|
9092
|
0
|
|
|
|
|
0
|
read($fh, $space, 4); |
|
9093
|
|
|
|
|
|
|
|
|
9094
|
|
|
|
|
|
|
# if colorspace is CMYK |
|
9095
|
0
|
0
|
0
|
|
|
0
|
if (($space eq 'CMYK' && (! defined($cs)) || $cs eq 'CMYK')) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
9096
|
|
|
|
|
|
|
|
|
9097
|
|
|
|
|
|
|
# store color as SAMPLE_NAME |
|
9098
|
0
|
|
|
|
|
0
|
$self->[1][$s][$sn->[0]] = $name; |
|
9099
|
|
|
|
|
|
|
|
|
9100
|
|
|
|
|
|
|
# init device array |
|
9101
|
0
|
|
|
|
|
0
|
$dev = []; |
|
9102
|
|
|
|
|
|
|
|
|
9103
|
|
|
|
|
|
|
# for each CMYK value |
|
9104
|
0
|
|
|
|
|
0
|
for my $i (0 .. 3) { |
|
9105
|
|
|
|
|
|
|
|
|
9106
|
|
|
|
|
|
|
# read 32-bit floating point value |
|
9107
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4); |
|
9108
|
|
|
|
|
|
|
|
|
9109
|
|
|
|
|
|
|
# reverse bytes if long-endian system |
|
9110
|
0
|
0
|
|
|
|
0
|
$buf = reverse($buf) if ($le); |
|
9111
|
|
|
|
|
|
|
|
|
9112
|
|
|
|
|
|
|
# unpack buffer |
|
9113
|
0
|
|
|
|
|
0
|
$dev->[$i] = unpack('f', $buf); |
|
9114
|
|
|
|
|
|
|
|
|
9115
|
|
|
|
|
|
|
} |
|
9116
|
|
|
|
|
|
|
|
|
9117
|
|
|
|
|
|
|
# if CMYK slice undefined |
|
9118
|
0
|
0
|
|
|
|
0
|
if (! defined($cmyk)) { |
|
9119
|
|
|
|
|
|
|
|
|
9120
|
|
|
|
|
|
|
# add CMYK slice |
|
9121
|
0
|
|
|
|
|
0
|
$cmyk = add_fmt($self, qw(CMYK_C CMYK_M CMYK_Y CMYK_K)); |
|
9122
|
|
|
|
|
|
|
|
|
9123
|
|
|
|
|
|
|
} |
|
9124
|
|
|
|
|
|
|
|
|
9125
|
|
|
|
|
|
|
# store CMYK values |
|
9126
|
0
|
|
|
|
|
0
|
@{$self->[1][$s]}[@{$cmyk}] = map {100 * $_} @{$dev}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9127
|
|
|
|
|
|
|
|
|
9128
|
|
|
|
|
|
|
# if colorspace is RGB |
|
9129
|
|
|
|
|
|
|
} elsif (($space eq 'RGB ' && (! defined($cs)) || $cs eq 'RGB ')) { |
|
9130
|
|
|
|
|
|
|
|
|
9131
|
|
|
|
|
|
|
# store color as SAMPLE_NAME |
|
9132
|
0
|
|
|
|
|
0
|
$self->[1][$s][$sn->[0]] = $name; |
|
9133
|
|
|
|
|
|
|
|
|
9134
|
|
|
|
|
|
|
# init device array |
|
9135
|
0
|
|
|
|
|
0
|
$dev = []; |
|
9136
|
|
|
|
|
|
|
|
|
9137
|
|
|
|
|
|
|
# for each RGB value |
|
9138
|
0
|
|
|
|
|
0
|
for my $i (0 .. 2) { |
|
9139
|
|
|
|
|
|
|
|
|
9140
|
|
|
|
|
|
|
# read 32-bit floating point value |
|
9141
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4); |
|
9142
|
|
|
|
|
|
|
|
|
9143
|
|
|
|
|
|
|
# reverse bytes if long-endian system |
|
9144
|
0
|
0
|
|
|
|
0
|
$buf = reverse($buf) if ($le); |
|
9145
|
|
|
|
|
|
|
|
|
9146
|
|
|
|
|
|
|
# unpack buffer |
|
9147
|
0
|
|
|
|
|
0
|
$dev->[$i] = unpack('f', $buf); |
|
9148
|
|
|
|
|
|
|
|
|
9149
|
|
|
|
|
|
|
} |
|
9150
|
|
|
|
|
|
|
|
|
9151
|
|
|
|
|
|
|
# if RGB slice undefined |
|
9152
|
0
|
0
|
|
|
|
0
|
if (! defined($rgb)) { |
|
9153
|
|
|
|
|
|
|
|
|
9154
|
|
|
|
|
|
|
# add RGB slice |
|
9155
|
0
|
|
|
|
|
0
|
$rgb = add_fmt($self, qw(RGB_R RGB_G RGB_B)); |
|
9156
|
|
|
|
|
|
|
|
|
9157
|
|
|
|
|
|
|
} |
|
9158
|
|
|
|
|
|
|
|
|
9159
|
|
|
|
|
|
|
# store RGB values |
|
9160
|
0
|
|
|
|
|
0
|
@{$self->[1][$s]}[@{$rgb}] = map {255 * $_} @{$dev}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9161
|
|
|
|
|
|
|
|
|
9162
|
|
|
|
|
|
|
# if colorspace is L*a*b* |
|
9163
|
|
|
|
|
|
|
} elsif (($space eq 'LAB ' && (! defined($cs)) || $cs eq 'LAB ')) { |
|
9164
|
|
|
|
|
|
|
|
|
9165
|
|
|
|
|
|
|
# store color as SAMPLE_NAME |
|
9166
|
0
|
|
|
|
|
0
|
$self->[1][$s][$sn->[0]] = $name; |
|
9167
|
|
|
|
|
|
|
|
|
9168
|
|
|
|
|
|
|
# init device array |
|
9169
|
0
|
|
|
|
|
0
|
$dev = []; |
|
9170
|
|
|
|
|
|
|
|
|
9171
|
|
|
|
|
|
|
# for each L*a*b* value |
|
9172
|
0
|
|
|
|
|
0
|
for my $i (0 .. 2) { |
|
9173
|
|
|
|
|
|
|
|
|
9174
|
|
|
|
|
|
|
# read 32-bit floating point value |
|
9175
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4); |
|
9176
|
|
|
|
|
|
|
|
|
9177
|
|
|
|
|
|
|
# reverse bytes if long-endian system |
|
9178
|
0
|
0
|
|
|
|
0
|
$buf = reverse($buf) if ($le); |
|
9179
|
|
|
|
|
|
|
|
|
9180
|
|
|
|
|
|
|
# unpack buffer |
|
9181
|
0
|
|
|
|
|
0
|
$dev->[$i] = unpack('f', $buf); |
|
9182
|
|
|
|
|
|
|
|
|
9183
|
|
|
|
|
|
|
} |
|
9184
|
|
|
|
|
|
|
|
|
9185
|
|
|
|
|
|
|
# if L*a*b* slice undefined |
|
9186
|
0
|
0
|
|
|
|
0
|
if (! defined($Lab)) { |
|
9187
|
|
|
|
|
|
|
|
|
9188
|
|
|
|
|
|
|
# add L*a*b* fields |
|
9189
|
0
|
|
|
|
|
0
|
$Lab = add_fmt($self, qw(LAB_L LAB_A LAB_B)); |
|
9190
|
|
|
|
|
|
|
|
|
9191
|
|
|
|
|
|
|
} |
|
9192
|
|
|
|
|
|
|
|
|
9193
|
|
|
|
|
|
|
# store L*a*b* values |
|
9194
|
0
|
|
|
|
|
0
|
@{$self->[1][$s]}[@{$Lab}] = (100 * $dev->[0], $dev->[1], $dev->[2]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9195
|
|
|
|
|
|
|
|
|
9196
|
|
|
|
|
|
|
# if colorspace is Grayscale |
|
9197
|
|
|
|
|
|
|
} elsif (($space eq 'Gray' && (! defined($cs)) || $cs eq 'Gray')) { |
|
9198
|
|
|
|
|
|
|
|
|
9199
|
|
|
|
|
|
|
# store color as SAMPLE_NAME |
|
9200
|
0
|
|
|
|
|
0
|
$self->[1][$s][$sn->[0]] = $name; |
|
9201
|
|
|
|
|
|
|
|
|
9202
|
|
|
|
|
|
|
# read 32-bit floating point value |
|
9203
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4); |
|
9204
|
|
|
|
|
|
|
|
|
9205
|
|
|
|
|
|
|
# reverse bytes if long-endian system |
|
9206
|
0
|
0
|
|
|
|
0
|
$buf = reverse($buf) if ($le); |
|
9207
|
|
|
|
|
|
|
|
|
9208
|
|
|
|
|
|
|
# unpack buffer |
|
9209
|
0
|
|
|
|
|
0
|
$dev = [unpack('f', $buf)]; |
|
9210
|
|
|
|
|
|
|
|
|
9211
|
|
|
|
|
|
|
# if CMYK slice is undefined |
|
9212
|
0
|
0
|
|
|
|
0
|
if (! defined($cmyk)) { |
|
9213
|
|
|
|
|
|
|
|
|
9214
|
|
|
|
|
|
|
# add CMYK slice |
|
9215
|
0
|
|
|
|
|
0
|
$cmyk = add_fmt($self, qw(CMYK_C CMYK_M CMYK_Y CMYK_K)); |
|
9216
|
|
|
|
|
|
|
|
|
9217
|
|
|
|
|
|
|
} |
|
9218
|
|
|
|
|
|
|
|
|
9219
|
|
|
|
|
|
|
# store CMYK values |
|
9220
|
0
|
|
|
|
|
0
|
@{$self->[1][$s]}[@{$cmyk}] = (0, 0, 0, 100 * (1 - $dev->[0])); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9221
|
|
|
|
|
|
|
|
|
9222
|
|
|
|
|
|
|
} |
|
9223
|
|
|
|
|
|
|
|
|
9224
|
|
|
|
|
|
|
} |
|
9225
|
|
|
|
|
|
|
|
|
9226
|
|
|
|
|
|
|
# set file pointer to next block |
|
9227
|
0
|
|
|
|
|
0
|
$mark += $blen + 6; |
|
9228
|
|
|
|
|
|
|
|
|
9229
|
|
|
|
|
|
|
# seek next block |
|
9230
|
0
|
|
|
|
|
0
|
seek($fh, $mark, 0); |
|
9231
|
|
|
|
|
|
|
|
|
9232
|
|
|
|
|
|
|
} |
|
9233
|
|
|
|
|
|
|
|
|
9234
|
|
|
|
|
|
|
# return |
|
9235
|
0
|
|
|
|
|
0
|
return(); |
|
9236
|
|
|
|
|
|
|
|
|
9237
|
|
|
|
|
|
|
} |
|
9238
|
|
|
|
|
|
|
|
|
9239
|
|
|
|
|
|
|
# read chart from ICC profile |
|
9240
|
|
|
|
|
|
|
# some profiles have tags containing chart data |
|
9241
|
|
|
|
|
|
|
# parameters: (object_reference, file_handle, hash) |
|
9242
|
|
|
|
|
|
|
# returns: (result) |
|
9243
|
|
|
|
|
|
|
sub _readChartICC { |
|
9244
|
|
|
|
|
|
|
|
|
9245
|
|
|
|
|
|
|
# get parameters |
|
9246
|
0
|
|
|
0
|
|
0
|
my ($self, $fh, $hash) = @_; |
|
9247
|
|
|
|
|
|
|
|
|
9248
|
|
|
|
|
|
|
# local variables |
|
9249
|
0
|
|
|
|
|
0
|
my (@header, @tagtab, %offset, %tags, $type, $class); |
|
9250
|
0
|
|
|
|
|
0
|
my ($temp, $data, $targ, $text, $result); |
|
9251
|
|
|
|
|
|
|
|
|
9252
|
|
|
|
|
|
|
# load ICC::Profile modules, if not already included |
|
9253
|
0
|
|
|
|
|
0
|
require ICC::Profile; |
|
9254
|
|
|
|
|
|
|
|
|
9255
|
|
|
|
|
|
|
# read the profile header |
|
9256
|
0
|
0
|
|
|
|
0
|
ICC::Profile::_readICCheader($fh, \@header) || return('failed reading ICC profile header'); |
|
9257
|
|
|
|
|
|
|
|
|
9258
|
|
|
|
|
|
|
# read the profile tag table |
|
9259
|
0
|
0
|
|
|
|
0
|
ICC::Profile::_readICCtagtable($fh, \@tagtab) || return('failed reading ICC profile tag table'); |
|
9260
|
|
|
|
|
|
|
|
|
9261
|
|
|
|
|
|
|
# for each tag |
|
9262
|
0
|
|
|
|
|
0
|
for my $tag (@tagtab) { |
|
9263
|
|
|
|
|
|
|
|
|
9264
|
|
|
|
|
|
|
# if tag contains measurement data |
|
9265
|
0
|
0
|
|
|
|
0
|
if ($tag->[0] =~ m/^(?:CxF |DevD|CIED|DEVD|targ)$/) { |
|
9266
|
|
|
|
|
|
|
|
|
9267
|
|
|
|
|
|
|
# if a duplicate tag |
|
9268
|
0
|
0
|
|
|
|
0
|
if (exists($offset{$tag->[1]})) { |
|
9269
|
|
|
|
|
|
|
|
|
9270
|
|
|
|
|
|
|
# use original tag |
|
9271
|
0
|
|
|
|
|
0
|
$tags{$tag->[0]} = $offset{$tag->[1]}; |
|
9272
|
|
|
|
|
|
|
|
|
9273
|
|
|
|
|
|
|
} else { |
|
9274
|
|
|
|
|
|
|
|
|
9275
|
|
|
|
|
|
|
# seek to start of tag |
|
9276
|
0
|
|
|
|
|
0
|
seek($fh, $tag->[1], 0); |
|
9277
|
|
|
|
|
|
|
|
|
9278
|
|
|
|
|
|
|
# read tag type signature |
|
9279
|
0
|
|
|
|
|
0
|
read($fh, $type, 4); |
|
9280
|
|
|
|
|
|
|
|
|
9281
|
|
|
|
|
|
|
# convert non-word characters to underscores |
|
9282
|
0
|
|
|
|
|
0
|
$type =~ s|\W|_|g; |
|
9283
|
|
|
|
|
|
|
|
|
9284
|
|
|
|
|
|
|
# form class specifier |
|
9285
|
0
|
|
|
|
|
0
|
$class = 'ICC::Profile::' . $type; |
|
9286
|
|
|
|
|
|
|
|
|
9287
|
|
|
|
|
|
|
# if 'class->new_fh' method exists |
|
9288
|
0
|
0
|
|
|
|
0
|
if ($class->can('new_fh')) { |
|
9289
|
|
|
|
|
|
|
|
|
9290
|
|
|
|
|
|
|
# create specific tag object |
|
9291
|
0
|
|
|
|
|
0
|
$tags{$tag->[0]} = $class->new_fh($self, $fh, $tag); |
|
9292
|
|
|
|
|
|
|
|
|
9293
|
|
|
|
|
|
|
} else { |
|
9294
|
|
|
|
|
|
|
|
|
9295
|
|
|
|
|
|
|
# create generic tag object |
|
9296
|
0
|
|
|
|
|
0
|
$tags{$tag->[0]} = ICC::Profile::Generic->new_fh($self, $fh, $tag); |
|
9297
|
|
|
|
|
|
|
|
|
9298
|
|
|
|
|
|
|
} |
|
9299
|
|
|
|
|
|
|
|
|
9300
|
|
|
|
|
|
|
# save tag in hash |
|
9301
|
0
|
|
|
|
|
0
|
$offset{$tag->[1]} = $tags{$tag->[0]}; |
|
9302
|
|
|
|
|
|
|
|
|
9303
|
|
|
|
|
|
|
} |
|
9304
|
|
|
|
|
|
|
|
|
9305
|
|
|
|
|
|
|
} |
|
9306
|
|
|
|
|
|
|
|
|
9307
|
|
|
|
|
|
|
} |
|
9308
|
|
|
|
|
|
|
|
|
9309
|
|
|
|
|
|
|
# if creator is i1Profiler and 'CxF ' tag exists |
|
9310
|
0
|
0
|
0
|
|
|
0
|
if ($header[23] eq 'XRCM' && exists($tags{'CxF '})) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
9311
|
|
|
|
|
|
|
|
|
9312
|
|
|
|
|
|
|
# close file handle |
|
9313
|
0
|
|
|
|
|
0
|
close($fh); |
|
9314
|
|
|
|
|
|
|
|
|
9315
|
|
|
|
|
|
|
# open file handle to CxF3 string |
|
9316
|
0
|
|
|
|
|
0
|
open($fh, '<', \$tags{'CxF '}->text()); |
|
9317
|
|
|
|
|
|
|
|
|
9318
|
|
|
|
|
|
|
# make chart from CxF3 string |
|
9319
|
0
|
|
|
|
|
0
|
return(_readChartCxF3($self, $fh, $hash)); |
|
9320
|
|
|
|
|
|
|
|
|
9321
|
|
|
|
|
|
|
# if creator is ProfileMaker and 'DevD' / 'CIED' tags exist |
|
9322
|
|
|
|
|
|
|
} elsif ($header[23] eq 'LOGO' && exists($tags{'DevD'}) && exists($tags{'CIED'})) { |
|
9323
|
|
|
|
|
|
|
|
|
9324
|
|
|
|
|
|
|
# close file handle |
|
9325
|
0
|
|
|
|
|
0
|
close($fh); |
|
9326
|
|
|
|
|
|
|
|
|
9327
|
|
|
|
|
|
|
# open file handle to 'DevD' text string |
|
9328
|
0
|
|
|
|
|
0
|
open($fh, '<', \$tags{'DevD'}->text()); |
|
9329
|
|
|
|
|
|
|
|
|
9330
|
|
|
|
|
|
|
# read chart from text |
|
9331
|
0
|
0
|
|
|
|
0
|
($result = _readChartASCII($self, $fh, $hash)) && return("failed reading ICC profile DEVD tag, $result"); |
|
9332
|
|
|
|
|
|
|
|
|
9333
|
|
|
|
|
|
|
# close file handle |
|
9334
|
0
|
|
|
|
|
0
|
close($fh); |
|
9335
|
|
|
|
|
|
|
|
|
9336
|
|
|
|
|
|
|
# make temporary chart object |
|
9337
|
0
|
|
|
|
|
0
|
$temp = ICC::Support::Chart->new(); |
|
9338
|
|
|
|
|
|
|
|
|
9339
|
|
|
|
|
|
|
# open file handle to 'CIED' text string |
|
9340
|
0
|
|
|
|
|
0
|
open($fh, '<', \$tags{'CIED'}->text()); |
|
9341
|
|
|
|
|
|
|
|
|
9342
|
|
|
|
|
|
|
# read chart from text |
|
9343
|
0
|
0
|
|
|
|
0
|
($result = _readChartASCII($temp, $fh, $hash)) && return("failed reading ICC profile CIED tag, $result"); |
|
9344
|
|
|
|
|
|
|
|
|
9345
|
|
|
|
|
|
|
# get data slice (all rows, spectral, XYZ and L*a*b* columns) |
|
9346
|
0
|
|
|
|
|
0
|
$data = slice($temp, [0 .. $#{$temp->[1]}], [grep {$temp->[1][0][$_] =~ m/^(nm\d{3}|XYZ_(X|Y|Z)|LAB_(L|A|B))$/} (0 .. $#{$temp->[1][0]})]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9347
|
|
|
|
|
|
|
|
|
9348
|
|
|
|
|
|
|
# append to chart |
|
9349
|
0
|
|
|
|
|
0
|
add_cols($self, $data); |
|
9350
|
|
|
|
|
|
|
|
|
9351
|
|
|
|
|
|
|
# for each keyword |
|
9352
|
0
|
|
|
|
|
0
|
for my $key (@{$temp->[3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9353
|
|
|
|
|
|
|
|
|
9354
|
|
|
|
|
|
|
# if keyword not in main chart |
|
9355
|
0
|
0
|
|
|
|
0
|
if (0 == grep {$key->[0] eq $_->[0]} @{$self->[3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9356
|
|
|
|
|
|
|
|
|
9357
|
|
|
|
|
|
|
# append keyword/value |
|
9358
|
0
|
|
|
|
|
0
|
push(@{$self->[3]}, $key); |
|
|
0
|
|
|
|
|
0
|
|
|
9359
|
|
|
|
|
|
|
|
|
9360
|
|
|
|
|
|
|
} |
|
9361
|
|
|
|
|
|
|
|
|
9362
|
|
|
|
|
|
|
} |
|
9363
|
|
|
|
|
|
|
|
|
9364
|
|
|
|
|
|
|
# return |
|
9365
|
0
|
|
|
|
|
0
|
return(); |
|
9366
|
|
|
|
|
|
|
|
|
9367
|
|
|
|
|
|
|
# if creator is Monaco and 'DEVD' tag exists (some old profiles are identified by preferred CMM) |
|
9368
|
|
|
|
|
|
|
} elsif (($header[23] eq 'MONS' || $header[1] eq 'mnco') && exists($tags{'DEVD'})) { |
|
9369
|
|
|
|
|
|
|
|
|
9370
|
|
|
|
|
|
|
# read chart from Monaco 'DEVD' tag |
|
9371
|
0
|
|
|
|
|
0
|
return(_readMonacoDEVD($self, $tags{'DEVD'}->data(), \@header)); |
|
9372
|
|
|
|
|
|
|
|
|
9373
|
|
|
|
|
|
|
# if 'targ' tag exists |
|
9374
|
|
|
|
|
|
|
} elsif (exists($tags{'targ'})) { |
|
9375
|
|
|
|
|
|
|
|
|
9376
|
|
|
|
|
|
|
# get the 'targ' tag |
|
9377
|
0
|
|
|
|
|
0
|
$targ = $tags{'targ'}; |
|
9378
|
|
|
|
|
|
|
|
|
9379
|
|
|
|
|
|
|
# if an 'ICC::Profile::text' object |
|
9380
|
0
|
0
|
|
|
|
0
|
if (ref($targ) eq 'ICC::Profile::text') { |
|
|
|
0
|
|
|
|
|
|
|
9381
|
|
|
|
|
|
|
|
|
9382
|
|
|
|
|
|
|
# get 'targ' tag text string |
|
9383
|
0
|
|
|
|
|
0
|
$text = $targ->text(); |
|
9384
|
|
|
|
|
|
|
|
|
9385
|
|
|
|
|
|
|
} elsif (ref($targ) eq 'ICC::Profile::Generic') { |
|
9386
|
|
|
|
|
|
|
|
|
9387
|
|
|
|
|
|
|
# get 'targ' tag text string |
|
9388
|
0
|
|
|
|
|
0
|
$text = $targ->data(); |
|
9389
|
|
|
|
|
|
|
|
|
9390
|
|
|
|
|
|
|
} else { |
|
9391
|
|
|
|
|
|
|
|
|
9392
|
|
|
|
|
|
|
# return |
|
9393
|
0
|
|
|
|
|
0
|
return("failed reading ICC profile 'targ' tag"); |
|
9394
|
|
|
|
|
|
|
|
|
9395
|
|
|
|
|
|
|
} |
|
9396
|
|
|
|
|
|
|
|
|
9397
|
|
|
|
|
|
|
# if reference to ICC Characterization Data Registry |
|
9398
|
0
|
0
|
|
|
|
0
|
if ($text =~ m/^ICCHDAT (.*)$/) { |
|
9399
|
|
|
|
|
|
|
|
|
9400
|
|
|
|
|
|
|
# return |
|
9401
|
0
|
|
|
|
|
0
|
return("profile derived from $1 characterization data, available at www.color.org"); |
|
9402
|
|
|
|
|
|
|
|
|
9403
|
|
|
|
|
|
|
} else { |
|
9404
|
|
|
|
|
|
|
|
|
9405
|
|
|
|
|
|
|
# close file handle |
|
9406
|
0
|
|
|
|
|
0
|
close($fh); |
|
9407
|
|
|
|
|
|
|
|
|
9408
|
|
|
|
|
|
|
# open file handle to text string |
|
9409
|
0
|
|
|
|
|
0
|
open($fh, '<', \$text); |
|
9410
|
|
|
|
|
|
|
|
|
9411
|
|
|
|
|
|
|
# read chart from text |
|
9412
|
0
|
|
|
|
|
0
|
return(_readChartASCII($self, $fh, $hash)); |
|
9413
|
|
|
|
|
|
|
|
|
9414
|
|
|
|
|
|
|
} |
|
9415
|
|
|
|
|
|
|
|
|
9416
|
|
|
|
|
|
|
} |
|
9417
|
|
|
|
|
|
|
|
|
9418
|
|
|
|
|
|
|
# return |
|
9419
|
0
|
|
|
|
|
0
|
return('failed reading ICC profile characterization data'); |
|
9420
|
|
|
|
|
|
|
|
|
9421
|
|
|
|
|
|
|
} |
|
9422
|
|
|
|
|
|
|
|
|
9423
|
|
|
|
|
|
|
# read chart from Monaco 'DEVD' tag |
|
9424
|
|
|
|
|
|
|
# parameters: (object_reference, tag_data, profile_header) |
|
9425
|
|
|
|
|
|
|
# returns: (result) |
|
9426
|
|
|
|
|
|
|
sub _readMonacoDEVD { |
|
9427
|
|
|
|
|
|
|
|
|
9428
|
|
|
|
|
|
|
# get parameters |
|
9429
|
0
|
|
|
0
|
|
0
|
my ($self, $data, $header) = @_; |
|
9430
|
|
|
|
|
|
|
|
|
9431
|
|
|
|
|
|
|
# local variables |
|
9432
|
0
|
|
|
|
|
0
|
my ($big, %cshash, $cs, $nc, $fix, $ix, $tag, $tac, $limit, $mult, $dev, $lab); |
|
9433
|
0
|
|
|
|
|
0
|
my ($ns, $sec, @devfix, @nd, $nt, @devstep, @dev, @cmy, @sum, @temp, $m, @dat); |
|
9434
|
|
|
|
|
|
|
|
|
9435
|
|
|
|
|
|
|
# get big-endian flag (true if our system is big-endian) |
|
9436
|
0
|
|
|
|
|
0
|
$big = ($Config{'byteorder'} =~ m/4321/); |
|
9437
|
|
|
|
|
|
|
|
|
9438
|
|
|
|
|
|
|
# colorspace hash (colorspace => number_channels) |
|
9439
|
0
|
|
|
|
|
0
|
%cshash = ('RGB ' => 3, 'CMYK' => 4, '5CLR' => 5, '6CLR' => 6, '7CLR' => 7, '8CLR' => 8); |
|
9440
|
|
|
|
|
|
|
|
|
9441
|
|
|
|
|
|
|
# initialize fixed value array |
|
9442
|
0
|
|
|
|
|
0
|
@devfix = (); |
|
9443
|
|
|
|
|
|
|
|
|
9444
|
|
|
|
|
|
|
# get colorspace from profile header |
|
9445
|
0
|
|
|
|
|
0
|
$cs = $header->[4]; |
|
9446
|
|
|
|
|
|
|
|
|
9447
|
|
|
|
|
|
|
# lookup number of channels |
|
9448
|
0
|
|
|
|
|
0
|
$nc = $cshash{$cs}; |
|
9449
|
|
|
|
|
|
|
|
|
9450
|
|
|
|
|
|
|
# set number of fixed channels |
|
9451
|
0
|
|
|
|
|
0
|
$fix = $nc - 3; |
|
9452
|
|
|
|
|
|
|
|
|
9453
|
|
|
|
|
|
|
# set index to start of first tag |
|
9454
|
0
|
|
|
|
|
0
|
$ix = 28; |
|
9455
|
|
|
|
|
|
|
|
|
9456
|
|
|
|
|
|
|
# set tag value |
|
9457
|
0
|
|
|
|
|
0
|
$tag = pack('N', 0x002D); |
|
9458
|
|
|
|
|
|
|
|
|
9459
|
|
|
|
|
|
|
# find TAC tag |
|
9460
|
0
|
|
0
|
|
|
0
|
do {$ix = index($data, $tag, $ix)} while ($ix >= 0 && $ix % 4 && $ix++); |
|
|
0
|
|
0
|
|
|
0
|
|
|
9461
|
|
|
|
|
|
|
|
|
9462
|
|
|
|
|
|
|
# verify tag found |
|
9463
|
0
|
0
|
|
|
|
0
|
($ix >= 0) || return('failed reading TAC from Monaco DEVD tag'); |
|
9464
|
|
|
|
|
|
|
|
|
9465
|
|
|
|
|
|
|
# get TAC value |
|
9466
|
0
|
0
|
|
|
|
0
|
$tac = 100 * unpack('d', $big ? substr($data, $ix + 4, 8) : reverse(substr($data, $ix + 4, 8))); |
|
9467
|
|
|
|
|
|
|
|
|
9468
|
|
|
|
|
|
|
# if RGB colorspace |
|
9469
|
0
|
0
|
|
|
|
0
|
if ($cs eq 'RGB ') { |
|
|
|
0
|
|
|
|
|
|
|
9470
|
|
|
|
|
|
|
|
|
9471
|
|
|
|
|
|
|
# add device fields |
|
9472
|
0
|
|
|
|
|
0
|
$dev = add_fmt($self, qw(RGB_R RGB_G RGB_B)); |
|
9473
|
|
|
|
|
|
|
|
|
9474
|
|
|
|
|
|
|
# set device multiplier |
|
9475
|
0
|
|
|
|
|
0
|
$mult = 255; |
|
9476
|
|
|
|
|
|
|
|
|
9477
|
|
|
|
|
|
|
# if CMYK colorspace |
|
9478
|
|
|
|
|
|
|
} elsif ($cs eq 'CMYK') { |
|
9479
|
|
|
|
|
|
|
|
|
9480
|
|
|
|
|
|
|
# add device fields |
|
9481
|
0
|
|
|
|
|
0
|
$dev = add_fmt($self, qw(CMYK_C CMYK_M CMYK_Y CMYK_K)); |
|
9482
|
|
|
|
|
|
|
|
|
9483
|
|
|
|
|
|
|
# set device multiplier |
|
9484
|
0
|
|
|
|
|
0
|
$mult = 100; |
|
9485
|
|
|
|
|
|
|
|
|
9486
|
|
|
|
|
|
|
} else { |
|
9487
|
|
|
|
|
|
|
|
|
9488
|
|
|
|
|
|
|
# add device fields |
|
9489
|
0
|
|
|
|
|
0
|
$dev = add_fmt($self, map {"$cs\_$_"} (1 .. $nc)); |
|
|
0
|
|
|
|
|
0
|
|
|
9490
|
|
|
|
|
|
|
|
|
9491
|
|
|
|
|
|
|
# set device multiplier |
|
9492
|
0
|
|
|
|
|
0
|
$mult = 100; |
|
9493
|
|
|
|
|
|
|
|
|
9494
|
|
|
|
|
|
|
} |
|
9495
|
|
|
|
|
|
|
|
|
9496
|
|
|
|
|
|
|
# add L*a*b* fields |
|
9497
|
0
|
|
|
|
|
0
|
$lab = add_fmt($self, qw(LAB_L LAB_A LAB_B)); |
|
9498
|
|
|
|
|
|
|
|
|
9499
|
|
|
|
|
|
|
# advance index |
|
9500
|
0
|
|
|
|
|
0
|
$ix += 12; |
|
9501
|
|
|
|
|
|
|
|
|
9502
|
|
|
|
|
|
|
# set tag value |
|
9503
|
0
|
|
|
|
|
0
|
$tag = pack('N', 0x0027); |
|
9504
|
|
|
|
|
|
|
|
|
9505
|
|
|
|
|
|
|
# find data group tag |
|
9506
|
0
|
|
0
|
|
|
0
|
do {$ix = index($data, $tag, $ix)} while ($ix >= 0 && $ix % 4 && $ix++); |
|
|
0
|
|
0
|
|
|
0
|
|
|
9507
|
|
|
|
|
|
|
|
|
9508
|
|
|
|
|
|
|
# verify tag found |
|
9509
|
0
|
0
|
|
|
|
0
|
($ix >= 0) || return('failed reading data group from Monaco DEVD tag'); |
|
9510
|
|
|
|
|
|
|
|
|
9511
|
|
|
|
|
|
|
# get number data sections in group |
|
9512
|
0
|
|
|
|
|
0
|
$ns = unpack('N', substr($data, $ix + 4, 4)); |
|
9513
|
|
|
|
|
|
|
|
|
9514
|
|
|
|
|
|
|
# advance index |
|
9515
|
0
|
|
|
|
|
0
|
$ix += 8; |
|
9516
|
|
|
|
|
|
|
|
|
9517
|
|
|
|
|
|
|
# for data each section |
|
9518
|
0
|
|
|
|
|
0
|
for my $s (0 .. $ns - 1) { |
|
9519
|
|
|
|
|
|
|
|
|
9520
|
|
|
|
|
|
|
# verify tag 0x0028 |
|
9521
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x0028)) || return(0); |
|
9522
|
|
|
|
|
|
|
|
|
9523
|
|
|
|
|
|
|
# get section index |
|
9524
|
0
|
|
|
|
|
0
|
$sec = unpack('N', substr($data, $ix + 4, 4)); |
|
9525
|
|
|
|
|
|
|
|
|
9526
|
|
|
|
|
|
|
# verify section index is correct |
|
9527
|
0
|
0
|
|
|
|
0
|
($sec == $s) || return('failed reading section index from Monaco DEVD tag'); |
|
9528
|
|
|
|
|
|
|
|
|
9529
|
|
|
|
|
|
|
# advance index |
|
9530
|
0
|
|
|
|
|
0
|
$ix += 8; |
|
9531
|
|
|
|
|
|
|
|
|
9532
|
|
|
|
|
|
|
# verify tag 0x002A (fixed device values) |
|
9533
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x002A)) || return('failed reading fixed device values from Monaco DEVD tag'); |
|
9534
|
|
|
|
|
|
|
|
|
9535
|
|
|
|
|
|
|
# if fixed device values (none for RGB) |
|
9536
|
0
|
0
|
|
|
|
0
|
if ($fix) { |
|
9537
|
|
|
|
|
|
|
|
|
9538
|
|
|
|
|
|
|
# get fixed device values (black plus any extra colors, e.g. orange or green) |
|
9539
|
0
|
0
|
|
|
|
0
|
@devfix = unpack("d$fix", $big ? substr($data, $ix + 4, 8 * $fix) : reverse(substr($data, $ix + 4, 8 * $fix))); |
|
9540
|
|
|
|
|
|
|
|
|
9541
|
|
|
|
|
|
|
# reverse array if little-endian |
|
9542
|
0
|
0
|
|
|
|
0
|
@devfix = reverse(@devfix) if (! $big); |
|
9543
|
|
|
|
|
|
|
|
|
9544
|
|
|
|
|
|
|
# apply multiplier |
|
9545
|
0
|
|
|
|
|
0
|
@devfix = map {$_ * $mult} @devfix; |
|
|
0
|
|
|
|
|
0
|
|
|
9546
|
|
|
|
|
|
|
|
|
9547
|
|
|
|
|
|
|
} |
|
9548
|
|
|
|
|
|
|
|
|
9549
|
|
|
|
|
|
|
# advance index |
|
9550
|
0
|
|
|
|
|
0
|
$ix += 8 * $fix + 4; |
|
9551
|
|
|
|
|
|
|
|
|
9552
|
|
|
|
|
|
|
# verify tag 0x002B (step counts by color) |
|
9553
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x002B)) || return('failed reading step counts from Monaco DEVD tag'); |
|
9554
|
|
|
|
|
|
|
|
|
9555
|
|
|
|
|
|
|
# get device step counts |
|
9556
|
0
|
|
|
|
|
0
|
@nd = unpack('N3', substr($data, $ix + 4, 12)); |
|
9557
|
|
|
|
|
|
|
|
|
9558
|
|
|
|
|
|
|
# get total number of steps |
|
9559
|
0
|
|
|
|
|
0
|
$nt = $nd[0] + $nd[1] + $nd[2]; |
|
9560
|
|
|
|
|
|
|
|
|
9561
|
|
|
|
|
|
|
# advance index |
|
9562
|
0
|
|
|
|
|
0
|
$ix += 16; |
|
9563
|
|
|
|
|
|
|
|
|
9564
|
|
|
|
|
|
|
# verify tag 0x002C (step values by color) |
|
9565
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x002C)) || return('failed reading step values from Monaco DEVD tag'); |
|
9566
|
|
|
|
|
|
|
|
|
9567
|
|
|
|
|
|
|
# get step values |
|
9568
|
0
|
0
|
|
|
|
0
|
@devstep = unpack("d$nt", $big ? substr($data, $ix + 4, 8 * $nt) : reverse(substr($data, $ix + 4, 8 * $nt))); |
|
9569
|
|
|
|
|
|
|
|
|
9570
|
|
|
|
|
|
|
# reverse array if little-endian |
|
9571
|
0
|
0
|
|
|
|
0
|
@devstep = reverse(@devstep) if (! $big); |
|
9572
|
|
|
|
|
|
|
|
|
9573
|
|
|
|
|
|
|
# apply multiplier |
|
9574
|
0
|
|
|
|
|
0
|
@devstep = map {$_ * $mult} @devstep; |
|
|
0
|
|
|
|
|
0
|
|
|
9575
|
|
|
|
|
|
|
|
|
9576
|
|
|
|
|
|
|
# advance index |
|
9577
|
0
|
|
|
|
|
0
|
$ix += 8 * $nt + 4; |
|
9578
|
|
|
|
|
|
|
|
|
9579
|
|
|
|
|
|
|
# initialize arrays |
|
9580
|
0
|
|
|
|
|
0
|
@dev = (); |
|
9581
|
0
|
|
|
|
|
0
|
@sum = (); |
|
9582
|
0
|
|
|
|
|
0
|
@temp = (); |
|
9583
|
|
|
|
|
|
|
|
|
9584
|
|
|
|
|
|
|
# if RGB colorspace |
|
9585
|
0
|
0
|
|
|
|
0
|
if ($cs eq 'RGB ') { |
|
9586
|
|
|
|
|
|
|
|
|
9587
|
|
|
|
|
|
|
# for each blue step |
|
9588
|
0
|
|
|
|
|
0
|
for my $i (0 .. $nd[2] - 1) { |
|
9589
|
|
|
|
|
|
|
|
|
9590
|
|
|
|
|
|
|
# for each green step |
|
9591
|
0
|
|
|
|
|
0
|
for my $j (0 .. $nd[1] - 1) { |
|
9592
|
|
|
|
|
|
|
|
|
9593
|
|
|
|
|
|
|
# for each red step |
|
9594
|
0
|
|
|
|
|
0
|
for my $k (0 .. $nd[0] - 1) { |
|
9595
|
|
|
|
|
|
|
|
|
9596
|
|
|
|
|
|
|
# save RGB values |
|
9597
|
0
|
|
|
|
|
0
|
push(@dev, $devstep[$k], $devstep[$j + $nd[0]], $devstep[$i + $nd[0] + $nd[1]]); |
|
9598
|
|
|
|
|
|
|
|
|
9599
|
|
|
|
|
|
|
} |
|
9600
|
|
|
|
|
|
|
|
|
9601
|
|
|
|
|
|
|
} |
|
9602
|
|
|
|
|
|
|
|
|
9603
|
|
|
|
|
|
|
} |
|
9604
|
|
|
|
|
|
|
|
|
9605
|
|
|
|
|
|
|
# if CMYK or NCLR colorspace |
|
9606
|
|
|
|
|
|
|
} else { |
|
9607
|
|
|
|
|
|
|
|
|
9608
|
|
|
|
|
|
|
# for each yellow step |
|
9609
|
0
|
|
|
|
|
0
|
for my $i (0 .. $nd[2] - 1) { |
|
9610
|
|
|
|
|
|
|
|
|
9611
|
|
|
|
|
|
|
# for each cyan step |
|
9612
|
0
|
|
|
|
|
0
|
for my $j (0 .. $nd[0] - 1) { |
|
9613
|
|
|
|
|
|
|
|
|
9614
|
|
|
|
|
|
|
# for each magenta step |
|
9615
|
0
|
|
|
|
|
0
|
for my $k (0 .. $nd[1] - 1) { |
|
9616
|
|
|
|
|
|
|
|
|
9617
|
|
|
|
|
|
|
# get CMY values |
|
9618
|
0
|
|
|
|
|
0
|
@cmy = ($devstep[$j], $devstep[$k + $nd[0]], $devstep[$i + $nd[0] + $nd[1]]); |
|
9619
|
|
|
|
|
|
|
|
|
9620
|
|
|
|
|
|
|
# save CMY values |
|
9621
|
0
|
|
|
|
|
0
|
push(@temp, [@cmy]); |
|
9622
|
|
|
|
|
|
|
|
|
9623
|
|
|
|
|
|
|
# save total ink value |
|
9624
|
0
|
|
|
|
|
0
|
push(@sum, List::Util::sum(@cmy, @devfix)); |
|
9625
|
|
|
|
|
|
|
|
|
9626
|
|
|
|
|
|
|
} |
|
9627
|
|
|
|
|
|
|
|
|
9628
|
|
|
|
|
|
|
} |
|
9629
|
|
|
|
|
|
|
|
|
9630
|
|
|
|
|
|
|
} |
|
9631
|
|
|
|
|
|
|
|
|
9632
|
|
|
|
|
|
|
# initialize actual ink limit |
|
9633
|
0
|
|
|
|
|
0
|
$limit = $nc * 100; |
|
9634
|
|
|
|
|
|
|
|
|
9635
|
|
|
|
|
|
|
# find actual ink limit (smallest value greater than TAC) |
|
9636
|
0
|
0
|
0
|
|
|
0
|
for (@sum) {$limit = $_ if ($_ > $tac && $_ < $limit)}; |
|
|
0
|
|
|
|
|
0
|
|
|
9637
|
|
|
|
|
|
|
|
|
9638
|
|
|
|
|
|
|
# for each sample |
|
9639
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#sum) { |
|
9640
|
|
|
|
|
|
|
|
|
9641
|
|
|
|
|
|
|
# get cmy values |
|
9642
|
0
|
|
|
|
|
0
|
@cmy = @{$temp[$i]}; |
|
|
0
|
|
|
|
|
0
|
|
|
9643
|
|
|
|
|
|
|
|
|
9644
|
|
|
|
|
|
|
# if sample within ink limit, or a corner point |
|
9645
|
0
|
0
|
0
|
|
|
0
|
if ($sum[$i] <= $limit || ((0 < grep {$_ == 0} @cmy) && (0 < grep {$_ == 100} @cmy))) { |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9646
|
|
|
|
|
|
|
|
|
9647
|
|
|
|
|
|
|
# copy cmy values |
|
9648
|
0
|
|
|
|
|
0
|
push(@dev, @cmy); |
|
9649
|
|
|
|
|
|
|
|
|
9650
|
|
|
|
|
|
|
} |
|
9651
|
|
|
|
|
|
|
|
|
9652
|
|
|
|
|
|
|
} |
|
9653
|
|
|
|
|
|
|
|
|
9654
|
|
|
|
|
|
|
} |
|
9655
|
|
|
|
|
|
|
|
|
9656
|
|
|
|
|
|
|
# verify tag 0x0032 (L*a*b* sample data) |
|
9657
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x0032)) || return('failed reading L*a*b* data from Monaco DEVD tag'); |
|
9658
|
|
|
|
|
|
|
|
|
9659
|
|
|
|
|
|
|
# get number of values |
|
9660
|
0
|
|
|
|
|
0
|
$m = unpack('N', substr($data, $ix + 4, 4)) * 3; |
|
9661
|
|
|
|
|
|
|
|
|
9662
|
|
|
|
|
|
|
# get L*a*b* color data |
|
9663
|
0
|
0
|
|
|
|
0
|
@dat = unpack("d$m", $big ? substr($data, $ix + 8, 8 * $m) : reverse(substr($data, $ix + 8, 8 * $m))); |
|
9664
|
|
|
|
|
|
|
|
|
9665
|
|
|
|
|
|
|
# reverse array if little-endian |
|
9666
|
0
|
0
|
|
|
|
0
|
@dat = reverse(@dat) if (! $big); |
|
9667
|
|
|
|
|
|
|
|
|
9668
|
|
|
|
|
|
|
# advance index |
|
9669
|
0
|
|
|
|
|
0
|
$ix += 8 * $m + 8; |
|
9670
|
|
|
|
|
|
|
|
|
9671
|
|
|
|
|
|
|
# verify @dev and @dat are same size |
|
9672
|
0
|
0
|
|
|
|
0
|
(scalar(@dev) == scalar(@dat)) || return('failed comparing data counts of Monaco DEVD tag'); |
|
9673
|
|
|
|
|
|
|
|
|
9674
|
|
|
|
|
|
|
# for each sample (3 values per sample) |
|
9675
|
0
|
|
|
|
|
0
|
for my $i (0 .. ($m/3 - 1)) { |
|
9676
|
|
|
|
|
|
|
|
|
9677
|
|
|
|
|
|
|
# add sample data to object |
|
9678
|
0
|
|
|
|
|
0
|
push (@{$self->[1]}, [@dev[($i * 3) .. ($i * 3 + 2)], @devfix, @dat[($i * 3) .. ($i * 3 + 2)]]); |
|
|
0
|
|
|
|
|
0
|
|
|
9679
|
|
|
|
|
|
|
|
|
9680
|
|
|
|
|
|
|
} |
|
9681
|
|
|
|
|
|
|
|
|
9682
|
|
|
|
|
|
|
# verify tag 0x0029 (end of section) |
|
9683
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x0029)) || return('failed reading section end from Monaco DEVD tag'); |
|
9684
|
|
|
|
|
|
|
|
|
9685
|
|
|
|
|
|
|
# advance index |
|
9686
|
0
|
|
|
|
|
0
|
$ix += 4; |
|
9687
|
|
|
|
|
|
|
|
|
9688
|
|
|
|
|
|
|
} |
|
9689
|
|
|
|
|
|
|
|
|
9690
|
|
|
|
|
|
|
# verify tag 0x0030 (end of data) |
|
9691
|
0
|
0
|
|
|
|
0
|
(substr($data, $ix, 4) eq pack('N', 0x0030)) || return('failed reading data end from Monaco DEVD tag'); |
|
9692
|
|
|
|
|
|
|
|
|
9693
|
|
|
|
|
|
|
# add 'CREATED' keyword/value from header date/time |
|
9694
|
0
|
|
|
|
|
0
|
push(@{$self->[3]}, ['CREATED', sprintf('%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ', @{$header}[6 .. 11])]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9695
|
|
|
|
|
|
|
|
|
9696
|
|
|
|
|
|
|
# return |
|
9697
|
0
|
|
|
|
|
0
|
return(); |
|
9698
|
|
|
|
|
|
|
|
|
9699
|
|
|
|
|
|
|
} |
|
9700
|
|
|
|
|
|
|
|
|
9701
|
|
|
|
|
|
|
# read chart from SpectraShop (.ss3) file |
|
9702
|
|
|
|
|
|
|
# parameters: (object_reference, file_handle, hash) |
|
9703
|
|
|
|
|
|
|
sub _readChartSS3 { |
|
9704
|
|
|
|
|
|
|
|
|
9705
|
|
|
|
|
|
|
# get parameters |
|
9706
|
0
|
|
|
0
|
|
0
|
my ($self, $fh, $hash) = @_; |
|
9707
|
|
|
|
|
|
|
|
|
9708
|
|
|
|
|
|
|
# local variables |
|
9709
|
0
|
|
|
|
|
0
|
my (%fmt, $buf, @data, $notes); |
|
9710
|
0
|
|
|
|
|
0
|
my ($meta, $measure, %tally, @keys, $value, $nm); |
|
9711
|
|
|
|
|
|
|
|
|
9712
|
|
|
|
|
|
|
# metadata format array (v32) |
|
9713
|
0
|
|
|
|
|
0
|
$fmt{'32'} = [ |
|
9714
|
|
|
|
|
|
|
[qw(Identifier_1 SAMPLE_NAME P)], |
|
9715
|
|
|
|
|
|
|
[qw(Identifier_2 SAMPLE_ID2 P)], |
|
9716
|
|
|
|
|
|
|
[qw(Identifier_3 SAMPLE_ID3 P)], |
|
9717
|
|
|
|
|
|
|
[qw(Material MATERIAL P)], |
|
9718
|
|
|
|
|
|
|
[qw(Manufacturer MANUFACTURER P)], |
|
9719
|
|
|
|
|
|
|
[qw(Model MODEL P)], |
|
9720
|
|
|
|
|
|
|
[qw(Serial_Number SERIAL_NUMBER P)], |
|
9721
|
|
|
|
|
|
|
[qw(Production_Date PROD_DATE P)], |
|
9722
|
|
|
|
|
|
|
[qw(Surface SURFACE P)], |
|
9723
|
|
|
|
|
|
|
[qw(Originator ORIGINATOR P)], |
|
9724
|
|
|
|
|
|
|
[qw(Creation_Date CREATED P)], |
|
9725
|
|
|
|
|
|
|
[qw(Comments NOTE P)], |
|
9726
|
|
|
|
|
|
|
[qw(Instrument INSTRUMENTATION P)], |
|
9727
|
|
|
|
|
|
|
[qw(Spectrum_Type SPECTRUM_TYPE n), [qw(Emissive-light Emissive-monitor Observer Reflective Transmissive)]], |
|
9728
|
|
|
|
|
|
|
[qw(Filter MEASUREMENT_FILTER P)], |
|
9729
|
|
|
|
|
|
|
[qw(Geometry MEASUREMENT_GEOMETRY P)], |
|
9730
|
|
|
|
|
|
|
[qw(Aperture MEASUREMENT_APERTURE P)], |
|
9731
|
|
|
|
|
|
|
[qw(Data_Reference DATA_REFERENCE P)], |
|
9732
|
|
|
|
|
|
|
[qw(Illuminant MEASUREMENT_SOURCE P)], |
|
9733
|
|
|
|
|
|
|
[qw(Backing SAMPLE_BACKING P)], |
|
9734
|
|
|
|
|
|
|
[qw(Measurements NSAMPLES n)], |
|
9735
|
|
|
|
|
|
|
[qw(Notes ACQUIRE_NOTE P)], |
|
9736
|
|
|
|
|
|
|
]; |
|
9737
|
|
|
|
|
|
|
|
|
9738
|
|
|
|
|
|
|
# metadata format array (v50) |
|
9739
|
0
|
|
|
|
|
0
|
$fmt{'50'} = [ |
|
9740
|
|
|
|
|
|
|
[qw(Identifier_1 SAMPLE_NAME P)], |
|
9741
|
|
|
|
|
|
|
[qw(Identifier_2 SAMPLE_ID2 P)], |
|
9742
|
|
|
|
|
|
|
[qw(Identifier_3 SAMPLE_ID3 P)], |
|
9743
|
|
|
|
|
|
|
[qw(Material MATERIAL P)], |
|
9744
|
|
|
|
|
|
|
[qw(Manufacturer MANUFACTURER P)], |
|
9745
|
|
|
|
|
|
|
[qw(Model MODEL P)], |
|
9746
|
|
|
|
|
|
|
[qw(Serial_Number SERIAL_NUMBER P)], |
|
9747
|
|
|
|
|
|
|
[qw(Production_Date PROD_DATE P)], |
|
9748
|
|
|
|
|
|
|
[qw(Surface SURFACE P)], |
|
9749
|
|
|
|
|
|
|
[qw(Originator ORIGINATOR P)], |
|
9750
|
|
|
|
|
|
|
[qw(Creation_Date CREATED P)], |
|
9751
|
|
|
|
|
|
|
[qw(Comments NOTE P)], |
|
9752
|
|
|
|
|
|
|
[qw(Instrument INSTRUMENTATION P)], |
|
9753
|
|
|
|
|
|
|
[qw(Serial_Number INSTRUMENT_SERIAL_NUMBER P)], |
|
9754
|
|
|
|
|
|
|
[qw(Spectrum_Type SPECTRUM_TYPE n), [qw(Emissive-light Emissive-monitor Observer Reflective Transmissive)]], |
|
9755
|
|
|
|
|
|
|
[qw(Filter MEASUREMENT_FILTER P)], |
|
9756
|
|
|
|
|
|
|
[qw(Geometry MEASUREMENT_GEOMETRY P)], |
|
9757
|
|
|
|
|
|
|
[qw(Aperture MEASUREMENT_APERTURE P)], |
|
9758
|
|
|
|
|
|
|
[qw(Data_Reference DATA_REFERENCE P)], |
|
9759
|
|
|
|
|
|
|
[qw(Illuminant MEASUREMENT_SOURCE P)], |
|
9760
|
|
|
|
|
|
|
[qw(Backing SAMPLE_BACKING P)], |
|
9761
|
|
|
|
|
|
|
[qw(Measurements NSAMPLES n)], |
|
9762
|
|
|
|
|
|
|
[qw(Notes ACQUIRE_NOTE P)], |
|
9763
|
|
|
|
|
|
|
]; |
|
9764
|
|
|
|
|
|
|
|
|
9765
|
|
|
|
|
|
|
# read version, samples, Collection Notes length |
|
9766
|
0
|
|
|
|
|
0
|
read($fh, $buf, 7); |
|
9767
|
|
|
|
|
|
|
|
|
9768
|
|
|
|
|
|
|
# unpack |
|
9769
|
0
|
|
|
|
|
0
|
@data = unpack('nx2nC', $buf); |
|
9770
|
|
|
|
|
|
|
|
|
9771
|
|
|
|
|
|
|
# read Collection Notes string |
|
9772
|
0
|
|
|
|
|
0
|
read($fh, $notes, $data[2]); |
|
9773
|
|
|
|
|
|
|
|
|
9774
|
|
|
|
|
|
|
# for each sample |
|
9775
|
0
|
|
|
|
|
0
|
for my $i (0 .. ($data[1] - 1)) { |
|
9776
|
|
|
|
|
|
|
|
|
9777
|
|
|
|
|
|
|
# for each metadata field |
|
9778
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$fmt{$data[0]}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9779
|
|
|
|
|
|
|
|
|
9780
|
|
|
|
|
|
|
# if a Pascal string |
|
9781
|
0
|
0
|
|
|
|
0
|
if ($fmt{$data[0]}[$j][2] eq 'P') { |
|
|
|
0
|
|
|
|
|
|
|
9782
|
|
|
|
|
|
|
|
|
9783
|
|
|
|
|
|
|
# read string length |
|
9784
|
0
|
|
|
|
|
0
|
read($fh, $buf, 1); |
|
9785
|
|
|
|
|
|
|
|
|
9786
|
|
|
|
|
|
|
# read string |
|
9787
|
0
|
|
|
|
|
0
|
read($fh, $meta->[$i][$j], unpack('C', $buf)); |
|
9788
|
|
|
|
|
|
|
|
|
9789
|
|
|
|
|
|
|
# if an unsigned short integer |
|
9790
|
|
|
|
|
|
|
} elsif ($fmt{$data[0]}[$j][2] eq 'n') { |
|
9791
|
|
|
|
|
|
|
|
|
9792
|
|
|
|
|
|
|
# read short integer |
|
9793
|
0
|
|
|
|
|
0
|
read($fh, $buf, 2); |
|
9794
|
|
|
|
|
|
|
|
|
9795
|
|
|
|
|
|
|
# unpack |
|
9796
|
0
|
|
|
|
|
0
|
$meta->[$i][$j] = unpack('n', $buf); |
|
9797
|
|
|
|
|
|
|
|
|
9798
|
|
|
|
|
|
|
} |
|
9799
|
|
|
|
|
|
|
|
|
9800
|
|
|
|
|
|
|
} |
|
9801
|
|
|
|
|
|
|
|
|
9802
|
|
|
|
|
|
|
# read wavelength parameters (start, end, increment, count) |
|
9803
|
0
|
|
|
|
|
0
|
read($fh, $buf, 8); |
|
9804
|
|
|
|
|
|
|
|
|
9805
|
|
|
|
|
|
|
# unpack (unsigned short integer) |
|
9806
|
0
|
|
|
|
|
0
|
$measure->[$i][0] = [unpack('n4', $buf)]; |
|
9807
|
|
|
|
|
|
|
|
|
9808
|
|
|
|
|
|
|
# for each wavelength |
|
9809
|
0
|
|
|
|
|
0
|
for my $j (1 .. $measure->[$i][0][3]) { |
|
9810
|
|
|
|
|
|
|
|
|
9811
|
|
|
|
|
|
|
# read measurements (avg, low, high, std_dev) |
|
9812
|
0
|
|
|
|
|
0
|
read($fh, $buf, 16); |
|
9813
|
|
|
|
|
|
|
|
|
9814
|
|
|
|
|
|
|
# unpack (32-bit float, big endian) |
|
9815
|
0
|
|
|
|
|
0
|
$measure->[$i][$j] = [unpack('(f4)>', $buf)]; |
|
9816
|
|
|
|
|
|
|
|
|
9817
|
|
|
|
|
|
|
} |
|
9818
|
|
|
|
|
|
|
|
|
9819
|
|
|
|
|
|
|
} |
|
9820
|
|
|
|
|
|
|
|
|
9821
|
|
|
|
|
|
|
# add Collection Notes to header line array, if not null string |
|
9822
|
0
|
0
|
|
|
|
0
|
push(@{$self->[3]}, ['FILE_DESCRIPTOR', "\"$notes\""]) if (length($notes)); |
|
|
0
|
|
|
|
|
0
|
|
|
9823
|
|
|
|
|
|
|
|
|
9824
|
|
|
|
|
|
|
# for each metadata field |
|
9825
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$meta->[0]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9826
|
|
|
|
|
|
|
|
|
9827
|
|
|
|
|
|
|
# init hash |
|
9828
|
0
|
|
|
|
|
0
|
%tally = (); |
|
9829
|
|
|
|
|
|
|
|
|
9830
|
|
|
|
|
|
|
# for each sample |
|
9831
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$meta}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9832
|
|
|
|
|
|
|
|
|
9833
|
|
|
|
|
|
|
# increment hash value |
|
9834
|
0
|
|
|
|
|
0
|
$tally{$meta->[$i][$j]}++; |
|
9835
|
|
|
|
|
|
|
|
|
9836
|
|
|
|
|
|
|
} |
|
9837
|
|
|
|
|
|
|
|
|
9838
|
|
|
|
|
|
|
# get hash keys |
|
9839
|
0
|
|
|
|
|
0
|
@keys = keys(%tally); |
|
9840
|
|
|
|
|
|
|
|
|
9841
|
|
|
|
|
|
|
# if one hash key |
|
9842
|
0
|
0
|
|
|
|
0
|
if (@keys == 1) { |
|
9843
|
|
|
|
|
|
|
|
|
9844
|
|
|
|
|
|
|
# if not the null string |
|
9845
|
0
|
0
|
|
|
|
0
|
if (length($keys[0])) { |
|
9846
|
|
|
|
|
|
|
|
|
9847
|
|
|
|
|
|
|
# if value is string |
|
9848
|
0
|
0
|
|
|
|
0
|
if ($fmt{$data[0]}[$j][2] eq 'P') { |
|
9849
|
|
|
|
|
|
|
|
|
9850
|
|
|
|
|
|
|
# wrap in quotes |
|
9851
|
0
|
|
|
|
|
0
|
$value = "\"$keys[0]\""; |
|
9852
|
|
|
|
|
|
|
|
|
9853
|
|
|
|
|
|
|
} else { |
|
9854
|
|
|
|
|
|
|
|
|
9855
|
|
|
|
|
|
|
# if value is an enumeration |
|
9856
|
0
|
0
|
|
|
|
0
|
if (defined($fmt{$data[0]}[$j][3])) { |
|
9857
|
|
|
|
|
|
|
|
|
9858
|
|
|
|
|
|
|
# look up enumerated value and wrap in quotes |
|
9859
|
0
|
|
|
|
|
0
|
$value = "\"$fmt{$data[0]}[$j][3][$keys[0]]\""; |
|
9860
|
|
|
|
|
|
|
|
|
9861
|
|
|
|
|
|
|
} else { |
|
9862
|
|
|
|
|
|
|
|
|
9863
|
|
|
|
|
|
|
# use value as-is |
|
9864
|
0
|
|
|
|
|
0
|
$value = $keys[0]; |
|
9865
|
|
|
|
|
|
|
|
|
9866
|
|
|
|
|
|
|
} |
|
9867
|
|
|
|
|
|
|
|
|
9868
|
|
|
|
|
|
|
} |
|
9869
|
|
|
|
|
|
|
|
|
9870
|
|
|
|
|
|
|
# add KEYWORD/VALUE to header line array |
|
9871
|
0
|
|
|
|
|
0
|
push(@{$self->[3]}, [$fmt{$data[0]}[$j][1], $value]); |
|
|
0
|
|
|
|
|
0
|
|
|
9872
|
|
|
|
|
|
|
|
|
9873
|
|
|
|
|
|
|
} |
|
9874
|
|
|
|
|
|
|
|
|
9875
|
|
|
|
|
|
|
} else { |
|
9876
|
|
|
|
|
|
|
|
|
9877
|
|
|
|
|
|
|
# add keyword to DATA_FORMAT array |
|
9878
|
0
|
|
|
|
|
0
|
push(@{$self->[1][0]}, $fmt{$data[0]}[$j][1]); |
|
|
0
|
|
|
|
|
0
|
|
|
9879
|
|
|
|
|
|
|
|
|
9880
|
|
|
|
|
|
|
# for each sample |
|
9881
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$meta}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9882
|
|
|
|
|
|
|
|
|
9883
|
|
|
|
|
|
|
# if value is an enumeration |
|
9884
|
0
|
0
|
|
|
|
0
|
if (defined($fmt{$data[0]}[$j][3])) { |
|
9885
|
|
|
|
|
|
|
|
|
9886
|
|
|
|
|
|
|
# look up enumerated value |
|
9887
|
0
|
|
|
|
|
0
|
$value = $fmt{$data[0]}[$j][3][$meta->[$i][$j]]; |
|
9888
|
|
|
|
|
|
|
|
|
9889
|
|
|
|
|
|
|
} else { |
|
9890
|
|
|
|
|
|
|
|
|
9891
|
|
|
|
|
|
|
# use value as-is |
|
9892
|
0
|
|
|
|
|
0
|
$value = $meta->[$i][$j]; |
|
9893
|
|
|
|
|
|
|
|
|
9894
|
|
|
|
|
|
|
} |
|
9895
|
|
|
|
|
|
|
|
|
9896
|
|
|
|
|
|
|
# add value to DATA array |
|
9897
|
0
|
|
|
|
|
0
|
push(@{$self->[1][$i + 1]}, $meta->[$i][$j]); |
|
|
0
|
|
|
|
|
0
|
|
|
9898
|
|
|
|
|
|
|
|
|
9899
|
|
|
|
|
|
|
} |
|
9900
|
|
|
|
|
|
|
|
|
9901
|
|
|
|
|
|
|
} |
|
9902
|
|
|
|
|
|
|
|
|
9903
|
|
|
|
|
|
|
} |
|
9904
|
|
|
|
|
|
|
|
|
9905
|
|
|
|
|
|
|
# for each wavelength parameter (start, end, increment, count) |
|
9906
|
0
|
|
|
|
|
0
|
for my $j (0 .. 3) { |
|
9907
|
|
|
|
|
|
|
|
|
9908
|
|
|
|
|
|
|
# init hash |
|
9909
|
0
|
|
|
|
|
0
|
%tally = (); |
|
9910
|
|
|
|
|
|
|
|
|
9911
|
|
|
|
|
|
|
# for each sample |
|
9912
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$measure}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9913
|
|
|
|
|
|
|
|
|
9914
|
|
|
|
|
|
|
# increment hash value |
|
9915
|
0
|
|
|
|
|
0
|
$tally{$measure->[$i][0][$j]}++; |
|
9916
|
|
|
|
|
|
|
|
|
9917
|
|
|
|
|
|
|
} |
|
9918
|
|
|
|
|
|
|
|
|
9919
|
|
|
|
|
|
|
# get hash keys |
|
9920
|
0
|
|
|
|
|
0
|
@keys = keys(%tally); |
|
9921
|
|
|
|
|
|
|
|
|
9922
|
|
|
|
|
|
|
# verify all samples have same wavelength parameter value |
|
9923
|
0
|
0
|
|
|
|
0
|
(@keys == 1) || return('samples have varied spectral range'); |
|
9924
|
|
|
|
|
|
|
|
|
9925
|
|
|
|
|
|
|
} |
|
9926
|
|
|
|
|
|
|
|
|
9927
|
|
|
|
|
|
|
# for each wavelength |
|
9928
|
0
|
|
|
|
|
0
|
for my $j (0 .. ($#{$measure->[0]} - 1)) { |
|
|
0
|
|
|
|
|
0
|
|
|
9929
|
|
|
|
|
|
|
|
|
9930
|
|
|
|
|
|
|
# compute wavelength from start and increment values |
|
9931
|
0
|
|
|
|
|
0
|
$nm = $measure->[0][0][0] + $j * $measure->[0][0][2]; |
|
9932
|
|
|
|
|
|
|
|
|
9933
|
|
|
|
|
|
|
# add keyword to DATA_FORMAT array |
|
9934
|
0
|
|
|
|
|
0
|
push(@{$self->[1][0]}, "nm$nm"); |
|
|
0
|
|
|
|
|
0
|
|
|
9935
|
|
|
|
|
|
|
|
|
9936
|
|
|
|
|
|
|
# for each sample |
|
9937
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$measure}) { |
|
|
0
|
|
|
|
|
0
|
|
|
9938
|
|
|
|
|
|
|
|
|
9939
|
|
|
|
|
|
|
# add average measurement to DATA array |
|
9940
|
0
|
|
|
|
|
0
|
push(@{$self->[1][$i + 1]}, $measure->[$i][$j + 1][0]); |
|
|
0
|
|
|
|
|
0
|
|
|
9941
|
|
|
|
|
|
|
|
|
9942
|
|
|
|
|
|
|
} |
|
9943
|
|
|
|
|
|
|
|
|
9944
|
|
|
|
|
|
|
} |
|
9945
|
|
|
|
|
|
|
|
|
9946
|
|
|
|
|
|
|
# return |
|
9947
|
0
|
|
|
|
|
0
|
return(); |
|
9948
|
|
|
|
|
|
|
|
|
9949
|
|
|
|
|
|
|
} |
|
9950
|
|
|
|
|
|
|
|
|
9951
|
|
|
|
|
|
|
# read data from TIFF file |
|
9952
|
|
|
|
|
|
|
# RGB, CMYK, and CIE L*a*b* color spaces supported |
|
9953
|
|
|
|
|
|
|
# 8-bit, 16-bit or 32-bit, Intel or Motorola byte order supported |
|
9954
|
|
|
|
|
|
|
# alpha and spot channels in RGB and CMYK files supported |
|
9955
|
|
|
|
|
|
|
# optional hash keys: 'rows', 'columns', 'crop', 'ratio', 'aperture', 'udf', 'format' |
|
9956
|
|
|
|
|
|
|
# default 'rows' and 'columns' are taken from image size, default 'ratio' is 0.5 |
|
9957
|
|
|
|
|
|
|
# 'crop' is an array containing the left, right, upper and lower crop values in pixels |
|
9958
|
|
|
|
|
|
|
# 'ratio' is a value between 0 and 1, sample is a single pixel when 'ratio' is 0 |
|
9959
|
|
|
|
|
|
|
# 'aperture' is in millimeters, and take precedence over 'ratio' |
|
9960
|
|
|
|
|
|
|
# 'udf' is a code reference to a pixel processing function |
|
9961
|
|
|
|
|
|
|
# 'format' is an array reference containing the format fields |
|
9962
|
|
|
|
|
|
|
# parameters: (object_reference, file_handle, hash) |
|
9963
|
|
|
|
|
|
|
# returns: (result) |
|
9964
|
|
|
|
|
|
|
sub _readChartTIFF { |
|
9965
|
|
|
|
|
|
|
|
|
9966
|
|
|
|
|
|
|
# get parameters |
|
9967
|
0
|
|
|
0
|
|
0
|
my ($self, $fh, $hash) = @_; |
|
9968
|
|
|
|
|
|
|
|
|
9969
|
|
|
|
|
|
|
# local variables |
|
9970
|
0
|
|
|
|
|
0
|
my ($buf, $short, $long, $fp, @header, $tags); |
|
9971
|
0
|
|
|
|
|
0
|
my ($cols, $rows, $bits, $pi, $samples); |
|
9972
|
0
|
|
|
|
|
0
|
my ($context, $fmt, $upf, $udf, $dev, $div, $dab); |
|
9973
|
0
|
|
|
|
|
0
|
my ($trows, $tcols, $crop, $roff, $coff); |
|
9974
|
0
|
|
|
|
|
0
|
my ($res, $size, $frac, $ratio, $rxo, $cxo, $pixels, $width); |
|
9975
|
0
|
|
|
|
|
0
|
my ($lower, $upper, $left, $right, $band, $pval, @data, @pix); |
|
9976
|
|
|
|
|
|
|
|
|
9977
|
|
|
|
|
|
|
# read the header |
|
9978
|
0
|
|
|
|
|
0
|
read($fh, $buf, 8); |
|
9979
|
|
|
|
|
|
|
|
|
9980
|
|
|
|
|
|
|
# if big-endian (Motorola) |
|
9981
|
0
|
0
|
|
|
|
0
|
if (substr($buf, 0, 2) eq 'MM') { |
|
|
|
0
|
|
|
|
|
|
|
9982
|
|
|
|
|
|
|
|
|
9983
|
|
|
|
|
|
|
# set 'unpack' formats |
|
9984
|
0
|
|
|
|
|
0
|
$short = 'n'; |
|
9985
|
0
|
|
|
|
|
0
|
$long = 'N'; |
|
9986
|
0
|
|
|
|
|
0
|
$fp = 'f>'; # might not be IEEE FP on some platforms |
|
9987
|
|
|
|
|
|
|
|
|
9988
|
|
|
|
|
|
|
# if little-endian (Intel) |
|
9989
|
|
|
|
|
|
|
} elsif (substr($buf, 0, 2) eq 'II'){ |
|
9990
|
|
|
|
|
|
|
|
|
9991
|
|
|
|
|
|
|
# set 'unpack' formats |
|
9992
|
0
|
|
|
|
|
0
|
$short = 'v'; |
|
9993
|
0
|
|
|
|
|
0
|
$long = 'V'; |
|
9994
|
0
|
|
|
|
|
0
|
$fp = 'f<'; # might not be IEEE FP on some platforms |
|
9995
|
|
|
|
|
|
|
|
|
9996
|
|
|
|
|
|
|
} else { |
|
9997
|
|
|
|
|
|
|
|
|
9998
|
|
|
|
|
|
|
# error |
|
9999
|
0
|
|
|
|
|
0
|
return('TIFF byte order incorrect'); |
|
10000
|
|
|
|
|
|
|
|
|
10001
|
|
|
|
|
|
|
} |
|
10002
|
|
|
|
|
|
|
|
|
10003
|
|
|
|
|
|
|
# unpack the header |
|
10004
|
0
|
|
|
|
|
0
|
@header = unpack("A2 $short $long", $buf); |
|
10005
|
|
|
|
|
|
|
|
|
10006
|
|
|
|
|
|
|
# verify file signature |
|
10007
|
0
|
0
|
|
|
|
0
|
($header[1] == 42) || return('TIFF file signature incorrect'); |
|
10008
|
|
|
|
|
|
|
|
|
10009
|
|
|
|
|
|
|
# read TIFF image file directory (IFD) |
|
10010
|
0
|
|
|
|
|
0
|
$tags = _readTIFFdir($fh, $header[2], $short, $long); |
|
10011
|
|
|
|
|
|
|
|
|
10012
|
|
|
|
|
|
|
# verify compression (1 = uncompressed) |
|
10013
|
0
|
0
|
|
|
|
0
|
($tags->{'259'}[0] == 1) || return('TIFF compression unsupported'); |
|
10014
|
|
|
|
|
|
|
|
|
10015
|
|
|
|
|
|
|
# verify orientation (1 = normal) |
|
10016
|
0
|
0
|
0
|
|
|
0
|
(! exists($tags->{'274'}) || $tags->{'274'}[0] == 1) || warn('TIFF orientation rotated and/or flipped'); |
|
10017
|
|
|
|
|
|
|
|
|
10018
|
|
|
|
|
|
|
# verify planar configuration (1 = chunky) |
|
10019
|
0
|
0
|
0
|
|
|
0
|
(! exists($tags->{'284'}) || $tags->{'284'}[0] == 1) || return('TIFF planar configuration unsupported'); |
|
10020
|
|
|
|
|
|
|
|
|
10021
|
|
|
|
|
|
|
# verify not tiled |
|
10022
|
0
|
0
|
|
|
|
0
|
(! exists($tags->{'322'})) || return('TIFF tiled layout unsupported'); |
|
10023
|
|
|
|
|
|
|
|
|
10024
|
|
|
|
|
|
|
# get TIFF columns (width) |
|
10025
|
0
|
|
|
|
|
0
|
$cols = $tags->{'256'}[0]; |
|
10026
|
|
|
|
|
|
|
|
|
10027
|
|
|
|
|
|
|
# get TIFF rows (length) |
|
10028
|
0
|
|
|
|
|
0
|
$rows = $tags->{'257'}[0]; |
|
10029
|
|
|
|
|
|
|
|
|
10030
|
|
|
|
|
|
|
# get TIFF bits per sample |
|
10031
|
0
|
|
|
|
|
0
|
$bits = $tags->{'258'}[0]; |
|
10032
|
|
|
|
|
|
|
|
|
10033
|
|
|
|
|
|
|
# verify bits per sample |
|
10034
|
0
|
0
|
0
|
|
|
0
|
($bits == 8 || $bits == 16 || $bits == 32) || return('TIFF bits per sample unsupported'); |
|
|
|
|
0
|
|
|
|
|
|
10035
|
|
|
|
|
|
|
|
|
10036
|
|
|
|
|
|
|
# get the photometric interpretation |
|
10037
|
0
|
|
|
|
|
0
|
$pi = $tags->{'262'}[0]; |
|
10038
|
|
|
|
|
|
|
|
|
10039
|
|
|
|
|
|
|
# if 32-bits per sample |
|
10040
|
0
|
0
|
|
|
|
0
|
if ($bits == 32) { |
|
10041
|
|
|
|
|
|
|
|
|
10042
|
|
|
|
|
|
|
# verify 32-bit IEEE FP format, RGB image |
|
10043
|
0
|
0
|
0
|
|
|
0
|
($tags->{'339'}[0] == 3 && $pi == 2) || return('TIFF format unsupported'); |
|
10044
|
|
|
|
|
|
|
|
|
10045
|
|
|
|
|
|
|
} |
|
10046
|
|
|
|
|
|
|
|
|
10047
|
|
|
|
|
|
|
# get TIFF samples per pixel |
|
10048
|
0
|
|
|
|
|
0
|
$samples = $tags->{'277'}[0]; |
|
10049
|
|
|
|
|
|
|
|
|
10050
|
|
|
|
|
|
|
# verify bits per sample array |
|
10051
|
0
|
0
|
|
|
|
0
|
($samples == grep {$_ == $bits} @{$tags->{'258'}}) || return('TIFF image structure unsupported'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10052
|
|
|
|
|
|
|
|
|
10053
|
|
|
|
|
|
|
# get context (if any) |
|
10054
|
0
|
|
|
|
|
0
|
$context = $hash->{'context'}; |
|
10055
|
|
|
|
|
|
|
|
|
10056
|
|
|
|
|
|
|
# get user defined function (if any) |
|
10057
|
0
|
|
|
|
|
0
|
$udf = $hash->{'udf'}; |
|
10058
|
|
|
|
|
|
|
|
|
10059
|
|
|
|
|
|
|
# verify UDF is a code reference |
|
10060
|
0
|
0
|
0
|
|
|
0
|
(ref($udf) eq 'CODE') || return('UDF not a code reference') if (defined($udf)); |
|
10061
|
|
|
|
|
|
|
|
|
10062
|
|
|
|
|
|
|
# set device value divisor |
|
10063
|
0
|
0
|
|
|
|
0
|
$dev = ($bits == 8) ? 255 : 65535; |
|
10064
|
|
|
|
|
|
|
|
|
10065
|
|
|
|
|
|
|
# add fields for udf (if any) |
|
10066
|
0
|
0
|
|
|
|
0
|
$fmt = add_fmt($self, map {defined($context) ? "$context|$_" : $_} @{$hash->{'format'}}) if defined($hash->{'format'}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10067
|
|
|
|
|
|
|
|
|
10068
|
|
|
|
|
|
|
# if RGB file |
|
10069
|
0
|
0
|
0
|
|
|
0
|
if ($pi == 2 && $samples < 13) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
10070
|
|
|
|
|
|
|
|
|
10071
|
|
|
|
|
|
|
# add RGB and ALPHA fields, if not already defined |
|
10072
|
0
|
0
|
|
|
|
0
|
$fmt = add_fmt($self, map {defined($context) ? "$context|$_" : $_} (qw(RGB_R RGB_G RGB_B), map {"RGB_A$_"} (1 .. $samples - 3))) if (! defined($fmt)); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10073
|
|
|
|
|
|
|
|
|
10074
|
|
|
|
|
|
|
# set unpack format (8, 16 or 32 bits) |
|
10075
|
0
|
0
|
|
|
|
0
|
$upf = ($bits == 8) ? 'C*' : ($bits == 16) ? "$short*" : "$fp*"; |
|
|
|
0
|
|
|
|
|
|
|
10076
|
|
|
|
|
|
|
|
|
10077
|
|
|
|
|
|
|
# set divisor (8, 16 or 32 bits) |
|
10078
|
0
|
0
|
|
|
|
0
|
$div = ($bits == 8) ? 1 : ($bits == 16) ? 257 : 1/255; |
|
|
|
0
|
|
|
|
|
|
|
10079
|
|
|
|
|
|
|
|
|
10080
|
|
|
|
|
|
|
# if CMYK file |
|
10081
|
|
|
|
|
|
|
} elsif ($pi == 5 && $samples == 4) { |
|
10082
|
|
|
|
|
|
|
|
|
10083
|
|
|
|
|
|
|
# add CMYK fields, if not already defined |
|
10084
|
0
|
0
|
|
|
|
0
|
$fmt = add_fmt($self, map {defined($context) ? "$context|$_" : $_} qw(CMYK_C CMYK_M CMYK_Y CMYK_K)) if (! defined($fmt)); |
|
|
0
|
0
|
|
|
|
0
|
|
|
10085
|
|
|
|
|
|
|
|
|
10086
|
|
|
|
|
|
|
# set unpack format (8 or 16 bits) |
|
10087
|
0
|
0
|
|
|
|
0
|
$upf = ($bits == 8) ? 'C*' : "$short*"; |
|
10088
|
|
|
|
|
|
|
|
|
10089
|
|
|
|
|
|
|
# set divisor (8 or 16 bits) |
|
10090
|
0
|
0
|
|
|
|
0
|
$div = ($bits == 8) ? 2.55 : 655.35; |
|
10091
|
|
|
|
|
|
|
|
|
10092
|
|
|
|
|
|
|
# if nCLR file |
|
10093
|
|
|
|
|
|
|
} elsif ($pi == 5 && $samples > 4 && $samples < 16) { |
|
10094
|
|
|
|
|
|
|
|
|
10095
|
|
|
|
|
|
|
# add nCLR fields, if not already defined |
|
10096
|
0
|
0
|
|
|
|
0
|
$fmt = add_fmt($self, map {defined($context) ? "$context|$_" : $_} map {sprintf('%xCLR_%x', $samples, $_)} (1 .. $samples)) if (! defined($fmt)); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10097
|
|
|
|
|
|
|
|
|
10098
|
|
|
|
|
|
|
# set unpack format (8 or 16 bits) |
|
10099
|
0
|
0
|
|
|
|
0
|
$upf = ($bits == 8) ? 'C*' : "$short*"; |
|
10100
|
|
|
|
|
|
|
|
|
10101
|
|
|
|
|
|
|
# set divisor (8 or 16 bits) |
|
10102
|
0
|
0
|
|
|
|
0
|
$div = ($bits == 8) ? 2.55 : 655.35; |
|
10103
|
|
|
|
|
|
|
|
|
10104
|
|
|
|
|
|
|
# if CIE L*a*b* file |
|
10105
|
|
|
|
|
|
|
} elsif ($pi == 8 && $samples == 3) { |
|
10106
|
|
|
|
|
|
|
|
|
10107
|
|
|
|
|
|
|
# add L*a*b* fields, if not already defined |
|
10108
|
0
|
0
|
|
|
|
0
|
$fmt = add_fmt($self, map {defined($context) ? "$context|$_" : $_} qw(LAB_L LAB_A LAB_B)) if (! defined($fmt)); |
|
|
0
|
0
|
|
|
|
0
|
|
|
10109
|
|
|
|
|
|
|
|
|
10110
|
|
|
|
|
|
|
# set unpack format (8 or 16 bits) |
|
10111
|
0
|
0
|
|
|
|
0
|
$upf = ($bits == 8) ? '(Ccc)*' : "$short*"; |
|
10112
|
|
|
|
|
|
|
|
|
10113
|
|
|
|
|
|
|
# set divisors (8 or 16 bits) |
|
10114
|
0
|
0
|
|
|
|
0
|
$div = ($bits == 8) ? 2.55 : 655.35; # L* |
|
10115
|
0
|
0
|
|
|
|
0
|
$dab = ($bits == 8) ? 1 : 256; # a* and b* |
|
10116
|
|
|
|
|
|
|
|
|
10117
|
|
|
|
|
|
|
} else { |
|
10118
|
|
|
|
|
|
|
|
|
10119
|
|
|
|
|
|
|
# return error |
|
10120
|
0
|
|
|
|
|
0
|
return('TIFF color space unsupported'); |
|
10121
|
|
|
|
|
|
|
|
|
10122
|
|
|
|
|
|
|
} |
|
10123
|
|
|
|
|
|
|
|
|
10124
|
|
|
|
|
|
|
# get target rows (could be undefined) |
|
10125
|
0
|
|
|
|
|
0
|
$trows = $hash->{'rows'}; |
|
10126
|
|
|
|
|
|
|
|
|
10127
|
|
|
|
|
|
|
# get target columns (could be undefined) |
|
10128
|
0
|
|
|
|
|
0
|
$tcols = $hash->{'columns'}; |
|
10129
|
|
|
|
|
|
|
|
|
10130
|
|
|
|
|
|
|
# if 'crop' parameter is defined |
|
10131
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'crop'})) { |
|
10132
|
|
|
|
|
|
|
|
|
10133
|
|
|
|
|
|
|
# get crop parameter |
|
10134
|
0
|
|
|
|
|
0
|
$crop = $hash->{'crop'}; |
|
10135
|
|
|
|
|
|
|
|
|
10136
|
|
|
|
|
|
|
# verify array reference |
|
10137
|
0
|
0
|
|
|
|
0
|
(ref($crop) eq 'ARRAY') || return('TIFF crop parameter not an array reference'); |
|
10138
|
|
|
|
|
|
|
|
|
10139
|
|
|
|
|
|
|
# verify array contains four non-negative integers |
|
10140
|
0
|
0
|
0
|
|
|
0
|
(4 == @{$crop} && 4 == grep {$_ == int($_) && $_ >= 0} @{$crop}) || return('TIFF crop parameter(s) invalid'); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10141
|
|
|
|
|
|
|
|
|
10142
|
|
|
|
|
|
|
# adjust rows and columns |
|
10143
|
0
|
|
|
|
|
0
|
$rows -= $crop->[2] + $crop->[3]; |
|
10144
|
0
|
|
|
|
|
0
|
$cols -= $crop->[0] + $crop->[1]; |
|
10145
|
|
|
|
|
|
|
|
|
10146
|
|
|
|
|
|
|
# verify cropped size |
|
10147
|
0
|
0
|
0
|
|
|
0
|
($rows > 0 && $cols > 0) || return('TIFF crop size too small'); |
|
10148
|
|
|
|
|
|
|
|
|
10149
|
|
|
|
|
|
|
# set offset values |
|
10150
|
0
|
|
|
|
|
0
|
$roff = $crop->[2]; |
|
10151
|
0
|
|
|
|
|
0
|
$coff = $crop->[0]; |
|
10152
|
|
|
|
|
|
|
|
|
10153
|
|
|
|
|
|
|
} else { |
|
10154
|
|
|
|
|
|
|
|
|
10155
|
|
|
|
|
|
|
# set offset values |
|
10156
|
0
|
|
|
|
|
0
|
$roff = 0; |
|
10157
|
0
|
|
|
|
|
0
|
$coff = 0; |
|
10158
|
|
|
|
|
|
|
|
|
10159
|
|
|
|
|
|
|
} |
|
10160
|
|
|
|
|
|
|
|
|
10161
|
|
|
|
|
|
|
# if aperture is defined in hash |
|
10162
|
0
|
0
|
|
|
|
0
|
if (defined($hash->{'aperture'})) { |
|
10163
|
|
|
|
|
|
|
|
|
10164
|
|
|
|
|
|
|
# compute image resolution |
|
10165
|
0
|
|
|
|
|
0
|
$res = $tags->{'283'}[0]/$tags->{'283'}[1]; |
|
10166
|
|
|
|
|
|
|
|
|
10167
|
|
|
|
|
|
|
# convert to lines/mm if resolution unit is inch |
|
10168
|
0
|
0
|
|
|
|
0
|
$res /= 25.4 if ($tags->{'296'}[0] == 2); |
|
10169
|
|
|
|
|
|
|
|
|
10170
|
|
|
|
|
|
|
# convert to lines/mm if resolution unit is cm |
|
10171
|
0
|
0
|
|
|
|
0
|
$res /= 10 if ($tags->{'296'}[0] == 3); |
|
10172
|
|
|
|
|
|
|
|
|
10173
|
|
|
|
|
|
|
# if target rows or target columns are defined |
|
10174
|
0
|
0
|
0
|
|
|
0
|
if (defined($trows) || defined($tcols)) { |
|
10175
|
|
|
|
|
|
|
|
|
10176
|
|
|
|
|
|
|
# use image rows if target rows undefined |
|
10177
|
0
|
0
|
|
|
|
0
|
$trows = $rows if (! defined($trows)); |
|
10178
|
|
|
|
|
|
|
|
|
10179
|
|
|
|
|
|
|
# use image columns if target columns undefined |
|
10180
|
0
|
0
|
|
|
|
0
|
$tcols = $cols if (! defined($tcols)); |
|
10181
|
|
|
|
|
|
|
|
|
10182
|
|
|
|
|
|
|
# compute aperture size (diameter in pixels) |
|
10183
|
0
|
|
|
|
|
0
|
($frac, $size) = POSIX::modf(sqrt(ICC::Shared::PI/4) * $res * $hash->{'aperture'}); |
|
10184
|
|
|
|
|
|
|
|
|
10185
|
|
|
|
|
|
|
# if fractional part < 0.25 |
|
10186
|
0
|
0
|
|
|
|
0
|
if ($frac < 0.25) { |
|
|
|
0
|
|
|
|
|
|
|
10187
|
|
|
|
|
|
|
|
|
10188
|
|
|
|
|
|
|
# set row and column index offsets |
|
10189
|
0
|
|
|
|
|
0
|
$rxo = $cxo = $size - 1; |
|
10190
|
|
|
|
|
|
|
|
|
10191
|
|
|
|
|
|
|
# if fractional part < 0.75 |
|
10192
|
|
|
|
|
|
|
} elsif ($frac < 0.75) { |
|
10193
|
|
|
|
|
|
|
|
|
10194
|
|
|
|
|
|
|
# set row index offset |
|
10195
|
0
|
|
|
|
|
0
|
$rxo = $size - 1; |
|
10196
|
|
|
|
|
|
|
|
|
10197
|
|
|
|
|
|
|
# set column index offset |
|
10198
|
0
|
|
|
|
|
0
|
$cxo = $size; |
|
10199
|
|
|
|
|
|
|
|
|
10200
|
|
|
|
|
|
|
} else { |
|
10201
|
|
|
|
|
|
|
|
|
10202
|
|
|
|
|
|
|
# set row and column index offsets |
|
10203
|
0
|
|
|
|
|
0
|
$rxo = $cxo = $size; |
|
10204
|
|
|
|
|
|
|
|
|
10205
|
|
|
|
|
|
|
} |
|
10206
|
|
|
|
|
|
|
|
|
10207
|
|
|
|
|
|
|
# verify aperture is within sample area |
|
10208
|
0
|
0
|
0
|
|
|
0
|
($rxo <= $rows/$trows && $cxo <= $cols/$tcols) or croak('TIFF aperture exceeds sample area') |
|
10209
|
|
|
|
|
|
|
|
|
10210
|
|
|
|
|
|
|
} else { |
|
10211
|
|
|
|
|
|
|
|
|
10212
|
|
|
|
|
|
|
# compute aperture area (in pixels) |
|
10213
|
0
|
|
|
|
|
0
|
$size = ICC::Shared::PI * ($res * $hash->{'aperture'}/2)**2; |
|
10214
|
|
|
|
|
|
|
|
|
10215
|
|
|
|
|
|
|
# compute the target rows |
|
10216
|
0
|
|
|
|
|
0
|
$trows = int(sqrt($size * $rows/$cols) + 0.5); |
|
10217
|
|
|
|
|
|
|
|
|
10218
|
|
|
|
|
|
|
# compute the target columns |
|
10219
|
0
|
|
|
|
|
0
|
$tcols = int($size/$trows + 0.5); |
|
10220
|
|
|
|
|
|
|
|
|
10221
|
|
|
|
|
|
|
# set row and column indices (single pixel sample) |
|
10222
|
0
|
|
|
|
|
0
|
$rxo = $cxo = 0; |
|
10223
|
|
|
|
|
|
|
|
|
10224
|
|
|
|
|
|
|
} |
|
10225
|
|
|
|
|
|
|
|
|
10226
|
|
|
|
|
|
|
} else { |
|
10227
|
|
|
|
|
|
|
|
|
10228
|
|
|
|
|
|
|
# use image rows if target rows undefined |
|
10229
|
0
|
0
|
|
|
|
0
|
$trows = $rows if (! defined($trows)); |
|
10230
|
|
|
|
|
|
|
|
|
10231
|
|
|
|
|
|
|
# use image columns if target columns undefined |
|
10232
|
0
|
0
|
|
|
|
0
|
$tcols = $cols if (! defined($tcols)); |
|
10233
|
|
|
|
|
|
|
|
|
10234
|
|
|
|
|
|
|
# get mask ratio (default 0.5) |
|
10235
|
0
|
0
|
|
|
|
0
|
$ratio = defined($hash->{'ratio'}) ? $hash->{'ratio'} : 0.5; |
|
10236
|
|
|
|
|
|
|
|
|
10237
|
|
|
|
|
|
|
# verify mask ratio |
|
10238
|
0
|
0
|
0
|
|
|
0
|
($ratio >= 0 && $ratio <= 1) or croak('TIFF mask ratio < 0 or > 1'); |
|
10239
|
|
|
|
|
|
|
|
|
10240
|
|
|
|
|
|
|
# compute row index offset |
|
10241
|
0
|
|
|
|
|
0
|
$rxo = int($ratio * $rows/$trows - 0.5); |
|
10242
|
|
|
|
|
|
|
|
|
10243
|
|
|
|
|
|
|
# compute column index offset |
|
10244
|
0
|
|
|
|
|
0
|
$cxo = int($ratio * $cols/$tcols - 0.5); |
|
10245
|
|
|
|
|
|
|
|
|
10246
|
|
|
|
|
|
|
} |
|
10247
|
|
|
|
|
|
|
|
|
10248
|
|
|
|
|
|
|
# warn if large target size |
|
10249
|
0
|
0
|
|
|
|
0
|
($trows * $tcols <= 10000) || warn('TIFF target size > 10000 samples'); |
|
10250
|
|
|
|
|
|
|
|
|
10251
|
|
|
|
|
|
|
# compute number of pixels |
|
10252
|
0
|
|
|
|
|
0
|
$pixels = ($rxo + 1) * ($cxo + 1); |
|
10253
|
|
|
|
|
|
|
|
|
10254
|
|
|
|
|
|
|
# compute row width (bytes) |
|
10255
|
0
|
|
|
|
|
0
|
$width = $tags->{'256'}[0] * List::Util::sum(@{$tags->{'258'}})/8; |
|
|
0
|
|
|
|
|
0
|
|
|
10256
|
|
|
|
|
|
|
|
|
10257
|
|
|
|
|
|
|
# for each target row |
|
10258
|
0
|
|
|
|
|
0
|
for my $i (0 .. $trows - 1) { |
|
10259
|
|
|
|
|
|
|
|
|
10260
|
|
|
|
|
|
|
# compute sample lower row |
|
10261
|
0
|
|
|
|
|
0
|
$lower = int(($i + 0.5) * $rows/$trows - $rxo/2) + $roff; |
|
10262
|
|
|
|
|
|
|
|
|
10263
|
|
|
|
|
|
|
# compute sample upper row |
|
10264
|
0
|
|
|
|
|
0
|
$upper = $lower + $rxo; |
|
10265
|
|
|
|
|
|
|
|
|
10266
|
|
|
|
|
|
|
# get sample band data |
|
10267
|
0
|
|
|
|
|
0
|
$band = _readTIFFband($fh, $tags, $lower, $upper, $width, $upf); |
|
10268
|
|
|
|
|
|
|
|
|
10269
|
|
|
|
|
|
|
# for each target column |
|
10270
|
0
|
|
|
|
|
0
|
for my $j (0 .. $tcols - 1) { |
|
10271
|
|
|
|
|
|
|
|
|
10272
|
|
|
|
|
|
|
# compute sample left column |
|
10273
|
0
|
|
|
|
|
0
|
$left = int(($j + 0.5) * $cols/$tcols - $cxo/2) + $coff; |
|
10274
|
|
|
|
|
|
|
|
|
10275
|
|
|
|
|
|
|
# compute sample right column |
|
10276
|
0
|
|
|
|
|
0
|
$right = $left + $cxo; |
|
10277
|
|
|
|
|
|
|
|
|
10278
|
|
|
|
|
|
|
# initialize data |
|
10279
|
0
|
|
|
|
|
0
|
@data = (); |
|
10280
|
|
|
|
|
|
|
|
|
10281
|
|
|
|
|
|
|
# for each row (band) |
|
10282
|
0
|
|
|
|
|
0
|
for my $m (0 .. $#{$band}) { |
|
|
0
|
|
|
|
|
0
|
|
|
10283
|
|
|
|
|
|
|
|
|
10284
|
|
|
|
|
|
|
# for each column |
|
10285
|
0
|
|
|
|
|
0
|
for my $n ($left .. $right) { |
|
10286
|
|
|
|
|
|
|
|
|
10287
|
|
|
|
|
|
|
# get pixel value (all samples) |
|
10288
|
0
|
|
|
|
|
0
|
@pix = @{$band->[$m]}[$n * $samples .. ($n + 1) * $samples - 1]; |
|
|
0
|
|
|
|
|
0
|
|
|
10289
|
|
|
|
|
|
|
|
|
10290
|
|
|
|
|
|
|
# if 16-bit L*a*b* |
|
10291
|
0
|
0
|
0
|
|
|
0
|
if ($pi == 8 && $bits == 16) { |
|
10292
|
|
|
|
|
|
|
|
|
10293
|
|
|
|
|
|
|
# adjust a* and b* if pixel value negative (signed 16-bit) |
|
10294
|
0
|
0
|
|
|
|
0
|
$pix[1] += -65536 if ($pix[1] > 32767); |
|
10295
|
0
|
0
|
|
|
|
0
|
$pix[2] += -65536 if ($pix[2] > 32767); |
|
10296
|
|
|
|
|
|
|
|
|
10297
|
|
|
|
|
|
|
} |
|
10298
|
|
|
|
|
|
|
|
|
10299
|
|
|
|
|
|
|
# if user defined function provided |
|
10300
|
0
|
0
|
|
|
|
0
|
if (defined($udf)) { |
|
10301
|
|
|
|
|
|
|
|
|
10302
|
|
|
|
|
|
|
# if L*a*b* file |
|
10303
|
0
|
0
|
|
|
|
0
|
if ($pi == 8) { |
|
10304
|
|
|
|
|
|
|
|
|
10305
|
|
|
|
|
|
|
# convert values |
|
10306
|
0
|
|
|
|
|
0
|
$pix[0] /= $div; |
|
10307
|
0
|
|
|
|
|
0
|
$pix[1] /= $dab; |
|
10308
|
0
|
|
|
|
|
0
|
$pix[2] /= $dab; |
|
10309
|
|
|
|
|
|
|
|
|
10310
|
|
|
|
|
|
|
} else { |
|
10311
|
|
|
|
|
|
|
|
|
10312
|
|
|
|
|
|
|
# convert to device values |
|
10313
|
0
|
|
|
|
|
0
|
@pix = map {$_/$dev} @pix; |
|
|
0
|
|
|
|
|
0
|
|
|
10314
|
|
|
|
|
|
|
|
|
10315
|
|
|
|
|
|
|
# if a CMYK file |
|
10316
|
0
|
0
|
|
|
|
0
|
if ($pi == 5) { |
|
10317
|
|
|
|
|
|
|
|
|
10318
|
|
|
|
|
|
|
# for alpha/spot colors (if any) |
|
10319
|
0
|
|
|
|
|
0
|
for my $s (4 .. $samples - 1) { |
|
10320
|
|
|
|
|
|
|
|
|
10321
|
|
|
|
|
|
|
# invert device value |
|
10322
|
0
|
|
|
|
|
0
|
$pix[$s] = 1 - $pix[$s]; |
|
10323
|
|
|
|
|
|
|
|
|
10324
|
|
|
|
|
|
|
} |
|
10325
|
|
|
|
|
|
|
|
|
10326
|
|
|
|
|
|
|
} |
|
10327
|
|
|
|
|
|
|
|
|
10328
|
|
|
|
|
|
|
} |
|
10329
|
|
|
|
|
|
|
|
|
10330
|
|
|
|
|
|
|
# call user defined function |
|
10331
|
0
|
|
|
|
|
0
|
@pix = &$udf(@pix); |
|
10332
|
|
|
|
|
|
|
|
|
10333
|
|
|
|
|
|
|
} |
|
10334
|
|
|
|
|
|
|
|
|
10335
|
|
|
|
|
|
|
# for each channel (may be different from TIFF samples) |
|
10336
|
0
|
|
|
|
|
0
|
for my $s (0 .. $#pix) { |
|
10337
|
|
|
|
|
|
|
|
|
10338
|
|
|
|
|
|
|
# accumulate pixel values |
|
10339
|
0
|
|
|
|
|
0
|
$data[$s] += $pix[$s] |
|
10340
|
|
|
|
|
|
|
|
|
10341
|
|
|
|
|
|
|
} |
|
10342
|
|
|
|
|
|
|
|
|
10343
|
|
|
|
|
|
|
} |
|
10344
|
|
|
|
|
|
|
|
|
10345
|
|
|
|
|
|
|
} |
|
10346
|
|
|
|
|
|
|
|
|
10347
|
|
|
|
|
|
|
# if user defined function provided |
|
10348
|
0
|
0
|
|
|
|
0
|
if (defined($udf)) { |
|
|
|
0
|
|
|
|
|
|
|
10349
|
|
|
|
|
|
|
|
|
10350
|
|
|
|
|
|
|
# save data in object |
|
10351
|
0
|
|
|
|
|
0
|
@{$self->[1][$j * $trows + $i + 1]}[@{$fmt}] = map {$_/$pixels} @data; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10352
|
|
|
|
|
|
|
|
|
10353
|
|
|
|
|
|
|
# if L*a*b* file |
|
10354
|
|
|
|
|
|
|
} elsif ($pi == 8) { |
|
10355
|
|
|
|
|
|
|
|
|
10356
|
|
|
|
|
|
|
# save data in object |
|
10357
|
0
|
|
|
|
|
0
|
$self->[1][$j * $trows + $i + 1][$fmt->[0]] = $data[0]/($pixels * $div); |
|
10358
|
0
|
|
|
|
|
0
|
$self->[1][$j * $trows + $i + 1][$fmt->[1]] = $data[1]/($pixels * $dab); |
|
10359
|
0
|
|
|
|
|
0
|
$self->[1][$j * $trows + $i + 1][$fmt->[2]] = $data[2]/($pixels * $dab); |
|
10360
|
|
|
|
|
|
|
|
|
10361
|
|
|
|
|
|
|
# all others |
|
10362
|
|
|
|
|
|
|
} else { |
|
10363
|
|
|
|
|
|
|
|
|
10364
|
|
|
|
|
|
|
# normalize data values |
|
10365
|
0
|
|
|
|
|
0
|
@data = map {$_/($pixels * $div)} @data; |
|
|
0
|
|
|
|
|
0
|
|
|
10366
|
|
|
|
|
|
|
|
|
10367
|
|
|
|
|
|
|
# if a CMYK file |
|
10368
|
0
|
0
|
|
|
|
0
|
if ($pi == 5) { |
|
10369
|
|
|
|
|
|
|
|
|
10370
|
|
|
|
|
|
|
# for alpha/spot colors (if any) |
|
10371
|
0
|
|
|
|
|
0
|
for my $s (4 .. $samples - 1) { |
|
10372
|
|
|
|
|
|
|
|
|
10373
|
|
|
|
|
|
|
# invert %-dot value |
|
10374
|
0
|
|
|
|
|
0
|
$data[$s] = 100 - $data[$s]; |
|
10375
|
|
|
|
|
|
|
|
|
10376
|
|
|
|
|
|
|
} |
|
10377
|
|
|
|
|
|
|
|
|
10378
|
|
|
|
|
|
|
} |
|
10379
|
|
|
|
|
|
|
|
|
10380
|
|
|
|
|
|
|
# save data in object |
|
10381
|
0
|
|
|
|
|
0
|
@{$self->[1][$j * $trows + $i + 1]}[@{$fmt}] = @data; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10382
|
|
|
|
|
|
|
|
|
10383
|
|
|
|
|
|
|
} |
|
10384
|
|
|
|
|
|
|
|
|
10385
|
|
|
|
|
|
|
} |
|
10386
|
|
|
|
|
|
|
|
|
10387
|
|
|
|
|
|
|
} |
|
10388
|
|
|
|
|
|
|
|
|
10389
|
|
|
|
|
|
|
# save the tag hash in object header |
|
10390
|
0
|
|
|
|
|
0
|
$self->[0]{'TIFF_tag'} = $tags; |
|
10391
|
|
|
|
|
|
|
|
|
10392
|
|
|
|
|
|
|
# add LGOROWLENGTH keyword |
|
10393
|
0
|
|
|
|
|
0
|
keyword($self, 'LGOROWLENGTH', $trows); |
|
10394
|
|
|
|
|
|
|
|
|
10395
|
|
|
|
|
|
|
# return |
|
10396
|
0
|
|
|
|
|
0
|
return(); |
|
10397
|
|
|
|
|
|
|
|
|
10398
|
|
|
|
|
|
|
} |
|
10399
|
|
|
|
|
|
|
|
|
10400
|
|
|
|
|
|
|
# read TIFF image file directory (IFD) |
|
10401
|
|
|
|
|
|
|
# parameters: (file_handle, offset, short_format, long_format) |
|
10402
|
|
|
|
|
|
|
# returns: (IFD_hash) |
|
10403
|
|
|
|
|
|
|
sub _readTIFFdir { |
|
10404
|
|
|
|
|
|
|
|
|
10405
|
|
|
|
|
|
|
# get parameters |
|
10406
|
0
|
|
|
0
|
|
0
|
my ($fh, $start, $short, $long) = @_; |
|
10407
|
|
|
|
|
|
|
|
|
10408
|
|
|
|
|
|
|
# local variables |
|
10409
|
0
|
|
|
|
|
0
|
my (@ts, $buf, $id, $type, $count, $size, $mark, $offset, $num, $denom, $tags); |
|
10410
|
|
|
|
|
|
|
|
|
10411
|
|
|
|
|
|
|
# field type size (in bytes) |
|
10412
|
0
|
|
|
|
|
0
|
@ts = (0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4); |
|
10413
|
|
|
|
|
|
|
|
|
10414
|
|
|
|
|
|
|
# seek start of IFD |
|
10415
|
0
|
|
|
|
|
0
|
seek($fh, $start, 0); |
|
10416
|
|
|
|
|
|
|
|
|
10417
|
|
|
|
|
|
|
# read number entries |
|
10418
|
0
|
|
|
|
|
0
|
read($fh, $buf, 2); |
|
10419
|
|
|
|
|
|
|
|
|
10420
|
|
|
|
|
|
|
# read the directory |
|
10421
|
0
|
|
|
|
|
0
|
for (1 .. unpack($short, $buf)) { |
|
10422
|
|
|
|
|
|
|
|
|
10423
|
|
|
|
|
|
|
# read first part of IFD entry |
|
10424
|
0
|
|
|
|
|
0
|
read($fh, $buf, 8); |
|
10425
|
|
|
|
|
|
|
|
|
10426
|
|
|
|
|
|
|
# unpack first three fields (ID, type, count) |
|
10427
|
0
|
|
|
|
|
0
|
($id, $type, $count) = unpack("$short$short$long", $buf); |
|
10428
|
|
|
|
|
|
|
|
|
10429
|
|
|
|
|
|
|
# read last part of IFD entry |
|
10430
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4); |
|
10431
|
|
|
|
|
|
|
|
|
10432
|
|
|
|
|
|
|
# determine value/offset size (size * count) + (1 if ASCII string) |
|
10433
|
0
|
0
|
|
|
|
0
|
$size = $ts[$type] * $count + (($type == 2) ? 1 : 0); |
|
10434
|
|
|
|
|
|
|
|
|
10435
|
|
|
|
|
|
|
# if an offset |
|
10436
|
0
|
0
|
0
|
|
|
0
|
if ($size > 4) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10437
|
|
|
|
|
|
|
|
|
10438
|
|
|
|
|
|
|
# mark file location |
|
10439
|
0
|
|
|
|
|
0
|
$mark = tell($fh); |
|
10440
|
|
|
|
|
|
|
|
|
10441
|
|
|
|
|
|
|
# unpack offset |
|
10442
|
0
|
|
|
|
|
0
|
$offset = unpack($long, $buf); |
|
10443
|
|
|
|
|
|
|
|
|
10444
|
|
|
|
|
|
|
# seek values |
|
10445
|
0
|
|
|
|
|
0
|
seek($fh, $offset, 0); |
|
10446
|
|
|
|
|
|
|
|
|
10447
|
|
|
|
|
|
|
# if binary string |
|
10448
|
0
|
0
|
0
|
|
|
0
|
if ($type == 1 || $type == 7) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10449
|
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
# read binary string |
|
10451
|
0
|
|
|
|
|
0
|
read($fh, $buf, $count); |
|
10452
|
|
|
|
|
|
|
|
|
10453
|
|
|
|
|
|
|
# unpack value |
|
10454
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("a$count", $buf)]; |
|
10455
|
|
|
|
|
|
|
|
|
10456
|
|
|
|
|
|
|
# if ASCII string |
|
10457
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
10458
|
|
|
|
|
|
|
|
|
10459
|
|
|
|
|
|
|
# read ASCII string |
|
10460
|
0
|
|
|
|
|
0
|
read($fh, $buf, $count); |
|
10461
|
|
|
|
|
|
|
|
|
10462
|
|
|
|
|
|
|
# unpack null-terminated ASCII string |
|
10463
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("Z$count", $buf)]; |
|
10464
|
|
|
|
|
|
|
|
|
10465
|
|
|
|
|
|
|
# if short values |
|
10466
|
|
|
|
|
|
|
} elsif ($type == 3) { |
|
10467
|
|
|
|
|
|
|
|
|
10468
|
|
|
|
|
|
|
# read values |
|
10469
|
0
|
|
|
|
|
0
|
read($fh, $buf, 2 * $count); |
|
10470
|
|
|
|
|
|
|
|
|
10471
|
|
|
|
|
|
|
# unpack values |
|
10472
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("$short$count", $buf)]; |
|
10473
|
|
|
|
|
|
|
|
|
10474
|
|
|
|
|
|
|
# if long values |
|
10475
|
|
|
|
|
|
|
} elsif ($type == 4) { |
|
10476
|
|
|
|
|
|
|
|
|
10477
|
|
|
|
|
|
|
# read values |
|
10478
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4 * $count); |
|
10479
|
|
|
|
|
|
|
|
|
10480
|
|
|
|
|
|
|
# unpack values |
|
10481
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("$long$count", $buf)]; |
|
10482
|
|
|
|
|
|
|
|
|
10483
|
|
|
|
|
|
|
# if rational values |
|
10484
|
|
|
|
|
|
|
} elsif ($type == 5) { |
|
10485
|
|
|
|
|
|
|
|
|
10486
|
|
|
|
|
|
|
# double count (one rational value is two long values) |
|
10487
|
0
|
|
|
|
|
0
|
$count *= 2; |
|
10488
|
|
|
|
|
|
|
|
|
10489
|
|
|
|
|
|
|
# read values |
|
10490
|
0
|
|
|
|
|
0
|
read($fh, $buf, 4 * $count); |
|
10491
|
|
|
|
|
|
|
|
|
10492
|
|
|
|
|
|
|
# unpack values |
|
10493
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("$long$count", $buf)]; |
|
10494
|
|
|
|
|
|
|
|
|
10495
|
|
|
|
|
|
|
} |
|
10496
|
|
|
|
|
|
|
|
|
10497
|
|
|
|
|
|
|
# reset file pointer |
|
10498
|
0
|
|
|
|
|
0
|
seek($fh, $mark, 0); |
|
10499
|
|
|
|
|
|
|
|
|
10500
|
|
|
|
|
|
|
# if binary string |
|
10501
|
|
|
|
|
|
|
} elsif ($type == 1 || $type == 7) { |
|
10502
|
|
|
|
|
|
|
|
|
10503
|
|
|
|
|
|
|
# unpack binary string |
|
10504
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("a$count", $buf)]; |
|
10505
|
|
|
|
|
|
|
|
|
10506
|
|
|
|
|
|
|
# if ASCII string |
|
10507
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
10508
|
|
|
|
|
|
|
|
|
10509
|
|
|
|
|
|
|
# unpack null-terminated ASCII string |
|
10510
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("Z$count", $buf)]; |
|
10511
|
|
|
|
|
|
|
|
|
10512
|
|
|
|
|
|
|
# if short value(s) |
|
10513
|
|
|
|
|
|
|
} elsif ($type == 3) { |
|
10514
|
|
|
|
|
|
|
|
|
10515
|
|
|
|
|
|
|
# unpack value(s) |
|
10516
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack("$short$count", $buf)]; |
|
10517
|
|
|
|
|
|
|
|
|
10518
|
|
|
|
|
|
|
# if long value |
|
10519
|
|
|
|
|
|
|
} elsif ($type == 4) { |
|
10520
|
|
|
|
|
|
|
|
|
10521
|
|
|
|
|
|
|
# unpack value |
|
10522
|
0
|
|
|
|
|
0
|
$tags->{$id} = [unpack($long, $buf)]; |
|
10523
|
|
|
|
|
|
|
|
|
10524
|
|
|
|
|
|
|
} else { |
|
10525
|
|
|
|
|
|
|
|
|
10526
|
|
|
|
|
|
|
# save packed value |
|
10527
|
0
|
|
|
|
|
0
|
$tags->{$id} = [$buf]; |
|
10528
|
|
|
|
|
|
|
|
|
10529
|
|
|
|
|
|
|
} |
|
10530
|
|
|
|
|
|
|
|
|
10531
|
|
|
|
|
|
|
} |
|
10532
|
|
|
|
|
|
|
|
|
10533
|
|
|
|
|
|
|
# return |
|
10534
|
0
|
|
|
|
|
0
|
return($tags); |
|
10535
|
|
|
|
|
|
|
|
|
10536
|
|
|
|
|
|
|
} |
|
10537
|
|
|
|
|
|
|
|
|
10538
|
|
|
|
|
|
|
# read TIFF image band |
|
10539
|
|
|
|
|
|
|
# row zero is top of image |
|
10540
|
|
|
|
|
|
|
# parameters: (file_handle, IFD_hash, lower_row, upper_row, row_width, unpack_format) |
|
10541
|
|
|
|
|
|
|
# returns: (2D_array) |
|
10542
|
|
|
|
|
|
|
sub _readTIFFband { |
|
10543
|
|
|
|
|
|
|
|
|
10544
|
|
|
|
|
|
|
# get parameters |
|
10545
|
0
|
|
|
0
|
|
0
|
my ($fh, $tags, $lower, $upper, $width, $upf) = @_; |
|
10546
|
|
|
|
|
|
|
|
|
10547
|
|
|
|
|
|
|
# local variables |
|
10548
|
0
|
|
|
|
|
0
|
my ($offset, $rows, $buf, $band); |
|
10549
|
|
|
|
|
|
|
|
|
10550
|
|
|
|
|
|
|
# get strip offset array |
|
10551
|
0
|
|
|
|
|
0
|
$offset = $tags->{'273'}; |
|
10552
|
|
|
|
|
|
|
|
|
10553
|
|
|
|
|
|
|
# get rows per strip |
|
10554
|
0
|
|
|
|
|
0
|
$rows = $tags->{'278'}[0]; |
|
10555
|
|
|
|
|
|
|
|
|
10556
|
|
|
|
|
|
|
# for each row |
|
10557
|
0
|
|
|
|
|
0
|
for my $i ($lower .. $upper) { |
|
10558
|
|
|
|
|
|
|
|
|
10559
|
|
|
|
|
|
|
# set file pointer |
|
10560
|
0
|
|
|
|
|
0
|
seek($fh, $offset->[int($i/$rows)] + ($i % $rows) * $width, 0); |
|
10561
|
|
|
|
|
|
|
|
|
10562
|
|
|
|
|
|
|
# read row data |
|
10563
|
0
|
|
|
|
|
0
|
read($fh, $buf, $width); |
|
10564
|
|
|
|
|
|
|
|
|
10565
|
|
|
|
|
|
|
# unpack data |
|
10566
|
0
|
|
|
|
|
0
|
$band->[$i - $lower] = [unpack($upf, $buf)]; |
|
10567
|
|
|
|
|
|
|
|
|
10568
|
|
|
|
|
|
|
} |
|
10569
|
|
|
|
|
|
|
|
|
10570
|
|
|
|
|
|
|
# return |
|
10571
|
0
|
|
|
|
|
0
|
return($band); |
|
10572
|
|
|
|
|
|
|
|
|
10573
|
|
|
|
|
|
|
} |
|
10574
|
|
|
|
|
|
|
|
|
10575
|
|
|
|
|
|
|
# write TIFF image file directory (IFD) |
|
10576
|
|
|
|
|
|
|
# parameters: (file_handle, offset, short_format, long_format, IFD_hash) |
|
10577
|
|
|
|
|
|
|
sub _writeTIFFdir { |
|
10578
|
|
|
|
|
|
|
|
|
10579
|
|
|
|
|
|
|
# get parameters |
|
10580
|
0
|
|
|
0
|
|
0
|
my ($fh, $ifd, $short, $long, $tags) = @_; |
|
10581
|
|
|
|
|
|
|
|
|
10582
|
|
|
|
|
|
|
# local variables |
|
10583
|
0
|
|
|
|
|
0
|
my (@ts, @sid, $mark, $type, $count, $size, $fmt); |
|
10584
|
|
|
|
|
|
|
|
|
10585
|
|
|
|
|
|
|
# field type size (in bytes) |
|
10586
|
0
|
|
|
|
|
0
|
@ts = (0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4); |
|
10587
|
|
|
|
|
|
|
|
|
10588
|
|
|
|
|
|
|
# make list of tag ids, sorted numerically |
|
10589
|
0
|
|
|
|
|
0
|
@sid = sort {$a <=> $b} keys(%{$tags}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10590
|
|
|
|
|
|
|
|
|
10591
|
|
|
|
|
|
|
# seek start of IFD |
|
10592
|
0
|
|
|
|
|
0
|
seek($fh, $ifd, 0); |
|
10593
|
|
|
|
|
|
|
|
|
10594
|
|
|
|
|
|
|
# write number of tags |
|
10595
|
0
|
|
|
|
|
0
|
print $fh pack($short, scalar(@sid)); |
|
10596
|
|
|
|
|
|
|
|
|
10597
|
|
|
|
|
|
|
# set data pointer |
|
10598
|
0
|
|
|
|
|
0
|
$mark = $ifd + 12 * @sid + 6; |
|
10599
|
|
|
|
|
|
|
|
|
10600
|
|
|
|
|
|
|
# for each tag |
|
10601
|
0
|
|
|
|
|
0
|
for my $id (@sid) { |
|
10602
|
|
|
|
|
|
|
|
|
10603
|
|
|
|
|
|
|
# get data type |
|
10604
|
0
|
|
|
|
|
0
|
$type = $tags->{$id}[0]; |
|
10605
|
|
|
|
|
|
|
|
|
10606
|
|
|
|
|
|
|
# if a binary string |
|
10607
|
0
|
0
|
0
|
|
|
0
|
if ($type == 1 || $type == 7) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10608
|
|
|
|
|
|
|
|
|
10609
|
|
|
|
|
|
|
# set count to string length |
|
10610
|
0
|
|
|
|
|
0
|
$count = length($tags->{$id}[1]); |
|
10611
|
|
|
|
|
|
|
|
|
10612
|
|
|
|
|
|
|
# if an ASCII string |
|
10613
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
10614
|
|
|
|
|
|
|
|
|
10615
|
|
|
|
|
|
|
# set count to string length + 1 |
|
10616
|
0
|
|
|
|
|
0
|
$count = length($tags->{$id}[1]) + 1; |
|
10617
|
|
|
|
|
|
|
|
|
10618
|
|
|
|
|
|
|
# if a rational value |
|
10619
|
|
|
|
|
|
|
} elsif ($type == 5) { |
|
10620
|
|
|
|
|
|
|
|
|
10621
|
|
|
|
|
|
|
# set count to number of values/2 |
|
10622
|
0
|
|
|
|
|
0
|
$count = $#{$tags->{$id}}/2; |
|
|
0
|
|
|
|
|
0
|
|
|
10623
|
|
|
|
|
|
|
|
|
10624
|
|
|
|
|
|
|
} else { |
|
10625
|
|
|
|
|
|
|
|
|
10626
|
|
|
|
|
|
|
# set count to number of values |
|
10627
|
0
|
|
|
|
|
0
|
$count = $#{$tags->{$id}}; |
|
|
0
|
|
|
|
|
0
|
|
|
10628
|
|
|
|
|
|
|
|
|
10629
|
|
|
|
|
|
|
} |
|
10630
|
|
|
|
|
|
|
|
|
10631
|
|
|
|
|
|
|
# if size of value/offset > 4 |
|
10632
|
0
|
0
|
|
|
|
0
|
if (($size = $count * $ts[$type]) > 4) { |
|
10633
|
|
|
|
|
|
|
|
|
10634
|
|
|
|
|
|
|
# write directory entry with offset |
|
10635
|
0
|
|
|
|
|
0
|
print $fh pack("$short$short$long$long", $id, $type, $count, $mark); |
|
10636
|
|
|
|
|
|
|
|
|
10637
|
|
|
|
|
|
|
# increment data pointer |
|
10638
|
0
|
|
|
|
|
0
|
$mark += $size; |
|
10639
|
|
|
|
|
|
|
|
|
10640
|
|
|
|
|
|
|
# make a word boundary |
|
10641
|
0
|
|
|
|
|
0
|
$mark += $mark % 2; |
|
10642
|
|
|
|
|
|
|
|
|
10643
|
|
|
|
|
|
|
} else { |
|
10644
|
|
|
|
|
|
|
|
|
10645
|
|
|
|
|
|
|
# if a binary string |
|
10646
|
0
|
0
|
0
|
|
|
0
|
if ($type == 1 || $type == 7) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10647
|
|
|
|
|
|
|
|
|
10648
|
|
|
|
|
|
|
# set pack format |
|
10649
|
0
|
|
|
|
|
0
|
$fmt = 'a4'; |
|
10650
|
|
|
|
|
|
|
|
|
10651
|
|
|
|
|
|
|
# if an ASCII string |
|
10652
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
10653
|
|
|
|
|
|
|
|
|
10654
|
|
|
|
|
|
|
# set pack format |
|
10655
|
0
|
|
|
|
|
0
|
$fmt = 'Z4'; |
|
10656
|
|
|
|
|
|
|
|
|
10657
|
|
|
|
|
|
|
# if a short value |
|
10658
|
|
|
|
|
|
|
} elsif ($type == 3) { |
|
10659
|
|
|
|
|
|
|
|
|
10660
|
|
|
|
|
|
|
# set pack format (one or two values) |
|
10661
|
0
|
0
|
|
|
|
0
|
$fmt = $count == 1 ? $short . 'x2' : $short . '2'; |
|
10662
|
|
|
|
|
|
|
|
|
10663
|
|
|
|
|
|
|
# if a long value |
|
10664
|
|
|
|
|
|
|
} elsif ($type == 4) { |
|
10665
|
|
|
|
|
|
|
|
|
10666
|
|
|
|
|
|
|
# set pack format |
|
10667
|
0
|
|
|
|
|
0
|
$fmt = $long; |
|
10668
|
|
|
|
|
|
|
|
|
10669
|
|
|
|
|
|
|
} else { |
|
10670
|
|
|
|
|
|
|
|
|
10671
|
|
|
|
|
|
|
# error |
|
10672
|
0
|
|
|
|
|
0
|
croak('unsupported TIFF data type, stopped'); |
|
10673
|
|
|
|
|
|
|
|
|
10674
|
|
|
|
|
|
|
} |
|
10675
|
|
|
|
|
|
|
|
|
10676
|
|
|
|
|
|
|
# write directory entry (12 bytes) with value(s) |
|
10677
|
0
|
|
|
|
|
0
|
print $fh pack("$short$short$long$fmt", $id, $type, $count, @{$tags->{$id}}[1 .. $#{$tags->{$id}}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10678
|
|
|
|
|
|
|
|
|
10679
|
|
|
|
|
|
|
} |
|
10680
|
|
|
|
|
|
|
|
|
10681
|
|
|
|
|
|
|
} |
|
10682
|
|
|
|
|
|
|
|
|
10683
|
|
|
|
|
|
|
# set data pointer |
|
10684
|
0
|
|
|
|
|
0
|
$mark = $ifd + 12 * @sid + 6; |
|
10685
|
|
|
|
|
|
|
|
|
10686
|
|
|
|
|
|
|
# for each tag |
|
10687
|
0
|
|
|
|
|
0
|
for my $id (@sid) { |
|
10688
|
|
|
|
|
|
|
|
|
10689
|
|
|
|
|
|
|
# get data type |
|
10690
|
0
|
|
|
|
|
0
|
$type = $tags->{$id}[0]; |
|
10691
|
|
|
|
|
|
|
|
|
10692
|
|
|
|
|
|
|
# if a binary string |
|
10693
|
0
|
0
|
0
|
|
|
0
|
if ($type == 1 || $type == 7) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10694
|
|
|
|
|
|
|
|
|
10695
|
|
|
|
|
|
|
# set count to string length |
|
10696
|
0
|
|
|
|
|
0
|
$count = length($tags->{$id}[1]); |
|
10697
|
|
|
|
|
|
|
|
|
10698
|
|
|
|
|
|
|
# if an ASCII string |
|
10699
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
10700
|
|
|
|
|
|
|
|
|
10701
|
|
|
|
|
|
|
# set count to string length + 1 |
|
10702
|
0
|
|
|
|
|
0
|
$count = length($tags->{$id}[1]) + 1; |
|
10703
|
|
|
|
|
|
|
|
|
10704
|
|
|
|
|
|
|
# if a rational value |
|
10705
|
|
|
|
|
|
|
} elsif ($type == 5) { |
|
10706
|
|
|
|
|
|
|
|
|
10707
|
|
|
|
|
|
|
# set count to number of values/2 |
|
10708
|
0
|
|
|
|
|
0
|
$count = $#{$tags->{$id}}/2; |
|
|
0
|
|
|
|
|
0
|
|
|
10709
|
|
|
|
|
|
|
|
|
10710
|
|
|
|
|
|
|
} else { |
|
10711
|
|
|
|
|
|
|
|
|
10712
|
|
|
|
|
|
|
# set count to number of values |
|
10713
|
0
|
|
|
|
|
0
|
$count = $#{$tags->{$id}}; |
|
|
0
|
|
|
|
|
0
|
|
|
10714
|
|
|
|
|
|
|
|
|
10715
|
|
|
|
|
|
|
} |
|
10716
|
|
|
|
|
|
|
|
|
10717
|
|
|
|
|
|
|
# if size of value/offset > 4 |
|
10718
|
0
|
0
|
|
|
|
0
|
if (($size = $count * $ts[$type]) > 4) { |
|
10719
|
|
|
|
|
|
|
|
|
10720
|
|
|
|
|
|
|
# if a binary string |
|
10721
|
0
|
0
|
0
|
|
|
0
|
if ($type == 1 || $type == 7) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10722
|
|
|
|
|
|
|
|
|
10723
|
|
|
|
|
|
|
# set pack format |
|
10724
|
0
|
|
|
|
|
0
|
$fmt = "a$count"; |
|
10725
|
|
|
|
|
|
|
|
|
10726
|
|
|
|
|
|
|
# if an ASCII string |
|
10727
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
10728
|
|
|
|
|
|
|
|
|
10729
|
|
|
|
|
|
|
# set pack format |
|
10730
|
0
|
|
|
|
|
0
|
$fmt = "Z$count"; |
|
10731
|
|
|
|
|
|
|
|
|
10732
|
|
|
|
|
|
|
# if a short value |
|
10733
|
|
|
|
|
|
|
} elsif ($type == 3) { |
|
10734
|
|
|
|
|
|
|
|
|
10735
|
|
|
|
|
|
|
# set pack format |
|
10736
|
0
|
|
|
|
|
0
|
$fmt = "$short$count"; |
|
10737
|
|
|
|
|
|
|
|
|
10738
|
|
|
|
|
|
|
# if a long value |
|
10739
|
|
|
|
|
|
|
} elsif ($type == 4) { |
|
10740
|
|
|
|
|
|
|
|
|
10741
|
|
|
|
|
|
|
# set pack format |
|
10742
|
0
|
|
|
|
|
0
|
$fmt = "$long$count"; |
|
10743
|
|
|
|
|
|
|
|
|
10744
|
|
|
|
|
|
|
# if a rational value |
|
10745
|
|
|
|
|
|
|
} elsif ($type == 5) { |
|
10746
|
|
|
|
|
|
|
|
|
10747
|
|
|
|
|
|
|
# set pack format |
|
10748
|
0
|
|
|
|
|
0
|
$fmt = "$long$#{$tags->{$id}}"; |
|
|
0
|
|
|
|
|
0
|
|
|
10749
|
|
|
|
|
|
|
|
|
10750
|
|
|
|
|
|
|
} else { |
|
10751
|
|
|
|
|
|
|
|
|
10752
|
|
|
|
|
|
|
# error |
|
10753
|
0
|
|
|
|
|
0
|
croak('unsupported TIFF data type, stopped'); |
|
10754
|
|
|
|
|
|
|
} |
|
10755
|
|
|
|
|
|
|
|
|
10756
|
|
|
|
|
|
|
# set file pointer |
|
10757
|
0
|
|
|
|
|
0
|
seek($fh, $mark, 0); |
|
10758
|
|
|
|
|
|
|
|
|
10759
|
|
|
|
|
|
|
# write the data value(s) |
|
10760
|
0
|
|
|
|
|
0
|
print $fh pack($fmt, @{$tags->{$id}}[1 .. $#{$tags->{$id}}]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10761
|
|
|
|
|
|
|
|
|
10762
|
|
|
|
|
|
|
# increment data pointer |
|
10763
|
0
|
|
|
|
|
0
|
$mark += $size; |
|
10764
|
|
|
|
|
|
|
|
|
10765
|
|
|
|
|
|
|
# make a word boundary |
|
10766
|
0
|
|
|
|
|
0
|
$mark += $mark % 2; |
|
10767
|
|
|
|
|
|
|
|
|
10768
|
|
|
|
|
|
|
} |
|
10769
|
|
|
|
|
|
|
|
|
10770
|
|
|
|
|
|
|
} |
|
10771
|
|
|
|
|
|
|
|
|
10772
|
|
|
|
|
|
|
} |
|
10773
|
|
|
|
|
|
|
|
|
10774
|
|
|
|
|
|
|
# write TIFF data strip |
|
10775
|
|
|
|
|
|
|
# parameters: (file_handle, IFD_hash, patch_width, gap_width, left_edge_width, right_edge_width, strip_index, strip_data_array, pack_format, dither_value) |
|
10776
|
|
|
|
|
|
|
sub _writeTIFFstrip { |
|
10777
|
|
|
|
|
|
|
|
|
10778
|
|
|
|
|
|
|
# get parameters |
|
10779
|
0
|
|
|
0
|
|
0
|
my ($fh, $tags, $width, $gap, $left, $right, $sx, $data, $fmt, $dither) = @_; |
|
10780
|
|
|
|
|
|
|
|
|
10781
|
|
|
|
|
|
|
# local variables |
|
10782
|
0
|
|
|
|
|
0
|
my ($pi, $samples, $bits, $max, $diff, $edge, $w, @spot, $rms, $gdata, @row, $strip); |
|
10783
|
|
|
|
|
|
|
|
|
10784
|
|
|
|
|
|
|
# get photometric interpretation |
|
10785
|
0
|
|
|
|
|
0
|
$pi = $tags->{'262'}[1]; |
|
10786
|
|
|
|
|
|
|
|
|
10787
|
|
|
|
|
|
|
# get number of samples (channels) |
|
10788
|
0
|
|
|
|
|
0
|
$samples = $tags->{'277'}[1]; |
|
10789
|
|
|
|
|
|
|
|
|
10790
|
|
|
|
|
|
|
# get bits per sample |
|
10791
|
0
|
|
|
|
|
0
|
$bits = $tags->{'258'}[1]; |
|
10792
|
|
|
|
|
|
|
|
|
10793
|
|
|
|
|
|
|
# max binary value (8, 16 or 32 bits) |
|
10794
|
0
|
0
|
|
|
|
0
|
$max = ($bits == 8) ? 255 : ($bits == 16) ? 65535 : 1; |
|
|
|
0
|
|
|
|
|
|
|
10795
|
|
|
|
|
|
|
|
|
10796
|
|
|
|
|
|
|
# make list of spot channel indices |
|
10797
|
0
|
|
|
|
|
0
|
@spot = (4 .. $tags->{'277'}[1] - 1); |
|
10798
|
|
|
|
|
|
|
|
|
10799
|
|
|
|
|
|
|
# for each patch |
|
10800
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$data}) { |
|
|
0
|
|
|
|
|
0
|
|
|
10801
|
|
|
|
|
|
|
|
|
10802
|
|
|
|
|
|
|
# if RGB data |
|
10803
|
0
|
0
|
|
|
|
0
|
if ($pi == 2) { |
|
|
|
0
|
|
|
|
|
|
|
10804
|
|
|
|
|
|
|
|
|
10805
|
|
|
|
|
|
|
# compute white and black differences |
|
10806
|
0
|
|
|
|
|
0
|
$diff->[$i][0] = sqrt(($max - $data->[$i][0])**2 + ($max - $data->[$i][1])**2 + ($max - $data->[$i][2])**2); |
|
10807
|
0
|
|
|
|
|
0
|
$diff->[$i][1] = sqrt($data->[$i][0]**2 + $data->[$i][1]**2 + $data->[$i][2]**2); |
|
10808
|
|
|
|
|
|
|
|
|
10809
|
|
|
|
|
|
|
# if CMYK data |
|
10810
|
|
|
|
|
|
|
} elsif ($pi == 5) { |
|
10811
|
|
|
|
|
|
|
|
|
10812
|
|
|
|
|
|
|
# compute rms value of CMY + spot channels (CMY weighted and spot channels inverted) |
|
10813
|
0
|
|
|
|
|
0
|
$rms = sqrt(List::Util::sum(0.25 * $data->[$i][0]**2, 3 * $data->[$i][1]**2, 0.25 * $data->[$i][2]**2, (map {($max - $data->[$i][$_])**2} @spot))/(3 + @spot)); |
|
|
0
|
|
|
|
|
0
|
|
|
10814
|
|
|
|
|
|
|
|
|
10815
|
|
|
|
|
|
|
# compute white and black differences (black * color) |
|
10816
|
0
|
|
|
|
|
0
|
$diff->[$i][0] = $max - ($max - $data->[$i][3]) * ($max - $rms)/$max; |
|
10817
|
0
|
|
|
|
|
0
|
$diff->[$i][1] = ($max - $data->[$i][3]) * ($max - $rms)/$max; |
|
10818
|
|
|
|
|
|
|
|
|
10819
|
|
|
|
|
|
|
# L*a*b* data |
|
10820
|
|
|
|
|
|
|
} else { |
|
10821
|
|
|
|
|
|
|
|
|
10822
|
|
|
|
|
|
|
# compute white and black differences (approx dEab) |
|
10823
|
0
|
|
|
|
|
0
|
$diff->[$i][0] = sqrt(($max - $data->[$i][0])**2 + 6.55 * $data->[$i][1]**2 + 6.55 * $data->[$i][2]**2); |
|
10824
|
0
|
|
|
|
|
0
|
$diff->[$i][1] = sqrt($data->[$i][0]**2 + 6.55 * $data->[$i][1]**2 + 6.55 * $data->[$i][2]**2); |
|
10825
|
|
|
|
|
|
|
|
|
10826
|
|
|
|
|
|
|
} |
|
10827
|
|
|
|
|
|
|
|
|
10828
|
|
|
|
|
|
|
# skip first patch |
|
10829
|
0
|
0
|
|
|
|
0
|
if ($i > 0) { |
|
10830
|
|
|
|
|
|
|
|
|
10831
|
|
|
|
|
|
|
# if RGB data |
|
10832
|
0
|
0
|
|
|
|
0
|
if ($pi == 2) { |
|
|
|
0
|
|
|
|
|
|
|
10833
|
|
|
|
|
|
|
|
|
10834
|
|
|
|
|
|
|
# if max white difference > max black difference |
|
10835
|
0
|
0
|
|
|
|
0
|
if (($diff->[$i - 1][0] > $diff->[$i][0] ? $diff->[$i - 1][0] : $diff->[$i][0]) > ($diff->[$i - 1][1] > $diff->[$i][1] ? $diff->[$i - 1][1] : $diff->[$i][1])) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10836
|
|
|
|
|
|
|
|
|
10837
|
|
|
|
|
|
|
# gap is white |
|
10838
|
0
|
|
|
|
|
0
|
$gdata->[$i - 1] = [($max) x 3]; |
|
10839
|
|
|
|
|
|
|
|
|
10840
|
|
|
|
|
|
|
} else { |
|
10841
|
|
|
|
|
|
|
|
|
10842
|
|
|
|
|
|
|
# gap is black |
|
10843
|
0
|
|
|
|
|
0
|
$gdata->[$i - 1] = [0, 0, 0]; |
|
10844
|
|
|
|
|
|
|
|
|
10845
|
|
|
|
|
|
|
} |
|
10846
|
|
|
|
|
|
|
|
|
10847
|
|
|
|
|
|
|
# if CMYK data |
|
10848
|
|
|
|
|
|
|
} elsif ($pi == 5) { |
|
10849
|
|
|
|
|
|
|
|
|
10850
|
|
|
|
|
|
|
# if max white difference > max black difference |
|
10851
|
0
|
0
|
|
|
|
0
|
if (($diff->[$i - 1][0] > $diff->[$i][0] ? $diff->[$i - 1][0] : $diff->[$i][0]) > ($diff->[$i - 1][1] > $diff->[$i][1] ? $diff->[$i - 1][1] : $diff->[$i][1])) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10852
|
|
|
|
|
|
|
|
|
10853
|
|
|
|
|
|
|
# gap is white |
|
10854
|
0
|
|
|
|
|
0
|
$gdata->[$i - 1] = [0, 0, 0, 0, ($max) x ($samples - 4)]; |
|
10855
|
|
|
|
|
|
|
|
|
10856
|
|
|
|
|
|
|
} else { |
|
10857
|
|
|
|
|
|
|
|
|
10858
|
|
|
|
|
|
|
# gap is black |
|
10859
|
0
|
|
|
|
|
0
|
$gdata->[$i - 1] = [0, 0, 0, ($max) x ($samples - 3)]; |
|
10860
|
|
|
|
|
|
|
|
|
10861
|
|
|
|
|
|
|
} |
|
10862
|
|
|
|
|
|
|
|
|
10863
|
|
|
|
|
|
|
# L*a*b* data |
|
10864
|
|
|
|
|
|
|
} else { |
|
10865
|
|
|
|
|
|
|
|
|
10866
|
|
|
|
|
|
|
# if max white difference > max black difference |
|
10867
|
0
|
0
|
|
|
|
0
|
if (($diff->[$i - 1][0] > $diff->[$i][0] ? $diff->[$i - 1][0] : $diff->[$i][0]) > ($diff->[$i - 1][1] > $diff->[$i][1] ? $diff->[$i - 1][1] : $diff->[$i][1])) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10868
|
|
|
|
|
|
|
|
|
10869
|
|
|
|
|
|
|
# gap is white |
|
10870
|
0
|
|
|
|
|
0
|
$gdata->[$i - 1] = [$max, 0, 0]; |
|
10871
|
|
|
|
|
|
|
|
|
10872
|
|
|
|
|
|
|
} else { |
|
10873
|
|
|
|
|
|
|
|
|
10874
|
|
|
|
|
|
|
# gap is black |
|
10875
|
0
|
|
|
|
|
0
|
$gdata->[$i - 1] = [0, 0, 0]; |
|
10876
|
|
|
|
|
|
|
|
|
10877
|
|
|
|
|
|
|
} |
|
10878
|
|
|
|
|
|
|
|
|
10879
|
|
|
|
|
|
|
} |
|
10880
|
|
|
|
|
|
|
|
|
10881
|
|
|
|
|
|
|
} |
|
10882
|
|
|
|
|
|
|
|
|
10883
|
|
|
|
|
|
|
} |
|
10884
|
|
|
|
|
|
|
|
|
10885
|
|
|
|
|
|
|
# compute edge pixel values (black) |
|
10886
|
0
|
0
|
|
|
|
0
|
$edge = ($pi == 5) ? [0, 0, 0, ($max) x ($samples - 3)] : [0, 0, 0]; |
|
10887
|
|
|
|
|
|
|
|
|
10888
|
|
|
|
|
|
|
# for each patch |
|
10889
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$data}) { |
|
|
0
|
|
|
|
|
0
|
|
|
10890
|
|
|
|
|
|
|
|
|
10891
|
|
|
|
|
|
|
# if first patch |
|
10892
|
0
|
0
|
|
|
|
0
|
if ($i == 0) { |
|
|
|
0
|
|
|
|
|
|
|
10893
|
|
|
|
|
|
|
|
|
10894
|
|
|
|
|
|
|
# add left edge data |
|
10895
|
0
|
|
|
|
|
0
|
push(@row, (@{$edge}) x $left->[0]); |
|
|
0
|
|
|
|
|
0
|
|
|
10896
|
|
|
|
|
|
|
|
|
10897
|
|
|
|
|
|
|
# set patch width |
|
10898
|
0
|
|
|
|
|
0
|
$w = $width - $left->[1]; |
|
10899
|
|
|
|
|
|
|
|
|
10900
|
|
|
|
|
|
|
# if last patch |
|
10901
|
0
|
|
|
|
|
0
|
} elsif ($i == $#{$data}) { |
|
10902
|
|
|
|
|
|
|
|
|
10903
|
|
|
|
|
|
|
# set patch width |
|
10904
|
0
|
|
|
|
|
0
|
$w = $width - $right->[1]; |
|
10905
|
|
|
|
|
|
|
|
|
10906
|
|
|
|
|
|
|
# others |
|
10907
|
|
|
|
|
|
|
} else { |
|
10908
|
|
|
|
|
|
|
|
|
10909
|
|
|
|
|
|
|
# set patch width |
|
10910
|
0
|
|
|
|
|
0
|
$w = $width; |
|
10911
|
|
|
|
|
|
|
|
|
10912
|
|
|
|
|
|
|
} |
|
10913
|
|
|
|
|
|
|
|
|
10914
|
|
|
|
|
|
|
# if dither enabled or 32-bits |
|
10915
|
0
|
0
|
0
|
|
|
0
|
if (defined($dither) || $bits == 32) { |
|
10916
|
|
|
|
|
|
|
|
|
10917
|
|
|
|
|
|
|
# add patch data |
|
10918
|
0
|
|
|
|
|
0
|
push(@row, (@{$data->[$i]}) x $w); |
|
|
0
|
|
|
|
|
0
|
|
|
10919
|
|
|
|
|
|
|
|
|
10920
|
|
|
|
|
|
|
} else { |
|
10921
|
|
|
|
|
|
|
|
|
10922
|
|
|
|
|
|
|
# add patch data, adding/subtracting 0.5 to round to the nearest integer (by 'pack', below) |
|
10923
|
0
|
0
|
|
|
|
0
|
push(@row, (map {$_ < 0 ? $_ - 0.5 : $_ + 0.5} @{$data->[$i]}) x $w); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10924
|
|
|
|
|
|
|
|
|
10925
|
|
|
|
|
|
|
} |
|
10926
|
|
|
|
|
|
|
|
|
10927
|
|
|
|
|
|
|
# if last patch |
|
10928
|
0
|
0
|
|
|
|
0
|
if ($i == $#{$data}) { |
|
|
0
|
|
|
|
|
0
|
|
|
10929
|
|
|
|
|
|
|
|
|
10930
|
|
|
|
|
|
|
# add right edge data |
|
10931
|
0
|
|
|
|
|
0
|
push(@row, (@{$edge}) x $right->[0]); |
|
|
0
|
|
|
|
|
0
|
|
|
10932
|
|
|
|
|
|
|
|
|
10933
|
|
|
|
|
|
|
} else { |
|
10934
|
|
|
|
|
|
|
|
|
10935
|
|
|
|
|
|
|
# add gap data |
|
10936
|
0
|
|
|
|
|
0
|
push(@row, (@{$gdata->[$i]}) x $gap); |
|
|
0
|
|
|
|
|
0
|
|
|
10937
|
|
|
|
|
|
|
|
|
10938
|
|
|
|
|
|
|
} |
|
10939
|
|
|
|
|
|
|
|
|
10940
|
|
|
|
|
|
|
} |
|
10941
|
|
|
|
|
|
|
|
|
10942
|
|
|
|
|
|
|
# set file pointer to strip offset |
|
10943
|
0
|
|
|
|
|
0
|
seek($fh, $tags->{'273'}[$sx + 1], 0); |
|
10944
|
|
|
|
|
|
|
|
|
10945
|
|
|
|
|
|
|
# if dither enabled and 8-bit |
|
10946
|
0
|
0
|
0
|
|
|
0
|
if (defined($dither) && $bits == 8) { |
|
10947
|
|
|
|
|
|
|
|
|
10948
|
|
|
|
|
|
|
# for each strip row |
|
10949
|
0
|
|
|
|
|
0
|
for my $i (0 .. $tags->{'278'}[1] - 1) { |
|
10950
|
|
|
|
|
|
|
|
|
10951
|
|
|
|
|
|
|
# write packed data with dithering |
|
10952
|
0
|
0
|
|
|
|
0
|
print $fh pack($fmt, map {$_ < 0 ? $_ - rand() : $_ + rand()} @row); |
|
|
0
|
|
|
|
|
0
|
|
|
10953
|
|
|
|
|
|
|
|
|
10954
|
|
|
|
|
|
|
} |
|
10955
|
|
|
|
|
|
|
|
|
10956
|
|
|
|
|
|
|
} else { |
|
10957
|
|
|
|
|
|
|
|
|
10958
|
|
|
|
|
|
|
# for each strip row |
|
10959
|
0
|
|
|
|
|
0
|
for my $i (0 .. $tags->{'278'}[1] - 1) { |
|
10960
|
|
|
|
|
|
|
|
|
10961
|
|
|
|
|
|
|
# write packed data |
|
10962
|
0
|
|
|
|
|
0
|
print $fh pack($fmt, @row); |
|
10963
|
|
|
|
|
|
|
|
|
10964
|
|
|
|
|
|
|
} |
|
10965
|
|
|
|
|
|
|
|
|
10966
|
|
|
|
|
|
|
} |
|
10967
|
|
|
|
|
|
|
|
|
10968
|
|
|
|
|
|
|
} |
|
10969
|
|
|
|
|
|
|
|
|
10970
|
|
|
|
|
|
|
# read chart from CxF3 data file |
|
10971
|
|
|
|
|
|
|
# parameters: (object_reference, file_handle, hash) |
|
10972
|
|
|
|
|
|
|
# returns: (result) |
|
10973
|
|
|
|
|
|
|
sub _readChartCxF3 { |
|
10974
|
|
|
|
|
|
|
|
|
10975
|
|
|
|
|
|
|
# get parameters |
|
10976
|
8
|
|
|
8
|
|
21
|
my ($self, $fh, $hash) = @_; |
|
10977
|
|
|
|
|
|
|
|
|
10978
|
|
|
|
|
|
|
# local variables |
|
10979
|
8
|
|
|
|
|
23
|
my ($dom, $root, @rns, $core, $ns, $xpc); |
|
10980
|
8
|
|
|
|
|
0
|
my (@obj, $ops_hash, $ix, $nx, $ops, $type, $name, $mode, $name_ix, $node, @data); |
|
10981
|
|
|
|
|
|
|
|
|
10982
|
|
|
|
|
|
|
# parse CxF3 document |
|
10983
|
8
|
50
|
|
|
|
14
|
eval{$dom = XML::LibXML->load_xml('IO' => $fh)} || return('failed parsing CxF3 document'); |
|
|
8
|
|
|
|
|
61
|
|
|
10984
|
|
|
|
|
|
|
|
|
10985
|
|
|
|
|
|
|
# get root element |
|
10986
|
8
|
|
|
|
|
7856
|
$root = $dom->documentElement(); |
|
10987
|
|
|
|
|
|
|
|
|
10988
|
|
|
|
|
|
|
# get root namespaces |
|
10989
|
8
|
|
|
|
|
61
|
@rns = $root->getNamespaces(); |
|
10990
|
|
|
|
|
|
|
|
|
10991
|
|
|
|
|
|
|
# get CxF3-core namespace object, verify a CxF3 document |
|
10992
|
8
|
50
|
|
|
|
22
|
(($core) = grep {$_->value eq 'http://colorexchangeformat.com/CxF3-core'} @rns) || return('CxF3 document has wrong URI'); |
|
|
16
|
|
|
|
|
72
|
|
|
10993
|
|
|
|
|
|
|
|
|
10994
|
|
|
|
|
|
|
# validate the CxF3 document |
|
10995
|
8
|
0
|
33
|
|
|
26
|
_validateCxF3($dom) if (defined($hash->{'validate'}) && $hash->{'validate'}); |
|
10996
|
|
|
|
|
|
|
|
|
10997
|
|
|
|
|
|
|
# if CxF3-core namespace has prefix |
|
10998
|
8
|
50
|
|
|
|
31
|
if ($ns = $core->declaredPrefix) { |
|
10999
|
|
|
|
|
|
|
|
|
11000
|
|
|
|
|
|
|
# append ':' to namespace prefix |
|
11001
|
8
|
|
|
|
|
22
|
$ns .= ':'; |
|
11002
|
|
|
|
|
|
|
|
|
11003
|
|
|
|
|
|
|
} else { |
|
11004
|
|
|
|
|
|
|
|
|
11005
|
|
|
|
|
|
|
# register default namespace |
|
11006
|
0
|
|
|
|
|
0
|
$xpc->registerNs('cc' => 'http://colorexchangeformat.com/CxF3-core'); |
|
11007
|
|
|
|
|
|
|
|
|
11008
|
|
|
|
|
|
|
# set default namespace prefix |
|
11009
|
0
|
|
|
|
|
0
|
$ns = 'cc:'; |
|
11010
|
|
|
|
|
|
|
|
|
11011
|
|
|
|
|
|
|
} |
|
11012
|
|
|
|
|
|
|
|
|
11013
|
|
|
|
|
|
|
# save document object model in header |
|
11014
|
8
|
|
|
|
|
19
|
$self->[0]{'CxF3_dom'} = $dom; |
|
11015
|
|
|
|
|
|
|
|
|
11016
|
|
|
|
|
|
|
# save record separator in header |
|
11017
|
|
|
|
|
|
|
# note: XML files might not have record separators |
|
11018
|
|
|
|
|
|
|
# so we use Perl's input record separator instead |
|
11019
|
8
|
|
|
|
|
25
|
$self->[0]{'read_rs'} = $/; |
|
11020
|
|
|
|
|
|
|
|
|
11021
|
|
|
|
|
|
|
# make XPathContext object |
|
11022
|
8
|
|
|
|
|
180
|
$xpc = XML::LibXML::XPathContext->new($root); |
|
11023
|
|
|
|
|
|
|
|
|
11024
|
|
|
|
|
|
|
# read CxF3 FileInformation nodes |
|
11025
|
8
|
|
|
|
|
34
|
_readCxF3fileinfo($self, $xpc, $ns); |
|
11026
|
|
|
|
|
|
|
|
|
11027
|
|
|
|
|
|
|
# get cc:Object nodes |
|
11028
|
8
|
|
|
|
|
371
|
@obj = $xpc->findnodes("${ns}Resources/${ns}ObjectCollection/${ns}Object"); |
|
11029
|
|
|
|
|
|
|
|
|
11030
|
|
|
|
|
|
|
# make the operations hash and add format fields |
|
11031
|
8
|
|
|
|
|
315
|
$ops_hash = _makeCxF3readops($self, $xpc, $ns, \@obj, $hash); |
|
11032
|
|
|
|
|
|
|
|
|
11033
|
|
|
|
|
|
|
# get the ObjectType attribute of first object |
|
11034
|
8
|
|
|
|
|
159
|
$type = $obj[0]->getAttribute('ObjectType'); |
|
11035
|
|
|
|
|
|
|
|
|
11036
|
|
|
|
|
|
|
# get the Name attribute of first object |
|
11037
|
8
|
|
|
|
|
87
|
$name = $obj[0]->getAttribute('Name'); |
|
11038
|
|
|
|
|
|
|
|
|
11039
|
|
|
|
|
|
|
# determine the object linking mode |
|
11040
|
8
|
|
|
|
|
114
|
$mode = $name =~ m/^$type(\d+)/; |
|
11041
|
|
|
|
|
|
|
|
|
11042
|
|
|
|
|
|
|
# initialize next sample index |
|
11043
|
8
|
|
|
|
|
14
|
$nx = 1; |
|
11044
|
|
|
|
|
|
|
|
|
11045
|
|
|
|
|
|
|
# for each cc:Object element |
|
11046
|
8
|
|
|
|
|
17
|
for my $s (@obj) { |
|
11047
|
|
|
|
|
|
|
|
|
11048
|
|
|
|
|
|
|
# get the ObjectType attribute |
|
11049
|
160
|
|
|
|
|
347
|
$type = $s->getAttribute('ObjectType'); |
|
11050
|
|
|
|
|
|
|
|
|
11051
|
|
|
|
|
|
|
# get the Name attribute |
|
11052
|
160
|
|
|
|
|
1414
|
$name = $s->getAttribute('Name'); |
|
11053
|
|
|
|
|
|
|
|
|
11054
|
|
|
|
|
|
|
# if Name is ObjectType with index appended (X-Rite i1Profiler) |
|
11055
|
160
|
50
|
|
|
|
1066
|
if ($mode) { |
|
|
|
0
|
|
|
|
|
|
|
11056
|
|
|
|
|
|
|
|
|
11057
|
|
|
|
|
|
|
# match row index |
|
11058
|
160
|
50
|
|
|
|
939
|
if ($name =~ m/^$type(\d+)/) { |
|
11059
|
|
|
|
|
|
|
|
|
11060
|
|
|
|
|
|
|
# set row index |
|
11061
|
160
|
|
|
|
|
402
|
$ix = $1; |
|
11062
|
|
|
|
|
|
|
|
|
11063
|
|
|
|
|
|
|
} else { |
|
11064
|
|
|
|
|
|
|
|
|
11065
|
|
|
|
|
|
|
# print message |
|
11066
|
0
|
|
|
|
|
0
|
print "invalid CxF3 Object node\n"; |
|
11067
|
|
|
|
|
|
|
|
|
11068
|
|
|
|
|
|
|
# next object |
|
11069
|
0
|
|
|
|
|
0
|
next; |
|
11070
|
|
|
|
|
|
|
|
|
11071
|
|
|
|
|
|
|
} |
|
11072
|
|
|
|
|
|
|
|
|
11073
|
|
|
|
|
|
|
# if Name found in hash (objects related by Name attribute) |
|
11074
|
|
|
|
|
|
|
} elsif (exists($name_ix->{$name})) { |
|
11075
|
|
|
|
|
|
|
|
|
11076
|
|
|
|
|
|
|
# set row index |
|
11077
|
0
|
|
|
|
|
0
|
$ix = $name_ix->{$name}; |
|
11078
|
|
|
|
|
|
|
|
|
11079
|
|
|
|
|
|
|
} else { |
|
11080
|
|
|
|
|
|
|
|
|
11081
|
|
|
|
|
|
|
# add Name to hash and increment next sample index |
|
11082
|
0
|
|
|
|
|
0
|
$ix = $name_ix->{$name} = $nx++; |
|
11083
|
|
|
|
|
|
|
|
|
11084
|
|
|
|
|
|
|
} |
|
11085
|
|
|
|
|
|
|
|
|
11086
|
|
|
|
|
|
|
# get operation list for this ObjectType |
|
11087
|
160
|
|
|
|
|
253
|
$ops = $ops_hash->{$type}; |
|
11088
|
|
|
|
|
|
|
|
|
11089
|
|
|
|
|
|
|
# for each operation |
|
11090
|
160
|
|
|
|
|
175
|
for my $i (0 .. $#{$ops}) { |
|
|
160
|
|
|
|
|
336
|
|
|
11091
|
|
|
|
|
|
|
|
|
11092
|
|
|
|
|
|
|
# get main Xpath node |
|
11093
|
160
|
|
|
|
|
335
|
($node) = $xpc->findnodes($ops->[$i][1], $s); |
|
11094
|
|
|
|
|
|
|
|
|
11095
|
|
|
|
|
|
|
# if subpaths |
|
11096
|
160
|
100
|
|
|
|
6167
|
if (@{$ops->[$i][2]}) { |
|
|
160
|
50
|
|
|
|
292
|
|
|
|
|
50
|
|
|
|
|
|
|
11097
|
|
|
|
|
|
|
|
|
11098
|
|
|
|
|
|
|
# if data class is NCLR |
|
11099
|
100
|
100
|
|
|
|
165
|
if ($ops->[$i][0] eq 'NCLR') { |
|
11100
|
|
|
|
|
|
|
|
|
11101
|
|
|
|
|
|
|
# get the CMYK values |
|
11102
|
20
|
|
|
|
|
25
|
@data = map {$xpc->findvalue($_, $node)} @{$ops->[$i][2]}; |
|
|
80
|
|
|
|
|
3658
|
|
|
|
20
|
|
|
|
|
32
|
|
|
11103
|
|
|
|
|
|
|
|
|
11104
|
|
|
|
|
|
|
# for each SpotColor |
|
11105
|
20
|
|
|
|
|
1168
|
for my $spotcolor ($xpc->findnodes("${ns}SpotColor", $node)) { |
|
11106
|
|
|
|
|
|
|
|
|
11107
|
|
|
|
|
|
|
# push SpotColor value |
|
11108
|
40
|
|
|
|
|
1689
|
push(@data, $xpc->findvalue("${ns}Percentage", $spotcolor)); |
|
11109
|
|
|
|
|
|
|
|
|
11110
|
|
|
|
|
|
|
} |
|
11111
|
|
|
|
|
|
|
|
|
11112
|
|
|
|
|
|
|
# set chart data (CMYK + SPOT values) |
|
11113
|
20
|
|
|
|
|
1107
|
@{$self->[1][$ix]}[@{$ops->[$i][3]}] = @data; |
|
|
20
|
|
|
|
|
101
|
|
|
|
20
|
|
|
|
|
307
|
|
|
11114
|
|
|
|
|
|
|
|
|
11115
|
|
|
|
|
|
|
} else { |
|
11116
|
|
|
|
|
|
|
|
|
11117
|
|
|
|
|
|
|
# set chart data using subpaths |
|
11118
|
80
|
|
|
|
|
96
|
@{$self->[1][$ix]}[@{$ops->[$i][3]}] = map {$xpc->findvalue($_, $node)} @{$ops->[$i][2]}; |
|
|
80
|
|
|
|
|
310
|
|
|
|
80
|
|
|
|
|
4454
|
|
|
|
280
|
|
|
|
|
11293
|
|
|
|
80
|
|
|
|
|
133
|
|
|
11119
|
|
|
|
|
|
|
|
|
11120
|
|
|
|
|
|
|
} |
|
11121
|
|
|
|
|
|
|
|
|
11122
|
|
|
|
|
|
|
# if no subpaths and one field |
|
11123
|
60
|
|
|
|
|
106
|
} elsif (@{$ops->[$i][3]} == 1) { |
|
11124
|
|
|
|
|
|
|
|
|
11125
|
|
|
|
|
|
|
# set chart data to text content |
|
11126
|
0
|
|
|
|
|
0
|
$self->[1][$ix][$ops->[$i][3][0]] = $node->textContent(); |
|
11127
|
|
|
|
|
|
|
|
|
11128
|
|
|
|
|
|
|
# if no subpaths and multiple fields (e.g. spectral data) |
|
11129
|
60
|
|
|
|
|
121
|
} elsif (@{$ops->[$i][3]} > 1) { |
|
11130
|
|
|
|
|
|
|
|
|
11131
|
|
|
|
|
|
|
# set chart data splitting text content |
|
11132
|
60
|
|
|
|
|
621
|
@{$self->[1][$ix]}[@{$ops->[$i][3]}] = split(' ', $node->textContent()); |
|
|
60
|
|
|
|
|
485
|
|
|
|
60
|
|
|
|
|
104
|
|
|
11133
|
|
|
|
|
|
|
|
|
11134
|
|
|
|
|
|
|
} |
|
11135
|
|
|
|
|
|
|
|
|
11136
|
|
|
|
|
|
|
} |
|
11137
|
|
|
|
|
|
|
|
|
11138
|
|
|
|
|
|
|
} |
|
11139
|
|
|
|
|
|
|
|
|
11140
|
|
|
|
|
|
|
# read CxF3 ColorSpecification nodes |
|
11141
|
8
|
|
|
|
|
28
|
_readCxF3colorspec($self, $xpc, $ns); |
|
11142
|
|
|
|
|
|
|
|
|
11143
|
|
|
|
|
|
|
# read CxF3 CustomResources nodes |
|
11144
|
8
|
|
|
|
|
224
|
_readCxF3customres($self, $xpc, $ns, \@rns); |
|
11145
|
|
|
|
|
|
|
|
|
11146
|
|
|
|
|
|
|
# clean-up contexts |
|
11147
|
8
|
|
|
|
|
157
|
_readCxF3cleanup($self); |
|
11148
|
|
|
|
|
|
|
|
|
11149
|
|
|
|
|
|
|
# save XPath context object in header |
|
11150
|
|
|
|
|
|
|
# note: all CustomResources namespaces are registered |
|
11151
|
8
|
|
|
|
|
18
|
$self->[0]{'CxF3_XPathContext'} = $xpc; |
|
11152
|
|
|
|
|
|
|
|
|
11153
|
|
|
|
|
|
|
# return |
|
11154
|
8
|
|
|
|
|
24
|
return(); |
|
11155
|
|
|
|
|
|
|
|
|
11156
|
|
|
|
|
|
|
} |
|
11157
|
|
|
|
|
|
|
|
|
11158
|
|
|
|
|
|
|
# make CxF3 read operations hash |
|
11159
|
|
|
|
|
|
|
# adds the format fields to object |
|
11160
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix, CxF3_object_array_reference, hash) |
|
11161
|
|
|
|
|
|
|
# returns: (hash_ref) |
|
11162
|
|
|
|
|
|
|
sub _makeCxF3readops { |
|
11163
|
|
|
|
|
|
|
|
|
11164
|
|
|
|
|
|
|
# get parameters |
|
11165
|
8
|
|
|
8
|
|
27
|
my ($self, $xpc, $ns, $obj, $hash) = @_; |
|
11166
|
|
|
|
|
|
|
|
|
11167
|
|
|
|
|
|
|
# local variables |
|
11168
|
8
|
|
|
|
|
31
|
my (@attr, @tags, %keys, $table, $k, $m, $n, $t, $type, $entry, $ops_hash); |
|
11169
|
8
|
|
|
|
|
0
|
my (@format, @nodes, $node, @data, $name, $colorspec, $start, $inc); |
|
11170
|
|
|
|
|
|
|
|
|
11171
|
|
|
|
|
|
|
# if cc:Object filter parameter provided |
|
11172
|
8
|
50
|
33
|
|
|
28
|
if (defined($hash->{'cc:Object'}) && ref($hash->{'cc:Object'}) eq 'ARRAY') { |
|
11173
|
|
|
|
|
|
|
|
|
11174
|
|
|
|
|
|
|
# for each entry |
|
11175
|
0
|
|
|
|
|
0
|
for (@{$hash->{'cc:Object'}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11176
|
|
|
|
|
|
|
|
|
11177
|
|
|
|
|
|
|
# match type/attribute |
|
11178
|
0
|
|
|
|
|
0
|
m/^([^\s\/]*?)\/?([^\s\/]*)$/; |
|
11179
|
|
|
|
|
|
|
|
|
11180
|
|
|
|
|
|
|
# save matched values |
|
11181
|
0
|
|
|
|
|
0
|
$entry = [$1, $2]; |
|
11182
|
|
|
|
|
|
|
|
|
11183
|
|
|
|
|
|
|
# if a valid attribute (see CxF3_Core.xsd) |
|
11184
|
0
|
0
|
|
|
|
0
|
if ($2 =~ m/^(?:|ObjectType|Name|Id|GUID|\*)$/) { |
|
11185
|
|
|
|
|
|
|
|
|
11186
|
|
|
|
|
|
|
# push on array |
|
11187
|
0
|
|
|
|
|
0
|
push(@attr, $entry); |
|
11188
|
|
|
|
|
|
|
|
|
11189
|
|
|
|
|
|
|
} else { |
|
11190
|
|
|
|
|
|
|
|
|
11191
|
|
|
|
|
|
|
# print warning |
|
11192
|
0
|
|
|
|
|
0
|
warn('invalid cc:Object attribute'); |
|
11193
|
|
|
|
|
|
|
|
|
11194
|
|
|
|
|
|
|
} |
|
11195
|
|
|
|
|
|
|
|
|
11196
|
|
|
|
|
|
|
} |
|
11197
|
|
|
|
|
|
|
|
|
11198
|
|
|
|
|
|
|
} |
|
11199
|
|
|
|
|
|
|
|
|
11200
|
|
|
|
|
|
|
# if cc:Tag filter parameter provided |
|
11201
|
8
|
50
|
33
|
|
|
33
|
if (defined($hash->{'cc:Tag'}) && ref($hash->{'cc:Tag'}) eq 'ARRAY') { |
|
11202
|
|
|
|
|
|
|
|
|
11203
|
|
|
|
|
|
|
# for each entry |
|
11204
|
0
|
|
|
|
|
0
|
for (@{$hash->{'cc:Tag'}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11205
|
|
|
|
|
|
|
|
|
11206
|
|
|
|
|
|
|
# match type/key |
|
11207
|
0
|
|
|
|
|
0
|
m/^([^\s\/]*?)\/?([^\s\/]*)$/; |
|
11208
|
|
|
|
|
|
|
|
|
11209
|
|
|
|
|
|
|
# push on array |
|
11210
|
0
|
|
|
|
|
0
|
push(@tags, [$1, $2]); |
|
11211
|
|
|
|
|
|
|
|
|
11212
|
|
|
|
|
|
|
} |
|
11213
|
|
|
|
|
|
|
|
|
11214
|
|
|
|
|
|
|
} |
|
11215
|
|
|
|
|
|
|
|
|
11216
|
|
|
|
|
|
|
# make hash for sort order of certain keys |
|
11217
|
8
|
|
|
|
|
39
|
%keys = ('SampleID' => -2, 'SampleName' => -1, 'Id' => -2, 'Name' => -1); |
|
11218
|
|
|
|
|
|
|
|
|
11219
|
|
|
|
|
|
|
# table [data_class, CxF3_main_path, [CxF3_sub_paths], [CGATS/ASCII field names]] |
|
11220
|
|
|
|
|
|
|
# some mappings have no sub-paths, which is indicated by an empty sub_path array |
|
11221
|
|
|
|
|
|
|
# the 'NCLR', 'SPECTRAL' and 'DENSITY' data classes are special cases |
|
11222
|
8
|
|
|
|
|
412
|
$table = [ |
|
11223
|
|
|
|
|
|
|
['RGB', "${ns}DeviceColorValues/${ns}ColorRGB", ["${ns}R", "${ns}G", "${ns}B"], [qw(RGB_R RGB_G RGB_B)]], |
|
11224
|
|
|
|
|
|
|
['CMYK', "${ns}DeviceColorValues/${ns}ColorCMYK", ["${ns}Cyan", "${ns}Magenta", "${ns}Yellow", "${ns}Black"], [qw(CMYK_C CMYK_M CMYK_Y CMYK_K)]], |
|
11225
|
|
|
|
|
|
|
['NCLR', "${ns}DeviceColorValues/${ns}ColorCMYKPlusN", ["${ns}Cyan", "${ns}Magenta", "${ns}Yellow", "${ns}Black"], [qw(nCLR)]], |
|
11226
|
|
|
|
|
|
|
['SPECTRAL', "${ns}ColorValues/${ns}ReflectanceSpectrum", [], [qw(nm)]], |
|
11227
|
|
|
|
|
|
|
['DENSITY', "${ns}ColorValues/${ns}ColorDensity/${ns}Density", [], [qw(D_RED D_GREEN D_BLUE D_VIS)]], |
|
11228
|
|
|
|
|
|
|
['XYZ', "${ns}ColorValues/${ns}ColorCIEXYZ", ["${ns}X", "${ns}Y", "${ns}Z"], [qw(XYZ_X XYZ_Y XYZ_Z)]], |
|
11229
|
|
|
|
|
|
|
['XYY', "${ns}ColorValues/${ns}ColorCIExyY", ["${ns}x", "${ns}y", "${ns}Y"], [qw(XYY_X XYY_Y XYY_YCAP)]], |
|
11230
|
|
|
|
|
|
|
['LAB', "${ns}ColorValues/${ns}ColorCIELab", ["${ns}L", "${ns}A", "${ns}B"], [qw(LAB_L LAB_A LAB_B)]], |
|
11231
|
|
|
|
|
|
|
['LCH', "${ns}ColorValues/${ns}ColorCIELCh", ["${ns}L", "${ns}C", "${ns}H"], [qw(LAB_L LAB_C LAB_H)]], |
|
11232
|
|
|
|
|
|
|
['SRGB', "${ns}ColorValues/${ns}ColorSRGB", ["${ns}R", "${ns}G", "${ns}B"], [qw(SRGB_R SRGB_G SRGB_B)]], |
|
11233
|
|
|
|
|
|
|
['DE', "${ns}ColorDifferenceValues/${ns}DeltaCIELab/${ns}dE", [], [qw(LAB_DE)]], |
|
11234
|
|
|
|
|
|
|
['DE94', "${ns}ColorDifferenceValues/${ns}DeltaCIELab/${ns}dE94", [], [qw(LAB_DE94)]], |
|
11235
|
|
|
|
|
|
|
['DECMC', "${ns}ColorDifferenceValues/${ns}DeltaCIELab/${ns}dEcmc", [], [qw(LAB_CMC)]], |
|
11236
|
|
|
|
|
|
|
['DE2000', "${ns}ColorDifferenceValues/${ns}DeltaCIELab/${ns}dE2000", [], [qw(LAB_2000)]], |
|
11237
|
|
|
|
|
|
|
]; |
|
11238
|
|
|
|
|
|
|
|
|
11239
|
|
|
|
|
|
|
# set next table index |
|
11240
|
8
|
|
|
|
|
38
|
$m = $#{$table} + 1; |
|
|
8
|
|
|
|
|
17
|
|
|
11241
|
|
|
|
|
|
|
|
|
11242
|
|
|
|
|
|
|
# for each CxF3 'Object' |
|
11243
|
8
|
|
|
|
|
10
|
for my $s (@{$obj}) { |
|
|
8
|
|
|
|
|
17
|
|
|
11244
|
|
|
|
|
|
|
|
|
11245
|
|
|
|
|
|
|
# get the ObjectType attribute |
|
11246
|
160
|
|
|
|
|
302
|
$type = $s->getAttribute('ObjectType'); |
|
11247
|
|
|
|
|
|
|
|
|
11248
|
|
|
|
|
|
|
# get the Name attribute |
|
11249
|
160
|
|
|
|
|
1152
|
$name = $s->getAttribute('Name'); |
|
11250
|
|
|
|
|
|
|
|
|
11251
|
|
|
|
|
|
|
# if 'ObjectType' not in hash |
|
11252
|
160
|
100
|
|
|
|
1105
|
if (! defined($ops_hash->{$type})) { |
|
11253
|
|
|
|
|
|
|
|
|
11254
|
|
|
|
|
|
|
# add 'ObjectType' to hash |
|
11255
|
16
|
|
|
|
|
48
|
$ops_hash->{$type} = []; |
|
11256
|
|
|
|
|
|
|
|
|
11257
|
|
|
|
|
|
|
# if 'Object' attributes are mapped |
|
11258
|
16
|
50
|
|
|
|
40
|
if (@attr) { |
|
11259
|
|
|
|
|
|
|
|
|
11260
|
|
|
|
|
|
|
# for each 'Object' attribute (GUID is optional) |
|
11261
|
0
|
|
|
|
|
0
|
for my $t (qw(ObjectType Name Id GUID)) { |
|
11262
|
|
|
|
|
|
|
|
|
11263
|
|
|
|
|
|
|
# if attribute exists and is mapped |
|
11264
|
0
|
0
|
0
|
|
|
0
|
if ($xpc->exists("\@$t", $s) && grep {($_->[0] eq $type || $_->[0] =~ m/^\*?$/) && ($_->[1] eq $t || $_->[1] =~ m/^\*?$/)} @attr) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
|
|
0
|
|
|
|
|
|
11265
|
|
|
|
|
|
|
|
|
11266
|
|
|
|
|
|
|
# get sort order |
|
11267
|
0
|
0
|
|
|
|
0
|
$k = defined($keys{$t}) ? $keys{$t} : $m++; |
|
11268
|
|
|
|
|
|
|
|
|
11269
|
|
|
|
|
|
|
# push table entry on hash array (note: attribute XPaths begin with @) |
|
11270
|
0
|
|
|
|
|
0
|
push(@{$ops_hash->{$type}}, $entry = ["ATTR:$t", "\@$t", [], [$t], $type, $k]); |
|
|
0
|
|
|
|
|
0
|
|
|
11271
|
|
|
|
|
|
|
|
|
11272
|
|
|
|
|
|
|
# push table entry on format array |
|
11273
|
0
|
|
|
|
|
0
|
push(@format, $entry); |
|
11274
|
|
|
|
|
|
|
|
|
11275
|
|
|
|
|
|
|
} |
|
11276
|
|
|
|
|
|
|
|
|
11277
|
|
|
|
|
|
|
} |
|
11278
|
|
|
|
|
|
|
|
|
11279
|
|
|
|
|
|
|
} else { |
|
11280
|
|
|
|
|
|
|
|
|
11281
|
|
|
|
|
|
|
# if Name is not ObjectType with appended number, and type is not 'Measurement' |
|
11282
|
16
|
50
|
33
|
|
|
388
|
if ($name !~ m/^$type(\d+)/ && $type ne 'Measurement') { |
|
11283
|
|
|
|
|
|
|
|
|
11284
|
|
|
|
|
|
|
# push table entry on hash array (note: attribute XPaths begin with @) |
|
11285
|
0
|
|
|
|
|
0
|
push(@{$ops_hash->{$type}}, $entry = ['NAME', '@Name', [], ['SAMPLE_NAME'], $type, -1]); |
|
|
0
|
|
|
|
|
0
|
|
|
11286
|
|
|
|
|
|
|
|
|
11287
|
|
|
|
|
|
|
# push table entry on format array |
|
11288
|
0
|
|
|
|
|
0
|
push(@format, $entry); |
|
11289
|
|
|
|
|
|
|
|
|
11290
|
|
|
|
|
|
|
} |
|
11291
|
|
|
|
|
|
|
|
|
11292
|
|
|
|
|
|
|
} |
|
11293
|
|
|
|
|
|
|
|
|
11294
|
|
|
|
|
|
|
# for each table entry |
|
11295
|
16
|
|
|
|
|
28
|
for my $i (0 .. $#{$table}) { |
|
|
16
|
|
|
|
|
45
|
|
|
11296
|
|
|
|
|
|
|
|
|
11297
|
|
|
|
|
|
|
# get table entry |
|
11298
|
224
|
|
|
|
|
4878
|
$t = $table->[$i]; |
|
11299
|
|
|
|
|
|
|
|
|
11300
|
|
|
|
|
|
|
# if main XPath exists |
|
11301
|
224
|
100
|
|
|
|
379
|
if ($xpc->exists($t->[1], $s)) { |
|
11302
|
|
|
|
|
|
|
|
|
11303
|
|
|
|
|
|
|
# get ColorSpecification attribute (if any) |
|
11304
|
16
|
|
|
|
|
451
|
$colorspec = $xpc->findvalue("$t->[1]/\@ColorSpecification", $s); |
|
11305
|
|
|
|
|
|
|
|
|
11306
|
|
|
|
|
|
|
# push table entry on hash array |
|
11307
|
16
|
|
|
|
|
1069
|
push(@{$ops_hash->{$type}}, $entry = [@{$t}, $type, $i, $colorspec]); |
|
|
16
|
|
|
|
|
49
|
|
|
|
16
|
|
|
|
|
44
|
|
|
11308
|
|
|
|
|
|
|
|
|
11309
|
|
|
|
|
|
|
# push table entry on format array |
|
11310
|
16
|
|
|
|
|
29
|
push(@format, $entry); |
|
11311
|
|
|
|
|
|
|
|
|
11312
|
|
|
|
|
|
|
# if an 'NCLR' entry |
|
11313
|
16
|
100
|
|
|
|
59
|
if ($entry->[0] eq 'NCLR') { |
|
|
|
100
|
|
|
|
|
|
|
11314
|
|
|
|
|
|
|
|
|
11315
|
|
|
|
|
|
|
# get cc:SpotColor nodes |
|
11316
|
2
|
|
|
|
|
9
|
@nodes = $xpc->findnodes(".//${ns}SpotColor", $s); |
|
11317
|
|
|
|
|
|
|
|
|
11318
|
|
|
|
|
|
|
# get number of colors |
|
11319
|
2
|
|
|
|
|
74
|
$n = @nodes + 4; |
|
11320
|
|
|
|
|
|
|
|
|
11321
|
|
|
|
|
|
|
# add format fields |
|
11322
|
2
|
|
|
|
|
7
|
$entry->[3] = [map {sprintf('%xCLR_%x', $n, $_)} (1 .. $n)]; |
|
|
12
|
|
|
|
|
35
|
|
|
11323
|
|
|
|
|
|
|
|
|
11324
|
|
|
|
|
|
|
# if a 'SPECTRAL' entry |
|
11325
|
|
|
|
|
|
|
} elsif ($entry->[0] eq 'SPECTRAL') { |
|
11326
|
|
|
|
|
|
|
|
|
11327
|
|
|
|
|
|
|
# get the ReflectanceSpectrum data |
|
11328
|
6
|
|
|
|
|
18
|
@data = split(' ', $xpc->findvalue($t->[1], $s)); |
|
11329
|
|
|
|
|
|
|
|
|
11330
|
|
|
|
|
|
|
# get the ColorSpecification node (linked by the ColorSpecification attribute) |
|
11331
|
6
|
|
|
|
|
359
|
($node) = $xpc->findnodes("${ns}Resources/${ns}ColorSpecificationCollection/${ns}ColorSpecification[\@Id='$colorspec']"); |
|
11332
|
|
|
|
|
|
|
|
|
11333
|
|
|
|
|
|
|
# get the StartWL attribute |
|
11334
|
6
|
|
|
|
|
292
|
$start = $xpc->findvalue("${ns}MeasurementSpec/${ns}WavelengthRange/\@StartWL", $node); |
|
11335
|
|
|
|
|
|
|
|
|
11336
|
|
|
|
|
|
|
# get the Increment attribute |
|
11337
|
6
|
|
|
|
|
319
|
$inc = $xpc->findvalue("${ns}MeasurementSpec/${ns}WavelengthRange/\@Increment", $node); |
|
11338
|
|
|
|
|
|
|
|
|
11339
|
|
|
|
|
|
|
# add format fields |
|
11340
|
6
|
|
|
|
|
298
|
$entry->[3] = [map {'nm' . ($start + $_ * $inc)} (0 .. $#data)]; |
|
|
216
|
|
|
|
|
341
|
|
|
11341
|
|
|
|
|
|
|
|
|
11342
|
|
|
|
|
|
|
} |
|
11343
|
|
|
|
|
|
|
|
|
11344
|
|
|
|
|
|
|
} |
|
11345
|
|
|
|
|
|
|
|
|
11346
|
|
|
|
|
|
|
} |
|
11347
|
|
|
|
|
|
|
|
|
11348
|
|
|
|
|
|
|
# if Tags are mapped |
|
11349
|
16
|
50
|
|
|
|
438
|
if (@tags) { |
|
11350
|
|
|
|
|
|
|
|
|
11351
|
|
|
|
|
|
|
# for each Tag |
|
11352
|
0
|
|
|
|
|
0
|
for my $t ($xpc->findnodes("${ns}TagCollection/${ns}Tag", $s)) { |
|
11353
|
|
|
|
|
|
|
|
|
11354
|
|
|
|
|
|
|
# get Tag Name attribute |
|
11355
|
0
|
|
|
|
|
0
|
$name = $t->getAttribute('Name'); |
|
11356
|
|
|
|
|
|
|
|
|
11357
|
|
|
|
|
|
|
# if this Tag is mapped |
|
11358
|
0
|
0
|
0
|
|
|
0
|
if (grep {($_->[0] eq $type || $_->[0] =~ m/^\*?$/) && ($_->[1] eq $name || $_->[1] =~ m/^\*?$/)} @tags) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
11359
|
|
|
|
|
|
|
|
|
11360
|
|
|
|
|
|
|
# get sort order |
|
11361
|
0
|
0
|
|
|
|
0
|
$k = defined($keys{$name}) ? $keys{$name} : $m++; |
|
11362
|
|
|
|
|
|
|
|
|
11363
|
|
|
|
|
|
|
# push table entry on hash array (note: attribute XPaths begin with @) |
|
11364
|
0
|
|
|
|
|
0
|
push(@{$ops_hash->{$type}}, $entry = ["TAG:$name", "${ns}TagCollection/${ns}Tag[\@Name = '$name']/\@Value", [], [$name], $type, $k]); |
|
|
0
|
|
|
|
|
0
|
|
|
11365
|
|
|
|
|
|
|
|
|
11366
|
|
|
|
|
|
|
# push table entry on format array |
|
11367
|
0
|
|
|
|
|
0
|
push(@format, $entry); |
|
11368
|
|
|
|
|
|
|
|
|
11369
|
|
|
|
|
|
|
} |
|
11370
|
|
|
|
|
|
|
|
|
11371
|
|
|
|
|
|
|
} |
|
11372
|
|
|
|
|
|
|
|
|
11373
|
|
|
|
|
|
|
} |
|
11374
|
|
|
|
|
|
|
|
|
11375
|
|
|
|
|
|
|
} |
|
11376
|
|
|
|
|
|
|
|
|
11377
|
|
|
|
|
|
|
} |
|
11378
|
|
|
|
|
|
|
|
|
11379
|
|
|
|
|
|
|
# sort format array by table index |
|
11380
|
8
|
|
|
|
|
43
|
@format = sort {$a->[5] <=> $b->[5]} @format; |
|
|
8
|
|
|
|
|
37
|
|
|
11381
|
|
|
|
|
|
|
|
|
11382
|
|
|
|
|
|
|
# for each format entry |
|
11383
|
8
|
|
|
|
|
17
|
for my $fmt (@format) { |
|
11384
|
|
|
|
|
|
|
|
|
11385
|
|
|
|
|
|
|
# add format fields to data array and replace keys with column indices |
|
11386
|
16
|
|
|
|
|
23
|
$fmt->[3] = add_fmt($self, map {"$fmt->[4]|$_"} @{$fmt->[3]}); |
|
|
256
|
|
|
|
|
484
|
|
|
|
16
|
|
|
|
|
27
|
|
|
11387
|
|
|
|
|
|
|
|
|
11388
|
|
|
|
|
|
|
# if entry has ColorSpecification |
|
11389
|
16
|
50
|
|
|
|
62
|
if (defined($fmt->[6])) { |
|
11390
|
|
|
|
|
|
|
|
|
11391
|
|
|
|
|
|
|
# add ColorSpecification attribute to colorimetry array |
|
11392
|
16
|
|
|
|
|
25
|
for (@{$fmt->[3]}) {$self->[2][5][$_] = $fmt->[6]} |
|
|
16
|
|
|
|
|
27
|
|
|
|
256
|
|
|
|
|
364
|
|
|
11393
|
|
|
|
|
|
|
|
|
11394
|
|
|
|
|
|
|
} |
|
11395
|
|
|
|
|
|
|
|
|
11396
|
|
|
|
|
|
|
} |
|
11397
|
|
|
|
|
|
|
|
|
11398
|
|
|
|
|
|
|
# return |
|
11399
|
8
|
|
|
|
|
92
|
return($ops_hash); |
|
11400
|
|
|
|
|
|
|
|
|
11401
|
|
|
|
|
|
|
} |
|
11402
|
|
|
|
|
|
|
|
|
11403
|
|
|
|
|
|
|
# read CxF3 FileInformation nodes |
|
11404
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix) |
|
11405
|
|
|
|
|
|
|
sub _readCxF3fileinfo { |
|
11406
|
|
|
|
|
|
|
|
|
11407
|
|
|
|
|
|
|
# get parameters |
|
11408
|
8
|
|
|
8
|
|
17
|
my ($self, $xpc, $ns) = @_; |
|
11409
|
|
|
|
|
|
|
|
|
11410
|
|
|
|
|
|
|
# local variables |
|
11411
|
8
|
|
|
|
|
18
|
my (@info, %keys, $name, $value); |
|
11412
|
|
|
|
|
|
|
|
|
11413
|
|
|
|
|
|
|
# get cc:FileInformation nodes (optional) |
|
11414
|
8
|
|
|
|
|
41
|
@info = $xpc->findnodes("${ns}FileInformation/*"); |
|
11415
|
|
|
|
|
|
|
|
|
11416
|
|
|
|
|
|
|
# make CxF3 => ASCII mapping table (from ISO 17972-1, Annex A) |
|
11417
|
8
|
|
|
|
|
416
|
%keys = ('Creator' => 'ORIGINATOR', 'Description' => 'FILE_DESCRIPTOR', 'CreationDate' => 'CREATED', 'Comment' => 'CXF3_COMMENT'); |
|
11418
|
|
|
|
|
|
|
|
|
11419
|
|
|
|
|
|
|
# for each cc:FileInformation element |
|
11420
|
8
|
|
|
|
|
18
|
for my $s (@info) { |
|
11421
|
|
|
|
|
|
|
|
|
11422
|
|
|
|
|
|
|
# if 'Tag' node |
|
11423
|
40
|
100
|
|
|
|
114
|
if ($s->localname() eq 'Tag') { |
|
11424
|
|
|
|
|
|
|
|
|
11425
|
|
|
|
|
|
|
# get name attribute |
|
11426
|
16
|
|
|
|
|
44
|
$name = $s->getAttribute('Name'); |
|
11427
|
|
|
|
|
|
|
|
|
11428
|
|
|
|
|
|
|
# get value attribute |
|
11429
|
16
|
|
|
|
|
140
|
$value = $s->getAttribute('Value'); |
|
11430
|
|
|
|
|
|
|
|
|
11431
|
|
|
|
|
|
|
} else { |
|
11432
|
|
|
|
|
|
|
|
|
11433
|
|
|
|
|
|
|
# get node name (no prefix) |
|
11434
|
24
|
|
|
|
|
47
|
$name = $s->localname(); |
|
11435
|
|
|
|
|
|
|
|
|
11436
|
|
|
|
|
|
|
# lookup name in hash |
|
11437
|
24
|
50
|
|
|
|
59
|
$name = defined($keys{$name}) ? $keys{$name} : $name; |
|
11438
|
|
|
|
|
|
|
|
|
11439
|
|
|
|
|
|
|
# get node value |
|
11440
|
24
|
|
|
|
|
81
|
$value = $s->textContent(); |
|
11441
|
|
|
|
|
|
|
|
|
11442
|
|
|
|
|
|
|
} |
|
11443
|
|
|
|
|
|
|
|
|
11444
|
|
|
|
|
|
|
# add name/value to header array |
|
11445
|
40
|
|
|
|
|
141
|
push(@{$self->[3]}, [$name, "\"$value\"", 'FileInformation']); |
|
|
40
|
|
|
|
|
150
|
|
|
11446
|
|
|
|
|
|
|
|
|
11447
|
|
|
|
|
|
|
} |
|
11448
|
|
|
|
|
|
|
|
|
11449
|
|
|
|
|
|
|
} |
|
11450
|
|
|
|
|
|
|
|
|
11451
|
|
|
|
|
|
|
# read CxF3 ColorSpecification nodes |
|
11452
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix) |
|
11453
|
|
|
|
|
|
|
sub _readCxF3colorspec { |
|
11454
|
|
|
|
|
|
|
|
|
11455
|
|
|
|
|
|
|
# get parameters |
|
11456
|
8
|
|
|
8
|
|
19
|
my ($self, $xpc, $ns) = @_; |
|
11457
|
|
|
|
|
|
|
|
|
11458
|
|
|
|
|
|
|
# local variables |
|
11459
|
8
|
|
|
|
|
25
|
my (@keys, @cspec, $id, $node, $child, $value); |
|
11460
|
|
|
|
|
|
|
|
|
11461
|
|
|
|
|
|
|
# make CxF3 => ASCII mapping table (from ISO 17972-1, Annex A) |
|
11462
|
8
|
|
|
|
|
216
|
@keys = ( |
|
11463
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}GeometryChoice" => 'MEASUREMENT_GEOMETRY'], |
|
11464
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}CalibrationStandard" => 'DEVCALSTD'], |
|
11465
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}Manufacturer" => 'MANUFACTURER'], |
|
11466
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}Model" => 'MODEL'], |
|
11467
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}SerialNumber" => 'SERIAL_NUMBER'], |
|
11468
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}DeviceClass" => 'DEVICE_CLASS'], |
|
11469
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}DeviceFilter" => 'FILTER'], |
|
11470
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}DeviceIllumination" => 'MEASUREMENT_SOURCE'], |
|
11471
|
|
|
|
|
|
|
["${ns}MeasurementSpec/${ns}Device/${ns}DevicePolarization" => 'POLARIZATION'], |
|
11472
|
|
|
|
|
|
|
); |
|
11473
|
|
|
|
|
|
|
|
|
11474
|
|
|
|
|
|
|
# find the ColorSpecification nodes |
|
11475
|
8
|
|
|
|
|
52
|
@cspec = $xpc->findnodes("${ns}Resources/${ns}ColorSpecificationCollection/${ns}ColorSpecification"); |
|
11476
|
|
|
|
|
|
|
|
|
11477
|
|
|
|
|
|
|
# for each ColorSpecification node |
|
11478
|
8
|
|
|
|
|
243
|
for my $s (@cspec) { |
|
11479
|
|
|
|
|
|
|
|
|
11480
|
|
|
|
|
|
|
# get the Id attribute and skip if 'Unknown' |
|
11481
|
16
|
100
|
|
|
|
311
|
next if (($id = $s->getAttribute('Id')) eq 'Unknown'); |
|
11482
|
|
|
|
|
|
|
|
|
11483
|
|
|
|
|
|
|
# for each entry in mapping table |
|
11484
|
8
|
|
|
|
|
92
|
for my $i (0 .. $#keys) { |
|
11485
|
|
|
|
|
|
|
|
|
11486
|
|
|
|
|
|
|
# if XPath is found |
|
11487
|
72
|
100
|
|
|
|
1275
|
if (($node) = $xpc->findnodes($keys[$i][0], $s)) { |
|
11488
|
|
|
|
|
|
|
|
|
11489
|
|
|
|
|
|
|
# get the first non-blank child node |
|
11490
|
24
|
50
|
|
|
|
825
|
if (($child) = $node->nonBlankChildNodes()) { |
|
11491
|
|
|
|
|
|
|
|
|
11492
|
|
|
|
|
|
|
# if child is an element node |
|
11493
|
24
|
100
|
|
|
|
347
|
if ($child->nodeType() == 1) { |
|
|
|
50
|
|
|
|
|
|
|
11494
|
|
|
|
|
|
|
|
|
11495
|
|
|
|
|
|
|
# serialize node |
|
11496
|
8
|
|
|
|
|
264
|
$value = $node->toString(1); |
|
11497
|
|
|
|
|
|
|
|
|
11498
|
|
|
|
|
|
|
# remove tabs and endlines |
|
11499
|
8
|
|
|
|
|
118
|
$value =~ s/[\t\n]+//g; |
|
11500
|
|
|
|
|
|
|
|
|
11501
|
|
|
|
|
|
|
# remove namespace prefix |
|
11502
|
8
|
|
|
|
|
169
|
$value =~ s/([<\/])${ns}/$1/g; |
|
11503
|
|
|
|
|
|
|
|
|
11504
|
|
|
|
|
|
|
# if child is a text node |
|
11505
|
|
|
|
|
|
|
} elsif ($child->nodeType() == 3) { |
|
11506
|
|
|
|
|
|
|
|
|
11507
|
|
|
|
|
|
|
# get the value |
|
11508
|
16
|
|
|
|
|
59
|
$value = $node->textContent(); |
|
11509
|
|
|
|
|
|
|
|
|
11510
|
|
|
|
|
|
|
} |
|
11511
|
|
|
|
|
|
|
|
|
11512
|
|
|
|
|
|
|
# save in header line array |
|
11513
|
24
|
|
|
|
|
37
|
push(@{$self->[3]}, [$keys[$i][1], "\"$value\"", $id]); |
|
|
24
|
|
|
|
|
107
|
|
|
11514
|
|
|
|
|
|
|
|
|
11515
|
|
|
|
|
|
|
} |
|
11516
|
|
|
|
|
|
|
|
|
11517
|
|
|
|
|
|
|
} |
|
11518
|
|
|
|
|
|
|
|
|
11519
|
|
|
|
|
|
|
} |
|
11520
|
|
|
|
|
|
|
|
|
11521
|
|
|
|
|
|
|
} |
|
11522
|
|
|
|
|
|
|
|
|
11523
|
|
|
|
|
|
|
} |
|
11524
|
|
|
|
|
|
|
|
|
11525
|
|
|
|
|
|
|
# read CxF3 CustomResources nodes |
|
11526
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix, root_namespace_array_reference) |
|
11527
|
|
|
|
|
|
|
sub _readCxF3customres { |
|
11528
|
|
|
|
|
|
|
|
|
11529
|
|
|
|
|
|
|
# get parameters |
|
11530
|
8
|
|
|
8
|
|
21
|
my ($self, $xpc, $ns, $rns) = @_; |
|
11531
|
|
|
|
|
|
|
|
|
11532
|
|
|
|
|
|
|
# local variables |
|
11533
|
8
|
|
|
|
|
23
|
my (@crnodes, $name, $cr, @crns, $nsobj, $uri, $nsd); |
|
11534
|
8
|
|
|
|
|
0
|
my (@nodes, @nodes2, @attr, $bg, $tint, $objref, $rsnr); |
|
11535
|
|
|
|
|
|
|
|
|
11536
|
|
|
|
|
|
|
# initialize default namespace prefix |
|
11537
|
8
|
|
|
|
|
13
|
$nsd = 'ns00'; |
|
11538
|
|
|
|
|
|
|
|
|
11539
|
|
|
|
|
|
|
# find the CustomResources nodes |
|
11540
|
8
|
|
|
|
|
27
|
@crnodes = $xpc->findnodes("${ns}CustomResources/*"); |
|
11541
|
|
|
|
|
|
|
|
|
11542
|
|
|
|
|
|
|
# for each CustomResources node |
|
11543
|
8
|
|
|
|
|
206
|
for my $s (@crnodes) { |
|
11544
|
|
|
|
|
|
|
|
|
11545
|
|
|
|
|
|
|
# get node properties |
|
11546
|
8
|
|
|
|
|
34
|
$cr = $s->prefix; |
|
11547
|
8
|
|
|
|
|
34
|
@crns = $s->getNamespaces(); |
|
11548
|
|
|
|
|
|
|
|
|
11549
|
|
|
|
|
|
|
# if node has prefix |
|
11550
|
8
|
50
|
|
|
|
21
|
if (defined($cr)) { |
|
11551
|
|
|
|
|
|
|
|
|
11552
|
|
|
|
|
|
|
# find corresponding namespace object |
|
11553
|
8
|
50
|
|
|
|
11
|
($nsobj) = grep {defined($_->declaredPrefix) && $_->declaredPrefix eq $cr} (@crns, @{$rns}); |
|
|
24
|
|
|
|
|
119
|
|
|
|
8
|
|
|
|
|
14
|
|
|
11554
|
|
|
|
|
|
|
|
|
11555
|
|
|
|
|
|
|
} else { |
|
11556
|
|
|
|
|
|
|
|
|
11557
|
|
|
|
|
|
|
# use the default node namespace (no declared prefix) |
|
11558
|
0
|
|
|
|
|
0
|
($nsobj) = grep {! defined($_->declaredPrefix)} @crns; |
|
|
0
|
|
|
|
|
0
|
|
|
11559
|
|
|
|
|
|
|
|
|
11560
|
|
|
|
|
|
|
# make a unique prefix |
|
11561
|
0
|
|
|
|
|
0
|
$cr = $nsd++; |
|
11562
|
|
|
|
|
|
|
|
|
11563
|
|
|
|
|
|
|
} |
|
11564
|
|
|
|
|
|
|
|
|
11565
|
|
|
|
|
|
|
# get node URI |
|
11566
|
8
|
|
|
|
|
21
|
$uri = $nsobj->value; |
|
11567
|
|
|
|
|
|
|
|
|
11568
|
|
|
|
|
|
|
# register custom resource namespace, if necessary |
|
11569
|
8
|
50
|
|
|
|
69
|
$xpc->registerNs($cr, $uri) if (! $xpc->lookupNs($cr)); |
|
11570
|
|
|
|
|
|
|
|
|
11571
|
|
|
|
|
|
|
# append ':' to namespace prefix |
|
11572
|
8
|
|
|
|
|
17
|
$cr .= ':'; |
|
11573
|
|
|
|
|
|
|
|
|
11574
|
|
|
|
|
|
|
# if spot ink characterization (CxF/X4) |
|
11575
|
8
|
50
|
|
|
|
38
|
if ($uri eq 'http://colorexchangeformat.com/CxF3-SpotInkCharacterisation') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
11576
|
|
|
|
|
|
|
|
|
11577
|
|
|
|
|
|
|
# get the attribute list |
|
11578
|
0
|
|
|
|
|
0
|
@attr = $s->attributes(); |
|
11579
|
|
|
|
|
|
|
|
|
11580
|
|
|
|
|
|
|
# add sic:SpotInkCharacterisation hash |
|
11581
|
0
|
|
|
|
|
0
|
$self->[0]{'sic:SpotInkCharacterisation'} = {map {$_->nodeName, $_->getValue()} @attr}; |
|
|
0
|
|
|
|
|
0
|
|
|
11582
|
|
|
|
|
|
|
|
|
11583
|
|
|
|
|
|
|
# get the sic:MeasurementSet nodes |
|
11584
|
0
|
0
|
|
|
|
0
|
if (@nodes = $xpc->findnodes("${cr}MeasurementSet", $s)) { |
|
11585
|
|
|
|
|
|
|
|
|
11586
|
|
|
|
|
|
|
# for each MeasurementSet node |
|
11587
|
0
|
|
|
|
|
0
|
for my $t (@nodes) { |
|
11588
|
|
|
|
|
|
|
|
|
11589
|
|
|
|
|
|
|
# get the Background attribute |
|
11590
|
0
|
|
|
|
|
0
|
($bg) = grep {$_->name eq 'Background'} $t->attributes(); |
|
|
0
|
|
|
|
|
0
|
|
|
11591
|
|
|
|
|
|
|
|
|
11592
|
|
|
|
|
|
|
# get Measurement nodes |
|
11593
|
0
|
|
|
|
|
0
|
@nodes2 = $xpc->findnodes("${cr}Measurement", $t); |
|
11594
|
|
|
|
|
|
|
|
|
11595
|
|
|
|
|
|
|
# for each Measurement node |
|
11596
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#nodes2) { |
|
11597
|
|
|
|
|
|
|
|
|
11598
|
|
|
|
|
|
|
# get Measurement node attributes |
|
11599
|
0
|
|
|
|
|
0
|
@attr = $nodes2[$i]->attributes(); |
|
11600
|
|
|
|
|
|
|
|
|
11601
|
|
|
|
|
|
|
# get the attribute list |
|
11602
|
0
|
|
|
|
|
0
|
@attr = $nodes2[$i]->attributes(); |
|
11603
|
|
|
|
|
|
|
|
|
11604
|
|
|
|
|
|
|
# add Measurement hash |
|
11605
|
0
|
|
|
|
|
0
|
$self->[0]{'sic:MeasurementSet'}{$bg->value}[$i] = {map {$_->nodeName, $_->getValue()} @attr}; |
|
|
0
|
|
|
|
|
0
|
|
|
11606
|
|
|
|
|
|
|
|
|
11607
|
|
|
|
|
|
|
} |
|
11608
|
|
|
|
|
|
|
|
|
11609
|
|
|
|
|
|
|
} |
|
11610
|
|
|
|
|
|
|
|
|
11611
|
|
|
|
|
|
|
} |
|
11612
|
|
|
|
|
|
|
|
|
11613
|
|
|
|
|
|
|
# if quality control |
|
11614
|
|
|
|
|
|
|
} elsif ($uri eq 'http://colorexchangeformat.com/CxF3-qualitycontrol') { |
|
11615
|
|
|
|
|
|
|
|
|
11616
|
|
|
|
|
|
|
# to be added someday |
|
11617
|
|
|
|
|
|
|
|
|
11618
|
|
|
|
|
|
|
# if prism (X-Rite i1Profiler) |
|
11619
|
|
|
|
|
|
|
} elsif ($uri = 'http://www.xrite.com/products/prism') { |
|
11620
|
|
|
|
|
|
|
|
|
11621
|
|
|
|
|
|
|
# get the attribute list, excluding namespace |
|
11622
|
8
|
|
|
|
|
28
|
@attr = grep {$_->getValue() ne 'http://www.xrite.com/products/prism'} $s->attributes(); |
|
|
16
|
|
|
|
|
143
|
|
|
11623
|
|
|
|
|
|
|
|
|
11624
|
|
|
|
|
|
|
# add xrp:Prism hash |
|
11625
|
8
|
|
|
|
|
28
|
$self->[0]{'xrp:Prism'} = {map {$_->nodeName, $_->getValue()} @attr}; |
|
|
8
|
|
|
|
|
64
|
|
|
11626
|
|
|
|
|
|
|
|
|
11627
|
|
|
|
|
|
|
# get the xrp:CustomAttributes node |
|
11628
|
8
|
50
|
|
|
|
32
|
if (@nodes = $xpc->findnodes("${cr}CustomAttributes", $s)) { |
|
11629
|
|
|
|
|
|
|
|
|
11630
|
|
|
|
|
|
|
# get the attribute list |
|
11631
|
8
|
|
|
|
|
256
|
@attr = $nodes[0]->attributes(); |
|
11632
|
|
|
|
|
|
|
|
|
11633
|
|
|
|
|
|
|
# add xrp:CustomAttributes hash |
|
11634
|
8
|
|
|
|
|
192
|
$self->[0]{'xrp:CustomAttributes'} = {map {$_->nodeName, $_->getValue()} @attr}; |
|
|
400
|
|
|
|
|
1393
|
|
|
11635
|
|
|
|
|
|
|
|
|
11636
|
|
|
|
|
|
|
} |
|
11637
|
|
|
|
|
|
|
|
|
11638
|
|
|
|
|
|
|
} else { |
|
11639
|
|
|
|
|
|
|
|
|
11640
|
|
|
|
|
|
|
# print message |
|
11641
|
0
|
|
|
|
|
0
|
print "unsupported custom resource '$uri' encountered when reading CxF3 file\n\n"; |
|
11642
|
|
|
|
|
|
|
|
|
11643
|
|
|
|
|
|
|
} |
|
11644
|
|
|
|
|
|
|
|
|
11645
|
|
|
|
|
|
|
} |
|
11646
|
|
|
|
|
|
|
|
|
11647
|
|
|
|
|
|
|
} |
|
11648
|
|
|
|
|
|
|
|
|
11649
|
|
|
|
|
|
|
# clean-up CxF3 contexts |
|
11650
|
|
|
|
|
|
|
# adds measurement condition when object type has none |
|
11651
|
|
|
|
|
|
|
# parameters: (object_reference) |
|
11652
|
|
|
|
|
|
|
sub _readCxF3cleanup { |
|
11653
|
|
|
|
|
|
|
|
|
11654
|
|
|
|
|
|
|
# get parameters |
|
11655
|
8
|
|
|
8
|
|
16
|
my ($self) = @_; |
|
11656
|
|
|
|
|
|
|
|
|
11657
|
|
|
|
|
|
|
# local variables |
|
11658
|
8
|
|
|
|
|
14
|
my ($id, $ms, $cond); |
|
11659
|
|
|
|
|
|
|
|
|
11660
|
|
|
|
|
|
|
# for each data format field |
|
11661
|
8
|
|
|
|
|
12
|
for my $i (0 .. $#{$self->[1][0]}) { |
|
|
8
|
|
|
|
|
27
|
|
|
11662
|
|
|
|
|
|
|
|
|
11663
|
|
|
|
|
|
|
# if context is 'Measurement' |
|
11664
|
256
|
50
|
|
|
|
388
|
if ($self->[1][0][$i] =~ m/^Measurement\|/) { |
|
11665
|
|
|
|
|
|
|
|
|
11666
|
|
|
|
|
|
|
# get ColorSpecification Id for this format field |
|
11667
|
0
|
|
|
|
|
0
|
$id = $self->[2][5][$i]; |
|
11668
|
|
|
|
|
|
|
|
|
11669
|
|
|
|
|
|
|
# if a 'MEASUREMENT_SOURCE' record with this ColorSpecification Id |
|
11670
|
0
|
0
|
|
|
|
0
|
if (($ms) = grep {$_->[0] eq 'MEASUREMENT_SOURCE' && $_->[2] eq $id} @{$self->[3]}) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11671
|
|
|
|
|
|
|
|
|
11672
|
|
|
|
|
|
|
# if measurement source contains an M-value |
|
11673
|
0
|
0
|
|
|
|
0
|
if ($ms->[1] =~ m/(M[0-3])/) { |
|
11674
|
|
|
|
|
|
|
|
|
11675
|
|
|
|
|
|
|
# use matched measurement condition |
|
11676
|
0
|
|
|
|
|
0
|
$cond = $1; |
|
11677
|
|
|
|
|
|
|
|
|
11678
|
|
|
|
|
|
|
} else { |
|
11679
|
|
|
|
|
|
|
|
|
11680
|
|
|
|
|
|
|
# use measurement condition M0 |
|
11681
|
0
|
|
|
|
|
0
|
$cond = 'M0'; |
|
11682
|
|
|
|
|
|
|
|
|
11683
|
|
|
|
|
|
|
} |
|
11684
|
|
|
|
|
|
|
|
|
11685
|
|
|
|
|
|
|
} else { |
|
11686
|
|
|
|
|
|
|
|
|
11687
|
|
|
|
|
|
|
# use measurement condition M0 |
|
11688
|
0
|
|
|
|
|
0
|
$cond = 'M0'; |
|
11689
|
|
|
|
|
|
|
|
|
11690
|
|
|
|
|
|
|
} |
|
11691
|
|
|
|
|
|
|
|
|
11692
|
|
|
|
|
|
|
# prepend data format with measurement condition |
|
11693
|
0
|
|
|
|
|
0
|
$self->[1][0][$i] = "$cond\_$self->[1][0][$i]"; |
|
11694
|
|
|
|
|
|
|
|
|
11695
|
|
|
|
|
|
|
} |
|
11696
|
|
|
|
|
|
|
|
|
11697
|
|
|
|
|
|
|
} |
|
11698
|
|
|
|
|
|
|
|
|
11699
|
|
|
|
|
|
|
} |
|
11700
|
|
|
|
|
|
|
|
|
11701
|
|
|
|
|
|
|
# make CxF3 write operations array |
|
11702
|
|
|
|
|
|
|
# parameters: (object_reference, CxF3_prefix, column_slice) |
|
11703
|
|
|
|
|
|
|
# returns: (array_ref) |
|
11704
|
|
|
|
|
|
|
sub _makeCxF3writeops { |
|
11705
|
|
|
|
|
|
|
|
|
11706
|
|
|
|
|
|
|
# get parameters |
|
11707
|
0
|
|
|
0
|
|
0
|
my ($self, $ns, $cols) = @_; |
|
11708
|
|
|
|
|
|
|
|
|
11709
|
|
|
|
|
|
|
# local variables |
|
11710
|
0
|
|
|
|
|
0
|
my ($n, %keys, $table, $class, $prefix, $key, $ops, $groups, $sort); |
|
11711
|
|
|
|
|
|
|
|
|
11712
|
|
|
|
|
|
|
# if column slice defined |
|
11713
|
0
|
0
|
|
|
|
0
|
if (defined($cols)) { |
|
11714
|
|
|
|
|
|
|
|
|
11715
|
|
|
|
|
|
|
# if column slice an empty array reference |
|
11716
|
0
|
0
|
0
|
|
|
0
|
if (ref($cols) eq 'ARRAY' && @{$cols} == 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
11717
|
|
|
|
|
|
|
|
|
11718
|
|
|
|
|
|
|
# use all columns |
|
11719
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
11720
|
|
|
|
|
|
|
|
|
11721
|
|
|
|
|
|
|
} else { |
|
11722
|
|
|
|
|
|
|
|
|
11723
|
|
|
|
|
|
|
# flatten column slice |
|
11724
|
0
|
|
|
|
|
0
|
$cols = ICC::Shared::flatten($cols); |
|
11725
|
|
|
|
|
|
|
|
|
11726
|
|
|
|
|
|
|
} |
|
11727
|
|
|
|
|
|
|
|
|
11728
|
|
|
|
|
|
|
} else { |
|
11729
|
|
|
|
|
|
|
|
|
11730
|
|
|
|
|
|
|
# use all columns |
|
11731
|
0
|
|
|
|
|
0
|
$cols = [0 .. $#{$self->[1][0]}]; |
|
|
0
|
|
|
|
|
0
|
|
|
11732
|
|
|
|
|
|
|
|
|
11733
|
|
|
|
|
|
|
} |
|
11734
|
|
|
|
|
|
|
|
|
11735
|
|
|
|
|
|
|
# map column slice, converting non-numeric values with 'test' method |
|
11736
|
0
|
0
|
|
|
|
0
|
@{$cols} = map {Scalar::Util::looks_like_number($_) ? $_ : $self->test($_)} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11737
|
|
|
|
|
|
|
|
|
11738
|
|
|
|
|
|
|
# get number of fields |
|
11739
|
0
|
|
|
|
|
0
|
$n = @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
11740
|
|
|
|
|
|
|
|
|
11741
|
|
|
|
|
|
|
# remove undefined keys |
|
11742
|
0
|
|
|
|
|
0
|
@{$cols} = grep {defined($self->[1][0][$_])} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11743
|
|
|
|
|
|
|
|
|
11744
|
|
|
|
|
|
|
# warn if undefined keys |
|
11745
|
0
|
0
|
|
|
|
0
|
($n == @{$cols}) || warn('undefined keys in column slice'); |
|
|
0
|
|
|
|
|
0
|
|
|
11746
|
|
|
|
|
|
|
|
|
11747
|
|
|
|
|
|
|
# get number of fields |
|
11748
|
0
|
|
|
|
|
0
|
$n = @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
11749
|
|
|
|
|
|
|
|
|
11750
|
|
|
|
|
|
|
# remove duplicate keys |
|
11751
|
0
|
|
|
|
|
0
|
@{$cols} = grep {! $keys{$self->[1][0][$_]}++} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11752
|
|
|
|
|
|
|
|
|
11753
|
|
|
|
|
|
|
# warn if duplicate keys |
|
11754
|
0
|
0
|
|
|
|
0
|
($n == @{$cols}) || warn('duplicate keys in column slice'); |
|
|
0
|
|
|
|
|
0
|
|
|
11755
|
|
|
|
|
|
|
|
|
11756
|
|
|
|
|
|
|
# table structure: [data_class, CxF3_main_path, [CxF3_sub_paths], regex, sort_order] |
|
11757
|
|
|
|
|
|
|
# some mappings have no sub-paths, which is indicated by an empty sub_path array |
|
11758
|
|
|
|
|
|
|
# sort_order array contains the last character(s) of the format keys, and is optional |
|
11759
|
|
|
|
|
|
|
# the 'NCLR', 'SPECTRAL' and 'DENSITY' data classes are special cases |
|
11760
|
0
|
|
|
|
|
0
|
$table = [ |
|
11761
|
|
|
|
|
|
|
['RGB', "$ns:DeviceColorValues/$ns:ColorRGB", ["$ns:R", "$ns:G", "$ns:B"], qr/^(?:(.*)\|)?RGB_[RGB]$/, [qw(R G B)]], |
|
11762
|
|
|
|
|
|
|
['CMYK', "$ns:DeviceColorValues/$ns:ColorCMYK", ["$ns:Cyan", "$ns:Magenta", "$ns:Yellow", "$ns:Black"], qr/^(?:(.*)\|)?CMYK_[CMYK]$/, [qw(C M Y K)]], |
|
11763
|
|
|
|
|
|
|
['NCLR', "$ns:DeviceColorValues/$ns:ColorCMYKPlusN", ["$ns:Cyan", "$ns:Magenta", "$ns:Yellow", "$ns:Black"], qr/^(?:(.*)\|)?(?:[2-9A-F]CLR_[1-9A-F]|PC[2-9A-F]_[1-9A-F])$/], |
|
11764
|
|
|
|
|
|
|
['SPECTRAL', "$ns:ColorValues/$ns:ReflectanceSpectrum", [], qr/^(?:(.*)\|)?(?:nm|SPECTRAL_NM_|SPECTRAL_NM|SPECTRAL_|NM_|R_)\d{3}$/], |
|
11765
|
|
|
|
|
|
|
['DENSITY', "$ns:ColorValues/$ns:ColorDensity/$ns:Density", [], qr/^(?:(.*)\|)?D_(?:RED|GREEN|BLUE|VIS)$/, [qw(RED GREEN BLUE VIS)]], |
|
11766
|
|
|
|
|
|
|
['XYZ', "$ns:ColorValues/$ns:ColorCIEXYZ", ["$ns:X", "$ns:Y", "$ns:Z"], qr/^(?:(.*)\|)?XYZ_[XYZ]$/, [qw(X Y Z)]], |
|
11767
|
|
|
|
|
|
|
['XYY', "$ns:ColorValues/$ns:ColorCIExyY", ["$ns:x", "$ns:y", "$ns:Y"], qr/^(?:(.*)\|)?XYY_(?:X|Y|CAPY)$/, [qw(_X _Y _CAPY)]], |
|
11768
|
|
|
|
|
|
|
['LAB', "$ns:ColorValues/$ns:ColorCIELab", ["$ns:L", "$ns:A", "$ns:B"], qr/^(?:(.*)\|)?LAB_[LAB]$/, [qw(L A B)]], |
|
11769
|
|
|
|
|
|
|
['LCH', "$ns:ColorValues/$ns:ColorCIELCh", ["$ns:L", "$ns:C", "$ns:H"], qr/^(?:(.*)\|)?LAB_[LCH]$/, [qw(L C H)]], |
|
11770
|
|
|
|
|
|
|
['SRGB', "$ns:ColorValues/$ns:ColorSRGB", ["$ns:R", "$ns:G", "$ns:B"], qr/^(?:(.*)\|)?SRGB_[RGB]$/, [qw(R G B)]], |
|
11771
|
|
|
|
|
|
|
['DE', "$ns:ColorDifferenceValues/$ns:DeltaCIELab/$ns:dE", [], qr/^(?:(.*)\|)?LAB_DE$/], |
|
11772
|
|
|
|
|
|
|
['DE94', "$ns:ColorDifferenceValues/$ns:DeltaCIELab/$ns:dE94", [], qr/^(?:(.*)\|)?LAB_DE94$/], |
|
11773
|
|
|
|
|
|
|
['DECMC', "$ns:ColorDifferenceValues/$ns:DeltaCIELab/$ns:dEcmc", [], qr/^(?:(.*)\|)?LAB_CMC$/], |
|
11774
|
|
|
|
|
|
|
['DE2000', "$ns:ColorDifferenceValues/$ns:DeltaCIELab/$ns:dE2000", [], qr/^(?:(.*)\|)?LAB_2000$/], |
|
11775
|
|
|
|
|
|
|
]; |
|
11776
|
|
|
|
|
|
|
|
|
11777
|
|
|
|
|
|
|
# following section builds operations array from column slice |
|
11778
|
|
|
|
|
|
|
# |
|
11779
|
|
|
|
|
|
|
# sort keys alphabetically |
|
11780
|
0
|
|
|
|
|
0
|
@{$cols} = sort {$self->[1][0][$a] cmp $self->[1][0][$b]} @{$cols}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11781
|
|
|
|
|
|
|
|
|
11782
|
|
|
|
|
|
|
# for each field |
|
11783
|
0
|
|
|
|
|
0
|
for my $i (@{$cols}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11784
|
|
|
|
|
|
|
|
|
11785
|
|
|
|
|
|
|
# if key matches current class and prefix (prefix could be undefined) |
|
11786
|
0
|
0
|
0
|
|
|
0
|
if (defined($class) && $self->[1][0][$i] =~ /$table->[$class][3]/ && (defined($prefix) ? $prefix : "\n") eq (defined($1) ? $1 : "\n")) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
11787
|
|
|
|
|
|
|
|
|
11788
|
|
|
|
|
|
|
# add index to current operation |
|
11789
|
0
|
|
|
|
|
0
|
push(@{$ops->[-1][4]}, $i); |
|
|
0
|
|
|
|
|
0
|
|
|
11790
|
|
|
|
|
|
|
|
|
11791
|
|
|
|
|
|
|
} else { |
|
11792
|
|
|
|
|
|
|
|
|
11793
|
|
|
|
|
|
|
# for each data class |
|
11794
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$table}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11795
|
|
|
|
|
|
|
|
|
11796
|
|
|
|
|
|
|
# if key matches class |
|
11797
|
0
|
0
|
|
|
|
0
|
if ($self->[1][0][$i] =~ /$table->[$j][3]/) { |
|
|
|
0
|
|
|
|
|
|
|
11798
|
|
|
|
|
|
|
|
|
11799
|
|
|
|
|
|
|
# save current prefix |
|
11800
|
0
|
|
|
|
|
0
|
$prefix = $1; |
|
11801
|
|
|
|
|
|
|
|
|
11802
|
|
|
|
|
|
|
# save current class |
|
11803
|
0
|
|
|
|
|
0
|
$class = $j; |
|
11804
|
|
|
|
|
|
|
|
|
11805
|
|
|
|
|
|
|
# add new operation |
|
11806
|
0
|
|
|
|
|
0
|
push(@{$ops}, [$table->[$j][0], $prefix, $table->[$j][1], $table->[$j][2], [$i], {}, $j]); |
|
|
0
|
|
|
|
|
0
|
|
|
11807
|
|
|
|
|
|
|
|
|
11808
|
|
|
|
|
|
|
# quit loop |
|
11809
|
0
|
|
|
|
|
0
|
last; |
|
11810
|
|
|
|
|
|
|
|
|
11811
|
|
|
|
|
|
|
# if no match found in table |
|
11812
|
0
|
|
|
|
|
0
|
} elsif ($j == $#{$table}) { |
|
11813
|
|
|
|
|
|
|
|
|
11814
|
|
|
|
|
|
|
# match prefix/key |
|
11815
|
0
|
|
|
|
|
0
|
$self->[1][0][$i] =~ m/^(?:(.*)\|)?(.*)/; |
|
11816
|
|
|
|
|
|
|
|
|
11817
|
|
|
|
|
|
|
# save matched values |
|
11818
|
0
|
|
|
|
|
0
|
$prefix = $1; |
|
11819
|
0
|
|
|
|
|
0
|
$key = $2; |
|
11820
|
|
|
|
|
|
|
|
|
11821
|
|
|
|
|
|
|
# set current class |
|
11822
|
0
|
|
|
|
|
0
|
$class = undef; |
|
11823
|
|
|
|
|
|
|
|
|
11824
|
|
|
|
|
|
|
# if prefix defined, and not Target or ...Measurement, and key is SAMPLE_NAME |
|
11825
|
0
|
0
|
0
|
|
|
0
|
if (defined($prefix) && $prefix !~ m/^Target$|Measurement$/ && $key =~ m/^SAMPLE_NAME$|^SampleName$/) { |
|
|
|
|
0
|
|
|
|
|
|
11826
|
|
|
|
|
|
|
|
|
11827
|
|
|
|
|
|
|
# add special operation to set 'Object' 'Name' attribute to SAMPLE_NAME |
|
11828
|
0
|
|
|
|
|
0
|
push(@{$ops}, ['TAG', $prefix, '', [], [], {'Name' => [$i]}, -1]); |
|
|
0
|
|
|
|
|
0
|
|
|
11829
|
|
|
|
|
|
|
|
|
11830
|
|
|
|
|
|
|
} else { |
|
11831
|
|
|
|
|
|
|
|
|
11832
|
|
|
|
|
|
|
# add Tag operation |
|
11833
|
0
|
|
|
|
|
0
|
push(@{$ops}, ['TAG', $prefix, "$ns:TagCollection/$ns:Tag", [], [], {'Name' => $key, 'Value' => [$i]}, 100]); |
|
|
0
|
|
|
|
|
0
|
|
|
11834
|
|
|
|
|
|
|
|
|
11835
|
|
|
|
|
|
|
} |
|
11836
|
|
|
|
|
|
|
|
|
11837
|
|
|
|
|
|
|
} |
|
11838
|
|
|
|
|
|
|
|
|
11839
|
|
|
|
|
|
|
} |
|
11840
|
|
|
|
|
|
|
|
|
11841
|
|
|
|
|
|
|
} |
|
11842
|
|
|
|
|
|
|
|
|
11843
|
|
|
|
|
|
|
} |
|
11844
|
|
|
|
|
|
|
|
|
11845
|
|
|
|
|
|
|
# following section sorts and verifies column slices, sets default prefixes and checks for multiple elements |
|
11846
|
|
|
|
|
|
|
# |
|
11847
|
|
|
|
|
|
|
# init loop variable |
|
11848
|
0
|
|
|
|
|
0
|
%keys = (); |
|
11849
|
|
|
|
|
|
|
|
|
11850
|
|
|
|
|
|
|
# for each array entry |
|
11851
|
0
|
|
|
|
|
0
|
for my $t (@{$ops}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11852
|
|
|
|
|
|
|
|
|
11853
|
|
|
|
|
|
|
# if sort order is defined |
|
11854
|
0
|
0
|
|
|
|
0
|
if (defined($table->[$t->[6]][4])) { |
|
11855
|
|
|
|
|
|
|
|
|
11856
|
|
|
|
|
|
|
# arrange column indices in sort order |
|
11857
|
0
|
|
|
|
|
0
|
@{$t->[4]} = map {my $end = $_; grep {$self->[1][0][$_] =~ m/$end$/} @{$t->[4]}} @{$table->[$t->[6]][4]}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11858
|
|
|
|
|
|
|
|
|
11859
|
|
|
|
|
|
|
} |
|
11860
|
|
|
|
|
|
|
|
|
11861
|
|
|
|
|
|
|
# if class is SPECTRAL |
|
11862
|
0
|
0
|
|
|
|
0
|
if ($t->[0] eq 'SPECTRAL') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
11863
|
|
|
|
|
|
|
|
|
11864
|
|
|
|
|
|
|
# verify spectral slice |
|
11865
|
0
|
0
|
|
|
|
0
|
(@{$t->[4]} == @{_spectral($self, $t->[1])}) || warn("invalid column slice - SPECTRAL class"); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11866
|
|
|
|
|
|
|
|
|
11867
|
|
|
|
|
|
|
# if class is DENSITY |
|
11868
|
|
|
|
|
|
|
} elsif ($t->[0] eq 'DENSITY') { |
|
11869
|
|
|
|
|
|
|
|
|
11870
|
|
|
|
|
|
|
# to be done |
|
11871
|
|
|
|
|
|
|
|
|
11872
|
|
|
|
|
|
|
# if class is NCLR |
|
11873
|
|
|
|
|
|
|
} elsif ($t->[0] eq 'NCLR') { |
|
11874
|
|
|
|
|
|
|
|
|
11875
|
|
|
|
|
|
|
# match first key to get number of channels |
|
11876
|
0
|
|
|
|
|
0
|
$self->[1][0][$t->[4][0]] =~ m/([2-9A-F])(?:CLR_|_)[1-9A-F]$/; |
|
11877
|
|
|
|
|
|
|
|
|
11878
|
|
|
|
|
|
|
# verify nCLR slice |
|
11879
|
0
|
0
|
|
|
|
0
|
(@{$t->[4]} == CORE::hex($1)) || warn("invalid column slice - NCLR class"); |
|
|
0
|
|
|
|
|
0
|
|
|
11880
|
|
|
|
|
|
|
|
|
11881
|
|
|
|
|
|
|
# all others |
|
11882
|
|
|
|
|
|
|
} else { |
|
11883
|
|
|
|
|
|
|
|
|
11884
|
|
|
|
|
|
|
# verify subpaths match column slice |
|
11885
|
0
|
0
|
0
|
|
|
0
|
(@{$t->[4]} == @{$t->[3]} || (@{$t->[4]} == 1 && @{$t->[3]} == 0)) || warn("invalid column slice - $t->[0] class"); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11886
|
|
|
|
|
|
|
|
|
11887
|
|
|
|
|
|
|
} |
|
11888
|
|
|
|
|
|
|
|
|
11889
|
|
|
|
|
|
|
# if prefix undefined |
|
11890
|
0
|
0
|
|
|
|
0
|
if (! defined($t->[1])) { |
|
11891
|
|
|
|
|
|
|
|
|
11892
|
|
|
|
|
|
|
# if XPath contains 'ColorValues' or 'ColorDifferenceValues' |
|
11893
|
0
|
0
|
|
|
|
0
|
if ($t->[2] =~ m/^$ns:(?:ColorValues|ColorDifferenceValues)\//) { |
|
|
|
0
|
|
|
|
|
|
|
11894
|
|
|
|
|
|
|
|
|
11895
|
|
|
|
|
|
|
# set prefix to M0_Measurement |
|
11896
|
0
|
|
|
|
|
0
|
$t->[1] = 'M0_Measurement'; |
|
11897
|
|
|
|
|
|
|
|
|
11898
|
|
|
|
|
|
|
# if XPath contains 'DeviceColorValues' |
|
11899
|
|
|
|
|
|
|
} elsif ($t->[2] =~ m/^$ns:DeviceColorValues\//) { |
|
11900
|
|
|
|
|
|
|
|
|
11901
|
|
|
|
|
|
|
# set prefix to Target |
|
11902
|
0
|
|
|
|
|
0
|
$t->[1] = 'Target'; |
|
11903
|
|
|
|
|
|
|
|
|
11904
|
|
|
|
|
|
|
# all others |
|
11905
|
|
|
|
|
|
|
} else { |
|
11906
|
|
|
|
|
|
|
|
|
11907
|
|
|
|
|
|
|
# set prefix to '~~' |
|
11908
|
0
|
|
|
|
|
0
|
$t->[1] = '~~'; |
|
11909
|
|
|
|
|
|
|
|
|
11910
|
|
|
|
|
|
|
} |
|
11911
|
|
|
|
|
|
|
|
|
11912
|
|
|
|
|
|
|
} |
|
11913
|
|
|
|
|
|
|
|
|
11914
|
|
|
|
|
|
|
# for 'ColorValues' or 'DeviceColorValues' |
|
11915
|
0
|
0
|
|
|
|
0
|
if ($t->[2] =~ m/^$ns:(ColorValues|DeviceColorValues)\//) { |
|
11916
|
|
|
|
|
|
|
|
|
11917
|
|
|
|
|
|
|
# warn on multiple elements (not allowed by i1Profiler) |
|
11918
|
0
|
0
|
|
|
|
0
|
print "warning: multiple $1 elements in CxF3 $t->[1] object\n" if ($keys{"$1/$t->[1]"}++ == 1); |
|
11919
|
|
|
|
|
|
|
|
|
11920
|
|
|
|
|
|
|
} |
|
11921
|
|
|
|
|
|
|
|
|
11922
|
|
|
|
|
|
|
} |
|
11923
|
|
|
|
|
|
|
|
|
11924
|
|
|
|
|
|
|
# following section groups operations by prefix |
|
11925
|
|
|
|
|
|
|
# |
|
11926
|
|
|
|
|
|
|
# sort by prefix, then by table index |
|
11927
|
0
|
0
|
|
|
|
0
|
@{$ops} = sort {($a->[1] cmp $b->[1]) or ($a->[6] <=> $b->[6])} @{$ops}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11928
|
|
|
|
|
|
|
|
|
11929
|
|
|
|
|
|
|
# init loop variable |
|
11930
|
0
|
|
|
|
|
0
|
$prefix = undef; |
|
11931
|
|
|
|
|
|
|
|
|
11932
|
|
|
|
|
|
|
# for each operation |
|
11933
|
0
|
|
|
|
|
0
|
for my $t (@{$ops}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11934
|
|
|
|
|
|
|
|
|
11935
|
|
|
|
|
|
|
# if same prefix as last operation |
|
11936
|
0
|
0
|
0
|
|
|
0
|
if (defined($prefix) && $prefix eq $t->[1]) { |
|
|
|
0
|
0
|
|
|
|
|
|
11937
|
|
|
|
|
|
|
|
|
11938
|
|
|
|
|
|
|
# add operation to last group |
|
11939
|
0
|
|
|
|
|
0
|
push(@{$groups->[-1]}, $t); |
|
|
0
|
|
|
|
|
0
|
|
|
11940
|
|
|
|
|
|
|
|
|
11941
|
|
|
|
|
|
|
# if class is TAG and prefix is '~~' |
|
11942
|
|
|
|
|
|
|
} elsif ($t->[0] eq 'TAG' && $t->[1] eq '~~') { |
|
11943
|
|
|
|
|
|
|
|
|
11944
|
|
|
|
|
|
|
# for each group |
|
11945
|
0
|
|
|
|
|
0
|
for my $g (@{$groups}) { |
|
|
0
|
|
|
|
|
0
|
|
|
11946
|
|
|
|
|
|
|
|
|
11947
|
|
|
|
|
|
|
# add operation |
|
11948
|
0
|
|
|
|
|
0
|
push(@{$g}, $t); |
|
|
0
|
|
|
|
|
0
|
|
|
11949
|
|
|
|
|
|
|
|
|
11950
|
|
|
|
|
|
|
} |
|
11951
|
|
|
|
|
|
|
|
|
11952
|
|
|
|
|
|
|
# set prefix |
|
11953
|
0
|
|
|
|
|
0
|
$prefix = undef; |
|
11954
|
|
|
|
|
|
|
|
|
11955
|
|
|
|
|
|
|
# others |
|
11956
|
|
|
|
|
|
|
} else { |
|
11957
|
|
|
|
|
|
|
|
|
11958
|
|
|
|
|
|
|
# add new group |
|
11959
|
0
|
|
|
|
|
0
|
push(@{$groups}, [$t]); |
|
|
0
|
|
|
|
|
0
|
|
|
11960
|
|
|
|
|
|
|
|
|
11961
|
|
|
|
|
|
|
# set prefix |
|
11962
|
0
|
|
|
|
|
0
|
$prefix = $t->[1]; |
|
11963
|
|
|
|
|
|
|
|
|
11964
|
|
|
|
|
|
|
} |
|
11965
|
|
|
|
|
|
|
|
|
11966
|
|
|
|
|
|
|
} |
|
11967
|
|
|
|
|
|
|
|
|
11968
|
|
|
|
|
|
|
# return |
|
11969
|
0
|
|
|
|
|
0
|
return($groups); |
|
11970
|
|
|
|
|
|
|
|
|
11971
|
|
|
|
|
|
|
} |
|
11972
|
|
|
|
|
|
|
|
|
11973
|
|
|
|
|
|
|
# write CxF3 FileInformation nodes |
|
11974
|
|
|
|
|
|
|
# optional hash parameter contains 'cc:FileInformation' filter array |
|
11975
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix, CxF3_namespace_URI, hash) |
|
11976
|
|
|
|
|
|
|
# returns: (datetime) |
|
11977
|
|
|
|
|
|
|
sub _writeCxF3fileinfo { |
|
11978
|
|
|
|
|
|
|
|
|
11979
|
|
|
|
|
|
|
# get parameters |
|
11980
|
0
|
|
|
0
|
|
0
|
my ($self, $xpc, $ns, $nsURI, $hash) = @_; |
|
11981
|
|
|
|
|
|
|
|
|
11982
|
|
|
|
|
|
|
# local variables |
|
11983
|
0
|
|
|
|
|
0
|
my (@filter, $t, $datetime, $info, %keys); |
|
11984
|
0
|
|
|
|
|
0
|
my ($keyword, $value, $source, $node, $child); |
|
11985
|
|
|
|
|
|
|
|
|
11986
|
|
|
|
|
|
|
# get filter array (if any) |
|
11987
|
0
|
0
|
|
|
|
0
|
@filter = @{ICC::Shared::flatten($hash->{'cc:FileInformation'})} if (defined($hash->{'cc:FileInformation'})); |
|
|
0
|
|
|
|
|
0
|
|
|
11988
|
|
|
|
|
|
|
|
|
11989
|
|
|
|
|
|
|
# make Time::Piece object |
|
11990
|
0
|
|
|
|
|
0
|
$t = localtime(); |
|
11991
|
|
|
|
|
|
|
|
|
11992
|
|
|
|
|
|
|
# get the 'FileInformation' node |
|
11993
|
0
|
|
|
|
|
0
|
($info) = $xpc->findnodes("$ns:FileInformation"); |
|
11994
|
|
|
|
|
|
|
|
|
11995
|
|
|
|
|
|
|
# make ASCII => CxF3 mapping table (from ISO 17972-1, Annex A) |
|
11996
|
0
|
|
|
|
|
0
|
%keys = ('ORIGINATOR' => "$ns:Creator", 'FILE_DESCRIPTOR' => "$ns:Description", 'CXF3_COMMENT' => "$ns:Comment"); |
|
11997
|
|
|
|
|
|
|
|
|
11998
|
|
|
|
|
|
|
# for each file header line |
|
11999
|
0
|
|
|
|
|
0
|
for (@{$self->[3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12000
|
|
|
|
|
|
|
|
|
12001
|
|
|
|
|
|
|
# get keyword, value and source |
|
12002
|
0
|
|
|
|
|
0
|
($keyword, $value, $source) = @{$_}; |
|
|
0
|
|
|
|
|
0
|
|
|
12003
|
|
|
|
|
|
|
|
|
12004
|
|
|
|
|
|
|
# strip quotes from value |
|
12005
|
0
|
|
|
|
|
0
|
$value =~ s/^\"(.*)\"$/$1/; |
|
12006
|
|
|
|
|
|
|
|
|
12007
|
|
|
|
|
|
|
# if keyword is 'CREATED' |
|
12008
|
0
|
0
|
0
|
|
|
0
|
if ($keyword eq 'CREATED') { |
|
|
|
0
|
0
|
|
|
|
|
|
12009
|
|
|
|
|
|
|
|
|
12010
|
|
|
|
|
|
|
# make Time::Piece object from 'CREATED' value |
|
12011
|
0
|
|
|
|
|
0
|
$t = _makeTimePiece($value); |
|
12012
|
|
|
|
|
|
|
|
|
12013
|
|
|
|
|
|
|
# if source is 'FileInformation' or keyword is in filter array |
|
12014
|
0
|
|
|
|
|
0
|
} elsif ((defined($source) && $source eq 'FileInformation') || grep {$_ eq $keyword} @filter) { |
|
12015
|
|
|
|
|
|
|
|
|
12016
|
|
|
|
|
|
|
# if keyword in mapping table |
|
12017
|
0
|
0
|
|
|
|
0
|
if (exists($keys{$keyword})) { |
|
12018
|
|
|
|
|
|
|
|
|
12019
|
|
|
|
|
|
|
# if XPath exists in FileInformation element |
|
12020
|
0
|
0
|
|
|
|
0
|
if (($node) = $xpc->findnodes($keys{$keyword}, $info)) { |
|
12021
|
|
|
|
|
|
|
|
|
12022
|
|
|
|
|
|
|
# if text content exists |
|
12023
|
0
|
0
|
0
|
|
|
0
|
if ((($child) = $node->nonBlankChildNodes) && $child->nodeType == 3) { |
|
12024
|
|
|
|
|
|
|
|
|
12025
|
|
|
|
|
|
|
# update text content |
|
12026
|
0
|
|
|
|
|
0
|
$child->setData($value); |
|
12027
|
|
|
|
|
|
|
|
|
12028
|
|
|
|
|
|
|
} |
|
12029
|
|
|
|
|
|
|
|
|
12030
|
|
|
|
|
|
|
} |
|
12031
|
|
|
|
|
|
|
|
|
12032
|
|
|
|
|
|
|
# must be a 'Tag' element |
|
12033
|
|
|
|
|
|
|
} else { |
|
12034
|
|
|
|
|
|
|
|
|
12035
|
|
|
|
|
|
|
# if XPath exists in FileInformation element |
|
12036
|
0
|
0
|
|
|
|
0
|
if (($node) = $xpc->findnodes("$ns:Tag[\@Name='$keyword']", $info)) { |
|
12037
|
|
|
|
|
|
|
|
|
12038
|
|
|
|
|
|
|
# update the Value attribute |
|
12039
|
0
|
|
|
|
|
0
|
$node->setAttribute('Value', $value); |
|
12040
|
|
|
|
|
|
|
|
|
12041
|
|
|
|
|
|
|
} else { |
|
12042
|
|
|
|
|
|
|
|
|
12043
|
|
|
|
|
|
|
# add new Tag element |
|
12044
|
0
|
|
|
|
|
0
|
$node = $info->appendChild(XML::LibXML::Element->new('Tag')); |
|
12045
|
0
|
|
|
|
|
0
|
$node->setAttribute('Name', $keyword); |
|
12046
|
0
|
|
|
|
|
0
|
$node->setAttribute('Value', $value); |
|
12047
|
0
|
|
|
|
|
0
|
$node->setNamespace($nsURI, $ns); |
|
12048
|
|
|
|
|
|
|
|
|
12049
|
|
|
|
|
|
|
} |
|
12050
|
|
|
|
|
|
|
|
|
12051
|
|
|
|
|
|
|
} |
|
12052
|
|
|
|
|
|
|
|
|
12053
|
|
|
|
|
|
|
} |
|
12054
|
|
|
|
|
|
|
|
|
12055
|
|
|
|
|
|
|
} |
|
12056
|
|
|
|
|
|
|
|
|
12057
|
|
|
|
|
|
|
# make ISO 8601 datetime string from Time::Piece object |
|
12058
|
0
|
|
|
|
|
0
|
$datetime = sprintf("%s%+03d:00", $t->datetime, $t->tzoffset->hours); |
|
12059
|
|
|
|
|
|
|
|
|
12060
|
|
|
|
|
|
|
# get the 'CreationDate' node |
|
12061
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:CreationDate", $info); |
|
12062
|
|
|
|
|
|
|
|
|
12063
|
|
|
|
|
|
|
# if text content exists |
|
12064
|
0
|
0
|
0
|
|
|
0
|
if ((($child) = $node->nonBlankChildNodes) && $child->nodeType == 3) { |
|
12065
|
|
|
|
|
|
|
|
|
12066
|
|
|
|
|
|
|
# update text content |
|
12067
|
0
|
|
|
|
|
0
|
$child->setData($datetime); |
|
12068
|
|
|
|
|
|
|
|
|
12069
|
|
|
|
|
|
|
} |
|
12070
|
|
|
|
|
|
|
|
|
12071
|
|
|
|
|
|
|
# return datetime |
|
12072
|
0
|
|
|
|
|
0
|
return($datetime); |
|
12073
|
|
|
|
|
|
|
|
|
12074
|
|
|
|
|
|
|
} |
|
12075
|
|
|
|
|
|
|
|
|
12076
|
|
|
|
|
|
|
# write CxF3 ColorSpecification nodes |
|
12077
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix, CxF3_namespace_URI, operations_array) |
|
12078
|
|
|
|
|
|
|
sub _writeCxF3colorspec { |
|
12079
|
|
|
|
|
|
|
|
|
12080
|
|
|
|
|
|
|
# get parameters |
|
12081
|
0
|
|
|
0
|
|
0
|
my ($self, $xpc, $ns, $nsURI, $ops) = @_; |
|
12082
|
|
|
|
|
|
|
|
|
12083
|
|
|
|
|
|
|
# local variables |
|
12084
|
0
|
|
|
|
|
0
|
my (@illum, @filter, $cscol, $template, $unknown); |
|
12085
|
0
|
|
|
|
|
0
|
my (%table, %cspec, %hash, $keyword, $value, $source); |
|
12086
|
0
|
|
|
|
|
0
|
my ($Id, $cs, @nodes, $node, $node2, $child, @wav); |
|
12087
|
0
|
|
|
|
|
0
|
my ($parser, $frag, $std, $xpath); |
|
12088
|
|
|
|
|
|
|
|
|
12089
|
|
|
|
|
|
|
# illumination types |
|
12090
|
0
|
|
|
|
|
0
|
@illum = qw(M0_Incandescent M1_Daylight M2_UVExcluded M3_Polarized); |
|
12091
|
|
|
|
|
|
|
|
|
12092
|
|
|
|
|
|
|
# filter types |
|
12093
|
0
|
|
|
|
|
0
|
@filter = qw(Filter_None Filter_None Filter_UVExcluded Filter_None); |
|
12094
|
|
|
|
|
|
|
|
|
12095
|
|
|
|
|
|
|
# get the 'ColorSpecificationCollection' node |
|
12096
|
0
|
|
|
|
|
0
|
($cscol) = $xpc->findnodes("$ns:Resources/$ns:ColorSpecificationCollection"); |
|
12097
|
|
|
|
|
|
|
|
|
12098
|
|
|
|
|
|
|
# get the 'ColorSpecification' node with Id = 'template' |
|
12099
|
0
|
|
|
|
|
0
|
($template) = $xpc->findnodes("$ns:ColorSpecification[\@Id='template']", $cscol); |
|
12100
|
|
|
|
|
|
|
|
|
12101
|
|
|
|
|
|
|
# get the 'ColorSpecification' node with Id = 'Unknown' |
|
12102
|
0
|
|
|
|
|
0
|
($unknown) = $xpc->findnodes("$ns:ColorSpecification[\@Id='Unknown']", $cscol); |
|
12103
|
|
|
|
|
|
|
|
|
12104
|
|
|
|
|
|
|
# make ASCII => CxF3 mapping table (from ISO 17972-1, Annex A) |
|
12105
|
0
|
|
|
|
|
0
|
%table = ( |
|
12106
|
|
|
|
|
|
|
'MEASUREMENT_GEOMETRY' => "$ns:MeasurementSpec/$ns:GeometryChoice", |
|
12107
|
|
|
|
|
|
|
'DEVCALSTD' => "$ns:MeasurementSpec/$ns:CalibrationStandard", |
|
12108
|
|
|
|
|
|
|
'MANUFACTURER' => "$ns:MeasurementSpec/$ns:Device/$ns:Manufacturer", |
|
12109
|
|
|
|
|
|
|
'MODEL' => "$ns:MeasurementSpec/$ns:Device/$ns:Model", |
|
12110
|
|
|
|
|
|
|
'SERIAL_NUMBER' => "$ns:MeasurementSpec/$ns:Device/$ns:SerialNumber", |
|
12111
|
|
|
|
|
|
|
'DEVICE_CLASS' => "$ns:MeasurementSpec/$ns:Device/$ns:DeviceClass", |
|
12112
|
|
|
|
|
|
|
'FILTER' => "$ns:MeasurementSpec/$ns:Device/$ns:DeviceFilter", |
|
12113
|
|
|
|
|
|
|
'MEASUREMENT_SOURCE' => "$ns:MeasurementSpec/$ns:Device/$ns:DeviceIllumination", |
|
12114
|
|
|
|
|
|
|
'POLARIZATION' => "$ns:MeasurementSpec/$ns:Device/$ns:DevicePolarization", |
|
12115
|
|
|
|
|
|
|
'SAMPLE_BACKING' => "$ns:MeasurementSpec/$ns:Backing", |
|
12116
|
|
|
|
|
|
|
); |
|
12117
|
|
|
|
|
|
|
|
|
12118
|
|
|
|
|
|
|
# for each group |
|
12119
|
0
|
|
|
|
|
0
|
for my $group (@{$ops}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12120
|
|
|
|
|
|
|
|
|
12121
|
|
|
|
|
|
|
# for each operation |
|
12122
|
0
|
|
|
|
|
0
|
for my $t (@{$group}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12123
|
|
|
|
|
|
|
|
|
12124
|
|
|
|
|
|
|
# if ColorValues (only ColorValues reference a ColorSpecification) |
|
12125
|
0
|
0
|
|
|
|
0
|
if ($t->[2] =~ m/^$ns:ColorValues\//) { |
|
|
|
0
|
|
|
|
|
|
|
12126
|
|
|
|
|
|
|
|
|
12127
|
|
|
|
|
|
|
# set Id to saved value, if defined, or add '_spec' to prefix |
|
12128
|
|
|
|
|
|
|
# the ColorSpecification Id is saved in the Colorimetry array when reading a CxF3 file |
|
12129
|
0
|
0
|
|
|
|
0
|
$Id = defined($self->[2][5][$t->[4][0]]) ? $self->[2][5][$t->[4][0]] : "$t->[1]\_spec"; |
|
12130
|
|
|
|
|
|
|
|
|
12131
|
|
|
|
|
|
|
# set attribute hash |
|
12132
|
0
|
|
|
|
|
0
|
$t->[5]{'ColorSpecification'} = $Id; |
|
12133
|
|
|
|
|
|
|
|
|
12134
|
|
|
|
|
|
|
# if 'ColorSpecification' undefined |
|
12135
|
0
|
0
|
|
|
|
0
|
if (! $cspec{$Id}++) { |
|
12136
|
|
|
|
|
|
|
|
|
12137
|
|
|
|
|
|
|
# initialize keyword hash |
|
12138
|
0
|
|
|
|
|
0
|
%hash = (); |
|
12139
|
|
|
|
|
|
|
|
|
12140
|
|
|
|
|
|
|
# add cloned 'ColorSpecification' element to 'ColorSpecificationCollection' |
|
12141
|
0
|
|
|
|
|
0
|
$cs = $cscol->appendChild($template->cloneNode(1)); |
|
12142
|
|
|
|
|
|
|
|
|
12143
|
|
|
|
|
|
|
# set the Id |
|
12144
|
0
|
|
|
|
|
0
|
$cs->setAttribute('Id', $Id); |
|
12145
|
|
|
|
|
|
|
|
|
12146
|
|
|
|
|
|
|
# if spectral data |
|
12147
|
|
|
|
|
|
|
# there are three types of spectral data, reflective, transmissive and emissive |
|
12148
|
|
|
|
|
|
|
# spectral data has a WavelengthRange node which contains the starting wavelength and increment |
|
12149
|
0
|
0
|
|
|
|
0
|
if ($t->[2] =~ m/(Reflectance|Transmittance|Emissive)Spectrum$/) { |
|
12150
|
|
|
|
|
|
|
|
|
12151
|
|
|
|
|
|
|
# get the 'MeasurementType' node |
|
12152
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:MeasurementSpec/$ns:MeasurementType", $cs); |
|
12153
|
|
|
|
|
|
|
|
|
12154
|
|
|
|
|
|
|
# if text content exists |
|
12155
|
0
|
0
|
0
|
|
|
0
|
if ((($child) = $node->nonBlankChildNodes) && $child->nodeType == 3) { |
|
12156
|
|
|
|
|
|
|
|
|
12157
|
|
|
|
|
|
|
# update text content |
|
12158
|
0
|
|
|
|
|
0
|
$child->setData("Spectrum_$1"); |
|
12159
|
|
|
|
|
|
|
|
|
12160
|
|
|
|
|
|
|
} |
|
12161
|
|
|
|
|
|
|
|
|
12162
|
|
|
|
|
|
|
# for first two data columns |
|
12163
|
0
|
|
|
|
|
0
|
for ($t->[4][0], $t->[4][1]) { |
|
12164
|
|
|
|
|
|
|
|
|
12165
|
|
|
|
|
|
|
# match wavelength in format key |
|
12166
|
0
|
|
|
|
|
0
|
$self->[1][0][$_] =~ m/(\d{3})$/; |
|
12167
|
|
|
|
|
|
|
|
|
12168
|
|
|
|
|
|
|
# push to array |
|
12169
|
0
|
|
|
|
|
0
|
push(@wav, $1); |
|
12170
|
|
|
|
|
|
|
|
|
12171
|
|
|
|
|
|
|
} |
|
12172
|
|
|
|
|
|
|
|
|
12173
|
|
|
|
|
|
|
# find the 'WavelengthRange' node |
|
12174
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:MeasurementSpec/$ns:WavelengthRange", $cs); |
|
12175
|
|
|
|
|
|
|
|
|
12176
|
|
|
|
|
|
|
# set the 'StartWL' attribute |
|
12177
|
0
|
|
|
|
|
0
|
$node->setAttribute('StartWL', $wav[0]); |
|
12178
|
|
|
|
|
|
|
|
|
12179
|
|
|
|
|
|
|
# set the 'Increment' attribute |
|
12180
|
0
|
|
|
|
|
0
|
$node->setAttribute('Increment', $wav[1] - $wav[0]); |
|
12181
|
|
|
|
|
|
|
|
|
12182
|
|
|
|
|
|
|
# set operation 'StartWL' attribute |
|
12183
|
0
|
|
|
|
|
0
|
$t->[5]{'StartWL'} = $wav[0]; |
|
12184
|
|
|
|
|
|
|
|
|
12185
|
|
|
|
|
|
|
} else { |
|
12186
|
|
|
|
|
|
|
|
|
12187
|
|
|
|
|
|
|
# find the 'WavelengthRange' node |
|
12188
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:MeasurementSpec/$ns:WavelengthRange", $cs); |
|
12189
|
|
|
|
|
|
|
|
|
12190
|
|
|
|
|
|
|
# unbind the node (used only with spectral data) |
|
12191
|
0
|
|
|
|
|
0
|
$node->unbindNode(); |
|
12192
|
|
|
|
|
|
|
|
|
12193
|
|
|
|
|
|
|
} |
|
12194
|
|
|
|
|
|
|
|
|
12195
|
|
|
|
|
|
|
# for each file header entry |
|
12196
|
0
|
|
|
|
|
0
|
for (@{$self->[3]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12197
|
|
|
|
|
|
|
|
|
12198
|
|
|
|
|
|
|
# get keyword, value and source |
|
12199
|
0
|
|
|
|
|
0
|
($keyword, $value, $source) = @{$_}; |
|
|
0
|
|
|
|
|
0
|
|
|
12200
|
|
|
|
|
|
|
|
|
12201
|
|
|
|
|
|
|
# strip quotes from value |
|
12202
|
0
|
|
|
|
|
0
|
$value =~ s/^\"(.*)\"$/$1/; |
|
12203
|
|
|
|
|
|
|
|
|
12204
|
|
|
|
|
|
|
# if source is ColorSpecification Id |
|
12205
|
0
|
0
|
0
|
|
|
0
|
if (defined($source) && $source eq $Id) { |
|
12206
|
|
|
|
|
|
|
|
|
12207
|
|
|
|
|
|
|
# add keyword to hash |
|
12208
|
0
|
|
|
|
|
0
|
$hash{$keyword}++; |
|
12209
|
|
|
|
|
|
|
|
|
12210
|
|
|
|
|
|
|
# if keyword in table |
|
12211
|
0
|
0
|
|
|
|
0
|
if (exists($table{$keyword})) { |
|
12212
|
|
|
|
|
|
|
|
|
12213
|
|
|
|
|
|
|
# if XPath does not exist in ColorSpecification element |
|
12214
|
0
|
0
|
|
|
|
0
|
if (! (($node) = $xpc->findnodes($table{$keyword}, $cs))) { |
|
12215
|
|
|
|
|
|
|
|
|
12216
|
|
|
|
|
|
|
# set node |
|
12217
|
0
|
|
|
|
|
0
|
$node = $cs; |
|
12218
|
|
|
|
|
|
|
|
|
12219
|
|
|
|
|
|
|
# initialize XPath |
|
12220
|
0
|
|
|
|
|
0
|
$xpath = undef; |
|
12221
|
|
|
|
|
|
|
|
|
12222
|
|
|
|
|
|
|
# for each segment |
|
12223
|
0
|
|
|
|
|
0
|
for (split(/\//, $table{$keyword})) { |
|
12224
|
|
|
|
|
|
|
|
|
12225
|
|
|
|
|
|
|
# add segment to XPath |
|
12226
|
0
|
0
|
|
|
|
0
|
$xpath = defined($xpath) ? "$xpath/$_" : $_; |
|
12227
|
|
|
|
|
|
|
|
|
12228
|
|
|
|
|
|
|
# if XPath exists in ColorSpecification element |
|
12229
|
0
|
0
|
|
|
|
0
|
if (($node2) = $xpc->findnodes($xpath, $cs)) { |
|
12230
|
|
|
|
|
|
|
|
|
12231
|
|
|
|
|
|
|
# use existing node |
|
12232
|
0
|
|
|
|
|
0
|
$node = $node2; |
|
12233
|
|
|
|
|
|
|
|
|
12234
|
|
|
|
|
|
|
} else { |
|
12235
|
|
|
|
|
|
|
|
|
12236
|
|
|
|
|
|
|
# add element for XPath segment |
|
12237
|
0
|
|
|
|
|
0
|
$node = $node->appendChild(XML::LibXML::Element->new($_)); |
|
12238
|
0
|
|
|
|
|
0
|
$node->setNamespace($nsURI, $ns); |
|
12239
|
|
|
|
|
|
|
|
|
12240
|
|
|
|
|
|
|
} |
|
12241
|
|
|
|
|
|
|
|
|
12242
|
|
|
|
|
|
|
} |
|
12243
|
|
|
|
|
|
|
|
|
12244
|
|
|
|
|
|
|
} |
|
12245
|
|
|
|
|
|
|
|
|
12246
|
|
|
|
|
|
|
# get the first non-blank child node |
|
12247
|
0
|
|
|
|
|
0
|
($child) = $node->nonBlankChildNodes(); |
|
12248
|
|
|
|
|
|
|
|
|
12249
|
|
|
|
|
|
|
# make a parser object |
|
12250
|
0
|
|
|
|
|
0
|
$parser = XML::LibXML->new(); |
|
12251
|
|
|
|
|
|
|
|
|
12252
|
|
|
|
|
|
|
# if value is an XML balanced chunk |
|
12253
|
0
|
0
|
0
|
|
|
0
|
if ($value =~ m/ && eval{$frag = $parser->parse_balanced_chunk($value)}) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
12254
|
|
|
|
|
|
|
|
|
12255
|
|
|
|
|
|
|
# get all element nodes |
|
12256
|
0
|
|
|
|
|
0
|
@nodes = $frag->findnodes('//*'); |
|
12257
|
|
|
|
|
|
|
|
|
12258
|
|
|
|
|
|
|
# replace existing node |
|
12259
|
0
|
|
|
|
|
0
|
$node->replaceNode($frag); |
|
12260
|
|
|
|
|
|
|
|
|
12261
|
|
|
|
|
|
|
# set namespace of each element |
|
12262
|
0
|
|
|
|
|
0
|
for (@nodes) {$_->setNamespace($nsURI, $ns)}; |
|
|
0
|
|
|
|
|
0
|
|
|
12263
|
|
|
|
|
|
|
|
|
12264
|
|
|
|
|
|
|
# if no child node |
|
12265
|
|
|
|
|
|
|
} elsif (! defined($child)) { |
|
12266
|
|
|
|
|
|
|
|
|
12267
|
|
|
|
|
|
|
# set text content to value |
|
12268
|
0
|
|
|
|
|
0
|
$node->appendText($value); |
|
12269
|
|
|
|
|
|
|
|
|
12270
|
|
|
|
|
|
|
# if child node is text type |
|
12271
|
|
|
|
|
|
|
} elsif ($child->nodeType == 3) { |
|
12272
|
|
|
|
|
|
|
|
|
12273
|
|
|
|
|
|
|
# modify existing text content |
|
12274
|
0
|
|
|
|
|
0
|
$child->setData($value); |
|
12275
|
|
|
|
|
|
|
|
|
12276
|
|
|
|
|
|
|
} |
|
12277
|
|
|
|
|
|
|
|
|
12278
|
|
|
|
|
|
|
} |
|
12279
|
|
|
|
|
|
|
|
|
12280
|
|
|
|
|
|
|
} |
|
12281
|
|
|
|
|
|
|
|
|
12282
|
|
|
|
|
|
|
} |
|
12283
|
|
|
|
|
|
|
|
|
12284
|
|
|
|
|
|
|
# match illumination standard in prefix (M0, M1, M2, M3) |
|
12285
|
0
|
0
|
|
|
|
0
|
$std = ($t->[1] =~ m/^M([0-3])/) ? $1 : 0; |
|
12286
|
|
|
|
|
|
|
|
|
12287
|
|
|
|
|
|
|
# if 'FILTER' not a keyword |
|
12288
|
0
|
0
|
|
|
|
0
|
if (! exists($hash{'FILTER'})) { |
|
12289
|
|
|
|
|
|
|
|
|
12290
|
|
|
|
|
|
|
# find the 'Device' node |
|
12291
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:MeasurementSpec/$ns:Device", $cs); |
|
12292
|
|
|
|
|
|
|
|
|
12293
|
|
|
|
|
|
|
# add 'DeviceFilter' node |
|
12294
|
0
|
|
|
|
|
0
|
$child = $node->appendChild(XML::LibXML::Element->new("$ns:DeviceFilter")); |
|
12295
|
0
|
|
|
|
|
0
|
$child->setNamespace($nsURI, $ns); |
|
12296
|
|
|
|
|
|
|
|
|
12297
|
|
|
|
|
|
|
# set filter type |
|
12298
|
0
|
|
|
|
|
0
|
$child->appendText($filter[$std]); |
|
12299
|
|
|
|
|
|
|
|
|
12300
|
|
|
|
|
|
|
} |
|
12301
|
|
|
|
|
|
|
|
|
12302
|
|
|
|
|
|
|
# if 'MEASUREMENT_SOURCE' not a keyword |
|
12303
|
0
|
0
|
|
|
|
0
|
if (! exists($hash{'MEASUREMENT_SOURCE'})) { |
|
12304
|
|
|
|
|
|
|
|
|
12305
|
|
|
|
|
|
|
# find the 'Device' node |
|
12306
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:MeasurementSpec/$ns:Device", $cs); |
|
12307
|
|
|
|
|
|
|
|
|
12308
|
|
|
|
|
|
|
# add 'DeviceIllumination' node |
|
12309
|
0
|
|
|
|
|
0
|
$child = $node->appendChild(XML::LibXML::Element->new("$ns:DeviceIllumination")); |
|
12310
|
0
|
|
|
|
|
0
|
$child->setNamespace($nsURI, $ns); |
|
12311
|
|
|
|
|
|
|
|
|
12312
|
|
|
|
|
|
|
# set illumination type |
|
12313
|
0
|
|
|
|
|
0
|
$child->appendText($illum[$std]); |
|
12314
|
|
|
|
|
|
|
|
|
12315
|
|
|
|
|
|
|
} |
|
12316
|
|
|
|
|
|
|
|
|
12317
|
|
|
|
|
|
|
# if 'POLARIZATION' not a keyword -and- M3 standard |
|
12318
|
0
|
0
|
0
|
|
|
0
|
if (! exists($hash{'POLARIZATION'}) && $std == 3) { |
|
12319
|
|
|
|
|
|
|
|
|
12320
|
|
|
|
|
|
|
# get the 'Device' node |
|
12321
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes("$ns:MeasurementSpec/$ns:Device", $cs); |
|
12322
|
|
|
|
|
|
|
|
|
12323
|
|
|
|
|
|
|
# add 'Polarization' node |
|
12324
|
0
|
|
|
|
|
0
|
$child = $node->appendChild(XML::LibXML::Element->new("$ns:Polarization")); |
|
12325
|
0
|
|
|
|
|
0
|
$child->setNamespace($nsURI, $ns); |
|
12326
|
|
|
|
|
|
|
|
|
12327
|
|
|
|
|
|
|
# set polarization to 'true' |
|
12328
|
0
|
|
|
|
|
0
|
$child->appendText(XML::LibXML::Boolean->True); |
|
12329
|
|
|
|
|
|
|
|
|
12330
|
|
|
|
|
|
|
} |
|
12331
|
|
|
|
|
|
|
|
|
12332
|
|
|
|
|
|
|
} |
|
12333
|
|
|
|
|
|
|
|
|
12334
|
|
|
|
|
|
|
# if 'DeviceColorValues' |
|
12335
|
|
|
|
|
|
|
} elsif ($t->[2] =~ m/^$ns:DeviceColorValues\//) { |
|
12336
|
|
|
|
|
|
|
|
|
12337
|
|
|
|
|
|
|
# set attributes hash |
|
12338
|
0
|
|
|
|
|
0
|
$t->[5]{'ColorSpecification'} = 'Unknown'; |
|
12339
|
|
|
|
|
|
|
|
|
12340
|
|
|
|
|
|
|
# increment 'ColorSpecification' hash |
|
12341
|
0
|
|
|
|
|
0
|
$cspec{'Unknown'}++; |
|
12342
|
|
|
|
|
|
|
|
|
12343
|
|
|
|
|
|
|
} |
|
12344
|
|
|
|
|
|
|
|
|
12345
|
|
|
|
|
|
|
} |
|
12346
|
|
|
|
|
|
|
|
|
12347
|
|
|
|
|
|
|
} |
|
12348
|
|
|
|
|
|
|
|
|
12349
|
|
|
|
|
|
|
# unbind 'template' node |
|
12350
|
0
|
|
|
|
|
0
|
$template->unbindNode(); |
|
12351
|
|
|
|
|
|
|
|
|
12352
|
|
|
|
|
|
|
# unbind 'Unknown' node, if not referenced |
|
12353
|
0
|
0
|
|
|
|
0
|
$unknown->unbindNode() if (! $cspec{'Unknown'}); |
|
12354
|
|
|
|
|
|
|
|
|
12355
|
|
|
|
|
|
|
} |
|
12356
|
|
|
|
|
|
|
|
|
12357
|
|
|
|
|
|
|
# write CxF3 CustomResources nodes |
|
12358
|
|
|
|
|
|
|
# parameters: (object_reference, XPath_object, CxF3_prefix) |
|
12359
|
|
|
|
|
|
|
sub _writeCxF3customres { |
|
12360
|
|
|
|
|
|
|
|
|
12361
|
|
|
|
|
|
|
# get parameters |
|
12362
|
0
|
|
|
0
|
|
0
|
my ($self, $xpc, $ns) = @_; |
|
12363
|
|
|
|
|
|
|
|
|
12364
|
|
|
|
|
|
|
# local variables |
|
12365
|
0
|
|
|
|
|
0
|
my ($nsURI, $sic, $ms, $xrp, $ca); |
|
12366
|
0
|
|
|
|
|
0
|
my ($cnode, $snode, $mnode, $pnode); |
|
12367
|
|
|
|
|
|
|
|
|
12368
|
|
|
|
|
|
|
# find the CustomResources node |
|
12369
|
0
|
|
|
|
|
0
|
($cnode) = $xpc->findnodes("$ns:CustomResources"); |
|
12370
|
|
|
|
|
|
|
|
|
12371
|
|
|
|
|
|
|
# if object header has 'sic:SpotInkCharacterisation' key |
|
12372
|
0
|
0
|
|
|
|
0
|
if (defined($sic = $self->[0]{'sic:SpotInkCharacterisation'})) { |
|
12373
|
|
|
|
|
|
|
|
|
12374
|
|
|
|
|
|
|
# set namespace URI |
|
12375
|
0
|
|
|
|
|
0
|
$nsURI = 'http://colorexchangeformat.com/CxF3-SpotInkCharacterisation'; |
|
12376
|
|
|
|
|
|
|
|
|
12377
|
|
|
|
|
|
|
# add sic:SpotInkCharacterisation node |
|
12378
|
0
|
|
|
|
|
0
|
$snode = _writeCxF3node($cnode, $xpc, 'sic:SpotInkCharacterisation', undef, $sic, $nsURI, 'sic'); |
|
12379
|
|
|
|
|
|
|
|
|
12380
|
|
|
|
|
|
|
# if object header has 'sic:MeasurementSet' key |
|
12381
|
0
|
0
|
|
|
|
0
|
if (defined($ms = $self->[0]{'sic:MeasurementSet'})) { |
|
12382
|
|
|
|
|
|
|
|
|
12383
|
|
|
|
|
|
|
# for each measurement set |
|
12384
|
0
|
|
|
|
|
0
|
for my $key (keys(%{$ms})) { |
|
|
0
|
|
|
|
|
0
|
|
|
12385
|
|
|
|
|
|
|
|
|
12386
|
|
|
|
|
|
|
# add sic:MeasurementSet node |
|
12387
|
0
|
|
|
|
|
0
|
$mnode = _writeCxF3node($snode, $xpc, 'sic:MeasurementSet', undef, {'Background' => $key}); |
|
12388
|
|
|
|
|
|
|
|
|
12389
|
|
|
|
|
|
|
# for each measurement |
|
12390
|
0
|
|
|
|
|
0
|
for my $m (@{$ms->{$key}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12391
|
|
|
|
|
|
|
|
|
12392
|
|
|
|
|
|
|
# add sic:Measurement node |
|
12393
|
0
|
|
|
|
|
0
|
_writeCxF3node($mnode, $xpc, 'sic:Measurement', undef, $m); |
|
12394
|
|
|
|
|
|
|
|
|
12395
|
|
|
|
|
|
|
} |
|
12396
|
|
|
|
|
|
|
|
|
12397
|
|
|
|
|
|
|
} |
|
12398
|
|
|
|
|
|
|
|
|
12399
|
|
|
|
|
|
|
} |
|
12400
|
|
|
|
|
|
|
|
|
12401
|
|
|
|
|
|
|
} |
|
12402
|
|
|
|
|
|
|
|
|
12403
|
|
|
|
|
|
|
# if object header has 'xrp:Prism' key |
|
12404
|
0
|
0
|
|
|
|
0
|
if (defined($xrp = $self->[0]{'xrp:Prism'})) { |
|
12405
|
|
|
|
|
|
|
|
|
12406
|
|
|
|
|
|
|
# set namespace URI |
|
12407
|
0
|
|
|
|
|
0
|
$nsURI = 'http://www.xrite.com/products/prism'; |
|
12408
|
|
|
|
|
|
|
|
|
12409
|
|
|
|
|
|
|
# add xrp:Prism node |
|
12410
|
0
|
|
|
|
|
0
|
$pnode = _writeCxF3node($cnode, $xpc, 'xrp:Prism', undef, $xrp, $nsURI, 'xrp'); |
|
12411
|
|
|
|
|
|
|
|
|
12412
|
|
|
|
|
|
|
# if object header has 'xrp:CustomAttributes' key |
|
12413
|
0
|
0
|
|
|
|
0
|
if (defined($ca = $self->[0]{'xrp:CustomAttributes'})) { |
|
12414
|
|
|
|
|
|
|
|
|
12415
|
|
|
|
|
|
|
# add xrp:CustomAttributes node |
|
12416
|
0
|
|
|
|
|
0
|
_writeCxF3node($pnode, $xpc, 'xrp:CustomAttributes', undef, $ca); |
|
12417
|
|
|
|
|
|
|
|
|
12418
|
|
|
|
|
|
|
} |
|
12419
|
|
|
|
|
|
|
|
|
12420
|
|
|
|
|
|
|
} |
|
12421
|
|
|
|
|
|
|
|
|
12422
|
|
|
|
|
|
|
} |
|
12423
|
|
|
|
|
|
|
|
|
12424
|
|
|
|
|
|
|
# write CxF3 node |
|
12425
|
|
|
|
|
|
|
# adds nodes to complete the XPath, as necessary |
|
12426
|
|
|
|
|
|
|
# text and attributes, if defined, are added to the last node |
|
12427
|
|
|
|
|
|
|
# the namespace of the added nodes may be specified, if different from the base node |
|
12428
|
|
|
|
|
|
|
# parameters: (base_node, XPath_object, XPath, text, attribute_hash, [namespace_URI, namespace_prefix]) |
|
12429
|
|
|
|
|
|
|
# returns: (last_node) |
|
12430
|
|
|
|
|
|
|
sub _writeCxF3node { |
|
12431
|
|
|
|
|
|
|
|
|
12432
|
|
|
|
|
|
|
# get parameters |
|
12433
|
0
|
|
|
0
|
|
0
|
my ($base, $xpc, $xpath, $text, $attr, $nsURI, $ns) = @_; |
|
12434
|
|
|
|
|
|
|
|
|
12435
|
|
|
|
|
|
|
# local variables |
|
12436
|
0
|
|
|
|
|
0
|
my (@seg, $node); |
|
12437
|
|
|
|
|
|
|
|
|
12438
|
|
|
|
|
|
|
# if the namespace URI and prefix are supplied |
|
12439
|
0
|
0
|
0
|
|
|
0
|
if (defined($nsURI) && defined($ns)) { |
|
12440
|
|
|
|
|
|
|
|
|
12441
|
|
|
|
|
|
|
# register supplied namespace |
|
12442
|
0
|
|
|
|
|
0
|
$xpc->registerNs($ns, $nsURI); |
|
12443
|
|
|
|
|
|
|
|
|
12444
|
|
|
|
|
|
|
} else { |
|
12445
|
|
|
|
|
|
|
|
|
12446
|
|
|
|
|
|
|
# use the base namespace prefix and URI |
|
12447
|
0
|
|
|
|
|
0
|
$ns = $base->prefix(); |
|
12448
|
0
|
|
|
|
|
0
|
$nsURI = $base->namespaceURI(); |
|
12449
|
|
|
|
|
|
|
|
|
12450
|
|
|
|
|
|
|
} |
|
12451
|
|
|
|
|
|
|
|
|
12452
|
|
|
|
|
|
|
# split XPath into segments |
|
12453
|
0
|
|
|
|
|
0
|
@seg = split('/', $xpath); |
|
12454
|
|
|
|
|
|
|
|
|
12455
|
|
|
|
|
|
|
# for each XPath segment |
|
12456
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#seg) { |
|
12457
|
|
|
|
|
|
|
|
|
12458
|
|
|
|
|
|
|
# get next node in Xpath |
|
12459
|
0
|
|
|
|
|
0
|
($node) = $xpc->findnodes($seg[$i], $base); |
|
12460
|
|
|
|
|
|
|
|
|
12461
|
|
|
|
|
|
|
# if node not found or last segment |
|
12462
|
0
|
0
|
0
|
|
|
0
|
if (! $node || $i == $#seg) { |
|
12463
|
|
|
|
|
|
|
|
|
12464
|
|
|
|
|
|
|
# add node |
|
12465
|
0
|
|
|
|
|
0
|
$node = $base->appendChild(XML::LibXML::Element->new($seg[$i])); |
|
12466
|
|
|
|
|
|
|
|
|
12467
|
|
|
|
|
|
|
# set node namespace |
|
12468
|
0
|
|
|
|
|
0
|
$node->setNamespace($nsURI, $ns); |
|
12469
|
|
|
|
|
|
|
|
|
12470
|
|
|
|
|
|
|
} |
|
12471
|
|
|
|
|
|
|
|
|
12472
|
|
|
|
|
|
|
# update base node |
|
12473
|
0
|
|
|
|
|
0
|
$base = $node; |
|
12474
|
|
|
|
|
|
|
|
|
12475
|
|
|
|
|
|
|
} |
|
12476
|
|
|
|
|
|
|
|
|
12477
|
|
|
|
|
|
|
# add text, if defined |
|
12478
|
0
|
0
|
|
|
|
0
|
$node->appendText($text) if (defined($text)); |
|
12479
|
|
|
|
|
|
|
|
|
12480
|
|
|
|
|
|
|
# if attributes defined |
|
12481
|
0
|
0
|
|
|
|
0
|
if (defined($attr)) { |
|
12482
|
|
|
|
|
|
|
|
|
12483
|
|
|
|
|
|
|
# for each attribute key |
|
12484
|
0
|
|
|
|
|
0
|
for (sort(keys(%{$attr}))) { |
|
|
0
|
|
|
|
|
0
|
|
|
12485
|
|
|
|
|
|
|
|
|
12486
|
|
|
|
|
|
|
# add attribute |
|
12487
|
0
|
|
|
|
|
0
|
$node->setAttribute($_, $attr->{$_}); |
|
12488
|
|
|
|
|
|
|
|
|
12489
|
|
|
|
|
|
|
} |
|
12490
|
|
|
|
|
|
|
|
|
12491
|
|
|
|
|
|
|
} |
|
12492
|
|
|
|
|
|
|
|
|
12493
|
|
|
|
|
|
|
# return added node |
|
12494
|
0
|
|
|
|
|
0
|
return($node); |
|
12495
|
|
|
|
|
|
|
|
|
12496
|
|
|
|
|
|
|
} |
|
12497
|
|
|
|
|
|
|
|
|
12498
|
|
|
|
|
|
|
# validate CxF3 document |
|
12499
|
|
|
|
|
|
|
# prints warning and error info |
|
12500
|
|
|
|
|
|
|
# parameters: (document_reference) |
|
12501
|
|
|
|
|
|
|
sub _validateCxF3 { |
|
12502
|
|
|
|
|
|
|
|
|
12503
|
|
|
|
|
|
|
# get document reference |
|
12504
|
0
|
|
|
0
|
|
0
|
my $doc = shift(); |
|
12505
|
|
|
|
|
|
|
|
|
12506
|
|
|
|
|
|
|
# load CxF3 schema |
|
12507
|
0
|
|
|
|
|
0
|
state $xmlschema = XML::LibXML::Schema->new('location' => ICC::Shared::getICCPath('Templates/CxF3_Core.xsd')); |
|
12508
|
|
|
|
|
|
|
|
|
12509
|
|
|
|
|
|
|
# validate the document |
|
12510
|
0
|
0
|
|
|
|
0
|
if (! defined(eval {$xmlschema->validate($doc)})) { |
|
|
0
|
|
|
|
|
0
|
|
|
12511
|
|
|
|
|
|
|
|
|
12512
|
|
|
|
|
|
|
# print warning on failure |
|
12513
|
0
|
|
|
|
|
0
|
print "warning: invalid CxF3 document\n$@\n"; |
|
12514
|
|
|
|
|
|
|
|
|
12515
|
|
|
|
|
|
|
} |
|
12516
|
|
|
|
|
|
|
|
|
12517
|
|
|
|
|
|
|
} |
|
12518
|
|
|
|
|
|
|
|
|
12519
|
|
|
|
|
|
|
# make patch set |
|
12520
|
|
|
|
|
|
|
# supported hash keys: 'colorspace', 'template', 'sort', 'limit' |
|
12521
|
|
|
|
|
|
|
# parameters: (object_reference, hash) |
|
12522
|
|
|
|
|
|
|
# returns: (result) |
|
12523
|
|
|
|
|
|
|
sub _makePatchSet { |
|
12524
|
|
|
|
|
|
|
|
|
12525
|
|
|
|
|
|
|
# get parameters |
|
12526
|
0
|
|
|
0
|
|
0
|
my ($self, $hash) = @_; |
|
12527
|
|
|
|
|
|
|
|
|
12528
|
|
|
|
|
|
|
# local variables |
|
12529
|
0
|
|
|
|
|
0
|
my ($cs, $template, $sort, $tac, $n, $data, $eps); |
|
12530
|
0
|
|
|
|
|
0
|
my (@fields, $loop, $limit, @inc, $init, $s, $code); |
|
12531
|
|
|
|
|
|
|
|
|
12532
|
|
|
|
|
|
|
# get the colorspace parameter |
|
12533
|
0
|
0
|
|
|
|
0
|
(defined($cs = $hash->{'colorspace'})) || return('colorspace parameter missing'); |
|
12534
|
|
|
|
|
|
|
|
|
12535
|
|
|
|
|
|
|
# get the template parameter |
|
12536
|
0
|
0
|
|
|
|
0
|
(defined($template = $hash->{'template'})) || return('template parameter missing'); |
|
12537
|
|
|
|
|
|
|
|
|
12538
|
|
|
|
|
|
|
# get the sort parameter (optional) |
|
12539
|
0
|
|
|
|
|
0
|
$sort = $hash->{'sort'}; |
|
12540
|
|
|
|
|
|
|
|
|
12541
|
|
|
|
|
|
|
# get the ink limit parameter (optional) |
|
12542
|
0
|
|
|
|
|
0
|
$tac = $hash->{'limit'}; |
|
12543
|
|
|
|
|
|
|
|
|
12544
|
|
|
|
|
|
|
# get number of elements in first group |
|
12545
|
0
|
|
|
|
|
0
|
$n = @{$template->[0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
12546
|
|
|
|
|
|
|
|
|
12547
|
|
|
|
|
|
|
# for each group |
|
12548
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$template}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12549
|
|
|
|
|
|
|
|
|
12550
|
|
|
|
|
|
|
# verify number of elements |
|
12551
|
0
|
0
|
|
|
|
0
|
($n == @{$template->[$i]}) || return("wrong number of elements in template group $i"); |
|
|
0
|
|
|
|
|
0
|
|
|
12552
|
|
|
|
|
|
|
|
|
12553
|
|
|
|
|
|
|
# verify number of array references |
|
12554
|
0
|
0
|
|
|
|
0
|
($n == grep {ref() eq 'ARRAY'} @{$template->[$i]}) || return("non-array element(s) in template group $i"); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12555
|
|
|
|
|
|
|
|
|
12556
|
|
|
|
|
|
|
# for each element |
|
12557
|
0
|
|
|
|
|
0
|
for my $j (0 .. $#{$template->[$i]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12558
|
|
|
|
|
|
|
|
|
12559
|
|
|
|
|
|
|
# verify element contains only numeric scalars |
|
12560
|
0
|
0
|
0
|
|
|
0
|
(@{$template->[$i][$j]} > 0 && @{$template->[$i][$j]} == grep {! ref() && Scalar::Util::looks_like_number($_)} @{$template->[$i][$j]}) || return("non-numeric element in template group $i, $j"); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12561
|
|
|
|
|
|
|
|
|
12562
|
|
|
|
|
|
|
} |
|
12563
|
|
|
|
|
|
|
|
|
12564
|
|
|
|
|
|
|
} |
|
12565
|
|
|
|
|
|
|
|
|
12566
|
|
|
|
|
|
|
# if RGB colorspace |
|
12567
|
0
|
0
|
|
|
|
0
|
if ($cs eq 'RGB') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12568
|
|
|
|
|
|
|
|
|
12569
|
|
|
|
|
|
|
# verify number of channels |
|
12570
|
0
|
0
|
|
|
|
0
|
($n == 3) || return('wrong number of template elements for RGB colorspace'); |
|
12571
|
|
|
|
|
|
|
|
|
12572
|
|
|
|
|
|
|
# set fields |
|
12573
|
0
|
|
|
|
|
0
|
@fields = qw(RGB_R RGB_G RGB_B); |
|
12574
|
|
|
|
|
|
|
|
|
12575
|
|
|
|
|
|
|
# if CMYK colorspace |
|
12576
|
|
|
|
|
|
|
} elsif ($cs eq 'CMYK') { |
|
12577
|
|
|
|
|
|
|
|
|
12578
|
|
|
|
|
|
|
# verify number of channels |
|
12579
|
0
|
0
|
|
|
|
0
|
($n == 4) || return('wrong number of template elements for CMYK colorspace'); |
|
12580
|
|
|
|
|
|
|
|
|
12581
|
|
|
|
|
|
|
# set fields |
|
12582
|
0
|
|
|
|
|
0
|
@fields = qw(CMYK_C CMYK_M CMYK_Y CMYK_K); |
|
12583
|
|
|
|
|
|
|
|
|
12584
|
|
|
|
|
|
|
# if nCLR colorspace |
|
12585
|
|
|
|
|
|
|
} elsif ($cs eq 'nCLR') { |
|
12586
|
|
|
|
|
|
|
|
|
12587
|
|
|
|
|
|
|
# verify number of channels |
|
12588
|
0
|
0
|
0
|
|
|
0
|
($n > 0 && $n < 16) || return('wrong number of template elements for nCLR colorspace'); |
|
12589
|
|
|
|
|
|
|
|
|
12590
|
|
|
|
|
|
|
# set fields |
|
12591
|
0
|
|
|
|
|
0
|
@fields = map {$n . "CLR_$_"} (1 .. $n); |
|
|
0
|
|
|
|
|
0
|
|
|
12592
|
|
|
|
|
|
|
|
|
12593
|
|
|
|
|
|
|
# if L*a*b* colorspace |
|
12594
|
|
|
|
|
|
|
} elsif ($cs eq 'Lab') { |
|
12595
|
|
|
|
|
|
|
|
|
12596
|
|
|
|
|
|
|
# verify number of channels |
|
12597
|
0
|
0
|
|
|
|
0
|
($n == 3) || return('wrong number of template elements for L*a*b* colorspace'); |
|
12598
|
|
|
|
|
|
|
|
|
12599
|
|
|
|
|
|
|
# set fields |
|
12600
|
0
|
|
|
|
|
0
|
@fields = qw(LAB_L LAB_A LAB_B); |
|
12601
|
|
|
|
|
|
|
|
|
12602
|
|
|
|
|
|
|
} else { |
|
12603
|
|
|
|
|
|
|
|
|
12604
|
|
|
|
|
|
|
# error |
|
12605
|
0
|
|
|
|
|
0
|
return('invalid colorspace parameter'); |
|
12606
|
|
|
|
|
|
|
|
|
12607
|
|
|
|
|
|
|
} |
|
12608
|
|
|
|
|
|
|
|
|
12609
|
|
|
|
|
|
|
# make loop variable list |
|
12610
|
0
|
|
|
|
|
0
|
$loop = join(', ', map {"\$i$_"} (0 .. $n - 1)); |
|
|
0
|
|
|
|
|
0
|
|
|
12611
|
|
|
|
|
|
|
|
|
12612
|
|
|
|
|
|
|
# make initial code fragment |
|
12613
|
0
|
|
|
|
|
0
|
$init = "\$data->[\$s++] = [$loop]"; |
|
12614
|
|
|
|
|
|
|
|
|
12615
|
|
|
|
|
|
|
# initialize index |
|
12616
|
0
|
|
|
|
|
0
|
$s = 0; |
|
12617
|
|
|
|
|
|
|
|
|
12618
|
|
|
|
|
|
|
# for each group |
|
12619
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$template}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12620
|
|
|
|
|
|
|
|
|
12621
|
|
|
|
|
|
|
# copy initial code fragment |
|
12622
|
0
|
|
|
|
|
0
|
$code = $init; |
|
12623
|
|
|
|
|
|
|
|
|
12624
|
|
|
|
|
|
|
# for each device channel (in reverse order) |
|
12625
|
0
|
|
|
|
|
0
|
for my $j (reverse(0 .. $#{$template->[$i]})) { |
|
|
0
|
|
|
|
|
0
|
|
|
12626
|
|
|
|
|
|
|
|
|
12627
|
|
|
|
|
|
|
# add loop code to fragment |
|
12628
|
0
|
|
|
|
|
0
|
$code = "for my \$i$j (" . join(', ', @{$template->[$i][$j]}) . ") {$code}"; |
|
|
0
|
|
|
|
|
0
|
|
|
12629
|
|
|
|
|
|
|
|
|
12630
|
|
|
|
|
|
|
} |
|
12631
|
|
|
|
|
|
|
|
|
12632
|
|
|
|
|
|
|
# evaluate code fragment |
|
12633
|
0
|
|
|
|
|
0
|
eval($code); |
|
12634
|
|
|
|
|
|
|
|
|
12635
|
|
|
|
|
|
|
} |
|
12636
|
|
|
|
|
|
|
|
|
12637
|
|
|
|
|
|
|
# if ink limit defined and color space is CMYK or nCLR |
|
12638
|
0
|
0
|
0
|
|
|
0
|
if (defined($tac) && ($cs eq 'CMYK' || $cs eq 'nCLR')) { |
|
|
|
|
0
|
|
|
|
|
|
12639
|
|
|
|
|
|
|
|
|
12640
|
|
|
|
|
|
|
# compute max comparison error |
|
12641
|
0
|
|
|
|
|
0
|
$eps = 1E-12; |
|
12642
|
|
|
|
|
|
|
|
|
12643
|
|
|
|
|
|
|
# verify ink limit is a number |
|
12644
|
0
|
0
|
0
|
|
|
0
|
if (! ref($tac) && Scalar::Util::looks_like_number($tac)) { |
|
12645
|
|
|
|
|
|
|
|
|
12646
|
|
|
|
|
|
|
# for each patch |
|
12647
|
0
|
|
|
|
|
0
|
for (@{$data}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12648
|
|
|
|
|
|
|
|
|
12649
|
|
|
|
|
|
|
# add the total ink value |
|
12650
|
0
|
|
|
|
|
0
|
push(@{$_}, List::Util::sum(@{$_})); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12651
|
|
|
|
|
|
|
|
|
12652
|
|
|
|
|
|
|
} |
|
12653
|
|
|
|
|
|
|
|
|
12654
|
|
|
|
|
|
|
# make sort code fragment (sorts in ascending order by columns K ... total_ink_value) |
|
12655
|
0
|
|
|
|
|
0
|
$code = '@{$data} = sort {' . join(' || ', map {"\$a->[$_] <=> \$b->[$_]"} (3 .. $n)) . '} @{$data}'; |
|
|
0
|
|
|
|
|
0
|
|
|
12656
|
|
|
|
|
|
|
|
|
12657
|
|
|
|
|
|
|
# sort data |
|
12658
|
0
|
|
|
|
|
0
|
eval($code); |
|
12659
|
|
|
|
|
|
|
|
|
12660
|
|
|
|
|
|
|
# for each patch |
|
12661
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$data}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12662
|
|
|
|
|
|
|
|
|
12663
|
|
|
|
|
|
|
# undefine limit if new group (different black or spot values) |
|
12664
|
0
|
0
|
|
|
|
0
|
undef($limit) if (grep {$data->[$i][$_] != $data->[$i ? $i - 1 : 0][$_]} (3 .. $n - 1)); |
|
|
0
|
0
|
|
|
|
0
|
|
|
12665
|
|
|
|
|
|
|
|
|
12666
|
|
|
|
|
|
|
# select patch if limit undefined or total ink <= limit or a CMY corner point |
|
12667
|
0
|
0
|
0
|
|
|
0
|
push(@inc, [@{$data->[$i]}[0 .. $n - 1]]) if (! defined($limit) || ($data->[$i][-1] - $limit <= $eps) || ((grep {$data->[$i][$_] == 0} (0 .. 2)) && (grep {$data->[$i][$_] == 100} (0 .. 2)))); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12668
|
|
|
|
|
|
|
|
|
12669
|
|
|
|
|
|
|
# set limit if undefined and total ink > TAC |
|
12670
|
0
|
0
|
0
|
|
|
0
|
$limit = $data->[$i][-1] if (! defined($limit) && $data->[$i][-1] - $tac > $eps); |
|
12671
|
|
|
|
|
|
|
|
|
12672
|
|
|
|
|
|
|
} |
|
12673
|
|
|
|
|
|
|
|
|
12674
|
|
|
|
|
|
|
# set data to selected patches |
|
12675
|
0
|
|
|
|
|
0
|
$data = \@inc; |
|
12676
|
|
|
|
|
|
|
|
|
12677
|
|
|
|
|
|
|
} else { |
|
12678
|
|
|
|
|
|
|
|
|
12679
|
|
|
|
|
|
|
# display warning |
|
12680
|
0
|
|
|
|
|
0
|
carp("invalid ink limit parameter, ink limiting failed\n"); |
|
12681
|
|
|
|
|
|
|
|
|
12682
|
|
|
|
|
|
|
} |
|
12683
|
|
|
|
|
|
|
|
|
12684
|
|
|
|
|
|
|
} |
|
12685
|
|
|
|
|
|
|
|
|
12686
|
|
|
|
|
|
|
# if sort parameter defined |
|
12687
|
0
|
0
|
|
|
|
0
|
if (defined($sort)) { |
|
12688
|
|
|
|
|
|
|
|
|
12689
|
|
|
|
|
|
|
# verify sort parameter |
|
12690
|
0
|
0
|
0
|
|
|
0
|
if (ICC::Shared::is_num_vector($sort) && @{$sort} == grep {$_ && $_ == int($_) && abs($_) <= @{$data->[0]}} @{$sort}) { |
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12691
|
|
|
|
|
|
|
|
|
12692
|
|
|
|
|
|
|
# make sort code fragment |
|
12693
|
0
|
0
|
|
|
|
0
|
$code = '@{$data} = sort {' . join(' || ', map {my $dir = m/-/; my $col = abs($_) - 1; $dir ? "\$b->[$col] <=> \$a->[$col]" : "\$a->[$col] <=> \$b->[$col]"} @{$sort}) . '} @{$data}'; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12694
|
|
|
|
|
|
|
|
|
12695
|
|
|
|
|
|
|
# evaluate code fragment |
|
12696
|
0
|
|
|
|
|
0
|
eval($code); |
|
12697
|
|
|
|
|
|
|
|
|
12698
|
|
|
|
|
|
|
} else { |
|
12699
|
|
|
|
|
|
|
|
|
12700
|
|
|
|
|
|
|
# display warning |
|
12701
|
0
|
|
|
|
|
0
|
carp("invalid sort parameter, sorting failed\n"); |
|
12702
|
|
|
|
|
|
|
|
|
12703
|
|
|
|
|
|
|
} |
|
12704
|
|
|
|
|
|
|
|
|
12705
|
|
|
|
|
|
|
} |
|
12706
|
|
|
|
|
|
|
|
|
12707
|
|
|
|
|
|
|
# add format fields |
|
12708
|
0
|
|
|
|
|
0
|
unshift(@{$data}, [@fields]); |
|
|
0
|
|
|
|
|
0
|
|
|
12709
|
|
|
|
|
|
|
|
|
12710
|
|
|
|
|
|
|
# set object reference |
|
12711
|
0
|
|
|
|
|
0
|
$self->[1] = $data; |
|
12712
|
|
|
|
|
|
|
|
|
12713
|
|
|
|
|
|
|
# return |
|
12714
|
0
|
|
|
|
|
0
|
return(); |
|
12715
|
|
|
|
|
|
|
|
|
12716
|
|
|
|
|
|
|
} |
|
12717
|
|
|
|
|
|
|
|
|
12718
|
|
|
|
|
|
|
# make Time::Piece object from text string |
|
12719
|
|
|
|
|
|
|
# parses most common date/time notations |
|
12720
|
|
|
|
|
|
|
# no object returned if parsing fails |
|
12721
|
|
|
|
|
|
|
# parameter: (string -or- value) |
|
12722
|
|
|
|
|
|
|
# returns: (object) |
|
12723
|
|
|
|
|
|
|
sub _makeTimePiece { |
|
12724
|
|
|
|
|
|
|
|
|
12725
|
|
|
|
|
|
|
# get parameter |
|
12726
|
0
|
|
|
0
|
|
0
|
my $str = shift(); |
|
12727
|
|
|
|
|
|
|
|
|
12728
|
|
|
|
|
|
|
# local variables |
|
12729
|
0
|
|
|
|
|
0
|
my ($parse, $fmt, $hr, $sec, $month); |
|
12730
|
|
|
|
|
|
|
|
|
12731
|
|
|
|
|
|
|
# if a numeric value (Unix time) |
|
12732
|
0
|
0
|
|
|
|
0
|
if (Scalar::Util::looks_like_number($str)) { |
|
12733
|
|
|
|
|
|
|
|
|
12734
|
|
|
|
|
|
|
# return Time::Piece object from Unix time |
|
12735
|
0
|
|
|
|
|
0
|
return(scalar(localtime($str))); |
|
12736
|
|
|
|
|
|
|
|
|
12737
|
|
|
|
|
|
|
} else { |
|
12738
|
|
|
|
|
|
|
|
|
12739
|
|
|
|
|
|
|
# if UTC offset matched (time string ends in '+/-hh:mm', '+/-hhmm', or '+/-hh') |
|
12740
|
0
|
0
|
|
|
|
0
|
if ($str =~ s/(T[\d:]+)([+-]\d{2}):?(\d{2})?/$1/) { |
|
|
|
0
|
|
|
|
|
|
|
12741
|
|
|
|
|
|
|
|
|
12742
|
|
|
|
|
|
|
# set UTC offset to matched value |
|
12743
|
0
|
0
|
|
|
|
0
|
$parse = $2 . (defined($3) ? $3 : '00'); |
|
12744
|
|
|
|
|
|
|
|
|
12745
|
|
|
|
|
|
|
# set UTC format |
|
12746
|
0
|
|
|
|
|
0
|
$fmt = '%z'; |
|
12747
|
|
|
|
|
|
|
|
|
12748
|
|
|
|
|
|
|
# if Zulu time (time string ends in 'Z') |
|
12749
|
|
|
|
|
|
|
} elsif ($str =~ s/(T[\d:]+)Z/$1/) { |
|
12750
|
|
|
|
|
|
|
|
|
12751
|
|
|
|
|
|
|
# set UTC offset to 0 |
|
12752
|
0
|
|
|
|
|
0
|
$parse = '+0000'; |
|
12753
|
|
|
|
|
|
|
|
|
12754
|
|
|
|
|
|
|
# set UTC format |
|
12755
|
0
|
|
|
|
|
0
|
$fmt = '%z'; |
|
12756
|
|
|
|
|
|
|
|
|
12757
|
|
|
|
|
|
|
} else { |
|
12758
|
|
|
|
|
|
|
|
|
12759
|
|
|
|
|
|
|
# initialize strings |
|
12760
|
0
|
|
|
|
|
0
|
$parse = $fmt = ''; |
|
12761
|
|
|
|
|
|
|
|
|
12762
|
|
|
|
|
|
|
} |
|
12763
|
|
|
|
|
|
|
|
|
12764
|
|
|
|
|
|
|
# if time matched (time string 'hh:mm' or 'hh:mm:ss', 'AM' or 'PM' optional) |
|
12765
|
0
|
0
|
|
|
|
0
|
if ($str =~ s/(\d{1,2})(:\d{1,2})(:\d{1,2})?\s*(AM|PM)?//) { |
|
12766
|
|
|
|
|
|
|
|
|
12767
|
|
|
|
|
|
|
# if 12 AM |
|
12768
|
0
|
0
|
0
|
|
|
0
|
if (defined($4) && $4 eq 'AM' && $1 == 12) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
12769
|
|
|
|
|
|
|
|
|
12770
|
|
|
|
|
|
|
# set hour |
|
12771
|
0
|
|
|
|
|
0
|
$hr = 0; |
|
12772
|
|
|
|
|
|
|
|
|
12773
|
|
|
|
|
|
|
# if 1 PM - 11 PM |
|
12774
|
|
|
|
|
|
|
} elsif (defined($4) && $4 eq 'PM' && $1 > 0 && $1 < 12) { |
|
12775
|
|
|
|
|
|
|
|
|
12776
|
|
|
|
|
|
|
# set hour |
|
12777
|
0
|
|
|
|
|
0
|
$hr = $1 + 12; |
|
12778
|
|
|
|
|
|
|
|
|
12779
|
|
|
|
|
|
|
} else { |
|
12780
|
|
|
|
|
|
|
|
|
12781
|
|
|
|
|
|
|
# set hour |
|
12782
|
0
|
|
|
|
|
0
|
$hr = $1; |
|
12783
|
|
|
|
|
|
|
|
|
12784
|
|
|
|
|
|
|
} |
|
12785
|
|
|
|
|
|
|
|
|
12786
|
|
|
|
|
|
|
# set seconds |
|
12787
|
0
|
0
|
|
|
|
0
|
$sec = defined($3) ? $3 : ':00'; |
|
12788
|
|
|
|
|
|
|
|
|
12789
|
|
|
|
|
|
|
# add time string |
|
12790
|
0
|
|
|
|
|
0
|
$parse = "T$hr$2$sec$parse"; |
|
12791
|
|
|
|
|
|
|
|
|
12792
|
|
|
|
|
|
|
# add time format |
|
12793
|
0
|
|
|
|
|
0
|
$fmt = "T%T$fmt"; |
|
12794
|
|
|
|
|
|
|
|
|
12795
|
|
|
|
|
|
|
} |
|
12796
|
|
|
|
|
|
|
|
|
12797
|
|
|
|
|
|
|
# if three number date matched |
|
12798
|
0
|
0
|
|
|
|
0
|
if ($str =~ m/(\d{1,4})[\/-](\d{1,2})[\/-](\d{1,4})/) { |
|
|
|
0
|
|
|
|
|
|
|
12799
|
|
|
|
|
|
|
|
|
12800
|
|
|
|
|
|
|
# if first value > 99 |
|
12801
|
0
|
0
|
|
|
|
0
|
if ($1 > 99) { |
|
|
|
0
|
|
|
|
|
|
|
12802
|
|
|
|
|
|
|
|
|
12803
|
|
|
|
|
|
|
# add date string |
|
12804
|
0
|
|
|
|
|
0
|
$parse = "$1-$2-$3$parse"; |
|
12805
|
|
|
|
|
|
|
|
|
12806
|
|
|
|
|
|
|
# if last value > 99 |
|
12807
|
|
|
|
|
|
|
} elsif ($3 > 99) { |
|
12808
|
|
|
|
|
|
|
|
|
12809
|
|
|
|
|
|
|
# add date string |
|
12810
|
0
|
|
|
|
|
0
|
$parse = "$3-$1-$2$parse"; |
|
12811
|
|
|
|
|
|
|
|
|
12812
|
|
|
|
|
|
|
# last value is two digit year |
|
12813
|
|
|
|
|
|
|
} else { |
|
12814
|
|
|
|
|
|
|
|
|
12815
|
|
|
|
|
|
|
# add date string |
|
12816
|
0
|
0
|
|
|
|
0
|
$parse = ($3 > 68 ? 1900 + $3 : 2000 + $3) . "-$1-$2$parse"; |
|
12817
|
|
|
|
|
|
|
|
|
12818
|
|
|
|
|
|
|
} |
|
12819
|
|
|
|
|
|
|
|
|
12820
|
|
|
|
|
|
|
# add date format |
|
12821
|
0
|
|
|
|
|
0
|
$fmt = "%Y-%m-%d$fmt"; |
|
12822
|
|
|
|
|
|
|
|
|
12823
|
|
|
|
|
|
|
# if text month matched |
|
12824
|
|
|
|
|
|
|
} elsif (uc($str) =~ m/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/) { |
|
12825
|
|
|
|
|
|
|
|
|
12826
|
|
|
|
|
|
|
# save month |
|
12827
|
0
|
|
|
|
|
0
|
$month = $1; |
|
12828
|
|
|
|
|
|
|
|
|
12829
|
|
|
|
|
|
|
# if two numbers matched |
|
12830
|
0
|
0
|
|
|
|
0
|
if ($str =~ m/(\d{1,4})[^\d]+(\d{1,4})/) { |
|
|
|
0
|
|
|
|
|
|
|
12831
|
|
|
|
|
|
|
|
|
12832
|
|
|
|
|
|
|
# if first value > 99 |
|
12833
|
0
|
0
|
|
|
|
0
|
if ($1 > 99) { |
|
|
|
0
|
|
|
|
|
|
|
12834
|
|
|
|
|
|
|
|
|
12835
|
|
|
|
|
|
|
# add date string |
|
12836
|
0
|
|
|
|
|
0
|
$parse = "$1-$month-$2$parse"; |
|
12837
|
|
|
|
|
|
|
|
|
12838
|
|
|
|
|
|
|
# if last value > 99 |
|
12839
|
|
|
|
|
|
|
} elsif ($2 > 99) { |
|
12840
|
|
|
|
|
|
|
|
|
12841
|
|
|
|
|
|
|
# add date string |
|
12842
|
0
|
|
|
|
|
0
|
$parse = "$2-$month-$1$parse"; |
|
12843
|
|
|
|
|
|
|
|
|
12844
|
|
|
|
|
|
|
# last value is two digit year |
|
12845
|
|
|
|
|
|
|
} else { |
|
12846
|
|
|
|
|
|
|
|
|
12847
|
|
|
|
|
|
|
# add date string |
|
12848
|
0
|
0
|
|
|
|
0
|
$parse = ($2 > 68 ? 1900 + $2 : 2000 + $2) . "/$month/$1$parse"; |
|
12849
|
|
|
|
|
|
|
|
|
12850
|
|
|
|
|
|
|
} |
|
12851
|
|
|
|
|
|
|
|
|
12852
|
|
|
|
|
|
|
# if one number matched |
|
12853
|
|
|
|
|
|
|
} elsif ($str =~ m/(\d{1,4})/) { |
|
12854
|
|
|
|
|
|
|
|
|
12855
|
|
|
|
|
|
|
# if value > 99 |
|
12856
|
0
|
0
|
|
|
|
0
|
if ($1 > 99) { |
|
12857
|
|
|
|
|
|
|
|
|
12858
|
|
|
|
|
|
|
# add date string |
|
12859
|
0
|
|
|
|
|
0
|
$parse = "$1-$month-1$parse"; |
|
12860
|
|
|
|
|
|
|
|
|
12861
|
|
|
|
|
|
|
} else { |
|
12862
|
|
|
|
|
|
|
|
|
12863
|
|
|
|
|
|
|
# add date string |
|
12864
|
0
|
0
|
|
|
|
0
|
$parse = ($1 > 68 ? 1900 + $1 : 2000 + $1) . "/$month/1$parse"; |
|
12865
|
|
|
|
|
|
|
|
|
12866
|
|
|
|
|
|
|
} |
|
12867
|
|
|
|
|
|
|
|
|
12868
|
|
|
|
|
|
|
} |
|
12869
|
|
|
|
|
|
|
|
|
12870
|
|
|
|
|
|
|
# add date format |
|
12871
|
0
|
|
|
|
|
0
|
$fmt = "%Y-%b-%d$fmt"; |
|
12872
|
|
|
|
|
|
|
|
|
12873
|
|
|
|
|
|
|
} |
|
12874
|
|
|
|
|
|
|
|
|
12875
|
|
|
|
|
|
|
# return Time::Piece object, if string parsed successfully |
|
12876
|
0
|
0
|
|
|
|
0
|
return(Time::Piece->strptime($parse, $fmt)) if (length($parse)); |
|
12877
|
|
|
|
|
|
|
|
|
12878
|
|
|
|
|
|
|
} |
|
12879
|
|
|
|
|
|
|
|
|
12880
|
|
|
|
|
|
|
} |
|
12881
|
|
|
|
|
|
|
|
|
12882
|
|
|
|
|
|
|
# get file list |
|
12883
|
|
|
|
|
|
|
# uses Perl 'bsd_glob' function |
|
12884
|
|
|
|
|
|
|
# parameter: (path) |
|
12885
|
|
|
|
|
|
|
# returns: (ref_to_file_list) |
|
12886
|
|
|
|
|
|
|
sub _files { |
|
12887
|
|
|
|
|
|
|
|
|
12888
|
|
|
|
|
|
|
# get path |
|
12889
|
21
|
|
|
21
|
|
33
|
my $path = shift(); |
|
12890
|
|
|
|
|
|
|
|
|
12891
|
|
|
|
|
|
|
# replace '~~' with 'ICC' directory path |
|
12892
|
21
|
|
|
|
|
48
|
$path =~ s/^~~/ICC::Shared::getICCPath()/e; |
|
|
0
|
|
|
|
|
0
|
|
|
12893
|
|
|
|
|
|
|
|
|
12894
|
|
|
|
|
|
|
# get list of files and/or directories |
|
12895
|
21
|
|
|
|
|
641
|
my @files = File::Glob::bsd_glob($path); |
|
12896
|
|
|
|
|
|
|
|
|
12897
|
|
|
|
|
|
|
# if list is just one directory |
|
12898
|
21
|
100
|
66
|
|
|
302
|
if (@files == 1 && -d $files[0]) { |
|
12899
|
|
|
|
|
|
|
|
|
12900
|
|
|
|
|
|
|
# get files in that directory |
|
12901
|
2
|
|
|
|
|
215
|
@files = grep {-f} File::Glob::bsd_glob("$path/*"); |
|
|
8
|
|
|
|
|
95
|
|
|
12902
|
|
|
|
|
|
|
|
|
12903
|
|
|
|
|
|
|
} else { |
|
12904
|
|
|
|
|
|
|
|
|
12905
|
|
|
|
|
|
|
# filter the files |
|
12906
|
19
|
|
|
|
|
60
|
@files = grep {-f} @files; |
|
|
19
|
|
|
|
|
225
|
|
|
12907
|
|
|
|
|
|
|
|
|
12908
|
|
|
|
|
|
|
} |
|
12909
|
|
|
|
|
|
|
|
|
12910
|
|
|
|
|
|
|
# return file list |
|
12911
|
21
|
|
|
|
|
77
|
return(\@files); |
|
12912
|
|
|
|
|
|
|
|
|
12913
|
|
|
|
|
|
|
} |
|
12914
|
|
|
|
|
|
|
|
|
12915
|
|
|
|
|
|
|
# compute Mahalanobis distance |
|
12916
|
|
|
|
|
|
|
# assumes parameters are valid |
|
12917
|
|
|
|
|
|
|
# parameters: (vector1, vector2, inverse_covariance_matrix) |
|
12918
|
|
|
|
|
|
|
# returns: (distance) |
|
12919
|
|
|
|
|
|
|
sub _mahal { |
|
12920
|
|
|
|
|
|
|
|
|
12921
|
|
|
|
|
|
|
# get parameters |
|
12922
|
0
|
|
|
0
|
|
0
|
my ($x, $y, $sinv) = @_; |
|
12923
|
|
|
|
|
|
|
|
|
12924
|
|
|
|
|
|
|
# local variables |
|
12925
|
0
|
|
|
|
|
0
|
my ($d, $dT); |
|
12926
|
|
|
|
|
|
|
|
|
12927
|
|
|
|
|
|
|
# for each dimension |
|
12928
|
0
|
|
|
|
|
0
|
for my $i (0 .. $#{$x}) { |
|
|
0
|
|
|
|
|
0
|
|
|
12929
|
|
|
|
|
|
|
|
|
12930
|
|
|
|
|
|
|
# save difference |
|
12931
|
0
|
|
|
|
|
0
|
$d->[0][$i] = $dT->[$i][0] = $x->[$i] - $y->[$i]; |
|
12932
|
|
|
|
|
|
|
|
|
12933
|
|
|
|
|
|
|
} |
|
12934
|
|
|
|
|
|
|
|
|
12935
|
|
|
|
|
|
|
# bless matrices |
|
12936
|
0
|
|
|
|
|
0
|
bless($d, 'Math::Matrix'); |
|
12937
|
0
|
|
|
|
|
0
|
bless($dT, 'Math::Matrix'); |
|
12938
|
|
|
|
|
|
|
|
|
12939
|
|
|
|
|
|
|
# return Mahalanobis distance |
|
12940
|
0
|
|
|
|
|
0
|
return(sqrt(($d * $sinv * $dT)->[0][0])); |
|
12941
|
|
|
|
|
|
|
|
|
12942
|
|
|
|
|
|
|
} |
|
12943
|
|
|
|
|
|
|
|
|
12944
|
|
|
|
|
|
|
# get L*a*b* encoding code refs |
|
12945
|
|
|
|
|
|
|
# parameter: (object_reference, hash) |
|
12946
|
|
|
|
|
|
|
# returns: (get_code_ref, set_code_ref) |
|
12947
|
|
|
|
|
|
|
sub _lab_encoding { |
|
12948
|
|
|
|
|
|
|
|
|
12949
|
|
|
|
|
|
|
# get object reference |
|
12950
|
29
|
|
|
29
|
|
70
|
my ($self, $hash) = @_; |
|
12951
|
|
|
|
|
|
|
|
|
12952
|
|
|
|
|
|
|
# local variable |
|
12953
|
29
|
|
|
|
|
33
|
my ($encode); |
|
12954
|
|
|
|
|
|
|
|
|
12955
|
|
|
|
|
|
|
# get encoding parameter from hash |
|
12956
|
29
|
|
|
|
|
46
|
$encode = $hash->{'encoding'}; |
|
12957
|
|
|
|
|
|
|
|
|
12958
|
|
|
|
|
|
|
# if encoding parameter undefined |
|
12959
|
29
|
50
|
|
|
|
53
|
if (! defined($encode)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12960
|
|
|
|
|
|
|
|
|
12961
|
|
|
|
|
|
|
# return code refs (identity) |
|
12962
|
29
|
|
|
6
|
|
293
|
return(sub {@_}, sub {@_}); |
|
|
41
|
|
|
|
|
76
|
|
|
|
6
|
|
|
|
|
10
|
|
|
12963
|
|
|
|
|
|
|
|
|
12964
|
|
|
|
|
|
|
# if encoding is 8/16-bit ICC CIELAB |
|
12965
|
|
|
|
|
|
|
} elsif ($encode == 0) { |
|
12966
|
|
|
|
|
|
|
|
|
12967
|
|
|
|
|
|
|
# return code refs |
|
12968
|
0
|
0
|
|
0
|
|
0
|
return(sub {defined($_[0]) ? $_[0] / 100 : $_[0], defined($_[1]) ? ($_[1] + 128)/255 : $_[1], defined($_[2]) ? ($_[2] + 128)/255 : $_[2]}, |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12969
|
0
|
0
|
|
0
|
|
0
|
sub {defined($_[0]) ? $_[0] * 100 : $_[0], defined($_[1]) ? $_[1] * 255 - 128 : $_[1], defined($_[2]) ? $_[2] * 255 - 128 : $_[2]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
12970
|
|
|
|
|
|
|
|
|
12971
|
|
|
|
|
|
|
# if encoding is 16-bit ICC legacy L*a*b* |
|
12972
|
|
|
|
|
|
|
} elsif ($encode == 1) { |
|
12973
|
|
|
|
|
|
|
|
|
12974
|
|
|
|
|
|
|
# return code refs |
|
12975
|
0
|
0
|
|
0
|
|
0
|
return(sub {defined($_[0]) ? $_[0] * 256/25700 : $_[0], defined($_[1]) ? ($_[1] + 128) * 256/65535 : $_[1], defined($_[2]) ? ($_[2] + 128) * 256/65535 : $_[2]}, |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12976
|
0
|
0
|
|
0
|
|
0
|
sub {defined($_[0]) ? $_[0] * 25700/256 : $_[0], defined($_[1]) ? $_[1] * 65535/256 - 128 : $_[1], defined($_[2]) ? $_[2] * 65535/256 - 128 : $_[2]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
12977
|
|
|
|
|
|
|
|
|
12978
|
|
|
|
|
|
|
# if encoding is 16-bit EFI/Monaco L*a*b* |
|
12979
|
|
|
|
|
|
|
} elsif ($encode == 2) { |
|
12980
|
|
|
|
|
|
|
|
|
12981
|
|
|
|
|
|
|
# return code refs |
|
12982
|
0
|
0
|
|
0
|
|
0
|
return(sub {defined($_[0]) ? $_[0]/100 : $_[0], defined($_[1]) ? ($_[1] + 128) * 256/65535 : $_[1], defined($_[2]) ? ($_[2] + 128) * 256/65535 : $_[2]}, |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12983
|
0
|
0
|
|
0
|
|
0
|
sub {defined($_[0]) ? $_[0] * 100 : $_[0], defined($_[1]) ? $_[1] * 65535/256 - 128 : $_[1], defined($_[2]) ? $_[2] * 65535/256 - 128 : $_[2]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
12984
|
|
|
|
|
|
|
|
|
12985
|
|
|
|
|
|
|
# if encoding is L*a*b* |
|
12986
|
|
|
|
|
|
|
} elsif ($encode == 3) { |
|
12987
|
|
|
|
|
|
|
|
|
12988
|
|
|
|
|
|
|
# return code refs (identity) |
|
12989
|
0
|
|
|
0
|
|
0
|
return(sub {@_}, sub {@_}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12990
|
|
|
|
|
|
|
|
|
12991
|
|
|
|
|
|
|
# if encoding is LxLyLz |
|
12992
|
|
|
|
|
|
|
} elsif ($encode == 4) { |
|
12993
|
|
|
|
|
|
|
|
|
12994
|
|
|
|
|
|
|
# return code refs |
|
12995
|
0
|
0
|
0
|
0
|
|
0
|
return(sub {if (defined($_[0]) && defined($_[1]) && defined($_[2])) {$_[0] + 116 * $_[1]/500, $_[0], $_[0] - 116 * $_[2]/200} else {@_}}, |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12996
|
0
|
0
|
0
|
0
|
|
0
|
sub {if (defined($_[0]) && defined($_[1]) && defined($_[2])) {$_[1], 500 * ($_[0] - $_[1])/116, 200 * ($_[1] - $_[2])/116} else {@_}}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
12997
|
|
|
|
|
|
|
|
|
12998
|
|
|
|
|
|
|
# if encoding is unit LxLyLz |
|
12999
|
|
|
|
|
|
|
} elsif ($encode == 5) { |
|
13000
|
|
|
|
|
|
|
|
|
13001
|
|
|
|
|
|
|
# return code refs |
|
13002
|
0
|
0
|
0
|
0
|
|
0
|
return(sub {if (defined($_[0]) && defined($_[1]) && defined($_[2])) {map {$_/100} ($_[0] + 116 * $_[1]/500, $_[0], $_[0] - 116 * $_[2]/200)} else {@_}}, |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
13003
|
0
|
0
|
0
|
0
|
|
0
|
sub {if (defined($_[0]) && defined($_[1]) && defined($_[2])) {map {$_ * 100} ($_[1], 500 * ($_[0] - $_[1])/116, 200 * ($_[1] - $_[2])/116)} else {@_}}); |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
13004
|
|
|
|
|
|
|
|
|
13005
|
|
|
|
|
|
|
} else { |
|
13006
|
|
|
|
|
|
|
|
|
13007
|
|
|
|
|
|
|
# error |
|
13008
|
0
|
|
|
|
|
0
|
croak('invalid L*a*b* encoding'); |
|
13009
|
|
|
|
|
|
|
|
|
13010
|
|
|
|
|
|
|
} |
|
13011
|
|
|
|
|
|
|
|
|
13012
|
|
|
|
|
|
|
} |
|
13013
|
|
|
|
|
|
|
|
|
13014
|
|
|
|
|
|
|
# get XYZ encoding code refs |
|
13015
|
|
|
|
|
|
|
# assumes there are XYZ columns |
|
13016
|
|
|
|
|
|
|
# parameter: (object_reference, column_slice, [hash]) |
|
13017
|
|
|
|
|
|
|
# returns: (get_code_ref, set_code_ref) |
|
13018
|
|
|
|
|
|
|
sub _xyz_encoding { |
|
13019
|
|
|
|
|
|
|
|
|
13020
|
|
|
|
|
|
|
# get object reference |
|
13021
|
23
|
|
|
23
|
|
42
|
my ($self, $cols, $hash) = @_; |
|
13022
|
|
|
|
|
|
|
|
|
13023
|
|
|
|
|
|
|
# local variable |
|
13024
|
23
|
|
|
|
|
31
|
my ($encode, $wtpt); |
|
13025
|
|
|
|
|
|
|
|
|
13026
|
|
|
|
|
|
|
# get encoding parameter from hash |
|
13027
|
23
|
|
|
|
|
35
|
$encode = $hash->{'encoding'}; |
|
13028
|
|
|
|
|
|
|
|
|
13029
|
|
|
|
|
|
|
# if encoding parameter undefined |
|
13030
|
23
|
50
|
0
|
|
|
41
|
if (! defined($encode)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13031
|
|
|
|
|
|
|
|
|
13032
|
|
|
|
|
|
|
# return code refs (identity) |
|
13033
|
23
|
|
|
18
|
|
119
|
return(sub {@_}, sub {@_}); |
|
|
18
|
|
|
|
|
28
|
|
|
|
3
|
|
|
|
|
5
|
|
|
13034
|
|
|
|
|
|
|
|
|
13035
|
|
|
|
|
|
|
# if encoding is L* |
|
13036
|
|
|
|
|
|
|
} elsif ($encode eq 'L*' || $encode == 4) { |
|
13037
|
|
|
|
|
|
|
|
|
13038
|
|
|
|
|
|
|
# get illuminant white point |
|
13039
|
0
|
0
|
|
|
|
0
|
($wtpt = _illumWP($self, $cols, $hash)) or croak('illuminant white point required for LxLyLz encoding'); |
|
13040
|
|
|
|
|
|
|
|
|
13041
|
|
|
|
|
|
|
# return code refs |
|
13042
|
0
|
0
|
|
0
|
|
0
|
return(sub {defined($_[0]) ? ICC::Shared::x2L($_[0] / $wtpt->[0]) : $_[0], defined($_[1]) ? ICC::Shared::x2L($_[1] / $wtpt->[1]) : $_[1], defined($_[2]) ? ICC::Shared::x2L($_[2] / $wtpt->[2]) : $_[2]}, |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13043
|
0
|
0
|
|
0
|
|
0
|
sub {defined($_[0]) ? ICC::Shared::L2x($_[0]) * $wtpt->[0] : $_[0], defined($_[1]) ? ICC::Shared::L2x($_[1]) * $wtpt->[1] : $_[1], defined($_[2]) ? ICC::Shared::L2x($_[2]) * $wtpt->[2] : $_[2]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
13044
|
|
|
|
|
|
|
|
|
13045
|
|
|
|
|
|
|
# if encoding is 16-bit ICC XYZ |
|
13046
|
|
|
|
|
|
|
} elsif ($encode == 7) { |
|
13047
|
|
|
|
|
|
|
|
|
13048
|
|
|
|
|
|
|
# return code refs |
|
13049
|
0
|
0
|
|
0
|
|
0
|
return(sub {map {defined() ? $_ / 199.9969482421875 : $_} @_}, sub {map {defined() ? $_ * 199.9969482421875 : $_} @_}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
13050
|
|
|
|
|
|
|
|
|
13051
|
|
|
|
|
|
|
# if encoding is 32-bit ICC XYZNumber |
|
13052
|
|
|
|
|
|
|
} elsif ($encode == 8) { |
|
13053
|
|
|
|
|
|
|
|
|
13054
|
|
|
|
|
|
|
# return code refs |
|
13055
|
0
|
0
|
|
0
|
|
0
|
return(sub {map {defined() ? $_ / 100 : $_} @_}, sub {map {defined() ? $_ * 100 : $_} @_}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
13056
|
|
|
|
|
|
|
|
|
13057
|
|
|
|
|
|
|
# if encoding is xyz |
|
13058
|
|
|
|
|
|
|
} elsif ($encode == 9) { |
|
13059
|
|
|
|
|
|
|
|
|
13060
|
|
|
|
|
|
|
# get illuminant white point |
|
13061
|
0
|
0
|
|
|
|
0
|
($wtpt = _illumWP($self, $cols, $hash)) or croak('illuminant white point required for xyz encoding'); |
|
13062
|
|
|
|
|
|
|
|
|
13063
|
|
|
|
|
|
|
# return code refs |
|
13064
|
0
|
0
|
|
0
|
|
0
|
return(sub {defined($_[0]) ? $_[0] / $wtpt->[0] : $_[0], defined($_[1]) ? $_[1] / $wtpt->[1] : $_[1], defined($_[2]) ? $_[2] / $wtpt->[2] : $_[2]}, |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13065
|
0
|
0
|
|
0
|
|
0
|
sub {defined($_[0]) ? $_[0] * $wtpt->[0] : $_[0], defined($_[1]) ? $_[1] * $wtpt->[1] : $_[1], defined($_[2]) ? $_[2] * $wtpt->[2] : $_[2]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
13066
|
|
|
|
|
|
|
|
|
13067
|
|
|
|
|
|
|
# if encoding is XYZ |
|
13068
|
|
|
|
|
|
|
} elsif ($encode == 10) { |
|
13069
|
|
|
|
|
|
|
|
|
13070
|
|
|
|
|
|
|
# return code refs (identity) |
|
13071
|
0
|
|
|
0
|
|
0
|
return(sub {@_}, sub {@_}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
13072
|
|
|
|
|
|
|
|
|
13073
|
|
|
|
|
|
|
# if encoding is media relative xyz |
|
13074
|
|
|
|
|
|
|
} elsif ($encode == 11) { |
|
13075
|
|
|
|
|
|
|
|
|
13076
|
|
|
|
|
|
|
# get media white point |
|
13077
|
0
|
0
|
|
|
|
0
|
($wtpt = _mediaWP($self, $cols, $hash)) or croak('media white point required for media relative xyz encoding'); |
|
13078
|
|
|
|
|
|
|
|
|
13079
|
|
|
|
|
|
|
# return code refs |
|
13080
|
0
|
0
|
|
0
|
|
0
|
return(sub {defined($_[0]) ? $_[0] / $wtpt->[0] : $_[0], defined($_[1]) ? $_[1] / $wtpt->[1] : $_[1], defined($_[2]) ? $_[2] / $wtpt->[2] : $_[2]}, |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13081
|
0
|
0
|
|
0
|
|
0
|
sub {defined($_[0]) ? $_[0] * $wtpt->[0] : $_[0], defined($_[1]) ? $_[1] * $wtpt->[1] : $_[1], defined($_[2]) ? $_[2] * $wtpt->[2] : $_[2]}); |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
13082
|
|
|
|
|
|
|
|
|
13083
|
|
|
|
|
|
|
} else { |
|
13084
|
|
|
|
|
|
|
|
|
13085
|
|
|
|
|
|
|
# error |
|
13086
|
0
|
|
|
|
|
0
|
croak('invalid XYZ encoding'); |
|
13087
|
|
|
|
|
|
|
|
|
13088
|
|
|
|
|
|
|
} |
|
13089
|
|
|
|
|
|
|
|
|
13090
|
|
|
|
|
|
|
} |
|
13091
|
|
|
|
|
|
|
|
|
13092
|
|
|
|
|
|
|
# get density encoding code refs |
|
13093
|
|
|
|
|
|
|
# parameter: (object_reference, hash) |
|
13094
|
|
|
|
|
|
|
# returns: (get_code_ref, set_code_ref) |
|
13095
|
|
|
|
|
|
|
sub _density_encoding { |
|
13096
|
|
|
|
|
|
|
|
|
13097
|
|
|
|
|
|
|
# get object reference |
|
13098
|
17
|
|
|
17
|
|
23
|
my ($self, $hash) = @_; |
|
13099
|
|
|
|
|
|
|
|
|
13100
|
|
|
|
|
|
|
# get encoding parameter from hash |
|
13101
|
17
|
|
|
|
|
30
|
my $encode = $hash->{'encoding'}; |
|
13102
|
|
|
|
|
|
|
|
|
13103
|
|
|
|
|
|
|
# if encoding parameter undefined or density |
|
13104
|
17
|
50
|
33
|
|
|
40
|
if (! defined($encode) || $encode eq 'density') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13105
|
|
|
|
|
|
|
|
|
13106
|
|
|
|
|
|
|
# return code refs (identity) |
|
13107
|
17
|
|
|
0
|
|
82
|
return(sub {@_}, sub {@_}); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13108
|
|
|
|
|
|
|
|
|
13109
|
|
|
|
|
|
|
# if encoding is linear (RGBV) |
|
13110
|
|
|
|
|
|
|
} elsif ($encode eq 'linear') { |
|
13111
|
|
|
|
|
|
|
|
|
13112
|
|
|
|
|
|
|
# return code refs |
|
13113
|
0
|
0
|
|
0
|
|
|
return(sub {map {defined() ? 100 * POSIX::pow(10, -$_) : $_} @_}, sub {map {if (defined()) {if ($_ > 0) {-POSIX::log10($_/100)} else {warn("log of $_"); 99}} else {$_}} @_}); |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13114
|
|
|
|
|
|
|
|
|
13115
|
|
|
|
|
|
|
# if encoding is unit |
|
13116
|
|
|
|
|
|
|
} elsif ($encode eq 'unit') { |
|
13117
|
|
|
|
|
|
|
|
|
13118
|
|
|
|
|
|
|
# return code refs |
|
13119
|
0
|
0
|
|
0
|
|
|
return(sub {map {defined() ? POSIX::pow(10, -$_) : $_} @_}, sub {map {if (defined()) {if ($_ > 0) {-POSIX::log10($_)} else {warn("log of $_"); 99}} else {$_}} @_}); |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13120
|
|
|
|
|
|
|
|
|
13121
|
|
|
|
|
|
|
# if encoding is L* |
|
13122
|
|
|
|
|
|
|
} elsif ($encode eq 'L*') { |
|
13123
|
|
|
|
|
|
|
|
|
13124
|
|
|
|
|
|
|
# return code refs |
|
13125
|
0
|
0
|
|
0
|
|
|
return(sub {map {defined() ? ICC::Shared::x2L(POSIX::pow(10, -$_)) : $_} @_}, sub {map {if (defined()) {if ($_ > 0) {-POSIX::log10(ICC::Shared::L2x($_))} else {warn("log of $_"); 99}} else {$_}} @_}); |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13126
|
|
|
|
|
|
|
|
|
13127
|
|
|
|
|
|
|
} else { |
|
13128
|
|
|
|
|
|
|
|
|
13129
|
|
|
|
|
|
|
# error |
|
13130
|
0
|
|
|
|
|
|
croak('invalid density encoding'); |
|
13131
|
|
|
|
|
|
|
|
|
13132
|
|
|
|
|
|
|
} |
|
13133
|
|
|
|
|
|
|
|
|
13134
|
|
|
|
|
|
|
} |
|
13135
|
|
|
|
|
|
|
|
|
13136
|
|
|
|
|
|
|
# get rgbv encoding code refs |
|
13137
|
|
|
|
|
|
|
# parameter: (object_reference, hash) |
|
13138
|
|
|
|
|
|
|
# returns: (get_code_ref, set_code_ref) |
|
13139
|
|
|
|
|
|
|
sub _rgbv_encoding { |
|
13140
|
|
|
|
|
|
|
|
|
13141
|
|
|
|
|
|
|
# get object reference |
|
13142
|
0
|
|
|
0
|
|
|
my ($self, $hash) = @_; |
|
13143
|
|
|
|
|
|
|
|
|
13144
|
|
|
|
|
|
|
# get encoding parameter from hash |
|
13145
|
0
|
|
|
|
|
|
my $encode = $hash->{'encoding'}; |
|
13146
|
|
|
|
|
|
|
|
|
13147
|
|
|
|
|
|
|
# if encoding parameter undefined or linear |
|
13148
|
0
|
0
|
0
|
|
|
|
if (! defined($encode) || $encode eq 'linear'|| $encode eq 'RGBV') { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13149
|
|
|
|
|
|
|
|
|
13150
|
|
|
|
|
|
|
# return code refs (identity) |
|
13151
|
0
|
|
|
0
|
|
|
return(sub {@_}, sub {@_}); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13152
|
|
|
|
|
|
|
|
|
13153
|
|
|
|
|
|
|
# if encoding is unit |
|
13154
|
|
|
|
|
|
|
} elsif ($encode eq 'unit') { |
|
13155
|
|
|
|
|
|
|
|
|
13156
|
|
|
|
|
|
|
# return code refs |
|
13157
|
0
|
|
|
0
|
|
|
return(sub {map {$_/100} @_}, sub {map {$_ * 100} @_}); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13158
|
|
|
|
|
|
|
|
|
13159
|
|
|
|
|
|
|
# if encoding is density |
|
13160
|
|
|
|
|
|
|
} elsif ($encode eq 'density') { |
|
13161
|
|
|
|
|
|
|
|
|
13162
|
|
|
|
|
|
|
# return code refs |
|
13163
|
0
|
0
|
|
0
|
|
|
return(sub {map {if (defined()) {if ($_ > 0) {-POSIX::log10($_/100)} else {warn("log of $_"); 99}} else {$_}} @_}, sub {map {defined() ? 100 * POSIX::pow(10, -$_) : $_} @_}); |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13164
|
|
|
|
|
|
|
|
|
13165
|
|
|
|
|
|
|
# if encoding is L* |
|
13166
|
|
|
|
|
|
|
} elsif ($encode eq 'L*') { |
|
13167
|
|
|
|
|
|
|
|
|
13168
|
|
|
|
|
|
|
# return code refs |
|
13169
|
0
|
|
|
0
|
|
|
return(sub {map {ICC::Shared::x2L($_/100)} @_}, sub {map {ICC::Shared::L2x($_) * 100} @_}); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13170
|
|
|
|
|
|
|
|
|
13171
|
|
|
|
|
|
|
} else { |
|
13172
|
|
|
|
|
|
|
|
|
13173
|
|
|
|
|
|
|
# error |
|
13174
|
0
|
|
|
|
|
|
croak('invalid rgbv encoding'); |
|
13175
|
|
|
|
|
|
|
|
|
13176
|
|
|
|
|
|
|
} |
|
13177
|
|
|
|
|
|
|
|
|
13178
|
|
|
|
|
|
|
} |
|
13179
|
|
|
|
|
|
|
|
|
13180
|
|
|
|
|
|
|
#--------- additional Math::Matrix methods --------- |
|
13181
|
|
|
|
|
|
|
|
|
13182
|
|
|
|
|
|
|
package Math::Matrix; |
|
13183
|
|
|
|
|
|
|
|
|
13184
|
|
|
|
|
|
|
# rotate matrix |
|
13185
|
|
|
|
|
|
|
# rotation: 0 = None, 1 = 90° CW, 2 = 180°, 3 = 90° CCW |
|
13186
|
|
|
|
|
|
|
# note: rotation describes appearance in MeasureTool |
|
13187
|
|
|
|
|
|
|
# parameter: (rotation) |
|
13188
|
|
|
|
|
|
|
# returns: (rotated_matrix) |
|
13189
|
|
|
|
|
|
|
sub rotate { |
|
13190
|
|
|
|
|
|
|
|
|
13191
|
|
|
|
|
|
|
# get parameters |
|
13192
|
0
|
|
|
0
|
0
|
|
my ($self, $rot) = @_; |
|
13193
|
|
|
|
|
|
|
|
|
13194
|
|
|
|
|
|
|
# local variables |
|
13195
|
0
|
|
|
|
|
|
my ($rows, $cols, $replace); |
|
13196
|
|
|
|
|
|
|
|
|
13197
|
|
|
|
|
|
|
# return if rotation undefined |
|
13198
|
0
|
0
|
|
|
|
|
return($self) if (! defined($rot)); |
|
13199
|
|
|
|
|
|
|
|
|
13200
|
|
|
|
|
|
|
# resolve rotation parameter |
|
13201
|
0
|
|
|
|
|
|
$rot = int($rot) % 4; |
|
13202
|
|
|
|
|
|
|
|
|
13203
|
|
|
|
|
|
|
# get upper row index |
|
13204
|
0
|
|
|
|
|
|
$rows = $#{$self}; |
|
|
0
|
|
|
|
|
|
|
|
13205
|
|
|
|
|
|
|
|
|
13206
|
|
|
|
|
|
|
# get upper column index |
|
13207
|
0
|
|
|
|
|
|
$cols = $#{$self->[0]}; |
|
|
0
|
|
|
|
|
|
|
|
13208
|
|
|
|
|
|
|
|
|
13209
|
|
|
|
|
|
|
# if rotation = 0 (none) |
|
13210
|
0
|
0
|
|
|
|
|
if ($rot == 0) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13211
|
|
|
|
|
|
|
|
|
13212
|
|
|
|
|
|
|
# for each row |
|
13213
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13214
|
|
|
|
|
|
|
|
|
13215
|
|
|
|
|
|
|
# for each column |
|
13216
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13217
|
|
|
|
|
|
|
|
|
13218
|
|
|
|
|
|
|
# copy matrix element |
|
13219
|
0
|
|
|
|
|
|
$replace->[$i][$j] = $self->[$i][$j]; |
|
13220
|
|
|
|
|
|
|
|
|
13221
|
|
|
|
|
|
|
} |
|
13222
|
|
|
|
|
|
|
|
|
13223
|
|
|
|
|
|
|
} |
|
13224
|
|
|
|
|
|
|
|
|
13225
|
|
|
|
|
|
|
# if rotation = 1 (90° CW) |
|
13226
|
|
|
|
|
|
|
} elsif ($rot == 1) { |
|
13227
|
|
|
|
|
|
|
|
|
13228
|
|
|
|
|
|
|
# for each row |
|
13229
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13230
|
|
|
|
|
|
|
|
|
13231
|
|
|
|
|
|
|
# for each column |
|
13232
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13233
|
|
|
|
|
|
|
|
|
13234
|
|
|
|
|
|
|
# copy matrix element |
|
13235
|
0
|
|
|
|
|
|
$replace->[$j][$i] = $self->[$i][$cols - $j]; |
|
13236
|
|
|
|
|
|
|
|
|
13237
|
|
|
|
|
|
|
} |
|
13238
|
|
|
|
|
|
|
|
|
13239
|
|
|
|
|
|
|
} |
|
13240
|
|
|
|
|
|
|
|
|
13241
|
|
|
|
|
|
|
# if rotation = 2 (180°) |
|
13242
|
|
|
|
|
|
|
} elsif ($rot == 2) { |
|
13243
|
|
|
|
|
|
|
|
|
13244
|
|
|
|
|
|
|
# for each row |
|
13245
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13246
|
|
|
|
|
|
|
|
|
13247
|
|
|
|
|
|
|
# for each column |
|
13248
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13249
|
|
|
|
|
|
|
|
|
13250
|
|
|
|
|
|
|
# copy matrix element |
|
13251
|
0
|
|
|
|
|
|
$replace->[$i][$j] = $self->[$rows - $i][$cols - $j]; |
|
13252
|
|
|
|
|
|
|
|
|
13253
|
|
|
|
|
|
|
} |
|
13254
|
|
|
|
|
|
|
|
|
13255
|
|
|
|
|
|
|
} |
|
13256
|
|
|
|
|
|
|
|
|
13257
|
|
|
|
|
|
|
# if rotation = 3 (90° CCW) |
|
13258
|
|
|
|
|
|
|
} elsif ($rot == 3) { |
|
13259
|
|
|
|
|
|
|
|
|
13260
|
|
|
|
|
|
|
# for each row |
|
13261
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13262
|
|
|
|
|
|
|
|
|
13263
|
|
|
|
|
|
|
# for each column |
|
13264
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13265
|
|
|
|
|
|
|
|
|
13266
|
|
|
|
|
|
|
# copy matrix element |
|
13267
|
0
|
|
|
|
|
|
$replace->[$j][$i] = $self->[$rows - $i][$j]; |
|
13268
|
|
|
|
|
|
|
|
|
13269
|
|
|
|
|
|
|
} |
|
13270
|
|
|
|
|
|
|
|
|
13271
|
|
|
|
|
|
|
} |
|
13272
|
|
|
|
|
|
|
|
|
13273
|
|
|
|
|
|
|
} |
|
13274
|
|
|
|
|
|
|
|
|
13275
|
|
|
|
|
|
|
# return new object |
|
13276
|
0
|
|
|
|
|
|
return(bless($replace, 'Math::Matrix')); |
|
13277
|
|
|
|
|
|
|
|
|
13278
|
|
|
|
|
|
|
} |
|
13279
|
|
|
|
|
|
|
|
|
13280
|
|
|
|
|
|
|
# flip matrix |
|
13281
|
|
|
|
|
|
|
# flip: 0 = transpose, 1 = horizontal, 2 = cross transpose, 3 = vertical |
|
13282
|
|
|
|
|
|
|
# note: flip describes appearance in MeasureTool |
|
13283
|
|
|
|
|
|
|
# parameter: (flip) |
|
13284
|
|
|
|
|
|
|
# returns: (flipped_matrix) |
|
13285
|
|
|
|
|
|
|
sub flip { |
|
13286
|
|
|
|
|
|
|
|
|
13287
|
|
|
|
|
|
|
# get parameters |
|
13288
|
0
|
|
|
0
|
0
|
|
my ($self, $flip) = @_; |
|
13289
|
|
|
|
|
|
|
|
|
13290
|
|
|
|
|
|
|
# local variables |
|
13291
|
0
|
|
|
|
|
|
my ($rows, $cols, $replace); |
|
13292
|
|
|
|
|
|
|
|
|
13293
|
|
|
|
|
|
|
# return if flip undefined |
|
13294
|
0
|
0
|
|
|
|
|
return($self) if (! defined($flip)); |
|
13295
|
|
|
|
|
|
|
|
|
13296
|
|
|
|
|
|
|
# resolve flip parameter |
|
13297
|
0
|
|
|
|
|
|
$flip = int($flip) % 4; |
|
13298
|
|
|
|
|
|
|
|
|
13299
|
|
|
|
|
|
|
# get upper row index |
|
13300
|
0
|
|
|
|
|
|
$rows = $#{$self}; |
|
|
0
|
|
|
|
|
|
|
|
13301
|
|
|
|
|
|
|
|
|
13302
|
|
|
|
|
|
|
# get upper column index |
|
13303
|
0
|
|
|
|
|
|
$cols = $#{$self->[0]}; |
|
|
0
|
|
|
|
|
|
|
|
13304
|
|
|
|
|
|
|
|
|
13305
|
|
|
|
|
|
|
# if flip = 0 (transpose) |
|
13306
|
0
|
0
|
|
|
|
|
if ($flip == 0) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13307
|
|
|
|
|
|
|
|
|
13308
|
|
|
|
|
|
|
# for each row |
|
13309
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13310
|
|
|
|
|
|
|
|
|
13311
|
|
|
|
|
|
|
# for each column |
|
13312
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13313
|
|
|
|
|
|
|
|
|
13314
|
|
|
|
|
|
|
# copy matrix element |
|
13315
|
0
|
|
|
|
|
|
$replace->[$j][$i] = $self->[$i][$j]; |
|
13316
|
|
|
|
|
|
|
|
|
13317
|
|
|
|
|
|
|
} |
|
13318
|
|
|
|
|
|
|
|
|
13319
|
|
|
|
|
|
|
} |
|
13320
|
|
|
|
|
|
|
|
|
13321
|
|
|
|
|
|
|
# if flip = 1 (horizontal) |
|
13322
|
|
|
|
|
|
|
} elsif ($flip == 1) { |
|
13323
|
|
|
|
|
|
|
|
|
13324
|
|
|
|
|
|
|
# for each row |
|
13325
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13326
|
|
|
|
|
|
|
|
|
13327
|
|
|
|
|
|
|
# for each column |
|
13328
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13329
|
|
|
|
|
|
|
|
|
13330
|
|
|
|
|
|
|
# copy matrix element |
|
13331
|
0
|
|
|
|
|
|
$replace->[$i][$j] = $self->[$rows - $i][$j]; |
|
13332
|
|
|
|
|
|
|
|
|
13333
|
|
|
|
|
|
|
} |
|
13334
|
|
|
|
|
|
|
|
|
13335
|
|
|
|
|
|
|
} |
|
13336
|
|
|
|
|
|
|
|
|
13337
|
|
|
|
|
|
|
# if flip = 2 (cross transpose) |
|
13338
|
|
|
|
|
|
|
} elsif ($flip == 2) { |
|
13339
|
|
|
|
|
|
|
|
|
13340
|
|
|
|
|
|
|
# for each row |
|
13341
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13342
|
|
|
|
|
|
|
|
|
13343
|
|
|
|
|
|
|
# for each column |
|
13344
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13345
|
|
|
|
|
|
|
|
|
13346
|
|
|
|
|
|
|
# copy matrix element |
|
13347
|
0
|
|
|
|
|
|
$replace->[$j][$i] = $self->[$rows - $i][$cols - $j]; |
|
13348
|
|
|
|
|
|
|
|
|
13349
|
|
|
|
|
|
|
} |
|
13350
|
|
|
|
|
|
|
|
|
13351
|
|
|
|
|
|
|
} |
|
13352
|
|
|
|
|
|
|
|
|
13353
|
|
|
|
|
|
|
# if flip = 3 (vertical) |
|
13354
|
|
|
|
|
|
|
} elsif ($flip == 3) { |
|
13355
|
|
|
|
|
|
|
|
|
13356
|
|
|
|
|
|
|
# for each row |
|
13357
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13358
|
|
|
|
|
|
|
|
|
13359
|
|
|
|
|
|
|
# for each column |
|
13360
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13361
|
|
|
|
|
|
|
|
|
13362
|
|
|
|
|
|
|
# copy matrix element |
|
13363
|
0
|
|
|
|
|
|
$replace->[$i][$j] = $self->[$i][$cols - $j]; |
|
13364
|
|
|
|
|
|
|
|
|
13365
|
|
|
|
|
|
|
} |
|
13366
|
|
|
|
|
|
|
|
|
13367
|
|
|
|
|
|
|
} |
|
13368
|
|
|
|
|
|
|
|
|
13369
|
|
|
|
|
|
|
} |
|
13370
|
|
|
|
|
|
|
|
|
13371
|
|
|
|
|
|
|
# return new object |
|
13372
|
0
|
|
|
|
|
|
return(bless($replace, 'Math::Matrix')); |
|
13373
|
|
|
|
|
|
|
|
|
13374
|
|
|
|
|
|
|
} |
|
13375
|
|
|
|
|
|
|
|
|
13376
|
|
|
|
|
|
|
# randomize matrix |
|
13377
|
|
|
|
|
|
|
# returns: (randomized_matrix) |
|
13378
|
|
|
|
|
|
|
sub randomize { |
|
13379
|
|
|
|
|
|
|
|
|
13380
|
|
|
|
|
|
|
# get object reference |
|
13381
|
0
|
|
|
0
|
0
|
|
my $self = shift(); |
|
13382
|
|
|
|
|
|
|
|
|
13383
|
|
|
|
|
|
|
# local variables |
|
13384
|
0
|
|
|
|
|
|
my (@ix, $rows, $cols, $replace); |
|
13385
|
|
|
|
|
|
|
|
|
13386
|
|
|
|
|
|
|
# flatten and randomize matrix |
|
13387
|
0
|
|
|
|
|
|
@ix = List::Util::shuffle(@{ICC::Shared::flatten($self)}); |
|
|
0
|
|
|
|
|
|
|
|
13388
|
|
|
|
|
|
|
|
|
13389
|
|
|
|
|
|
|
# get upper row index |
|
13390
|
0
|
|
|
|
|
|
$rows = $#{$self}; |
|
|
0
|
|
|
|
|
|
|
|
13391
|
|
|
|
|
|
|
|
|
13392
|
|
|
|
|
|
|
# get upper column index |
|
13393
|
0
|
|
|
|
|
|
$cols = $#{$self->[0]}; |
|
|
0
|
|
|
|
|
|
|
|
13394
|
|
|
|
|
|
|
|
|
13395
|
|
|
|
|
|
|
# for each row |
|
13396
|
0
|
|
|
|
|
|
for my $i (0 .. $rows) { |
|
13397
|
|
|
|
|
|
|
|
|
13398
|
|
|
|
|
|
|
# for each column |
|
13399
|
0
|
|
|
|
|
|
for my $j (0 .. $cols) { |
|
13400
|
|
|
|
|
|
|
|
|
13401
|
|
|
|
|
|
|
# set element |
|
13402
|
0
|
|
|
|
|
|
$replace->[$i][$j] = $ix[$i * ($cols + 1) + $j]; |
|
13403
|
|
|
|
|
|
|
|
|
13404
|
|
|
|
|
|
|
} |
|
13405
|
|
|
|
|
|
|
|
|
13406
|
|
|
|
|
|
|
} |
|
13407
|
|
|
|
|
|
|
|
|
13408
|
|
|
|
|
|
|
# return new object |
|
13409
|
0
|
|
|
|
|
|
return(bless($replace, 'Math::Matrix')); |
|
13410
|
|
|
|
|
|
|
|
|
13411
|
|
|
|
|
|
|
} |
|
13412
|
|
|
|
|
|
|
|
|
13413
|
|
|
|
|
|
|
1; |
|
13414
|
|
|
|
|
|
|
|