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