File Coverage

blib/lib/ICC/Profile/ncl2.pm
Criterion Covered Total %
statement 9 116 7.7
branch 0 38 0.0
condition 0 27 0.0
subroutine 3 12 25.0
pod 1 6 16.6
total 13 199 6.5


line stmt bran cond sub pod time code
1             package ICC::Profile::ncl2;
2              
3 2     2   80181 use strict;
  2         10  
  2         46  
4 2     2   7 use Carp;
  2         4  
  2         108  
5              
6             our $VERSION = 0.22;
7              
8             # revised 2018-08-07
9             #
10             # Copyright © 2004-2020 by William B. Birkett
11              
12             # inherit from Shared
13 2     2   366 use parent qw(ICC::Shared);
  2         256  
  2         8  
14              
15             # create new ncl2 tag object
16             # parameters: ()
17             # parameters: (ref_to_color_table_array)
18             # parameters: (ref_to_A2B1_tag, [ref_to_array_of_colorant_names])
19             # returns: (ref_to_object)
20             sub new {
21              
22             # get object class
23 0     0 0   my $class = shift();
24              
25             # create empty ncl2 object
26 0           my $self = [
27             {}, # object header
28             [] # colorant array
29             ];
30              
31             # if parameter supplied
32 0 0         if (@_) {
33            
34             # if first parameter is an array or matrix
35 0 0 0       if (ref($_[0]) eq 'ARRAY' || UNIVERSAL::isa($_[0], 'Math::Matrix')) {
36            
37             # get array reference
38 0           my $array = shift();
39            
40             # for each row
41 0           for my $i (0 .. $#{$array}) {
  0            
42            
43             # copy to object
44 0           $self->[1][$i] = [@{$array->[$i]}];
  0            
45            
46             }
47            
48             } else {
49            
50             # add color table from A2B1 tag
51 0           _newICCncl2($self, @_);
52            
53             }
54            
55             }
56              
57             # bless object
58 0           bless($self, $class);
59              
60             # return object reference
61 0           return($self);
62              
63             }
64              
65             # create ncl2 tag object from ICC profile
66             # parameters: (ref_to_parent_object, file_handle, ref_to_tag_table_entry)
67             # returns: (ref_to_object)
68             sub new_fh {
69              
70             # get object class
71 0     0 0   my $class = shift();
72              
73             # create empty ncl2 object
74 0           my $self = [
75             {}, # object header
76             [] # colorant array
77             ];
78              
79             # verify 3 parameters
80 0 0         (@_ == 3) or croak('wrong number of parameters');
81              
82             # read ncl2 data from profile
83 0           _readICCncl2($self, @_);
84              
85             # bless object
86 0           bless($self, $class);
87              
88             # return object reference
89 0           return($self);
90              
91             }
92              
93             # writes ncl2 tag object to ICC profile
94             # parameters: (ref_to_parent_object, file_handle, ref_to_tag_table_entry)
95             sub write_fh {
96              
97             # verify 4 parameters
98 0 0   0 0   (@_ == 4) or croak('wrong number of parameters');
99              
100             # write text data to profile
101 0           goto &_writeICCncl2;
102              
103             }
104              
105             # get tag size (for writing to profile)
106             # returns: (tag_size)
107             sub size {
108              
109             # get parameters
110 0     0 0   my ($self) = @_;
111              
112             # return size
113 0 0         return(@{$self->[1]} ? 84 + @{$self->[1]} * (30 + @{$self->[1][0]} * 2) : 84);
  0            
  0            
  0            
114              
115             }
116              
117             # get/set named color array
118             # each row contains name, PCS values, and optional device values
119             # all value are 16-bit (0 - 65563)
120             # parameters: ([array_reference])
121             # returns: (array_reference)
122             sub array {
123              
124             # get object reference
125 0     0 0   my $self = shift();
126              
127             # if parameters
128 0 0         if (@_) {
129            
130             # if one parameter, a single array reference or Math::Matrix object
131 0 0 0       if (@_ == 1 && (ref($_[0]) eq 'ARRAY' || UNIVERSAL::isa($_[0], 'Math::Matrix'))) {
      0        
132            
133             # get array reference
134 0           my $array = shift();
135            
136             # initialize data array
137 0           $self->[1] = [];
138            
139             # if array is not empty
140 0 0         if (@{$array}) {
  0            
141            
142             # for each row
143 0           for my $i (0 .. $#{$array}) {
  0            
144            
145             # copy to object
146 0           $self->[1][$i] = [@{$array->[$i]}];
  0            
147            
148             }
149            
150             }
151            
152             } else {
153            
154             # error
155 0           croak('parameter must be an array reference');
156            
157             }
158            
159             }
160              
161             # return color table reference
162 0           return($self->[1]);
163              
164             }
165              
166             # print object contents to string
167             # format is an array structure
168             # parameter: ([format])
169             # returns: (string)
170             sub sdump {
171              
172             # get parameters
173 0     0 1   my ($self, $p) = @_;
174              
175             # local variables
176 0           my ($s, $fmt);
177              
178             # resolve parameter to an array reference
179 0 0         $p = defined($p) ? ref($p) eq 'ARRAY' ? $p : [$p] : [];
    0          
180              
181             # get format string
182 0 0 0       $fmt = defined($p->[0]) && ! ref($p->[0]) ? $p->[0] : 'undef';
183              
184             # set string to object ID
185 0           $s = sprintf("'%s' object, (0x%x)\n", ref($self), $self);
186              
187             # return
188 0           return($s);
189              
190             }
191              
192             # new colorant tag from nCLR A2B1 tag
193             # parameters: (ref_to_object, ref_to_A2B1_tag, [ref_to_array_of_colorant_names])
194             sub _newICCncl2 {
195              
196             # get parameters
197 0     0     my ($self, $tag, $name) = @_;
198              
199             # local variables
200 0           my ($type, $csi, $cso);
201 0           my ($cnt, @in, @out);
202              
203             # get tag type
204 0           $type = ref($tag);
205              
206             # get input colorspace
207 0           $csi = $tag->[0]{'input_cs'};
208              
209             # get output colorspace
210 0           $cso = $tag->[0]{'output_cs'};
211              
212             # if allowable tag type
213 0 0 0       if (($type eq 'ICC::Profile::mft1' || $type eq 'ICC::Profile::mft2' || $type eq 'ICC::Profile::mAB_') &&
      0        
      0        
      0        
214             ($csi =~ m|^([2-9A-F])CLR$|) && ($cso eq 'Lab ' || $cso eq 'XYZ ')) {
215            
216             # get count from match
217 0           $cnt = hex($1);
218            
219             # set transform mask
220 0           $tag->[6] = 0x0f;
221            
222             # for each colorant
223 0           for my $i (0 .. $cnt - 1) {
224            
225             # for each input
226 0           for my $j (0 .. $cnt - 1) {
227            
228             # set input
229 0 0         $in[$j] = $i == $j ? 1 : 0;
230            
231             }
232            
233             # if name array supplied
234 0 0         if (defined($name->[$i])) {
235            
236             # set the colorant name
237 0           $self->[1][$i][0] = $name->[$i];
238            
239             } else {
240            
241             # set the colorant name
242 0           $self->[1][$i][0] = sprintf('colorant_%x', $i + 1);
243            
244             }
245            
246             # if tag type is 'mft2' or colorspace is 'XYZ '
247 0 0 0       if ($type eq 'ICC::Profile::mft2' || $cso eq 'XYZ ') {
248            
249             # transform to PCS (legacy 16-bit Lab or XYZ)
250 0           @{$self->[1][$i]}[1 .. 3] = map {$_ * 65535} $tag->transform(@in);
  0            
  0            
251            
252             } else {
253            
254             # transform to PCS and convert to legacy 16-bit Lab
255 0           @{$self->[1][$i]}[1 .. 3] = map {$_ * 65280} $tag->transform(@in);
  0            
  0            
256            
257             }
258            
259             # push the device values (always 16-bit)
260 0           push(@{$self->[1][$i]}, map {$_ * 65535} @in);
  0            
  0            
261            
262             }
263            
264             # set pcs
265 0           $self->[0]{'pcs'} = $cso;
266            
267             # set data color space
268 0           $self->[0]{'dcs'} = $csi;
269            
270             # set flags
271 0           $self->[0]{'vsflag'} = 0;
272            
273             # set prefix
274 0           $self->[0]{'prefix'} = '';
275            
276             # set suffix
277 0           $self->[0]{'suffix'} = '';
278            
279             } else {
280            
281             # message
282 0           carp('wrong tag type');
283            
284             }
285            
286             }
287              
288             # read ncl2 tag from ICC profile
289             # parameters: (ref_to_object, ref_to_parent_object, file_handle, ref_to_tag_table_entry)
290             sub _readICCncl2 {
291              
292             # get parameters
293 0     0     my ($self, $parent, $fh, $tag) = @_;
294              
295             # local variables
296 0           my ($buf, $cnt, $dvc, $rsz, $fmt);
297              
298             # save tag signature
299 0           $self->[0]{'signature'} = $tag->[0];
300              
301             # save data color space
302 0           $self->[0]{'dcs'} = $parent->[1][4];
303              
304             # save profile connection space ('Lab ' or 'XYZ ')
305 0           $self->[0]{'pcs'} = $parent->[1][5];
306              
307             # seek start of tag
308 0           seek($fh, $tag->[1], 0);
309              
310             # read tag header
311 0           read($fh, $buf, 84);
312              
313             # unpack header
314 0           ($self->[0]{'vsflag'}, $cnt, $dvc, $self->[0]{'prefix'}, $self->[0]{'suffix'}) = unpack('x8 N3 Z32 Z32', $buf);
315              
316             # adjust device color count to include PCS
317 0           $dvc += 3;
318              
319             # set record size
320 0           $rsz = 32 + 2 * $dvc;
321              
322             # set unpack format
323 0           $fmt = "Z32n$dvc";
324              
325             # for each named color
326 0           for my $i (0 .. $cnt - 1) {
327            
328             # read record
329 0           read($fh, $buf, $rsz);
330            
331             # unpack color name, PCS and device values
332 0           $self->[1][$i] = [unpack($fmt, $buf)];
333            
334             }
335            
336             }
337              
338             # write ncl2 tag to ICC profile
339             # parameters: (ref_to_object, ref_to_parent_object, file_handle, ref_to_tag_table_entry)
340             sub _writeICCncl2 {
341              
342             # get parameters
343 0     0     my ($self, $parent, $fh, $tag) = @_;
344              
345             # local variables
346 0           my ($vsflag, $prefix, $suffix);
347 0           my ($cnt, $dvc, $fmt);
348              
349             # get vsflag, prefix and suffix using defaults if undefined
350 0 0         $vsflag = defined($self->[0]{'vsflag'}) ? $self->[0]{'vsflag'} : 0;
351 0 0         $prefix = defined($self->[0]{'prefix'}) ? $self->[0]{'prefix'} : '';
352 0 0         $suffix = defined($self->[0]{'suffix'}) ? $self->[0]{'suffix'} : '';
353              
354             # get count from array size
355 0           $cnt = @{$self->[1]};
  0            
356              
357             # get device colors from array size
358 0 0         $dvc = @{$self->[1]} ? @{$self->[1][0]} - 4 : 0;
  0            
  0            
359              
360             # seek start of tag
361 0           seek($fh, $tag->[1], 0);
362              
363             # write header
364 0           print $fh pack('a4 x4 N3 Z32 Z32', 'ncl2', $vsflag, $cnt, $dvc, $prefix, $suffix);
365              
366             # make pack format
367 0           $fmt = 'Z32n' . ($dvc + 3);
368              
369             # for each named color
370 0           for my $rec (@{$self->[1]}) {
  0            
371            
372             # write color name, pcs and device values
373 0           print $fh pack($fmt, @{$rec});
  0            
374            
375             }
376            
377             }
378              
379             1;