xref: /webtrees/app/Report/AbstractRenderer.php (revision b6f35a76f16ee5da672b7d3d886becc6b838498e)
1*b6f35a76SGreg Roach<?php
2*b6f35a76SGreg Roach
3*b6f35a76SGreg Roach/**
4*b6f35a76SGreg Roach * webtrees: online genealogy
5*b6f35a76SGreg Roach * Copyright (C) 2019 webtrees development team
6*b6f35a76SGreg Roach * This program is free software: you can redistribute it and/or modify
7*b6f35a76SGreg Roach * it under the terms of the GNU General Public License as published by
8*b6f35a76SGreg Roach * the Free Software Foundation, either version 3 of the License, or
9*b6f35a76SGreg Roach * (at your option) any later version.
10*b6f35a76SGreg Roach * This program is distributed in the hope that it will be useful,
11*b6f35a76SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*b6f35a76SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*b6f35a76SGreg Roach * GNU General Public License for more details.
14*b6f35a76SGreg Roach * You should have received a copy of the GNU General Public License
15*b6f35a76SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
16*b6f35a76SGreg Roach */
17*b6f35a76SGreg Roach
18*b6f35a76SGreg Roachdeclare(strict_types=1);
19*b6f35a76SGreg Roach
20*b6f35a76SGreg Roachnamespace Fisharebest\Webtrees\Report;
21*b6f35a76SGreg Roach
22*b6f35a76SGreg Roachuse Fisharebest\Webtrees\I18N;
23*b6f35a76SGreg Roachuse Fisharebest\Webtrees\MediaFile;
24*b6f35a76SGreg Roachuse Fisharebest\Webtrees\Webtrees;
25*b6f35a76SGreg Roachuse League\Flysystem\FilesystemInterface;
26*b6f35a76SGreg Roach
27*b6f35a76SGreg Roachuse function current;
28*b6f35a76SGreg Roach
29*b6f35a76SGreg Roach/**
30*b6f35a76SGreg Roach * Class AbstractRenderer - base for PDF and HTML reports
31*b6f35a76SGreg Roach */
32*b6f35a76SGreg Roachabstract class AbstractRenderer
33*b6f35a76SGreg Roach{
34*b6f35a76SGreg Roach    // Reports layouts are measured in points.
35*b6f35a76SGreg Roach    protected const UNITS = 'pt';
36*b6f35a76SGreg Roach
37*b6f35a76SGreg Roach    // A point is 1/72 of an inch
38*b6f35a76SGreg Roach    protected const INCH_TO_POINTS = 72.0;
39*b6f35a76SGreg Roach    protected const MM_TO_POINTS   = 72.0 / 25.4;
40*b6f35a76SGreg Roach
41*b6f35a76SGreg Roach    protected const PAPER_SIZES = [
42*b6f35a76SGreg Roach        // ISO 216
43*b6f35a76SGreg Roach        'A0'         => [841.0 * self::MM_TO_POINTS, 1189.0 * self::MM_TO_POINTS],
44*b6f35a76SGreg Roach        'A1'         => [594.0 * self::MM_TO_POINTS, 841.0 * self::MM_TO_POINTS],
45*b6f35a76SGreg Roach        'A2'         => [420.0 * self::MM_TO_POINTS, 594.0 * self::MM_TO_POINTS],
46*b6f35a76SGreg Roach        'A3'         => [297.0 * self::MM_TO_POINTS, 420.0 * self::MM_TO_POINTS],
47*b6f35a76SGreg Roach        'A4'         => [210.0 * self::MM_TO_POINTS, 297.0 * self::MM_TO_POINTS],
48*b6f35a76SGreg Roach        // US
49*b6f35a76SGreg Roach        'US-Letter'  => [8.5 * self::INCH_TO_POINTS, 11.0 * self::INCH_TO_POINTS],
50*b6f35a76SGreg Roach        'US-Legal'   => [8.5 * self::INCH_TO_POINTS, 14.0 * self::INCH_TO_POINTS],
51*b6f35a76SGreg Roach        'US-Tabloid' => [11.0 * self::INCH_TO_POINTS, 17.0 * self::INCH_TO_POINTS],
52*b6f35a76SGreg Roach    ];
53*b6f35a76SGreg Roach
54*b6f35a76SGreg Roach    /** @var float Left Margin */
55*b6f35a76SGreg Roach    public $left_margin = 18.0 * self::MM_TO_POINTS;
56*b6f35a76SGreg Roach
57*b6f35a76SGreg Roach    /** @var float Right Margin */
58*b6f35a76SGreg Roach    public $right_margin = 9.9 * self::MM_TO_POINTS;
59*b6f35a76SGreg Roach
60*b6f35a76SGreg Roach    /** @var float Top Margin */
61*b6f35a76SGreg Roach    public $top_margin = 26.8 * self::MM_TO_POINTS;
62*b6f35a76SGreg Roach
63*b6f35a76SGreg Roach    /** @var float Bottom Margin */
64*b6f35a76SGreg Roach    public $bottom_margin = 21.6 * self::MM_TO_POINTS;
65*b6f35a76SGreg Roach
66*b6f35a76SGreg Roach    /** @var float Header Margin */
67*b6f35a76SGreg Roach    public $header_margin = 4.9 * self::MM_TO_POINTS;
68*b6f35a76SGreg Roach
69*b6f35a76SGreg Roach    /** @var float Footer Margin */
70*b6f35a76SGreg Roach    public $footer_margin = 9.9 * self::MM_TO_POINTS;
71*b6f35a76SGreg Roach
72*b6f35a76SGreg Roach    /** @var string Page orientation (portrait, landscape) */
73*b6f35a76SGreg Roach    public $orientation = 'portrait';
74*b6f35a76SGreg Roach
75*b6f35a76SGreg Roach    /** @var string Page format name */
76*b6f35a76SGreg Roach    public $page_format = 'A4';
77*b6f35a76SGreg Roach
78*b6f35a76SGreg Roach    /** @var float Height of page format in points */
79*b6f35a76SGreg Roach    public $page_height = 0.0;
80*b6f35a76SGreg Roach
81*b6f35a76SGreg Roach    /** @var float Width of page format in points */
82*b6f35a76SGreg Roach    public $page_width = 0.0;
83*b6f35a76SGreg Roach
84*b6f35a76SGreg Roach    /** @var string[][] An array of the Styles elements found in the document */
85*b6f35a76SGreg Roach    public $styles = [];
86*b6f35a76SGreg Roach
87*b6f35a76SGreg Roach    /** @var string The default Report font name */
88*b6f35a76SGreg Roach    public $default_font = 'dejavusans';
89*b6f35a76SGreg Roach
90*b6f35a76SGreg Roach    /** @var float The default Report font size */
91*b6f35a76SGreg Roach    public $default_font_size = 12.0;
92*b6f35a76SGreg Roach
93*b6f35a76SGreg Roach    /** @var string Header (H), Page header (PH), Body (B) or Footer (F) */
94*b6f35a76SGreg Roach    public $processing = 'H';
95*b6f35a76SGreg Roach
96*b6f35a76SGreg Roach    /** @var bool RTL Language (false=LTR, true=RTL) */
97*b6f35a76SGreg Roach    public $rtl = false;
98*b6f35a76SGreg Roach
99*b6f35a76SGreg Roach    /** @var bool Show the Generated by... (true=show the text) */
100*b6f35a76SGreg Roach    public $show_generated_by = true;
101*b6f35a76SGreg Roach
102*b6f35a76SGreg Roach    /** @var string Generated By... text */
103*b6f35a76SGreg Roach    public $generated_by = '';
104*b6f35a76SGreg Roach
105*b6f35a76SGreg Roach    /** @var string The report title */
106*b6f35a76SGreg Roach    public $title = '';
107*b6f35a76SGreg Roach
108*b6f35a76SGreg Roach    /** @var string Author of the report, the users full name */
109*b6f35a76SGreg Roach    public $rauthor = Webtrees::NAME . ' ' . Webtrees::VERSION;
110*b6f35a76SGreg Roach
111*b6f35a76SGreg Roach    /** @var string Keywords */
112*b6f35a76SGreg Roach    public $rkeywords = '';
113*b6f35a76SGreg Roach
114*b6f35a76SGreg Roach    /** @var string Report Description / Subject */
115*b6f35a76SGreg Roach    public $rsubject = '';
116*b6f35a76SGreg Roach
117*b6f35a76SGreg Roach    /**
118*b6f35a76SGreg Roach     * Clear the Header.
119*b6f35a76SGreg Roach     *
120*b6f35a76SGreg Roach     * @return void
121*b6f35a76SGreg Roach     */
122*b6f35a76SGreg Roach    abstract public function clearHeader(): void;
123*b6f35a76SGreg Roach
124*b6f35a76SGreg Roach    /**
125*b6f35a76SGreg Roach     * Create a new Page Header object
126*b6f35a76SGreg Roach     *
127*b6f35a76SGreg Roach     * @return ReportBasePageHeader
128*b6f35a76SGreg Roach     */
129*b6f35a76SGreg Roach    abstract public function createPageHeader(): ReportBasePageHeader;
130*b6f35a76SGreg Roach
131*b6f35a76SGreg Roach    /**
132*b6f35a76SGreg Roach     * Add an element.
133*b6f35a76SGreg Roach     *
134*b6f35a76SGreg Roach     * @param ReportBaseElement|string $element
135*b6f35a76SGreg Roach     *
136*b6f35a76SGreg Roach     * @return void
137*b6f35a76SGreg Roach     */
138*b6f35a76SGreg Roach    abstract public function addElement($element): void;
139*b6f35a76SGreg Roach
140*b6f35a76SGreg Roach    /**
141*b6f35a76SGreg Roach     * Run the report.
142*b6f35a76SGreg Roach     *
143*b6f35a76SGreg Roach     * @return void
144*b6f35a76SGreg Roach     */
145*b6f35a76SGreg Roach    abstract public function run(): void;
146*b6f35a76SGreg Roach
147*b6f35a76SGreg Roach    /**
148*b6f35a76SGreg Roach     * Create a new Cell object.
149*b6f35a76SGreg Roach     *
150*b6f35a76SGreg Roach     * @param int    $width   cell width (expressed in points)
151*b6f35a76SGreg Roach     * @param int    $height  cell height (expressed in points)
152*b6f35a76SGreg Roach     * @param mixed  $border  Border style
153*b6f35a76SGreg Roach     * @param string $align   Text alignement
154*b6f35a76SGreg Roach     * @param string $bgcolor Background color code
155*b6f35a76SGreg Roach     * @param string $style   The name of the text style
156*b6f35a76SGreg Roach     * @param int    $ln      Indicates where the current position should go after the call
157*b6f35a76SGreg Roach     * @param mixed  $top     Y-position
158*b6f35a76SGreg Roach     * @param mixed  $left    X-position
159*b6f35a76SGreg Roach     * @param int    $fill    Indicates if the cell background must be painted (1) or transparent (0). Default value: 1
160*b6f35a76SGreg Roach     * @param int    $stretch Stretch carachter mode
161*b6f35a76SGreg Roach     * @param string $bocolor Border color
162*b6f35a76SGreg Roach     * @param string $tcolor  Text color
163*b6f35a76SGreg Roach     * @param bool   $reseth
164*b6f35a76SGreg Roach     *
165*b6f35a76SGreg Roach     * @return ReportBaseCell
166*b6f35a76SGreg Roach     */
167*b6f35a76SGreg Roach    abstract public function createCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth): ReportBaseCell;
168*b6f35a76SGreg Roach
169*b6f35a76SGreg Roach    /**
170*b6f35a76SGreg Roach     * Create a new TextBox object.
171*b6f35a76SGreg Roach     *
172*b6f35a76SGreg Roach     * @param float  $width   Text box width
173*b6f35a76SGreg Roach     * @param float  $height  Text box height
174*b6f35a76SGreg Roach     * @param bool   $border
175*b6f35a76SGreg Roach     * @param string $bgcolor Background color code in HTML
176*b6f35a76SGreg Roach     * @param bool   $newline
177*b6f35a76SGreg Roach     * @param float  $left
178*b6f35a76SGreg Roach     * @param float  $top
179*b6f35a76SGreg Roach     * @param bool   $pagecheck
180*b6f35a76SGreg Roach     * @param string $style
181*b6f35a76SGreg Roach     * @param bool   $fill
182*b6f35a76SGreg Roach     * @param bool   $padding
183*b6f35a76SGreg Roach     * @param bool   $reseth
184*b6f35a76SGreg Roach     *
185*b6f35a76SGreg Roach     * @return ReportBaseTextbox
186*b6f35a76SGreg Roach     */
187*b6f35a76SGreg Roach    abstract public function createTextBox(
188*b6f35a76SGreg Roach        float $width,
189*b6f35a76SGreg Roach        float $height,
190*b6f35a76SGreg Roach        bool $border,
191*b6f35a76SGreg Roach        string $bgcolor,
192*b6f35a76SGreg Roach        bool $newline,
193*b6f35a76SGreg Roach        float $left,
194*b6f35a76SGreg Roach        float $top,
195*b6f35a76SGreg Roach        bool $pagecheck,
196*b6f35a76SGreg Roach        string $style,
197*b6f35a76SGreg Roach        bool $fill,
198*b6f35a76SGreg Roach        bool $padding,
199*b6f35a76SGreg Roach        bool $reseth
200*b6f35a76SGreg Roach    ): ReportBaseTextbox;
201*b6f35a76SGreg Roach
202*b6f35a76SGreg Roach    /**
203*b6f35a76SGreg Roach     * Create a text element.
204*b6f35a76SGreg Roach     *
205*b6f35a76SGreg Roach     * @param string $style
206*b6f35a76SGreg Roach     * @param string $color
207*b6f35a76SGreg Roach     *
208*b6f35a76SGreg Roach     * @return ReportBaseText
209*b6f35a76SGreg Roach     */
210*b6f35a76SGreg Roach    abstract public function createText(string $style, string $color): ReportBaseText;
211*b6f35a76SGreg Roach
212*b6f35a76SGreg Roach    /**
213*b6f35a76SGreg Roach     * Create an HTML element.
214*b6f35a76SGreg Roach     *
215*b6f35a76SGreg Roach     * @param string   $tag
216*b6f35a76SGreg Roach     * @param string[] $attrs
217*b6f35a76SGreg Roach     *
218*b6f35a76SGreg Roach     * @return ReportBaseHtml
219*b6f35a76SGreg Roach     */
220*b6f35a76SGreg Roach    abstract public function createHTML(string $tag, array $attrs): ReportBaseHtml;
221*b6f35a76SGreg Roach
222*b6f35a76SGreg Roach    /**
223*b6f35a76SGreg Roach     * Create a line.
224*b6f35a76SGreg Roach     *
225*b6f35a76SGreg Roach     * @param float $x1
226*b6f35a76SGreg Roach     * @param float $y1
227*b6f35a76SGreg Roach     * @param float $x2
228*b6f35a76SGreg Roach     * @param float $y2
229*b6f35a76SGreg Roach     *
230*b6f35a76SGreg Roach     * @return ReportBaseLine
231*b6f35a76SGreg Roach     */
232*b6f35a76SGreg Roach    abstract public function createLine(float $x1, float $y1, float $x2, float $y2): ReportBaseLine;
233*b6f35a76SGreg Roach
234*b6f35a76SGreg Roach    /**
235*b6f35a76SGreg Roach     * Create a new image object.
236*b6f35a76SGreg Roach     *
237*b6f35a76SGreg Roach     * @param string $file  Filename
238*b6f35a76SGreg Roach     * @param float  $x
239*b6f35a76SGreg Roach     * @param float  $y
240*b6f35a76SGreg Roach     * @param float  $w     Image width
241*b6f35a76SGreg Roach     * @param float  $h     Image height
242*b6f35a76SGreg Roach     * @param string $align L:left, C:center, R:right or empty to use x/y
243*b6f35a76SGreg Roach     * @param string $ln    T:same line, N:next line
244*b6f35a76SGreg Roach     *
245*b6f35a76SGreg Roach     * @return ReportBaseImage
246*b6f35a76SGreg Roach     */
247*b6f35a76SGreg Roach    abstract public function createImage(string $file, float $x, float $y, float $w, float $h, string $align, string $ln): ReportBaseImage;
248*b6f35a76SGreg Roach
249*b6f35a76SGreg Roach    /**
250*b6f35a76SGreg Roach     * Create a new image object from Media Object.
251*b6f35a76SGreg Roach     *
252*b6f35a76SGreg Roach     * @param MediaFile           $media_file
253*b6f35a76SGreg Roach     * @param float               $x
254*b6f35a76SGreg Roach     * @param float               $y
255*b6f35a76SGreg Roach     * @param float               $w     Image width
256*b6f35a76SGreg Roach     * @param float               $h     Image height
257*b6f35a76SGreg Roach     * @param string              $align L:left, C:center, R:right or empty to use x/y
258*b6f35a76SGreg Roach     * @param string              $ln    T:same line, N:next line
259*b6f35a76SGreg Roach     * @param FilesystemInterface $data_filesystem
260*b6f35a76SGreg Roach     *
261*b6f35a76SGreg Roach     * @return ReportBaseImage
262*b6f35a76SGreg Roach     */
263*b6f35a76SGreg Roach    abstract public function createImageFromObject(
264*b6f35a76SGreg Roach        MediaFile $media_file,
265*b6f35a76SGreg Roach        float $x,
266*b6f35a76SGreg Roach        float $y,
267*b6f35a76SGreg Roach        float $w,
268*b6f35a76SGreg Roach        float $h,
269*b6f35a76SGreg Roach        string $align,
270*b6f35a76SGreg Roach        string $ln,
271*b6f35a76SGreg Roach        FilesystemInterface $data_filesystem
272*b6f35a76SGreg Roach    ): ReportBaseImage;
273*b6f35a76SGreg Roach
274*b6f35a76SGreg Roach    /**
275*b6f35a76SGreg Roach     * Create a new Footnote object.
276*b6f35a76SGreg Roach     *
277*b6f35a76SGreg Roach     * @param string $style Style name
278*b6f35a76SGreg Roach     *
279*b6f35a76SGreg Roach     * @return ReportBaseFootnote
280*b6f35a76SGreg Roach     */
281*b6f35a76SGreg Roach    abstract public function createFootnote($style): ReportBaseFootnote;
282*b6f35a76SGreg Roach
283*b6f35a76SGreg Roach    /**
284*b6f35a76SGreg Roach     * Initial Setup
285*b6f35a76SGreg Roach     * Setting up document wide defaults that will be inherited of the report modules
286*b6f35a76SGreg Roach     * As DEFAULT A4 and Portrait will be used if not set
287*b6f35a76SGreg Roach     *
288*b6f35a76SGreg Roach     * @return void
289*b6f35a76SGreg Roach     */
290*b6f35a76SGreg Roach    public function setup(): void
291*b6f35a76SGreg Roach    {
292*b6f35a76SGreg Roach        $this->rtl = I18N::direction() === 'rtl';
293*b6f35a76SGreg Roach
294*b6f35a76SGreg Roach        $this->rkeywords = '';
295*b6f35a76SGreg Roach
296*b6f35a76SGreg Roach        // I18N: This is a report footer. %s is the name of the application.
297*b6f35a76SGreg Roach        $this->generated_by = I18N::translate('Generated by %s', Webtrees::NAME . ' ' . Webtrees::VERSION);
298*b6f35a76SGreg Roach
299*b6f35a76SGreg Roach        // Paper size - defaults to A4 if the report fails to define a size.
300*b6f35a76SGreg Roach        [$this->page_width, $this->page_height] = self::PAPER_SIZES[$this->page_format] ?? self::PAPER_SIZES['A4'];
301*b6f35a76SGreg Roach    }
302*b6f35a76SGreg Roach
303*b6f35a76SGreg Roach    /**
304*b6f35a76SGreg Roach     * Process the Header , Page header, Body or Footer
305*b6f35a76SGreg Roach     *
306*b6f35a76SGreg Roach     * @param string $p Header (H), Page header (PH), Body (B) or Footer (F)
307*b6f35a76SGreg Roach     *
308*b6f35a76SGreg Roach     * @return void
309*b6f35a76SGreg Roach     */
310*b6f35a76SGreg Roach    public function setProcessing(string $p): void
311*b6f35a76SGreg Roach    {
312*b6f35a76SGreg Roach        $this->processing = $p;
313*b6f35a76SGreg Roach    }
314*b6f35a76SGreg Roach
315*b6f35a76SGreg Roach    /**
316*b6f35a76SGreg Roach     * Add the Title when raw character data is used in Title
317*b6f35a76SGreg Roach     *
318*b6f35a76SGreg Roach     * @param string $data
319*b6f35a76SGreg Roach     *
320*b6f35a76SGreg Roach     * @return void
321*b6f35a76SGreg Roach     */
322*b6f35a76SGreg Roach    public function addTitle(string $data): void
323*b6f35a76SGreg Roach    {
324*b6f35a76SGreg Roach        $this->title .= $data;
325*b6f35a76SGreg Roach    }
326*b6f35a76SGreg Roach
327*b6f35a76SGreg Roach    /**
328*b6f35a76SGreg Roach     * Add the Description when raw character data is used in Description
329*b6f35a76SGreg Roach     *
330*b6f35a76SGreg Roach     * @param string $data
331*b6f35a76SGreg Roach     *
332*b6f35a76SGreg Roach     * @return void
333*b6f35a76SGreg Roach     */
334*b6f35a76SGreg Roach    public function addDescription(string $data): void
335*b6f35a76SGreg Roach    {
336*b6f35a76SGreg Roach        $this->rsubject .= $data;
337*b6f35a76SGreg Roach    }
338*b6f35a76SGreg Roach
339*b6f35a76SGreg Roach    /**
340*b6f35a76SGreg Roach     * Add Style to Styles array
341*b6f35a76SGreg Roach     *
342*b6f35a76SGreg Roach     * @param string[] $style
343*b6f35a76SGreg Roach     *
344*b6f35a76SGreg Roach     * @return void
345*b6f35a76SGreg Roach     */
346*b6f35a76SGreg Roach    public function addStyle(array $style): void
347*b6f35a76SGreg Roach    {
348*b6f35a76SGreg Roach        $this->styles[$style['name']] = $style;
349*b6f35a76SGreg Roach    }
350*b6f35a76SGreg Roach
351*b6f35a76SGreg Roach    /**
352*b6f35a76SGreg Roach     * Get a style from the Styles array
353*b6f35a76SGreg Roach     *
354*b6f35a76SGreg Roach     * @param string $s Style name
355*b6f35a76SGreg Roach     *
356*b6f35a76SGreg Roach     * @return array
357*b6f35a76SGreg Roach     */
358*b6f35a76SGreg Roach    public function getStyle(string $s): array
359*b6f35a76SGreg Roach    {
360*b6f35a76SGreg Roach        if (!isset($this->styles[$s])) {
361*b6f35a76SGreg Roach            return current($this->styles);
362*b6f35a76SGreg Roach        }
363*b6f35a76SGreg Roach
364*b6f35a76SGreg Roach        return $this->styles[$s];
365*b6f35a76SGreg Roach    }
366*b6f35a76SGreg Roach}
367