File Coverage

blib/lib/PDF/Builder/Resource/XObject/Form/BarCode.pm
Criterion Covered Total %
statement 105 130 80.7
branch 26 36 72.2
condition 37 70 52.8
subroutine 9 11 81.8
pod 3 6 50.0
total 180 253 71.1


line stmt bran cond sub pod time code
1             package PDF::Builder::Resource::XObject::Form::BarCode;
2              
3 2     2   1514 use base 'PDF::Builder::Resource::XObject::Form::Hybrid';
  2         6  
  2         284  
4              
5 2     2   14 use strict;
  2         3  
  2         48  
6 2     2   23 use warnings;
  2         4  
  2         194  
7              
8             our $VERSION = '3.028'; # VERSION
9             our $LAST_UPDATE = '3.027'; # manually update whenever code is changed
10              
11 2     2   12 use PDF::Builder::Util;
  2         5  
  2         367  
12 2     2   14 use PDF::Builder::Basic::PDF::Utils;
  2         223  
  2         3352  
13              
14             =head1 NAME
15              
16             PDF::Builder::Resource::XObject::Form::BarCode - Base class for one-dimensional barcodes
17              
18             Inherits from L<PDF::Builder::Resource::XObject::Form::Hybrid>
19              
20             =head1 METHODS
21              
22             =head2 new
23              
24             $barcode = PDF::Builder::Resource::XObject::Form::BarCode->new($pdf, %options)
25              
26             =over
27              
28             Creates a barcode form resource.
29              
30             =back
31              
32             =cut
33              
34             sub new {
35 6     6 1 25 my ($class, $pdf, %options) = @_;
36             # copy dashed option names to preferred undashed names
37 6 100 66     28 if (defined $options{'-font'} && !defined $options{'font'}) { $options{'font'} = delete($options{'-font'}); }
  1         3  
38 6 100 66     22 if (defined $options{'-umzn'} && !defined $options{'umzn'}) { $options{'umzn'} = delete($options{'-umzn'}); }
  1         2  
39 6 100 66     22 if (defined $options{'-lmzn'} && !defined $options{'lmzn'}) { $options{'lmzn'} = delete($options{'-lmzn'}); }
  1         3  
40 6 100 66     22 if (defined $options{'-zone'} && !defined $options{'zone'}) { $options{'zone'} = delete($options{'-zone'}); }
  1         15  
41 6 50 33     15 if (defined $options{'-quzn'} && !defined $options{'quzn'}) { $options{'quzn'} = delete($options{'-quzn'}); }
  0         0  
42 6 50 33     17 if (defined $options{'-ofwt'} && !defined $options{'ofwt'}) { $options{'ofwt'} = delete($options{'-ofwt'}); }
  0         0  
43 6 100 66     19 if (defined $options{'-fnsz'} && !defined $options{'fnsz'}) { $options{'fnsz'} = delete($options{'-fnsz'}); }
  1         2  
44 6 50 33     21 if (defined $options{'-spcr'} && !defined $options{'spcr'}) { $options{'spcr'} = delete($options{'-spcr'}); }
  0         0  
45 6 50 33     34 if (defined $options{'-mils'} && !defined $options{'mils'}) { $options{'mils'} = delete($options{'-mils'}); }
  0         0  
46 6 50 33     19 if (defined $options{'-color'} && !defined $options{'color'}) { $options{'color'} = delete($options{'-color'}); }
  0         0  
47              
48 6         39 my $self = $class->SUPER::new($pdf);
49              
50 6         17 $self->{' bfont'} = $options{'font'};
51              
52 6   50     29 $self->{' umzn'} = $options{'umzn'} || 0; # (u)pper (m)ending (z)o(n)e
53 6   100     21 $self->{' lmzn'} = $options{'lmzn'} || 0; # (l)ower (m)ending (z)o(n)e
54 6   100     23 $self->{' zone'} = $options{'zone'} || 0; # barcode height
55 6   50     74 $self->{' quzn'} = $options{'quzn'} || 0; # (qu)iet (z)o(n)e
56 6   50     21 $self->{' ofwt'} = $options{'ofwt'} || 0.01; # (o)ver(f)low (w)id(t)h
57 6         15 $self->{' fnsz'} = $options{'fnsz'}; # (f)o(n)t(s)i(z)e
58 6   50     24 $self->{' spcr'} = $options{'spcr'} || ''; # (sp)a(c)e(r) between chars in label
59 6   50     21 $self->{' mils'} = $options{'mils'} || 1000/72; # single barcode unit width. 1 mil = 1/1000 of one inch. 1000/72 - for backward compatibility
60 6   50     23 $self->{' color'} = $options{'color'} || 'black'; # barcode color
61              
62 6         20 return $self;
63             }
64              
65             my %bar_widths = (
66             0 => 0,
67             1 => 1, 'a' => 1, 'A' => 1,
68             2 => 2, 'b' => 2, 'B' => 2,
69             3 => 3, 'c' => 3, 'C' => 3,
70             4 => 4, 'd' => 4, 'D' => 4,
71             5 => 5, 'e' => 5, 'E' => 5,
72             6 => 6, 'f' => 6, 'F' => 6,
73             7 => 7, 'g' => 7, 'G' => 7,
74             8 => 8, 'h' => 8, 'H' => 8,
75             9 => 9, 'i' => 9, 'I' => 9,
76             );
77              
78             sub encode {
79 2     2 0 2197 my ($self, $string) = @_;
80              
81 2         9 my @bars = map { [ $self->encode_string($_), $_ ] } split(//, $string);
  17         26  
82 2         7 return @bars;
83             }
84              
85             sub encode_string {
86 17     17 0 19 my ($self, $string) = @_;
87              
88 17         18 my $bar;
89 17         24 foreach my $character (split(//, $string)) {
90 17         26 $bar .= $self->encode_char($character);
91             }
92 17         38 return $bar;
93             }
94              
95             sub drawbar {
96 6     6 0 15 my $self = shift();
97 6         10 my @sets = @{shift()};
  6         21  
98 6         19 my $caption = shift();
99              
100 6         63 $self->fillcolor($self->{' color'});
101 6         68 $self->strokecolor($self->{' color'});
102 6         50 $self->linedash();
103              
104 6         14 my $x = $self->{' quzn'};
105 6         11 my $is_space_next = 0;
106 6         22 my $wdt_factor = $self->{' mils'} / 1000 * 72;
107 6         13 foreach my $set (@sets) {
108 30         82 my ($code, $label);
109 30 100       66 if (ref($set)) {
110 18         29 ($code, $label) = @{$set};
  18         201  
111             } else {
112 12         24 $code = $set;
113 12         26 $label = undef;
114             }
115              
116 30         51 my $code_width = 0;
117 30         49 my ($font_size, $y_label);
118 30         105 foreach my $bar (split(//, $code)) {
119 172         386 my $bar_width = $bar_widths{$bar} * $wdt_factor;
120              
121 172         281 my ($y0, $y1);
122 172 100       636 if ($bar =~ /[0-9]/) {
    50          
    0          
123 115         250 $y0 = $self->{' quzn'} + $self->{' lmzn'};
124 115         218 $y1 = $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'} + $self->{' umzn'};
125 115         190 $y_label = $self->{' quzn'};
126 115 50 66     306 if ($self->{' fnsz'} and $self->{' lmzn'} < $self->{' fnsz'}) {
127 0         0 $y_label -= $self->{' fnsz'} * 0.8 - $self->{' lmzn'};
128             }
129 115   66     391 $font_size = $self->{' fnsz'} || $self->{' lmzn'};
130             } elsif ($bar =~ /[a-z]/) {
131 57         93 $y0 = $self->{' quzn'};
132 57         105 $y1 = $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'} + $self->{' umzn'};
133 57         109 $y_label = $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'} + $self->{' umzn'} + 2;
134 57   66     182 $font_size = $self->{' fnsz'} || $self->{' umzn'};
135             } elsif ($bar =~ /[A-Z]/) {
136 0         0 $y0 = $self->{' quzn'};
137 0         0 $y1 = $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'};
138 0   0     0 $font_size = $self->{' fnsz'} || $self->{' umzn'};
139 0         0 $y_label = $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'} + $self->{' umzn'} - $font_size;
140             } else {
141 0         0 $y0 = $self->{' quzn'} + $self->{' lmzn'};
142 0         0 $y1 = $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'} + $self->{' umzn'};
143 0         0 $y_label = $self->{' quzn'};
144 0   0     0 $font_size = $self->{' fnsz'} || $self->{' lmzn'};
145             }
146              
147 172 100 100     528 unless ($is_space_next or $bar eq '0') {
148 86         499 $self->linewidth($bar_width - $self->{' ofwt'});
149 86         418 $self->move($x + $code_width + $bar_width / 2, $y0);
150 86         400 $self->line($x + $code_width + $bar_width / 2, $y1);
151 86         304 $self->stroke();
152             }
153 172         304 $is_space_next = not $is_space_next;
154              
155 172         341 $code_width += $bar_width;
156             }
157              
158 30 100 100     146 if (defined($label) and $self->{' lmzn'}) {
159 1         5 $label = join($self->{' spcr'}, split(//, $label));
160 1         21 $self->textstart();
161 1         12 $self->translate($x + ($code_width / 2), $y_label);
162 1         9 $self->font($self->{' bfont'}, $font_size);
163 1         22 $self->text_center($label);
164 1         7 $self->textend();
165             }
166              
167 30         65 $x += $code_width;
168             }
169              
170 6         14 $x += $self->{' quzn'};
171              
172 6 50       15 if (defined $caption) {
173 0   0     0 my $font_size = $self->{' fnsz'} || $self->{' lmzn'};
174 0         0 my $y_caption = $self->{' quzn'} - $font_size;
175 0         0 $self->textstart();
176 0         0 $self->translate($x / 2, $y_caption);
177 0         0 $self->font($self->{' bfont'}, $font_size);
178 0         0 $self->text_center($caption);
179 0         0 $self->textend();
180             }
181              
182 6         16 $self->{' w'} = $x;
183 6         36 $self->{' h'} = 2 * $self->{' quzn'} + $self->{' lmzn'} + $self->{' zone'} + $self->{' umzn'};
184 6         93 $self->bbox(0, 0, $self->{' w'}, $self->{' h'});
185 6         27 return;
186             }
187              
188             =head2 width
189              
190             $width = $barcode->width()
191              
192             =over
193              
194             Returns the width of the bar code.
195              
196             =back
197              
198             =cut
199              
200             sub width {
201 0     0 1   my $self = shift;
202              
203 0           return $self->{' w'};
204             }
205              
206             =head2 height
207              
208             $height = $barcode->height()
209              
210             =over
211              
212             Returns the height of the bar code.
213              
214             =back
215              
216             =cut
217              
218              
219             sub height {
220 0     0 1   my $self = shift;
221              
222 0           return $self->{' h'};
223             }
224              
225             1;