File Coverage

blib/lib/ICC/Profile/para.pm
Criterion Covered Total %
statement 45 215 20.9
branch 7 152 4.6
condition 2 27 7.4
subroutine 10 21 47.6
pod 1 13 7.6
total 65 428 15.1


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