File Coverage

blib/lib/ICC/Profile/para.pm
Criterion Covered Total %
statement 42 212 19.8
branch 7 152 4.6
condition 2 27 7.4
subroutine 9 20 45.0
pod 1 13 7.6
total 61 424 14.3


line stmt bran cond sub pod time code
1             package ICC::Profile::para;
2              
3 5     5   98927 use strict;
  5         21  
  5         150  
4 5     5   21 use Carp;
  5         10  
  5         286  
5              
6             our $VERSION = 0.42;
7              
8             # revised 2018-08-31
9             #
10             # Copyright © 2004-2020 by William B. Birkett
11              
12             # inherit from Shared
13 5     5   27 use parent qw(ICC::Shared);
  5         7  
  5         21  
14              
15             # parameter count by function type
16             our @Np = (1, 3, 4, 5, 7);
17              
18             # create new 'para' tag object
19             # parameters: ([ref_to_array])
20             # returns: (ref_to_object)
21             sub new {
22              
23             # get object class
24 1     1 0 675 my $class = shift();
25            
26             # create empty para object
27 1         3 my $self = [
28             {}, # object header
29             [] # parameter array
30             ];
31              
32             # if parameter supplied
33 1 50       4 if (@_) {
34            
35             # verify array reference
36 0 0       0 (ref($_[0]) eq 'ARRAY') or croak('not an array reference');
37            
38             # verify function type
39 0 0 0     0 ($_[0][0] == int($_[0][0]) && defined($Np[$_[0][0]])) or croak('invalid function type');
40            
41             # verify number of parameters
42 0 0       0 ($#{$_[0]} == $Np[$_[0][0]]) or croak('wrong number of parameters');
  0         0  
43            
44             # copy array
45 0         0 $self->[1] = [@{shift()}];
  0         0  
46            
47             }
48              
49             # bless object
50 1         2 bless($self, $class);
51            
52             # return object reference
53 1         3 return($self);
54              
55             }
56              
57             # create inverse 'para' object
58             # returns: (ref_to_object)
59             sub inv {
60              
61             # get object
62 0     0 0 0 my $self = shift();
63              
64             # get parameter array
65 0         0 my @p = @{$self->[1]};
  0         0  
66              
67             # validate parameters
68 0 0       0 ($p[1]) or croak('invalid gamma value');
69 0 0 0     0 ($p[2]) or croak('invalid a value') if ($p[0] > 0);
70 0 0 0     0 ($p[4]) or croak('invalid c value') if ($p[0] > 2);
71              
72             # if type 0
73 0 0       0 if ($p[0] == 0) {
    0          
    0          
    0          
    0          
74            
75             # return inverse curve [0, γ]
76 0         0 return(ICC::Profile::para->new([0, 1/$p[1]]));
77            
78             # if type 1
79             } elsif ($p[0] == 1) {
80            
81             # return inverse curve [2, γ, a, b, c]
82 0         0 return(ICC::Profile::para->new([2, 1/$p[1], 1/$p[2]**$p[1], 0, -$p[3]/$p[2]]));
83            
84             # if type 2
85             } elsif ($p[0] == 2) {
86            
87             # return inverse curve [2, γ, a, b, c]
88 0         0 return(ICC::Profile::para->new([2, 1/$p[1], 1/$p[2]**$p[1], -$p[4]/$p[2]**$p[1], -$p[3]/$p[2]]));
89            
90             # if type 3
91             } elsif ($p[0] == 3) {
92            
93             # return inverse curve [4, γ, a, b, c, d, e, f]
94 0         0 return(ICC::Profile::para->new([4, 1/$p[1], 1/$p[2]**$p[1], 0, 1/$p[4], $p[4] * $p[5], -$p[3]/$p[2], 0]));
95            
96             # if type 4
97             } elsif ($p[0] == 4) {
98            
99             # return inverse curve [4, γ, a, b, c, d, e, f]
100 0         0 return(ICC::Profile::para->new([4, 1/$p[1], 1/$p[2]**$p[1], -$p[6]/$p[2]**$p[1], 1/$p[4], $p[4] * $p[5] + $p[7], -$p[3]/$p[2], -$p[7]/$p[4]]));
101            
102             } else {
103            
104             # error
105 0         0 croak('invalid \'para\' object');
106            
107             }
108            
109             }
110              
111             # get/set array reference
112             # parameters: ([ref_to_array])
113             # returns: (ref_to_array)
114             sub array {
115              
116             # get object reference
117 0     0 0 0 my $self = shift();
118            
119             # local variables
120 0         0 my ($array, $type);
121            
122             # if parameter
123 0 0       0 if (@_) {
124            
125             # get array reference
126 0         0 $array = shift();
127            
128             # verify array reference
129 0 0       0 (ref($array) eq 'ARRAY') or croak('not an array reference');
130            
131             # get function type
132 0         0 $type = $array->[0];
133            
134             # verify function type (integer, 0 - 4)
135 0 0 0     0 ($type == int($type) && $type >= 0 && $type <= 4) or croak('invalid function type');
      0        
136            
137             # verify number of parameters
138 0 0       0 ($#{$array} == $Np[$type]) or croak('wrong number of parameters');
  0         0  
139            
140             # set array reference
141 0         0 $self->[1] = $array;
142            
143             }
144            
145             # return array reference
146 0         0 return($self->[1]);
147              
148             }
149              
150             # compute curve function
151             # domain/range is (0 - 1)
152             # parameters: (input_value)
153             # returns: (output_value)
154             sub transform {
155              
156             # get parameters
157 0     0 0 0 my ($self, $in) = @_;
158              
159             # local variables
160 0         0 my ($a, $type);
161              
162             # get parameter array
163 0         0 $a = $self->[1];
164              
165             # get function type
166 0         0 $type = $a->[0];
167              
168             # function type 0
169 0 0       0 if ($type == 0) {
    0          
    0          
    0          
    0          
170            
171             # if gamma = 1
172 0 0       0 if ($a->[1] == 1) {
173            
174             # return x
175 0         0 return($in);
176            
177             } else {
178            
179             # if input > 0
180 0 0       0 if ($in > 0) {
181            
182             # return x**g
183 0         0 return($in ** $a->[1]);
184            
185             } else {
186            
187             # return 0
188 0         0 return(0);
189            
190             }
191            
192             }
193            
194             # function type 1
195             } elsif ($type == 1) {
196            
197             # if input ≥ -b/a
198 0 0       0 if ($in >= - $a->[3]/$a->[2]) {
199            
200             # return (ax + b)**g
201 0         0 return(($a->[2] * $in + $a->[3]) ** $a->[1]);
202            
203             } else {
204            
205             # return 0
206 0         0 return(0);
207            
208             }
209            
210             # function type 2
211             } elsif ($type == 2) {
212            
213             # if input ≥ -b/a
214 0 0       0 if ($in >= - $a->[3]/$a->[2]) {
215            
216             # return (ax + b)**g + c
217 0         0 return(($a->[2] * $in + $a->[3]) ** $a->[1] + $a->[4]);
218            
219             } else {
220            
221             # return c
222 0         0 return($a->[4]);
223            
224             }
225            
226             # function type 3
227             } elsif ($type == 3) {
228            
229             # if input ≥ d
230 0 0       0 if ($in >= $a->[5]) {
231            
232             # return (ax + b)**g
233 0         0 return(($a->[2] * $in + $a->[3]) ** $a->[1]);
234            
235             } else {
236            
237             # return cx
238 0         0 return($a->[4] * $in);
239            
240             }
241            
242             # function type 4
243             } elsif ($type == 4) {
244            
245             # if input ≥ d
246 0 0       0 if ($in >= $a->[5]) {
247            
248             # return (ax + b)**g + e
249 0         0 return(($a->[2] * $in + $a->[3]) ** $a->[1] + $a->[6]);
250            
251             } else {
252            
253             # return (cx + f)
254 0         0 return($a->[4] * $in + $a->[7]);
255            
256             }
257            
258             } else {
259            
260             # error
261 0         0 croak('invalid parametric function type');
262            
263             }
264            
265             }
266              
267             # compute curve inverse
268             # domain/range is (0 - 1)
269             # parameters: (input_value)
270             # returns: (output_value)
271             sub inverse {
272              
273             # get parameters
274 0     0 0 0 my ($self, $in) = @_;
275              
276             # local variables
277 0         0 my ($a, $type);
278              
279             # get parameter array reference
280 0         0 $a = $self->[1];
281              
282             # get function type
283 0         0 $type = $a->[0];
284              
285             # function type 0
286 0 0       0 if ($type == 0) {
    0          
    0          
    0          
    0          
287            
288             # if gamma = 1
289 0 0       0 if ($a->[1] == 1) {
290            
291             # return y
292 0         0 return($in);
293            
294             } else {
295            
296             # if input > 0
297 0 0       0 if ($in > 0) {
298            
299             # return y**(1/g)
300 0         0 return($in ** (1/$a->[1]));
301            
302             } else {
303            
304             # return 0
305 0         0 return(0);
306            
307             }
308            
309             }
310            
311             # function type 1
312             } elsif ($type == 1) {
313            
314             # if input ≥ 0
315 0 0       0 if ($in >= 0) {
316            
317             # return (y**(1/g) - b)/a
318 0         0 return(($in ** (1/$a->[1]) - $a->[3])/$a->[2]);
319            
320             } else {
321            
322             # return -b/a
323 0         0 return(- $a->[3]/$a->[2]);
324            
325             }
326            
327             # function type 2
328             } elsif ($type == 2) {
329            
330             # if input ≥ c
331 0 0       0 if ($in >= $a->[4]) {
332            
333             # return ((y - c)**(1/g) - b)/a
334 0         0 return((($in - $a->[4]) ** (1/$a->[1]) - $a->[3])/$a->[2]);
335            
336             } else {
337            
338             # return -b/a
339 0         0 return(- $a->[3]/$a->[2]);
340            
341             }
342            
343             # function type 3
344             } elsif ($type == 3) {
345            
346             # if input ≥ cd
347 0 0       0 if ($in >= ($a->[4] * $a->[5])) {
348            
349             # return (y**(1/g) - b)/a
350 0         0 return(($in ** (1/$a->[1]) - $a->[3])/$a->[2]);
351            
352             } else {
353            
354             # return y/c
355 0         0 return($in/$a->[4]);
356            
357             }
358            
359             # function type 4
360             } elsif ($type == 4) {
361            
362             # if input ≥ cd + f
363 0 0       0 if ($in >= ($a->[4] * $a->[5] + $a->[7])) {
364            
365             # return ((y - e)**(1/g) - b)/a
366 0         0 return((($in - $a->[6]) ** (1/$a->[1]) - $a->[3])/$a->[2]);
367            
368             } else {
369            
370             # return (y - f)/c
371 0         0 return(($in - $a->[7])/$a->[4]);
372            
373             }
374            
375             } else {
376            
377             # error
378 0         0 croak('invalid parametric function type');
379            
380             }
381            
382             }
383              
384             # compute curve derivative
385             # domain is (0 - 1)
386             # parameters: (input_value)
387             # returns: (derivative_value)
388             sub derivative {
389              
390             # get parameters
391 0     0 0 0 my ($self, $in) = @_;
392              
393             # local variables
394 0         0 my ($a, $type);
395              
396             # get parameter array
397 0         0 $a = $self->[1];
398              
399             # get function type
400 0         0 $type = $a->[0];
401              
402             # function type 0
403 0 0       0 if ($type == 0) {
    0          
    0          
    0          
    0          
404            
405             # if gamma = 1
406 0 0       0 if ($a->[1] == 1) {
407            
408             # return 1
409 0         0 return(1);
410            
411             } else {
412            
413             # if input > 0
414 0 0       0 if ($in > 0) {
415            
416             # return derivative
417 0         0 return($a->[1] * $in ** ($a->[1] - 1));
418            
419             } else {
420            
421             # return 0
422 0         0 return(0);
423            
424             }
425            
426             }
427            
428             # function type 1
429             } elsif ($type == 1) {
430            
431             # if input ≥ -b/a
432 0 0       0 if ($in >= - $a->[3]/$a->[2]) {
433            
434             # return ga(ax + b)**(g - 1)
435 0         0 return($a->[1] * $a->[2] * ($a->[2] * $in + $a->[3]) ** ($a->[1] - 1));
436            
437             } else {
438            
439             # return 0
440 0         0 return(0);
441            
442             }
443            
444             # function type 2
445             } elsif ($type == 2) {
446            
447             # if input ≥ -b/a
448 0 0       0 if ($in >= - $a->[3]/$a->[2]) {
449            
450             # return ga(ax + b)**(g - 1)
451 0         0 return($a->[1] * $a->[2] * ($a->[2] * $in + $a->[3]) ** ($a->[1] - 1));
452            
453             } else {
454            
455             # return 0
456 0         0 return(0);
457            
458             }
459            
460             # function type 3
461             } elsif ($type == 3) {
462            
463             # if input ≥ d
464 0 0       0 if ($in >= $a->[5]) {
465            
466             # return ga(ax + b)**(g - 1)
467 0         0 return($a->[1] * $a->[2] * ($a->[2] * $in + $a->[3]) ** ($a->[1] - 1));
468            
469             } else {
470            
471             # return c
472 0         0 return($a->[4]);
473            
474             }
475            
476             # function type 4
477             } elsif ($type == 4) {
478            
479             # if input ≥ d
480 0 0       0 if ($in >= $a->[5]) {
481            
482             # return ga(ax + b)**(g - 1)
483 0         0 return($a->[1] * $a->[2] * ($a->[2] * $in + $a->[3]) ** ($a->[1] - 1));
484            
485             } else {
486            
487             # return c
488 0         0 return($a->[4]);
489            
490             }
491            
492             } else {
493            
494             # error
495 0         0 croak('invalid parametric function type');
496            
497             }
498            
499             }
500              
501             # directional parametric partial derivatives
502             # nominal domain (0 - 1)
503             # parameters: (input_value)
504             # returns: (partial_derivative_array)
505             sub parametric {
506              
507             # get parameters
508 0     0 0 0 my ($self, $in) = @_;
509              
510             # local variables
511 0         0 my ($array, $type);
512 0         0 my ($axb, $dyda, $dydb);
513              
514             # get parameter array reference
515 0         0 $array = $self->[1];
516              
517             # get function type
518 0         0 $type = $array->[0];
519              
520             # function type 0
521 0 0       0 if ($type == 0) {
    0          
    0          
    0          
    0          
522            
523             # return ∂Y/∂γ
524 0         0 return($in**$array->[1] * log($in));
525            
526             # function type 1
527             } elsif ($type == 1) {
528            
529             # compute (aX + b) value
530 0         0 $axb = $array->[2] * $in + $array->[3];
531            
532             # if X >= -b/a
533 0 0       0 if ($axb >= 0) {
534            
535             # compute ∂Y/∂b
536 0         0 $dydb = $array->[1] * $axb**($array->[1] - 1);
537            
538             # compute ∂Y/∂a
539 0         0 $dyda = $dydb * $in;
540            
541             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b
542 0         0 return($axb**$array->[1] * log($axb), $dyda, $dydb);
543            
544             } else {
545            
546             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b
547 0         0 return(0, 0, 0);
548            
549             }
550            
551             # function type 2
552             } elsif ($type == 2) {
553            
554             # compute (aX + b) value
555 0         0 $axb = $array->[2] * $in + $array->[3];
556            
557             # if X >= -b/a
558 0 0       0 if ($axb >= 0) {
559            
560             # compute ∂Y/∂b
561 0         0 $dydb = $array->[1] * $axb**($array->[1] - 1);
562            
563             # compute ∂Y/∂a
564 0         0 $dyda = $dydb * $in;
565            
566             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b, ∂Y/∂c
567 0         0 return($axb**$array->[1] * log($axb), $dyda, $dydb, 1);
568            
569             } else {
570            
571             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b, ∂Y/∂c
572 0         0 return(0, 0, 0, 1);
573            
574             }
575            
576             # function type 3
577             } elsif ($type == 3) {
578            
579             # if X >= d
580 0 0       0 if ($in >= $array->[5]) {
581            
582             # compute (aX + b) value
583 0         0 $axb = $array->[2] * $in + $array->[3];
584            
585             # compute ∂Y/∂b
586 0         0 $dydb = $array->[1] * $axb**($array->[1] - 1);
587            
588             # compute ∂Y/∂a
589 0         0 $dyda = $dydb * $in;
590            
591             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b, ∂Y/∂c
592 0         0 return($axb**$array->[1] * log($axb), $dyda, $dydb, 0);
593            
594             } else {
595            
596             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b, ∂Y/∂c
597 0         0 return(0, 0, 0, $in);
598            
599             }
600            
601             # function type 4
602             } elsif ($type == 4) {
603            
604             # if X >= d
605 0 0       0 if ($in >= $array->[5]) {
606            
607             # compute (aX + b) value
608 0         0 $axb = $array->[2] * $in + $array->[3];
609            
610             # compute ∂Y/∂b
611 0         0 $dydb = $array->[1] * $axb**($array->[1] - 1);
612            
613             # compute ∂Y/∂a
614 0         0 $dyda = $dydb * $in;
615            
616             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b, ∂Y/∂c, ∂Y/∂e, ∂Y/∂f
617 0         0 return($axb**$array->[1] * log($axb), $dyda, $dydb, 0, 1, 0);
618            
619             } else {
620            
621             # return ∂Y/∂γ, ∂Y/∂a, ∂Y/∂b, ∂Y/∂c, ∂Y/∂e, ∂Y/∂f
622 0         0 return(0, 0, 0, $in, 0, 1);
623            
624             }
625            
626             } else {
627            
628             # error
629 0         0 croak('invalid parametric function type');
630            
631             }
632            
633             }
634              
635             # create para tag object from ICC profile
636             # parameters: (ref_to_parent_object, file_handle, ref_to_tag_table_entry)
637             # returns: (ref_to_object)
638             sub new_fh {
639              
640             # get object class
641 16     16 0 513 my $class = shift();
642              
643             # create empty para object
644 16         27 my $self = [
645             {}, # object header
646             [] # parameter array
647             ];
648              
649             # verify 3 parameters
650 16 50       35 (@_ == 3) or croak('wrong number of parameters');
651              
652             # read para data from profile
653 16         36 _readICCpara($self, @_);
654              
655             # bless object
656 16         31 bless($self, $class);
657              
658             # return object reference
659 16         53 return($self);
660              
661             }
662              
663             # writes para tag object to ICC profile
664             # parameters: (ref_to_parent_object, file_handle, ref_to_tag_table_entry)
665             sub write_fh {
666              
667             # verify 4 parameters
668 16 50   16 0 880 (@_ == 4) or croak('wrong number of parameters');
669              
670             # write para data to profile
671 16         42 goto &_writeICCpara;
672              
673             }
674              
675             # get tag size (for writing to profile)
676             # returns: (tag_size)
677             sub size {
678            
679             # get parameters
680 60     60 0 497 my ($self) = @_;
681            
682             # return size
683 60         129 return(12 + $Np[$self->[1][0]] * 4);
684            
685             }
686              
687             # make table for 'curv' objects
688             # assumes curve domain/range is (0 - 1)
689             # parameters: (number_of_table_entries, [direction])
690             # returns: (ref_to_table_array)
691             sub table {
692              
693             # get parameters
694 0     0 0 0 my ($self, $n, $dir) = @_;
695              
696             # local variables
697 0         0 my ($up, $table);
698              
699             # validate number of table entries
700 0 0 0     0 ($n == int($n) && $n >= 2) or carp('invalid number of table entries');
701              
702             # array upper index
703 0         0 $up = $n - 1;
704              
705             # for each table entry
706 0         0 for my $i (0 .. $up) {
707            
708             # compute table value
709 0         0 $table->[$i] = _transform($self, $dir, $i/$up);
710            
711             }
712              
713             # return table reference
714 0         0 return($table);
715              
716             }
717              
718             # make 'curv' object
719             # assumes curve domain/range is (0 - 1)
720             # parameters: (number_of_table_entries, [direction])
721             # returns: (ref_to_curv_object)
722             sub curv {
723              
724             # return 'curv' object reference
725 0     0 0 0 return(ICC::Profile::curv->new(table(@_)));
726              
727             }
728              
729             # print object contents to string
730             # format is an array structure
731             # parameter: ([format])
732             # returns: (string)
733             sub sdump {
734              
735             # get parameters
736 0     0 1 0 my ($self, $p) = @_;
737              
738             # local variables
739 0         0 my ($s, $fmt, $type);
740              
741             # resolve parameter to an array reference
742 0 0       0 $p = defined($p) ? ref($p) eq 'ARRAY' ? $p : [$p] : [];
    0          
743              
744             # get format string
745 0 0 0     0 $fmt = defined($p->[0]) && ! ref($p->[0]) ? $p->[0] : 'undef';
746              
747             # set string to object ID
748 0         0 $s = sprintf("'%s' object, (0x%x)\n", ref($self), $self);
749              
750             # if object has parameters
751 0 0       0 if (defined($type = $self->[1][0])) {
752            
753             # if function type 0
754 0 0       0 if ($type == 0) {
    0          
    0          
    0          
    0          
755            
756             # append parameter string
757 0         0 $s .= sprintf(" function type %d, gamma %.3f\n", @{$self->[1]});
  0         0  
758            
759             # if function type 1
760             } elsif ($type == 1) {
761            
762             # append parameter string
763 0         0 $s .= sprintf(" function type %d, gamma %.3f, a %.3f, b %.3f\n", @{$self->[1]});
  0         0  
764            
765             # if function type 2
766             } elsif ($type == 2) {
767            
768             # append parameter string
769 0         0 $s .= sprintf(" function type %d, gamma %.3f, a %.3f, b %.3f, c %.3f\n", @{$self->[1]});
  0         0  
770            
771             # if function type 3
772             } elsif ($type == 3) {
773            
774             # append parameter string
775 0         0 $s .= sprintf(" function type %d, gamma %.3f, a %.3f, b %.3f, c %.3f, d %.3f\n", @{$self->[1]});
  0         0  
776            
777             # if function type 4
778             } elsif ($type == 4) {
779            
780             # append parameter string
781 0         0 $s .= sprintf(" function type %d, gamma %.3f, a %.3f, b %.3f, c %.3f, d %.3f, e %.3f, f %.3f\n", @{$self->[1]});
  0         0  
782            
783             } else {
784            
785             # append error string
786 0         0 $s .= " invalid function type\n";
787            
788             }
789            
790             } else {
791            
792             # append string
793 0         0 $s .= " \n";
794            
795             }
796              
797             # return
798 0         0 return($s);
799              
800             }
801              
802             # directional derivative
803             # nominal domain (0 - 1)
804             # direction: 0 - normal, 1 - inverse
805             # parameters: (object_reference, direction, input_value)
806             # returns: (derivative_value)
807             sub _derivative {
808            
809             # get parameters
810 0     0   0 my ($self, $dir, $in) = @_;
811            
812             # if inverse transform
813 0 0       0 if ($dir) {
814            
815             # compute derivative
816 0         0 my $d = derivative($self, $in);
817            
818             # if non-zero
819 0 0       0 if ($d) {
820            
821             # return inverse
822 0         0 return(1/$d);
823            
824             } else {
825            
826             # error
827 0         0 croak('infinite derivative');
828            
829             }
830            
831             } else {
832            
833             # return derivative
834 0         0 return(derivative($self, $in));
835            
836             }
837            
838             }
839              
840             # directional transform
841             # nominal domain (0 - 1)
842             # direction: 0 - normal, 1 - inverse
843             # parameters: (object_reference, direction, input_value)
844             # returns: (output_value)
845             sub _transform {
846            
847             # get parameters
848 0     0   0 my ($self, $dir, $in) = @_;
849            
850             # if inverse transform
851 0 0       0 if ($dir) {
852            
853             # return inverse
854 0         0 return(inverse($self, $in));
855            
856             } else {
857            
858             # return transform
859 0         0 return(transform($self, $in));
860            
861             }
862            
863             }
864              
865             # read para tag from ICC profile
866             # parameters: (ref_to_object, ref_to_parent_object, file_handle, ref_to_tag_table_entry)
867             sub _readICCpara {
868              
869             # get parameters
870 16     16   42 my ($self, $parent, $fh, $tag) = @_;
871              
872             # local variables
873 16         21 my ($buf, $fun, $cnt);
874              
875             # save tag signature
876 16         33 $self->[0]{'signature'} = $tag->[0];
877              
878             # seek start of tag
879 16         129 seek($fh, $tag->[1], 0);
880              
881             # read tag type signature and function type
882 16         103 read($fh, $buf, 12);
883              
884             # unpack function type
885 16         45 $fun = unpack('x8 n x2', $buf);
886              
887             # get parameter count and verify
888 16 50       38 defined($cnt = $Np[$fun]) or croak('invalid function type when reading \'para\' tag');
889              
890             # read parameter values
891 16         32 read($fh, $buf, $cnt * 4);
892              
893             # unpack the values
894 16 100       42 $self->[1] = [$fun, map {($_ & 0x80000000) ? $_/65536 - 65536 : $_/65536} unpack("N$cnt", $buf)];
  26         81  
895              
896             }
897              
898             # write para tag to ICC profile
899             # parameters: (ref_to_object, ref_to_parent_object, file_handle, ref_to_tag_table_entry)
900             sub _writeICCpara {
901              
902             # get parameters
903 16     16   25 my ($self, $parent, $fh, $tag) = @_;
904              
905             # verify object structure
906 16 50 33     76 ($self->[1][0] == int($self->[1][0]) && defined($Np[$self->[1][0]]) && $Np[$self->[1][0]] == $#{$self->[1]}) or croak('invalid function data when writing \'para\' tag');
  16   33     44  
907              
908             # seek start of tag
909 16         115 seek($fh, $tag->[1], 0);
910              
911             # write tag
912 16         43 print $fh pack('a4 x4 n x2 N*', 'para', $self->[1][0], map {$_ * 65536} @{$self->[1]}[1 .. $#{$self->[1]}]);
  26         114  
  16         27  
  16         27  
913              
914             }
915              
916             1;