File Coverage

blib/lib/ICC/Profile/ncl2.pm
Criterion Covered Total %
statement 12 119 10.0
branch 0 38 0.0
condition 0 27 0.0
subroutine 4 13 30.7
pod 1 6 16.6
total 17 203 8.3


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