# -- # Copyright (C) 2001-2019 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::PDF; use strict; use warnings; use PDF::API2; our @ObjectDependencies = ( 'Kernel::Config', 'Kernel::System::Cache', 'Kernel::System::DateTime', 'Kernel::System::Log', 'Kernel::System::Main', ); =head1 NAME Kernel::System::PDF - pdf lib =head1 DESCRIPTION Functions for generating PDF files. =head1 PUBLIC INTERFACE =head2 new() Don't use the constructor directly, use the ObjectManager instead: my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF'); Please note that currently you should only create one PDF object per instance of this class. =cut sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # read string width cache $Self->{CacheStringWidth} = $Kernel::OM->Get('Kernel::System::Cache')->Get( Type => 'PDF', Key => 'CacheStringWidth', ) || {}; return $Self; } =head2 DocumentNew() Create a new PDF Document These font aliases are available in all methods: Proportional ProportionalBold ProportionalItalic ProportionalBoldItalic Monospaced MonospacedBold MonospacedItalic MonospacedBoldItalic $True = $PDFObject->DocumentNew( Title => 'The Document Title', # Title of PDF Document Encode => 'utf-8', # Charset of Document Testfonts => 1, # (optional) default 0 ); =cut sub DocumentNew { my ( $Self, %Param ) = @_; # check pdf object if ( $Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Can not create new Document!', ); return; } # get config object my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); # get Product and Version my $PDFCreator = ''; # set to empty value if Secure::DisableBanner is active if ( !$Kernel::OM->Get('Kernel::Config')->Get('Secure::DisableBanner') ) { $PDFCreator = $ConfigObject->Get('Product') . ' ' . $ConfigObject->Get('Version'); } # set document title $Self->{Document}->{Title} = $Param{Title} || $PDFCreator; # set document encode $Self->{Document}->{Encode} = $Param{Encode} || 'utf-8'; # set logo file $Self->{Document}->{LogoFile} = $ConfigObject->Get('PDF::LogoFile'); # create a new document $Self->{PDF} = PDF::API2->new(); # check pdf object if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Can not create new Document: $!', ); return; } # get time object my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime'); # set document infos $Self->{PDF}->info( 'Author' => $PDFCreator, 'CreationDate' => "D:" . $DateTimeObject->Format( Format => '%Y%m%d%H:%M:%S' ) . "+01'00'", 'Creator' => $PDFCreator, 'Producer' => $PDFCreator, 'Title' => $Self->{Document}->{Title}, 'Subject' => $Self->{Document}->{Title}, ); # add font directory my $FontDir = $ConfigObject->Get('Home') . '/var/fonts'; $Self->{PDF}->addFontDirs($FontDir); if ( !$Param{Testfonts} ) { # get font config my %FontFiles = %{ $ConfigObject->Get('PDF::TTFontFile') }; # set fonts for my $FontType ( sort keys %FontFiles ) { $Self->{Font}->{$FontType} = $Self->{PDF}->ttfont( $FontFiles{$FontType}, -encode => $Self->{Document}->{Encode}, -unicodemap => 1, ); } } else { # set testfont (only used in unitests) $Self->{Font}->{Testfont1} = $Self->{PDF}->corefont( 'Helvetica', -encode => $Self->{Document}->{Encode}, -unicodemap => 1, ); $Self->{Font}->{Testfont2} = $Self->{PDF}->ttfont( 'DejaVuSans.ttf', -encode => $Self->{Document}->{Encode}, -unicodemap => 1, ); # get font config my %FontFiles = %{ $ConfigObject->Get('PDF::TTFontFile') }; # set fonts for my $FontType ( sort keys %FontFiles ) { $Self->{Font}->{$FontType} = $Self->{Font}->{Testfont1}; } } return 1; } =head2 PageBlankNew() Create a new, blank Page $True = $PDFObject->PageBlankNew( Width => 200, # (optional) default 595 (Din A4) - _ both or nothing Height => 300, # (optional) default 842 (Din A4) - PageOrientation => 'landscape', # (optional) default normal (normal|landscape) MarginTop => 40, # (optional) default 0 - MarginRight => 40, # (optional) default 0 |_ all or nothing MarginBottom => 40, # (optional) default 0 | MarginLeft => 40, # (optional) default 0 - ShowPageNumber => 0, # (optional) default 1 ); =cut sub PageBlankNew { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Object!" ); return; } # set PageOrientation if ( !defined( $Param{PageOrientation} ) ) { $Param{PageOrientation} = 'normal'; } # set margins $Param{MarginTop} = $Param{MarginTop} || 0; $Param{MarginRight} = $Param{MarginRight} || 0; $Param{MarginBottom} = $Param{MarginBottom} || 0; $Param{MarginLeft} = $Param{MarginLeft} || 0; # create a new page $Self->{Page} = $Self->{PDF}->page(); # if page was created if ( $Self->{Page} ) { # set new page width and height $Self->_CurPageDimSet( %Param, ); # get current page dimension an set mediabox my %Page = $Self->_CurPageDimGet(); $Self->{Page}->mediabox( $Page{Width}, $Page{Height}, ); # set default value of ShowPageNumber, if no value given my $ShowPageNumber = 1; if ( defined( $Param{ShowPageNumber} ) && $Param{ShowPageNumber} eq 0 ) { $ShowPageNumber = 0; } # set the page numbers $Self->_CurPageNumberSet( ShowPageNumber => $ShowPageNumber, ); # set printable dimension $Self->_CurPrintableDimSet( Top => $Param{MarginTop}, Right => $Param{MarginRight}, Bottom => $Param{MarginBottom}, Left => $Param{MarginLeft}, ); # set activ dimension $Self->DimSet( Dim => 'content', ); return 1; } $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Can not create new blank Page!" ); return; } =head2 PageNew() Create a new Page $PDFObject->PageNew( Width => 200, # (optional) default 595 (Din A4) Height => 300, # (optional) default 842 (Din A4) PageOrientation => 'landscape', # (optional) default normal (normal|landscape) MarginTop => 40, # (optional) default 0 MarginRight => 40, # (optional) default 0 MarginBottom => 40, # (optional) default 0 MarginLeft => 40, # (optional) default 0 ShowPageNumber => 0, # (optional) default 1 LogoFile => '/path/to/file.jpg', # (optional) you can use jpg, gif and png-Images HeaderRight => 'Header Right Text', # (optional) HeadlineLeft => 'Headline Text', # (optional) HeadlineRight => 'Headline Text', # (optional) FooterLeft => 'Footer Left Text', # (optional) FooterRight => 'Footer Right Text', # (optional) ); =cut sub PageNew { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Object!" ); return; } my %Data = (); # set new page width and height, if values are given if ( $Param{Width} && $Param{Height} ) { $Data{Width} = $Param{Width}; $Data{Height} = $Param{Height}; } # set new margin, if values are given if ( $Param{MarginTop} && $Param{MarginRight} && $Param{MarginBottom} && $Param{MarginLeft} ) { $Data{MarginTop} = $Param{MarginTop}; $Data{MarginRight} = $Param{MarginRight}; $Data{MarginBottom} = $Param{MarginBottom}; $Data{MarginLeft} = $Param{MarginLeft}; } if ( $Param{ShowPageNumber} ) { $Data{ShowPageNumber} = $Param{ShowPageNumber}; } if ( $Param{PageOrientation} ) { $Data{PageOrientation} = $Param{PageOrientation}; } # create a blank page $Self->PageBlankNew(%Data); if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page Object!" ); return; } # set activ dimension $Self->DimSet( Dim => 'printable', ); # get current printable dimension my %Printable = $Self->_CurPrintableDimGet(); # get logofile my $LogoFile = $Self->{Document}->{LogoFile} || $Kernel::OM->Get('Kernel::Config')->Get('Home') . '/var/logo-otrs.png'; if ( defined( $Param{LogoFile} ) && -e $Param{LogoFile} && ( $Param{LogoFile} =~ /^.*\.gif$/i || $Param{LogoFile} =~ /^.*\.jpg$/i || $Param{LogoFile} =~ /^.*\.png$/i ) ) { $LogoFile = $Param{LogoFile}; } # output the logo image at header left $Self->Image( File => $LogoFile, Width => 700, Height => 100, ); if ( $Param{HeaderRight} ) { # set new position $Self->PositionSet( Move => 'relativ', X => 168, Y => 15, ); # output page header right $Self->Text( Text => $Param{HeaderRight}, Type => 'Cut', Color => '#404040', FontSize => 12, Height => 12, Align => 'right', ); } # set new position $Self->PositionSet( X => 'left', Y => 'top', ); # set new position $Self->PositionSet( Move => 'relativ', Y => -29, ); # output the lines in top of the page $Self->HLine( Color => '#505050', LineWidth => 0.5, ); if ( $Param{FooterLeft} ) { # set new position $Self->PositionSet( X => 'left', Y => 'bottom', ); # set new position $Self->PositionSet( Move => 'relativ', Y => 8, ); # output page footer left $Self->Text( Text => $Param{FooterLeft}, Width => ( $Printable{Width} / 4 * 3 ), Type => 'Cut', Color => '#404040', FontSize => 8, Height => 8, Align => 'left', ); } if ( $Param{FooterRight} ) { # set new position $Self->PositionSet( X => 'left', Y => 'bottom', ); # set new position $Self->PositionSet( Move => 'relativ', X => ( $Printable{Width} / 4 * 3 ), Y => 8, ); # output page footer right $Self->Text( Text => $Param{FooterRight}, Type => 'Cut', Color => '#404040', FontSize => 8, Height => 8, Align => 'right', ); } # set new position $Self->PositionSet( X => 'left', Y => 'bottom', ); # set new position $Self->PositionSet( Move => 'relativ', Y => 11, ); # output the lines in bottom of the page $Self->HLine( Color => '#505050', LineWidth => 0.5, ); if ( $Param{HeadlineLeft} && $Param{HeadlineRight} ) { # set new position $Self->PositionSet( X => 'left', Y => 'top', ); # set new position $Self->PositionSet( Move => 'relativ', Y => -44, ); $Self->Text( Text => $Param{HeadlineLeft}, Width => ( $Printable{Width} / 2 ), Height => 12, Type => 'Cut', Font => 'ProportionalBold', FontSize => 12, ); $Self->PositionSet( X => 'left', Y => 'top', ); $Self->PositionSet( Move => 'relativ', X => ( $Printable{Width} / 2 ), Y => -48, ); $Self->Text( Text => $Param{HeadlineRight}, Height => 8, Type => 'Cut', Font => 'Proportional', FontSize => 8, Color => '#404040', Align => 'right', ); # set new content dimension $Self->_CurContentDimSet( Top => $Printable{Top} + 64, Right => $Printable{Right}, Bottom => $Printable{Bottom} + 16, Left => $Printable{Left}, ); } else { # set new content dimension $Self->_CurContentDimSet( Top => $Printable{Top} + 34, Right => $Printable{Right}, Bottom => $Printable{Bottom} + 16, Left => $Printable{Left}, ); } # set activ dimension $Self->DimSet( Dim => 'content', ); return 1; } =head2 DocumentOutput() Return the PDF as string $DocumentString = $PDFObject->DocumentOutput(); =cut sub DocumentOutput { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Object!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } # return the document as string my $DocumentString = $Self->{PDF}->stringify(); $Self->{PDF}->end(); return $DocumentString; } =head2 Table() Add a table. In case of missing or misused parameters, C is returned in scalar context and an empty list is returned in list context. Return $Return{State} $Return{RequiredWidth} $Return{RequiredHeight} $Return{CellData} # (reference) complete calculated $Return{ColumnData} # (reference) complete calculated %Return = $PDFObject->Table( CellData => $CellData, # 2D arrayref (see example) ColumnData => $ColumnData, # arrayref (see example) RowData => $RowData, # arrayref (see example) Type => 'Cut', # (optional) default ReturnLeftOver (ReturnLeftOver|ReturnLeftOverHard|Cut) Width => 300, # (optional) default maximal width Height => 400, # (optional) default minimal height Font => 'Monospaced', # (optional) default Proportional (see DocumentNew()) FontSize => 9, # (optional) default 11 FontColor => 'red', # (optional) default black FontColorEven => 'blue', # (optional) cell font color for even rows FontColorOdd => 'green', # (optional) cell font color for odd rows Align => 'right', # (optional) default left (left|center|right) Lead => 3, # (optional) default 1 Padding => 18, # (optional) default 3 PaddingTop => 10, # (optional) top cell padding, overides Padding PaddingRight => 30, # (optional) right cell padding, overides Padding PaddingBottom => 30, # (optional) bottom cell padding, overides Padding PaddingLeft => 10, # (optional) left cell padding, overides Padding BackgroundColor => '#101010', # (optional) default white BackgroundColorEven => '#F0F0F0', # (optional) cell background color for even rows BackgroundColorOdd => '#A0A0A0', # (optional) cell background color for odd rows Border => 1, # (optional) default 1 (values between 0 and 20) BorderColor => '#FF0000', # (optional) default black ); $CellData = [ [ { Content => "Cell 1 (Row 1, Column 1)", # (optional) Font => 'Monospaced', # (optional) (see DocumentNew()) FontSize => 13, # (optional) FontColor => '#00FF00', # (optional) Align => 'center', # (optional) Lead => 7, # (optional) BackgroundColor => '#101010', # (optional) }, { Content => "Cell 2 (Row 1, Column 2)", }, ], [ { Content => "Cell 3 (Row 2, Column 1)", }, { Content => "Cell 4 (Row 2, Column 2)", }, ], ]; $ColumData = [ # this array was automaticly generated, if not given { Width => 11, # (optional) }, { Width => 44, }, ]; $RowData = [ # this array was automaticly generated, if not given { Height => 11, # (optional) }, { Height => 44, }, ]; =cut sub Table { my ( $Self, %Param ) = @_; # check needed stuff for (qw(CellData)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); $Param{State} = 1; return; } } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); $Param{State} = 1; return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); $Param{State} = 1; return; } my %Dim; # get dimension (printable or content) if ( $Self->DimGet() eq 'printable' ) { %Dim = $Self->_CurPrintableDimGet(); } else { %Dim = $Self->_CurContentDimGet(); } # get current position my %Position = $Self->_CurPositionGet(); # set default values $Param{ColumnData} ||= []; $Param{RowData} ||= []; if ( ref( $Param{CellData} ) eq 'ARRAY' && ref( $Param{ColumnData} ) eq 'ARRAY' && ref( $Param{RowData} ) eq 'ARRAY' ) { if ( !defined( $Param{OutputCount} ) ) { # set default values $Param{Type} ||= 'ReturnLeftOver'; $Param{Font} ||= 'Proportional'; if ( !defined( $Param{FontSize} ) || $Param{FontSize} <= 0 ) { $Param{FontSize} = 10; } if ( !defined( $Param{Lead} ) || $Param{Lead} < -( $Param{FontSize} ) ) { $Param{Lead} = int( $Param{FontSize} / 4 ); if ( $Param{Lead} < 1 ) { $Param{Lead} = 1; } } $Param{FontColor} ||= 'black'; $Param{FontColorOdd} ||= $Param{FontColor}; $Param{FontColorEven} ||= $Param{FontColor}; $Param{BackgroundColor} ||= 'NULL'; $Param{BackgroundColorOdd} ||= $Param{BackgroundColor}; $Param{BackgroundColorEven} ||= $Param{BackgroundColor}; $Param{Align} = $Param{Align} || 'left'; if ( !defined( $Param{Border} ) || $Param{Border} < 0 ) { $Param{Border} = 1; } $Param{BorderColor} ||= 'black'; $Param{PaddingTop} ||= $Param{Padding} || 3; $Param{PaddingRight} ||= $Param{Padding} || 3; $Param{PaddingBottom} ||= $Param{Padding} || 3; $Param{PaddingLeft} ||= $Param{Padding} || 3; # check given Width my $DefaultWidth = $Dim{Left} + $Dim{Width} - $Position{X}; if ( !defined( $Param{Width} ) || ( $Param{Width} - $Param{PaddingLeft} - $Param{PaddingRight} - ( 2 * $Param{Border} ) ) < 0 || $Param{Width} > $DefaultWidth ) { $Param{Width} = $DefaultWidth; } # set output count $Param{OutputCount} = 0; # set state $Param{State} = 0; # calculate required table attributes $Self->_TableCalculate( %Param, ); } # check given Height my $DefaultHeight = $Position{Y} - $Dim{Bottom}; if ( !defined( $Param{Height} ) || ( $Param{Height} - $Param{PaddingTop} - $Param{PaddingBottom} - ( 2 * $Param{Border} ) ) < 0 || $Param{Height} > $DefaultHeight ) { $Param{Height} = $DefaultHeight; } # get maximum number of pages my $MaxPages = $Kernel::OM->Get('Kernel::Config')->Get('PDF::MaxPages'); if ( !$MaxPages || $MaxPages < 1 || $MaxPages > 1000 ) { $MaxPages = 100; } # infinite loop protection if ( $Param{OutputCount} < $MaxPages ) { my %Block = $Self->_TableBlockNextCalculate( CellData => $Param{CellData}, ColumnData => $Param{ColumnData}, ); # if active cells found if ( $Block{State} ) { # start row output my $Row = $Block{ReturnRowStart}; my $RowCounter = 0; my $RowLoop = 1; my $LastBlock = $Param{ColumnData}->[ $#{ $Param{ColumnData} } ]->{Block}; my $LastRow = $#{ $Param{RowData} }; while ($RowLoop) { # stop loop, if last row if ( $Row <= $LastRow ) { # calculate row height, if block is 0 if ( !$Block{ReturnBlock} ) { $Self->_TableRowCalculate( Row => $Row, %Param, ); } # save old position my %PositionOld = %Position; if ( $Param{RowData}->[$Row]->{OutputHeight} && $Param{RowData}->[$Row]->{OutputHeight} <= $Position{Y} - $Dim{Bottom} ) { for ( $Block{ReturnColumnStart} .. $Block{ReturnColumnStop} ) { my $Column = $_; $Self->_TableCellOutput( Text => $Param{CellData}->[$Row]->[$Column]->{Content}, Type => $Param{CellData}->[$Row]->[$Column]->{Type}, Width => $Param{ColumnData}->[$Column]->{OutputWidth}, Height => $Param{RowData}->[$Row]->{OutputHeight}, Font => $Param{CellData}->[$Row]->[$Column]->{Font}, FontSize => $Param{CellData}->[$Row]->[$Column]->{FontSize}, FontColor => $Param{CellData}->[$Row]->[$Column]->{FontColor}, Align => $Param{CellData}->[$Row]->[$Column]->{Align}, Lead => $Param{CellData}->[$Row]->[$Column]->{Lead}, PaddingTop => $Param{PaddingTop}, PaddingRight => $Param{PaddingRight}, PaddingBottom => $Param{PaddingBottom}, PaddingLeft => $Param{PaddingLeft}, BackgroundColor => $Param{CellData}->[$Row]->[$Column]->{BackgroundColor}, Border => $Param{Border}, BorderColor => $Param{BorderColor}, ); # deactivate cell and delete content $Param{CellData}->[$Row]->[$Column]->{Off} = 1; $Param{CellData}->[$Row]->[$Column]->{Content} = ' '; # set new position $Self->_CurPositionSet( X => $Position{X} + $Param{ColumnData}->[$Column]->{OutputWidth} - $Param{Border}, Y => $Position{Y}, ); # get current position %Position = $Self->_CurPositionGet(); } # set new position $Self->_CurPositionSet( X => $PositionOld{X}, Y => $PositionOld{Y} - $Param{RowData}->[$Row]->{OutputHeight} + $Param{Border}, ); # get current position %Position = $Self->_CurPositionGet(); } else { my $NewOutputHeight = $Position{Y} - $Dim{Bottom}; my $NewTextHeight = $NewOutputHeight - $Param{PaddingTop} - $Param{PaddingBottom} - ( 2 * $Param{Border} ); if ( $NewTextHeight > $Param{RowData}->[$Row]->{MinFontSize} ) { for ( $Block{ReturnColumnStart} .. $Block{ReturnColumnStop} ) { my $Column = $_; my $Type = 'ReturnLeftOver'; if ( $Param{CellData}->[$Row]->[$Column]->{Type} eq 'ReturnLeftOverHard' ) { $Type = 'ReturnLeftOverHard'; } my %Return = $Self->_TableCellOutput( Text => $Param{CellData}->[$Row]->[$Column]->{Content}, Type => $Type, Width => $Param{ColumnData}->[$Column]->{OutputWidth}, Height => $NewOutputHeight, Font => $Param{CellData}->[$Row]->[$Column]->{Font}, FontSize => $Param{CellData}->[$Row]->[$Column]->{FontSize}, FontColor => $Param{CellData}->[$Row]->[$Column]->{FontColor}, Align => $Param{CellData}->[$Row]->[$Column]->{Align}, Lead => $Param{CellData}->[$Row]->[$Column]->{Lead}, PaddingTop => $Param{PaddingTop}, PaddingRight => $Param{PaddingRight}, PaddingBottom => $Param{PaddingBottom}, PaddingLeft => $Param{PaddingLeft}, BackgroundColor => $Param{CellData}->[$Row]->[$Column]->{BackgroundColor}, Border => $Param{Border}, BorderColor => $Param{BorderColor}, ); # set new content if ( !$Return{State} ) { $Param{CellData}->[$Row]->[$Column]->{Content} = $Return{LeftOver}; } else { $Param{CellData}->[$Row]->[$Column]->{Content} = ' '; } # correcting content if ( $Param{CellData}->[$Row]->[$Column]->{Content} eq '' ) { $Param{CellData}->[$Row]->[$Column]->{Content} = ' '; } $Param{CellData}->[$Row]->[$Column]->{TmpOff} = 1; # recalculate height if ( $Block{ReturnBlock} eq $LastBlock && $Column eq $Block{ReturnColumnStop} ) { # if Height was given if ( $Param{RowData}->[$Row]->{Height} > 0 ) { $Param{RowData}->[$Row]->{Height} -= $NewTextHeight; # if rest too small, deactivate all cells of this row if ( $Param{RowData}->[$Row]->{Height} < $Param{RowData}->[$Row]->{MinFontSize} ) { for my $CellOff ( @{ $Param{CellData}->[$Row] } ) { $CellOff->{Content} = ' '; $CellOff->{Off} = 1; $CellOff->{Tmp} = 0; } } } $Self->_TableRowCalculate( Row => $Row, %Param, ); } # set new position $Self->_CurPositionSet( X => $Position{X} + $Param{ColumnData}->[$Column]->{OutputWidth} - $Param{Border}, Y => $Position{Y}, ); # get current position %Position = $Self->_CurPositionGet(); } } $RowLoop = 0; } } else { $RowLoop = 0; } if ( $RowCounter > 100 ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Too much row loops on page! Infinite Loop protection. Table Output aborted." ); $RowLoop = 0; } # increment Row and RowCounter $Row++; $RowCounter++; } } else { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "No active cells! Table Output aborted." ); $Param{State} = 1; } } else { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Too much loops! Infinite Loop protection. Table Output aborted." ); $Param{State} = 1; } } else { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need array references of CellData, ColumnData and RowData! Table Output aborted." ); $Param{State} = 1; } # count remaining cells my $RemainingCells = $Self->_TableCellOnCount( CellData => $Param{CellData}, ); # set state if ( !$RemainingCells ) { $Param{State} = 1; } $Param{OutputCount}++; return %Param; } =head2 Text() Output a text line Return $Return{State} $Return{RequiredWidth} $Return{RequiredHeight} $Return{LeftOver} %Return = $PDFObject->Text( Text => 'Text', # Text Width => 300, # (optional) available width of textblock Height => 200, # (optional) available height of textblock Type => 'Cut', # (optional) default ReturnLeftOver (ReturnLeftOver|ReturnLeftOverHard|Cut) Font => 'ProportionalBold', # (optional) default Proportional (see DocumentNew()) FontSize => 15, # (optional) default 10 Color => '#FF0000', # (optional) default #000000 Align => 'center', # (optional) default left (left|center|right) Lead => 20, # (optional) default 1 distance between lines ); =cut sub Text { my ( $Self, %Param ) = @_; # check needed stuff for (qw(Text)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my %Dim; # get dimension (printable or content) if ( $Self->DimGet() eq 'printable' ) { %Dim = $Self->_CurPrintableDimGet(); } else { %Dim = $Self->_CurContentDimGet(); } # get current position my %Position = $Self->_CurPositionGet(); $Param{Type} = $Param{Type} || 'ReturnLeftOver'; $Param{Color} = $Param{Color} || 'black'; $Param{Font} = $Param{Font} || 'Proportional'; $Param{Align} = $Param{Align} || 'left'; if ( !defined( $Param{FontSize} ) || $Param{FontSize} <= 0 ) { $Param{FontSize} = 10; } if ( !defined( $Param{Lead} ) || $Param{Lead} < -( $Param{FontSize} ) ) { $Param{Lead} = int( $Param{FontSize} / 4 ); if ( $Param{Lead} < 1 ) { $Param{Lead} = 1; } } # check Width if ( !defined( $Param{Width} ) || $Param{Width} < 0 || ( $Position{X} + $Param{Width} ) >= ( $Dim{Left} + $Dim{Width} ) ) { $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X}; } # check Height if ( !defined( $Param{Height} ) || $Param{Height} < 0 || ( $Position{Y} - $Param{Height} ) < $Dim{Bottom} ) { $Param{Height} = $Position{Y} - $Dim{Bottom}; } # calculate the given text my %Return = $Self->_TextCalculate( Text => $Param{Text}, Type => $Param{Type}, Width => $Param{Width}, Height => $Param{Height}, Font => $Param{Font}, FontSize => $Param{FontSize}, Lead => $Param{Lead}, ); if ( $Return{LeftOver} ne $Param{Text} ) { # create a text object my $Text = $Self->{Page}->text(); # set font and fontsize $Text->font( $Self->{Font}->{ $Param{Font} }, $Param{FontSize} ); # set fontcolor $Text->fillcolor( $Param{Color} ); # save original X position my $PositionX = $Position{X}; my $Counter1 = 0; for my $Row ( @{ $Return{PossibleRows} } ) { # calculate width of row my $RowWidth = $Self->_StringWidth( Text => $Row, Font => $Param{Font}, FontSize => $Param{FontSize}, ); if ( $Param{Align} eq 'right' ) { # set new position $Self->_CurPositionSet( X => $PositionX + $Param{Width} - $RowWidth, ); } elsif ( $Param{Align} eq 'center' ) { # set new position $Self->_CurPositionSet( X => $PositionX + ( ( $Param{Width} - $RowWidth ) / 2 ), ); } # set new position if ( $Counter1 > 0 ) { $Self->_CurPositionSet( Y => $Position{Y} - $Param{FontSize} - $Param{Lead}, ); } else { $Self->_CurPositionSet( Y => $Position{Y} - $Param{FontSize}, ); } # get current position %Position = $Self->_CurPositionGet(); # get to position $Text->translate( $Position{X}, $Position{Y} ); # output text $Text->text($Row); $Counter1++; } # set new position $Self->_CurPositionSet( X => $PositionX, ); } return %Return; } =head2 Image() Output a image $True = $PDFObject->Image( File => '/path/image.gif', # (gif|jpg|png) Type => 'ReturnFalse' # (optional) default Reduce (ReturnFalse|Reduce) Width => 300, # width of image Height => 150, # height of image ); =cut sub Image { my ( $Self, %Param ) = @_; # check needed stuff for (qw(File Width Height)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( !-e $Param{File} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "File $Param{File} not found!" ); return; } my %Dim; # get dimension (printable or content) if ( $Self->DimGet() eq 'printable' ) { %Dim = $Self->_CurPrintableDimGet(); } else { %Dim = $Self->_CurContentDimGet(); } $Param{Width} = $Param{Width} / ( 300 / 72 ); $Param{Height} = $Param{Height} / ( 300 / 72 ); my $Image = $Self->{Page}->gfx(); my $ImageFile; # if image already used, use the existing image object if ( defined( $Self->{CacheImageObject}->{ $Param{File} } ) ) { $ImageFile = $Self->{CacheImageObject}->{ $Param{File} }; } else { if ( $Param{File} =~ /^.*\.gif$/i ) { $ImageFile = $Self->{PDF}->image_gif( $Param{File} ); } elsif ( $Param{File} =~ /^.*\.jpg$/i ) { $ImageFile = $Self->{PDF}->image_jpeg( $Param{File} ); } elsif ( $Param{File} =~ /^.*\.png$/i ) { $ImageFile = $Self->{PDF}->image_png( $Param{File} ); } else { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Imagetype of File $Param{File} not supported", ); return; } # cache image object $Self->{CacheImageObject}->{ $Param{File} } = $ImageFile; } # get current position my %Position = $Self->_CurPositionGet(); my $Reduce = 0; # check values if ( ( $Position{X} + $Param{Width} ) >= ( $Dim{Left} + $Dim{Width} ) ) { $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X}; $Reduce = 1; } if ( $Param{Width} < 1 ) { $Param{Width} = 1; } if ( ( $Position{Y} - $Param{Height} ) <= $Dim{Bottom} ) { $Param{Height} = $Position{Y} - $Dim{Bottom}; $Reduce = 1; } if ( $Param{Height} < 1 ) { $Param{Height} = 1; } my $Return = 1; if ( defined( $Param{Type} ) && $Param{Type} eq 'ReturnFalse' && $Reduce ) { $Return = 0; } else { # output the image $Image->image( $ImageFile, $Position{X}, $Position{Y} - $Param{Height}, $Param{Width}, $Param{Height}, ); # set new position $Self->_CurPositionSet( Y => $Position{Y} - $Param{Height}, ); } return $Return; } =head2 HLine() Output a horizontal line $True = $PDFObject->HLine( Width => 300, # (optional) default 'end of printable dimension' Type => 'ReturnFalse' # (optional) default Cut (ReturnFalse|Cut) Color => '#101010', # (optional) default black LineWidth => 1, # (optional) default 1 ); =cut sub HLine { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!", ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!", ); return; } my %Dim; # get current position my %Position = $Self->_CurPositionGet(); # get dimension (printable or content) if ( $Self->DimGet() eq 'printable' ) { %Dim = $Self->_CurPrintableDimGet(); } else { %Dim = $Self->_CurContentDimGet(); } # set default color $Param{Color} = $Param{Color} || 'black'; # check LineWidth if ( !defined( $Param{LineWidth} ) || $Param{LineWidth} <= 0 || $Param{LineWidth} > 100 ) { $Param{LineWidth} = 1; } my $Cut = 0; if ( $Position{Y} - $Param{LineWidth} < $Dim{Bottom} ) { $Param{LineWidth} = $Position{Y} - $Dim{Bottom}; if ( $Param{LineWidth} < 1 ) { $Param{LineWidth} = 1; } $Cut = 1; } $Param{LineWidth} = 0 - $Param{LineWidth}; # check Width if ( defined( $Param{Width} ) && $Param{Width} >= 1 ) { if ( $Position{X} + $Param{Width} > $Dim{Left} + $Dim{Width} ) { $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X}; $Cut = 1; } } else { $Param{Width} = $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X}; } # output the lines in top and bottom of the page my $Line = $Self->{Page}->gfx(); $Line->fillcolor( $Param{Color} ); # check values my $Output = 0; if ( $Self->DimGet() eq 'printable' && $Self->_CurPrintableDimCheck( X => $Position{X}, Y => $Position{Y} ) && $Self->_CurPrintableDimCheck( X => $Position{X} + $Param{Width}, Y => $Position{Y} - $Param{LineWidth} ) ) { $Output = 1; } elsif ( $Self->_CurContentDimCheck( X => $Position{X}, Y => $Position{Y} ) && $Self->_CurContentDimCheck( X => $Position{X} + $Param{Width}, Y => $Position{Y} - $Param{LineWidth} ) ) { $Output = 1; } if ( defined( $Param{Type} ) && $Param{Type} eq 'ReturnFalse' && $Cut ) { $Output = 1; } if ($Output) { # output line $Line->rect( $Position{X}, $Position{Y}, $Param{Width}, $Param{LineWidth} ); $Line->fill(); # set new position $Self->_CurPositionSet( Y => $Position{Y} - $Param{LineWidth}, ); } return $Output; } =head2 PositionSet() Set new position on current page $True = $PDFObject->PositionSet( Move => 'absolut', # (optional) default absolut (absolut|relativ) X => 10, # (optional) (|left|center|right) Y => 20, # (optional) (|top|middle|bottom) ); =cut sub PositionSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!", ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!", ); return; } my %Data; my %Dim; my %Position = $Self->_CurPositionGet(); # get dimension (printable or content) if ( $Self->DimGet() eq 'printable' ) { $Data{Dim} = 'printable'; %Dim = $Self->_CurPrintableDimGet(); } else { $Data{Dim} = 'content'; %Dim = $Self->_CurContentDimGet(); } if ( defined( $Param{X} ) ) { if ( $Param{X} eq 'left' ) { $Data{X} = $Dim{Left}; } elsif ( $Param{X} eq 'center' ) { $Data{X} = ( $Dim{Width} / 2 ) + $Dim{Left}; } elsif ( $Param{X} eq 'right' ) { $Data{X} = $Dim{Left} + $Dim{Width}; } else { if ( defined( $Param{Move} ) && $Param{Move} eq 'relativ' ) { if ( ( $Position{X} + $Param{X} ) >= $Dim{Left} && ( $Position{X} + $Param{X} ) < ( $Dim{Left} + $Dim{Width} ) ) { $Data{X} = $Position{X} + $Param{X}; } elsif ( ( $Position{X} + $Param{X} ) >= ( $Dim{Left} + $Dim{Width} ) ) { $Data{X} = $Dim{Left} + $Dim{Width}; } else { $Data{X} = $Dim{Left}; } } else { if ( $Param{X} >= $Dim{Left} && $Param{X} < ( $Dim{Left} + $Dim{Width} ) ) { $Data{X} = $Param{X}; } elsif ( $Param{X} >= ( $Dim{Left} + $Dim{Width} ) ) { $Data{X} = $Dim{Left} + $Dim{Width}; } else { $Data{X} = $Dim{Left}; } } } } if ( defined( $Param{Y} ) ) { if ( $Param{Y} eq 'top' ) { $Data{Y} = $Dim{Bottom} + $Dim{Height}; } elsif ( $Param{Y} eq 'middle' ) { $Data{Y} = ( $Dim{Height} / 2 ) + $Dim{Bottom}; } elsif ( $Param{Y} eq 'bottom' ) { $Data{Y} = $Dim{Bottom}; } else { if ( defined( $Param{Move} ) && $Param{Move} eq 'relativ' ) { if ( ( $Position{Y} + $Param{Y} ) <= ( $Dim{Bottom} + $Dim{Height} ) && ( $Position{Y} + $Param{Y} ) > $Dim{Bottom} ) { $Data{Y} = $Position{Y} + $Param{Y}; } elsif ( ( $Position{Y} + $Param{Y} ) <= $Dim{Bottom} ) { $Data{Y} = $Dim{Bottom}; } else { $Data{Y} = $Dim{Bottom} + $Dim{Height}; } } else { if ( $Param{Y} > $Dim{Bottom} && $Param{Y} <= ( $Dim{Bottom} + $Dim{Height} ) ) { $Data{Y} = $Param{Y}; } elsif ( $Param{Y} <= $Dim{Bottom} ) { $Data{Y} = $Dim{Bottom}; } else { $Data{Y} = $Dim{Bottom} + $Dim{Height}; } } } } $Self->_CurPositionSet( %Data, ); return 1; } =head2 PositionGet() Get position on current page Return $Position{X} $Position{Y} %Position = $PDFObject->PositionGet(); =cut sub PositionGet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!", ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!", ); return; } my %Position = $Self->_CurPositionGet(); return %Position; } =head2 DimSet() Set active dimension $Dim = $PDFObject->DimSet( Dim => 'printable', # (optional) default content (content|printable) ); =cut sub DimSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!", ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!", ); return; } if ( defined( $Param{Dim} ) && $Param{Dim} eq 'printable' ) { $Self->{Current}->{Dim} = 'printable'; } else { $Self->{Current}->{Dim} = 'content'; } return $Self->{Current}->{Dim}; } =head2 DimGet() Get active dimension (printable or content) $Dim = $PDFObject->DimGet(); =cut sub DimGet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( $Self->{Current}->{Dim} eq 'printable' || $Self->{Current}->{Dim} eq 'content' ) { $Self->{Current}->{Dim} = 'content'; } return $Self->{Current}->{Dim}; } =begin Internal: =head2 _TableCalculate() calculate params of table. Return # normally no return required, only references %Param The returned hash is usually not needed, as the passed in references are modified in place. In case of missing or misused parameters, C is returned in scalar context and an empty list is returned in list context. %Return = $PDFObject->_TableCalculate( CellData => $CellData, # 2D arrayref (see example) ColumnData => $ColumnData, # arrayref (see example) RowData => $RowData, # arrayref (see example) Width => 300, # (optional) default default maximal width Height => 400, # (optional) default minimal height Font => 'Monospaced', # (optional) default Proportional (see DocumentNew()) FontSize => 9, # (optional) default 11 FontColor => 'red', # (optional) default black FontColorEven => 'blue', # (optional) cell font color for even rows FontColorOdd => 'green', # (optional) cell font color for odd rows Align => 'right', # (optional) default left (left|center|right) Lead => 3, # (optional) default 1 PaddingTop => 10, # (optional) top cell padding, overides Padding PaddingRight => 30, # (optional) right cell padding, overides Padding PaddingBottom => 30, # (optional) bottom cell padding, overides Padding PaddingLeft => 10, # (optional) left cell padding, overides Padding BackgroundColor => '#101010', # (optional) default white BackgroundColorEven => '#F0F0F0', # (optional) cell background color for even rows BackgroundColorOdd => '#A0A0A0', # (optional) cell background color for odd rows Border => 1, # (optional) default 1 (values between 0 and 20) BorderColor => '#FF0000', # (optional) default black ); $CellData = [ [ { Content => "Cell 1 (Row 1, Column 1)", # (optional) Font => 'Monospaced', # (optional) FontSize => 13, # (optional) FontColor => '#00FF00', # (optional) Align => 'center', # (optional) Lead => 7, # (optional) BackgroundColor => '#101010', # (optional) }, { Content => "Cell 2 (Row 1, Column 2)", }, ], [ { Content => "Cell 3 (Row 2, Column 1)", }, { Content => "Cell 4 (Row 2, Column 2)", }, ], ]; $ColumData = [ # this array was automaticly generated, if not given { Width => 11, # (optional) }, { Width => 44, }, ]; $RowData = [ # this array was automaticly generated, if not given { Height => 11, # (optional) }, { Height => 44, }, ]; =cut sub _TableCalculate { my ( $Self, %Param ) = @_; # check needed stuff for ( qw( CellData ColumnData RowData Type Font FontSize Lead FontColor Align BackgroundColor Width Border BorderColor PaddingTop PaddingRight PaddingBottom PaddingLeft ) ) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( ref( $Param{CellData} ) ne 'ARRAY' || ref( $Param{ColumnData} ) ne 'ARRAY' || ref( $Param{RowData} ) ne 'ARRAY' ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need array references of CellData, ColumnData and RowData!" ); return; } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } # analyse, if table is corrupt my $ColumnMax = 0; my $RowMax = 0; for my $Row ( @{ $Param{CellData} } ) { if ( scalar(@$Row) > $ColumnMax ) { $ColumnMax = scalar(@$Row); } $RowMax++; } # repair, if table is corrupt if ( $RowMax eq 0 ) { ${ $Param{CellData} }[0] = []; $RowMax = 1; } if ( $ColumnMax eq 0 ) { $ColumnMax = 1; } # cut ColumnData, if to much values if ( defined( ${ $Param{ColumnData} }[$ColumnMax] ) ) { splice( @{ $Param{ColumnData} }, $ColumnMax ); } # cut RowData, if to much values if ( defined( ${ $Param{RowData} }[$RowMax] ) ) { splice( @{ $Param{RowData} }, $RowMax ); } my $RowCounter = 0; for my $Row ( @{ $Param{CellData} } ) { my $MinFontSize = 999; for ( my $ColumnCounter = 0; $ColumnCounter < $ColumnMax; $ColumnCounter++ ) { # repair, if row is corrupt if ( !defined( $Row->[$ColumnCounter] ) ) { $Row->[$ColumnCounter] = {}; } # reference of current cell my $Cell = $Row->[$ColumnCounter]; # if row is odd if ( $RowCounter & 1 ) { # set FontColor, if row is odd if ( !defined( $Cell->{FontColor} ) && defined( $Param{FontColorOdd} ) ) { $Cell->{FontColor} = $Param{FontColorOdd}; } # set BackgroundColor, if row is odd if ( !defined( $Cell->{BackgroundColor} ) && defined( $Param{BackgroundColorOdd} ) ) { $Cell->{BackgroundColor} = $Param{BackgroundColorOdd}; } } # if row is even else { # set FontColor, if row is even if ( !defined( $Cell->{FontColor} ) && defined( $Param{FontColorEven} ) ) { $Cell->{FontColor} = $Param{FontColorEven}; } # set BackgroundColor, if row is even if ( !defined( $Cell->{BackgroundColor} ) && defined( $Param{BackgroundColorEven} ) ) { $Cell->{BackgroundColor} = $Param{BackgroundColorEven}; } } # set cell state if ( !defined( $Cell->{Off} ) ) { $Cell->{Off} = 0; } # set temp cell state if ( !defined( $Cell->{TmpOff} ) ) { $Cell->{TmpOff} = 0; } # prepare text if ( defined( $Cell->{Content} ) ) { $Cell->{Content} = $Self->_PrepareText( Text => $Cell->{Content}, ); } # set content blank, if not defined if ( !defined( $Cell->{Content} ) || $Cell->{Content} eq '' ) { $Cell->{Content} = ' '; } # set default values for (qw(Type Font FontSize FontColor Align Lead BackgroundColor)) { if ( !defined( $Cell->{$_} ) ) { $Cell->{$_} = $Param{$_}; } } # calculate width of complete column content if ( !defined( $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} ) ) { $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} = 0; } my $CompleteContentWidth = $Self->_StringWidth( Text => $Cell->{Content}, Font => $Cell->{Font}, FontSize => $Cell->{FontSize}, ); if ( $CompleteContentWidth > $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} ) { $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} = $CompleteContentWidth; } # calculate with of the greaterst word if ( !defined( $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} ) ) { $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} = 0; } my @Words = split( /\s+/, $Cell->{Content} ); my $WordMaxLength = 0; for (@Words) { my $WordLength = length($_); if ( $WordMaxLength <= $WordLength + 2 ) { $WordMaxLength = $WordLength; # calculate width of word my $WordWidth = $Self->_StringWidth( Text => $_, Font => $Cell->{Font}, FontSize => $Cell->{FontSize}, ); if ( $WordWidth > $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} ) { $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} = $WordWidth; } } } # find the smallerst fontsize if ( $Cell->{FontSize} < $MinFontSize ) { $MinFontSize = $Cell->{FontSize}; } } # set MinFontSize $Param{RowData}->[$RowCounter]->{MinFontSize} = $MinFontSize; $RowCounter++; } # estimate width of columns (without padding and border) for my $Column ( @{ $Param{ColumnData} } ) { if ( !defined( $Column->{Width} ) ) { $Column->{Width} = 0; } if ( $Column->{Width} > 0 ) { $Column->{EstimateWidth} = $Column->{Width}; } else { # estimate width of column $Column->{EstimateWidth} = ( $Column->{MaxColWidth} + $Column->{MinColWidth} ) / 2; } # reduce calculated width and width, if calculated width is greater than table width my $MaxWidth = $Param{Width} - $Param{PaddingLeft} - $Param{PaddingRight} - ( 2 * $Param{Border} ); if ( $Column->{EstimateWidth} > $MaxWidth ) { $Column->{EstimateWidth} = $MaxWidth; if ( $Column->{Width} > 0 ) { $Column->{Width} = $MaxWidth; } } # set width to 1, if width is too small if ( $Column->{EstimateWidth} < 1 ) { $Column->{EstimateWidth} = 1; } } # calculate exactly width of columns my $ColumnBlocks = []; $ColumnBlocks->[0]->{Width} = 0; $ColumnBlocks->[0]->{ColumnStart} = 0; $ColumnBlocks->[0]->{ColumnStop} = 0; $ColumnBlocks->[0]->{ColumnFix} = 0; $ColumnBlocks->[0]->{ColumnDyn} = 0; my $Block = 0; my $Counter = 0; for my $Column ( @{ $Param{ColumnData} } ) { my $ColumnWidth = $Column->{EstimateWidth} + $Param{PaddingLeft} + $Param{PaddingRight} + ( 2 * $Param{Border} ); if ( !$ColumnBlocks->[$Block]->{Width} ) { $ColumnBlocks->[$Block]->{Width} = $ColumnWidth; } else { if ( ( $ColumnBlocks->[$Block]->{Width} + $ColumnWidth - $Param{Border} ) > $Param{Width} ) { $ColumnBlocks->[$Block]->{ColumnStop} = $Counter - 1; $Block++; $ColumnBlocks->[$Block]->{Width} = $ColumnWidth; $ColumnBlocks->[$Block]->{ColumnStart} = $Counter; $ColumnBlocks->[$Block]->{ColumnFix} = 0; $ColumnBlocks->[$Block]->{ColumnDyn} = 0; } else { $ColumnBlocks->[$Block]->{Width} += $ColumnWidth - $Param{Border}; } $ColumnBlocks->[$Block]->{ColumnStop} = $Counter; } if ( $Column->{Width} > 0 ) { $ColumnBlocks->[$Block]->{ColumnFix}++; } else { $ColumnBlocks->[$Block]->{ColumnDyn}++; } $Counter++; } my $LastBlock = $#{$ColumnBlocks}; my $Counter2 = 0; for my $CurBlock ( @{$ColumnBlocks} ) { my $ExtraSpaceComplete; # no extra space for laast block if ( $Counter2 && $Counter2 eq $LastBlock ) { $ExtraSpaceComplete = 0; } else { $ExtraSpaceComplete = $Param{Width} - $CurBlock->{Width}; } my $ExtraSpaceDyn = 0; my $ExtraSpaceFix = 0; if ( $CurBlock->{ColumnDyn} > 0 ) { $ExtraSpaceDyn = $ExtraSpaceComplete / $CurBlock->{ColumnDyn}; } else { $ExtraSpaceFix = $ExtraSpaceComplete / $CurBlock->{ColumnFix}; } for ( $CurBlock->{ColumnStart} .. $CurBlock->{ColumnStop} ) { my $Column = $Param{ColumnData}->[$_]; my $ExtraSpace = 0; if ( $Column->{Width} > 0 ) { $ExtraSpace = $ExtraSpaceFix; } else { $ExtraSpace = $ExtraSpaceDyn; } $Column->{OutputWidth} = $Column->{EstimateWidth} + $ExtraSpace + $Param{PaddingLeft} + $Param{PaddingRight} + ( 2 * $Param{Border} ); $Column->{TextWidth} = $Column->{EstimateWidth} + $ExtraSpace; if ( $Column->{OutputWidth} < 1 ) { $Column->{OutputWidth} = 1; } if ( $Column->{TextWidth} < 1 ) { $Column->{TextWidth} = 1; } $Column->{Block} = $Counter2; } $Counter2++; } return %Param; } =head2 _TableBlockNextCalculate() calculate what block can output next Return $Return{State} $Return{ReturnBlock} $Return{ReturnRowStart} $Return{ReturnColumnStart} $Return{ReturnColumnStop} %Return = $PDFObject->_TableBlockNextCalculate( CellData => $CellData, # 2D arrayref ColumnData => $ColumnData, # arrayref ); =cut sub _TableBlockNextCalculate { my ( $Self, %Param ) = @_; my %Return = ( State => 0, ReturnBlock => 0, ReturnRowStart => 0, ReturnColumnStart => 0, ReturnColumnStop => 0, ); # check needed stuff for (qw(CellData ColumnData)) { if ( !defined $Param{$_} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( ref $Param{CellData} ne 'ARRAY' || ref $Param{ColumnData} ne 'ARRAY' ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need array references of CellData and ColumnData!" ); return; } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my $RowStart = 'NULL'; my $ColumnStart = 'NULL'; my $ColumnStop = 0; # calculate, what cells can output (what cells are active) my $RowCounter = 0; for my $Row ( @{ $Param{CellData} } ) { # if last block was temporary off, reactivate the row if ( $Param{CellData}->[$RowCounter]->[ $#{ $Param{CellData}->[$RowCounter] } ]->{TmpOff} ) { for ( my $ColumnCounter = 0; $ColumnCounter < scalar(@$Row); $ColumnCounter++ ) { $Row->[$ColumnCounter]->{TmpOff} = 0; } } # now calculate, what cells can output (what cells are active) COLUMN_COUNTER: for ( my $ColumnCounter = 0; $ColumnCounter < scalar @$Row; $ColumnCounter++ ) { # calculate RowStart and ColumnStart if ( $Row->[$ColumnCounter]->{Off} ne 1 && $Row->[$ColumnCounter]->{TmpOff} ne 1 && $RowStart eq 'NULL' && $ColumnStart eq 'NULL' ) { $RowStart = $RowCounter; $ColumnStart = $ColumnCounter; $ColumnStop = $ColumnStart; last COLUMN_COUNTER; } } $RowCounter++; } if ( $RowStart ne 'NULL' && $ColumnStart ne 'NULL' ) { # find last column of block my $Block = $Param{ColumnData}->[$ColumnStart]->{Block}; my $ColumnCounter = 0; for my $Column ( @{ $Param{ColumnData} } ) { if ( $ColumnCounter > $ColumnStop && $Column->{Block} eq $Block ) { $ColumnStop = $ColumnCounter; } $ColumnCounter++; } $Return{State} = 1; $Return{ReturnBlock} = $Block; $Return{ReturnRowStart} = $RowStart; $Return{ReturnColumnStart} = $ColumnStart; $Return{ReturnColumnStop} = $ColumnStop; } return %Return; } =head2 _TableRowCalculate() calculate row of table Return # normally no return required, only references %Param %Return = $PDFObject->_TableRowCalculate( CellData => $CellData, # 2D arrayref RowData => $RowData, # arrayref ColumnData => $ColumnData, # arrayref Row => 3, # current row ); =cut sub _TableRowCalculate { my ( $Self, %Param ) = @_; # check needed stuff for (qw(CellData RowData ColumnData Row)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( ref( $Param{CellData} ) ne 'ARRAY' || ref( $Param{ColumnData} ) ne 'ARRAY' || ref( $Param{RowData} ) ne 'ARRAY' ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need array references of CellData, ColumnData and RowData!" ); return; } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( $Param{RowData}->[ $Param{Row} ]->{Height} ) { $Param{RowData}->[ $Param{Row} ]->{TextHeight} = $Param{RowData}->[ $Param{Row} ]->{Height}; } else { # calculate height of row $Param{RowData}->[ $Param{Row} ]->{Height} = 0; $Param{RowData}->[ $Param{Row} ]->{TextHeight} = 0; my $BiggerstFontSize = 0; my $ColumnCounter = 0; for my $Column ( @{ $Param{ColumnData} } ) { my $Cell = $Param{CellData}->[ $Param{Row} ]->[$ColumnCounter]; my %Calculate = $Self->_TextCalculate( Text => $Cell->{Content}, Type => 'ReturnLeftOver', Width => $Column->{TextWidth}, Height => 1000000, Font => $Cell->{Font}, FontSize => $Cell->{FontSize}, Lead => $Cell->{Lead}, ); if ( $Calculate{RequiredHeight} > $Param{RowData}->[ $Param{Row} ]->{TextHeight} ) { $Param{RowData}->[ $Param{Row} ]->{TextHeight} = $Calculate{RequiredHeight}; } if ( $Cell->{FontSize} > $BiggerstFontSize ) { $BiggerstFontSize = $Cell->{FontSize}; } $ColumnCounter++; } if ( !$Param{RowData}->[ $Param{Row} ]->{TextHeight} ) { $Param{RowData}->[ $Param{Row} ]->{TextHeight} = $BiggerstFontSize; } } $Param{RowData}->[ $Param{Row} ]->{OutputHeight} = $Param{RowData}->[ $Param{Row} ]->{TextHeight} + $Param{PaddingTop} + $Param{PaddingBottom} + ( 2 * $Param{Border} ); return %Param; } =head2 _TableCellOutput() output a cell of a table Return $Return{State} $Return{RequiredWidth} $Return{RequiredHeight} $Return{LeftOver} %Return = $PDFObject->_TableCellOutput( Width => 70, Height => 40, Text => 'Text', Type => 'Cut', Font => 'ProportionalBold', FontSize => 15, FontColor => '#FF0000', Align => 'center', Lead => 20, PaddingTop => 10, PaddingRight => 30, PaddingBottom => 30, PaddingLeft => 10, BackgroundColor => '#101010', Border => 1, BorderColor => '#FF0000', ); =cut sub _TableCellOutput { my ( $Self, %Param ) = @_; my %Return = ( State => 0, RequiredWidth => 0, RequiredHeight => 0, LeftOver => '', ); # check needed stuff for ( qw(Width Height Text Type Font FontSize FontColor Align Lead PaddingTop PaddingRight PaddingBottom PaddingLeft BackgroundColor Border BorderColor) ) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my %Dim; # get dimension (printable or content) if ( $Self->DimGet() eq 'printable' ) { %Dim = $Self->_CurPrintableDimGet(); } else { %Dim = $Self->_CurContentDimGet(); } # get current position my %Position = $Self->_CurPositionGet(); # output background if ( $Param{BackgroundColor} ne 'NULL' ) { my $Background = $Self->{Page}->gfx(); $Background->fillcolor( $Param{BackgroundColor} ); $Background->rect( $Position{X}, $Position{Y}, $Param{Width}, -( $Param{Height} ) ); $Background->fill(); } # output top border if ( $Param{Border} > 0 ) { my $BorderTop = $Self->{Page}->gfx(); $BorderTop->fillcolor( $Param{BorderColor} ); $BorderTop->rect( $Position{X}, $Position{Y}, $Param{Width}, -( $Param{Border} ) ); $BorderTop->fill(); } # output right border if ( $Param{Border} > 0 ) { my $BorderRight = $Self->{Page}->gfx(); $BorderRight->fillcolor( $Param{BorderColor} ); $BorderRight->rect( ( $Position{X} + $Param{Width} - $Param{Border} ), $Position{Y}, $Param{Border}, -( $Param{Height} ) ); $BorderRight->fill(); } # output bottom border if ( $Param{Border} > 0 ) { my $BorderBottom = $Self->{Page}->gfx(); $BorderBottom->fillcolor( $Param{BorderColor} ); $BorderBottom->rect( $Position{X}, ( $Position{Y} - $Param{Height} + $Param{Border} ), $Param{Width}, -( $Param{Border} ) ); $BorderBottom->fill(); } # output left border if ( $Param{Border} > 0 ) { my $BorderLeft = $Self->{Page}->gfx(); $BorderLeft->fillcolor( $Param{BorderColor} ); $BorderLeft->rect( $Position{X}, $Position{Y}, $Param{Border}, -( $Param{Height} ) ); $BorderLeft->fill(); } # calculate text start position my $TextX = $Position{X} + $Param{Border} + $Param{PaddingLeft}; my $TextY = $Position{Y} - $Param{Border} - $Param{PaddingTop} + 1; # calculate width and height of text my $TextWidth = $Param{Width} - $Param{PaddingLeft} - $Param{PaddingRight} - ( 2 * $Param{Border} ); my $TextHeight = $Param{Height} - $Param{PaddingTop} - $Param{PaddingBottom} - ( 2 * $Param{Border} ); # set new position $Self->PositionSet( X => $TextX, Y => $TextY, ); %Return = $Self->Text( Text => $Param{Text}, Type => $Param{Type}, Width => $TextWidth, Height => $TextHeight, Font => $Param{Font}, FontSize => $Param{FontSize}, Color => $Param{FontColor}, Align => $Param{Align}, Lead => $Param{Lead}, ); return %Return; } =head2 _TableCellOnCount() count all active cells Return $CellCount $Count = $PDFObject->_TableCellOnCount( CellData => $CellData, # 2D arrayref ); =cut sub _TableCellOnCount { my ( $Self, %Param ) = @_; my $Return = 0; # check needed stuff for (qw(CellData)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( ref( $Param{CellData} ) ne 'ARRAY' ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need array references of CellData!" ); return; } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } for my $Row ( @{ $Param{CellData} } ) { for ( my $ColumnCounter = 0; $ColumnCounter < scalar(@$Row); $ColumnCounter++ ) { if ( $Row->[$ColumnCounter]->{Off} ne 1 ) { $Return++; } } } return $Return; } =head2 _TextCalculate() calculate required values of given text Return $Return{State} $Return{RequiredWidth} $Return{RequiredHeight} $Return{LeftOver} $Return{PossibleRows} # (Array Ref) %Return = $PDFObject->_TextCalculate( Text => $Text, # text Type => 'Cut', # (ReturnLeftOver|ReturnLeftOverHard|Cut) Width => 300, # available width Height => 200, # available height Font => 'ProportionalBold', # font of text FontSize => 6, # fontsize of text Lead => 20, # lead ); =cut sub _TextCalculate { my ( $Self, %Param ) = @_; my %Return = ( State => 0, RequiredWidth => 0, RequiredHeight => 0, LeftOver => '', ); my @PossibleRows; # check needed stuff for (qw(Text Type Width Height Font FontSize Lead)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my $TextLength = 0; if ( $Param{Width} <= 0 || $Param{Height} <= 0 ) { $Return{LeftOver} = $Param{Text}; $Param{Text} = undef; } else { $Param{Text} = $Self->_PrepareText( Text => $Param{Text}, ); $TextLength = length( $Param{Text} ); } my $Counter1 = 0; while ( defined( $Param{Text} ) ) { my $Row; my $DelPreSpace = 0; # get next row of given text if ( $Param{Text} =~ s/^(.*?)\n(.*)/$2/s ) { $Row = $1; } else { $Row = $Param{Text}; $Param{Text} = undef; } # delete one space at begin of row, if exists $Row =~ s/^\s//; # calculate width of the row my $RowWidth = $Self->_StringWidth( Text => $Row, Font => $Param{Font}, FontSize => $Param{FontSize}, ); # calculate height of the row my $RowHeight = $Param{FontSize}; if ( $Counter1 > 0 ) { $RowHeight += $Param{Lead}; } if ( $Return{RequiredHeight} + $RowHeight <= $Param{Height} ) { # if row is greater then $Param{Width} if ( $RowWidth > $Param{Width} ) { # estimate point of cut my $Factor = $RowWidth / $Param{Width}; my $Cut = int( length($Row) / $Factor ); # cut the row my $RowFore = substr( $Row, 0, $Cut ); my $RowRear = substr( $Row, $Cut ); # calculate width of fore row my $RowForeWidth = $Self->_StringWidth( Text => $RowFore, Font => $Param{Font}, FontSize => $Param{FontSize}, ); # caculate exactly point of cut while ( $RowForeWidth < $Param{Width} ) { $RowFore .= substr( $RowRear, 0, 1 ); $RowRear = substr( $RowRear, 1 ); $RowForeWidth = $Self->_StringWidth( Text => $RowFore, Font => $Param{Font}, FontSize => $Param{FontSize}, ); } while ( $RowForeWidth > $Param{Width} ) { $RowRear = chop($RowFore) . $RowRear; $RowForeWidth = $Self->_StringWidth( Text => $RowFore, Font => $Param{Font}, FontSize => $Param{FontSize}, ); } if ( $Param{Type} eq 'ReturnLeftOver' || $Param{Type} eq 'Cut' ) { if ( $RowFore =~ /[^\s]$/ && $RowRear =~ /^[^\s]/ ) { $RowFore =~ s/^(.*)(\s+.+?)$/$1/; if ($2) { $RowRear = $2 . $RowRear; } } } $Row = $RowFore; if ( $Param{Text} ) { $Param{Text} = $RowRear . "\n" . $Param{Text}; } else { $Param{Text} = $RowRear; } } # delete spaces at end of row, if spaces exists $Row =~ s/^(.*)\s$/$1/; # add Row to PossibleRows array push( @PossibleRows, $Row ); $Return{RequiredHeight} += $RowHeight; # check, if min one character can count (protection of infinite loop) if ( defined( $Param{Text} ) ) { if ( length( $Param{Text} ) >= $TextLength ) { $Return{RequiredWidth} = 0; $Return{RequiredHeight} = 0; $Return{LeftOver} = $Param{Text}; $Param{Text} = undef; @PossibleRows = (); } else { $TextLength = length( $Param{Text} ); } } } else { $Return{LeftOver} = $Row; if ( $Param{Text} ) { $Return{LeftOver} .= "\n" . $Param{Text}; $Param{Text} = undef; } } $Counter1++; } # cut text if type is Cut if ( $Param{Type} eq 'Cut' && $Return{LeftOver} ) { my $LastRow = $PossibleRows[-1]; if ($LastRow) { # calculate width [..] my $PPWidth = $Self->_StringWidth( Text => '[..]', Font => $Param{Font}, FontSize => $Param{FontSize}, ); if ( $PPWidth <= $Param{Width} ) { # calculate width of LastRow and [..] my $TextCutWidth = $Self->_StringWidth( Text => $LastRow, Font => $Param{Font}, FontSize => $Param{FontSize}, ); # calculate last line while ( $TextCutWidth + $PPWidth > $Param{Width} ) { chop($LastRow); # calculate width of shorted LastRow and [..] $TextCutWidth = $Self->_StringWidth( Text => $LastRow, Font => $Param{Font}, FontSize => $Param{FontSize}, ); } $PossibleRows[-1] = $LastRow . '[..]'; } $Return{LeftOver} = ''; } } # calculate RequiredWidth my $Counter2 = 0; for (@PossibleRows) { my $RowWidth = $Self->_StringWidth( Text => $_, Font => $Param{Font}, FontSize => $Param{FontSize}, ); # set new RequiredWidth if ( $RowWidth > $Return{RequiredWidth} ) { $Return{RequiredWidth} = $RowWidth; } $Counter2++; } # correct RequiredHeight if ( $Return{RequiredWidth} eq 0 ) { $Return{RequiredHeight} = 0; } # set state if ( !$Return{LeftOver} ) { $Return{State} = 1; } $Return{PossibleRows} = \@PossibleRows; return %Return; } =head2 _StringWidth() calculate width of given text $Width = $PDFObject->_StringWidth( Text => 'Text', # text Font => 'ProportionalBold', # font of text FontSize => 6, # fontsize of text ); =cut sub _StringWidth { my ( $Self, %Param ) = @_; # check needed stuff for (qw(Text Font FontSize)) { if ( !defined $Param{$_} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } # check document if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } # check page if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } return $Self->{CacheStringWidth}->{ $Param{Font} }->{ $Param{FontSize} }->{ $Param{Text} } if $Self->{CacheStringWidth}->{ $Param{Font} }->{ $Param{FontSize} }->{ $Param{Text} }; # create a text object $Self->{TextWidthObject} ||= $Self->{Page}->text(); # set font and fontsize $Self->{TextWidthObject}->font( $Self->{Font}->{ $Param{Font} }, $Param{FontSize} ); # calculate width of given text my $StringWidth = $Self->{TextWidthObject}->advancewidth( $Param{Text} ); return $StringWidth if length $Param{Text} > 20; # write width cache if length is not more than 20 chars $Self->{CacheStringWidth}->{ $Param{Font} }->{ $Param{FontSize} }->{ $Param{Text} } = $StringWidth; return $StringWidth; } =head2 _PrepareText() prepare given text for output $Width = $PDFObject->_PrepareText( Text => 'Text', # text ); =cut sub _PrepareText { my ( $Self, %Param ) = @_; # check needed stuff for (qw(Text)) { if ( !defined( $Param{$_} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } # prepare new line $Param{Text} =~ s/(\n\r|\r\r\n|\r\n)/\n/g; $Param{Text} =~ s/\r/\n/g; # convert page brake to new lines $Param{Text} =~ s/\f/\n\n/g; # convert tabs to spaces $Param{Text} =~ s/\t/ /g; return $Param{Text}; } =head2 _CurPageNumberSet() set number of current page $PDFObject->_CurPageNumberSet( ShowPageNumber => 0, # (optional) default 1 ); =cut sub _CurPageNumberSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } # set number of all over pages to 0, if first page if ( !defined( $Self->{Current}->{Page} ) ) { $Self->{Current}->{Page} = 0; } # set number of displayed pages to 0, if first page if ( !defined( $Self->{Current}->{PageNumber} ) ) { $Self->{Current}->{PageNumber} = 0; } # increment all over pages $Self->{Current}->{Page}++; # set page number of current page if ( $Param{ShowPageNumber} eq 0 ) { $Self->{PageData}->{ $Self->{Current}->{Page} }->{PageNumber} = ''; } else { $Self->{Current}->{PageNumber}++; $Self->{PageData}->{ $Self->{Current}->{Page} }->{PageNumber} = $Self->{Current}->{PageNumber}; } return 1; } =head2 _CurPageDimSet() Set current Page Dimension $PDFObject->_CurPageDimSet( Width => 123, # (optional) default 595 (Din A4) Height => 321, # (optional) default 842 (Din A4) PageOrientation => 'landscape', # (optional) (normal|landscape) ); =cut sub _CurPageDimSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my $NewValue; # set CurPageWidth if ( defined( $Param{Width} ) && $Param{Width} >= 100 && $Param{Width} <= 10000 ) { $Self->{Current}->{PageWidth} = int( $Param{Width} ); $NewValue = 1; } # set CurPageHeight if ( defined( $Param{Height} ) && $Param{Height} >= 100 && $Param{Height} <= 10000 ) { $Self->{Current}->{PageHeight} = int( $Param{Height} ); $NewValue = 1; } # get default pagesize my $DefaultWidth = 595; # DIN A4 my $DefaultHeight = 842; # DIN A4 if ( $Kernel::OM->Get('Kernel::Config')->Get('PDF::PageSize') eq 'letter' ) { $DefaultWidth = 612; $DefaultHeight = 792; } # set page orientation if ( defined( $Param{PageOrientation} ) && $Param{PageOrientation} eq 'landscape' ) { my $TmpWidth = $DefaultWidth; $DefaultWidth = $DefaultHeight; $DefaultHeight = $TmpWidth; } # set default values if ( !defined( $Self->{Current}->{PageWidth} ) ) { $Self->{Current}->{PageWidth} = $DefaultWidth; $NewValue = 1; } if ( !defined( $Self->{Current}->{PageHeight} ) ) { $Self->{Current}->{PageHeight} = $DefaultHeight; $NewValue = 1; } if ($NewValue) { # set new printable dimension $Self->{Current}->{PrintableTop} = 0; $Self->{Current}->{PrintableRight} = 0; $Self->{Current}->{PrintableBottom} = 0; $Self->{Current}->{PrintableLeft} = 0; $Self->{Current}->{PrintableWidth} = $Self->{Current}->{PageWidth}; $Self->{Current}->{PrintableHeight} = $Self->{Current}->{PageHeight}; # set new content dimension $Self->{Current}->{ContentTop} = $Self->{Current}->{PrintableTop}; $Self->{Current}->{ContentRight} = $Self->{Current}->{PrintableRight}; $Self->{Current}->{ContentBottom} = $Self->{Current}->{PrintableBottom}; $Self->{Current}->{ContentLeft} = $Self->{Current}->{PrintableLeft}; $Self->{Current}->{ContentWidth} = $Self->{Current}->{PrintableWidth}; $Self->{Current}->{ContentHeight} = $Self->{Current}->{PrintableHeight}; # set new current position $Self->{Current}->{PositionX} = $Self->{Current}->{ContentLeft}; $Self->{Current}->{PositionY} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop}; } return 1; } =head2 _CurPageDimGet() Get current Page Dimension (Width, Height) Return $CurPageDim{Width} $CurPageDim{Height} %CurPageDim = $PDFObject->_CurPageDimGet(); =cut sub _CurPageDimGet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( !$Self->{Current}->{PageWidth} || !$Self->{Current}->{PageHeight} ) { $Self->_CurPageDimSet(); } my %Data; if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { $Data{Width} = $Self->{Current}->{PageWidth}; $Data{Height} = $Self->{Current}->{PageHeight}; } return %Data; } =head2 _CurPageDimCheck() Check given X an/or Y if inside the page dimension $True = $PDFObject->_CurPageDimCheck( X => 200, # (optional) Y => 100, # (optional) ); =cut sub _CurPageDimCheck { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my $Return = 0; my %Page = $Self->_CurPageDimGet(); if ( defined( $Param{X} ) ) { if ( $Param{X} >= 0 && $Param{X} <= $Page{Width} ) { $Return = 1; } } if ( defined( $Param{Y} ) ) { if ( $Param{Y} >= 0 && $Param{Y} <= $Page{Height} ) { $Return = 1; } } return $Return; } =head2 _CurPrintableDimSet() Set current Printable Dimension $True = $PDFObject->_CurPrintableDimSet( Top => 20, # (optional) Right => 20, # (optional) Bottom => 20, # (optional) Left => 20, # (optional) ); =cut sub _CurPrintableDimSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { my $NewValue; # set CurPrintableTop if ( defined( $Param{Top} ) && $Param{Top} > 0 && $Param{Top} < $Self->{Current}->{PageHeight} / 2 ) { $Self->{Current}->{PrintableTop} = $Param{Top}; $NewValue = 1; } # set CurPrintableRight if ( defined( $Param{Right} ) && $Param{Right} > 0 && $Param{Right} < $Self->{Current}->{PageWidth} / 2 ) { $Self->{Current}->{PrintableRight} = $Param{Right}; $NewValue = 1; } # set CurPrintableBottom if ( defined( $Param{Bottom} ) && $Param{Bottom} > 0 && $Param{Bottom} < $Self->{Current}->{PageHeight} / 2 ) { $Self->{Current}->{PrintableBottom} = $Param{Bottom}; $NewValue = 1; } # set CurPrintableLeft if ( defined( $Param{Left} ) && $Param{Left} > 0 && $Param{Left} < $Self->{Current}->{PageWidth} / 2 ) { $Self->{Current}->{PrintableLeft} = $Param{Left}; $NewValue = 1; } if ($NewValue) { # calculate new printable width and height $Self->{Current}->{PrintableWidth} = $Self->{Current}->{PageWidth} - $Self->{Current}->{PrintableLeft} - $Self->{Current}->{PrintableRight}; $Self->{Current}->{PrintableHeight} = $Self->{Current}->{PageHeight} - $Self->{Current}->{PrintableTop} - $Self->{Current}->{PrintableBottom}; # set new content dimension $Self->{Current}->{ContentTop} = $Self->{Current}->{PrintableTop}; $Self->{Current}->{ContentRight} = $Self->{Current}->{PrintableRight}; $Self->{Current}->{ContentBottom} = $Self->{Current}->{PrintableBottom}; $Self->{Current}->{ContentLeft} = $Self->{Current}->{PrintableLeft}; $Self->{Current}->{ContentWidth} = $Self->{Current}->{PrintableWidth}; $Self->{Current}->{ContentHeight} = $Self->{Current}->{PrintableHeight}; # set new current position $Self->{Current}->{PositionX} = $Self->{Current}->{ContentLeft}; $Self->{Current}->{PositionY} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop}; } } return 1; } =head2 _CurPrintableDimGet() Get current Printable Dimension Return $CurPrintableDim{Top} $CurPrintableDim{Right} $CurPrintableDim{Bottom} $CurPrintableDim{Left} $CurPrintableDim{Width} $CurPrintableDim{Height} %CurPrintableDim = $PDFObject->_CurPrintableDimGet(); =cut sub _CurPrintableDimGet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my %Data; if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { $Data{Top} = $Self->{Current}->{PrintableTop}; $Data{Right} = $Self->{Current}->{PrintableRight}; $Data{Bottom} = $Self->{Current}->{PrintableBottom}; $Data{Left} = $Self->{Current}->{PrintableLeft}; $Data{Width} = $Self->{Current}->{PrintableWidth}; $Data{Height} = $Self->{Current}->{PrintableHeight}; } return %Data; } =head2 _CurPrintableDimCheck() Check given X an/or Y if inside the printable dimension $True = $PDFObject->_CurPrintableDimCheck( X => 200, # (optional) Y => 100, # (optional) ); =cut sub _CurPrintableDimCheck { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my $Return = 0; my %Printable = $Self->_CurPrintableDimGet(); if ( defined( $Param{X} ) ) { if ( $Param{X} >= $Printable{Left} && $Param{X} <= ( $Printable{Left} + $Printable{Width} ) ) { $Return = 1; } } if ( defined( $Param{Y} ) ) { if ( $Param{Y} >= $Printable{Bottom} && $Param{Y} <= ( $Printable{Bottom} + $Printable{Height} ) ) { $Return = 1; } } return $Return; } =head2 _CurContentDimSet() Set current Content Dimension $True = $PDFObject->_CurContentDimSet( Top => 20, # (optional) Right => 20, # (optional) Bottom => 20, # (optional) Left => 20, # (optional) ); =cut sub _CurContentDimSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { my $NewValue; # set CurContentTop if ( defined( $Param{Top} ) && $Param{Top} >= $Self->{Current}->{PrintableTop} && $Param{Top} < $Self->{Current}->{PageHeight} / 2 ) { $Self->{Current}->{ContentTop} = $Param{Top}; $NewValue = 1; } # set CurContentRight if ( defined( $Param{Right} ) && $Param{Right} >= $Self->{Current}->{PrintableRight} && $Param{Right} < $Self->{Current}->{PageWidth} / 2 ) { $Self->{Current}->{ContentRight} = $Param{Right}; $NewValue = 1; } # set CurContentBottom if ( defined( $Param{Bottom} ) && $Param{Bottom} >= $Self->{Current}->{PrintableBottom} && $Param{Bottom} < $Self->{Current}->{PageHeight} / 2 ) { $Self->{Current}->{ContentBottom} = $Param{Bottom}; $NewValue = 1; } # set CurContentLeft if ( defined( $Param{Left} ) && $Param{Left} >= $Self->{Current}->{PrintableLeft} && $Param{Left} < $Self->{Current}->{PageWidth} / 2 ) { $Self->{Current}->{ContentLeft} = $Param{Left}; $NewValue = 1; } if ($NewValue) { # calculate new content width and height $Self->{Current}->{ContentWidth} = $Self->{Current}->{PageWidth} - $Self->{Current}->{ContentLeft} - $Self->{Current}->{ContentRight}; $Self->{Current}->{ContentHeight} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop} - $Self->{Current}->{ContentBottom}; # set new current position $Self->{Current}->{PositionX} = $Self->{Current}->{ContentLeft}; $Self->{Current}->{PositionY} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop}; } } return 1; } =head2 _CurContentDimGet() Get current Content Dimension Return $CurContentDim{Top} $CurContentDim{Right} $CurContentDim{Bottom} $CurContentDim{Left} $CurContentDim{Width} $CurContentDim{Height} %CurContentDim = $PDFObject->_CurContentDimGet(); =cut sub _CurContentDimGet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my %Data; if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { $Data{Top} = $Self->{Current}->{ContentTop}; $Data{Right} = $Self->{Current}->{ContentRight}; $Data{Bottom} = $Self->{Current}->{ContentBottom}; $Data{Left} = $Self->{Current}->{ContentLeft}; $Data{Width} = $Self->{Current}->{ContentWidth}; $Data{Height} = $Self->{Current}->{ContentHeight}; } return %Data; } =head2 _CurContentDimCheck() Check given X an/or Y if inside the content dimension $True = $PDFObject->_CurContentDimCheck( X => 200, # (optional) Y => 100, # (optional) ); =cut sub _CurContentDimCheck { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my $Return = 0; my %Content = $Self->_CurContentDimGet(); if ( defined( $Param{X} ) ) { if ( $Param{X} >= $Content{Left} && $Param{X} <= ( $Content{Left} + $Content{Width} ) ) { $Return = 1; } } if ( defined( $Param{Y} ) ) { if ( $Param{Y} >= $Content{Bottom} && $Param{Y} <= ( $Content{Bottom} + $Content{Height} ) ) { $Return = 1; } } return $Return; } =head2 _CurPositionSet() Set current Position $True = $PDFObject->_CurPositionSet( X => 20, # (optional) Y => 20, # (optional) ); =cut sub _CurPositionSet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { if ( $Self->DimGet() eq 'printable' ) { if ( defined( $Param{X} ) && $Param{X} >= $Self->{Current}->{PrintableLeft} && $Param{X} <= $Self->{Current}->{PageWidth} - $Self->{Current}->{PrintableRight} ) { $Self->{Current}->{PositionX} = $Param{X}; } if ( defined( $Param{Y} ) && $Param{Y} <= $Self->{Current}->{PageHeight} - $Self->{Current}->{PrintableTop} && $Param{Y} >= $Self->{Current}->{PrintableBottom} ) { $Self->{Current}->{PositionY} = $Param{Y}; } } else { if ( defined( $Param{X} ) && $Param{X} >= $Self->{Current}->{ContentLeft} && $Param{X} <= $Self->{Current}->{PageWidth} - $Self->{Current}->{ContentRight} ) { $Self->{Current}->{PositionX} = $Param{X}; } if ( defined( $Param{Y} ) && $Param{Y} <= $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop} && $Param{Y} >= $Self->{Current}->{ContentBottom} ) { $Self->{Current}->{PositionY} = $Param{Y}; } } } return 1; } =head2 _CurPositionGet() Get current Position Return $CurPosition{X} $CurPosition{Y} %CurPosition = $PDFObject->_CurPositionGet(); =cut sub _CurPositionGet { my ( $Self, %Param ) = @_; if ( !$Self->{PDF} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a PDF Document!" ); return; } if ( !$Self->{Page} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need a Page!" ); return; } my %Data; if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) { $Data{X} = $Self->{Current}->{PositionX}; $Data{Y} = $Self->{Current}->{PositionY}; } return %Data; } sub DESTROY { my ( $Self, %Param ) = @_; # set cache $Kernel::OM->Get('Kernel::System::Cache')->Set( Type => 'PDF', TTL => 60 * 60 * 24 * 20, Key => 'CacheStringWidth', Value => $Self->{CacheStringWidth}, ); return 1; } 1; =end Internal: =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). This software comes with ABSOLUTELY NO WARRANTY. For details, see the enclosed file COPYING for license information (GPL). If you did not receive this file, see L. =cut