File Coverage

blib/lib/Color/Swatch/ASE/Writer.pm
Criterion Covered Total %
statement 142 152 93.4
branch 31 54 57.4
condition n/a
subroutine 26 26 100.0
pod 3 3 100.0
total 202 235 85.9


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