File Coverage

blib/lib/SVG/Barcode.pm
Criterion Covered Total %
statement 116 162 71.6
branch 8 24 33.3
condition 1 3 33.3
subroutine 28 33 84.8
pod 10 10 100.0
total 163 232 70.2


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