File Coverage

blib/lib/SVG/Barcode.pm
Criterion Covered Total %
statement 112 158 70.8
branch 6 20 30.0
condition n/a
subroutine 27 32 84.3
pod 9 9 100.0
total 154 219 70.3


line stmt bran cond sub pod time code
1             package SVG::Barcode;
2 1     1   64496 use strict;
  1         10  
  1         27  
3 1     1   4 use warnings;
  1         2  
  1         24  
4 1     1   3 use utf8;
  1         2  
  1         5  
5 1     1   24 use v5.24;
  1         3  
6 1     1   6 use feature 'signatures';
  1         2  
  1         110  
7 1     1   5 no warnings 'experimental::signatures';
  1         2  
  1         44  
8              
9 1     1   5 use Carp 'croak';
  1         1  
  1         50  
10 1     1   455 use POSIX 'fmax';
  1         5548  
  1         5  
11 1     1   1610 use Sub::Util 'set_subname';
  1         271  
  1         69  
12              
13             our $VERSION = '0.10';
14              
15 1         412 use constant DEFAULTS => {
16             background => 'white',
17             class => '',
18             foreground => 'black',
19             height => '',
20             id => '',
21             margin => 2,
22             width => '',
23 1     1   6 };
  1         2  
24              
25             _param(__PACKAGE__, $_, DEFAULTS->{$_}) for keys DEFAULTS->%*;
26              
27             # constructor
28              
29 4     4 1 2275 sub new ($class, %params) {
  4         5  
  4         10  
  4         4  
30 4         35 my $self = bless {DEFAULTS->%*, $class->DEFAULTS->%*}, $class;
31              
32 4         69 $self->$_($params{$_}) for keys %params;
33              
34 3         21 return $self;
35             }
36              
37             # methods
38              
39 3     3 1 464 sub plot ($self, $text) {
  2         4  
  2         3  
  2         3  
40             $self->{elements}
41 2         9 = [qq| |];
42 2         6 $self->{vbwidth} = $self->{vbheight} = 0;
43              
44 2         6 $self->_plot($text);
45              
46 1         2 $self->{vbheight} += $self->{margin};
47 1         2 $self->{vbwidth} += $self->{margin};
48 1         5 my @attr = (qq|viewBox="0 0 $self->{vbwidth} $self->{vbheight}"|);
49 1         3 for my $name (qw|id class width height|) {
50 4 100       11 my $value = $self->$name or next;
51 2         7 push @attr, qq|$name="$value"|;
52             }
53 1         6 my $attributes = join ' ', sort @attr;
54              
55             my $svg
56             = qq|\n|
57             . join("\n", $self->{elements}->@*)
58 1         7 . qq|\n|;
59              
60 1         5 return $svg;
61             }
62              
63             # internal methods
64              
65 7     7   10 sub _param ($class, $name, $default) {
  7         8  
  7         8  
  7         8  
  7         7  
66 1     1   7 no strict 'refs'; ## no critic 'ProhibitNoStrict'
  1         2  
  1         31  
67 1     1   4 no warnings 'redefine';
  1         2  
  1         1085  
68 7     27 1 28 *{"${class}::$name"} = set_subname $name, sub ($self, $newvalue = undef) {
  27     27 1 29  
  27     27 1 8437  
  27     27 1 32  
  27     27 1 34  
        27 1    
        27 1    
        27      
69 27 100       46 if (defined $newvalue) {
70 7 100       17 $self->{$name} = $newvalue eq '' ? $default : $newvalue;
71 7         10 delete $self->{plotter};
72 7         21 return $self;
73             } else {
74 20         78 return $self->{$name};
75             }
76 7         40 };
77             }
78              
79 1     1   2 sub _plot (@) {
  1         2  
80 1         160 croak 'Method _plot not implemented by subclass!';
81             }
82              
83 0     0   0 sub _plot_1d ($self, $code, $sign) {
  0         0  
  0         0  
  0         0  
  0         0  
84 0         0 my @line;
85 0         0 my $width = $self->{linewidth};
86 0         0 my $height = $self->{lineheight};
87             my $add_line = sub {
88 0 0   0   0 if (@line) {
89 0         0 $self->_rect(@line);
90 0         0 @line = ();
91             }
92 0         0 };
93              
94 0         0 for my $x (0 .. $#$code) {
95 0 0       0 if ($code->[$x] eq $sign) {
96 0 0       0 if (@line) {
97 0         0 $line[2] += $width;
98             } else {
99 0         0 @line = ($x * $width, 0, $width, $height);
100             }
101             } else {
102 0         0 $add_line->();
103             }
104             }
105 0         0 $add_line->();
106             }
107              
108 0     0   0 sub _plot_2d ($self, $code, $sign) {
  0         0  
  0         0  
  0         0  
  0         0  
109 0         0 my $x_max = $code->[0]->@* - 1;
110 0         0 my $y_max = $code->@* - 1;
111              
112 0         0 my @dot;
113 0         0 my $dotsize = $self->{dotsize};
114             my $add_dot = sub {
115 0 0   0   0 if (@dot) {
116 0         0 $self->_rect(@dot);
117 0         0 @dot = ();
118             }
119 0         0 };
120              
121 0         0 for my $y (0 .. $y_max) {
122 0         0 for my $x (0 .. $x_max) {
123 0 0       0 if ($code->[$y][$x] eq $sign) {
124 0 0       0 if (@dot) {
125 0         0 $dot[2] += $dotsize;
126             } else {
127 0         0 @dot = ($x * $dotsize, $y * $dotsize, $dotsize, $dotsize);
128             }
129             } else {
130 0         0 $add_dot->();
131             }
132             }
133 0         0 $add_dot->();
134             }
135             }
136              
137 0     0   0 sub _plot_text ($self, $text) {
  0         0  
  0         0  
  0         0  
138 0 0       0 if (my $size = $self->{textsize}) {
139 0         0 $self->_text($text, 0, $self->{lineheight} + $size, $size);
140             }
141             }
142              
143 4     4   17 sub _rect ($self, $x, $y, $width, $height, $color = $self->{foreground}) {
  4         6  
  4         4  
  4         6  
  4         3  
  4         5  
  4         6  
  4         5  
144 4         6 my $x1 = $x + $self->{margin};
145 4         5 my $y1 = $y + $self->{margin};
146 4         13 $self->{vbwidth} = fmax $self->{vbwidth}, $x1 + $width;
147 4         8 $self->{vbheight} = fmax $self->{vbheight}, $y1 + $height;
148              
149             push $self->{elements}->@*,
150 4         13 qq| |;
151              
152 4         8 return $self;
153             }
154              
155 1     1   5 sub _text ($self, $text, $x, $y, $size, $color = $self->{foreground}) {
  1         2  
  1         2  
  1         3  
  1         2  
  1         1  
  1         2  
  1         2  
156 1         4 my $escaped = $self->_xml_escape($text);
157 1         3 my $x1 = $x + $self->{margin};
158 1         3 my $y1 = $y + $self->{margin};
159 1         3 $self->{vbheight} = fmax $self->{vbheight}, $y1;
160              
161             push $self->{elements}->@*,
162 1         11 qq| $escaped|;
163              
164 1         2 return $self;
165             }
166              
167             # from Mojo::Util
168             my %XML = (
169             '&' => '&',
170             '<' => '<',
171             '>' => '>',
172             '"' => '"',
173             '\'' => '''
174             );
175              
176 1     1   2 sub _xml_escape ($self, $str) {
  1         2  
  1         2  
  1         1  
177 1         7 $str =~ s/([&<>"'])/$XML{$1}/ge;
  2         7  
178 1         3 return $str;
179             }
180              
181             1;
182              
183             =encoding utf8
184              
185             =head1 NAME
186              
187             SVG::Barcode - Base class for SVG 1D and 2D codes
188              
189             =head1 SYNOPSIS
190              
191             use SVG::Barcode::Subclass;
192              
193             my $plotter = SVG::Barcode::Subclass->new;
194              
195             $plotter->foreground; # black
196             $plotter->background; # white
197             $plotter->margin; # 2
198             $plotter->id;
199             $plotter->class;
200             $plotter->width;
201             $plotter->height;
202              
203             %params = (
204             foreground => 'red',
205             id => 'barcode',
206             );
207             $plotter = SVG::Barcode::Subclass->new(%params);
208              
209             my $svg = $plotter->plot($text);
210              
211             =head1 DESCRIPTION
212              
213             L is a base class for SVG 1D and 2D codes.
214              
215             You will not use it directly, it will be loaded by its subclasses:
216              
217             =over
218              
219             =item * L
220              
221             =item * L
222              
223             =item * L
224              
225             =back
226              
227             =head1 CONSTRUCTOR
228              
229             =head2 new
230              
231             $plotter = SVG::Barcode::Subclass->new; # create with defaults
232             $plotter = SVG::Barcode::Subclass->new(%params);
233              
234             =head1 METHODS
235              
236             =head2 plot
237              
238             $svg = $plotter->plot($text);
239              
240             Creates a barcode.
241              
242             =head1 PARAMETERS
243              
244             =head2 background
245              
246             $value = $plotter->background;
247             $plotter = $plotter->background($newvalue);
248             $plotter = $plotter->background(''); # white
249              
250             Getter and setter for the background color. Default C.
251              
252             =head2 class
253              
254             $value = $plotter->class;
255             $plotter = $plotter->class($newvalue);
256             $plotter = $plotter->class(''); # ''
257              
258             Getter and setter for the class of the svg element. Default C<''>.
259              
260             =head2 foreground
261              
262             $value = $plotter->foreground;
263             $plotter = $plotter->foreground($newvalue);
264             $plotter = $plotter->foreground(''); # black
265              
266             Getter and setter for the foreground color. Default C.
267              
268             =head2 height
269              
270             $value = $plotter->height;
271             $plotter = $plotter->height($newvalue);
272             $plotter = $plotter->height(''); # ''
273              
274             Getter and setter for the height of the svg element. Default C<''>.
275              
276             =head2 id
277              
278             $value = $plotter->id;
279             $plotter = $plotter->id($newvalue);
280             $plotter = $plotter->id(''); # ''
281              
282             Getter and setter for the id of the svg element. Default C<''>.
283              
284             =head2 margin
285              
286             $value = $plotter->margin;
287             $plotter = $plotter->margin($newvalue);
288             $plotter = $plotter->margin(''); # 2
289              
290             Getter and setter for the margin around the barcode. Default C<2>.
291              
292             =head2 width
293              
294             $value = $plotter->width;
295             $plotter = $plotter->width($newvalue);
296             $plotter = $plotter->width(''); # ''
297              
298             Getter and setter for the width of the svg element. Default C<''>.
299              
300             =head1 SEE ALSO
301              
302             L, L, L.
303              
304             =head1 AUTHOR & COPYRIGHT
305              
306             © 2019 by Tekki (Rolf Stöckli).
307              
308             This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.
309              
310             =cut