File Coverage

blib/lib/SVG/Barcode/EAN13.pm
Criterion Covered Total %
statement 104 105 99.0
branch 11 14 78.5
condition 1 3 33.3
subroutine 17 17 100.0
pod 1 1 100.0
total 134 140 95.7


line stmt bran cond sub pod time code
1             package SVG::Barcode::EAN13;
2             $SVG::Barcode::EAN13::VERSION = '0.9';
3 2     2   222240 use parent 'SVG::Barcode';
  2         553  
  2         10  
4 2     2   32513 use strict;
  2         3  
  2         53  
5 2     2   8 use warnings;
  2         4  
  2         82  
6 2     2   8 use utf8;
  2         8  
  2         87  
7 2     2   65 use v5.24;
  2         7  
8 2     2   9 use feature 'signatures';
  2         3  
  2         265  
9 2     2   9 no warnings 'experimental::signatures';
  2         3  
  2         82  
10              
11 2     2   12 use POSIX 'fmax';
  2         3  
  2         12  
12 2     2   132 use Exporter 'import';
  2         3  
  2         103  
13             our @EXPORT_OK = qw|plot_ean13|;
14              
15 2     2   13275 use GD::Barcode::EAN13;
  2         4545  
  2         128  
16              
17 2         2375 use constant DEFAULTS => {
18             lineheight => 50,
19             linewidth => 1,
20             quietzone => 9, # EAN13 needs an explicit quiet zone left and right
21             textsize => 10,
22 2     2   12 };
  2         4  
23              
24             SVG::Barcode::_param(__PACKAGE__, $_, DEFAULTS->{$_}) for keys DEFAULTS->%*;
25              
26             # functions
27              
28 4     4 1 173553 sub plot_ean13 ($text, %params) {
  3         10  
  3         10  
  3         5  
29 3         33 return __PACKAGE__->new(%params)->plot($text);
30             }
31              
32             # internal methods
33              
34             # Add support for taller lines (typically at the sides and middle)
35 5     5   10 sub _plot_1d ($self, $code, $sign, $signlong) {
  5         9  
  5         29  
  5         9  
  5         7  
  5         8  
36 5         8 my @line;
37 5         23 my $width = $self->{linewidth};
38 5         11 my $height = $self->{lineheight};
39             my $add_line = sub {
40 255 100   255   373 if (@line) {
41 150         242 $self->_rect(@line);
42 150         205 @line = ();
43             }
44 5         24 };
45 5         20 for my $x (0 .. $#$code) {
46 475 100       610 if ($code->[$x] eq $sign) {
    100          
47 195 100       246 if (@line) {
48 75         85 $line[2] += $width;
49             } else {
50 120         181 @line = ($x * $width, 0, $width, $height);
51             }
52             } elsif ($code->[$x] eq $signlong) {
53             # Make a slightly taller line
54 30 50       35 if (@line) {
55 0         0 $line[2] += $width;
56             } else {
57 30         64 @line = ($x * $width, 0, $width, $height * 1.1);
58             }
59             } else {
60 250         255 $add_line->();
61             }
62             }
63 5         12 $add_line->();
64             }
65              
66 5     5   212548 sub _plot ($self, $text) {
  5         11  
  5         8  
  5         31  
67 5 50 33     66 $self->{plotter} ||= GD::Barcode::EAN13->new($text)
68             or die "Cannot create GD::Barcode::EAN13 plotter: " . $GD::Barcode::EAN13::errStr;
69              
70 5         207 my @code = split //, $self->{plotter}->barcode();
71 5         944 $self->_plot_1d(\@code, '1', 'G');
72 5         33 $self->_plot_text($self->{plotter}->{text});
73             }
74              
75             # We have to add the quiet zones on the sides
76 150     150   127 sub _rect ($self, $x, $y, $width, $height, $color = $self->{foreground}) {
  150         177  
  150         137  
  150         138  
  150         187  
  150         156  
  150         159  
  150         172  
77 150         168 my $x1 = $x + $self->{margin} + $self->{quietzone};
78 150         147 my $y1 = $y + $self->{margin};
79 150         264 $self->{vbwidth} = fmax($self->{vbwidth}, $x1 + $width + $self->{quietzone});
80 150         220 $self->{vbheight} = fmax($self->{vbheight}, $y1 + $height);
81             push $self->{elements}->@*,
82 150         374 qq| |;
83 150         171 return $self;
84             }
85              
86             # Handle aligning the text below the barcode
87             # TODO: find a better way to calculate the positions relative to the bars
88 3     3   65 sub _text ($self, $text, $x_offset, $y_offset, $size, $color = $self->{foreground}) {
  3         5  
  3         5  
  3         6  
  3         18  
  3         5  
  3         6  
  3         4  
89 3 50       8 return $self if $size == 0;
90              
91 3         18 my $escaped = $self->_xml_escape($text);
92 3         33 my $margin = $self->{margin};
93 3         5 my $qz = $self->{quietzone};
94 3         4 my $width = $self->{linewidth};
95              
96 3         21 my ($sys_char, $left_digits, $right_digits) =
97             $escaped =~ m/^(\d)(\d{6})(\d{6})$/;
98              
99 3         5 my $y1 = $y_offset; # Position below the shortest bars
100 3         9 $self->{vbheight} = fmax $self->{vbheight}, $y1 + $size; # Ensure height accounts for text
101              
102             # System character (1st digit)
103 3         6 my $x_sys = $margin; # Just inside the margin
104 3         14 push $self->{elements}->@*, qq| $sys_char|;
105              
106             # Left 6 digits
107 3         16 my $x_left = $margin + $qz + (40 * $width) - (length($left_digits) * $size / 2);
108 3         9 push $self->{elements}->@*, qq| $left_digits|;
109              
110             # Right 6 digits
111 3         8 my $x_right = $margin + $qz + (85 * $width) - (length($right_digits) * $size / 2);
112 3         12 push $self->{elements}->@*, qq| $right_digits|;
113              
114 3         23 return $self;
115             }
116              
117             1;
118              
119             __END__