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