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
|
|
|
|
|
|
|
|