See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
1 <?php 2 3 /** 4 * This file is part of FPDI 5 * 6 * @package setasign\Fpdi 7 * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com) 8 * @license http://opensource.org/licenses/mit-license The MIT License 9 */ 10 11 namespace setasign\Fpdi; 12 13 /** 14 * Trait FpdfTplTrait 15 * 16 * This class adds a templating feature to tFPDF. 17 */ 18 trait FpdfTplTrait 19 { 20 /** 21 * Data of all created templates. 22 * 23 * @var array 24 */ 25 protected $templates = []; 26 27 /** 28 * The template id for the currently created template. 29 * 30 * @var null|int 31 */ 32 protected $currentTemplateId; 33 34 /** 35 * A counter for template ids. 36 * 37 * @var int 38 */ 39 protected $templateId = 0; 40 41 /** 42 * Set the page format of the current page. 43 * 44 * @param array $size An array with two values defining the size. 45 * @param string $orientation "L" for landscape, "P" for portrait. 46 * @throws \BadMethodCallException 47 */ 48 public function setPageFormat($size, $orientation) 49 { 50 if ($this->currentTemplateId !== null) { 51 throw new \BadMethodCallException('The page format cannot be changed when writing to a template.'); 52 } 53 54 if (!\in_array($orientation, ['P', 'L'], true)) { 55 throw new \InvalidArgumentException(\sprintf( 56 'Invalid page orientation "%s"! Only "P" and "L" are allowed!', 57 $orientation 58 )); 59 } 60 61 $size = $this->_getpagesize($size); 62 63 if ( 64 $orientation != $this->CurOrientation 65 || $size[0] != $this->CurPageSize[0] 66 || $size[1] != $this->CurPageSize[1] 67 ) { 68 // New size or orientation 69 if ($orientation === 'P') { 70 $this->w = $size[0]; 71 $this->h = $size[1]; 72 } else { 73 $this->w = $size[1]; 74 $this->h = $size[0]; 75 } 76 $this->wPt = $this->w * $this->k; 77 $this->hPt = $this->h * $this->k; 78 $this->PageBreakTrigger = $this->h - $this->bMargin; 79 $this->CurOrientation = $orientation; 80 $this->CurPageSize = $size; 81 82 $this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt); 83 } 84 } 85 86 /** 87 * Draws a template onto the page or another template. 88 * 89 * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the 90 * aspect ratio. 91 * 92 * @param mixed $tpl The template id 93 * @param array|float|int $x The abscissa of upper-left corner. Alternatively you could use an assoc array 94 * with the keys "x", "y", "width", "height", "adjustPageSize". 95 * @param float|int $y The ordinate of upper-left corner. 96 * @param float|int|null $width The width. 97 * @param float|int|null $height The height. 98 * @param bool $adjustPageSize 99 * @return array The size 100 * @see FpdfTplTrait::getTemplateSize() 101 */ 102 public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false) 103 { 104 if (!isset($this->templates[$tpl])) { 105 throw new \InvalidArgumentException('Template does not exist!'); 106 } 107 108 if (\is_array($x)) { 109 unset($x['tpl']); 110 \extract($x, EXTR_IF_EXISTS); 111 /** @noinspection NotOptimalIfConditionsInspection */ 112 /** @noinspection PhpConditionAlreadyCheckedInspection */ 113 if (\is_array($x)) { 114 $x = 0; 115 } 116 } 117 118 $template = $this->templates[$tpl]; 119 120 $originalSize = $this->getTemplateSize($tpl); 121 $newSize = $this->getTemplateSize($tpl, $width, $height); 122 if ($adjustPageSize) { 123 $this->setPageFormat($newSize, $newSize['orientation']); 124 } 125 126 $this->_out( 127 // reset standard values, translate and scale 128 \sprintf( 129 'q 0 J 1 w 0 j 0 G 0 g %.4F 0 0 %.4F %.4F %.4F cm /%s Do Q', 130 ($newSize['width'] / $originalSize['width']), 131 ($newSize['height'] / $originalSize['height']), 132 $x * $this->k, 133 ($this->h - $y - $newSize['height']) * $this->k, 134 $template['id'] 135 ) 136 ); 137 138 return $newSize; 139 } 140 141 /** 142 * Get the size of a template. 143 * 144 * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the 145 * aspect ratio. 146 * 147 * @param mixed $tpl The template id 148 * @param float|int|null $width The width. 149 * @param float|int|null $height The height. 150 * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P) 151 */ 152 public function getTemplateSize($tpl, $width = null, $height = null) 153 { 154 if (!isset($this->templates[$tpl])) { 155 return false; 156 } 157 158 if ($width === null && $height === null) { 159 $width = $this->templates[$tpl]['width']; 160 $height = $this->templates[$tpl]['height']; 161 } elseif ($width === null) { 162 $width = $height * $this->templates[$tpl]['width'] / $this->templates[$tpl]['height']; 163 } 164 165 if ($height === null) { 166 $height = $width * $this->templates[$tpl]['height'] / $this->templates[$tpl]['width']; 167 } 168 169 if ($height <= 0. || $width <= 0.) { 170 throw new \InvalidArgumentException('Width or height parameter needs to be larger than zero.'); 171 } 172 173 return [ 174 'width' => $width, 175 'height' => $height, 176 0 => $width, 177 1 => $height, 178 'orientation' => $width > $height ? 'L' : 'P' 179 ]; 180 } 181 182 /** 183 * Begins a new template. 184 * 185 * @param float|int|null $width The width of the template. If null, the current page width is used. 186 * @param float|int|null $height The height of the template. If null, the current page height is used. 187 * @param bool $groupXObject Define the form XObject as a group XObject to support transparency (if used). 188 * @return int A template identifier. 189 */ 190 public function beginTemplate($width = null, $height = null, $groupXObject = false) 191 { 192 if ($width === null) { 193 $width = $this->w; 194 } 195 196 if ($height === null) { 197 $height = $this->h; 198 } 199 200 $templateId = $this->getNextTemplateId(); 201 202 // initiate buffer with current state of FPDF 203 $buffer = "2 J\n" 204 . \sprintf('%.2F w', $this->LineWidth * $this->k) . "\n"; 205 206 if ($this->FontFamily) { 207 $buffer .= \sprintf("BT /F%d %.2F Tf ET\n", $this->CurrentFont['i'], $this->FontSizePt); 208 } 209 210 if ($this->DrawColor !== '0 G') { 211 $buffer .= $this->DrawColor . "\n"; 212 } 213 if ($this->FillColor !== '0 g') { 214 $buffer .= $this->FillColor . "\n"; 215 } 216 217 if ($groupXObject && \version_compare('1.4', $this->PDFVersion, '>')) { 218 $this->PDFVersion = '1.4'; 219 } 220 221 $this->templates[$templateId] = [ 222 'objectNumber' => null, 223 'id' => 'TPL' . $templateId, 224 'buffer' => $buffer, 225 'width' => $width, 226 'height' => $height, 227 'groupXObject' => $groupXObject, 228 'state' => [ 229 'x' => $this->x, 230 'y' => $this->y, 231 'AutoPageBreak' => $this->AutoPageBreak, 232 'bMargin' => $this->bMargin, 233 'tMargin' => $this->tMargin, 234 'lMargin' => $this->lMargin, 235 'rMargin' => $this->rMargin, 236 'h' => $this->h, 237 'w' => $this->w, 238 'FontFamily' => $this->FontFamily, 239 'FontStyle' => $this->FontStyle, 240 'FontSizePt' => $this->FontSizePt, 241 'FontSize' => $this->FontSize, 242 'underline' => $this->underline, 243 'TextColor' => $this->TextColor, 244 'DrawColor' => $this->DrawColor, 245 'FillColor' => $this->FillColor, 246 'ColorFlag' => $this->ColorFlag 247 ] 248 ]; 249 250 $this->SetAutoPageBreak(false); 251 $this->currentTemplateId = $templateId; 252 253 $this->h = $height; 254 $this->w = $width; 255 256 $this->SetXY($this->lMargin, $this->tMargin); 257 $this->SetRightMargin($this->w - $width + $this->rMargin); 258 259 return $templateId; 260 } 261 262 /** 263 * Ends a template. 264 * 265 * @return bool|int|null A template identifier. 266 */ 267 public function endTemplate() 268 { 269 if ($this->currentTemplateId === null) { 270 return false; 271 } 272 273 $templateId = $this->currentTemplateId; 274 $template = $this->templates[$templateId]; 275 276 $state = $template['state']; 277 $this->SetXY($state['x'], $state['y']); 278 $this->tMargin = $state['tMargin']; 279 $this->lMargin = $state['lMargin']; 280 $this->rMargin = $state['rMargin']; 281 $this->h = $state['h']; 282 $this->w = $state['w']; 283 $this->SetAutoPageBreak($state['AutoPageBreak'], $state['bMargin']); 284 285 $this->FontFamily = $state['FontFamily']; 286 $this->FontStyle = $state['FontStyle']; 287 $this->FontSizePt = $state['FontSizePt']; 288 $this->FontSize = $state['FontSize']; 289 290 $this->TextColor = $state['TextColor']; 291 $this->DrawColor = $state['DrawColor']; 292 $this->FillColor = $state['FillColor']; 293 $this->ColorFlag = $state['ColorFlag']; 294 295 $this->underline = $state['underline']; 296 297 $fontKey = $this->FontFamily . $this->FontStyle; 298 if ($fontKey) { 299 $this->CurrentFont =& $this->fonts[$fontKey]; 300 } else { 301 unset($this->CurrentFont); 302 } 303 304 $this->currentTemplateId = null; 305 306 return $templateId; 307 } 308 309 /** 310 * Get the next template id. 311 * 312 * @return int 313 */ 314 protected function getNextTemplateId() 315 { 316 return $this->templateId++; 317 } 318 319 /* overwritten FPDF methods: */ 320 321 /** 322 * @inheritdoc 323 */ 324 public function AddPage($orientation = '', $size = '', $rotation = 0) 325 { 326 if ($this->currentTemplateId !== null) { 327 throw new \BadMethodCallException('Pages cannot be added when writing to a template.'); 328 } 329 parent::AddPage($orientation, $size, $rotation); 330 } 331 332 /** 333 * @inheritdoc 334 */ 335 public function Link($x, $y, $w, $h, $link) 336 { 337 if ($this->currentTemplateId !== null) { 338 throw new \BadMethodCallException('Links cannot be set when writing to a template.'); 339 } 340 parent::Link($x, $y, $w, $h, $link); 341 } 342 343 /** 344 * @inheritdoc 345 */ 346 public function SetLink($link, $y = 0, $page = -1) 347 { 348 if ($this->currentTemplateId !== null) { 349 throw new \BadMethodCallException('Links cannot be set when writing to a template.'); 350 } 351 return parent::SetLink($link, $y, $page); 352 } 353 354 /** 355 * @inheritdoc 356 */ 357 public function SetDrawColor($r, $g = null, $b = null) 358 { 359 parent::SetDrawColor($r, $g, $b); 360 if ($this->page === 0 && $this->currentTemplateId !== null) { 361 $this->_out($this->DrawColor); 362 } 363 } 364 365 /** 366 * @inheritdoc 367 */ 368 public function SetFillColor($r, $g = null, $b = null) 369 { 370 parent::SetFillColor($r, $g, $b); 371 if ($this->page === 0 && $this->currentTemplateId !== null) { 372 $this->_out($this->FillColor); 373 } 374 } 375 376 /** 377 * @inheritdoc 378 */ 379 public function SetLineWidth($width) 380 { 381 parent::SetLineWidth($width); 382 if ($this->page === 0 && $this->currentTemplateId !== null) { 383 $this->_out(\sprintf('%.2F w', $width * $this->k)); 384 } 385 } 386 387 /** 388 * @inheritdoc 389 */ 390 public function SetFont($family, $style = '', $size = 0) 391 { 392 parent::SetFont($family, $style, $size); 393 if ($this->page === 0 && $this->currentTemplateId !== null) { 394 $this->_out(\sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); 395 } 396 } 397 398 /** 399 * @inheritdoc 400 */ 401 public function SetFontSize($size) 402 { 403 parent::SetFontSize($size); 404 if ($this->page === 0 && $this->currentTemplateId !== null) { 405 $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); 406 } 407 } 408 409 /** 410 * @inheritdoc 411 */ 412 protected function _putimages() 413 { 414 parent::_putimages(); 415 416 foreach ($this->templates as $key => $template) { 417 $this->_newobj(); 418 $this->templates[$key]['objectNumber'] = $this->n; 419 420 $this->_put('<</Type /XObject /Subtype /Form /FormType 1'); 421 $this->_put(\sprintf( 422 '/BBox[0 0 %.2F %.2F]', 423 $template['width'] * $this->k, 424 $template['height'] * $this->k 425 )); 426 $this->_put('/Resources 2 0 R'); // default resources dictionary of FPDF 427 428 if ($this->compress) { 429 $buffer = \gzcompress($template['buffer']); 430 $this->_put('/Filter/FlateDecode'); 431 } else { 432 $buffer = $template['buffer']; 433 } 434 435 $this->_put('/Length ' . \strlen($buffer)); 436 437 if ($template['groupXObject']) { 438 $this->_put('/Group <</Type/Group/S/Transparency>>'); 439 } 440 441 $this->_put('>>'); 442 $this->_putstream($buffer); 443 $this->_put('endobj'); 444 } 445 } 446 447 /** 448 * @inheritdoc 449 */ 450 protected function _putxobjectdict() 451 { 452 foreach ($this->templates as $key => $template) { 453 $this->_put('/' . $template['id'] . ' ' . $template['objectNumber'] . ' 0 R'); 454 } 455 456 parent::_putxobjectdict(); 457 } 458 459 /** 460 * @inheritdoc 461 */ 462 public function _out($s) 463 { 464 if ($this->currentTemplateId !== null) { 465 $this->templates[$this->currentTemplateId]['buffer'] .= $s . "\n"; 466 } else { 467 parent::_out($s); 468 } 469 } 470 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body