1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::System::PDF;
10
11use strict;
12use warnings;
13
14use PDF::API2;
15
16our @ObjectDependencies = (
17    'Kernel::Config',
18    'Kernel::System::Cache',
19    'Kernel::System::DateTime',
20    'Kernel::System::Log',
21    'Kernel::System::Main',
22);
23
24=head1 NAME
25
26Kernel::System::PDF - pdf lib
27
28=head1 DESCRIPTION
29
30Functions for generating PDF files.
31
32=head1 PUBLIC INTERFACE
33
34=head2 new()
35
36Don't use the constructor directly, use the ObjectManager instead:
37
38    my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
39
40Please note that currently you should only create one PDF object per instance of
41this class.
42
43=cut
44
45sub new {
46    my ( $Type, %Param ) = @_;
47
48    # allocate new hash for object
49    my $Self = {};
50    bless( $Self, $Type );
51
52    # read string width cache
53    $Self->{CacheStringWidth} = $Kernel::OM->Get('Kernel::System::Cache')->Get(
54        Type => 'PDF',
55        Key  => 'CacheStringWidth',
56    ) || {};
57
58    return $Self;
59}
60
61=head2 DocumentNew()
62
63Create a new PDF Document
64
65These font aliases are available in all methods:
66        Proportional
67        ProportionalBold
68        ProportionalItalic
69        ProportionalBoldItalic
70        Monospaced
71        MonospacedBold
72        MonospacedItalic
73        MonospacedBoldItalic
74
75    $True = $PDFObject->DocumentNew(
76        Title     => 'The Document Title',  # Title of PDF Document
77        Encode    => 'utf-8',               # Charset of Document
78        Testfonts => 1,                     # (optional) default 0
79    );
80
81=cut
82
83sub DocumentNew {
84    my ( $Self, %Param ) = @_;
85
86    # check pdf object
87    if ( $Self->{PDF} ) {
88        $Kernel::OM->Get('Kernel::System::Log')->Log(
89            Priority => 'error',
90            Message  => 'Can not create new Document!',
91        );
92        return;
93    }
94
95    # get config object
96    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
97
98    # get Product and Version
99    my $PDFCreator = '';    # set to empty value if Secure::DisableBanner is active
100    if ( !$Kernel::OM->Get('Kernel::Config')->Get('Secure::DisableBanner') ) {
101        $PDFCreator = $ConfigObject->Get('Product') . ' ' . $ConfigObject->Get('Version');
102    }
103
104    # set document title
105    $Self->{Document}->{Title} = $Param{Title} || $PDFCreator;
106
107    # set document encode
108    $Self->{Document}->{Encode} = $Param{Encode} || 'utf-8';
109
110    # set logo file
111    $Self->{Document}->{LogoFile} = $ConfigObject->Get('PDF::LogoFile');
112
113    # create a new document
114    $Self->{PDF} = PDF::API2->new();
115
116    # check pdf object
117    if ( !$Self->{PDF} ) {
118        $Kernel::OM->Get('Kernel::System::Log')->Log(
119            Priority => 'error',
120            Message  => 'Can not create new Document: $!',
121        );
122        return;
123    }
124
125    # get time object
126    my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
127
128    # set document infos
129    $Self->{PDF}->info(
130        'Author'       => $PDFCreator,
131        'CreationDate' => "D:"
132            . $DateTimeObject->Format( Format => '%Y%m%d%H:%M:%S' )
133            . "+01'00'",
134        'Creator'  => $PDFCreator,
135        'Producer' => $PDFCreator,
136        'Title'    => $Self->{Document}->{Title},
137        'Subject'  => $Self->{Document}->{Title},
138    );
139
140    # add font directory
141    my $FontDir = $ConfigObject->Get('Home') . '/var/fonts';
142    $Self->{PDF}->addFontDirs($FontDir);
143
144    if ( !$Param{Testfonts} ) {
145
146        # get font config
147        my %FontFiles = %{ $ConfigObject->Get('PDF::TTFontFile') };
148
149        # set fonts
150        for my $FontType ( sort keys %FontFiles ) {
151            $Self->{Font}->{$FontType} = $Self->{PDF}->ttfont(
152                $FontFiles{$FontType},
153                -encode     => $Self->{Document}->{Encode},
154                -unicodemap => 1,
155            );
156        }
157    }
158    else {
159
160        # set testfont (only used in unitests)
161        $Self->{Font}->{Testfont1} = $Self->{PDF}->corefont(
162            'Helvetica',
163            -encode     => $Self->{Document}->{Encode},
164            -unicodemap => 1,
165        );
166        $Self->{Font}->{Testfont2} = $Self->{PDF}->ttfont(
167            'DejaVuSans.ttf',
168            -encode     => $Self->{Document}->{Encode},
169            -unicodemap => 1,
170        );
171
172        # get font config
173        my %FontFiles = %{ $ConfigObject->Get('PDF::TTFontFile') };
174
175        # set fonts
176        for my $FontType ( sort keys %FontFiles ) {
177            $Self->{Font}->{$FontType} = $Self->{Font}->{Testfont1};
178        }
179    }
180
181    return 1;
182}
183
184=head2 PageBlankNew()
185
186Create a new, blank Page
187
188    $True = $PDFObject->PageBlankNew(
189        Width           => 200,          # (optional) default 595 (Din A4) - _ both or nothing
190        Height          => 300,          # (optional) default 842 (Din A4) -
191        PageOrientation => 'landscape',  # (optional) default normal (normal|landscape)
192        MarginTop       => 40,           # (optional) default 0 -
193        MarginRight     => 40,           # (optional) default 0  |_ all or nothing
194        MarginBottom    => 40,           # (optional) default 0  |
195        MarginLeft      => 40,           # (optional) default 0 -
196        ShowPageNumber  => 0,            # (optional) default 1
197    );
198
199=cut
200
201sub PageBlankNew {
202    my ( $Self, %Param ) = @_;
203
204    if ( !$Self->{PDF} ) {
205        $Kernel::OM->Get('Kernel::System::Log')->Log(
206            Priority => 'error',
207            Message  => "Need a PDF Object!"
208        );
209        return;
210    }
211
212    # set PageOrientation
213    if ( !defined( $Param{PageOrientation} ) ) {
214        $Param{PageOrientation} = 'normal';
215    }
216
217    # set margins
218    $Param{MarginTop}    = $Param{MarginTop}    || 0;
219    $Param{MarginRight}  = $Param{MarginRight}  || 0;
220    $Param{MarginBottom} = $Param{MarginBottom} || 0;
221    $Param{MarginLeft}   = $Param{MarginLeft}   || 0;
222
223    # create a new page
224    $Self->{Page} = $Self->{PDF}->page();
225
226    # if page was created
227    if ( $Self->{Page} ) {
228
229        # set new page width and height
230        $Self->_CurPageDimSet( %Param, );
231
232        # get current page dimension an set mediabox
233        my %Page = $Self->_CurPageDimGet();
234        $Self->{Page}->mediabox( $Page{Width}, $Page{Height}, );
235
236        # set default value of ShowPageNumber, if no value given
237        my $ShowPageNumber = 1;
238        if ( defined( $Param{ShowPageNumber} ) && $Param{ShowPageNumber} eq 0 ) {
239            $ShowPageNumber = 0;
240        }
241
242        # set the page numbers
243        $Self->_CurPageNumberSet(
244            ShowPageNumber => $ShowPageNumber,
245        );
246
247        # set printable dimension
248        $Self->_CurPrintableDimSet(
249            Top    => $Param{MarginTop},
250            Right  => $Param{MarginRight},
251            Bottom => $Param{MarginBottom},
252            Left   => $Param{MarginLeft},
253        );
254
255        # set activ dimension
256        $Self->DimSet(
257            Dim => 'content',
258        );
259
260        return 1;
261    }
262
263    $Kernel::OM->Get('Kernel::System::Log')->Log(
264        Priority => 'error',
265        Message  => "Can not create new blank Page!"
266    );
267
268    return;
269}
270
271=head2 PageNew()
272
273Create a new Page
274
275    $PDFObject->PageNew(
276        Width           => 200,                 # (optional) default 595 (Din A4)
277        Height          => 300,                 # (optional) default 842 (Din A4)
278        PageOrientation => 'landscape',         # (optional) default normal (normal|landscape)
279        MarginTop       => 40,                  # (optional) default 0
280        MarginRight     => 40,                  # (optional) default 0
281        MarginBottom    => 40,                  # (optional) default 0
282        MarginLeft      => 40,                  # (optional) default 0
283        ShowPageNumber  => 0,                   # (optional) default 1
284        LogoFile        => '/path/to/file.jpg', # (optional) you can use jpg, gif and png-Images
285        HeaderRight     => 'Header Right Text', # (optional)
286        HeadlineLeft    => 'Headline Text',     # (optional)
287        HeadlineRight   => 'Headline Text',     # (optional)
288        FooterLeft      => 'Footer Left Text',  # (optional)
289        FooterRight     => 'Footer Right Text', # (optional)
290    );
291
292=cut
293
294sub PageNew {
295    my ( $Self, %Param ) = @_;
296
297    if ( !$Self->{PDF} ) {
298        $Kernel::OM->Get('Kernel::System::Log')->Log(
299            Priority => 'error',
300            Message  => "Need a PDF Object!"
301        );
302        return;
303    }
304
305    my %Data = ();
306
307    # set new page width and height, if values are given
308    if ( $Param{Width} && $Param{Height} ) {
309        $Data{Width}  = $Param{Width};
310        $Data{Height} = $Param{Height};
311    }
312
313    # set new margin, if values are given
314    if ( $Param{MarginTop} && $Param{MarginRight} && $Param{MarginBottom} && $Param{MarginLeft} ) {
315        $Data{MarginTop}    = $Param{MarginTop};
316        $Data{MarginRight}  = $Param{MarginRight};
317        $Data{MarginBottom} = $Param{MarginBottom};
318        $Data{MarginLeft}   = $Param{MarginLeft};
319    }
320    if ( $Param{ShowPageNumber} ) {
321        $Data{ShowPageNumber} = $Param{ShowPageNumber};
322    }
323    if ( $Param{PageOrientation} ) {
324        $Data{PageOrientation} = $Param{PageOrientation};
325    }
326
327    # create a blank page
328    $Self->PageBlankNew(%Data);
329    if ( !$Self->{PDF} ) {
330        $Kernel::OM->Get('Kernel::System::Log')->Log(
331            Priority => 'error',
332            Message  => "Need a Page Object!"
333        );
334        return;
335    }
336
337    # set activ dimension
338    $Self->DimSet(
339        Dim => 'printable',
340    );
341
342    # get current printable dimension
343    my %Printable = $Self->_CurPrintableDimGet();
344
345    # get logofile
346    my $LogoFile = $Self->{Document}->{LogoFile}
347        || $Kernel::OM->Get('Kernel::Config')->Get('Home') . '/var/logo-otrs.png';
348
349    if (
350        defined( $Param{LogoFile} )
351        && -e $Param{LogoFile}
352        && (
353            $Param{LogoFile}    =~ /^.*\.gif$/i
354            || $Param{LogoFile} =~ /^.*\.jpg$/i
355            || $Param{LogoFile} =~ /^.*\.png$/i
356        )
357        )
358    {
359        $LogoFile = $Param{LogoFile};
360    }
361
362    # output the logo image at header left
363    $Self->Image(
364        File   => $LogoFile,
365        Width  => 700,
366        Height => 100,
367    );
368
369    if ( $Param{HeaderRight} ) {
370
371        # set new position
372        $Self->PositionSet(
373            Move => 'relativ',
374            X    => 168,
375            Y    => 15,
376        );
377
378        # output page header right
379        $Self->Text(
380            Text     => $Param{HeaderRight},
381            Type     => 'Cut',
382            Color    => '#404040',
383            FontSize => 12,
384            Height   => 12,
385            Align    => 'right',
386        );
387    }
388
389    # set new position
390    $Self->PositionSet(
391        X => 'left',
392        Y => 'top',
393    );
394
395    # set new position
396    $Self->PositionSet(
397        Move => 'relativ',
398        Y    => -29,
399    );
400
401    # output the lines in top of the page
402    $Self->HLine(
403        Color     => '#505050',
404        LineWidth => 0.5,
405    );
406
407    if ( $Param{FooterLeft} ) {
408
409        # set new position
410        $Self->PositionSet(
411            X => 'left',
412            Y => 'bottom',
413        );
414
415        # set new position
416        $Self->PositionSet(
417            Move => 'relativ',
418            Y    => 8,
419        );
420
421        # output page footer left
422        $Self->Text(
423            Text     => $Param{FooterLeft},
424            Width    => ( $Printable{Width} / 4 * 3 ),
425            Type     => 'Cut',
426            Color    => '#404040',
427            FontSize => 8,
428            Height   => 8,
429            Align    => 'left',
430        );
431    }
432
433    if ( $Param{FooterRight} ) {
434
435        # set new position
436        $Self->PositionSet(
437            X => 'left',
438            Y => 'bottom',
439        );
440
441        # set new position
442        $Self->PositionSet(
443            Move => 'relativ',
444            X    => ( $Printable{Width} / 4 * 3 ),
445            Y    => 8,
446        );
447
448        # output page footer right
449        $Self->Text(
450            Text     => $Param{FooterRight},
451            Type     => 'Cut',
452            Color    => '#404040',
453            FontSize => 8,
454            Height   => 8,
455            Align    => 'right',
456        );
457    }
458
459    # set new position
460    $Self->PositionSet(
461        X => 'left',
462        Y => 'bottom',
463    );
464
465    # set new position
466    $Self->PositionSet(
467        Move => 'relativ',
468        Y    => 11,
469    );
470
471    # output the lines in bottom of the page
472    $Self->HLine(
473        Color     => '#505050',
474        LineWidth => 0.5,
475    );
476
477    if ( $Param{HeadlineLeft} && $Param{HeadlineRight} ) {
478
479        # set new position
480        $Self->PositionSet(
481            X => 'left',
482            Y => 'top',
483        );
484
485        # set new position
486        $Self->PositionSet(
487            Move => 'relativ',
488            Y    => -44,
489        );
490        $Self->Text(
491            Text     => $Param{HeadlineLeft},
492            Width    => ( $Printable{Width} / 2 ),
493            Height   => 12,
494            Type     => 'Cut',
495            Font     => 'ProportionalBold',
496            FontSize => 12,
497        );
498        $Self->PositionSet(
499            X => 'left',
500            Y => 'top',
501        );
502        $Self->PositionSet(
503            Move => 'relativ',
504            X    => ( $Printable{Width} / 2 ),
505            Y    => -48,
506        );
507        $Self->Text(
508            Text     => $Param{HeadlineRight},
509            Height   => 8,
510            Type     => 'Cut',
511            Font     => 'Proportional',
512            FontSize => 8,
513            Color    => '#404040',
514            Align    => 'right',
515        );
516
517        # set new content dimension
518        $Self->_CurContentDimSet(
519            Top    => $Printable{Top} + 64,
520            Right  => $Printable{Right},
521            Bottom => $Printable{Bottom} + 16,
522            Left   => $Printable{Left},
523        );
524    }
525    else {
526
527        # set new content dimension
528        $Self->_CurContentDimSet(
529            Top    => $Printable{Top} + 34,
530            Right  => $Printable{Right},
531            Bottom => $Printable{Bottom} + 16,
532            Left   => $Printable{Left},
533        );
534    }
535
536    # set activ dimension
537    $Self->DimSet(
538        Dim => 'content',
539    );
540
541    return 1;
542}
543
544=head2 DocumentOutput()
545
546Return the PDF as string
547
548    $DocumentString = $PDFObject->DocumentOutput();
549
550=cut
551
552sub DocumentOutput {
553    my ( $Self, %Param ) = @_;
554
555    if ( !$Self->{PDF} ) {
556        $Kernel::OM->Get('Kernel::System::Log')->Log(
557            Priority => 'error',
558            Message  => "Need a PDF Object!"
559        );
560        return;
561    }
562    if ( !$Self->{Page} ) {
563        $Kernel::OM->Get('Kernel::System::Log')->Log(
564            Priority => 'error',
565            Message  => "Need a Page!"
566        );
567        return;
568    }
569
570    # return the document as string
571    my $DocumentString = $Self->{PDF}->stringify();
572    $Self->{PDF}->end();
573
574    return $DocumentString;
575}
576
577=head2 Table()
578
579Add a table.
580
581In case of missing or misused parameters, C<undef> is returned in scalar context
582and an empty list is returned in list context.
583
584    Return
585        $Return{State}
586        $Return{RequiredWidth}
587        $Return{RequiredHeight}
588        $Return{CellData}                # (reference) complete calculated
589        $Return{ColumnData}              # (reference) complete calculated
590
591    %Return = $PDFObject->Table(
592        CellData            => $CellData,    # 2D arrayref (see example)
593        ColumnData          => $ColumnData,  # arrayref (see example)
594        RowData             => $RowData,     # arrayref (see example)
595        Type                => 'Cut',        # (optional) default ReturnLeftOver (ReturnLeftOver|ReturnLeftOverHard|Cut)
596        Width               => 300,          # (optional) default maximal width
597        Height              => 400,          # (optional) default minimal height
598        Font                => 'Monospaced', # (optional) default Proportional (see DocumentNew())
599        FontSize            => 9,            # (optional) default 11
600        FontColor           => 'red',        # (optional) default black
601        FontColorEven       => 'blue',       # (optional) cell font color for even rows
602        FontColorOdd        => 'green',      # (optional) cell font color for odd rows
603        Align               => 'right',      # (optional) default left (left|center|right)
604        Lead                => 3,            # (optional) default 1
605        Padding             => 18,           # (optional) default 3
606        PaddingTop          => 10,           # (optional) top cell padding, overides Padding
607        PaddingRight        => 30,           # (optional) right cell padding, overides Padding
608        PaddingBottom       => 30,           # (optional) bottom cell padding, overides Padding
609        PaddingLeft         => 10,           # (optional) left cell padding, overides Padding
610        BackgroundColor     => '#101010',    # (optional) default white
611        BackgroundColorEven => '#F0F0F0',    # (optional) cell background color for even rows
612        BackgroundColorOdd  => '#A0A0A0',    # (optional) cell background color for odd rows
613        Border              => 1,            # (optional) default 1 (values between 0 and 20)
614        BorderColor         => '#FF0000',    # (optional) default black
615    );
616
617    $CellData = [
618        [
619            {
620                Content => "Cell 1 (Row 1, Column 1)",  # (optional)
621                Font => 'Monospaced',                   # (optional) (see DocumentNew())
622                FontSize => 13,                         # (optional)
623                FontColor => '#00FF00',                 # (optional)
624                Align => 'center',                      # (optional)
625                Lead => 7,                              # (optional)
626                BackgroundColor => '#101010',           # (optional)
627            },
628            {
629                Content => "Cell 2 (Row 1, Column 2)",
630            },
631        ],
632        [
633            {
634                Content => "Cell 3 (Row 2, Column 1)",
635            },
636            {
637                Content => "Cell 4 (Row 2, Column 2)",
638            },
639        ],
640    ];
641
642    $ColumData = [        # this array was automaticly generated, if not given
643        {
644            Width => 11,  # (optional)
645        },
646        {
647            Width => 44,
648        },
649    ];
650
651    $RowData = [           # this array was automaticly generated, if not given
652        {
653            Height => 11,  # (optional)
654        },
655        {
656            Height => 44,
657        },
658    ];
659
660=cut
661
662sub Table {
663    my ( $Self, %Param ) = @_;
664
665    # check needed stuff
666    for (qw(CellData)) {
667        if ( !defined( $Param{$_} ) ) {
668            $Kernel::OM->Get('Kernel::System::Log')->Log(
669                Priority => 'error',
670                Message  => "Need $_!"
671            );
672            $Param{State} = 1;
673            return;
674        }
675    }
676    if ( !$Self->{PDF} ) {
677        $Kernel::OM->Get('Kernel::System::Log')->Log(
678            Priority => 'error',
679            Message  => "Need a PDF Document!"
680        );
681        $Param{State} = 1;
682        return;
683    }
684    if ( !$Self->{Page} ) {
685        $Kernel::OM->Get('Kernel::System::Log')->Log(
686            Priority => 'error',
687            Message  => "Need a Page!"
688        );
689        $Param{State} = 1;
690        return;
691    }
692
693    my %Dim;
694
695    # get dimension (printable or content)
696    if ( $Self->DimGet() eq 'printable' ) {
697        %Dim = $Self->_CurPrintableDimGet();
698    }
699    else {
700        %Dim = $Self->_CurContentDimGet();
701    }
702
703    # get current position
704    my %Position = $Self->_CurPositionGet();
705
706    # set default values
707    $Param{ColumnData} ||= [];
708    $Param{RowData}    ||= [];
709
710    if (
711        ref( $Param{CellData} ) eq 'ARRAY'
712        && ref( $Param{ColumnData} ) eq 'ARRAY'
713        && ref( $Param{RowData} ) eq 'ARRAY'
714        )
715    {
716        if ( !defined( $Param{OutputCount} ) ) {
717
718            # set default values
719            $Param{Type} ||= 'ReturnLeftOver';
720            $Param{Font} ||= 'Proportional';
721            if ( !defined( $Param{FontSize} ) || $Param{FontSize} <= 0 ) {
722                $Param{FontSize} = 10;
723            }
724            if ( !defined( $Param{Lead} ) || $Param{Lead} < -( $Param{FontSize} ) ) {
725                $Param{Lead} = int( $Param{FontSize} / 4 );
726                if ( $Param{Lead} < 1 ) {
727                    $Param{Lead} = 1;
728                }
729            }
730            $Param{FontColor}     ||= 'black';
731            $Param{FontColorOdd}  ||= $Param{FontColor};
732            $Param{FontColorEven} ||= $Param{FontColor};
733
734            $Param{BackgroundColor}     ||= 'NULL';
735            $Param{BackgroundColorOdd}  ||= $Param{BackgroundColor};
736            $Param{BackgroundColorEven} ||= $Param{BackgroundColor};
737
738            $Param{Align} = $Param{Align} || 'left';
739
740            if ( !defined( $Param{Border} ) || $Param{Border} < 0 ) {
741                $Param{Border} = 1;
742            }
743            $Param{BorderColor}   ||= 'black';
744            $Param{PaddingTop}    ||= $Param{Padding} || 3;
745            $Param{PaddingRight}  ||= $Param{Padding} || 3;
746            $Param{PaddingBottom} ||= $Param{Padding} || 3;
747            $Param{PaddingLeft}   ||= $Param{Padding} || 3;
748
749            # check given Width
750            my $DefaultWidth = $Dim{Left} + $Dim{Width} - $Position{X};
751            if (
752                !defined( $Param{Width} )
753                || (
754                    $Param{Width}
755                    - $Param{PaddingLeft}
756                    - $Param{PaddingRight}
757                    - ( 2 * $Param{Border} )
758                )
759                < 0
760                || $Param{Width} > $DefaultWidth
761                )
762            {
763                $Param{Width} = $DefaultWidth;
764            }
765
766            # set output count
767            $Param{OutputCount} = 0;
768
769            # set state
770            $Param{State} = 0;
771
772            # calculate required table attributes
773            $Self->_TableCalculate( %Param, );
774        }
775
776        # check given Height
777        my $DefaultHeight = $Position{Y} - $Dim{Bottom};
778        if (
779            !defined( $Param{Height} )
780            || (
781                $Param{Height}
782                - $Param{PaddingTop}
783                - $Param{PaddingBottom}
784                - ( 2 * $Param{Border} )
785            )
786            < 0
787            || $Param{Height} > $DefaultHeight
788            )
789        {
790            $Param{Height} = $DefaultHeight;
791        }
792
793        # get maximum number of pages
794        my $MaxPages = $Kernel::OM->Get('Kernel::Config')->Get('PDF::MaxPages');
795
796        if ( !$MaxPages || $MaxPages < 1 || $MaxPages > 1000 ) {
797            $MaxPages = 100;
798        }
799
800        # infinite loop protection
801        if ( $Param{OutputCount} < $MaxPages ) {
802            my %Block = $Self->_TableBlockNextCalculate(
803                CellData   => $Param{CellData},
804                ColumnData => $Param{ColumnData},
805            );
806
807            # if active cells found
808            if ( $Block{State} ) {
809
810                # start row output
811                my $Row        = $Block{ReturnRowStart};
812                my $RowCounter = 0;
813                my $RowLoop    = 1;
814                my $LastBlock  = $Param{ColumnData}->[ $#{ $Param{ColumnData} } ]->{Block};
815                my $LastRow    = $#{ $Param{RowData} };
816
817                while ($RowLoop) {
818
819                    # stop loop, if last row
820                    if ( $Row <= $LastRow ) {
821
822                        # calculate row height, if block is 0
823                        if ( !$Block{ReturnBlock} ) {
824                            $Self->_TableRowCalculate(
825                                Row => $Row,
826                                %Param,
827                            );
828                        }
829
830                        # save old position
831                        my %PositionOld = %Position;
832                        if (
833                            $Param{RowData}->[$Row]->{OutputHeight}
834                            && $Param{RowData}->[$Row]->{OutputHeight} <= $Position{Y} - $Dim{Bottom}
835                            )
836                        {
837                            for ( $Block{ReturnColumnStart} .. $Block{ReturnColumnStop} ) {
838                                my $Column = $_;
839                                $Self->_TableCellOutput(
840                                    Text          => $Param{CellData}->[$Row]->[$Column]->{Content},
841                                    Type          => $Param{CellData}->[$Row]->[$Column]->{Type},
842                                    Width         => $Param{ColumnData}->[$Column]->{OutputWidth},
843                                    Height        => $Param{RowData}->[$Row]->{OutputHeight},
844                                    Font          => $Param{CellData}->[$Row]->[$Column]->{Font},
845                                    FontSize      => $Param{CellData}->[$Row]->[$Column]->{FontSize},
846                                    FontColor     => $Param{CellData}->[$Row]->[$Column]->{FontColor},
847                                    Align         => $Param{CellData}->[$Row]->[$Column]->{Align},
848                                    Lead          => $Param{CellData}->[$Row]->[$Column]->{Lead},
849                                    PaddingTop    => $Param{PaddingTop},
850                                    PaddingRight  => $Param{PaddingRight},
851                                    PaddingBottom => $Param{PaddingBottom},
852                                    PaddingLeft   => $Param{PaddingLeft},
853                                    BackgroundColor =>
854                                        $Param{CellData}->[$Row]->[$Column]->{BackgroundColor},
855                                    Border      => $Param{Border},
856                                    BorderColor => $Param{BorderColor},
857                                );
858
859                                # deactivate cell and delete content
860                                $Param{CellData}->[$Row]->[$Column]->{Off}     = 1;
861                                $Param{CellData}->[$Row]->[$Column]->{Content} = ' ';
862
863                                # set new position
864                                $Self->_CurPositionSet(
865                                    X => $Position{X}
866                                        + $Param{ColumnData}->[$Column]->{OutputWidth}
867                                        - $Param{Border},
868                                    Y => $Position{Y},
869                                );
870
871                                # get current position
872                                %Position = $Self->_CurPositionGet();
873                            }
874
875                            # set new position
876                            $Self->_CurPositionSet(
877                                X => $PositionOld{X},
878                                Y => $PositionOld{Y}
879                                    - $Param{RowData}->[$Row]->{OutputHeight}
880                                    + $Param{Border},
881                            );
882
883                            # get current position
884                            %Position = $Self->_CurPositionGet();
885                        }
886                        else {
887                            my $NewOutputHeight = $Position{Y} - $Dim{Bottom};
888                            my $NewTextHeight   = $NewOutputHeight
889                                - $Param{PaddingTop}
890                                - $Param{PaddingBottom}
891                                - ( 2 * $Param{Border} );
892
893                            if ( $NewTextHeight > $Param{RowData}->[$Row]->{MinFontSize} ) {
894                                for ( $Block{ReturnColumnStart} .. $Block{ReturnColumnStop} ) {
895                                    my $Column = $_;
896                                    my $Type   = 'ReturnLeftOver';
897                                    if (
898                                        $Param{CellData}->[$Row]->[$Column]->{Type} eq
899                                        'ReturnLeftOverHard'
900                                        )
901                                    {
902                                        $Type = 'ReturnLeftOverHard';
903                                    }
904                                    my %Return = $Self->_TableCellOutput(
905                                        Text     => $Param{CellData}->[$Row]->[$Column]->{Content},
906                                        Type     => $Type,
907                                        Width    => $Param{ColumnData}->[$Column]->{OutputWidth},
908                                        Height   => $NewOutputHeight,
909                                        Font     => $Param{CellData}->[$Row]->[$Column]->{Font},
910                                        FontSize => $Param{CellData}->[$Row]->[$Column]->{FontSize},
911                                        FontColor =>
912                                            $Param{CellData}->[$Row]->[$Column]->{FontColor},
913                                        Align         => $Param{CellData}->[$Row]->[$Column]->{Align},
914                                        Lead          => $Param{CellData}->[$Row]->[$Column]->{Lead},
915                                        PaddingTop    => $Param{PaddingTop},
916                                        PaddingRight  => $Param{PaddingRight},
917                                        PaddingBottom => $Param{PaddingBottom},
918                                        PaddingLeft   => $Param{PaddingLeft},
919                                        BackgroundColor =>
920                                            $Param{CellData}->[$Row]->[$Column]->{BackgroundColor},
921                                        Border      => $Param{Border},
922                                        BorderColor => $Param{BorderColor},
923                                    );
924
925                                    # set new content
926                                    if ( !$Return{State} ) {
927                                        $Param{CellData}->[$Row]->[$Column]->{Content} = $Return{LeftOver};
928                                    }
929                                    else {
930                                        $Param{CellData}->[$Row]->[$Column]->{Content} = ' ';
931                                    }
932
933                                    # correcting content
934                                    if ( $Param{CellData}->[$Row]->[$Column]->{Content} eq '' ) {
935                                        $Param{CellData}->[$Row]->[$Column]->{Content} = ' ';
936                                    }
937                                    $Param{CellData}->[$Row]->[$Column]->{TmpOff} = 1;
938
939                                    # recalculate height
940                                    if (
941                                        $Block{ReturnBlock} eq $LastBlock
942                                        && $Column eq $Block{ReturnColumnStop}
943                                        )
944                                    {
945
946                                        # if Height was given
947                                        if ( $Param{RowData}->[$Row]->{Height} > 0 ) {
948                                            $Param{RowData}->[$Row]->{Height} -= $NewTextHeight;
949
950                                            # if rest too small, deactivate all cells of this row
951                                            if (
952                                                $Param{RowData}->[$Row]->{Height}
953                                                < $Param{RowData}->[$Row]->{MinFontSize}
954                                                )
955                                            {
956                                                for my $CellOff ( @{ $Param{CellData}->[$Row] } ) {
957                                                    $CellOff->{Content} = ' ';
958                                                    $CellOff->{Off}     = 1;
959                                                    $CellOff->{Tmp}     = 0;
960                                                }
961                                            }
962                                        }
963                                        $Self->_TableRowCalculate(
964                                            Row => $Row,
965                                            %Param,
966                                        );
967                                    }
968
969                                    # set new position
970                                    $Self->_CurPositionSet(
971                                        X => $Position{X}
972                                            + $Param{ColumnData}->[$Column]->{OutputWidth}
973                                            - $Param{Border},
974                                        Y => $Position{Y},
975                                    );
976
977                                    # get current position
978                                    %Position = $Self->_CurPositionGet();
979                                }
980                            }
981                            $RowLoop = 0;
982                        }
983                    }
984                    else {
985                        $RowLoop = 0;
986                    }
987
988                    if ( $RowCounter > 100 ) {
989                        $Kernel::OM->Get('Kernel::System::Log')->Log(
990                            Priority => 'error',
991                            Message =>
992                                "Too much row loops on page! Infinite Loop protection. Table Output aborted."
993                        );
994                        $RowLoop = 0;
995                    }
996
997                    # increment Row and RowCounter
998                    $Row++;
999                    $RowCounter++;
1000                }
1001            }
1002            else {
1003                $Kernel::OM->Get('Kernel::System::Log')->Log(
1004                    Priority => 'error',
1005                    Message  => "No active cells! Table Output aborted."
1006                );
1007                $Param{State} = 1;
1008            }
1009        }
1010        else {
1011            $Kernel::OM->Get('Kernel::System::Log')->Log(
1012                Priority => 'error',
1013                Message  => "Too much loops! Infinite Loop protection. Table Output aborted."
1014            );
1015            $Param{State} = 1;
1016        }
1017    }
1018    else {
1019        $Kernel::OM->Get('Kernel::System::Log')->Log(
1020            Priority => 'error',
1021            Message =>
1022                "Need array references of CellData, ColumnData and RowData! Table Output aborted."
1023        );
1024        $Param{State} = 1;
1025    }
1026
1027    # count remaining cells
1028    my $RemainingCells = $Self->_TableCellOnCount(
1029        CellData => $Param{CellData},
1030    );
1031
1032    # set state
1033    if ( !$RemainingCells ) {
1034        $Param{State} = 1;
1035    }
1036
1037    $Param{OutputCount}++;
1038
1039    return %Param;
1040}
1041
1042=head2 Text()
1043
1044Output a text line
1045
1046    Return
1047        $Return{State}
1048        $Return{RequiredWidth}
1049        $Return{RequiredHeight}
1050        $Return{LeftOver}
1051
1052    %Return = $PDFObject->Text(
1053        Text     => 'Text',              # Text
1054        Width    => 300,                 # (optional) available width of textblock
1055        Height   => 200,                 # (optional) available height of textblock
1056        Type     => 'Cut',               # (optional) default ReturnLeftOver (ReturnLeftOver|ReturnLeftOverHard|Cut)
1057        Font     => 'ProportionalBold',  # (optional) default Proportional  (see DocumentNew())
1058        FontSize => 15,                  # (optional) default 10
1059        Color    => '#FF0000',           # (optional) default #000000
1060        Align    => 'center',            # (optional) default left (left|center|right)
1061        Lead     => 20,                  # (optional) default 1 distance between lines
1062    );
1063
1064=cut
1065
1066sub Text {
1067    my ( $Self, %Param ) = @_;
1068
1069    # check needed stuff
1070    for (qw(Text)) {
1071        if ( !defined( $Param{$_} ) ) {
1072            $Kernel::OM->Get('Kernel::System::Log')->Log(
1073                Priority => 'error',
1074                Message  => "Need $_!"
1075            );
1076            return;
1077        }
1078    }
1079    if ( !$Self->{PDF} ) {
1080        $Kernel::OM->Get('Kernel::System::Log')->Log(
1081            Priority => 'error',
1082            Message  => "Need a PDF Document!"
1083        );
1084        return;
1085    }
1086    if ( !$Self->{Page} ) {
1087        $Kernel::OM->Get('Kernel::System::Log')->Log(
1088            Priority => 'error',
1089            Message  => "Need a Page!"
1090        );
1091        return;
1092    }
1093
1094    my %Dim;
1095
1096    # get dimension (printable or content)
1097    if ( $Self->DimGet() eq 'printable' ) {
1098        %Dim = $Self->_CurPrintableDimGet();
1099    }
1100    else {
1101        %Dim = $Self->_CurContentDimGet();
1102    }
1103
1104    # get current position
1105    my %Position = $Self->_CurPositionGet();
1106
1107    $Param{Type}  = $Param{Type}  || 'ReturnLeftOver';
1108    $Param{Color} = $Param{Color} || 'black';
1109    $Param{Font}  = $Param{Font}  || 'Proportional';
1110    $Param{Align} = $Param{Align} || 'left';
1111
1112    if ( !defined( $Param{FontSize} ) || $Param{FontSize} <= 0 ) {
1113        $Param{FontSize} = 10;
1114    }
1115    if ( !defined( $Param{Lead} ) || $Param{Lead} < -( $Param{FontSize} ) ) {
1116        $Param{Lead} = int( $Param{FontSize} / 4 );
1117        if ( $Param{Lead} < 1 ) {
1118            $Param{Lead} = 1;
1119        }
1120    }
1121
1122    # check Width
1123    if (
1124        !defined( $Param{Width} )
1125        || $Param{Width} < 0
1126        || ( $Position{X} + $Param{Width} ) >= ( $Dim{Left} + $Dim{Width} )
1127        )
1128    {
1129        $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X};
1130    }
1131
1132    # check Height
1133    if (
1134        !defined( $Param{Height} )
1135        || $Param{Height} < 0
1136        || ( $Position{Y} - $Param{Height} ) < $Dim{Bottom}
1137        )
1138    {
1139        $Param{Height} = $Position{Y} - $Dim{Bottom};
1140    }
1141
1142    # calculate the given text
1143    my %Return = $Self->_TextCalculate(
1144        Text     => $Param{Text},
1145        Type     => $Param{Type},
1146        Width    => $Param{Width},
1147        Height   => $Param{Height},
1148        Font     => $Param{Font},
1149        FontSize => $Param{FontSize},
1150        Lead     => $Param{Lead},
1151    );
1152
1153    if ( $Return{LeftOver} ne $Param{Text} ) {
1154
1155        # create a text object
1156        my $Text = $Self->{Page}->text();
1157
1158        # set font and fontsize
1159        $Text->font( $Self->{Font}->{ $Param{Font} }, $Param{FontSize} );
1160
1161        # set fontcolor
1162        $Text->fillcolor( $Param{Color} );
1163
1164        # save original X position
1165        my $PositionX = $Position{X};
1166
1167        my $Counter1 = 0;
1168        for my $Row ( @{ $Return{PossibleRows} } ) {
1169
1170            # calculate width of row
1171            my $RowWidth = $Self->_StringWidth(
1172                Text     => $Row,
1173                Font     => $Param{Font},
1174                FontSize => $Param{FontSize},
1175            );
1176
1177            if ( $Param{Align} eq 'right' ) {
1178
1179                # set new position
1180                $Self->_CurPositionSet(
1181                    X => $PositionX + $Param{Width} - $RowWidth,
1182                );
1183            }
1184            elsif ( $Param{Align} eq 'center' ) {
1185
1186                # set new position
1187                $Self->_CurPositionSet(
1188                    X => $PositionX + ( ( $Param{Width} - $RowWidth ) / 2 ),
1189                );
1190            }
1191
1192            # set new position
1193            if ( $Counter1 > 0 ) {
1194                $Self->_CurPositionSet(
1195                    Y => $Position{Y} - $Param{FontSize} - $Param{Lead},
1196                );
1197            }
1198            else {
1199                $Self->_CurPositionSet(
1200                    Y => $Position{Y} - $Param{FontSize},
1201                );
1202            }
1203
1204            # get current position
1205            %Position = $Self->_CurPositionGet();
1206
1207            # get to position
1208            $Text->translate( $Position{X}, $Position{Y} );
1209
1210            # output text
1211            $Text->text($Row);
1212
1213            $Counter1++;
1214        }
1215
1216        # set new position
1217        $Self->_CurPositionSet(
1218            X => $PositionX,
1219        );
1220    }
1221
1222    return %Return;
1223}
1224
1225=head2 Image()
1226
1227Output a image
1228
1229    $True = $PDFObject->Image(
1230        File   => '/path/image.gif',  # (gif|jpg|png)
1231        Type   => 'ReturnFalse'       # (optional) default Reduce (ReturnFalse|Reduce)
1232        Width  => 300,                # width of image
1233        Height => 150,                # height of image
1234    );
1235
1236=cut
1237
1238sub Image {
1239    my ( $Self, %Param ) = @_;
1240
1241    # check needed stuff
1242    for (qw(File Width Height)) {
1243        if ( !defined( $Param{$_} ) ) {
1244            $Kernel::OM->Get('Kernel::System::Log')->Log(
1245                Priority => 'error',
1246                Message  => "Need $_!"
1247            );
1248            return;
1249        }
1250    }
1251    if ( !$Self->{PDF} ) {
1252        $Kernel::OM->Get('Kernel::System::Log')->Log(
1253            Priority => 'error',
1254            Message  => "Need a PDF Document!"
1255        );
1256        return;
1257    }
1258    if ( !$Self->{Page} ) {
1259        $Kernel::OM->Get('Kernel::System::Log')->Log(
1260            Priority => 'error',
1261            Message  => "Need a Page!"
1262        );
1263        return;
1264    }
1265    if ( !-e $Param{File} ) {
1266        $Kernel::OM->Get('Kernel::System::Log')->Log(
1267            Priority => 'error',
1268            Message  => "File $Param{File} not found!"
1269        );
1270        return;
1271    }
1272
1273    my %Dim;
1274
1275    # get dimension (printable or content)
1276    if ( $Self->DimGet() eq 'printable' ) {
1277        %Dim = $Self->_CurPrintableDimGet();
1278    }
1279    else {
1280        %Dim = $Self->_CurContentDimGet();
1281    }
1282
1283    $Param{Width}  = $Param{Width} / ( 300 / 72 );
1284    $Param{Height} = $Param{Height} / ( 300 / 72 );
1285
1286    my $Image = $Self->{Page}->gfx();
1287    my $ImageFile;
1288
1289    # if image already used, use the existing image object
1290    if ( defined( $Self->{CacheImageObject}->{ $Param{File} } ) ) {
1291        $ImageFile = $Self->{CacheImageObject}->{ $Param{File} };
1292    }
1293    else {
1294        if ( $Param{File} =~ /^.*\.gif$/i ) {
1295            $ImageFile = $Self->{PDF}->image_gif( $Param{File} );
1296        }
1297        elsif ( $Param{File} =~ /^.*\.jpg$/i ) {
1298            $ImageFile = $Self->{PDF}->image_jpeg( $Param{File} );
1299        }
1300        elsif ( $Param{File} =~ /^.*\.png$/i ) {
1301            $ImageFile = $Self->{PDF}->image_png( $Param{File} );
1302        }
1303        else {
1304            $Kernel::OM->Get('Kernel::System::Log')->Log(
1305                Priority => 'error',
1306                Message  => "Imagetype of File $Param{File} not supported",
1307            );
1308            return;
1309        }
1310
1311        # cache image object
1312        $Self->{CacheImageObject}->{ $Param{File} } = $ImageFile;
1313    }
1314
1315    # get current position
1316    my %Position = $Self->_CurPositionGet();
1317
1318    my $Reduce = 0;
1319
1320    # check values
1321    if ( ( $Position{X} + $Param{Width} ) >= ( $Dim{Left} + $Dim{Width} ) ) {
1322        $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X};
1323        $Reduce = 1;
1324    }
1325    if ( $Param{Width} < 1 ) {
1326        $Param{Width} = 1;
1327    }
1328
1329    if ( ( $Position{Y} - $Param{Height} ) <= $Dim{Bottom} ) {
1330        $Param{Height} = $Position{Y} - $Dim{Bottom};
1331        $Reduce = 1;
1332    }
1333    if ( $Param{Height} < 1 ) {
1334        $Param{Height} = 1;
1335    }
1336
1337    my $Return = 1;
1338
1339    if ( defined( $Param{Type} ) && $Param{Type} eq 'ReturnFalse' && $Reduce ) {
1340        $Return = 0;
1341    }
1342    else {
1343
1344        # output the image
1345        $Image->image(
1346            $ImageFile, $Position{X}, $Position{Y} - $Param{Height},
1347            $Param{Width}, $Param{Height},
1348        );
1349
1350        # set new position
1351        $Self->_CurPositionSet(
1352            Y => $Position{Y} - $Param{Height},
1353        );
1354    }
1355
1356    return $Return;
1357}
1358
1359=head2 HLine()
1360
1361Output a horizontal line
1362
1363    $True = $PDFObject->HLine(
1364        Width     => 300,           # (optional) default 'end of printable dimension'
1365        Type      => 'ReturnFalse'  # (optional) default Cut (ReturnFalse|Cut)
1366        Color     => '#101010',     # (optional) default black
1367        LineWidth => 1,             # (optional) default 1
1368    );
1369
1370=cut
1371
1372sub HLine {
1373    my ( $Self, %Param ) = @_;
1374
1375    if ( !$Self->{PDF} ) {
1376        $Kernel::OM->Get('Kernel::System::Log')->Log(
1377            Priority => 'error',
1378            Message  => "Need a PDF Document!",
1379        );
1380        return;
1381    }
1382    if ( !$Self->{Page} ) {
1383        $Kernel::OM->Get('Kernel::System::Log')->Log(
1384            Priority => 'error',
1385            Message  => "Need a Page!",
1386        );
1387        return;
1388    }
1389
1390    my %Dim;
1391
1392    # get current position
1393    my %Position = $Self->_CurPositionGet();
1394
1395    # get dimension (printable or content)
1396    if ( $Self->DimGet() eq 'printable' ) {
1397        %Dim = $Self->_CurPrintableDimGet();
1398    }
1399    else {
1400        %Dim = $Self->_CurContentDimGet();
1401    }
1402
1403    # set default color
1404    $Param{Color} = $Param{Color} || 'black';
1405
1406    # check LineWidth
1407    if ( !defined( $Param{LineWidth} ) || $Param{LineWidth} <= 0 || $Param{LineWidth} > 100 ) {
1408        $Param{LineWidth} = 1;
1409    }
1410
1411    my $Cut = 0;
1412
1413    if ( $Position{Y} - $Param{LineWidth} < $Dim{Bottom} ) {
1414        $Param{LineWidth} = $Position{Y} - $Dim{Bottom};
1415        if ( $Param{LineWidth} < 1 ) {
1416            $Param{LineWidth} = 1;
1417        }
1418        $Cut = 1;
1419    }
1420    $Param{LineWidth} = 0 - $Param{LineWidth};
1421
1422    # check Width
1423    if ( defined( $Param{Width} ) && $Param{Width} >= 1 ) {
1424        if ( $Position{X} + $Param{Width} > $Dim{Left} + $Dim{Width} ) {
1425            $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X};
1426            $Cut = 1;
1427        }
1428    }
1429    else {
1430        $Param{Width} = $Param{Width} = $Dim{Left} + $Dim{Width} - $Position{X};
1431    }
1432
1433    # output the lines in top and bottom of the page
1434    my $Line = $Self->{Page}->gfx();
1435    $Line->fillcolor( $Param{Color} );
1436
1437    # check values
1438    my $Output = 0;
1439    if (
1440        $Self->DimGet() eq 'printable'
1441        && $Self->_CurPrintableDimCheck(
1442            X => $Position{X},
1443            Y => $Position{Y}
1444        )
1445        && $Self->_CurPrintableDimCheck(
1446            X => $Position{X} + $Param{Width},
1447            Y => $Position{Y} - $Param{LineWidth}
1448        )
1449        )
1450    {
1451        $Output = 1;
1452    }
1453    elsif (
1454        $Self->_CurContentDimCheck(
1455            X => $Position{X},
1456            Y => $Position{Y}
1457        )
1458        && $Self->_CurContentDimCheck(
1459            X => $Position{X} + $Param{Width},
1460            Y => $Position{Y} - $Param{LineWidth}
1461        )
1462        )
1463    {
1464        $Output = 1;
1465    }
1466
1467    if ( defined( $Param{Type} ) && $Param{Type} eq 'ReturnFalse' && $Cut ) {
1468        $Output = 1;
1469    }
1470
1471    if ($Output) {
1472
1473        # output line
1474        $Line->rect( $Position{X}, $Position{Y}, $Param{Width}, $Param{LineWidth} );
1475        $Line->fill();
1476
1477        # set new position
1478        $Self->_CurPositionSet(
1479            Y => $Position{Y} - $Param{LineWidth},
1480        );
1481    }
1482
1483    return $Output;
1484}
1485
1486=head2 PositionSet()
1487
1488Set new position on current page
1489
1490    $True = $PDFObject->PositionSet(
1491        Move => 'absolut',  # (optional) default absolut (absolut|relativ)
1492        X    => 10,         # (optional) (<integer>|left|center|right)
1493        Y    => 20,         # (optional) (<integer>|top|middle|bottom)
1494    );
1495
1496=cut
1497
1498sub PositionSet {
1499    my ( $Self, %Param ) = @_;
1500
1501    if ( !$Self->{PDF} ) {
1502        $Kernel::OM->Get('Kernel::System::Log')->Log(
1503            Priority => 'error',
1504            Message  => "Need a PDF Document!",
1505        );
1506        return;
1507    }
1508    if ( !$Self->{Page} ) {
1509        $Kernel::OM->Get('Kernel::System::Log')->Log(
1510            Priority => 'error',
1511            Message  => "Need a Page!",
1512        );
1513        return;
1514    }
1515
1516    my %Data;
1517    my %Dim;
1518    my %Position = $Self->_CurPositionGet();
1519
1520    # get dimension (printable or content)
1521    if ( $Self->DimGet() eq 'printable' ) {
1522        $Data{Dim} = 'printable';
1523        %Dim = $Self->_CurPrintableDimGet();
1524    }
1525    else {
1526        $Data{Dim} = 'content';
1527        %Dim = $Self->_CurContentDimGet();
1528    }
1529
1530    if ( defined( $Param{X} ) ) {
1531        if ( $Param{X} eq 'left' ) {
1532            $Data{X} = $Dim{Left};
1533        }
1534        elsif ( $Param{X} eq 'center' ) {
1535            $Data{X} = ( $Dim{Width} / 2 ) + $Dim{Left};
1536        }
1537        elsif ( $Param{X} eq 'right' ) {
1538            $Data{X} = $Dim{Left} + $Dim{Width};
1539        }
1540        else {
1541            if ( defined( $Param{Move} ) && $Param{Move} eq 'relativ' ) {
1542                if (
1543                    ( $Position{X} + $Param{X} )
1544                    >= $Dim{Left}
1545                    && ( $Position{X} + $Param{X} ) < ( $Dim{Left} + $Dim{Width} )
1546                    )
1547                {
1548                    $Data{X} = $Position{X} + $Param{X};
1549                }
1550                elsif ( ( $Position{X} + $Param{X} ) >= ( $Dim{Left} + $Dim{Width} ) ) {
1551                    $Data{X} = $Dim{Left} + $Dim{Width};
1552                }
1553                else {
1554                    $Data{X} = $Dim{Left};
1555                }
1556            }
1557            else {
1558                if ( $Param{X} >= $Dim{Left} && $Param{X} < ( $Dim{Left} + $Dim{Width} ) ) {
1559                    $Data{X} = $Param{X};
1560                }
1561                elsif ( $Param{X} >= ( $Dim{Left} + $Dim{Width} ) ) {
1562                    $Data{X} = $Dim{Left} + $Dim{Width};
1563                }
1564                else {
1565                    $Data{X} = $Dim{Left};
1566                }
1567            }
1568        }
1569    }
1570
1571    if ( defined( $Param{Y} ) ) {
1572        if ( $Param{Y} eq 'top' ) {
1573            $Data{Y} = $Dim{Bottom} + $Dim{Height};
1574        }
1575        elsif ( $Param{Y} eq 'middle' ) {
1576            $Data{Y} = ( $Dim{Height} / 2 ) + $Dim{Bottom};
1577        }
1578        elsif ( $Param{Y} eq 'bottom' ) {
1579            $Data{Y} = $Dim{Bottom};
1580        }
1581        else {
1582            if ( defined( $Param{Move} ) && $Param{Move} eq 'relativ' ) {
1583                if (
1584                    ( $Position{Y} + $Param{Y} )
1585                    <= ( $Dim{Bottom} + $Dim{Height} )
1586                    && ( $Position{Y} + $Param{Y} ) > $Dim{Bottom}
1587                    )
1588                {
1589                    $Data{Y} = $Position{Y} + $Param{Y};
1590                }
1591                elsif ( ( $Position{Y} + $Param{Y} ) <= $Dim{Bottom} ) {
1592                    $Data{Y} = $Dim{Bottom};
1593                }
1594                else {
1595                    $Data{Y} = $Dim{Bottom} + $Dim{Height};
1596                }
1597            }
1598            else {
1599                if ( $Param{Y} > $Dim{Bottom} && $Param{Y} <= ( $Dim{Bottom} + $Dim{Height} ) ) {
1600                    $Data{Y} = $Param{Y};
1601                }
1602                elsif ( $Param{Y} <= $Dim{Bottom} ) {
1603                    $Data{Y} = $Dim{Bottom};
1604                }
1605                else {
1606                    $Data{Y} = $Dim{Bottom} + $Dim{Height};
1607                }
1608            }
1609        }
1610    }
1611
1612    $Self->_CurPositionSet( %Data, );
1613
1614    return 1;
1615}
1616
1617=head2 PositionGet()
1618
1619Get position on current page
1620
1621    Return
1622        $Position{X}
1623        $Position{Y}
1624
1625    %Position = $PDFObject->PositionGet();
1626
1627=cut
1628
1629sub PositionGet {
1630    my ( $Self, %Param ) = @_;
1631
1632    if ( !$Self->{PDF} ) {
1633        $Kernel::OM->Get('Kernel::System::Log')->Log(
1634            Priority => 'error',
1635            Message  => "Need a PDF Document!",
1636        );
1637        return;
1638    }
1639    if ( !$Self->{Page} ) {
1640        $Kernel::OM->Get('Kernel::System::Log')->Log(
1641            Priority => 'error',
1642            Message  => "Need a Page!",
1643        );
1644        return;
1645    }
1646
1647    my %Position = $Self->_CurPositionGet();
1648
1649    return %Position;
1650}
1651
1652=head2 DimSet()
1653
1654Set active dimension
1655
1656    $Dim = $PDFObject->DimSet(
1657        Dim => 'printable',  # (optional) default content (content|printable)
1658    );
1659
1660=cut
1661
1662sub DimSet {
1663    my ( $Self, %Param ) = @_;
1664
1665    if ( !$Self->{PDF} ) {
1666        $Kernel::OM->Get('Kernel::System::Log')->Log(
1667            Priority => 'error',
1668            Message  => "Need a PDF Document!",
1669        );
1670        return;
1671    }
1672    if ( !$Self->{Page} ) {
1673        $Kernel::OM->Get('Kernel::System::Log')->Log(
1674            Priority => 'error',
1675            Message  => "Need a Page!",
1676        );
1677        return;
1678    }
1679
1680    if ( defined( $Param{Dim} ) && $Param{Dim} eq 'printable' ) {
1681        $Self->{Current}->{Dim} = 'printable';
1682    }
1683    else {
1684        $Self->{Current}->{Dim} = 'content';
1685    }
1686
1687    return $Self->{Current}->{Dim};
1688}
1689
1690=head2 DimGet()
1691
1692Get active dimension (printable or content)
1693
1694    $Dim = $PDFObject->DimGet();
1695
1696=cut
1697
1698sub DimGet {
1699    my ( $Self, %Param ) = @_;
1700
1701    if ( !$Self->{PDF} ) {
1702        $Kernel::OM->Get('Kernel::System::Log')->Log(
1703            Priority => 'error',
1704            Message  => "Need a PDF Document!"
1705        );
1706        return;
1707    }
1708    if ( !$Self->{Page} ) {
1709        $Kernel::OM->Get('Kernel::System::Log')->Log(
1710            Priority => 'error',
1711            Message  => "Need a Page!"
1712        );
1713        return;
1714    }
1715
1716    if ( $Self->{Current}->{Dim} eq 'printable' || $Self->{Current}->{Dim} eq 'content' ) {
1717        $Self->{Current}->{Dim} = 'content';
1718    }
1719
1720    return $Self->{Current}->{Dim};
1721}
1722
1723=begin Internal:
1724
1725=head2 _TableCalculate()
1726
1727calculate params of table.
1728
1729    Return  # normally no return required, only references
1730        %Param
1731
1732The returned hash is usually not needed, as the passed in references are
1733modified in place.
1734In case of missing or misused parameters, C<undef> is returned in scalar context
1735and an empty list is returned in list context.
1736
1737    %Return = $PDFObject->_TableCalculate(
1738        CellData            => $CellData,     # 2D arrayref (see example)
1739        ColumnData          => $ColumnData,   # arrayref (see example)
1740        RowData             => $RowData,      # arrayref (see example)
1741        Width               => 300,           # (optional) default default maximal width
1742        Height              => 400,           # (optional) default minimal height
1743        Font                => 'Monospaced',  # (optional) default Proportional (see DocumentNew())
1744        FontSize            => 9,             # (optional) default 11
1745        FontColor           => 'red',         # (optional) default black
1746        FontColorEven       => 'blue',        # (optional) cell font color for even rows
1747        FontColorOdd        => 'green',       # (optional) cell font color for odd rows
1748        Align               => 'right',       # (optional) default left (left|center|right)
1749        Lead                => 3,             # (optional) default 1
1750        PaddingTop          => 10,            # (optional) top cell padding, overides Padding
1751        PaddingRight        => 30,            # (optional) right cell padding, overides Padding
1752        PaddingBottom       => 30,            # (optional) bottom cell padding, overides Padding
1753        PaddingLeft         => 10,            # (optional) left cell padding, overides Padding
1754        BackgroundColor     => '#101010',     # (optional) default white
1755        BackgroundColorEven => '#F0F0F0',     # (optional) cell background color for even rows
1756        BackgroundColorOdd  => '#A0A0A0',     # (optional) cell background color for odd rows
1757        Border              => 1,             # (optional) default 1 (values between 0 and 20)
1758        BorderColor         => '#FF0000',     # (optional) default black
1759    );
1760
1761    $CellData = [
1762        [
1763            {
1764                Content         => "Cell 1 (Row 1, Column 1)",  # (optional)
1765                Font            => 'Monospaced',                # (optional)
1766                FontSize        => 13,                          # (optional)
1767                FontColor       => '#00FF00',                   # (optional)
1768                Align           => 'center',                    # (optional)
1769                Lead            => 7,                           # (optional)
1770                BackgroundColor => '#101010',                   # (optional)
1771            },
1772            {
1773                Content => "Cell 2 (Row 1, Column 2)",
1774            },
1775        ],
1776        [
1777            {
1778                Content => "Cell 3 (Row 2, Column 1)",
1779            },
1780            {
1781                Content => "Cell 4 (Row 2, Column 2)",
1782            },
1783        ],
1784    ];
1785
1786    $ColumData = [        # this array was automaticly generated, if not given
1787        {
1788            Width => 11,  # (optional)
1789        },
1790        {
1791            Width => 44,
1792        },
1793    ];
1794
1795    $RowData = [           # this array was automaticly generated, if not given
1796        {
1797            Height => 11,  # (optional)
1798        },
1799        {
1800            Height => 44,
1801        },
1802    ];
1803
1804=cut
1805
1806sub _TableCalculate {
1807    my ( $Self, %Param ) = @_;
1808
1809    # check needed stuff
1810    for (
1811        qw(
1812        CellData ColumnData RowData
1813        Type Font FontSize Lead FontColor Align BackgroundColor Width Border BorderColor
1814        PaddingTop PaddingRight PaddingBottom PaddingLeft
1815        )
1816        )
1817    {
1818        if ( !defined( $Param{$_} ) ) {
1819            $Kernel::OM->Get('Kernel::System::Log')->Log(
1820                Priority => 'error',
1821                Message  => "Need $_!"
1822            );
1823            return;
1824        }
1825    }
1826    if (
1827        ref( $Param{CellData} ) ne 'ARRAY'
1828        || ref( $Param{ColumnData} ) ne 'ARRAY'
1829        || ref( $Param{RowData} ) ne 'ARRAY'
1830        )
1831    {
1832        $Kernel::OM->Get('Kernel::System::Log')->Log(
1833            Priority => 'error',
1834            Message  => "Need array references of CellData, ColumnData and RowData!"
1835        );
1836        return;
1837    }
1838    if ( !$Self->{PDF} ) {
1839        $Kernel::OM->Get('Kernel::System::Log')->Log(
1840            Priority => 'error',
1841            Message  => "Need a PDF Document!"
1842        );
1843        return;
1844    }
1845    if ( !$Self->{Page} ) {
1846        $Kernel::OM->Get('Kernel::System::Log')->Log(
1847            Priority => 'error',
1848            Message  => "Need a Page!"
1849        );
1850        return;
1851    }
1852
1853    # analyse, if table is corrupt
1854    my $ColumnMax = 0;
1855    my $RowMax    = 0;
1856    for my $Row ( @{ $Param{CellData} } ) {
1857        if ( scalar(@$Row) > $ColumnMax ) {
1858            $ColumnMax = scalar(@$Row);
1859        }
1860        $RowMax++;
1861    }
1862
1863    # repair, if table is corrupt
1864    if ( $RowMax eq 0 ) {
1865        ${ $Param{CellData} }[0] = [];
1866        $RowMax = 1;
1867    }
1868    if ( $ColumnMax eq 0 ) {
1869        $ColumnMax = 1;
1870    }
1871
1872    # cut ColumnData, if to much values
1873    if ( defined( ${ $Param{ColumnData} }[$ColumnMax] ) ) {
1874        splice( @{ $Param{ColumnData} }, $ColumnMax );
1875    }
1876
1877    # cut RowData, if to much values
1878    if ( defined( ${ $Param{RowData} }[$RowMax] ) ) {
1879        splice( @{ $Param{RowData} }, $RowMax );
1880    }
1881
1882    my $RowCounter = 0;
1883    for my $Row ( @{ $Param{CellData} } ) {
1884        my $MinFontSize = 999;
1885        for ( my $ColumnCounter = 0; $ColumnCounter < $ColumnMax; $ColumnCounter++ ) {
1886
1887            # repair, if row is corrupt
1888            if ( !defined( $Row->[$ColumnCounter] ) ) {
1889                $Row->[$ColumnCounter] = {};
1890            }
1891
1892            # reference of current cell
1893            my $Cell = $Row->[$ColumnCounter];
1894
1895            # if row is odd
1896            if ( $RowCounter & 1 ) {
1897
1898                # set FontColor, if row is odd
1899                if (
1900                    !defined( $Cell->{FontColor} )
1901                    && defined( $Param{FontColorOdd} )
1902                    )
1903                {
1904                    $Cell->{FontColor} = $Param{FontColorOdd};
1905                }
1906
1907                # set BackgroundColor, if row is odd
1908                if (
1909                    !defined( $Cell->{BackgroundColor} )
1910                    && defined( $Param{BackgroundColorOdd} )
1911                    )
1912                {
1913                    $Cell->{BackgroundColor} = $Param{BackgroundColorOdd};
1914                }
1915            }
1916
1917            # if row is even
1918            else {
1919
1920                # set FontColor, if row is even
1921                if (
1922                    !defined( $Cell->{FontColor} )
1923                    && defined( $Param{FontColorEven} )
1924                    )
1925                {
1926                    $Cell->{FontColor} = $Param{FontColorEven};
1927                }
1928
1929                # set BackgroundColor, if row is even
1930                if (
1931                    !defined( $Cell->{BackgroundColor} )
1932                    && defined( $Param{BackgroundColorEven} )
1933                    )
1934                {
1935                    $Cell->{BackgroundColor} = $Param{BackgroundColorEven};
1936                }
1937            }
1938
1939            # set cell state
1940            if ( !defined( $Cell->{Off} ) ) {
1941                $Cell->{Off} = 0;
1942            }
1943
1944            # set temp cell state
1945            if ( !defined( $Cell->{TmpOff} ) ) {
1946                $Cell->{TmpOff} = 0;
1947            }
1948
1949            # prepare text
1950            if ( defined( $Cell->{Content} ) ) {
1951                $Cell->{Content} = $Self->_PrepareText(
1952                    Text => $Cell->{Content},
1953                );
1954            }
1955
1956            # set content blank, if not defined
1957            if (
1958                !defined( $Cell->{Content} )
1959                || $Cell->{Content} eq ''
1960                )
1961            {
1962                $Cell->{Content} = ' ';
1963            }
1964
1965            # set default values
1966            for (qw(Type Font FontSize FontColor Align Lead BackgroundColor)) {
1967                if ( !defined( $Cell->{$_} ) ) {
1968                    $Cell->{$_} = $Param{$_};
1969                }
1970            }
1971
1972            # calculate width of complete column content
1973            if ( !defined( $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} ) ) {
1974                $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} = 0;
1975            }
1976            my $CompleteContentWidth = $Self->_StringWidth(
1977                Text     => $Cell->{Content},
1978                Font     => $Cell->{Font},
1979                FontSize => $Cell->{FontSize},
1980            );
1981            if ( $CompleteContentWidth > $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} ) {
1982                $Param{ColumnData}->[$ColumnCounter]->{MaxColWidth} = $CompleteContentWidth;
1983            }
1984
1985            # calculate with of the greaterst word
1986            if ( !defined( $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} ) ) {
1987                $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} = 0;
1988            }
1989            my @Words         = split( /\s+/, $Cell->{Content} );
1990            my $WordMaxLength = 0;
1991            for (@Words) {
1992                my $WordLength = length($_);
1993                if ( $WordMaxLength <= $WordLength + 2 ) {
1994                    $WordMaxLength = $WordLength;
1995
1996                    # calculate width of word
1997                    my $WordWidth = $Self->_StringWidth(
1998                        Text     => $_,
1999                        Font     => $Cell->{Font},
2000                        FontSize => $Cell->{FontSize},
2001                    );
2002                    if ( $WordWidth > $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} ) {
2003                        $Param{ColumnData}->[$ColumnCounter]->{MinColWidth} = $WordWidth;
2004                    }
2005                }
2006            }
2007
2008            # find the smallerst fontsize
2009            if ( $Cell->{FontSize} < $MinFontSize ) {
2010                $MinFontSize = $Cell->{FontSize};
2011            }
2012        }
2013
2014        # set MinFontSize
2015        $Param{RowData}->[$RowCounter]->{MinFontSize} = $MinFontSize;
2016        $RowCounter++;
2017    }
2018
2019    # estimate width of columns (without padding and border)
2020    for my $Column ( @{ $Param{ColumnData} } ) {
2021        if ( !defined( $Column->{Width} ) ) {
2022            $Column->{Width} = 0;
2023        }
2024        if ( $Column->{Width} > 0 ) {
2025            $Column->{EstimateWidth} = $Column->{Width};
2026        }
2027        else {
2028
2029            # estimate width of column
2030            $Column->{EstimateWidth} = ( $Column->{MaxColWidth} + $Column->{MinColWidth} ) / 2;
2031        }
2032
2033        # reduce calculated width and width, if calculated width is greater than table width
2034        my $MaxWidth = $Param{Width} - $Param{PaddingLeft} - $Param{PaddingRight} - ( 2 * $Param{Border} );
2035        if ( $Column->{EstimateWidth} > $MaxWidth ) {
2036            $Column->{EstimateWidth} = $MaxWidth;
2037            if ( $Column->{Width} > 0 ) {
2038                $Column->{Width} = $MaxWidth;
2039            }
2040        }
2041
2042        # set width to 1, if width is too small
2043        if ( $Column->{EstimateWidth} < 1 ) {
2044            $Column->{EstimateWidth} = 1;
2045        }
2046    }
2047
2048    # calculate exactly width of columns
2049    my $ColumnBlocks = [];
2050    $ColumnBlocks->[0]->{Width}       = 0;
2051    $ColumnBlocks->[0]->{ColumnStart} = 0;
2052    $ColumnBlocks->[0]->{ColumnStop}  = 0;
2053    $ColumnBlocks->[0]->{ColumnFix}   = 0;
2054    $ColumnBlocks->[0]->{ColumnDyn}   = 0;
2055
2056    my $Block   = 0;
2057    my $Counter = 0;
2058    for my $Column ( @{ $Param{ColumnData} } ) {
2059        my $ColumnWidth = $Column->{EstimateWidth}
2060            + $Param{PaddingLeft}
2061            + $Param{PaddingRight}
2062            + ( 2 * $Param{Border} );
2063
2064        if ( !$ColumnBlocks->[$Block]->{Width} ) {
2065            $ColumnBlocks->[$Block]->{Width} = $ColumnWidth;
2066        }
2067        else {
2068            if (
2069                ( $ColumnBlocks->[$Block]->{Width} + $ColumnWidth - $Param{Border} )
2070                > $Param{Width}
2071                )
2072            {
2073                $ColumnBlocks->[$Block]->{ColumnStop} = $Counter - 1;
2074                $Block++;
2075                $ColumnBlocks->[$Block]->{Width}       = $ColumnWidth;
2076                $ColumnBlocks->[$Block]->{ColumnStart} = $Counter;
2077                $ColumnBlocks->[$Block]->{ColumnFix}   = 0;
2078                $ColumnBlocks->[$Block]->{ColumnDyn}   = 0;
2079            }
2080            else {
2081                $ColumnBlocks->[$Block]->{Width} += $ColumnWidth - $Param{Border};
2082            }
2083            $ColumnBlocks->[$Block]->{ColumnStop} = $Counter;
2084        }
2085
2086        if ( $Column->{Width} > 0 ) {
2087            $ColumnBlocks->[$Block]->{ColumnFix}++;
2088        }
2089        else {
2090            $ColumnBlocks->[$Block]->{ColumnDyn}++;
2091        }
2092
2093        $Counter++;
2094    }
2095    my $LastBlock = $#{$ColumnBlocks};
2096    my $Counter2  = 0;
2097    for my $CurBlock ( @{$ColumnBlocks} ) {
2098        my $ExtraSpaceComplete;
2099
2100        # no extra space for laast block
2101        if ( $Counter2 && $Counter2 eq $LastBlock ) {
2102            $ExtraSpaceComplete = 0;
2103        }
2104        else {
2105            $ExtraSpaceComplete = $Param{Width} - $CurBlock->{Width};
2106        }
2107
2108        my $ExtraSpaceDyn = 0;
2109        my $ExtraSpaceFix = 0;
2110
2111        if ( $CurBlock->{ColumnDyn} > 0 ) {
2112            $ExtraSpaceDyn = $ExtraSpaceComplete / $CurBlock->{ColumnDyn};
2113        }
2114        else {
2115            $ExtraSpaceFix = $ExtraSpaceComplete / $CurBlock->{ColumnFix};
2116        }
2117
2118        for ( $CurBlock->{ColumnStart} .. $CurBlock->{ColumnStop} ) {
2119            my $Column     = $Param{ColumnData}->[$_];
2120            my $ExtraSpace = 0;
2121            if ( $Column->{Width} > 0 ) {
2122                $ExtraSpace = $ExtraSpaceFix;
2123            }
2124            else {
2125                $ExtraSpace = $ExtraSpaceDyn;
2126            }
2127
2128            $Column->{OutputWidth} = $Column->{EstimateWidth}
2129                + $ExtraSpace
2130                + $Param{PaddingLeft}
2131                + $Param{PaddingRight}
2132                + ( 2 * $Param{Border} );
2133            $Column->{TextWidth} = $Column->{EstimateWidth} + $ExtraSpace;
2134
2135            if ( $Column->{OutputWidth} < 1 ) {
2136                $Column->{OutputWidth} = 1;
2137            }
2138            if ( $Column->{TextWidth} < 1 ) {
2139                $Column->{TextWidth} = 1;
2140            }
2141            $Column->{Block} = $Counter2;
2142        }
2143        $Counter2++;
2144    }
2145
2146    return %Param;
2147}
2148
2149=head2 _TableBlockNextCalculate()
2150
2151calculate what block can output next
2152
2153   Return
2154       $Return{State}
2155       $Return{ReturnBlock}
2156       $Return{ReturnRowStart}
2157       $Return{ReturnColumnStart}
2158       $Return{ReturnColumnStop}
2159
2160   %Return = $PDFObject->_TableBlockNextCalculate(
2161       CellData   => $CellData,    # 2D arrayref
2162       ColumnData => $ColumnData,  # arrayref
2163   );
2164
2165=cut
2166
2167sub _TableBlockNextCalculate {
2168    my ( $Self, %Param ) = @_;
2169
2170    my %Return = (
2171        State             => 0,
2172        ReturnBlock       => 0,
2173        ReturnRowStart    => 0,
2174        ReturnColumnStart => 0,
2175        ReturnColumnStop  => 0,
2176    );
2177
2178    # check needed stuff
2179    for (qw(CellData ColumnData)) {
2180        if ( !defined $Param{$_} ) {
2181            $Kernel::OM->Get('Kernel::System::Log')->Log(
2182                Priority => 'error',
2183                Message  => "Need $_!"
2184            );
2185            return;
2186        }
2187    }
2188    if ( ref $Param{CellData} ne 'ARRAY' || ref $Param{ColumnData} ne 'ARRAY' ) {
2189        $Kernel::OM->Get('Kernel::System::Log')->Log(
2190            Priority => 'error',
2191            Message  => "Need array references of CellData and ColumnData!"
2192        );
2193        return;
2194    }
2195    if ( !$Self->{PDF} ) {
2196        $Kernel::OM->Get('Kernel::System::Log')->Log(
2197            Priority => 'error',
2198            Message  => "Need a PDF Document!"
2199        );
2200        return;
2201    }
2202    if ( !$Self->{Page} ) {
2203        $Kernel::OM->Get('Kernel::System::Log')->Log(
2204            Priority => 'error',
2205            Message  => "Need a Page!"
2206        );
2207        return;
2208    }
2209
2210    my $RowStart    = 'NULL';
2211    my $ColumnStart = 'NULL';
2212    my $ColumnStop  = 0;
2213
2214    # calculate, what cells can output (what cells are active)
2215    my $RowCounter = 0;
2216    for my $Row ( @{ $Param{CellData} } ) {
2217
2218        # if last block was temporary off, reactivate the row
2219        if ( $Param{CellData}->[$RowCounter]->[ $#{ $Param{CellData}->[$RowCounter] } ]->{TmpOff} )
2220        {
2221            for ( my $ColumnCounter = 0; $ColumnCounter < scalar(@$Row); $ColumnCounter++ ) {
2222                $Row->[$ColumnCounter]->{TmpOff} = 0;
2223            }
2224        }
2225
2226        # now calculate, what cells can output (what cells are active)
2227        COLUMN_COUNTER:
2228        for ( my $ColumnCounter = 0; $ColumnCounter < scalar @$Row; $ColumnCounter++ ) {
2229
2230            # calculate RowStart and ColumnStart
2231            if (
2232                $Row->[$ColumnCounter]->{Off} ne 1
2233                && $Row->[$ColumnCounter]->{TmpOff} ne 1
2234                && $RowStart eq 'NULL'
2235                && $ColumnStart eq 'NULL'
2236                )
2237            {
2238                $RowStart    = $RowCounter;
2239                $ColumnStart = $ColumnCounter;
2240                $ColumnStop  = $ColumnStart;
2241                last COLUMN_COUNTER;
2242            }
2243        }
2244        $RowCounter++;
2245    }
2246
2247    if ( $RowStart ne 'NULL' && $ColumnStart ne 'NULL' ) {
2248
2249        # find last column of block
2250        my $Block         = $Param{ColumnData}->[$ColumnStart]->{Block};
2251        my $ColumnCounter = 0;
2252        for my $Column ( @{ $Param{ColumnData} } ) {
2253            if (
2254                $ColumnCounter > $ColumnStop
2255                && $Column->{Block} eq $Block
2256                )
2257            {
2258                $ColumnStop = $ColumnCounter;
2259            }
2260            $ColumnCounter++;
2261        }
2262
2263        $Return{State}             = 1;
2264        $Return{ReturnBlock}       = $Block;
2265        $Return{ReturnRowStart}    = $RowStart;
2266        $Return{ReturnColumnStart} = $ColumnStart;
2267        $Return{ReturnColumnStop}  = $ColumnStop;
2268    }
2269
2270    return %Return;
2271}
2272
2273=head2 _TableRowCalculate()
2274
2275calculate row of table
2276
2277   Return  # normally no return required, only references
2278       %Param
2279
2280   %Return = $PDFObject->_TableRowCalculate(
2281       CellData   => $CellData,    # 2D arrayref
2282       RowData    => $RowData,     # arrayref
2283       ColumnData => $ColumnData,  # arrayref
2284       Row        => 3,            # current row
2285   );
2286
2287=cut
2288
2289sub _TableRowCalculate {
2290    my ( $Self, %Param ) = @_;
2291
2292    # check needed stuff
2293    for (qw(CellData RowData ColumnData Row)) {
2294        if ( !defined( $Param{$_} ) ) {
2295            $Kernel::OM->Get('Kernel::System::Log')->Log(
2296                Priority => 'error',
2297                Message  => "Need $_!"
2298            );
2299            return;
2300        }
2301    }
2302    if (
2303        ref( $Param{CellData} ) ne 'ARRAY'
2304        || ref( $Param{ColumnData} ) ne 'ARRAY'
2305        || ref( $Param{RowData} ) ne 'ARRAY'
2306        )
2307    {
2308        $Kernel::OM->Get('Kernel::System::Log')->Log(
2309            Priority => 'error',
2310            Message  => "Need array references of CellData, ColumnData and RowData!"
2311        );
2312        return;
2313    }
2314    if ( !$Self->{PDF} ) {
2315        $Kernel::OM->Get('Kernel::System::Log')->Log(
2316            Priority => 'error',
2317            Message  => "Need a PDF Document!"
2318        );
2319        return;
2320    }
2321    if ( !$Self->{Page} ) {
2322        $Kernel::OM->Get('Kernel::System::Log')->Log(
2323            Priority => 'error',
2324            Message  => "Need a Page!"
2325        );
2326        return;
2327    }
2328
2329    if ( $Param{RowData}->[ $Param{Row} ]->{Height} ) {
2330        $Param{RowData}->[ $Param{Row} ]->{TextHeight} = $Param{RowData}->[ $Param{Row} ]->{Height};
2331    }
2332    else {
2333
2334        # calculate height of row
2335        $Param{RowData}->[ $Param{Row} ]->{Height}     = 0;
2336        $Param{RowData}->[ $Param{Row} ]->{TextHeight} = 0;
2337        my $BiggerstFontSize = 0;
2338        my $ColumnCounter    = 0;
2339        for my $Column ( @{ $Param{ColumnData} } ) {
2340            my $Cell      = $Param{CellData}->[ $Param{Row} ]->[$ColumnCounter];
2341            my %Calculate = $Self->_TextCalculate(
2342                Text     => $Cell->{Content},
2343                Type     => 'ReturnLeftOver',
2344                Width    => $Column->{TextWidth},
2345                Height   => 1000000,
2346                Font     => $Cell->{Font},
2347                FontSize => $Cell->{FontSize},
2348                Lead     => $Cell->{Lead},
2349            );
2350            if ( $Calculate{RequiredHeight} > $Param{RowData}->[ $Param{Row} ]->{TextHeight} ) {
2351                $Param{RowData}->[ $Param{Row} ]->{TextHeight} = $Calculate{RequiredHeight};
2352            }
2353            if ( $Cell->{FontSize} > $BiggerstFontSize ) {
2354                $BiggerstFontSize = $Cell->{FontSize};
2355            }
2356            $ColumnCounter++;
2357        }
2358        if ( !$Param{RowData}->[ $Param{Row} ]->{TextHeight} ) {
2359            $Param{RowData}->[ $Param{Row} ]->{TextHeight} = $BiggerstFontSize;
2360        }
2361    }
2362    $Param{RowData}->[ $Param{Row} ]->{OutputHeight} = $Param{RowData}->[ $Param{Row} ]->{TextHeight}
2363        + $Param{PaddingTop}
2364        + $Param{PaddingBottom}
2365        + ( 2 * $Param{Border} );
2366
2367    return %Param;
2368}
2369
2370=head2 _TableCellOutput()
2371
2372output a cell of a table
2373
2374   Return
2375       $Return{State}
2376       $Return{RequiredWidth}
2377       $Return{RequiredHeight}
2378       $Return{LeftOver}
2379
2380   %Return = $PDFObject->_TableCellOutput(
2381       Width           => 70,
2382       Height          => 40,
2383       Text            => 'Text',
2384       Type            => 'Cut',
2385       Font            => 'ProportionalBold',
2386       FontSize        => 15,
2387       FontColor       => '#FF0000',
2388       Align           => 'center',
2389       Lead            => 20,
2390       PaddingTop      => 10,
2391       PaddingRight    => 30,
2392       PaddingBottom   => 30,
2393       PaddingLeft     => 10,
2394       BackgroundColor => '#101010',
2395       Border          => 1,
2396       BorderColor     => '#FF0000',
2397   );
2398
2399=cut
2400
2401sub _TableCellOutput {
2402    my ( $Self, %Param ) = @_;
2403
2404    my %Return = (
2405        State          => 0,
2406        RequiredWidth  => 0,
2407        RequiredHeight => 0,
2408        LeftOver       => '',
2409    );
2410
2411    # check needed stuff
2412    for (
2413        qw(Width Height Text Type Font FontSize FontColor Align Lead
2414        PaddingTop PaddingRight PaddingBottom PaddingLeft BackgroundColor Border BorderColor)
2415        )
2416    {
2417        if ( !defined( $Param{$_} ) ) {
2418            $Kernel::OM->Get('Kernel::System::Log')->Log(
2419                Priority => 'error',
2420                Message  => "Need $_!"
2421            );
2422            return;
2423        }
2424    }
2425    if ( !$Self->{PDF} ) {
2426        $Kernel::OM->Get('Kernel::System::Log')->Log(
2427            Priority => 'error',
2428            Message  => "Need a PDF Document!"
2429        );
2430        return;
2431    }
2432    if ( !$Self->{Page} ) {
2433        $Kernel::OM->Get('Kernel::System::Log')->Log(
2434            Priority => 'error',
2435            Message  => "Need a Page!"
2436        );
2437        return;
2438    }
2439    my %Dim;
2440
2441    # get dimension (printable or content)
2442    if ( $Self->DimGet() eq 'printable' ) {
2443        %Dim = $Self->_CurPrintableDimGet();
2444    }
2445    else {
2446        %Dim = $Self->_CurContentDimGet();
2447    }
2448
2449    # get current position
2450    my %Position = $Self->_CurPositionGet();
2451
2452    # output background
2453    if ( $Param{BackgroundColor} ne 'NULL' ) {
2454        my $Background = $Self->{Page}->gfx();
2455        $Background->fillcolor( $Param{BackgroundColor} );
2456        $Background->rect( $Position{X}, $Position{Y}, $Param{Width}, -( $Param{Height} ) );
2457        $Background->fill();
2458    }
2459
2460    # output top border
2461    if ( $Param{Border} > 0 ) {
2462        my $BorderTop = $Self->{Page}->gfx();
2463        $BorderTop->fillcolor( $Param{BorderColor} );
2464        $BorderTop->rect( $Position{X}, $Position{Y}, $Param{Width}, -( $Param{Border} ) );
2465        $BorderTop->fill();
2466    }
2467
2468    # output right border
2469    if ( $Param{Border} > 0 ) {
2470        my $BorderRight = $Self->{Page}->gfx();
2471        $BorderRight->fillcolor( $Param{BorderColor} );
2472        $BorderRight->rect(
2473            ( $Position{X} + $Param{Width} - $Param{Border} ),
2474            $Position{Y}, $Param{Border}, -( $Param{Height} )
2475        );
2476        $BorderRight->fill();
2477    }
2478
2479    # output bottom border
2480    if ( $Param{Border} > 0 ) {
2481        my $BorderBottom = $Self->{Page}->gfx();
2482        $BorderBottom->fillcolor( $Param{BorderColor} );
2483        $BorderBottom->rect(
2484            $Position{X}, ( $Position{Y} - $Param{Height} + $Param{Border} ),
2485            $Param{Width}, -( $Param{Border} )
2486        );
2487        $BorderBottom->fill();
2488    }
2489
2490    # output left border
2491    if ( $Param{Border} > 0 ) {
2492        my $BorderLeft = $Self->{Page}->gfx();
2493        $BorderLeft->fillcolor( $Param{BorderColor} );
2494        $BorderLeft->rect( $Position{X}, $Position{Y}, $Param{Border}, -( $Param{Height} ) );
2495        $BorderLeft->fill();
2496    }
2497
2498    # calculate text start position
2499    my $TextX = $Position{X} + $Param{Border} + $Param{PaddingLeft};
2500    my $TextY = $Position{Y} - $Param{Border} - $Param{PaddingTop} + 1;
2501
2502    # calculate width and height of text
2503    my $TextWidth  = $Param{Width} - $Param{PaddingLeft} - $Param{PaddingRight} - ( 2 * $Param{Border} );
2504    my $TextHeight = $Param{Height} - $Param{PaddingTop} - $Param{PaddingBottom} - ( 2 * $Param{Border} );
2505
2506    # set new position
2507    $Self->PositionSet(
2508        X => $TextX,
2509        Y => $TextY,
2510    );
2511
2512    %Return = $Self->Text(
2513        Text     => $Param{Text},
2514        Type     => $Param{Type},
2515        Width    => $TextWidth,
2516        Height   => $TextHeight,
2517        Font     => $Param{Font},
2518        FontSize => $Param{FontSize},
2519        Color    => $Param{FontColor},
2520        Align    => $Param{Align},
2521        Lead     => $Param{Lead},
2522    );
2523
2524    return %Return;
2525}
2526
2527=head2 _TableCellOnCount()
2528
2529count all active cells
2530
2531   Return
2532       $CellCount
2533
2534   $Count = $PDFObject->_TableCellOnCount(
2535       CellData => $CellData,  # 2D arrayref
2536   );
2537
2538=cut
2539
2540sub _TableCellOnCount {
2541    my ( $Self, %Param ) = @_;
2542
2543    my $Return = 0;
2544
2545    # check needed stuff
2546    for (qw(CellData)) {
2547        if ( !defined( $Param{$_} ) ) {
2548            $Kernel::OM->Get('Kernel::System::Log')->Log(
2549                Priority => 'error',
2550                Message  => "Need $_!"
2551            );
2552            return;
2553        }
2554    }
2555    if ( ref( $Param{CellData} ) ne 'ARRAY' ) {
2556        $Kernel::OM->Get('Kernel::System::Log')->Log(
2557            Priority => 'error',
2558            Message  => "Need array references of CellData!"
2559        );
2560        return;
2561    }
2562    if ( !$Self->{PDF} ) {
2563        $Kernel::OM->Get('Kernel::System::Log')->Log(
2564            Priority => 'error',
2565            Message  => "Need a PDF Document!"
2566        );
2567        return;
2568    }
2569    if ( !$Self->{Page} ) {
2570        $Kernel::OM->Get('Kernel::System::Log')->Log(
2571            Priority => 'error',
2572            Message  => "Need a Page!"
2573        );
2574        return;
2575    }
2576    for my $Row ( @{ $Param{CellData} } ) {
2577        for ( my $ColumnCounter = 0; $ColumnCounter < scalar(@$Row); $ColumnCounter++ ) {
2578            if ( $Row->[$ColumnCounter]->{Off} ne 1 ) {
2579                $Return++;
2580            }
2581        }
2582    }
2583
2584    return $Return;
2585}
2586
2587=head2 _TextCalculate()
2588
2589calculate required values of given text
2590
2591   Return
2592       $Return{State}
2593       $Return{RequiredWidth}
2594       $Return{RequiredHeight}
2595       $Return{LeftOver}
2596       $Return{PossibleRows}  # (Array Ref)
2597
2598   %Return = $PDFObject->_TextCalculate(
2599       Text     => $Text,               # text
2600       Type     => 'Cut',               # (ReturnLeftOver|ReturnLeftOverHard|Cut)
2601       Width    => 300,                 # available width
2602       Height   => 200,                 # available height
2603       Font     => 'ProportionalBold',  # font of text
2604       FontSize => 6,                   # fontsize of text
2605       Lead     => 20,                  # lead
2606   );
2607
2608=cut
2609
2610sub _TextCalculate {
2611    my ( $Self, %Param ) = @_;
2612
2613    my %Return = (
2614        State          => 0,
2615        RequiredWidth  => 0,
2616        RequiredHeight => 0,
2617        LeftOver       => '',
2618    );
2619    my @PossibleRows;
2620
2621    # check needed stuff
2622    for (qw(Text Type Width Height Font FontSize Lead)) {
2623        if ( !defined( $Param{$_} ) ) {
2624            $Kernel::OM->Get('Kernel::System::Log')->Log(
2625                Priority => 'error',
2626                Message  => "Need $_!"
2627            );
2628            return;
2629        }
2630    }
2631    if ( !$Self->{PDF} ) {
2632        $Kernel::OM->Get('Kernel::System::Log')->Log(
2633            Priority => 'error',
2634            Message  => "Need a PDF Document!"
2635        );
2636        return;
2637    }
2638    if ( !$Self->{Page} ) {
2639        $Kernel::OM->Get('Kernel::System::Log')->Log(
2640            Priority => 'error',
2641            Message  => "Need a Page!"
2642        );
2643        return;
2644    }
2645    my $TextLength = 0;
2646
2647    if ( $Param{Width} <= 0 || $Param{Height} <= 0 ) {
2648        $Return{LeftOver} = $Param{Text};
2649        $Param{Text}      = undef;
2650    }
2651    else {
2652        $Param{Text} = $Self->_PrepareText(
2653            Text => $Param{Text},
2654        );
2655        $TextLength = length( $Param{Text} );
2656    }
2657    my $Counter1 = 0;
2658    while ( defined( $Param{Text} ) ) {
2659        my $Row;
2660        my $DelPreSpace = 0;
2661
2662        # get next row of given text
2663        if ( $Param{Text} =~ s/^(.*?)\n(.*)/$2/s ) {
2664            $Row = $1;
2665        }
2666        else {
2667            $Row = $Param{Text};
2668            $Param{Text} = undef;
2669        }
2670
2671        # delete one space at begin of row, if exists
2672        $Row =~ s/^\s//;
2673
2674        # calculate width of the row
2675        my $RowWidth = $Self->_StringWidth(
2676            Text     => $Row,
2677            Font     => $Param{Font},
2678            FontSize => $Param{FontSize},
2679        );
2680
2681        # calculate height of the row
2682        my $RowHeight = $Param{FontSize};
2683        if ( $Counter1 > 0 ) {
2684            $RowHeight += $Param{Lead};
2685        }
2686
2687        if ( $Return{RequiredHeight} + $RowHeight <= $Param{Height} ) {
2688
2689            # if row is greater then $Param{Width}
2690            if ( $RowWidth > $Param{Width} ) {
2691
2692                # estimate point of cut
2693                my $Factor = $RowWidth / $Param{Width};
2694                my $Cut    = int( length($Row) / $Factor );
2695
2696                # cut the row
2697                my $RowFore = substr( $Row, 0, $Cut );
2698                my $RowRear = substr( $Row, $Cut );
2699
2700                # calculate width of fore row
2701                my $RowForeWidth = $Self->_StringWidth(
2702                    Text     => $RowFore,
2703                    Font     => $Param{Font},
2704                    FontSize => $Param{FontSize},
2705                );
2706
2707                # caculate exactly point of cut
2708                while ( $RowForeWidth < $Param{Width} ) {
2709                    $RowFore .= substr( $RowRear, 0, 1 );
2710                    $RowRear      = substr( $RowRear, 1 );
2711                    $RowForeWidth = $Self->_StringWidth(
2712                        Text     => $RowFore,
2713                        Font     => $Param{Font},
2714                        FontSize => $Param{FontSize},
2715                    );
2716                }
2717                while ( $RowForeWidth > $Param{Width} ) {
2718                    $RowRear      = chop($RowFore) . $RowRear;
2719                    $RowForeWidth = $Self->_StringWidth(
2720                        Text     => $RowFore,
2721                        Font     => $Param{Font},
2722                        FontSize => $Param{FontSize},
2723                    );
2724                }
2725
2726                if ( $Param{Type} eq 'ReturnLeftOver' || $Param{Type} eq 'Cut' ) {
2727                    if ( $RowFore =~ /[^\s]$/ && $RowRear =~ /^[^\s]/ ) {
2728                        $RowFore =~ s/^(.*)(\s+.+?)$/$1/;
2729                        if ($2) {
2730                            $RowRear = $2 . $RowRear;
2731                        }
2732                    }
2733                }
2734
2735                $Row = $RowFore;
2736                if ( $Param{Text} ) {
2737                    $Param{Text} = $RowRear . "\n" . $Param{Text};
2738                }
2739                else {
2740                    $Param{Text} = $RowRear;
2741                }
2742            }
2743
2744            # delete spaces at end of row, if spaces exists
2745            $Row =~ s/^(.*)\s$/$1/;
2746
2747            # add Row to PossibleRows array
2748            push( @PossibleRows, $Row );
2749            $Return{RequiredHeight} += $RowHeight;
2750
2751            # check, if min one character can count (protection of infinite loop)
2752            if ( defined( $Param{Text} ) ) {
2753                if ( length( $Param{Text} ) >= $TextLength ) {
2754                    $Return{RequiredWidth}  = 0;
2755                    $Return{RequiredHeight} = 0;
2756                    $Return{LeftOver}       = $Param{Text};
2757                    $Param{Text}            = undef;
2758                    @PossibleRows           = ();
2759                }
2760                else {
2761                    $TextLength = length( $Param{Text} );
2762                }
2763            }
2764        }
2765        else {
2766            $Return{LeftOver} = $Row;
2767            if ( $Param{Text} ) {
2768                $Return{LeftOver} .= "\n" . $Param{Text};
2769                $Param{Text} = undef;
2770            }
2771        }
2772        $Counter1++;
2773    }
2774
2775    # cut text if type is Cut
2776    if ( $Param{Type} eq 'Cut' && $Return{LeftOver} ) {
2777        my $LastRow = $PossibleRows[-1];
2778        if ($LastRow) {
2779
2780            # calculate width [..]
2781            my $PPWidth = $Self->_StringWidth(
2782                Text     => '[..]',
2783                Font     => $Param{Font},
2784                FontSize => $Param{FontSize},
2785            );
2786            if ( $PPWidth <= $Param{Width} ) {
2787
2788                # calculate width of LastRow and [..]
2789                my $TextCutWidth = $Self->_StringWidth(
2790                    Text     => $LastRow,
2791                    Font     => $Param{Font},
2792                    FontSize => $Param{FontSize},
2793                );
2794
2795                # calculate last line
2796                while ( $TextCutWidth + $PPWidth > $Param{Width} ) {
2797                    chop($LastRow);
2798
2799                    # calculate width of shorted LastRow and [..]
2800                    $TextCutWidth = $Self->_StringWidth(
2801                        Text     => $LastRow,
2802                        Font     => $Param{Font},
2803                        FontSize => $Param{FontSize},
2804                    );
2805                }
2806                $PossibleRows[-1] = $LastRow . '[..]';
2807
2808            }
2809            $Return{LeftOver} = '';
2810        }
2811    }
2812
2813    # calculate RequiredWidth
2814    my $Counter2 = 0;
2815    for (@PossibleRows) {
2816        my $RowWidth = $Self->_StringWidth(
2817            Text     => $_,
2818            Font     => $Param{Font},
2819            FontSize => $Param{FontSize},
2820        );
2821
2822        # set new RequiredWidth
2823        if ( $RowWidth > $Return{RequiredWidth} ) {
2824            $Return{RequiredWidth} = $RowWidth;
2825        }
2826
2827        $Counter2++;
2828    }
2829
2830    # correct RequiredHeight
2831    if ( $Return{RequiredWidth} eq 0 ) {
2832        $Return{RequiredHeight} = 0;
2833    }
2834
2835    # set state
2836    if ( !$Return{LeftOver} ) {
2837        $Return{State} = 1;
2838    }
2839
2840    $Return{PossibleRows} = \@PossibleRows;
2841
2842    return %Return;
2843}
2844
2845=head2 _StringWidth()
2846
2847calculate width of given text
2848
2849   $Width = $PDFObject->_StringWidth(
2850       Text     => 'Text',              # text
2851       Font     => 'ProportionalBold',  # font of text
2852       FontSize => 6,                   # fontsize of text
2853   );
2854
2855=cut
2856
2857sub _StringWidth {
2858    my ( $Self, %Param ) = @_;
2859
2860    # check needed stuff
2861    for (qw(Text Font FontSize)) {
2862        if ( !defined $Param{$_} ) {
2863            $Kernel::OM->Get('Kernel::System::Log')->Log(
2864                Priority => 'error',
2865                Message  => "Need $_!"
2866            );
2867            return;
2868        }
2869    }
2870
2871    # check document
2872    if ( !$Self->{PDF} ) {
2873        $Kernel::OM->Get('Kernel::System::Log')->Log(
2874            Priority => 'error',
2875            Message  => "Need a PDF Document!"
2876        );
2877        return;
2878    }
2879
2880    # check page
2881    if ( !$Self->{Page} ) {
2882        $Kernel::OM->Get('Kernel::System::Log')->Log(
2883            Priority => 'error',
2884            Message  => "Need a Page!"
2885        );
2886        return;
2887    }
2888
2889    return $Self->{CacheStringWidth}->{ $Param{Font} }->{ $Param{FontSize} }->{ $Param{Text} }
2890        if $Self->{CacheStringWidth}->{ $Param{Font} }->{ $Param{FontSize} }->{ $Param{Text} };
2891
2892    # create a text object
2893    $Self->{TextWidthObject} ||= $Self->{Page}->text();
2894
2895    # set font and fontsize
2896    $Self->{TextWidthObject}->font( $Self->{Font}->{ $Param{Font} }, $Param{FontSize} );
2897
2898    # calculate width of given text
2899    my $StringWidth = $Self->{TextWidthObject}->advancewidth( $Param{Text} );
2900
2901    return $StringWidth if length $Param{Text} > 20;
2902
2903    # write width cache if length is not more than 20 chars
2904    $Self->{CacheStringWidth}->{ $Param{Font} }->{ $Param{FontSize} }->{ $Param{Text} } = $StringWidth;
2905
2906    return $StringWidth;
2907}
2908
2909=head2 _PrepareText()
2910
2911prepare given text for output
2912
2913   $Width = $PDFObject->_PrepareText(
2914       Text => 'Text',  # text
2915   );
2916
2917=cut
2918
2919sub _PrepareText {
2920    my ( $Self, %Param ) = @_;
2921
2922    # check needed stuff
2923    for (qw(Text)) {
2924        if ( !defined( $Param{$_} ) ) {
2925            $Kernel::OM->Get('Kernel::System::Log')->Log(
2926                Priority => 'error',
2927                Message  => "Need $_!"
2928            );
2929            return;
2930        }
2931    }
2932    if ( !$Self->{PDF} ) {
2933        $Kernel::OM->Get('Kernel::System::Log')->Log(
2934            Priority => 'error',
2935            Message  => "Need a PDF Document!"
2936        );
2937        return;
2938    }
2939    if ( !$Self->{Page} ) {
2940        $Kernel::OM->Get('Kernel::System::Log')->Log(
2941            Priority => 'error',
2942            Message  => "Need a Page!"
2943        );
2944        return;
2945    }
2946
2947    # prepare new line
2948    $Param{Text} =~ s/(\n\r|\r\r\n|\r\n)/\n/g;
2949    $Param{Text} =~ s/\r/\n/g;
2950
2951    # convert page brake to new lines
2952    $Param{Text} =~ s/\f/\n\n/g;
2953
2954    # convert tabs to spaces
2955    $Param{Text} =~ s/\t/  /g;
2956
2957    return $Param{Text};
2958}
2959
2960=head2 _CurPageNumberSet()
2961
2962set number of current page
2963
2964   $PDFObject->_CurPageNumberSet(
2965       ShowPageNumber => 0,  # (optional) default 1
2966   );
2967
2968=cut
2969
2970sub _CurPageNumberSet {
2971    my ( $Self, %Param ) = @_;
2972
2973    if ( !$Self->{PDF} ) {
2974        $Kernel::OM->Get('Kernel::System::Log')->Log(
2975            Priority => 'error',
2976            Message  => "Need a PDF Document!"
2977        );
2978        return;
2979    }
2980    if ( !$Self->{Page} ) {
2981        $Kernel::OM->Get('Kernel::System::Log')->Log(
2982            Priority => 'error',
2983            Message  => "Need a Page!"
2984        );
2985        return;
2986    }
2987
2988    # set number of all over pages to 0, if first page
2989    if ( !defined( $Self->{Current}->{Page} ) ) {
2990        $Self->{Current}->{Page} = 0;
2991    }
2992
2993    # set number of displayed pages to 0, if first page
2994    if ( !defined( $Self->{Current}->{PageNumber} ) ) {
2995        $Self->{Current}->{PageNumber} = 0;
2996    }
2997
2998    # increment all over pages
2999    $Self->{Current}->{Page}++;
3000
3001    # set page number of current page
3002    if ( $Param{ShowPageNumber} eq 0 ) {
3003        $Self->{PageData}->{ $Self->{Current}->{Page} }->{PageNumber} = '';
3004    }
3005    else {
3006        $Self->{Current}->{PageNumber}++;
3007        $Self->{PageData}->{ $Self->{Current}->{Page} }->{PageNumber} = $Self->{Current}->{PageNumber};
3008    }
3009
3010    return 1;
3011}
3012
3013=head2 _CurPageDimSet()
3014
3015Set current Page Dimension
3016
3017   $PDFObject->_CurPageDimSet(
3018       Width           => 123,          # (optional) default 595 (Din A4)
3019       Height          => 321,          # (optional) default 842 (Din A4)
3020       PageOrientation => 'landscape',  # (optional) (normal|landscape)
3021   );
3022
3023=cut
3024
3025sub _CurPageDimSet {
3026    my ( $Self, %Param ) = @_;
3027
3028    if ( !$Self->{PDF} ) {
3029        $Kernel::OM->Get('Kernel::System::Log')->Log(
3030            Priority => 'error',
3031            Message  => "Need a PDF Document!"
3032        );
3033        return;
3034    }
3035    if ( !$Self->{Page} ) {
3036        $Kernel::OM->Get('Kernel::System::Log')->Log(
3037            Priority => 'error',
3038            Message  => "Need a Page!"
3039        );
3040        return;
3041    }
3042
3043    my $NewValue;
3044
3045    # set CurPageWidth
3046    if ( defined( $Param{Width} ) && $Param{Width} >= 100 && $Param{Width} <= 10000 ) {
3047        $Self->{Current}->{PageWidth} = int( $Param{Width} );
3048        $NewValue = 1;
3049    }
3050
3051    # set CurPageHeight
3052    if ( defined( $Param{Height} ) && $Param{Height} >= 100 && $Param{Height} <= 10000 ) {
3053        $Self->{Current}->{PageHeight} = int( $Param{Height} );
3054        $NewValue = 1;
3055    }
3056
3057    # get default pagesize
3058    my $DefaultWidth  = 595;    # DIN A4
3059    my $DefaultHeight = 842;    # DIN A4
3060    if ( $Kernel::OM->Get('Kernel::Config')->Get('PDF::PageSize') eq 'letter' ) {
3061        $DefaultWidth  = 612;
3062        $DefaultHeight = 792;
3063    }
3064
3065    # set page orientation
3066    if ( defined( $Param{PageOrientation} ) && $Param{PageOrientation} eq 'landscape' ) {
3067        my $TmpWidth = $DefaultWidth;
3068        $DefaultWidth  = $DefaultHeight;
3069        $DefaultHeight = $TmpWidth;
3070    }
3071
3072    # set default values
3073    if ( !defined( $Self->{Current}->{PageWidth} ) ) {
3074        $Self->{Current}->{PageWidth} = $DefaultWidth;
3075        $NewValue = 1;
3076    }
3077    if ( !defined( $Self->{Current}->{PageHeight} ) ) {
3078        $Self->{Current}->{PageHeight} = $DefaultHeight;
3079        $NewValue = 1;
3080    }
3081
3082    if ($NewValue) {
3083
3084        # set new printable dimension
3085        $Self->{Current}->{PrintableTop}    = 0;
3086        $Self->{Current}->{PrintableRight}  = 0;
3087        $Self->{Current}->{PrintableBottom} = 0;
3088        $Self->{Current}->{PrintableLeft}   = 0;
3089        $Self->{Current}->{PrintableWidth}  = $Self->{Current}->{PageWidth};
3090        $Self->{Current}->{PrintableHeight} = $Self->{Current}->{PageHeight};
3091
3092        # set new content dimension
3093        $Self->{Current}->{ContentTop}    = $Self->{Current}->{PrintableTop};
3094        $Self->{Current}->{ContentRight}  = $Self->{Current}->{PrintableRight};
3095        $Self->{Current}->{ContentBottom} = $Self->{Current}->{PrintableBottom};
3096        $Self->{Current}->{ContentLeft}   = $Self->{Current}->{PrintableLeft};
3097        $Self->{Current}->{ContentWidth}  = $Self->{Current}->{PrintableWidth};
3098        $Self->{Current}->{ContentHeight} = $Self->{Current}->{PrintableHeight};
3099
3100        # set new current position
3101        $Self->{Current}->{PositionX} = $Self->{Current}->{ContentLeft};
3102        $Self->{Current}->{PositionY} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop};
3103    }
3104
3105    return 1;
3106}
3107
3108=head2 _CurPageDimGet()
3109
3110Get current Page Dimension (Width, Height)
3111
3112   Return
3113       $CurPageDim{Width}
3114       $CurPageDim{Height}
3115
3116   %CurPageDim = $PDFObject->_CurPageDimGet();
3117
3118=cut
3119
3120sub _CurPageDimGet {
3121    my ( $Self, %Param ) = @_;
3122
3123    if ( !$Self->{PDF} ) {
3124        $Kernel::OM->Get('Kernel::System::Log')->Log(
3125            Priority => 'error',
3126            Message  => "Need a PDF Document!"
3127        );
3128        return;
3129    }
3130    if ( !$Self->{Page} ) {
3131        $Kernel::OM->Get('Kernel::System::Log')->Log(
3132            Priority => 'error',
3133            Message  => "Need a Page!"
3134        );
3135        return;
3136    }
3137
3138    if ( !$Self->{Current}->{PageWidth} || !$Self->{Current}->{PageHeight} ) {
3139        $Self->_CurPageDimSet();
3140    }
3141
3142    my %Data;
3143    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3144        $Data{Width}  = $Self->{Current}->{PageWidth};
3145        $Data{Height} = $Self->{Current}->{PageHeight};
3146    }
3147
3148    return %Data;
3149}
3150
3151=head2 _CurPageDimCheck()
3152
3153Check given X an/or Y if inside the page dimension
3154
3155   $True = $PDFObject->_CurPageDimCheck(
3156       X => 200,  # (optional)
3157       Y => 100,  # (optional)
3158   );
3159
3160=cut
3161
3162sub _CurPageDimCheck {
3163    my ( $Self, %Param ) = @_;
3164
3165    if ( !$Self->{PDF} ) {
3166        $Kernel::OM->Get('Kernel::System::Log')->Log(
3167            Priority => 'error',
3168            Message  => "Need a PDF Document!"
3169        );
3170        return;
3171    }
3172    if ( !$Self->{Page} ) {
3173        $Kernel::OM->Get('Kernel::System::Log')->Log(
3174            Priority => 'error',
3175            Message  => "Need a Page!"
3176        );
3177        return;
3178    }
3179
3180    my $Return = 0;
3181    my %Page   = $Self->_CurPageDimGet();
3182
3183    if ( defined( $Param{X} ) ) {
3184        if ( $Param{X} >= 0 && $Param{X} <= $Page{Width} ) {
3185            $Return = 1;
3186        }
3187    }
3188
3189    if ( defined( $Param{Y} ) ) {
3190        if ( $Param{Y} >= 0 && $Param{Y} <= $Page{Height} ) {
3191            $Return = 1;
3192        }
3193    }
3194
3195    return $Return;
3196}
3197
3198=head2 _CurPrintableDimSet()
3199
3200Set current Printable Dimension
3201
3202   $True = $PDFObject->_CurPrintableDimSet(
3203       Top    => 20,  # (optional)
3204       Right  => 20,  # (optional)
3205       Bottom => 20,  # (optional)
3206       Left   => 20,  # (optional)
3207   );
3208
3209=cut
3210
3211sub _CurPrintableDimSet {
3212    my ( $Self, %Param ) = @_;
3213
3214    if ( !$Self->{PDF} ) {
3215        $Kernel::OM->Get('Kernel::System::Log')->Log(
3216            Priority => 'error',
3217            Message  => "Need a PDF Document!"
3218        );
3219        return;
3220    }
3221    if ( !$Self->{Page} ) {
3222        $Kernel::OM->Get('Kernel::System::Log')->Log(
3223            Priority => 'error',
3224            Message  => "Need a Page!"
3225        );
3226        return;
3227    }
3228
3229    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3230        my $NewValue;
3231
3232        # set CurPrintableTop
3233        if (
3234            defined( $Param{Top} )
3235            && $Param{Top} > 0
3236            && $Param{Top} < $Self->{Current}->{PageHeight} / 2
3237            )
3238        {
3239            $Self->{Current}->{PrintableTop} = $Param{Top};
3240            $NewValue = 1;
3241        }
3242
3243        # set CurPrintableRight
3244        if (
3245            defined( $Param{Right} )
3246            && $Param{Right} > 0
3247            && $Param{Right} < $Self->{Current}->{PageWidth} / 2
3248            )
3249        {
3250            $Self->{Current}->{PrintableRight} = $Param{Right};
3251            $NewValue = 1;
3252        }
3253
3254        # set CurPrintableBottom
3255        if (
3256            defined( $Param{Bottom} )
3257            && $Param{Bottom} > 0
3258            && $Param{Bottom} < $Self->{Current}->{PageHeight} / 2
3259            )
3260        {
3261            $Self->{Current}->{PrintableBottom} = $Param{Bottom};
3262            $NewValue = 1;
3263        }
3264
3265        # set CurPrintableLeft
3266        if (
3267            defined( $Param{Left} )
3268            && $Param{Left} > 0
3269            && $Param{Left} < $Self->{Current}->{PageWidth} / 2
3270            )
3271        {
3272            $Self->{Current}->{PrintableLeft} = $Param{Left};
3273            $NewValue = 1;
3274        }
3275
3276        if ($NewValue) {
3277
3278            # calculate new printable width and height
3279            $Self->{Current}->{PrintableWidth} = $Self->{Current}->{PageWidth}
3280                - $Self->{Current}->{PrintableLeft}
3281                - $Self->{Current}->{PrintableRight};
3282            $Self->{Current}->{PrintableHeight} = $Self->{Current}->{PageHeight}
3283                - $Self->{Current}->{PrintableTop}
3284                - $Self->{Current}->{PrintableBottom};
3285
3286            # set new content dimension
3287            $Self->{Current}->{ContentTop}    = $Self->{Current}->{PrintableTop};
3288            $Self->{Current}->{ContentRight}  = $Self->{Current}->{PrintableRight};
3289            $Self->{Current}->{ContentBottom} = $Self->{Current}->{PrintableBottom};
3290            $Self->{Current}->{ContentLeft}   = $Self->{Current}->{PrintableLeft};
3291            $Self->{Current}->{ContentWidth}  = $Self->{Current}->{PrintableWidth};
3292            $Self->{Current}->{ContentHeight} = $Self->{Current}->{PrintableHeight};
3293
3294            # set new current position
3295            $Self->{Current}->{PositionX} = $Self->{Current}->{ContentLeft};
3296            $Self->{Current}->{PositionY} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop};
3297        }
3298    }
3299
3300    return 1;
3301}
3302
3303=head2 _CurPrintableDimGet()
3304
3305Get current Printable Dimension
3306
3307   Return
3308       $CurPrintableDim{Top}
3309       $CurPrintableDim{Right}
3310       $CurPrintableDim{Bottom}
3311       $CurPrintableDim{Left}
3312       $CurPrintableDim{Width}
3313       $CurPrintableDim{Height}
3314
3315   %CurPrintableDim = $PDFObject->_CurPrintableDimGet();
3316
3317=cut
3318
3319sub _CurPrintableDimGet {
3320    my ( $Self, %Param ) = @_;
3321
3322    if ( !$Self->{PDF} ) {
3323        $Kernel::OM->Get('Kernel::System::Log')->Log(
3324            Priority => 'error',
3325            Message  => "Need a PDF Document!"
3326        );
3327        return;
3328    }
3329    if ( !$Self->{Page} ) {
3330        $Kernel::OM->Get('Kernel::System::Log')->Log(
3331            Priority => 'error',
3332            Message  => "Need a Page!"
3333        );
3334        return;
3335    }
3336
3337    my %Data;
3338    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3339        $Data{Top}    = $Self->{Current}->{PrintableTop};
3340        $Data{Right}  = $Self->{Current}->{PrintableRight};
3341        $Data{Bottom} = $Self->{Current}->{PrintableBottom};
3342        $Data{Left}   = $Self->{Current}->{PrintableLeft};
3343        $Data{Width}  = $Self->{Current}->{PrintableWidth};
3344        $Data{Height} = $Self->{Current}->{PrintableHeight};
3345    }
3346
3347    return %Data;
3348}
3349
3350=head2 _CurPrintableDimCheck()
3351
3352Check given X an/or Y if inside the printable dimension
3353
3354   $True = $PDFObject->_CurPrintableDimCheck(
3355       X => 200,  # (optional)
3356       Y => 100,  # (optional)
3357   );
3358
3359=cut
3360
3361sub _CurPrintableDimCheck {
3362    my ( $Self, %Param ) = @_;
3363
3364    if ( !$Self->{PDF} ) {
3365        $Kernel::OM->Get('Kernel::System::Log')->Log(
3366            Priority => 'error',
3367            Message  => "Need a PDF Document!"
3368        );
3369        return;
3370    }
3371    if ( !$Self->{Page} ) {
3372        $Kernel::OM->Get('Kernel::System::Log')->Log(
3373            Priority => 'error',
3374            Message  => "Need a Page!"
3375        );
3376        return;
3377    }
3378
3379    my $Return    = 0;
3380    my %Printable = $Self->_CurPrintableDimGet();
3381
3382    if ( defined( $Param{X} ) ) {
3383        if (
3384            $Param{X} >= $Printable{Left}
3385            && $Param{X} <= ( $Printable{Left} + $Printable{Width} )
3386            )
3387        {
3388            $Return = 1;
3389        }
3390    }
3391
3392    if ( defined( $Param{Y} ) ) {
3393        if (
3394            $Param{Y} >= $Printable{Bottom}
3395            && $Param{Y} <= ( $Printable{Bottom} + $Printable{Height} )
3396            )
3397        {
3398            $Return = 1;
3399        }
3400    }
3401
3402    return $Return;
3403}
3404
3405=head2 _CurContentDimSet()
3406
3407Set current Content Dimension
3408
3409   $True = $PDFObject->_CurContentDimSet(
3410       Top    => 20,  # (optional)
3411       Right  => 20,  # (optional)
3412       Bottom => 20,  # (optional)
3413       Left   => 20,  # (optional)
3414   );
3415
3416=cut
3417
3418sub _CurContentDimSet {
3419    my ( $Self, %Param ) = @_;
3420
3421    if ( !$Self->{PDF} ) {
3422        $Kernel::OM->Get('Kernel::System::Log')->Log(
3423            Priority => 'error',
3424            Message  => "Need a PDF Document!"
3425        );
3426        return;
3427    }
3428    if ( !$Self->{Page} ) {
3429        $Kernel::OM->Get('Kernel::System::Log')->Log(
3430            Priority => 'error',
3431            Message  => "Need a Page!"
3432        );
3433        return;
3434    }
3435
3436    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3437        my $NewValue;
3438
3439        # set CurContentTop
3440        if (
3441            defined( $Param{Top} )
3442            && $Param{Top} >= $Self->{Current}->{PrintableTop}
3443            && $Param{Top} < $Self->{Current}->{PageHeight} / 2
3444            )
3445        {
3446            $Self->{Current}->{ContentTop} = $Param{Top};
3447            $NewValue = 1;
3448        }
3449
3450        # set CurContentRight
3451        if (
3452            defined( $Param{Right} )
3453            && $Param{Right} >= $Self->{Current}->{PrintableRight}
3454            && $Param{Right} < $Self->{Current}->{PageWidth} / 2
3455            )
3456        {
3457            $Self->{Current}->{ContentRight} = $Param{Right};
3458            $NewValue = 1;
3459        }
3460
3461        # set CurContentBottom
3462        if (
3463            defined( $Param{Bottom} )
3464            && $Param{Bottom} >= $Self->{Current}->{PrintableBottom}
3465            && $Param{Bottom} < $Self->{Current}->{PageHeight} / 2
3466            )
3467        {
3468            $Self->{Current}->{ContentBottom} = $Param{Bottom};
3469            $NewValue = 1;
3470        }
3471
3472        # set CurContentLeft
3473        if (
3474            defined( $Param{Left} )
3475            && $Param{Left} >= $Self->{Current}->{PrintableLeft}
3476            && $Param{Left} < $Self->{Current}->{PageWidth} / 2
3477            )
3478        {
3479            $Self->{Current}->{ContentLeft} = $Param{Left};
3480            $NewValue = 1;
3481        }
3482
3483        if ($NewValue) {
3484
3485            # calculate new content width and height
3486            $Self->{Current}->{ContentWidth} = $Self->{Current}->{PageWidth}
3487                - $Self->{Current}->{ContentLeft}
3488                - $Self->{Current}->{ContentRight};
3489            $Self->{Current}->{ContentHeight} = $Self->{Current}->{PageHeight}
3490                - $Self->{Current}->{ContentTop}
3491                - $Self->{Current}->{ContentBottom};
3492
3493            # set new current position
3494            $Self->{Current}->{PositionX} = $Self->{Current}->{ContentLeft};
3495            $Self->{Current}->{PositionY} = $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop};
3496        }
3497    }
3498
3499    return 1;
3500}
3501
3502=head2 _CurContentDimGet()
3503
3504Get current Content Dimension
3505
3506   Return
3507       $CurContentDim{Top}
3508       $CurContentDim{Right}
3509       $CurContentDim{Bottom}
3510       $CurContentDim{Left}
3511       $CurContentDim{Width}
3512       $CurContentDim{Height}
3513
3514   %CurContentDim = $PDFObject->_CurContentDimGet();
3515
3516=cut
3517
3518sub _CurContentDimGet {
3519    my ( $Self, %Param ) = @_;
3520
3521    if ( !$Self->{PDF} ) {
3522        $Kernel::OM->Get('Kernel::System::Log')->Log(
3523            Priority => 'error',
3524            Message  => "Need a PDF Document!"
3525        );
3526        return;
3527    }
3528    if ( !$Self->{Page} ) {
3529        $Kernel::OM->Get('Kernel::System::Log')->Log(
3530            Priority => 'error',
3531            Message  => "Need a Page!"
3532        );
3533        return;
3534    }
3535
3536    my %Data;
3537    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3538        $Data{Top}    = $Self->{Current}->{ContentTop};
3539        $Data{Right}  = $Self->{Current}->{ContentRight};
3540        $Data{Bottom} = $Self->{Current}->{ContentBottom};
3541        $Data{Left}   = $Self->{Current}->{ContentLeft};
3542        $Data{Width}  = $Self->{Current}->{ContentWidth};
3543        $Data{Height} = $Self->{Current}->{ContentHeight};
3544    }
3545
3546    return %Data;
3547}
3548
3549=head2 _CurContentDimCheck()
3550
3551Check given X an/or Y if inside the content dimension
3552
3553   $True = $PDFObject->_CurContentDimCheck(
3554       X => 200,  # (optional)
3555       Y => 100,  # (optional)
3556   );
3557
3558=cut
3559
3560sub _CurContentDimCheck {
3561    my ( $Self, %Param ) = @_;
3562
3563    if ( !$Self->{PDF} ) {
3564        $Kernel::OM->Get('Kernel::System::Log')->Log(
3565            Priority => 'error',
3566            Message  => "Need a PDF Document!"
3567        );
3568        return;
3569    }
3570    if ( !$Self->{Page} ) {
3571        $Kernel::OM->Get('Kernel::System::Log')->Log(
3572            Priority => 'error',
3573            Message  => "Need a Page!"
3574        );
3575        return;
3576    }
3577
3578    my $Return  = 0;
3579    my %Content = $Self->_CurContentDimGet();
3580
3581    if ( defined( $Param{X} ) ) {
3582        if ( $Param{X} >= $Content{Left} && $Param{X} <= ( $Content{Left} + $Content{Width} ) ) {
3583            $Return = 1;
3584        }
3585    }
3586
3587    if ( defined( $Param{Y} ) ) {
3588        if ( $Param{Y} >= $Content{Bottom} && $Param{Y} <= ( $Content{Bottom} + $Content{Height} ) )
3589        {
3590            $Return = 1;
3591        }
3592    }
3593
3594    return $Return;
3595}
3596
3597=head2 _CurPositionSet()
3598
3599Set current Position
3600
3601   $True = $PDFObject->_CurPositionSet(
3602       X => 20,  # (optional)
3603       Y => 20,  # (optional)
3604   );
3605
3606=cut
3607
3608sub _CurPositionSet {
3609    my ( $Self, %Param ) = @_;
3610
3611    if ( !$Self->{PDF} ) {
3612        $Kernel::OM->Get('Kernel::System::Log')->Log(
3613            Priority => 'error',
3614            Message  => "Need a PDF Document!"
3615        );
3616        return;
3617    }
3618    if ( !$Self->{Page} ) {
3619        $Kernel::OM->Get('Kernel::System::Log')->Log(
3620            Priority => 'error',
3621            Message  => "Need a Page!"
3622        );
3623        return;
3624    }
3625
3626    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3627        if ( $Self->DimGet() eq 'printable' ) {
3628            if (
3629                defined( $Param{X} )
3630                && $Param{X} >= $Self->{Current}->{PrintableLeft}
3631                && $Param{X} <= $Self->{Current}->{PageWidth} - $Self->{Current}->{PrintableRight}
3632                )
3633            {
3634                $Self->{Current}->{PositionX} = $Param{X};
3635            }
3636            if (
3637                defined( $Param{Y} )
3638                && $Param{Y} <= $Self->{Current}->{PageHeight} - $Self->{Current}->{PrintableTop}
3639                && $Param{Y} >= $Self->{Current}->{PrintableBottom}
3640                )
3641            {
3642                $Self->{Current}->{PositionY} = $Param{Y};
3643            }
3644        }
3645        else {
3646            if (
3647                defined( $Param{X} )
3648                && $Param{X} >= $Self->{Current}->{ContentLeft}
3649                && $Param{X} <= $Self->{Current}->{PageWidth} - $Self->{Current}->{ContentRight}
3650                )
3651            {
3652                $Self->{Current}->{PositionX} = $Param{X};
3653            }
3654            if (
3655                defined( $Param{Y} )
3656                && $Param{Y} <= $Self->{Current}->{PageHeight} - $Self->{Current}->{ContentTop}
3657                && $Param{Y} >= $Self->{Current}->{ContentBottom}
3658                )
3659            {
3660                $Self->{Current}->{PositionY} = $Param{Y};
3661            }
3662        }
3663    }
3664
3665    return 1;
3666}
3667
3668=head2 _CurPositionGet()
3669
3670Get current Position
3671
3672   Return
3673       $CurPosition{X}
3674       $CurPosition{Y}
3675
3676   %CurPosition = $PDFObject->_CurPositionGet();
3677
3678=cut
3679
3680sub _CurPositionGet {
3681    my ( $Self, %Param ) = @_;
3682
3683    if ( !$Self->{PDF} ) {
3684        $Kernel::OM->Get('Kernel::System::Log')->Log(
3685            Priority => 'error',
3686            Message  => "Need a PDF Document!"
3687        );
3688        return;
3689    }
3690    if ( !$Self->{Page} ) {
3691        $Kernel::OM->Get('Kernel::System::Log')->Log(
3692            Priority => 'error',
3693            Message  => "Need a Page!"
3694        );
3695        return;
3696    }
3697
3698    my %Data;
3699    if ( $Self->{Current}->{PageWidth} && $Self->{Current}->{PageHeight} ) {
3700        $Data{X} = $Self->{Current}->{PositionX};
3701        $Data{Y} = $Self->{Current}->{PositionY};
3702    }
3703
3704    return %Data;
3705}
3706
3707sub DESTROY {
3708    my ( $Self, %Param ) = @_;
3709
3710    # set cache
3711    $Kernel::OM->Get('Kernel::System::Cache')->Set(
3712        Type  => 'PDF',
3713        TTL   => 60 * 60 * 24 * 20,
3714        Key   => 'CacheStringWidth',
3715        Value => $Self->{CacheStringWidth},
3716    );
3717
3718    return 1;
3719}
3720
37211;
3722
3723=end Internal:
3724
3725=head1 TERMS AND CONDITIONS
3726
3727This software is part of the OTRS project (L<https://otrs.org/>).
3728
3729This software comes with ABSOLUTELY NO WARRANTY. For details, see
3730the enclosed file COPYING for license information (GPL). If you
3731did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
3732
3733=cut
3734