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