diff --git a/VERSION b/VERSION index 18f6eaf..c91e267 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.0.72 +8.0.73 diff --git a/examples/index.php b/examples/index.php index fdcc505..27ec0af 100644 --- a/examples/index.php +++ b/examples/index.php @@ -57,6 +57,7 @@ // Add first page $page01 = $pdf->page->add(); +$pdf->setBookmark('Images', '', 0, -1, 0, 0, 'B', 'blue'); // Add Images @@ -112,6 +113,7 @@ // Add second page $page02 = $pdf->page->add(); +$pdf->setBookmark('Graphics', '', 0, -1, 0, 0, 'B', 'green'); $style1 = [ 'lineWidth' => 0.5, @@ -406,6 +408,7 @@ // Add page 2 $page03 = $pdf->page->add(); +$pdf->setBookmark('Ellipse', '', 1); $pdf->graph->setPageWidth($page03['width']); $pdf->graph->setPageHeight($page03['height']); @@ -439,6 +442,7 @@ // Add page 4 $page04 = $pdf->page->add(); +$pdf->setBookmark('Pie Chart', '', 1); $pdf->graph->setPageWidth($page04['width']); $pdf->graph->setPageHeight($page04['height']); @@ -461,6 +465,7 @@ // Add page 5 $page05 = $pdf->page->add(); +$pdf->setBookmark('Crop Marks and Color Maps', '', 1); $pdf->graph->setPageWidth($page05['width']); $pdf->graph->setPageHeight($page05['height']); @@ -672,6 +677,7 @@ // Add page 6 $page06 = $pdf->page->add(); +$pdf->setBookmark('Color Gradients', '', 1); $pdf->graph->setPageWidth($page06['width']); $pdf->graph->setPageHeight($page06['height']); @@ -732,6 +738,7 @@ // Add page 7 $page07 = $pdf->page->add(); +$pdf->setBookmark('Color gradient mesh', '', 1); $pdf->graph->setPageWidth($page07['width']); $pdf->graph->setPageHeight($page07['height']); @@ -819,6 +826,7 @@ // Add page 8 $page08 = $pdf->page->add(); +$pdf->setBookmark('Transformations', '', 1); $pdf->graph->setPageWidth($page08['width']); $pdf->graph->setPageHeight($page08['height']); @@ -946,6 +954,7 @@ // Add page 9 $page09 = $pdf->page->add(); +$pdf->setBookmark('Barcodes', '', 0, -1, 0, 0, 'B', ''); $dest_barcode_page = $pdf->setNamedDestination('barcode'); @@ -993,6 +1002,7 @@ // Add page 10 $page10 = $pdf->page->add(); +$pdf->setBookmark('Image Clipping', '', 0, -1, 0, 0, 'B', ''); $pdf->graph->setPageWidth($page10['width']); $pdf->graph->setPageHeight($page10['height']); @@ -1012,6 +1022,7 @@ // Add page 11 $page11 = $pdf->page->add(); +$pdf->setBookmark('Text', '', 0, -1, 0, 0, 'B', ''); // Add an internal link to this page $page11_link = $pdf->addInternalLink(); @@ -1063,6 +1074,9 @@ true, false, false, + false, + false, + false, '', [ 'xoffset' => 0.5, @@ -1095,6 +1109,9 @@ $txt3 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'."\n".'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; +$col = $pdf->color->getPdfColor('blue'); +$pdf->page->addContent($col); + // single block of text $txtbox = $pdf->getTextCell( $txt3, // string $txt, @@ -1115,6 +1132,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, false, // bool $drawcell = true, '', // string $forcedir = '', @@ -1122,6 +1142,9 @@ ); $pdf->page->addContent($txtbox); +$col = $pdf->color->getPdfColor('black'); +$pdf->page->addContent($col); + $bfont4 = $pdf->font->insert($pdf->pon, 'freeserif', 'I', 14); $pdf->page->addContent($bfont4['out']); @@ -1160,6 +1183,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1187,6 +1213,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1214,6 +1243,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1243,6 +1275,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1271,6 +1306,7 @@ // block of text between two page regions $pdf->addTextCell( $txt3, // string $txt, + -1, // int $pid = -1, 20, // float $posx = 0, 165, // float $posy = 0, 150, // float $width = 0, @@ -1288,6 +1324,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1301,6 +1340,7 @@ $pdf->enableZeroWidthBreakPoints(true); $pdf->addTextCell( "TEST-TEXT-ENABLE-AUTO-BREAK-POINTS", // string $txt, + -1, // int $pid = -1, 20, // float $posx = 0, 233, // float $posy = 0, 85, // float $width = 0, @@ -1318,6 +1358,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1327,6 +1370,7 @@ $pdf->enableZeroWidthBreakPoints(false); $pdf->addTextCell( "TEST-TEXT-DISABLE-AUTO-BREAK-POINTS", // string $txt, + -1, // int $pid = -1, 20, // float $posx = 0, 252, // float $posy = 0, 85, // float $width = 0, @@ -1344,6 +1388,9 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', @@ -1360,6 +1407,7 @@ // block of text between two page regions $pdf->addTextCell( $txt3 . "\n" . $txt4 . "\n" . $txt5, // string $txt, + -1, // int $pid = -1, 20, // float $posx = 0, 265, // float $posy = 0, 120, // float $width = 0, @@ -1377,18 +1425,50 @@ true, // bool $jlast = true, true, // bool $fill = true, false, // bool $stroke = false, + false, //bool $underline = false, + false, //bool $linethrough = false, + false, //bool $overline = false, false, // bool $clip = false, true, // bool $drawcell = true, '', // string $forcedir = '', null, // ?array $shadow = null, ); +$pdf->addTextCell( + 'overline, linethrough and underline', // string $txt, + -1, // int $pid = -1, + 15, // float $posx = 0, + 50, // float $posy = 0, + 180, // float $width = 0, + 0, // float $height = 0, + 0, // float $offset = 0, + 1, // float $linespace = 0, + 'T', // string $valign = 'C', + 'L', // string $halign = 'C', + null, // ?array $cell = null, + [], // array $styles = [], + 0, // float $strokewidth = 0, + 0, // float $wordspacing = 0, + 0, // float $leading = 0, + 0, // float $rise = 0, + true, // bool $jlast = true, + true, // bool $fill = true, + false, // bool $stroke = false, + true, //bool $underline = false, + true, //bool $linethrough = false, + true, //bool $overline = false, + false, // bool $clip = false, + false, // bool $drawcell = true, + '', // string $forcedir = '', + null // ?array $shadow = null, +); // ---------- // Page signature $pageC01 = $pdf->page->add(); +$pdf->setBookmark('Signature', '', 0, -1, 0, 0, 'B', 'red'); /* NOTES: @@ -1440,6 +1520,7 @@ // XOBject template $pageC02 = $pdf->page->add(); +$pdf->setBookmark('XOBject Template', '', 0, -1, 0, 0, 'B', ''); $tid = $pdf->newXObjectTemplate(80, 80, []); @@ -1469,6 +1550,7 @@ // Layers $pageV01 = $pdf->page->add(); +$pdf->setBookmark('Layers', '', 0, -1, 0, 0, 'B', ''); $pdf->page->addContent($bfont4['out']); diff --git a/src/Base.php b/src/Base.php index e447adb..d870a03 100644 --- a/src/Base.php +++ b/src/Base.php @@ -136,7 +136,7 @@ abstract class Base /** * TCPDF version. */ - protected string $version = '8.0.72'; + protected string $version = '8.0.73'; /** * Time is seconds since EPOCH when the document was created. diff --git a/src/Output.php b/src/Output.php index 07546b6..186a067 100644 --- a/src/Output.php +++ b/src/Output.php @@ -355,19 +355,19 @@ * } * * @phpstan-type TOutline array{ - * 'c': array, - * 'first': int, - * 'l': int, - * 'last': int, - * 'next': int, - * 'p': int, - * 'parent': int, - * 'prev': int, - * 's': string, * 't': string, * 'u': string, + * 'l': int, + * 'p': int, * 'x': float, * 'y': float, + * 's': string, + * 'c': string, + * 'parent': int, + * 'last': int, + * 'first': int, + * 'prev': int, + * 'next': int, * } * * @phpstan-type TSignature array{ @@ -808,13 +808,15 @@ protected function getOutCatalog(): string $out .= ' /PageLayout /' . $this->display['layout']; } - if (! empty($this->display['mode'])) { - $out .= ' /PageMode /' . $this->display['mode']; - } - if ($this->outlines !== []) { $out .= ' /Outlines ' . $this->outlinerootoid . ' 0 R'; - $out .= ' /PageMode /UseOutlines'; + if (empty($this->display['mode'])) { + $this->display['mode'] = 'UseOutlines'; + } + } + + if (! empty($this->display['mode'])) { + $out .= ' /PageMode /' . $this->display['mode']; } //$out .= ' /Threads []'; @@ -1217,13 +1219,13 @@ protected function getOutEmbeddedFiles(): string * 3 DeviceRGB * 4 DeviceCMYK * - * @param array $colors Array of colors. + * @param array $color Array of colors. */ - protected static function getColorStringFromArray(array $colors): string + protected static function getColorStringFromArray(array $color): string { - $col = array_values($colors); + $col = array_values($color); $out = '['; - match (count($colors)) { + match (count($color)) { 4 => $out .= sprintf( '%F %F %F %F', (max(0, min(100, (float) $col[0])) / 100), @@ -1287,8 +1289,9 @@ protected function getOutAnnotations(): string . $this->getOutAnnotationFlags($annot) // @phpstan-ignore-line . $this->getAnnotationAppearanceStream($annot, (int) $width, (int) $height) // @phpstan-ignore-line . $this->getAnnotationBorder($annot); // @phpstan-ignore-line - if (! empty($annot['opt']['c']) && is_array($annot['opt']['c'])) { - $out .= ' /C ' . static::getColorStringFromArray($annot['opt']['c']); + + if (! empty($annot['opt']['c']) && is_string($annot['opt']['c'])) { + $out .= ' /C [ ' . $this->color->getPdfRgbComponents($annot['opt']['c']) . ' ]'; } //$out .= ' /StructParent '; @@ -2516,7 +2519,6 @@ protected function processPrevNextBookmarks(): int $lru[$o['l']] = $i; $level = $o['l']; } - return $lru[0]; } @@ -2570,19 +2572,16 @@ protected function getOutBookmarks(): string . '<<' . ' /Title ' . $this->getOutTextString($title, $oid, true) . ' /Parent ' . ($first_oid + $outline['parent']) . ' 0 R'; - if (isset($outline['prev'])) { + if ($outline['prev'] >= 0) { $out .= ' /Prev ' . ($first_oid + $outline['prev']) . ' 0 R'; } - - if (isset($outline['next'])) { + if ($outline['next'] >= 0) { $out .= ' /Next ' . ($first_oid + $outline['next']) . ' 0 R'; } - - if (isset($outline['first'])) { + if ($outline['first'] >= 0) { $out .= ' /First ' . ($first_oid + $outline['first']) . ' 0 R'; } - - if (isset($outline['last'])) { + if ($outline['last'] >= 0) { $out .= ' /Last ' . ($first_oid + $outline['last']) . ' 0 R'; } @@ -2647,10 +2646,10 @@ protected function getOutBookmarks(): string $out .= sprintf(' /F %d', $style); // set bookmark color - if (! empty($outline['c']) && is_array($outline['c'])) { - $out .= ' /C [' . static::getColorStringFromArray($outline['c']) . ']'; - } else { + if (empty($outline['c'])) { $out .= ' /C [0.0 0.0 0.0]'; // black + } else { + $out .= ' /C [ ' . $this->color->getPdfRgbComponents($outline['c']) . ' ]'; } $out .= ' /Count 0 >>' . "\n" diff --git a/src/Tcpdf.php b/src/Tcpdf.php index 8b0e088..4a4bdd0 100644 --- a/src/Tcpdf.php +++ b/src/Tcpdf.php @@ -229,6 +229,9 @@ public function setDisplayMode( return $this; } + // ===| BARCODE |======================================================= + + /** * Get a barcode PDF code. * @@ -272,6 +275,8 @@ public function getBarcode( return $out . $this->graph->getStopTransform(); } + // ===| ANNOTATION |==================================================== + /** * Add an annotation and returns the object id. * @@ -364,7 +369,7 @@ public function setAnnotation( * @param float $posy Ordinate of upper-left corner. * @param float $width Width. * @param float $height Height. - * @param string $link URL to open when the link is clicked or an identifier returned by setInternalLink(). + * @param string $link URL to open when the link is clicked or an identifier returned by addInternalLink(). * A single character prefix may be used to specify the link action: * - '#' = internal destination * - '%' = embedded PDF file @@ -398,11 +403,11 @@ public function setLink( * @return string Internal link identifier to be used with setLink(). * */ - public function addInternalLink(int $page = 0, float $posy = 0): string + public function addInternalLink(int $page = -1, float $posy = 0): string { $lnkid = '@' . (count($this->links) + 1); $this->links[$lnkid] = [ - 'p' => ($page < 1) ? $this->page->getPage()['pid'] : $page, + 'p' => ($page < 0) ? $this->page->getPage()['pid'] : $page, 'y' => $posy, ]; return $lnkid; @@ -420,19 +425,72 @@ public function addInternalLink(int $page = 0, float $posy = 0): string */ public function setNamedDestination( string $name, - int $page = 0, + int $page = -1, float $posx = 0, float $posy = 0, ): string { $ename = $this->encrypt->encodeNameObject($name); $this->dests[$ename] = [ - 'p' => ($page < 1) ? $this->page->getPage()['pid'] : $page, + 'p' => ($page < 0) ? $this->page->getPage()['pid'] : $page, 'x' => $posx, 'y' => $posy, ]; return '#' . $ename; } + /** + * Add a bookmark entry. + * + * @param string $name Bookmark description that will be printed in the TOC. + * @param string $link (Optional) URL to open when the link is clicked + * or an identifier returned by addInternalLink(). + * A single character prefix may be used to specify the link action: + * - '#' = internal destination + * - '%' = embedded PDF file + * - '*' = embedded generic file + * @param int $level Bookmark level (minimum 0). + * + * @param int $page Page number. + * @param float $posx Abscissa of upper-left corner. + * @param float $posy Ordinate of upper-left corner. + * @param string $fstyle Font style. + * Possible values are (case insensitive): + * - regular (default) + * - B: bold + * - I: italic + * - U: underline + * - D: strikeout (linethrough) + * - O: overline + * @param string $color Color name. + */ + public function setBookmark( + string $name, + string $link = '', + int $level = 0, + int $page = -1, + float $posx = 0, + float $posy = 0, + string $fstyle = '', + string $color = '', + ): void { + $maxlevel = ((count($this->outlines) > 0) ? (end($this->outlines)['l'] + 1) : 0); + $this->outlines[] = [ + 't' => $name, + 'u' => $link, + 'l' => (($level < 0) ? 0 : ($level > $maxlevel ? $maxlevel : $level)), + 'p' => (($page < 0) ? $this->page->getPage()['pid'] : $page), + 'x' => $posx, + 'y' => $posy, + 's' => strtoupper($fstyle), + 'c' => $color, + 'parent' => 0, + 'first' => -1, + 'last' => -1, + 'next' => -1, + 'prev' => -1, + ]; + } + // ===| SIGNATURE |===================================================== /** @@ -589,7 +647,7 @@ protected function getSignatureAppearanceArray( ): array { $sigapp = []; - $sigapp['page'] = ($page < 1) ? $this->page->getPage()['pid'] : $page; + $sigapp['page'] = ($page < 0) ? $this->page->getPage()['pid'] : $page; $sigapp['name'] = (empty($name)) ? 'Signature' : $name; $pntx = $this->toPoints($posx);