#
# This file is part of Koha.
#
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
#
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
use strict;
use warnings;
use autouse 'Data::Dumper' => qw(Dumper);
-use Text::Wrap qw(wrap);
#use Font::TTFMetrics;
-use C4::Creators::Lib 1.000000 qw(get_font_types);
-use C4::Creators::PDF 1.000000 qw(StrWidth);
-use C4::Patroncards::Lib 1.000000 qw(unpack_UTF8 text_alignment leading box get_borrower_attributes);
+use C4::Creators::Lib qw( get_unit_values );
+use C4::Creators::PDF qw(StrWidth);
+use C4::Patroncards::Lib qw(
+ box
+ get_borrower_attributes
+ leading
+ text_alignment
+);
-BEGIN {
- use version; our $VERSION = qv('1.0.0_1');
-}
+=head1 NAME
+
+C4::Patroncards::Patroncard
+
+=head1 SYNOPSIS
+
+ use C4::Patroncards::Patroncard;
+
+ # Please extend
+
+
+=head1 DESCRIPTION
+
+ This module allows you to ...
+
+=head1 FUNCTIONS
+
+=head2 new
+
+=cut
sub new {
my ($invocant, %params) = @_;
my $type = ref($invocant) || $invocant;
+
+ my $units = get_unit_values();
+ my $unitvalue = 1;
+ my $unitdesc = '';
+ foreach my $un (@$units){
+ if ($un->{'type'} eq $params{'layout'}->{'units'}) {
+ $unitvalue = $un->{'value'};
+ $unitdesc = $un->{'desc'};
+ }
+ }
+
my $self = {
batch_id => $params{'batch_id'},
#card_number => $params{'card_number'},
height => $params{'height'},
width => $params{'width'},
layout => $params{'layout'},
+ unitvalue => $unitvalue,
+ unitdesc => $unitdesc,
text_wrap_cols => $params{'text_wrap_cols'},
+ barcode_height_scale => $params{'layout'}->{'barcode'}[0]->{'height_scale'} || 0.01,
+ barcode_width_scale => $params{'layout'}->{'barcode'}[0]->{'width_scale'} || 0.8,
};
bless ($self, $type);
return $self;
}
+=head2 draw_barcode
+
+=cut
+
sub draw_barcode {
my ($self, $pdf) = @_;
-#FIXME: We do some scaling foo on the barcode here which probably should be done by the one invoking draw_barcode
- my $barcode_width = 0.8 * $self->{'width'}; # this scales the barcode width to 80% of the label width
- my $barcode_y_scale_factor = 0.01 * $self->{'height'}; # this scales the barcode height to 1% of the label height
+ # Default values for barcode scaling are set in constructor to work with pre-existing installations
+ my $barcode_height_scale = $self->{'barcode_height_scale'};
+ my $barcode_width_scale = $self->{'barcode_width_scale'};
+
_draw_barcode( $self,
llx => $self->{'llx'} + $self->{'layout'}->{'barcode'}->[0]->{'llx'},
lly => $self->{'lly'} + $self->{'layout'}->{'barcode'}->[0]->{'lly'},
- width => $barcode_width,
- y_scale_factor => $barcode_y_scale_factor,
+ width => $self->{'width'} * $barcode_width_scale,
+ y_scale_factor => $self->{'height'} * $barcode_height_scale,
barcode_type => $self->{'layout'}->{'barcode'}->[0]->{'type'},
barcode_data => $self->{'layout'}->{'barcode'}->[0]->{'data'},
text => $self->{'layout'}->{'barcode'}->[0]->{'text_print'},
);
}
+=head2 draw_guide_box
+
+=cut
+
sub draw_guide_box {
my ($self, $pdf) = @_;
warn sprintf('No pdf object passed in.') and return -1 if !$pdf;
+
my $obj_stream = "q\n"; # save the graphic state
$obj_stream .= "0.5 w\n"; # border line width
$obj_stream .= "1.0 0.0 0.0 RG\n"; # border color red
$pdf->Add($obj_stream);
}
+=head2 draw_guide_grid
+
+ $patron_card->draw_guide_grid($pdf)
+
+Adds a grid to the PDF output ($pdf) to support layout design
+
+=cut
+
+sub draw_guide_grid {
+ my ($self, $pdf) = @_;
+ warn sprintf('No pdf object passed in.') and return -1 if !$pdf;
+
+ # Set up the grid in user defined units.
+ # Each 5th and 10th line get separate values
+
+ my $obj_stream = "q\n"; # save the graphic state
+ my $x = $self->{'llx'};
+ my $y = $self->{'lly'};
+
+ my $cnt = 0;
+ for ( $x = $self->{'llx'}/$self->{'unitvalue'}; $x <= ($self->{'llx'} + $self->{'width'})/$self->{'unitvalue'}; $x++) {
+ my $xx = $x*$self->{'unitvalue'};
+ my $yy = $y + $self->{'height'};
+ if ( ($cnt % 10) && ! ($cnt % 5) ) {
+ $obj_stream .= "0.0 1.0 0.0 RG\n";
+ $obj_stream .= "0 w\n";
+ } elsif ( $cnt % 5 ) {
+ $obj_stream .= "0.0 1.0 1.0 RG\n";
+ $obj_stream .= "0 w\n";
+ } else {
+ $obj_stream .= "0.0 0.0 1.0 RG\n";
+ $obj_stream .= "0 w\n";
+ }
+ $cnt ++;
+
+ $obj_stream .= "$xx $y m\n";
+ $obj_stream .= "$xx $yy l\n";
+
+ $obj_stream .= "s\n";
+ }
+
+ $x = $self->{'llx'};
+ $y = $self->{'lly'};
+ $cnt = 0;
+ for ( $y = $self->{'lly'}/$self->{'unitvalue'}; $y <= ($self->{'lly'} + $self->{'height'})/$self->{'unitvalue'}; $y++) {
+
+ my $xx = $x + $self->{'width'};
+ my $yy = $y*$self->{'unitvalue'};
+
+ if ( ($cnt % 10) && ! ($cnt % 5) ) {
+ $obj_stream .= "0.0 1.0 0.0 RG\n";
+ $obj_stream .= "0 w\n";
+ } elsif ( $cnt % 5 ) {
+ $obj_stream .= "0.0 1.0 1.0 RG\n";
+ $obj_stream .= "0 w\n";
+ } else {
+ $obj_stream .= "0.0 0.0 1.0 RG\n";
+ $obj_stream .= "0 w\n";
+ }
+ $cnt ++;
+
+ $obj_stream .= "$x $yy m\n";
+ $obj_stream .= "$xx $yy l\n";
+ $obj_stream .= "s\n";
+ }
+
+ $obj_stream .= "Q\n"; # restore the graphic state
+ $pdf->Add($obj_stream);
+
+ # Add info about units
+ my $strbottom = "0/0 $self->{'unitdesc'}";
+ my $strtop = sprintf('%.2f', $self->{'width'}/$self->{'unitvalue'}) .'/'. sprintf('%.2f', $self->{'height'}/$self->{'unitvalue'});
+ my $font_size = 6;
+ $pdf->Font( 'Courier' );
+ $pdf->FontSize( $font_size );
+ my $strtop_len = $pdf->StrWidth($strtop) * 1.5;
+ $pdf->Text( $self->{'llx'} + 2, $self->{'lly'} + 2, $strbottom );
+ $pdf->Text( $self->{'llx'} + $self->{'width'} - $strtop_len , $self->{'lly'} + $self->{'height'} - $font_size , $strtop );
+}
+
+=head2 draw_text
+
+ $patron_card->draw_text($pdf)
+
+Draws text to PDF output ($pdf)
+
+=cut
+
sub draw_text {
my ($self, $pdf, %params) = @_;
warn sprintf('No pdf object passed in.') and return -1 if !$pdf;
my @card_text = ();
return unless (ref($self->{'layout'}->{'text'}) eq 'ARRAY'); # just in case there is not text
+
my $text = [@{$self->{'layout'}->{'text'}}]; # make a copy of the arrayref *not* simply a pointer
while (scalar @$text) {
my $line = shift @$text;
my $parse_line = $line;
my @orig_line = split(/ /,$line);
- if ($parse_line =~ m/<[A-Za-z0-9]+>/) { # test to see if the line has db fields embedded...
+ if ($parse_line =~ m/<[A-Za-z0-9_]+>/) { # test to see if the line has db fields embedded...
my @fields = ();
- while ($parse_line =~ m/<([A-Za-z0-9]+)>(.*$)/) {
+ while ($parse_line =~ m/<([A-Za-z0-9_]+)>(.*$)/) {
push (@fields, $1);
$parse_line = $2;
}
my $borrower_attributes = get_borrower_attributes($self->{'borrower_number'},@fields);
- grep{ # substitute data for db fields
- if ($_ =~ m/<([A-Za-z0-9]+)>/) {
+ @orig_line = map { # substitute data for db fields
+ my $l = $_;
+ if ($l =~ m/<([A-Za-z0-9_]+)>/) {
my $field = $1;
- $_ =~ s/$_/$borrower_attributes->{$field}/;
+ $l =~ s/$l/$borrower_attributes->{$field}/;
}
+ $l;
} @orig_line;
$line = join(' ',@orig_line);
}
my $text_attribs = shift @$text;
- my $origin_llx = $self->{'llx'} + $text_attribs->{'llx'};
- my $origin_lly = $self->{'lly'} + $text_attribs->{'lly'};
+ my $origin_llx = $self->{'llx'} + $text_attribs->{'llx'} * $self->{'unitvalue'};
+ my $origin_lly = $self->{'lly'} + $text_attribs->{'lly'} * $self->{'unitvalue'};
my $Tx = 0; # final text llx
my $Ty = $origin_lly; # final text lly
my $Tw = 0; # final text word spacing. See http://www.adobe.com/devnet/pdf/pdf_reference.html ISO 32000-1
while (1) {
# $line =~ m/^.*(\s\b.*\b\s*|\s&|\<\b.*\b\>)$/; # original regexp... can be removed after dev stage is over
$line =~ m/^.*(\s.*\s*|\s&|\<.*\>)$/;
- warn sprintf('Line wrap failed. DEBUG INFO: Data: \'%s\'\n Method: C4::Patroncards->draw_text Additional Information: Line wrap regexp failed. (Please file in this information in a bug report at http://bugs.koha.org', $line) and last WRAP_LINES if !$1;
$trim = $1 . $trim;
- $line =~ s/$1//;
+ #Sanitize the input into this regular expression so regex metacharacters are escaped as literal values (https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=22429)
+ $line =~ s/\Q$1\E$//;
$string_width = C4::Creators::PDF->StrWidth($line, $text_attribs->{'font'}, $text_attribs->{'font_size'});
# $font_units_width = $m->string_width($line);
# $string_width = ($font_units_width * $text_attribs->{'font_size'}) / $units_per_em;
$string_width = C4::Creators::PDF->StrWidth($line, $text_attribs->{'font'}, $text_attribs->{'font_size'});
#$font_units_width = $m->string_width($line);
#$string_width = ($font_units_width * $text_attribs->{'font_size'}) / $units_per_em;
- if (($string_width + $text_attribs->{'llx'}) < $self->{'width'}) {
- ($Tx, $Tw) = text_alignment($origin_llx, $self->{'width'}, $text_attribs->{'llx'}, $string_width, $line, $text_attribs->{'text_alignment'});
+ if ( $string_width + ( $text_attribs->{'llx'} * $self->{'unitvalue'} ) < $self->{'width'}) {
+ ($Tx, $Tw) = text_alignment($origin_llx, $self->{'width'}, $text_attribs->{'llx'} * $self->{'unitvalue'}, $string_width, $line, $text_attribs->{'text_alignment'});
$line =~ s/^\s+//g; # strip naughty leading spaces
push @lines, {line=> $line, Tx => $Tx, Ty => $Ty, Tw => $Tw};
last WRAP_LINES;
}
}
else {
- ($Tx, $Tw) = text_alignment($origin_llx, $self->{'width'}, $text_attribs->{'llx'}, $string_width, $line, $text_attribs->{'text_alignment'});
+ ($Tx, $Tw) = text_alignment($origin_llx, $self->{'width'}, $text_attribs->{'llx'} * $self->{'unitvalue'}, $string_width, $line, $text_attribs->{'text_alignment'});
$line =~ s/^\s+//g; # strip naughty leading spaces
push @lines, {line=> $line, Tx => $Tx, Ty => $Ty, Tw => $Tw};
}
else {
$box_height += $text_attribs->{'font_size'};
}
- box ($origin_llx, $box_lly, $self->{'width'} - $text_attribs->{'llx'}, $box_height, $pdf);
+ box ($origin_llx, $box_lly, $self->{'width'} - ( $text_attribs->{'llx'} * $self->{'unitvalue'} ), $box_height, $pdf);
}
-# my $font_resource = $pdf->TTFont("/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold.ttf");
-# $pdf->FontSize($text_attribs->{'font_size'});
- my $font_resource = $pdf->Font($text_attribs->{'font'});
+ $pdf->Font($text_attribs->{'font'});
+ $pdf->FontSize($text_attribs->{'font_size'});
foreach my $line (@lines) {
-# $pdf->Text($line->{'Tx'}, $line->{'Ty'}, $line->{'line'});
- my $text_line = "BT /$font_resource $text_attribs->{'font_size'} Tf $line->{'Tx'} $line->{'Ty'} Td $line->{'Tw'} Tw ($line->{'line'}) Tj ET";
- $pdf->Add($text_line);
+ $pdf->Text($line->{'Tx'}, $line->{'Ty'}, $line->{'line'});
}
}
}
+=head2 draw_image
+
+ $patron_card->draw_image($pdf)
+
+Draws images to PDF output ($pdf)
+
+=cut
+
sub draw_image {
my ($self, $pdf) = @_;
warn sprintf('No pdf object passed in.') and return -1 if !$pdf;
my $images = $self->{'layout'}->{'images'};
+
PROCESS_IMAGES:
foreach my $image (keys %$images) {
next PROCESS_IMAGES if $images->{$image}->{'data_source'}->[0]->{'image_source'} eq 'none';
- my $Tx = $self->{'llx'} + $images->{$image}->{'Tx'};
- my $Ty = $self->{'lly'} + $images->{$image}->{'Ty'};
+ my $Tx = $self->{'llx'} + $images->{$image}->{'Tx'} * $self->{'unitvalue'};
+ my $Ty = $self->{'lly'} + $images->{$image}->{'Ty'} * $self->{'unitvalue'};
warn sprintf('No image passed in.') and next if !$images->{$image}->{'data'};
my $intName = $pdf->AltJpeg($images->{$image}->{'data'},$images->{$image}->{'Sx'}, $images->{$image}->{'Sy'}, 1, $images->{$image}->{'alt'}->{'data'},$images->{$image}->{'alt'}->{'Sx'}, $images->{$image}->{'alt'}->{'Sy'}, 1);
my $obj_stream = "q\n";
$obj_stream .= "$images->{$image}->{'Sx'} $images->{$image}->{'Ox'} $images->{$image}->{'Oy'} $images->{$image}->{'Sy'} $Tx $Ty cm\n"; # see http://www.adobe.com/devnet/pdf/pdf_reference.html sec 8.3.3 of ISO 32000-1
+ $obj_stream .= "$images->{$image}->{'scale'} 0 0 $images->{$image}->{'scale'} 0 0 cm\n"; #scale to 20%
$obj_stream .= "/$intName Do\n";
$obj_stream .= "Q\n";
$pdf->Add($obj_stream);
}
}
+=head2 draw_barcode
+
+ $patron_card->draw_barcode($pdf)
+
+Draws a barcode to PDF output ($pdf)
+
+=cut
+
sub _draw_barcode { # this is cut-and-paste from Label.pm because there is no common place for it atm...
my $self = shift;
my %params = @_;
+
my $x_scale_factor = 1;
my $num_of_chars = length($params{'barcode_data'});
my $tot_bar_length = 0;
}
eval {
PDF::Reuse::Barcode::Code39(
- x => $params{'llx'},
- y => $params{'lly'},
+ x => $params{'llx'} * $self->{'unitvalue'},
+ y => $params{'lly'} * $self->{'unitvalue'},
value => "*$params{barcode_data}*",
xSize => $x_scale_factor,
ySize => $params{'y_scale_factor'},
$x_scale_factor = ($params{'width'} / $tot_bar_length) * 0.9;
eval {
PDF::Reuse::Barcode::COOP2of5(
- x => $params{'llx'},
- y => $params{'lly'},
- value => "*$params{barcode_data}*",
+ x => $params{'llx'}* $self->{'unitvalue'},
+ y => $params{'lly'}* $self->{'unitvalue'},
+ value => $params{barcode_data},
xSize => $x_scale_factor,
ySize => $params{'y_scale_factor'},
mode => 'graphic',
$x_scale_factor = ($params{'width'} / $tot_bar_length) * 0.9;
eval {
PDF::Reuse::Barcode::Industrial2of5(
- x => $params{'llx'},
- y => $params{'lly'},
- value => "*$params{barcode_data}*",
+ x => $params{'llx'}* $self->{'unitvalue'} ,
+ y => $params{'lly'}* $self->{'unitvalue'},
+ value => $params{barcode_data},
xSize => $x_scale_factor,
ySize => $params{'y_scale_factor'},
mode => 'graphic',
Chris Nighswonger <cnighswonger AT foundations DOT edu>
=cut
-
-
-