File Coverage

blib/lib/SVG/Barcode/EAN8.pm
Criterion Covered Total %
statement 102 103 99.0
branch 11 14 78.5
condition 1 3 33.3
subroutine 17 17 100.0
pod 1 1 100.0
total 132 138 95.6


line stmt bran cond sub pod time code
1             package SVG::Barcode::EAN8;
2             $SVG::Barcode::EAN8::VERSION = '0.9';
3 2     2   255317 use parent 'SVG::Barcode';
  2         728  
  2         14  
4 2     2   40087 use strict;
  2         4  
  2         51  
5 2     2   12 use warnings;
  2         5  
  2         139  
6 2     2   13 use utf8;
  2         6  
  2         16  
7 2     2   72 use v5.24;
  2         8  
8 2     2   12 use feature 'signatures';
  2         4  
  2         291  
9 2     2   13 no warnings 'experimental::signatures';
  2         4  
  2         122  
10              
11 2     2   16 use POSIX 'fmax';
  2         4  
  2         13  
12 2     2   216 use Exporter 'import';
  2         5  
  2         188  
13             our @EXPORT_OK = qw|plot_ean8|;
14              
15 2     2   1294 use GD::Barcode::EAN8;
  2         6177  
  2         154  
16              
17 2         3361 use constant DEFAULTS => {
18             lineheight => 50,
19             linewidth => 1,
20             quietzone => 7, # EAN8 needs a 7-module quiet zone left and right
21             textsize => 10,
22 2     2   18 };
  2         3  
23              
24             SVG::Barcode::_param(__PACKAGE__, $_, DEFAULTS->{$_}) for keys DEFAULTS->%*;
25              
26             # functions
27              
28 3     3 1 273956 sub plot_ean8 ($text, %params) {
  3         7  
  3         7  
  3         6  
29 3         28 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   26 sub _plot_1d ($self, $code, $sign, $signlong) {
  5         10  
  5         11  
  5         10  
  5         9  
  5         9  
36 5         8 my @line;
37 5         21 my $width = $self->{linewidth};
38 5         13 my $height = $self->{lineheight};
39             my $add_line = sub {
40 180 100   180   408 if (@line) {
41 110         285 $self->_rect(@line);
42 110         264 @line = ();
43             }
44 5         28 };
45 5         23 for my $x (0 .. $#$code) {
46 335 100       771 if ($code->[$x] eq $sign) {
    100          
47 130 100       229 if (@line) {
48 50         86 $line[2] += $width;
49             } else {
50 80         185 @line = ($x * $width, 0, $width, $height);
51             }
52             } elsif ($code->[$x] eq $signlong) {
53             # Make a slightly taller line
54 30 50       56 if (@line) {
55 0         0 $line[2] += $width;
56             } else {
57 30         128 @line = ($x * $width, 0, $width, $height * 1.1);
58             }
59             } else {
60 175         306 $add_line->();
61             }
62             }
63 5         13 $add_line->();
64             }
65              
66 5     5   294396 sub _plot ($self, $text) {
  5         11  
  5         9  
  5         12  
67 5 50 33     64 $self->{plotter} ||= GD::Barcode::EAN8->new($text)
68             or die "Cannot create GD::Barcode::EAN8 plotter: " . $GD::Barcode::EAN8::errStr;
69              
70 5         228 my @code = split //, $self->{plotter}->barcode();
71 5         726 $self->_plot_1d(\@code, '1', 'G');
72 5         38 $self->_plot_text($self->{plotter}->{text});
73             }
74              
75             # We have to add the quiet zones on the sides
76 110     110   174 sub _rect ($self, $x, $y, $width, $height, $color = $self->{foreground}) {
  110         164  
  110         170  
  110         165  
  110         196  
  110         199  
  110         193  
  110         161  
77 110         213 my $x1 = $x + $self->{margin} + $self->{quietzone};
78 110         219 my $y1 = $y + $self->{margin};
79 110         367 $self->{vbwidth} = fmax($self->{vbwidth}, $x1 + $width + $self->{quietzone});
80 110         351 $self->{vbheight} = fmax($self->{vbheight}, $y1 + $height);
81             push $self->{elements}->@*,
82 110         424 qq| |;
83 110         236 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   59 sub _text ($self, $text, $x_offset, $y_offset, $size, $color = $self->{foreground}) {
  3         6  
  3         53  
  3         9  
  3         6  
  3         6  
  3         8  
  3         5  
89 3 50       12 return $self if $size == 0;
90              
91 3         51 my $escaped = $self->_xml_escape($text);
92 3         44 my $margin = $self->{margin};
93 3         5 my $qz = $self->{quietzone};
94 3         8 my $width = $self->{linewidth};
95              
96             # EAN-8 text is split into two groups of 4 digits.
97 3         21 my ($left_digits, $right_digits) = $escaped =~ m/^(\d{4})(\d{4})$/;
98              
99 3         17 my $y1 = $y_offset; # Position below the shortest bars
100 3         16 $self->{vbheight} = fmax $self->{vbheight}, $y1 + $size; # Ensure height accounts for text
101              
102             # Left 4 digits (centered over left half of barcode)
103             # Barcode: 3 (start) + 28 (left) + 5 (center) + 28 (right) + 3 (end) = 67 modules
104             # Left text is centered in the 28 modules of the left data block.
105             # Center of left block is at module 3 (start) + 14 (half of 28) = 17
106 3         9 my $x_left = $margin + $qz + (17 * $width);
107             push $self->{elements}->@*,
108 3         15 qq| $left_digits|;
109              
110             # Right 4 digits (centered over right half of barcode)
111             # Center of right block is at module 3+28+5 (start+left+center) + 14 (half of 28) = 50
112 3         7 my $x_right = $margin + $qz + (50 * $width);
113             push $self->{elements}->@*,
114 3         11 qq| $right_digits|;
115              
116 3         37 return $self;
117             }
118              
119             1;
120              
121             __END__