File Coverage

blib/lib/SVG/Barcode/UPCE.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::UPCE;
2             $SVG::Barcode::UPCE::VERSION = '0.9';
3 2     2   250813 use parent 'SVG::Barcode';
  2         759  
  2         14  
4 2     2   39009 use strict;
  2         6  
  2         56  
5 2     2   13 use warnings;
  2         4  
  2         137  
6 2     2   15 use utf8;
  2         6  
  2         19  
7 2     2   77 use v5.24;
  2         8  
8 2     2   14 use feature 'signatures';
  2         4  
  2         342  
9 2     2   14 no warnings 'experimental::signatures';
  2         5  
  2         110  
10              
11 2     2   31 use POSIX 'fmax';
  2         9  
  2         13  
12 2     2   172 use Exporter 'import';
  2         4  
  2         158  
13             our @EXPORT_OK = qw|plot_upce|;
14              
15 2     2   1330 use GD::Barcode::UPCE;
  2         6666  
  2         181  
16              
17 2         3591 use constant DEFAULTS => {
18             lineheight => 50,
19             linewidth => 1,
20             quietzone => 9, # UPCE needs an explicit quiet zone left and right
21             textsize => 10,
22 2     2   14 };
  2         4  
23              
24             SVG::Barcode::_param(__PACKAGE__, $_, DEFAULTS->{$_}) for keys DEFAULTS->%*;
25              
26             # functions
27              
28 4     4 1 234375 sub plot_upce ($text, %params) {
  3         9  
  3         7  
  3         6  
29 3         24 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         11  
  5         20  
  5         10  
  5         8  
  5         6  
36 5         9 my @line;
37 5         10 my $width = $self->{linewidth};
38 5         12 my $height = $self->{lineheight};
39             my $add_line = sub {
40 110 100   110   189 if (@line) {
41 85         179 $self->_rect(@line);
42 85         163 @line = ();
43             }
44 5         26 };
45 5         50 for my $x (0 .. $#$code) {
46 255 100       473 if ($code->[$x] eq $sign) {
    100          
47 125 100       209 if (@line) {
48 65         88 $line[2] += $width;
49             } else {
50 60         108 @line = ($x * $width, 0, $width, $height);
51             }
52             } elsif ($code->[$x] eq $signlong) {
53             # Make a slightly taller line
54 25 50       43 if (@line) {
55 0         0 $line[2] += $width;
56             } else {
57 25         64 @line = ($x * $width, 0, $width, $height * 1.1);
58             }
59             } else {
60 105         141 $add_line->();
61             }
62             }
63 5         12 $add_line->();
64             }
65              
66 5     5   238425 sub _plot ($self, $text) {
  5         11  
  5         9  
  5         10  
67 5 50 33     66 $self->{plotter} ||= GD::Barcode::UPCE->new($text)
68             or die "Cannot create GD::Barcode::UPCE plotter: " . $GD::Barcode::UPCE::errStr;
69              
70 5         267 my @code = split //, $self->{plotter}->barcode();
71 5         627 $self->_plot_1d(\@code, '1', 'G');
72 5         64 $self->_plot_text($self->{plotter}->{text});
73             }
74              
75             # We have to add the quiet zones on the sides
76 85     85   102 sub _rect ($self, $x, $y, $width, $height, $color = $self->{foreground}) {
  85         106  
  85         97  
  85         112  
  85         107  
  85         122  
  85         110  
  85         100  
77 85         124 my $x1 = $x + $self->{margin} + $self->{quietzone};
78 85         109 my $y1 = $y + $self->{margin};
79 85         212 $self->{vbwidth} = fmax($self->{vbwidth}, $x1 + $width + $self->{quietzone});
80 85         200 $self->{vbheight} = fmax($self->{vbheight}, $y1 + $height);
81             push $self->{elements}->@*,
82 85         298 qq| |;
83 85         153 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   46 sub _text ($self, $text, $x_offset, $y_offset, $size, $color = $self->{foreground}) {
  3         5  
  3         6  
  3         22  
  3         12  
  3         6  
  3         7  
  3         6  
89 3 50       12 return $self if $size == 0;
90              
91 3         19 my $escaped = $self->_xml_escape($text);
92 3         44 my $margin = $self->{margin};
93 3         5 my $qz = $self->{quietzone};
94 3         7 my $width = $self->{linewidth};
95              
96             # The full barcode string is 95 modules wide.
97             # The text is split into 3 parts:
98             # - 1st digit (system character)
99             # - next 5 digits
100             # - last 5 digits + check digit
101              
102 3         33 my ($sys_char, $middle_digits, $check_digit) =
103             $escaped =~ m/^(\d)(\d{6})(\d)$/;
104              
105 3         6 my $y1 = $y_offset; # Position below the shortest bars
106 3         15 $self->{vbheight} = fmax $self->{vbheight}, $y1 + $size; # Ensure height accounts for text
107              
108             # System character (1st digit)
109 3         7 my $x_sys = $margin; # Just inside the margin
110 3         17 push $self->{elements}->@*, qq| $sys_char|;
111              
112             # Middle 6 digits
113 3         15 my $x_left = $margin + $qz + (40 * $width) - (length($middle_digits) * $size / 2);
114 3         12 push $self->{elements}->@*, qq| $middle_digits|;
115              
116             # Check digit (last digit)
117 3         7 my $x_check = $margin + $qz + 55; # Approximately just inside the margin
118 3         23 push $self->{elements}->@*, qq| $check_digit|;
119 3         26 return $self;
120             }
121              
122             1;
123              
124             __END__