@@ -, +, @@ font metrics --- C4/Labels/Label.pm | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 6 deletions(-) --- a/C4/Labels/Label.pm +++ a/C4/Labels/Label.pm @@ -3,7 +3,6 @@ package C4::Labels::Label; use strict; use warnings; -use Text::Wrap; use Algorithm::CheckDigits; use Text::CSV_XS; use Data::Dumper; @@ -381,6 +380,71 @@ sub create_label { return; } +sub wrap_fields_proportional { + my ($self, %params) = @_; + my $font = $params{'font'}; + my $font_size = $params{'font_size'}; + my $field_data = $params{'field_data'}; + my @lines; + + my $field_length = length $field_data; + my @fieldchar_map; + my @fieldwidth_map; + my @fieldcharwidthsum_map; + my $fieldcharwidthsum = 0.0; # adjusted for margins to align with draw_label_text + my $line_startpos = 0; + my $ignore_subsequent_lines = 0; + + # build lookup maps and use them to scan backward to break on space when truncation would be detected. + my $idx = 0; + for ( $idx=0; $idx <= $field_length; $idx++ ) { + my $fieldchar = substr $field_data, $idx, 1; + $fieldchar_map[$idx] = $fieldchar; + + my $fieldchar_width = C4::Creators::PDF->StrWidth($fieldchar, $font, $self->{'font_size'}); + $fieldcharwidthsum = $fieldcharwidthsum + $fieldchar_width; + $fieldcharwidthsum_map[$idx] = $fieldcharwidthsum; # accumulation of field widths for this field_data + + if ( $fieldcharwidthsum > ($self->{'width'} - $self->{'left_text_margin'}) ) { # truncation detect + + # search backward until space to break text on. + my $space_start_idx = $idx - 1; # start from current position - 1 + + SPACESCAN: for ( my $space_idx = $space_start_idx; $space_idx >= 0; $space_idx--) { # in reverse + + if ( $fieldchar_map[$space_idx] eq ' ' ) { + my $line_length = $space_idx - $line_startpos; + my $text_line = substr $field_data, $line_startpos, $line_length; + push @lines, $text_line; + + if ( ! $self->{'text_wrap_cols'} ) { $ignore_subsequent_lines = 1; } # so we don't write more + + $line_startpos = $space_idx + 1; + + # re-adjust fieldcharwidthsum to start from line_startpos thru current idx of master loop + $fieldcharwidthsum = 0.0; + for ( my $widthsum_idx = $line_startpos; $widthsum_idx <= $idx; $widthsum_idx++ ) { + my $fc = substr $field_data, $widthsum_idx, 1; + my $fcw = C4::Creators::PDF->StrWidth($fc, $font, $self->{'font_size'}); + $fieldcharwidthsum = $fieldcharwidthsum + $fcw; + } + + last SPACESCAN; + } + } + } + } + + # flush what didn't get flushed from truncation if we haven't written anything yet. + if ( $ignore_subsequent_lines == 0 ) { + my $line_length = $field_length - $line_startpos; + my $text_line = substr $field_data, $line_startpos, $line_length; + push @lines, $text_line; + } + + return \@lines; +} + sub draw_label_text { my ($self, %params) = @_; my @label_text = (); @@ -430,8 +494,13 @@ sub draw_label_text { $field_data =~ s/\(/\\\(/g; # Escape '(' and ')' for the pdf object stream... $field_data =~ s/\)/\\\)/g; } - eval{$Text::Wrap::columns = $self->{'text_wrap_cols'};}; - my @line = split(/\n/ ,wrap('', '', $field_data)); + + my @line = @{ wrap_fields_proportional( $self, + font => $font, + font_size => $self->{'font_size'}, + field_data => $field_data + ) }; + # If this is a title field, limit to two lines; all others limit to one... FIXME: this is rather arbitrary if ($field->{'code'} eq 'title' && scalar(@line) >= 2) { while (scalar(@line) > 2) { @@ -452,9 +521,9 @@ sub draw_label_text { $text_llx = $params{'llx'} + $self->{'width'} - ($self->{'left_text_margin'} + $string_width); } elsif($self->{'justify'} eq 'C') { - # some code to try and center each line on the label based on font size and string point width... - my $whitespace = ($self->{'width'} - ($string_width + (2 * $self->{'left_text_margin'}))); - $text_llx = (($whitespace / 2) + $params{'llx'} + $self->{'left_text_margin'}); + # some code to try and center each line on the label based on font size and string point width... + my $whitespace = ($self->{'width'} - ($string_width + (2 * $self->{'left_text_margin'}))); + $text_llx = (($whitespace / 2) + $params{'llx'} + $self->{'left_text_margin'}); } else { $text_llx = ($params{'llx'} + $self->{'left_text_margin'}); --