diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 511b231..77793d8 100755 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,3 +1,7 @@ +5.9.097 (2011-06-23) + - The method setHtmlVSpace() now can be used also for tags: div, li, br, dt and dd. + - The Named Destination feature was added (check the example n. 15) - thanks to Christian Deligant. + 5.9.096 (2011-06-19) - Bug item #3322234 "Surrogate pairs codes in arrUTF8ToUTF16BE" was fixed. diff --git a/README.TXT b/README.TXT index 6ede262..6434dbe 100755 --- a/README.TXT +++ b/README.TXT @@ -8,8 +8,8 @@ http://sourceforge.net/donate/index.php?group_id=128076 ------------------------------------------------------------ Name: TCPDF -Version: 5.9.096 -Release date: 2011-06-19 +Version: 5.9.097 +Release date: 2011-06-23 Author: Nicola Asuni Copyright (c) 2002-2011: @@ -45,7 +45,7 @@ Main Features: * text rendering modes (fill, stroke and clipping); * multiple columns mode; * no-write page regions; - * bookmarks and table of content; + * bookmarks, named destinations and table of content; * text hyphenation; * text stretching and spacing (tracking/kerning); * automatic page break, line break and text alignments including justification; @@ -64,7 +64,7 @@ Source Code Documentation: http://www.tcpdf.org/doc/ For Additional Documentation: - http: www.tcpdf.org + http://www.tcpdf.org License Copyright (C) 2002-2011 Nicola Asuni - Tecnick.com S.r.l. diff --git a/examples/example_015.php b/examples/example_015.php index 58c9424..3a79301 100755 --- a/examples/example_015.php +++ b/examples/example_015.php @@ -6,6 +6,7 @@ // // Description : Example 015 for TCPDF class // Bookmarks (Table of Content) +// and Named Destinations. // // Author: Nicola Asuni // @@ -81,7 +82,8 @@ $pdf->Bookmark('Chapter 1', 0, 0, '', 'B', array(0,64,128)); $pdf->Cell(0, 10, 'Chapter 1', 0, 1, 'L'); $pdf->SetFont('times', 'I', 14); -$pdf->Write(0, 'You can set PDF Bookmarks using the Bookmark() method.'); +$pdf->Write(0, 'You can set PDF Bookmarks using the Bookmark() method. +You can set PDF Named Destinations using the setDestination() method.'); $pdf->SetFont('times', 'B', 20); @@ -104,13 +106,25 @@ $pdf->Bookmark('Paragraph 1.3', 1, 0, '', '', array(0,0,0)); $pdf->Cell(0, 10, 'Paragraph 1.3', 0, 1, 'L'); $pdf->AddPage(); +// add a named destination so you can open this document at this page using the link: "example_015.pdf#chapter2" +$pdf->setDestination('chapter2', 0, ''); $pdf->Bookmark('Chapter 2', 0, 0, '', 'BI', array(128,0,0)); $pdf->Cell(0, 10, 'Chapter 2', 0, 1, 'L'); +$pdf->SetFont('times', 'I', 14); +$pdf->Write(0, 'Once saved, you can open this document at this page using the link: "example_015.pdf#chapter2".'); $pdf->AddPage(); +$pdf->setDestination('chapter3', 0, ''); +$pdf->SetFont('times', 'B', 20); $pdf->Bookmark('Chapter 3', 0, 0, '', 'B', array(0,64,128)); $pdf->Cell(0, 10, 'Chapter 3', 0, 1, 'L'); +$pdf->AddPage(); +$pdf->setDestination('chapter4', 0, ''); +$pdf->SetFont('times', 'B', 20); +$pdf->Bookmark('Chapter 4', 0, 0, '', 'B', array(0,64,128)); +$pdf->Cell(0, 10, 'Chapter 4', 0, 1, 'L'); + // --------------------------------------------------------- //Close and output PDF document diff --git a/tcpdf.php b/tcpdf.php index 15e3793..5ffafa6 100755 --- a/tcpdf.php +++ b/tcpdf.php @@ -1,9 +1,9 @@ text rendering modes (fill, stroke and clipping); *
  • multiple columns mode;
  • *
  • no-write page regions;
  • - *
  • bookmarks and table of content;
  • + *
  • bookmarks, named destinations and table of content;
  • *
  • text hyphenation;
  • *
  • text stretching and spacing (tracking/kerning);
  • *
  • automatic page break, line break and text alignments including justification;
  • @@ -134,7 +134,7 @@ * Tools to encode your unicode fonts are on fonts/utils directory.

    * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 5.9.096 + * @version 5.9.097 */ // Main configuration file. Define the K_TCPDF_EXTERNAL_CONFIG constant to skip this file. @@ -146,7 +146,7 @@ require_once(dirname(__FILE__).'/config/tcpdf_config.php'); * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
    * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 5.9.096 + * @version 5.9.097 * @author Nicola Asuni - info@tecnick.com */ class TCPDF { @@ -157,7 +157,7 @@ class TCPDF { * Current TCPDF version. * @private */ - private $tcpdf_version = '5.9.096'; + private $tcpdf_version = '5.9.097'; // Protected properties @@ -1628,6 +1628,13 @@ class TCPDF { */ protected $pdflayers = false; + /** + * A dictionary of names and corresponding destinations (Dests key on document Catalog). + * @protected + * @since 5.9.097 (2011-06-23) + */ + protected $dests = array(); + /** * Directory used for the last SVG image. * @protected @@ -10971,7 +10978,34 @@ class TCPDF { protected function _putcatalog() { $oid = $this->_newobj(); $out = '<< /Type /Catalog'; + $out .= ' /Version /'.$this->PDFVersion; + //$out .= ' /Extensions <<>>'; $out .= ' /Pages 1 0 R'; + //$out .= ' /PageLabels ' //...; + $out .= ' /Names <<'; + if ((!empty($this->javascript)) OR (!empty($this->js_objects))) { + $out .= ' /JavaScript '.($this->n_js).' 0 R'; + } + $out .= ' >>'; + if (!empty($this->dests)) { + $out .= ' /Dests <<'; + foreach($this->dests as $name => $o) { + $out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ 0 %.2F null]', $this->page_obj_id[($o['p'])], ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k))); + } + $out .= ' >>'; + } + $out .= $this->_putviewerpreferences(); + if (isset($this->LayoutMode) AND (!$this->empty_string($this->LayoutMode))) { + $out .= ' /PageLayout /'.$this->LayoutMode; + } + if (isset($this->PageMode) AND (!$this->empty_string($this->PageMode))) { + $out .= ' /PageMode /'.$this->PageMode; + } + if (count($this->outlines) > 0) { + $out .= ' /Outlines '.$this->OutlineRoot.' 0 R'; + $out .= ' /PageMode /UseOutlines'; + } + //$out .= ' /Threads []'; if ($this->ZoomMode == 'fullpage') { $out .= ' /OpenAction ['.$this->page_obj_id[1].' 0 R /Fit]'; } elseif ($this->ZoomMode == 'fullwidth') { @@ -10979,27 +11013,19 @@ class TCPDF { } elseif ($this->ZoomMode == 'real') { $out .= ' /OpenAction ['.$this->page_obj_id[1].' 0 R /XYZ null null 1]'; } elseif (!is_string($this->ZoomMode)) { - $out .= sprintf(' /OpenAction ['.$this->page_obj_id[1].' 0 R /XYZ null null %.2F]',($this->ZoomMode / 100)); - } - if (isset($this->LayoutMode) AND (!$this->empty_string($this->LayoutMode))) { - $out .= ' /PageLayout /'.$this->LayoutMode; - } - if (isset($this->PageMode) AND (!$this->empty_string($this->PageMode))) { - $out .= ' /PageMode /'.$this->PageMode; + $out .= sprintf(' /OpenAction ['.$this->page_obj_id[1].' 0 R /XYZ null null %.2F]', ($this->ZoomMode / 100)); } + //$out .= ' /AA <<>>'; + //$out .= ' /URI <<>>'; + //$out .= ' /Metadata X Y R'; + //$out .= ' /StructTreeRoot <<>>'; + //$out .= ' /MarkInfo <<>>'; if (isset($this->l['a_meta_language'])) { $out .= ' /Lang '.$this->_textstring($this->l['a_meta_language'], $oid); } - $out .= ' /Names <<'; - if ((!empty($this->javascript)) OR (!empty($this->js_objects))) { - $out .= ' /JavaScript '.($this->n_js).' 0 R'; - } - $out .= ' >>'; - if (count($this->outlines) > 0) { - $out .= ' /Outlines '.$this->OutlineRoot.' 0 R'; - $out .= ' /PageMode /UseOutlines'; - } - $out .= ' '.$this->_putviewerpreferences(); + //$out .= ' /SpiderInfo <<>>'; + //$out .= ' /OutputIntents []'; + //$out .= ' /PieceInfo <<>>'; if ($this->pdflayers) { $p = $this->n_ocg_print.' 0 R'; $v = $this->n_ocg_view.' 0 R'; @@ -11053,6 +11079,10 @@ class TCPDF { } } } + //$out .= ' /Legal <<>>'; + //$out .= ' /Requirements []'; + //$out .= ' /Collection <<>>'; + //$out .= ' /NeedsRendering true'; $out .= ' >>'; $out .= "\n".'endobj'; $this->_out($out); @@ -11067,7 +11097,7 @@ class TCPDF { * @protected */ protected function _putviewerpreferences() { - $out = '/ViewerPreferences <<'; + $out = ' /ViewerPreferences <<'; if ($this->rtl) { $out .= ' /Direction /R2L'; } else { @@ -14560,11 +14590,88 @@ class TCPDF { // END OF BIDIRECTIONAL TEXT SECTION ------------------- /** - * Adds a bookmark. - * @param $txt (string) bookmark description. - * @param $level (int) bookmark level (minimum value is 0). + * Encode a name object. + * @param $name (string) Name object to encode. + * @return (string) Encoded name object. + * @protected + * @author Nicola Asuni + * @since 5.9.097 (2011-06-23) + */ + protected function encodeNameObject($name) { + $escname = ''; + $length = strlen($name); + for ($i = 0; $i < $length; ++$i) { + $chr = $name{$i}; + if (preg_match('/[0-9a-zA-Z]/', $chr) == 1) { + $escname .= $chr; + } else { + $escname .= sprintf('#%02X', ord($chr)); + } + } + return $escname; + } + + /** + * Add a Named Destination. + * NOTE: destination names are unique, so only last entry will be saved. + * @param $name (string) Destination name. + * @param $y (float) Y position in user units of the destiantion on the selected page (default = -1 = current position; 0 = page start;). + * @param $page (int) Target page number (leave empty for current page). + * @return (string) Stripped named destination identifier or false in case of error. + * @public + * @author Christian Deligant, Nicola Asuni + * @since 5.9.097 (2011-06-23) + */ + public function setDestination($name, $y=-1, $page='') { + // remove unsupported characters + $name = $this->encodeNameObject($name); + if ($this->empty_string($name)) { + return false; + } + if ($y == -1) { + $y = $this->GetY(); + } + if (empty($page)) { + $page = $this->PageNo(); + if (empty($page)) { + return; + } + } + $this->dests[$name] = array('y' => $y, 'p' => $page); + return $name; + } + + /** + * Return the Named Destination array. + * @return (array) Named Destination array. + * @public + * @author Nicola Asuni + * @since 5.9.097 (2011-06-23) + */ + public function getDestination() { + return $this->dests; + } + + /** + * Adds a bookmark - alias for Bookmark(). + * @param $txt (string) Bookmark description. + * @param $level (int) Bookmark level (minimum value is 0). * @param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;). - * @param $page (int) target page number (leave empty for current page). + * @param $page (int) Target page number (leave empty for current page). + * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic. + * @param $color (array) RGB color array (values from 0 to 255). + * @public + */ + public function setBookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0)) { + $this->Bookmark($txt, $level, $y, $page, $style, $color); + } + + /** + * Adds a bookmark. + * @param $txt (string) Bookmark description. + * @param $level (int) Bookmark level (minimum value is 0). + * @param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;). + * @param $page (int) Target page number (leave empty for current page). * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic. * @param $color (array) RGB color array (values from 0 to 255). * @public @@ -21121,7 +21228,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } else { $n = 1; } - $hb = ($n * $cur_h); + if ((!isset($this->tagvspaces[$tag['value']])) AND (in_array($tag['value'], array('div', 'dt', 'dd', 'li', 'br')))) { + $hb = 0; + } else { + $hb = ($n * $cur_h); + } if (($this->htmlvspace <= 0) AND ($n > 0)) { if (isset($parent['fontsize'])) { $hbz = (($parent['fontsize'] / $this->k) * $this->cell_height_ratio); @@ -21327,7 +21438,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'dt': { - $this->addHTMLVertSpace($hbz, 0, $cell, $firsttag); + $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; } case 'dd': { @@ -21337,7 +21448,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->lMargin += $this->listindent; } ++$this->listindentlevel; - $this->addHTMLVertSpace($hbz, 0, $cell, $firsttag); + $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; } case 'ul': @@ -21372,7 +21483,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } case 'li': { if ($key > 2) { - $this->addHTMLVertSpace($hbz, 0, $cell, $firsttag); + $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); } if ($this->listordered[$this->listnum]) { // ordered item @@ -21414,11 +21525,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'br': { - $this->addHTMLVertSpace($hbz, 0, $cell, $firsttag); + $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; } case 'div': { - $this->addHTMLVertSpace($hbz, 0, $cell, $firsttag); + $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; } case 'p': { @@ -21742,7 +21853,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } else { $n = 1; } - $hb = ($n * $pre_h); + if ((!isset($this->tagvspaces[$tag['value']])) AND ($tag['value'] == 'div')) { + $hb = 0; + } else { + $hb = ($n * $pre_h); + } if ($maxbottomliney > $this->PageBreakTrigger) { $hbz = ($this->FontSize * $this->cell_height_ratio); } elseif ($this->y < $maxbottomliney) { @@ -22127,7 +22242,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'div': { - $this->addHTMLVertSpace($hbz, 0, $cell, false, $lasttag); + $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag); break; } case 'blockquote': { @@ -23470,6 +23585,15 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->outlines[$key]['p'] = $topage; } } + // adjust dests + $tmpdests = $this->dests; + foreach ($tmpdests as $key => $dest) { + if (($dest['p'] >= $topage) AND ($dest['p'] < $frompage)) { + $this->dests[$key]['p'] = $dest['p'] + 1; + } elseif ($dest['p'] == $frompage) { + $this->dests[$key]['p'] = $topage; + } + } // adjust links $tmplinks = $this->links; foreach ($tmplinks as $key => $link) { @@ -23629,6 +23753,15 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: unset($this->outlines[$key]); } } + // adjust dests + $tmpdests = $this->dests; + foreach ($tmpdests as $key => $dest) { + if ($dest['p'] > $page) { + $this->dests[$key]['p'] = $dest['p'] - 1; + } elseif ($dest['p'] == $page) { + unset($this->dests[$key]); + } + } // adjust links $tmplinks = $this->links; foreach ($tmplinks as $key => $link) {