1b6f35a76SGreg Roach<?php 2b6f35a76SGreg Roach 3b6f35a76SGreg Roach/** 4b6f35a76SGreg Roach * webtrees: online genealogy 5*89f7189bSGreg Roach * Copyright (C) 2021 webtrees development team 6b6f35a76SGreg Roach * This program is free software: you can redistribute it and/or modify 7b6f35a76SGreg Roach * it under the terms of the GNU General Public License as published by 8b6f35a76SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9b6f35a76SGreg Roach * (at your option) any later version. 10b6f35a76SGreg Roach * This program is distributed in the hope that it will be useful, 11b6f35a76SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12b6f35a76SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13b6f35a76SGreg Roach * GNU General Public License for more details. 14b6f35a76SGreg Roach * You should have received a copy of the GNU General Public License 15*89f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 16b6f35a76SGreg Roach */ 17b6f35a76SGreg Roach 18b6f35a76SGreg Roachdeclare(strict_types=1); 19b6f35a76SGreg Roach 20b6f35a76SGreg Roachnamespace Fisharebest\Webtrees\Report; 21b6f35a76SGreg Roach 22b6f35a76SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsRtl; 23b6f35a76SGreg Roachuse Fisharebest\Webtrees\I18N; 24b6f35a76SGreg Roachuse Fisharebest\Webtrees\MediaFile; 25b6f35a76SGreg Roachuse Fisharebest\Webtrees\Webtrees; 26b6f35a76SGreg Roachuse League\Flysystem\FilesystemInterface; 27b6f35a76SGreg Roach 28b6f35a76SGreg Roachuse function ceil; 29b6f35a76SGreg Roachuse function count; 30b6f35a76SGreg Roachuse function explode; 31b6f35a76SGreg Roachuse function preg_match; 32b6f35a76SGreg Roachuse function str_replace; 33b6f35a76SGreg Roachuse function stripos; 34b6f35a76SGreg Roachuse function substr_count; 35b6f35a76SGreg Roach 36b6f35a76SGreg Roach/** 37b6f35a76SGreg Roach * Class HtmlRenderer 38b6f35a76SGreg Roach */ 39b6f35a76SGreg Roachclass HtmlRenderer extends AbstractRenderer 40b6f35a76SGreg Roach{ 41b6f35a76SGreg Roach /** 42b6f35a76SGreg Roach * Cell padding 43b6f35a76SGreg Roach * 44b6f35a76SGreg Roach * @var float 45b6f35a76SGreg Roach */ 46b6f35a76SGreg Roach public $cPadding = 2; 47b6f35a76SGreg Roach 48b6f35a76SGreg Roach /** 49b6f35a76SGreg Roach * Cell height ratio 50b6f35a76SGreg Roach * 51b6f35a76SGreg Roach * @var float 52b6f35a76SGreg Roach */ 53b6f35a76SGreg Roach public $cellHeightRatio = 1.8; 54b6f35a76SGreg Roach 55b6f35a76SGreg Roach /** 56b6f35a76SGreg Roach * Current horizontal position 57b6f35a76SGreg Roach * 58b6f35a76SGreg Roach * @var float 59b6f35a76SGreg Roach */ 60b6f35a76SGreg Roach public $X = 0.0; 61b6f35a76SGreg Roach 62b6f35a76SGreg Roach /** 63b6f35a76SGreg Roach * Current vertical position 64b6f35a76SGreg Roach * 65b6f35a76SGreg Roach * @var float 66b6f35a76SGreg Roach */ 67b6f35a76SGreg Roach public $Y = 0.0; 68b6f35a76SGreg Roach 69b6f35a76SGreg Roach /** 70b6f35a76SGreg Roach * Currently used style name 71b6f35a76SGreg Roach * 72b6f35a76SGreg Roach * @var string 73b6f35a76SGreg Roach */ 74b6f35a76SGreg Roach public $currentStyle = ''; 75b6f35a76SGreg Roach 76b6f35a76SGreg Roach /** 77b6f35a76SGreg Roach * Page number counter 78b6f35a76SGreg Roach * 79b6f35a76SGreg Roach * @var int 80b6f35a76SGreg Roach */ 81b6f35a76SGreg Roach public $pageN = 1; 82b6f35a76SGreg Roach 83b6f35a76SGreg Roach /** 84b6f35a76SGreg Roach * Store the page width without left and right margins 85b6f35a76SGreg Roach * 86b6f35a76SGreg Roach * In HTML, we don't need this 87b6f35a76SGreg Roach * 88b6f35a76SGreg Roach * @var float 89b6f35a76SGreg Roach */ 90b6f35a76SGreg Roach public $noMarginWidth = 0.0; 91b6f35a76SGreg Roach 92b6f35a76SGreg Roach /** 93b6f35a76SGreg Roach * Last cell height 94b6f35a76SGreg Roach * 95b6f35a76SGreg Roach * @var float 96b6f35a76SGreg Roach */ 97b6f35a76SGreg Roach public $lastCellHeight = 0.0; 98b6f35a76SGreg Roach 99b6f35a76SGreg Roach /** 100b6f35a76SGreg Roach * LTR or RTL alignement; "left" on LTR, "right" on RTL 101b6f35a76SGreg Roach * Used in <div> 102b6f35a76SGreg Roach * 103b6f35a76SGreg Roach * @var string 104b6f35a76SGreg Roach */ 105b6f35a76SGreg Roach public $alignRTL = 'left'; 106b6f35a76SGreg Roach 107b6f35a76SGreg Roach /** 108b6f35a76SGreg Roach * LTR or RTL entity 109b6f35a76SGreg Roach * 110b6f35a76SGreg Roach * @var string 111b6f35a76SGreg Roach */ 112b6f35a76SGreg Roach public $entityRTL = '‎'; 113b6f35a76SGreg Roach 114b6f35a76SGreg Roach /** 115b6f35a76SGreg Roach * Largest Font Height is used by TextBox etc. 116b6f35a76SGreg Roach * 117b6f35a76SGreg Roach * Use this to calculate a the text height. 118b6f35a76SGreg Roach * This makes sure that the text fits into the cell/box when different font sizes are used 119b6f35a76SGreg Roach * 120b6f35a76SGreg Roach * @var float 121b6f35a76SGreg Roach */ 122b6f35a76SGreg Roach public $largestFontHeight = 0; 123b6f35a76SGreg Roach 124b6f35a76SGreg Roach /** 125b6f35a76SGreg Roach * Keep track of the highest Y position 126b6f35a76SGreg Roach * 127b6f35a76SGreg Roach * Used with Header div / Body div / Footer div / "addpage" / The bottom of the last image etc. 128b6f35a76SGreg Roach * 129b6f35a76SGreg Roach * @var float 130b6f35a76SGreg Roach */ 131b6f35a76SGreg Roach public $maxY = 0; 132b6f35a76SGreg Roach 133b6f35a76SGreg Roach /** @var ReportBaseElement[] Array of elements in the header */ 134b6f35a76SGreg Roach public $headerElements = []; 135b6f35a76SGreg Roach 136b6f35a76SGreg Roach /** @var ReportBaseElement[] Array of elements in the footer */ 137b6f35a76SGreg Roach public $footerElements = []; 138b6f35a76SGreg Roach 139b6f35a76SGreg Roach /** @var ReportBaseElement[] Array of elements in the body */ 140b6f35a76SGreg Roach public $bodyElements = []; 141b6f35a76SGreg Roach 142b6f35a76SGreg Roach /** @var ReportHtmlFootnote[] Array of elements in the footer notes */ 143b6f35a76SGreg Roach public $printedfootnotes = []; 144b6f35a76SGreg Roach 145b6f35a76SGreg Roach /** 146b6f35a76SGreg Roach * HTML Setup - ReportHtml 147b6f35a76SGreg Roach * 148b6f35a76SGreg Roach * @return void 149b6f35a76SGreg Roach */ 150b6f35a76SGreg Roach public function setup(): void 151b6f35a76SGreg Roach { 152b6f35a76SGreg Roach parent::setup(); 153b6f35a76SGreg Roach 154b6f35a76SGreg Roach // Setting up the correct dimensions if Portrait (default) or Landscape 155b6f35a76SGreg Roach if ($this->orientation === 'landscape') { 156b6f35a76SGreg Roach $tmpw = $this->page_width; 157b6f35a76SGreg Roach $this->page_width = $this->page_height; 158b6f35a76SGreg Roach $this->page_height = $tmpw; 159b6f35a76SGreg Roach } 160b6f35a76SGreg Roach // Store the pagewidth without margins 161b6f35a76SGreg Roach $this->noMarginWidth = $this->page_width - $this->left_margin - $this->right_margin; 162b6f35a76SGreg Roach // If RTL 163b6f35a76SGreg Roach if ($this->rtl) { 164b6f35a76SGreg Roach $this->alignRTL = 'right'; 165b6f35a76SGreg Roach $this->entityRTL = '‏'; 166b6f35a76SGreg Roach } 167b6f35a76SGreg Roach // Change the default HTML font name 168b6f35a76SGreg Roach $this->default_font = 'Arial'; 169b6f35a76SGreg Roach 170b6f35a76SGreg Roach if ($this->show_generated_by) { 171b6f35a76SGreg Roach // The default style name for Generated by.... is 'genby' 172b6f35a76SGreg Roach $element = new ReportHtmlCell(0, 10, 0, 'C', '', 'genby', 1, ReportBaseElement::CURRENT_POSITION, ReportBaseElement::CURRENT_POSITION, 0, 0, '', '', true); 173b6f35a76SGreg Roach $element->addText($this->generated_by); 174b6f35a76SGreg Roach $element->setUrl(Webtrees::URL); 175b6f35a76SGreg Roach $this->footerElements[] = $element; 176b6f35a76SGreg Roach } 177b6f35a76SGreg Roach } 178b6f35a76SGreg Roach 179b6f35a76SGreg Roach /** 180b6f35a76SGreg Roach * Add an element. 181b6f35a76SGreg Roach * 182b6f35a76SGreg Roach * @param ReportBaseElement|string $element 183b6f35a76SGreg Roach * 184b6f35a76SGreg Roach * @return void 185b6f35a76SGreg Roach */ 186b6f35a76SGreg Roach public function addElement($element): void 187b6f35a76SGreg Roach { 188b6f35a76SGreg Roach if ($this->processing === 'B') { 189b6f35a76SGreg Roach $this->bodyElements[] = $element; 190b6f35a76SGreg Roach } elseif ($this->processing === 'H') { 191b6f35a76SGreg Roach $this->headerElements[] = $element; 192b6f35a76SGreg Roach } elseif ($this->processing === 'F') { 193b6f35a76SGreg Roach $this->footerElements[] = $element; 194b6f35a76SGreg Roach } 195b6f35a76SGreg Roach } 196b6f35a76SGreg Roach 197b6f35a76SGreg Roach /** 198b6f35a76SGreg Roach * Generate footnotes 199b6f35a76SGreg Roach * 200b6f35a76SGreg Roach * @return void 201b6f35a76SGreg Roach */ 202b6f35a76SGreg Roach public function footnotes(): void 203b6f35a76SGreg Roach { 204b6f35a76SGreg Roach $this->currentStyle = ''; 205b6f35a76SGreg Roach if (!empty($this->printedfootnotes)) { 206b6f35a76SGreg Roach foreach ($this->printedfootnotes as $element) { 207b6f35a76SGreg Roach $element->renderFootnote($this); 208b6f35a76SGreg Roach } 209b6f35a76SGreg Roach } 210b6f35a76SGreg Roach } 211b6f35a76SGreg Roach 212b6f35a76SGreg Roach /** 213b6f35a76SGreg Roach * Run the report. 214b6f35a76SGreg Roach * 215b6f35a76SGreg Roach * @return void 216b6f35a76SGreg Roach */ 217b6f35a76SGreg Roach public function run(): void 218b6f35a76SGreg Roach { 219b6f35a76SGreg Roach // Setting up the styles 220b6f35a76SGreg Roach echo '<style type="text/css">'; 221b6f35a76SGreg Roach echo '#bodydiv { font: 10px sans-serif;}'; 222b6f35a76SGreg Roach foreach ($this->styles as $class => $style) { 223b6f35a76SGreg Roach echo '.', $class, ' { '; 224b6f35a76SGreg Roach if ($style['font'] === 'dejavusans') { 225b6f35a76SGreg Roach $style['font'] = $this->default_font; 226b6f35a76SGreg Roach } 227b6f35a76SGreg Roach echo 'font-family: ', $style['font'], '; '; 228b6f35a76SGreg Roach echo 'font-size: ', $style['size'], 'pt; '; 229b6f35a76SGreg Roach // Case-insensitive 230b6f35a76SGreg Roach if (stripos($style['style'], 'B') !== false) { 231b6f35a76SGreg Roach echo 'font-weight: bold; '; 232b6f35a76SGreg Roach } 233b6f35a76SGreg Roach if (stripos($style['style'], 'I') !== false) { 234b6f35a76SGreg Roach echo 'font-style: italic; '; 235b6f35a76SGreg Roach } 236b6f35a76SGreg Roach if (stripos($style['style'], 'U') !== false) { 237b6f35a76SGreg Roach echo 'text-decoration: underline; '; 238b6f35a76SGreg Roach } 239b6f35a76SGreg Roach if (stripos($style['style'], 'D') !== false) { 240b6f35a76SGreg Roach echo 'text-decoration: line-through; '; 241b6f35a76SGreg Roach } 242b6f35a76SGreg Roach echo '}', PHP_EOL; 243b6f35a76SGreg Roach } 244b6f35a76SGreg Roach 245b6f35a76SGreg Roach //-- header divider 246b6f35a76SGreg Roach echo '</style>', PHP_EOL; 247b6f35a76SGreg Roach echo '<div id="headermargin" style="position: relative; top: auto; height: ', $this->header_margin, 'pt; width: ', $this->noMarginWidth, 'pt;"></div>'; 248b6f35a76SGreg Roach echo '<div id="headerdiv" style="position: relative; top: auto; width: ', $this->noMarginWidth, 'pt;">'; 249b6f35a76SGreg Roach foreach ($this->headerElements as $element) { 250b6f35a76SGreg Roach if ($element instanceof ReportBaseElement) { 251b6f35a76SGreg Roach $element->render($this); 252b6f35a76SGreg Roach } elseif ($element === 'footnotetexts') { 253b6f35a76SGreg Roach $this->footnotes(); 254b6f35a76SGreg Roach } elseif ($element === 'addpage') { 255b6f35a76SGreg Roach $this->addPage(); 256b6f35a76SGreg Roach } 257b6f35a76SGreg Roach } 258b6f35a76SGreg Roach //-- body 259b6f35a76SGreg Roach echo '</div>'; 260b6f35a76SGreg Roach echo '<script>document.getElementById("headerdiv").style.height="', $this->top_margin - $this->header_margin - 6, 'pt";</script>'; 261b6f35a76SGreg Roach echo '<div id="bodydiv" style="position: relative; top: auto; width: ', $this->noMarginWidth, 'pt; height: 100%;">'; 262b6f35a76SGreg Roach $this->Y = 0; 263b6f35a76SGreg Roach $this->maxY = 0; 264b6f35a76SGreg Roach foreach ($this->bodyElements as $element) { 265b6f35a76SGreg Roach if ($element instanceof ReportBaseElement) { 266b6f35a76SGreg Roach $element->render($this); 267b6f35a76SGreg Roach } elseif ($element === 'footnotetexts') { 268b6f35a76SGreg Roach $this->footnotes(); 269b6f35a76SGreg Roach } elseif ($element === 'addpage') { 270b6f35a76SGreg Roach $this->addPage(); 271b6f35a76SGreg Roach } 272b6f35a76SGreg Roach } 273b6f35a76SGreg Roach //-- footer 274b6f35a76SGreg Roach echo '</div>'; 275b6f35a76SGreg Roach echo '<script>document.getElementById("bodydiv").style.height="', $this->maxY, 'pt";</script>'; 276b6f35a76SGreg Roach echo '<div id="bottommargin" style="position: relative; top: auto; height: ', $this->bottom_margin - $this->footer_margin, 'pt;width:', $this->noMarginWidth, 'pt;"></div>'; 277b6f35a76SGreg Roach echo '<div id="footerdiv" style="position: relative; top: auto; width: ', $this->noMarginWidth, 'pt;height:auto;">'; 278b6f35a76SGreg Roach $this->Y = 0; 279b6f35a76SGreg Roach $this->X = 0; 280b6f35a76SGreg Roach $this->maxY = 0; 281b6f35a76SGreg Roach foreach ($this->footerElements as $element) { 282b6f35a76SGreg Roach if ($element instanceof ReportBaseElement) { 283b6f35a76SGreg Roach $element->render($this); 284b6f35a76SGreg Roach } elseif ($element === 'footnotetexts') { 285b6f35a76SGreg Roach $this->footnotes(); 286b6f35a76SGreg Roach } elseif ($element === 'addpage') { 287b6f35a76SGreg Roach $this->addPage(); 288b6f35a76SGreg Roach } 289b6f35a76SGreg Roach } 290b6f35a76SGreg Roach echo '</div>'; 291b6f35a76SGreg Roach echo '<script>document.getElementById("footerdiv").style.height="', $this->maxY, 'pt";</script>'; 292b6f35a76SGreg Roach echo '<div id="footermargin" style="position: relative; top: auto; height: ', $this->footer_margin, 'pt;width:', $this->noMarginWidth, 'pt;"></div>'; 293b6f35a76SGreg Roach } 294b6f35a76SGreg Roach 295b6f35a76SGreg Roach /** 296b6f35a76SGreg Roach * Create a new Cell object. 297b6f35a76SGreg Roach * 298b6f35a76SGreg Roach * @param int $width cell width (expressed in points) 299b6f35a76SGreg Roach * @param int $height cell height (expressed in points) 300b6f35a76SGreg Roach * @param mixed $border Border style 301b6f35a76SGreg Roach * @param string $align Text alignement 302b6f35a76SGreg Roach * @param string $bgcolor Background color code 303b6f35a76SGreg Roach * @param string $style The name of the text style 304b6f35a76SGreg Roach * @param int $ln Indicates where the current position should go after the call 305b6f35a76SGreg Roach * @param mixed $top Y-position 306b6f35a76SGreg Roach * @param mixed $left X-position 307b6f35a76SGreg Roach * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 1 308b6f35a76SGreg Roach * @param int $stretch Stretch carachter mode 309b6f35a76SGreg Roach * @param string $bocolor Border color 310b6f35a76SGreg Roach * @param string $tcolor Text color 311b6f35a76SGreg Roach * @param bool $reseth 312b6f35a76SGreg Roach * 313b6f35a76SGreg Roach * @return ReportBaseCell 314b6f35a76SGreg Roach */ 315b6f35a76SGreg Roach public function createCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth): ReportBaseCell 316b6f35a76SGreg Roach { 317b6f35a76SGreg Roach return new ReportHtmlCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth); 318b6f35a76SGreg Roach } 319b6f35a76SGreg Roach 320b6f35a76SGreg Roach /** 321b6f35a76SGreg Roach * Create a new TextBox object. 322b6f35a76SGreg Roach * 323b6f35a76SGreg Roach * @param float $width Text box width 324b6f35a76SGreg Roach * @param float $height Text box height 325b6f35a76SGreg Roach * @param bool $border 326b6f35a76SGreg Roach * @param string $bgcolor Background color code in HTML 327b6f35a76SGreg Roach * @param bool $newline 328b6f35a76SGreg Roach * @param float $left 329b6f35a76SGreg Roach * @param float $top 330b6f35a76SGreg Roach * @param bool $pagecheck 331b6f35a76SGreg Roach * @param string $style 332b6f35a76SGreg Roach * @param bool $fill 333b6f35a76SGreg Roach * @param bool $padding 334b6f35a76SGreg Roach * @param bool $reseth 335b6f35a76SGreg Roach * 336b6f35a76SGreg Roach * @return ReportBaseTextbox 337b6f35a76SGreg Roach */ 338b6f35a76SGreg Roach public function createTextBox( 339b6f35a76SGreg Roach float $width, 340b6f35a76SGreg Roach float $height, 341b6f35a76SGreg Roach bool $border, 342b6f35a76SGreg Roach string $bgcolor, 343b6f35a76SGreg Roach bool $newline, 344b6f35a76SGreg Roach float $left, 345b6f35a76SGreg Roach float $top, 346b6f35a76SGreg Roach bool $pagecheck, 347b6f35a76SGreg Roach string $style, 348b6f35a76SGreg Roach bool $fill, 349b6f35a76SGreg Roach bool $padding, 350b6f35a76SGreg Roach bool $reseth 351b6f35a76SGreg Roach ): ReportBaseTextbox { 352b6f35a76SGreg Roach return new ReportHtmlTextbox($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth); 353b6f35a76SGreg Roach } 354b6f35a76SGreg Roach 355b6f35a76SGreg Roach /** 356b6f35a76SGreg Roach * Create a text element. 357b6f35a76SGreg Roach * 358b6f35a76SGreg Roach * @param string $style 359b6f35a76SGreg Roach * @param string $color 360b6f35a76SGreg Roach * 361b6f35a76SGreg Roach * @return ReportBaseText 362b6f35a76SGreg Roach */ 363b6f35a76SGreg Roach public function createText(string $style, string $color): ReportBaseText 364b6f35a76SGreg Roach { 365b6f35a76SGreg Roach return new ReportHtmlText($style, $color); 366b6f35a76SGreg Roach } 367b6f35a76SGreg Roach 368b6f35a76SGreg Roach /** 369b6f35a76SGreg Roach * Create a new Footnote object. 370b6f35a76SGreg Roach * 371b6f35a76SGreg Roach * @param string $style Style name 372b6f35a76SGreg Roach * 373b6f35a76SGreg Roach * @return ReportBaseFootnote 374b6f35a76SGreg Roach */ 375b6f35a76SGreg Roach public function createFootnote($style): ReportBaseFootnote 376b6f35a76SGreg Roach { 377b6f35a76SGreg Roach return new ReportHtmlFootnote($style); 378b6f35a76SGreg Roach } 379b6f35a76SGreg Roach 380b6f35a76SGreg Roach /** 381b6f35a76SGreg Roach * Create a new image object. 382b6f35a76SGreg Roach * 383b6f35a76SGreg Roach * @param string $file Filename 384b6f35a76SGreg Roach * @param float $x 385b6f35a76SGreg Roach * @param float $y 386b6f35a76SGreg Roach * @param float $w Image width 387b6f35a76SGreg Roach * @param float $h Image height 388b6f35a76SGreg Roach * @param string $align L:left, C:center, R:right or empty to use x/y 389b6f35a76SGreg Roach * @param string $ln T:same line, N:next line 390b6f35a76SGreg Roach * 391b6f35a76SGreg Roach * @return ReportBaseImage 392b6f35a76SGreg Roach */ 393b6f35a76SGreg Roach public function createImage(string $file, float $x, float $y, float $w, float $h, string $align, string $ln): ReportBaseImage 394b6f35a76SGreg Roach { 395b6f35a76SGreg Roach return new ReportHtmlImage($file, $x, $y, $w, $h, $align, $ln); 396b6f35a76SGreg Roach } 397b6f35a76SGreg Roach 398b6f35a76SGreg Roach /** 399b6f35a76SGreg Roach * Create a new image object from Media Object. 400b6f35a76SGreg Roach * 401b6f35a76SGreg Roach * @param MediaFile $media_file 402b6f35a76SGreg Roach * @param float $x 403b6f35a76SGreg Roach * @param float $y 404b6f35a76SGreg Roach * @param float $w Image width 405b6f35a76SGreg Roach * @param float $h Image height 406b6f35a76SGreg Roach * @param string $align L:left, C:center, R:right or empty to use x/y 407b6f35a76SGreg Roach * @param string $ln T:same line, N:next line 408b6f35a76SGreg Roach * @param FilesystemInterface $data_filesystem 409b6f35a76SGreg Roach * 410b6f35a76SGreg Roach * @return ReportBaseImage 411b6f35a76SGreg Roach */ 412b6f35a76SGreg Roach public function createImageFromObject( 413b6f35a76SGreg Roach MediaFile $media_file, 414b6f35a76SGreg Roach float $x, 415b6f35a76SGreg Roach float $y, 416b6f35a76SGreg Roach float $w, 417b6f35a76SGreg Roach float $h, 418b6f35a76SGreg Roach string $align, 419b6f35a76SGreg Roach string $ln, 420b6f35a76SGreg Roach FilesystemInterface $data_filesystem 421b6f35a76SGreg Roach ): ReportBaseImage { 4221558ebe9SGreg Roach return new ReportHtmlImage($media_file->imageUrl((int) $w, (int) $h, 'crop'), $x, $y, $w, $h, $align, $ln); 423b6f35a76SGreg Roach } 424b6f35a76SGreg Roach 425b6f35a76SGreg Roach /** 426b6f35a76SGreg Roach * Create a line. 427b6f35a76SGreg Roach * 428b6f35a76SGreg Roach * @param float $x1 429b6f35a76SGreg Roach * @param float $y1 430b6f35a76SGreg Roach * @param float $x2 431b6f35a76SGreg Roach * @param float $y2 432b6f35a76SGreg Roach * 433b6f35a76SGreg Roach * @return ReportBaseLine 434b6f35a76SGreg Roach */ 435b6f35a76SGreg Roach public function createLine(float $x1, float $y1, float $x2, float $y2): ReportBaseLine 436b6f35a76SGreg Roach { 437b6f35a76SGreg Roach return new ReportHtmlLine($x1, $y1, $x2, $y2); 438b6f35a76SGreg Roach } 439b6f35a76SGreg Roach 440b6f35a76SGreg Roach /** 441b6f35a76SGreg Roach * Clear the Header 442b6f35a76SGreg Roach * 443b6f35a76SGreg Roach * @return void 444b6f35a76SGreg Roach */ 445b6f35a76SGreg Roach public function clearHeader(): void 446b6f35a76SGreg Roach { 447b6f35a76SGreg Roach $this->headerElements = []; 448b6f35a76SGreg Roach } 449b6f35a76SGreg Roach 450b6f35a76SGreg Roach /** 451b6f35a76SGreg Roach * Update the Page Number and set a new Y if max Y is larger - ReportHtml 452b6f35a76SGreg Roach * 453b6f35a76SGreg Roach * @return void 454b6f35a76SGreg Roach */ 455b6f35a76SGreg Roach public function addPage(): void 456b6f35a76SGreg Roach { 457b6f35a76SGreg Roach $this->pageN++; 458b6f35a76SGreg Roach 459b6f35a76SGreg Roach // Add a little margin to max Y "between pages" 460b6f35a76SGreg Roach $this->maxY += 10; 461b6f35a76SGreg Roach 462b6f35a76SGreg Roach // If Y is still heigher by any reason... 463b6f35a76SGreg Roach if ($this->maxY < $this->Y) { 464b6f35a76SGreg Roach // ... update max Y 465b6f35a76SGreg Roach $this->maxY = $this->Y; 466b6f35a76SGreg Roach } else { 467b6f35a76SGreg Roach // else update Y so that nothing will be overwritten, like images or cells... 468b6f35a76SGreg Roach $this->Y = $this->maxY; 469b6f35a76SGreg Roach } 470b6f35a76SGreg Roach } 471b6f35a76SGreg Roach 472b6f35a76SGreg Roach /** 473b6f35a76SGreg Roach * Uppdate max Y to keep track it incase of a pagebreak - ReportHtml 474b6f35a76SGreg Roach * 475b6f35a76SGreg Roach * @param float $y 476b6f35a76SGreg Roach * 477b6f35a76SGreg Roach * @return void 478b6f35a76SGreg Roach */ 479b6f35a76SGreg Roach public function addMaxY($y): void 480b6f35a76SGreg Roach { 481b6f35a76SGreg Roach if ($this->maxY < $y) { 482b6f35a76SGreg Roach $this->maxY = $y; 483b6f35a76SGreg Roach } 484b6f35a76SGreg Roach } 485b6f35a76SGreg Roach 486b6f35a76SGreg Roach /** 487b6f35a76SGreg Roach * Checks the Footnote and numbers them - ReportHtml 488b6f35a76SGreg Roach * 489b6f35a76SGreg Roach * @param ReportHtmlFootnote $footnote 490b6f35a76SGreg Roach * 491b6f35a76SGreg Roach * @return ReportHtmlFootnote|bool object if already numbered, false otherwise 492b6f35a76SGreg Roach */ 493b6f35a76SGreg Roach public function checkFootnote(ReportHtmlFootnote $footnote) 494b6f35a76SGreg Roach { 495b6f35a76SGreg Roach $ct = count($this->printedfootnotes); 496b6f35a76SGreg Roach $i = 0; 497b6f35a76SGreg Roach $val = $footnote->getValue(); 498b6f35a76SGreg Roach while ($i < $ct) { 499b6f35a76SGreg Roach if ($this->printedfootnotes[$i]->getValue() === $val) { 500b6f35a76SGreg Roach // If this footnote already exist then set up the numbers for this object 501b6f35a76SGreg Roach $footnote->setNum($i + 1); 502b6f35a76SGreg Roach $footnote->setAddlink((string) ($i + 1)); 503b6f35a76SGreg Roach 504b6f35a76SGreg Roach return $this->printedfootnotes[$i]; 505b6f35a76SGreg Roach } 506b6f35a76SGreg Roach $i++; 507b6f35a76SGreg Roach } 508b6f35a76SGreg Roach // If this Footnote has not been set up yet 509b6f35a76SGreg Roach $footnote->setNum($ct + 1); 510b6f35a76SGreg Roach $footnote->setAddlink((string) ($ct + 1)); 511b6f35a76SGreg Roach $this->printedfootnotes[] = $footnote; 512b6f35a76SGreg Roach 513b6f35a76SGreg Roach return false; 514b6f35a76SGreg Roach } 515b6f35a76SGreg Roach 516b6f35a76SGreg Roach /** 517b6f35a76SGreg Roach * Count the number of lines - ReportHtml 518b6f35a76SGreg Roach * 519b6f35a76SGreg Roach * @param string $str 520b6f35a76SGreg Roach * 521b6f35a76SGreg Roach * @return int Number of lines. 0 if empty line 522b6f35a76SGreg Roach */ 523b6f35a76SGreg Roach public function countLines($str): int 524b6f35a76SGreg Roach { 525b6f35a76SGreg Roach if ($str === '') { 526b6f35a76SGreg Roach return 0; 527b6f35a76SGreg Roach } 528b6f35a76SGreg Roach 529b6f35a76SGreg Roach return substr_count($str, "\n") + 1; 530b6f35a76SGreg Roach } 531b6f35a76SGreg Roach 532b6f35a76SGreg Roach /** 533b6f35a76SGreg Roach * Get the current style. 534b6f35a76SGreg Roach * 535b6f35a76SGreg Roach * @return string 536b6f35a76SGreg Roach */ 537b6f35a76SGreg Roach public function getCurrentStyle(): string 538b6f35a76SGreg Roach { 539b6f35a76SGreg Roach return $this->currentStyle; 540b6f35a76SGreg Roach } 541b6f35a76SGreg Roach 542b6f35a76SGreg Roach /** 543b6f35a76SGreg Roach * Get the current style height. 544b6f35a76SGreg Roach * 545b6f35a76SGreg Roach * @return float 546b6f35a76SGreg Roach */ 547b6f35a76SGreg Roach public function getCurrentStyleHeight(): float 548b6f35a76SGreg Roach { 549b6f35a76SGreg Roach if (empty($this->currentStyle)) { 550b6f35a76SGreg Roach return $this->default_font_size; 551b6f35a76SGreg Roach } 552b6f35a76SGreg Roach $style = $this->getStyle($this->currentStyle); 553b6f35a76SGreg Roach 554b6f35a76SGreg Roach return (float) $style['size']; 555b6f35a76SGreg Roach } 556b6f35a76SGreg Roach 557b6f35a76SGreg Roach /** 558b6f35a76SGreg Roach * Get the current footnotes height. 559b6f35a76SGreg Roach * 560b6f35a76SGreg Roach * @param float $cellWidth 561b6f35a76SGreg Roach * 562b6f35a76SGreg Roach * @return float 563b6f35a76SGreg Roach */ 564b6f35a76SGreg Roach public function getFootnotesHeight(float $cellWidth): float 565b6f35a76SGreg Roach { 566b6f35a76SGreg Roach $h = 0; 567b6f35a76SGreg Roach foreach ($this->printedfootnotes as $element) { 568b6f35a76SGreg Roach $h += $element->getFootnoteHeight($this, $cellWidth); 569b6f35a76SGreg Roach } 570b6f35a76SGreg Roach 571b6f35a76SGreg Roach return $h; 572b6f35a76SGreg Roach } 573b6f35a76SGreg Roach 574b6f35a76SGreg Roach /** 575b6f35a76SGreg Roach * Get the maximum width from current position to the margin - ReportHtml 576b6f35a76SGreg Roach * 577b6f35a76SGreg Roach * @return float 578b6f35a76SGreg Roach */ 579b6f35a76SGreg Roach public function getRemainingWidth(): float 580b6f35a76SGreg Roach { 581b6f35a76SGreg Roach return $this->noMarginWidth - $this->X; 582b6f35a76SGreg Roach } 583b6f35a76SGreg Roach 584b6f35a76SGreg Roach /** 585b6f35a76SGreg Roach * Get the page height. 586b6f35a76SGreg Roach * 587b6f35a76SGreg Roach * @return float 588b6f35a76SGreg Roach */ 589b6f35a76SGreg Roach public function getPageHeight(): float 590b6f35a76SGreg Roach { 591b6f35a76SGreg Roach return $this->page_height - $this->top_margin; 592b6f35a76SGreg Roach } 593b6f35a76SGreg Roach 594b6f35a76SGreg Roach /** 595b6f35a76SGreg Roach * Get the width of a string. 596b6f35a76SGreg Roach * 597b6f35a76SGreg Roach * @param string $text 598b6f35a76SGreg Roach * 599b6f35a76SGreg Roach * @return float 600b6f35a76SGreg Roach */ 601b6f35a76SGreg Roach public function getStringWidth(string $text): float 602b6f35a76SGreg Roach { 603b6f35a76SGreg Roach $style = $this->getStyle($this->currentStyle); 604b6f35a76SGreg Roach 605b6f35a76SGreg Roach return mb_strlen($text) * ($style['size'] / 2); 606b6f35a76SGreg Roach } 607b6f35a76SGreg Roach 608b6f35a76SGreg Roach /** 609b6f35a76SGreg Roach * Get a text height in points - ReportHtml 610b6f35a76SGreg Roach * 611b6f35a76SGreg Roach * @param string $str 612b6f35a76SGreg Roach * 613b6f35a76SGreg Roach * @return float 614b6f35a76SGreg Roach */ 615b6f35a76SGreg Roach public function getTextCellHeight(string $str): float 616b6f35a76SGreg Roach { 617b6f35a76SGreg Roach // Count the number of lines to calculate the height 618b6f35a76SGreg Roach $nl = $this->countLines($str); 619b6f35a76SGreg Roach 620b6f35a76SGreg Roach // Calculate the cell height 621b6f35a76SGreg Roach return ceil(($this->getCurrentStyleHeight() * $this->cellHeightRatio) * $nl); 622b6f35a76SGreg Roach } 623b6f35a76SGreg Roach 624b6f35a76SGreg Roach /** 625b6f35a76SGreg Roach * Get the current X position - ReportHtml 626b6f35a76SGreg Roach * 627b6f35a76SGreg Roach * @return float 628b6f35a76SGreg Roach */ 629b6f35a76SGreg Roach public function getX(): float 630b6f35a76SGreg Roach { 631b6f35a76SGreg Roach return $this->X; 632b6f35a76SGreg Roach } 633b6f35a76SGreg Roach 634b6f35a76SGreg Roach /** 635b6f35a76SGreg Roach * Get the current Y position - ReportHtml 636b6f35a76SGreg Roach * 637b6f35a76SGreg Roach * @return float 638b6f35a76SGreg Roach */ 639b6f35a76SGreg Roach public function getY(): float 640b6f35a76SGreg Roach { 641b6f35a76SGreg Roach return $this->Y; 642b6f35a76SGreg Roach } 643b6f35a76SGreg Roach 644b6f35a76SGreg Roach /** 645b6f35a76SGreg Roach * Get the current page number - ReportHtml 646b6f35a76SGreg Roach * 647b6f35a76SGreg Roach * @return int 648b6f35a76SGreg Roach */ 649b6f35a76SGreg Roach public function pageNo(): int 650b6f35a76SGreg Roach { 651b6f35a76SGreg Roach return $this->pageN; 652b6f35a76SGreg Roach } 653b6f35a76SGreg Roach 654b6f35a76SGreg Roach /** 655b6f35a76SGreg Roach * Set the current style. 656b6f35a76SGreg Roach * 657b6f35a76SGreg Roach * @param string $s 658b6f35a76SGreg Roach * 659b6f35a76SGreg Roach * @void 660b6f35a76SGreg Roach */ 661b6f35a76SGreg Roach public function setCurrentStyle(string $s): void 662b6f35a76SGreg Roach { 663b6f35a76SGreg Roach $this->currentStyle = $s; 664b6f35a76SGreg Roach } 665b6f35a76SGreg Roach 666b6f35a76SGreg Roach /** 667b6f35a76SGreg Roach * Set the X position - ReportHtml 668b6f35a76SGreg Roach * 669b6f35a76SGreg Roach * @param float $x 670b6f35a76SGreg Roach * 671b6f35a76SGreg Roach * @return void 672b6f35a76SGreg Roach */ 673b6f35a76SGreg Roach public function setX($x): void 674b6f35a76SGreg Roach { 675b6f35a76SGreg Roach $this->X = $x; 676b6f35a76SGreg Roach } 677b6f35a76SGreg Roach 678b6f35a76SGreg Roach /** 679b6f35a76SGreg Roach * Set the Y position - ReportHtml 680b6f35a76SGreg Roach * 681b6f35a76SGreg Roach * Also updates Max Y position 682b6f35a76SGreg Roach * 683b6f35a76SGreg Roach * @param float $y 684b6f35a76SGreg Roach * 685b6f35a76SGreg Roach * @return void 686b6f35a76SGreg Roach */ 687b6f35a76SGreg Roach public function setY($y): void 688b6f35a76SGreg Roach { 689b6f35a76SGreg Roach $this->Y = $y; 690b6f35a76SGreg Roach if ($this->maxY < $y) { 691b6f35a76SGreg Roach $this->maxY = $y; 692b6f35a76SGreg Roach } 693b6f35a76SGreg Roach } 694b6f35a76SGreg Roach 695b6f35a76SGreg Roach /** 696b6f35a76SGreg Roach * Set the X and Y position - ReportHtml 697b6f35a76SGreg Roach * 698b6f35a76SGreg Roach * Also updates Max Y position 699b6f35a76SGreg Roach * 700b6f35a76SGreg Roach * @param float $x 701b6f35a76SGreg Roach * @param float $y 702b6f35a76SGreg Roach * 703b6f35a76SGreg Roach * @return void 704b6f35a76SGreg Roach */ 705b6f35a76SGreg Roach public function setXy($x, $y): void 706b6f35a76SGreg Roach { 707b6f35a76SGreg Roach $this->setX($x); 708b6f35a76SGreg Roach $this->setY($y); 709b6f35a76SGreg Roach } 710b6f35a76SGreg Roach 711b6f35a76SGreg Roach /** 712b6f35a76SGreg Roach * Wrap text - ReportHtml 713b6f35a76SGreg Roach * 714b6f35a76SGreg Roach * @param string $str Text to wrap 715b6f35a76SGreg Roach * @param float $width Width in points the text has to fit into 716b6f35a76SGreg Roach * 717b6f35a76SGreg Roach * @return string 718b6f35a76SGreg Roach */ 719b6f35a76SGreg Roach public function textWrap(string $str, float $width): string 720b6f35a76SGreg Roach { 721b6f35a76SGreg Roach // Calculate the line width 722b6f35a76SGreg Roach $lw = (int) ($width / ($this->getCurrentStyleHeight() / 2)); 723b6f35a76SGreg Roach // Wordwrap each line 724b6f35a76SGreg Roach $lines = explode("\n", $str); 725b6f35a76SGreg Roach // Line Feed counter 726b6f35a76SGreg Roach $lfct = count($lines); 727b6f35a76SGreg Roach $wraptext = ''; 728b6f35a76SGreg Roach foreach ($lines as $line) { 729b6f35a76SGreg Roach $wtext = FunctionsRtl::utf8WordWrap($line, $lw, "\n", true); 730b6f35a76SGreg Roach $wraptext .= $wtext; 731b6f35a76SGreg Roach // Add a new line as long as it’s not the last line 732b6f35a76SGreg Roach if ($lfct > 1) { 733b6f35a76SGreg Roach $wraptext .= "\n"; 734b6f35a76SGreg Roach } 735b6f35a76SGreg Roach $lfct--; 736b6f35a76SGreg Roach } 737b6f35a76SGreg Roach 738b6f35a76SGreg Roach return $wraptext; 739b6f35a76SGreg Roach } 740b6f35a76SGreg Roach 741b6f35a76SGreg Roach /** 742b6f35a76SGreg Roach * Write text - ReportHtml 743b6f35a76SGreg Roach * 744b6f35a76SGreg Roach * @param string $text Text to print 745b6f35a76SGreg Roach * @param string $color HTML RGB color code (Ex: #001122) 746b6f35a76SGreg Roach * @param bool $useclass 747b6f35a76SGreg Roach * 748b6f35a76SGreg Roach * @return void 749b6f35a76SGreg Roach */ 750b6f35a76SGreg Roach public function write($text, $color = '', $useclass = true): void 751b6f35a76SGreg Roach { 752b6f35a76SGreg Roach $style = $this->getStyle($this->getCurrentStyle()); 753b6f35a76SGreg Roach $htmlcode = '<span dir="' . I18N::direction() . '"'; 754b6f35a76SGreg Roach if ($useclass) { 755b6f35a76SGreg Roach $htmlcode .= ' class="' . $style['name'] . '"'; 756b6f35a76SGreg Roach } 757b6f35a76SGreg Roach // Check if Text Color is set and if it’s valid HTML color 758b6f35a76SGreg Roach if (preg_match('/#?(..)(..)(..)/', $color)) { 759b6f35a76SGreg Roach $htmlcode .= ' style="color:' . $color . ';"'; 760b6f35a76SGreg Roach } 761b6f35a76SGreg Roach 762b6f35a76SGreg Roach $htmlcode .= '>' . $text . '</span>'; 763b6f35a76SGreg Roach $htmlcode = str_replace([ 764b6f35a76SGreg Roach "\n", 765b6f35a76SGreg Roach '> ', 766b6f35a76SGreg Roach ' <', 767b6f35a76SGreg Roach ], [ 768b6f35a76SGreg Roach '<br>', 769b6f35a76SGreg Roach '> ', 770b6f35a76SGreg Roach ' <', 771b6f35a76SGreg Roach ], $htmlcode); 772b6f35a76SGreg Roach echo $htmlcode; 773b6f35a76SGreg Roach } 774b6f35a76SGreg Roach} 775