3 # Copyright 2006 Katipo Communications.
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA 02111-1307 USA
21 use vars qw($VERSION @ISA @EXPORT);
25 use Algorithm::CheckDigits;
27 # use Smart::Comments;
34 &get_label_options &get_label_items
35 &build_circ_barcode &draw_boundaries
36 &drawbox &GetActiveLabelTemplate
37 &GetAllLabelTemplates &DeleteTemplate
38 &GetSingleLabelTemplate &SaveTemplate
39 &CreateTemplate &SetActiveTemplate
40 &SaveConf &DrawSpineText &GetTextWrapCols
41 &GetUnitsValue &DrawBarcode
45 &get_batches &delete_batch
49 get_layout &save_layout &add_layout
50 &set_active_layout &by_order
52 &delete_layout &get_active_layout
55 &GetAllPrinterProfiles &GetSinglePrinterProfile
56 &SaveProfile &CreateProfile &DeleteProfile
57 &GetAssociatedProfile &SetAssociatedProfile
65 C4::Labels - Functions for printing spine labels and barcodes in Koha
71 =item get_label_options;
73 $options = get_label_options()
75 Return a pointer on a hash list containing info from labels_conf table in Koha DB.
80 sub get_label_options {
81 my $dbh = C4::Context->dbh;
82 my $query2 = " SELECT * FROM labels_conf where active = 1";
83 my $sth = $dbh->prepare($query2);
85 my $conf_data = $sth->fetchrow_hashref;
92 ## FIXME: this if/else could be compacted...
93 my $dbh = C4::Context->dbh;
95 my $query = " Select * from labels_conf";
96 my $sth = $dbh->prepare($query);
99 while ( my $data = $sth->fetchrow_hashref ) {
101 $data->{'fieldlist'} = get_text_fields( $data->{'id'} );
102 push( @resultsloop, $data );
112 my ($layout_id) = @_;
113 my $dbh = C4::Context->dbh;
115 # get the actual items to be printed.
116 my $query = " Select * from labels_conf where id = ?";
117 my $sth = $dbh->prepare($query);
118 $sth->execute($layout_id);
119 my $data = $sth->fetchrow_hashref;
124 sub get_active_layout {
125 my ($layout_id) = @_;
126 my $dbh = C4::Context->dbh;
128 # get the actual items to be printed.
129 my $query = " Select * from labels_conf where active = 1";
130 my $sth = $dbh->prepare($query);
132 my $data = $sth->fetchrow_hashref;
138 my ($layout_id) = @_;
139 my $dbh = C4::Context->dbh;
141 # get the actual items to be printed.
142 my $query = "delete from labels_conf where id = ?";
143 my $sth = $dbh->prepare($query);
144 $sth->execute($layout_id);
148 sub get_printingtypes {
149 my ($layout_id) = @_;
152 push( @printtypes, { code => 'BAR', desc => "barcode" } );
153 push( @printtypes, { code => 'BIB', desc => "biblio" } );
154 push( @printtypes, { code => 'BARBIB', desc => "barcode / biblio" } );
155 push( @printtypes, { code => 'BIBBAR', desc => "biblio / barcode" } );
156 push( @printtypes, { code => 'ALT', desc => "alternating labels" } );
158 my $conf = get_layout($layout_id);
159 my $active_printtype = $conf->{'printingtype'};
161 # lop thru layout, insert selected to hash
163 foreach my $printtype (@printtypes) {
164 if ( $printtype->{'code'} eq $active_printtype ) {
165 $printtype->{'active'} = 'MOO';
171 sub build_text_dropbox {
174 # my @fields = get_text_fields();
175 # my $field_count = scalar @fields;
176 my $field_count = 10; # <----------- FIXME hard coded
180 ? push( @lines, { num => '', selected => '1' } )
181 : push( @lines, { num => '' } );
182 for ( my $i = 1 ; $i <= $field_count ; $i++ ) {
183 my $line = { num => "$i" };
184 $line->{'selected'} = 1 if $i eq $order;
185 push( @lines, $line );
188 # add a blank row too
193 sub get_text_fields {
194 my ($layout_id, $sorttype) = @_;
196 my ( $a, $b, $c, $d, $e, $f, $g, $h, $i ,$j, $k );
198 my $sortorder = get_layout($layout_id);
205 order => $sortorder->{'itemtype'}
210 order => $sortorder->{'dewey'}
212 $c = { code => 'issn', desc => "ISSN",
213 order => $sortorder->{'issn'} };
214 $d = { code => 'isbn', desc => "ISBN",
215 order => $sortorder->{'isbn'} };
218 desc => "Classification",
219 order => $sortorder->{'class'}
224 order => $sortorder->{'subclass'}
229 order => $sortorder->{'barcode'}
232 { code => 'author', desc => "Author", order => $sortorder->{'author'} };
233 $i = { code => 'title', desc => "Title", order => $sortorder->{'title'} };
234 $j = { code => 'itemcallnumber', desc => "Call Number", order => $sortorder->{'itemcallnumber'} };
235 $k = { code => 'subtitle', desc => "Subtitle", order => $sortorder->{'subtitle'} };
237 my @text_fields = ( $a, $b, $c, $d, $e, $f, $g, $h, $i ,$j, $k );
240 foreach my $field (@text_fields) {
241 push( @new_fields, $field ) if $field->{'order'} > 0;
244 my @sorted_fields = sort by_order @new_fields;
246 foreach my $field (@sorted_fields) {
247 $sorttype eq 'codes' ? $active_fields .= "$field->{'code'} " :
248 $active_fields .= "$field->{'desc'} ";
250 return $active_fields;
255 $$a{order} <=> $$b{order};
260 my $dbh = C4::Context->dbh;
262 "select distinct batch_id from labels order by batch_id desc limit 1";
263 my $sth = $dbh->prepare($q);
265 my $data = $sth->fetchrow_hashref;
268 if ( !$data->{'batch_id'} ) {
272 $new_batch = ( $data->{'batch_id'} + 1 );
279 sub get_highest_batch {
281 my $dbh = C4::Context->dbh;
283 "select distinct batch_id from labels order by batch_id desc limit 1";
284 my $sth = $dbh->prepare($q);
286 my $data = $sth->fetchrow_hashref;
289 if ( !$data->{'batch_id'} ) {
293 $new_batch = $data->{'batch_id'};
301 my $dbh = C4::Context->dbh;
302 my $q = "select batch_id, count(*) as num from labels group by batch_id";
303 my $sth = $dbh->prepare($q);
306 while ( my $data = $sth->fetchrow_hashref ) {
307 push( @resultsloop, $data );
311 # Not sure why we are doing this rather than simply telling the user that no batches are currently defined.
312 # So I'm commenting this out and modifying label-manager.tmpl to properly inform the user as stated. -fbcit
313 # adding a dummy batch=1 value , if none exists in the db
314 # if ( !scalar(@resultsloop) ) {
315 # push( @resultsloop, { batch_id => '1' , num => '0' } );
322 my $dbh = C4::Context->dbh;
323 my $q = "DELETE FROM labels where batch_id = ?";
324 my $sth = $dbh->prepare($q);
325 $sth->execute($batch_id);
329 sub get_barcode_types {
330 my ($layout_id) = @_;
331 my $layout = get_layout($layout_id);
332 my $barcode = $layout->{'barcodetype'};
335 push( @array, { code => 'CODE39', desc => 'Code 39' } );
336 push( @array, { code => 'CODE39MOD', desc => 'Code39 + Modulo43' } );
337 push( @array, { code => 'CODE39MOD10', desc => 'Code39 + Modulo10' } );
338 push( @array, { code => 'ITF', desc => 'Interleaved 2 of 5' } );
340 foreach my $line (@array) {
341 if ( $line->{'code'} eq $barcode ) {
342 $line->{'active'} = 1;
353 $unitvalue = '1' if ( $units eq 'POINT' );
354 $unitvalue = '2.83464567' if ( $units eq 'MM' );
355 $unitvalue = '28.3464567' if ( $units eq 'CM' );
356 $unitvalue = 72 if ( $units eq 'INCH' );
360 sub GetTextWrapCols {
361 my ( $font, $fontsize, $label_width, $left_text_margin ) = @_;
365 # my $textlimit = $label_width - ($left_text_margin);
366 my $textlimit = $label_width - ( 2* $left_text_margin);
368 while ( $strwidth < $textlimit ) {
369 $strwidth = prStrWidth( $string, $font, $fontsize );
370 $string = $string . '0';
371 #warn "strwidth:$strwidth, textlimit:$textlimit, count:$count string:$string";
377 sub GetActiveLabelTemplate {
378 my $dbh = C4::Context->dbh;
379 my $query = " SELECT * FROM labels_templates where active = 1 limit 1";
380 my $sth = $dbh->prepare($query);
382 my $active_tmpl = $sth->fetchrow_hashref;
387 sub GetSingleLabelTemplate {
389 my $dbh = C4::Context->dbh;
390 my $query = " SELECT * FROM labels_templates where tmpl_id = ?";
391 my $sth = $dbh->prepare($query);
392 $sth->execute($tmpl_id);
393 my $template = $sth->fetchrow_hashref;
398 sub SetActiveTemplate {
402 my $dbh = C4::Context->dbh;
403 my $query = " UPDATE labels_templates SET active = NULL";
404 my $sth = $dbh->prepare($query);
407 $query = "UPDATE labels_templates SET active = 1 WHERE tmpl_id = ?";
408 $sth = $dbh->prepare($query);
409 $sth->execute($tmpl_id);
413 sub set_active_layout {
415 my ($layout_id) = @_;
416 my $dbh = C4::Context->dbh;
417 my $query = " UPDATE labels_conf SET active = NULL";
418 my $sth = $dbh->prepare($query);
421 $query = "UPDATE labels_conf SET active = 1 WHERE id = ?";
422 $sth = $dbh->prepare($query);
423 $sth->execute($layout_id);
429 my $dbh = C4::Context->dbh;
430 my $query = " DELETE FROM labels_templates where tmpl_id = ?";
431 my $sth = $dbh->prepare($query);
432 $sth->execute($tmpl_id);
438 $tmpl_id, $tmpl_code, $tmpl_desc, $page_width,
439 $page_height, $label_width, $label_height, $topmargin,
440 $leftmargin, $cols, $rows, $colgap,
441 $rowgap, $font, $fontsize, $units
443 warn "Passed \$font:$font";
444 my $dbh = C4::Context->dbh;
446 " UPDATE labels_templates SET tmpl_code=?, tmpl_desc=?, page_width=?,
447 page_height=?, label_width=?, label_height=?, topmargin=?,
448 leftmargin=?, cols=?, rows=?, colgap=?, rowgap=?, font=?, fontsize=?,
452 my $sth = $dbh->prepare($query);
454 $tmpl_code, $tmpl_desc, $page_width, $page_height,
455 $label_width, $label_height, $topmargin, $leftmargin,
456 $cols, $rows, $colgap, $rowgap,
457 $font, $fontsize, $units, $tmpl_id
459 my $dberror = $sth->errstr;
467 $tmpl_code, $tmpl_desc, $page_width, $page_height,
468 $label_width, $label_height, $topmargin, $leftmargin,
469 $cols, $rows, $colgap, $rowgap,
470 $font, $fontsize, $units
473 my $dbh = C4::Context->dbh;
475 my $query = "INSERT INTO labels_templates (tmpl_code, tmpl_desc, page_width,
476 page_height, label_width, label_height, topmargin,
477 leftmargin, cols, rows, colgap, rowgap, font, fontsize, units)
478 VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
480 my $sth = $dbh->prepare($query);
482 $tmpl_code, $tmpl_desc, $page_width, $page_height,
483 $label_width, $label_height, $topmargin, $leftmargin,
484 $cols, $rows, $colgap, $rowgap,
485 $font, $fontsize, $units
487 my $dberror = $sth->errstr;
492 sub GetAllLabelTemplates {
493 my $dbh = C4::Context->dbh;
495 # get the actual items to be printed.
497 my $query = " Select * from labels_templates ";
498 my $sth = $dbh->prepare($query);
501 while ( my $data = $sth->fetchrow_hashref ) {
502 push( @resultsloop, $data );
506 #warn Dumper @resultsloop;
514 $barcodetype, $title, $subtitle, $isbn, $issn,
515 $itemtype, $bcn, $dcn, $classif,
516 $subclass, $itemcallnumber, $author, $tmpl_id,
517 $printingtype, $guidebox, $startlabel, $layoutname
520 my $dbh = C4::Context->dbh;
521 my $query2 = "update labels_conf set active = NULL";
522 my $sth2 = $dbh->prepare($query2);
524 $query2 = "INSERT INTO labels_conf
525 ( barcodetype, title, subtitle, isbn,issn, itemtype, barcode,
526 dewey, class, subclass, itemcallnumber, author, printingtype,
527 guidebox, startlabel, layoutname, active )
528 values ( ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?,?,?, 1 )";
529 $sth2 = $dbh->prepare($query2);
531 $barcodetype, $title, $subtitle, $isbn, $issn,
533 $itemtype, $bcn, $dcn, $classif,
534 $subclass, $itemcallnumber, $author, $printingtype,
535 $guidebox, $startlabel, $layoutname
539 SetActiveTemplate($tmpl_id);
546 $barcodetype, $title, $subtitle, $isbn, $issn,
547 $itemtype, $bcn, $dcn, $classif,
548 $subclass, $itemcallnumber, $author, $tmpl_id,
549 $printingtype, $guidebox, $startlabel, $layoutname,
555 my $dbh = C4::Context->dbh;
556 my $query2 = "update labels_conf set
557 barcodetype=?, title=?, subtitle=?, isbn=?,issn=?,
558 itemtype=?, barcode=?, dewey=?, class=?,
559 subclass=?, itemcallnumber=?, author=?, printingtype=?,
560 guidebox=?, startlabel=?, layoutname=? where id = ?";
561 my $sth2 = $dbh->prepare($query2);
563 $barcodetype, $title, $subtitle, $isbn, $issn,
564 $itemtype, $bcn, $dcn, $classif,
565 $subclass, $itemcallnumber, $author, $printingtype,
566 $guidebox, $startlabel, $layoutname, $layout_id
573 =item GetAllPrinterProfiles;
575 @profiles = GetAllPrinterProfiles()
577 Returns an array of references-to-hash, whos keys are .....
581 sub GetAllPrinterProfiles {
583 my $dbh = C4::Context->dbh;
585 my $query = "SELECT * FROM printers_profile AS pp INNER JOIN labels_templates AS lt ON pp.tmpl_id = lt.tmpl_id; ";
586 my $sth = $dbh->prepare($query);
589 while ( my $data = $sth->fetchrow_hashref ) {
590 push( @resultsloop, $data );
597 =item GetSinglePrinterProfile;
599 $profile = GetSinglePrinterProfile()
601 Returns a hashref whos keys are...
605 sub GetSinglePrinterProfile {
607 my $dbh = C4::Context->dbh;
608 my $query = " SELECT * FROM printers_profile WHERE prof_id = ?; ";
609 my $sth = $dbh->prepare($query);
610 $sth->execute($prof_id);
611 my $template = $sth->fetchrow_hashref;
618 SaveProfile('parameters')
620 When passed a set of parameters, this function updates the given profile with the new parameters.
626 $prof_id, $offset_horz, $offset_vert, $creep_horz, $creep_vert, $units
628 my $dbh = C4::Context->dbh;
630 " UPDATE printers_profile
631 SET offset_horz=?, offset_vert=?, creep_horz=?, creep_vert=?, unit=?
633 my $sth = $dbh->prepare($query);
635 $offset_horz, $offset_vert, $creep_horz, $creep_vert, $units, $prof_id
642 CreateProfile('parameters')
644 When passed a set of parameters, this function creates a new profile containing those parameters
645 and returns any errors.
651 $prof_id, $printername, $paper_bin, $tmpl_id, $offset_horz,
652 $offset_vert, $creep_horz, $creep_vert, $units
654 my $dbh = C4::Context->dbh;
656 " INSERT INTO printers_profile (prof_id, printername, paper_bin, tmpl_id,
657 offset_horz, offset_vert, creep_horz, creep_vert, unit)
658 VALUES(?,?,?,?,?,?,?,?,?) ";
659 my $sth = $dbh->prepare($query);
661 $prof_id, $printername, $paper_bin, $tmpl_id, $offset_horz,
662 $offset_vert, $creep_horz, $creep_vert, $units
664 my $error = $sth->errstr;
671 DeleteProfile(prof_id)
673 When passed a profile id, this function deletes that profile from the database and returns any errors.
679 my $dbh = C4::Context->dbh;
680 my $query = " DELETE FROM printers_profile WHERE prof_id = ?";
681 my $sth = $dbh->prepare($query);
682 $sth->execute($prof_id);
683 my $error = $sth->errstr;
688 =item GetAssociatedProfile;
690 $assoc_prof = GetAssociatedProfile(tmpl_id)
692 When passed a template id, this function returns the parameters from the currently associated printer profile
693 in a hashref where key=fieldname and value=fieldvalue.
697 sub GetAssociatedProfile {
699 my $dbh = C4::Context->dbh;
700 # First we find out the prof_id for the associated profile...
701 my $query = "SELECT * FROM labels_profile WHERE tmpl_id = ?";
702 my $sth = $dbh->prepare($query);
703 $sth->execute($tmpl_id);
704 my $assoc_prof = $sth->fetchrow_hashref;
706 # Then we retrieve that profile and return it to the caller...
707 $assoc_prof = GetSinglePrinterProfile($assoc_prof->{'prof_id'});
711 =item SetAssociatedProfile;
713 SetAssociatedProfile($prof_id, $tmpl_id)
715 When passed both a profile id and template id, this function establishes an association between the two. No more
716 than one profile may be associated with any given template at the same time.
720 sub SetAssociatedProfile {
722 my ($prof_id, $tmpl_id) = @_;
724 my $dbh = C4::Context->dbh;
725 my $query = "INSERT INTO labels_profile (prof_id, tmpl_id) VALUES (?,?) ON DUPLICATE KEY UPDATE prof_id = ?";
726 my $sth = $dbh->prepare($query);
727 $sth->execute($prof_id, $tmpl_id, $prof_id);
731 =item get_label_items;
733 $options = get_label_items()
735 Returns an array of references-to-hash, whos keys are the field from the biblio, biblioitems, items and labels tables in the Koha database.
740 sub get_label_items {
742 my $dbh = C4::Context->dbh;
744 my @resultsloop = ();
750 my $query3 = "Select * from labels where batch_id = ? order by labelid ";
751 $sth = $dbh->prepare($query3);
752 $sth->execute($batch_id);
757 my $query3 = "Select * from labels";
758 $sth = $dbh->prepare($query3);
761 my $cnt = $sth->rows;
763 while ( my $data = $sth->fetchrow_hashref ) {
765 # lets get some summary info from each item
767 select i.*, bi.*, b.* from items i,biblioitems bi,biblio b
768 where itemnumber=? and i.biblioitemnumber=bi.biblioitemnumber and
769 bi.biblionumber=b.biblionumber";
771 my $sth1 = $dbh->prepare($query1);
772 $sth1->execute( $data->{'itemnumber'} );
774 my $data1 = $sth1->fetchrow_hashref();
775 $data1->{'labelno'} = $i1;
776 $data1->{'labelid'} = $data->{'labelid'};
777 $data1->{'batch_id'} = $batch_id;
778 $data1->{'summary'} =
779 "$data1->{'barcode'}, $data1->{'title'}, $data1->{'isbn'}";
781 push( @resultsloop, $data1 );
793 barcode title subtitle
794 dewey isbn issn author class
795 itemtype subclass itemcallnumber
801 sub deduplicate_batch {
802 my $batch_id = shift or return undef;
806 count(labelid) as count
809 GROUP BY itemnumber,batch_id
813 my $sth = C4::Context->dbh->prepare($query);
814 $sth->execute($batch_id);
815 $sth->rows or return undef;
822 ORDER BY timestamp ASC
825 while (my $data = $sth->fetchrow_hashref()) {
826 my $itemnumber = $data->{itemnumber} or next;
827 my $limit = $data->{count} - 1 or next;
828 my $sth2 = C4::Context->dbh->prepare("$del_query LIMIT $limit");
829 # die sprintf "$del_query LIMIT %s\n (%s, %s)", $limit, $batch_id, $itemnumber;
830 # $sth2->execute($batch_id, C4::Context->dbh->quote($data->{itemnumber}), $data->{count} - 1)
831 $sth2->execute($batch_id, $itemnumber) and
832 $killed += ($data->{count} - 1);
839 my ( $x_pos, $y_pos, $label_height, $label_width, $fontname, $fontsize, $left_text_margin,
840 $text_wrap_cols, $item, $conf_data, $printingtype )
842 # hack to fix column name mismatch betwen labels_conf.class, and bibitems.classification
843 $$item->{'class'} = $$item->{'classification'};
845 $Text::Wrap::columns = $text_wrap_cols;
846 $Text::Wrap::separator = "\n";
850 my $top_text_margin = ( $fontsize + 3 ); #FIXME: This should be a template parameter and passed in...
851 my $line_spacer = ( $fontsize * 0.20 ); # number of pixels between text rows (This is actually leading: baseline to baseline minus font size. Recommended starting point is 20% of font size.).
853 # add your printable fields manually in here
855 my $layout_id = $$conf_data->{'id'};
857 # my @fields = GetItemFields();
859 my $str_fields = get_text_fields($layout_id, 'codes' );
860 my @fields = split(/ /, $str_fields);
861 #warn Dumper(@fields);
863 my $vPos = ( $y_pos + ( $label_height - $top_text_margin ) );
864 my $font = prFont($fontname);
866 # warn Dumper $conf_data;
869 foreach my $field (@fields) {
872 # $$item->{"$field"} = $field . ": " . $$item->{"$field"};
874 # if the display option for this field is selected in the DB,
875 # and the item record has some values for this field, display it.
876 if ( $$conf_data->{"$field"} && $$item->{"$field"} ) {
878 # warn "CONF_TYPE = $field";
881 $str = $$item->{"$field"};
882 # strip out naughty existing nl/cr's
885 # strip out division slashes
887 # chop the string up into _upto_ 12 chunks
888 # and seperate the chunks with newlines
890 $str = wrap( "", "", "$str" );
891 $str = wrap( "", "", "$str" );
893 # split the chunks between newline's, into an array
894 my @strings = split /\n/, $str;
896 # then loop for each string line
897 foreach my $str (@strings) {
899 if ( $printingtype eq 'BIB' ) { #FIXME: This is a hack and needs to be implimented as a text justification option in the template...
900 # some code to try and center each line on the label based on font size and string point width...
901 my $stringwidth = prStrWidth($str, $fontname, $fontsize);
902 my $whitespace = ( $label_width - ( $stringwidth + (2 * $left_text_margin) ) );
903 $hPos = ( ( $whitespace / 2 ) + $x_pos + $left_text_margin );
904 #warn "\$label_width=$label_width \$stringwidth=$stringwidth \$whitespace=$whitespace \$left_text_margin=$left_text_margin for $str\n";
906 $hPos = ( $x_pos + $left_text_margin );
908 PrintText( $hPos, $vPos, $font, $fontsize, $str );
909 $vPos = $vPos - $line_spacer;
917 my ( $hPos, $vPos, $font, $fontsize, $text ) = @_;
918 my $str = "BT /$font $fontsize Tf $hPos $vPos Td ($text) Tj ET";
922 # Is this used anywhere?
926 # my ($fontsize) = @_;
928 # my $str = "BT/F13 30 Tf288 720 Td( AAAAAAAAAA ) TjET";
934 # x and y are from the top-left :)
935 my ( $x_pos, $y_pos, $height, $width, $barcode, $barcodetype ) = @_;
936 my $num_of_bars = length($barcode);
937 my $bar_width = $width * .8; # %80 of length of label width
940 my $guard_length = 10;
943 if ( $barcodetype eq 'CODE39' ) {
944 $bar_length = '17.5';
946 ( $bar_length * $num_of_bars ) + ( $guard_length * 2 );
947 $xsize_ratio = ( $bar_width / $tot_bar_length );
949 PDF::Reuse::Barcode::Code39(
950 x => ( $x_pos + ( $width / 10 ) ),
951 y => ( $y_pos + ( $height / 10 ) ),
952 value => "*$barcode*",
953 ySize => ( .02 * $height ),
954 xSize => $xsize_ratio,
959 warn "$barcodetype, $barcode FAILED:$@";
963 elsif ( $barcodetype eq 'CODE39MOD' ) {
965 # get modulo43 checksum
966 my $c39 = CheckDigits('code_39');
967 $barcode = $c39->complete($barcode);
971 ( $bar_length * $num_of_bars ) + ( $guard_length * 2 );
972 $xsize_ratio = ( $bar_width / $tot_bar_length );
974 PDF::Reuse::Barcode::Code39(
975 x => ( $x_pos + ( $width / 10 ) ),
976 y => ( $y_pos + ( $height / 10 ) ),
977 value => "*$barcode*",
978 ySize => ( .02 * $height ),
979 xSize => $xsize_ratio,
985 warn "$barcodetype, $barcode FAILED:$@";
988 elsif ( $barcodetype eq 'CODE39MOD10' ) {
990 # get modulo43 checksum
991 my $c39_10 = CheckDigits('visa');
992 $barcode = $c39_10->complete($barcode);
996 ( $bar_length * $num_of_bars ) + ( $guard_length * 2 );
997 $xsize_ratio = ( $bar_width / $tot_bar_length );
999 PDF::Reuse::Barcode::Code39(
1000 x => ( $x_pos + ( $width / 10 ) ),
1001 y => ( $y_pos + ( $height / 10 ) ),
1002 value => "*$barcode*",
1003 ySize => ( .02 * $height ),
1004 xSize => $xsize_ratio,
1011 warn "$barcodetype, $barcode FAILED:$@";
1016 elsif ( $barcodetype eq 'COOP2OF5' ) {
1017 $bar_length = '9.43333333333333';
1019 ( $bar_length * $num_of_bars ) + ( $guard_length * 2 );
1020 $xsize_ratio = ( $bar_width / $tot_bar_length ) * .9;
1022 PDF::Reuse::Barcode::COOP2of5(
1023 x => ( $x_pos + ( $width / 10 ) ),
1024 y => ( $y_pos + ( $height / 10 ) ),
1026 ySize => ( .02 * $height ),
1027 xSize => $xsize_ratio,
1031 warn "$barcodetype, $barcode FAILED:$@";
1035 elsif ( $barcodetype eq 'INDUSTRIAL2OF5' ) {
1036 $bar_length = '13.1333333333333';
1038 ( $bar_length * $num_of_bars ) + ( $guard_length * 2 );
1039 $xsize_ratio = ( $bar_width / $tot_bar_length ) * .9;
1041 PDF::Reuse::Barcode::Industrial2of5(
1042 x => ( $x_pos + ( $width / 10 ) ),
1043 y => ( $y_pos + ( $height / 10 ) ),
1045 ySize => ( .02 * $height ),
1046 xSize => $xsize_ratio,
1050 warn "$barcodetype, $barcode FAILED:$@";
1054 my $moo2 = $tot_bar_length * $xsize_ratio;
1056 warn "$x_pos, $y_pos, $barcode, $barcodetype" if $DEBUG;
1057 warn "BAR_WDTH = $bar_width, TOT.BAR.LGHT=$tot_bar_length R*TOT.BAR =$moo2" if $DEBUG;
1060 =item build_circ_barcode;
1062 build_circ_barcode( $x_pos, $y_pos, $barcode,
1063 $barcodetype, \$item);
1065 $item is the result of a previous call to get_label_items();
1070 sub build_circ_barcode {
1071 my ( $x_pos_circ, $y_pos, $value, $barcodetype, $item ) = @_;
1073 #warn Dumper \$item;
1075 #warn "value = $value\n";
1079 if ( $barcodetype eq 'EAN13' ) {
1081 #testing EAN13 barcodes hack
1082 $value = $value . '000000000';
1084 $value = substr( $value, 0, 12 );
1088 PDF::Reuse::Barcode::EAN13(
1089 x => ( $x_pos_circ + 27 ),
1090 y => ( $y_pos + 15 ),
1098 # added for xpdf compat. doesnt use type3 fonts., but increases filesize from 20k to 200k
1099 # i think its embedding extra fonts in the pdf file.
1100 # mode => 'graphic',
1104 $item->{'barcodeerror'} = 1;
1106 #warn "EAN13BARCODE FAILED:$@";
1112 elsif ( $barcodetype eq 'Code39' ) {
1115 PDF::Reuse::Barcode::Code39(
1116 x => ( $x_pos_circ + 9 ),
1117 y => ( $y_pos + 15 ),
1127 $item->{'barcodeerror'} = 1;
1129 #warn "CODE39BARCODE $value FAILED:$@";
1136 elsif ( $barcodetype eq 'Matrix2of5' ) {
1138 #warn "MATRIX ELSE:";
1140 #testing MATRIX25 barcodes hack
1141 # $value = $value.'000000000';
1144 # $value = substr( $value, 0, 12 );
1148 PDF::Reuse::Barcode::Matrix2of5(
1149 x => ( $x_pos_circ + 27 ),
1150 y => ( $y_pos + 15 ),
1160 $item->{'barcodeerror'} = 1;
1162 #warn "BARCODE FAILED:$@";
1169 elsif ( $barcodetype eq 'EAN8' ) {
1171 #testing ean8 barcodes hack
1172 $value = $value . '000000000';
1174 $value = substr( $value, 0, 8 );
1178 #warn "EAN8 ELSEIF";
1180 PDF::Reuse::Barcode::EAN8(
1181 x => ( $x_pos_circ + 42 ),
1182 y => ( $y_pos + 15 ),
1192 $item->{'barcodeerror'} = 1;
1194 #warn "BARCODE FAILED:$@";
1201 elsif ( $barcodetype eq 'UPC-E' ) {
1203 PDF::Reuse::Barcode::UPCE(
1204 x => ( $x_pos_circ + 27 ),
1205 y => ( $y_pos + 15 ),
1215 $item->{'barcodeerror'} = 1;
1217 #warn "BARCODE FAILED:$@";
1223 elsif ( $barcodetype eq 'NW7' ) {
1225 PDF::Reuse::Barcode::NW7(
1226 x => ( $x_pos_circ + 27 ),
1227 y => ( $y_pos + 15 ),
1237 $item->{'barcodeerror'} = 1;
1239 #warn "BARCODE FAILED:$@";
1245 elsif ( $barcodetype eq 'ITF' ) {
1247 PDF::Reuse::Barcode::ITF(
1248 x => ( $x_pos_circ + 27 ),
1249 y => ( $y_pos + 15 ),
1259 $item->{'barcodeerror'} = 1;
1261 #warn "BARCODE FAILED:$@";
1267 elsif ( $barcodetype eq 'Industrial2of5' ) {
1269 PDF::Reuse::Barcode::Industrial2of5(
1270 x => ( $x_pos_circ + 27 ),
1271 y => ( $y_pos + 15 ),
1280 $item->{'barcodeerror'} = 1;
1282 #warn "BARCODE FAILED:$@";
1288 elsif ( $barcodetype eq 'IATA2of5' ) {
1290 PDF::Reuse::Barcode::IATA2of5(
1291 x => ( $x_pos_circ + 27 ),
1292 y => ( $y_pos + 15 ),
1301 $item->{'barcodeerror'} = 1;
1303 #warn "BARCODE FAILED:$@";
1310 elsif ( $barcodetype eq 'COOP2of5' ) {
1312 PDF::Reuse::Barcode::COOP2of5(
1313 x => ( $x_pos_circ + 27 ),
1314 y => ( $y_pos + 15 ),
1323 $item->{'barcodeerror'} = 1;
1325 #warn "BARCODE FAILED:$@";
1331 elsif ( $barcodetype eq 'UPC-A' ) {
1334 PDF::Reuse::Barcode::UPCA(
1335 x => ( $x_pos_circ + 27 ),
1336 y => ( $y_pos + 15 ),
1345 $item->{'barcodeerror'} = 1;
1347 #warn "BARCODE FAILED:$@";
1356 =item draw_boundaries
1358 sub draw_boundaries ($x_pos_spine, $x_pos_circ1, $x_pos_circ2,
1359 $y_pos, $spine_width, $label_height, $circ_width)
1361 This sub draws boundary lines where the label outlines are, to aid in printer testing, and debugging.
1366 sub draw_boundaries {
1369 $x_pos_spine, $x_pos_circ1, $x_pos_circ2, $y_pos,
1370 $spine_width, $label_height, $circ_width
1373 my $y_pos_initial = ( ( 792 - 36 ) - 90 );
1374 $y_pos = $y_pos_initial; # FIXME - why are we ignoring the y_pos parameter by redefining it?
1377 for ( $i = 1 ; $i <= 8 ; $i++ ) {
1379 &drawbox( $x_pos_spine, $y_pos, ($spine_width), ($label_height) );
1381 #warn "OLD BOXES x=$x_pos_spine, y=$y_pos, w=$spine_width, h=$label_height";
1382 &drawbox( $x_pos_circ1, $y_pos, ($circ_width), ($label_height) );
1383 &drawbox( $x_pos_circ2, $y_pos, ($circ_width), ($label_height) );
1385 $y_pos = ( $y_pos - $label_height );
1392 sub drawbox { $lower_left_x, $lower_left_y,
1393 $upper_right_x, $upper_right_y )
1395 this is a low level sub, that draws a pdf box, it is called by draw_boxes
1397 FYI: the $upper_right_x and $upper_right_y values are RELATIVE to $lower_left_x and $lower_left_y
1399 and $lower_left_x, $lower_left_y are ABSOLUTE, this caught me out!
1405 my ( $llx, $lly, $urx, $ury ) = @_;
1407 # warn "llx,y= $llx,$lly , urx,y=$urx,$ury \n";
1409 my $str = "q\n"; # save the graphic state
1410 $str .= "0.5 w\n"; # border color red
1411 $str .= "1.0 0.0 0.0 RG\n"; # border color red
1412 # $str .= "0.5 0.75 1.0 rg\n"; # fill color blue
1413 $str .= "1.0 1.0 1.0 rg\n"; # fill color white
1415 $str .= "$llx $lly $urx $ury re\n"; # a rectangle
1416 $str .= "B\n"; # fill (and a little more)
1417 $str .= "Q\n"; # save the graphic state
1423 END { } # module clean-up code here (global destructor)
1432 Mason James <mason@katipo.co.nz>