File Coverage

lib/Color/Swatch/ASE/Writer.pm
Criterion Covered Total %
statement 146 156 93.5
branch 31 54 57.4
condition n/a
subroutine 27 27 100.0
pod 3 3 100.0
total 207 240 86.2


line stmt bran cond sub pod time code
1 12     12   679625 use 5.010; # pack >
  12         47  
  12         589  
2 12     12   70 use strict;
  12         25  
  12         696  
3 12     12   80 use warnings;
  12         23  
  12         469  
4 12     12   18278 use utf8;
  12         131  
  12         71  
5              
6             package Color::Swatch::ASE::Writer;
7              
8             our $VERSION = '0.001002';
9              
10             # ABSTRACT: Low level ASE ( Adobe Swatch Exchange ) file Writer.
11              
12             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
13              
14 12     12   16629 use Encode qw(encode);
  12         270189  
  12         38416  
15              
16             ## no critic (ValuesAndExpressions::ProhibitEscapedCharacters)
17             my $BLOCK_GROUP_START = "\x{c0}\x{01}";
18             my $BLOCK_GROUP_END = "\x{c0}\x{02}";
19             my $BLOCK_COLOR = "\x{00}\x{01}";
20             my $UTF16NULL = "\x{00}\x{00}";
21             ## use critic
22              
23              
24              
25              
26              
27              
28              
29             sub write_string {
30 11     11 1 317 my ( $class, $struct ) = @_;
31 11         29 my $out = q[];
32 11         81 $class->_write_signature( \$out, $struct->{signature} );
33 11 50       28 $class->_write_version( \$out, @{ $struct->{version} || [ 1, 0 ] } );
  11         136  
34 11         22 my @blocks = @{ $struct->{blocks} };
  11         35  
35              
36 11         59 $class->_write_num_blocks( \$out, scalar @blocks );
37              
38 11         426 for my $block ( 0 .. $#blocks ) {
39 23         2659 $class->_write_block( \$out, $blocks[$block] );
40             }
41              
42 11         68 return $out;
43             }
44              
45              
46              
47              
48              
49              
50              
51             sub write_filehandle {
52 1     1 1 24957 my ( $class, $filehandle, $structure ) = @_;
53 1         3 return print {$filehandle} $class->write_string($structure);
  1         6  
54             }
55              
56              
57              
58              
59              
60              
61              
62             sub write_file {
63 1     1 1 26320 my ( $class, $filename, $structure ) = @_;
64 1         11 require Path::Tiny;
65 1         6 return Path::Tiny::path($filename)->spew_raw( $class->write_string($structure) );
66             }
67              
68             sub _write_signature {
69 11     11   39 my ( undef, $string, $signature ) = @_;
70 11 50       52 $signature = 'ASEF' if not defined $signature;
71 11 50       57 if ( 'ASEF' ne $signature ) {
72 0         0 die 'Signature must be ASEF';
73             }
74 11         23 ${$string} .= $signature;
  11         35  
75 11         28 return;
76             }
77              
78             sub _write_bytes {
79 102     102   459 my ( undef, $string, $length, $bytes, $format ) = @_;
80 102         124 my @bytes;
81 102 50       568 if ( ref $bytes ) {
82 102         297 @bytes = @{$bytes};
  102         572  
83             }
84             else {
85 0         0 @bytes = ($bytes);
86             }
87 102         172 my $append = q[];
88 102 100       369 if ( not defined $format ) {
89 29         108 $append .= $_ for @bytes;
90             }
91             else {
92 73         600 $append = pack $format, @bytes;
93             }
94 102 50       798 if ( ( length $append ) ne $length ) {
95 0         0 warn 'Pack length did not match expected pack length!';
96             }
97 102 50       769 if ( $ENV{TRACE_ASE} ) {
98 0 0       0 *STDERR->printf( q[%s : %s %s = ], [ caller 1 ]->[3], $length, ( $format ? $format : q[] ) );
99 0         0 *STDERR->printf( q[%02x ], ord $_ ) for split //msx, $append;
100 0         0 *STDERR->printf("\n ");
101             }
102              
103 102         120 ${$string} .= $append;
  102         527  
104 102         550 return;
105             }
106              
107             sub _write_version {
108 11     11   35 my ( $self, $string, $version_major, $version_minor ) = @_;
109 11 50       56 $version_major = 1 if not defined $version_major;
110 11 50       42 $version_minor = 0 if not defined $version_minor;
111 11         71 $self->_write_bytes( $string, 4, [ $version_major, $version_minor ], q[nn] );
112 11         29 return;
113             }
114              
115             sub _write_num_blocks {
116 11     11   66 my ( $self, $string, $num_blocks ) = @_;
117 11         50 $self->_write_bytes( $string, 4, [$num_blocks], q[N] );
118 11         25 return;
119             }
120              
121             sub _write_block_group {
122 16     16   54 my ( $self, $string, $group, $default ) = @_;
123 16 100       221 $group = $default if not defined $group;
124 16         65 $self->_write_bytes( $string, 2, [$group], q[n] );
125 16         45 return;
126             }
127              
128             sub _write_block_label {
129 16     16   47 my ( undef, $string, $label ) = @_;
130 16 100       596 $label = q[] if not defined $label;
131 16         609 my $label_chars = encode( 'UTF16-BE', $label, Encode::FB_CROAK );
132 16         55004 $label_chars .= $UTF16NULL;
133 16 50       83 if ( $ENV{TRACE_ASE} ) {
134 0         0 *STDERR->printf( q[%s : = ], [ caller 0 ]->[3] );
135 0         0 *STDERR->printf( q[%02x ], ord $_ ) for split //msx, $label_chars;
136 0         0 *STDERR->printf("\n ");
137             }
138              
139 16         34 ${$string} .= $label_chars;
  16         43  
140 16         38 return;
141             }
142              
143             sub _write_group_start {
144 10     10   25 my ( $self, $string, $block ) = @_;
145 10         414 $self->_write_block_group( $string, $block->{group}, 13 );
146 10         217 $self->_write_block_label( $string, $block->{label} );
147 10         33 return;
148             }
149              
150             sub _write_group_end {
151 7     7   20 my ( undef, $string ) = @_;
152 7         12 ${$string} .= q[];
  7         187  
153 7         16 return;
154             }
155              
156             my $color_table = {
157             q[RGB ] => '_write_rgb',
158             q[LAB ] => '_write_lab',
159             q[CMYK] => '_write_cmyk',
160             q[Gray] => '_write_gray',
161             };
162              
163             sub _write_color_model {
164 6     6   16 my ( $self, $string, $model ) = @_;
165 6 50       25 die 'Color model not defined' if not defined $model;
166 6 50       29 die "Unknown color model $model" if not exists $color_table->{$model};
167 6         27 $self->_write_bytes( $string, 4, [$model] );
168 6         14 return;
169             }
170              
171             sub _write_rgb {
172 3     3   10 my ( $self, $string, @color ) = @_;
173 3 50       8 die 'RGB requires 3 values' if 3 != grep { defined and length } @color;
  9 50       95  
174 3         14 $self->_write_bytes( $string, 12, [@color], q[f>f>f>] );
175 3         9 return;
176             }
177              
178             sub _write_lab {
179 1     1   4 my ( $self, $string, @color ) = @_;
180 1 50       2 die 'LAB requires 3 values' if 3 != grep { defined and length } @color;
  3 50       289  
181              
182 1         680 $self->_write_bytes( $string, 12, [@color], q[f>f>f>] );
183 1         4 return;
184             }
185              
186             sub _write_cmyk {
187 1     1   4 my ( $self, $string, @color ) = @_;
188 1 50       2 die 'CMYK requires 4 values' if 4 != grep { defined and length } @color;
  4 50       40  
189 1         4 $self->_write_bytes( $string, 16, [@color], q[f>f>f>f>] );
190 1         4 return;
191             }
192              
193             sub _write_gray {
194 1     1   3 my ( $self, $string, @color ) = @_;
195 1 50       3 die 'Gray requires 1 value' if 1 != grep { defined and length } @color;
  1 50       25  
196 1         5 $self->_write_bytes( $string, 4, [@color], q[f>] );
197 1         3 return;
198             }
199              
200             sub _write_color_type {
201 6     6   20 my ( $self, $string, $type ) = @_;
202 6 50       26 $type = 2 if not defined $type;
203 6         26 $self->_write_bytes( $string, 2, [$type], q[n] );
204 6         175 return;
205             }
206              
207             sub _write_color {
208 6     6   17 my ( $self, $string, $block ) = @_;
209 6         42 $self->_write_block_group( $string, $block->{group}, 1 );
210 6         38 $self->_write_block_label( $string, $block->{label} );
211 6         39 $self->_write_color_model( $string, $block->{model} );
212 6         81 my $color_writer = $self->can( $color_table->{ $block->{model} } );
213 6         16 $self->$color_writer( $string, @{ $block->{values} } );
  6         27  
214 6         34 $self->_write_color_type( $string, $block->{color_type} );
215 6         17 return;
216             }
217              
218             sub _write_block_type {
219 23     23   42 my ( $self, $string, $type ) = @_;
220 23         118 $self->_write_bytes( $string, 2, [$type] );
221 23         212 return;
222             }
223              
224             sub _write_block_length {
225 23     23   44 my ( $self, $string, $length ) = @_;
226 23         253 $self->_write_bytes( $string, 4, [$length], q[N] );
227 23         48 return;
228             }
229              
230             sub _write_block_payload {
231 23     23   316 my ( $self, $string, $block_id, $block_body ) = @_;
232 23         97 $self->_write_block_type( $string, $block_id );
233 23         37 $self->_write_block_length( $string, length ${$block_body} );
  23         260  
234 23         32 ${$string} .= ${$block_body};
  23         40  
  23         80  
235 23         55 return;
236             }
237              
238             sub _write_block {
239 23     23   54 my ( $self, $string, $block ) = @_;
240              
241 23         201 my $block_body = q[];
242 23 100       246 if ( 'group_start' eq $block->{type} ) {
243 10         210 $self->_write_group_start( \$block_body, $block );
244 10         384 $self->_write_block_payload( $string, $BLOCK_GROUP_START, \$block_body );
245 10         33 return;
246             }
247 13 100       53 if ( 'group_end' eq $block->{type} ) {
248 7         715 $self->_write_group_end( \$block_body, $block );
249 7         188 $self->_write_block_payload( $string, $BLOCK_GROUP_END, \$block_body );
250 7         22 return;
251             }
252 6 50       30 if ( 'color' eq $block->{type} ) {
253 6         32 $self->_write_color( \$block_body, $block );
254 6         25 $self->_write_block_payload( $string, $BLOCK_COLOR, \$block_body );
255 6         19 return;
256             }
257 0           die 'Unknown block type ' . $block->{type};
258             }
259             1;
260              
261             __END__