1<?php 2 3namespace Mpdf\Writer; 4 5use Mpdf\Strict; 6use Mpdf\Mpdf; 7 8final class BookmarkWriter 9{ 10 11 use Strict; 12 13 /** 14 * @var \Mpdf\Mpdf 15 */ 16 private $mpdf; 17 18 /** 19 * @var \Mpdf\Writer\BaseWriter 20 */ 21 private $writer; 22 23 public function __construct(Mpdf $mpdf, BaseWriter $writer) 24 { 25 $this->mpdf = $mpdf; 26 $this->writer = $writer; 27 } 28 29 public function writeBookmarks() // _putbookmarks 30 { 31 $nb = count($this->mpdf->BMoutlines); 32 if ($nb === 0) { 33 return; 34 } 35 36 $bmo = $this->mpdf->BMoutlines; 37 $this->mpdf->BMoutlines = []; 38 $lastlevel = -1; 39 for ($i = 0; $i < count($bmo); $i++) { 40 if ($bmo[$i]['l'] > 0) { 41 while ($bmo[$i]['l'] - $lastlevel > 1) { // If jump down more than one level, insert a new entry 42 $new = $bmo[$i]; 43 $new['t'] = "[" . $new['t'] . "]"; // Put [] around text/title to highlight 44 $new['l'] = $lastlevel + 1; 45 $lastlevel++; 46 $this->mpdf->BMoutlines[] = $new; 47 } 48 } 49 $this->mpdf->BMoutlines[] = $bmo[$i]; 50 $lastlevel = $bmo[$i]['l']; 51 } 52 $nb = count($this->mpdf->BMoutlines); 53 54 $lru = []; 55 $level = 0; 56 foreach ($this->mpdf->BMoutlines as $i => $o) { 57 if ($o['l'] > 0) { 58 $parent = $lru[$o['l'] - 1]; 59 // Set parent and last pointers 60 $this->mpdf->BMoutlines[$i]['parent'] = $parent; 61 $this->mpdf->BMoutlines[$parent]['last'] = $i; 62 if ($o['l'] > $level) { 63 // Level increasing: set first pointer 64 $this->mpdf->BMoutlines[$parent]['first'] = $i; 65 } 66 } else { 67 $this->mpdf->BMoutlines[$i]['parent'] = $nb; 68 } 69 if ($o['l'] <= $level and $i > 0) { 70 // Set prev and next pointers 71 $prev = $lru[$o['l']]; 72 $this->mpdf->BMoutlines[$prev]['next'] = $i; 73 $this->mpdf->BMoutlines[$i]['prev'] = $prev; 74 } 75 $lru[$o['l']] = $i; 76 $level = $o['l']; 77 } 78 79 80 // Outline items 81 $n = $this->mpdf->n + 1; 82 foreach ($this->mpdf->BMoutlines as $i => $o) { 83 $this->writer->object(); 84 $this->writer->write('<</Title ' . $this->writer->utf16BigEndianTextString($o['t'])); 85 $this->writer->write('/Parent ' . ($n + $o['parent']) . ' 0 R'); 86 if (isset($o['prev'])) { 87 $this->writer->write('/Prev ' . ($n + $o['prev']) . ' 0 R'); 88 } 89 if (isset($o['next'])) { 90 $this->writer->write('/Next ' . ($n + $o['next']) . ' 0 R'); 91 } 92 if (isset($o['first'])) { 93 $this->writer->write('/First ' . ($n + $o['first']) . ' 0 R'); 94 } 95 if (isset($o['last'])) { 96 $this->writer->write('/Last ' . ($n + $o['last']) . ' 0 R'); 97 } 98 99 100 if (isset($this->mpdf->pageDim[$o['p']]['h'])) { 101 $h = $this->mpdf->pageDim[$o['p']]['h']; 102 } else { 103 $h = 0; 104 } 105 106 $this->writer->write(sprintf('/Dest [%d 0 R /XYZ 0 %.3F null]', 1 + 2 * ($o['p']), ($h - $o['y']) * Mpdf::SCALE)); 107 if (isset($this->mpdf->bookmarkStyles) && isset($this->mpdf->bookmarkStyles[$o['l']])) { 108 // font style 109 $bms = $this->mpdf->bookmarkStyles[$o['l']]['style']; 110 $style = 0; 111 if (strpos($bms, 'B') !== false) { 112 $style += 2; 113 } 114 if (strpos($bms, 'I') !== false) { 115 $style += 1; 116 } 117 $this->writer->write(sprintf('/F %d', $style)); 118 // Colour 119 $col = $this->mpdf->bookmarkStyles[$o['l']]['color']; 120 if (isset($col) && is_array($col) && count($col) == 3) { 121 $this->writer->write(sprintf('/C [%.3F %.3F %.3F]', ($col[0] / 255), ($col[1] / 255), ($col[2] / 255))); 122 } 123 } 124 125 $this->writer->write('/Count 0>>'); 126 $this->writer->write('endobj'); 127 } 128 // Outline root 129 $this->writer->object(); 130 131 $this->mpdf->OutlineRoot = $this->mpdf->n; 132 133 $this->writer->write('<</Type /BMoutlines /First ' . $n . ' 0 R'); 134 $this->writer->write('/Last ' . ($n + $lru[0]) . ' 0 R>>'); 135 $this->writer->write('endobj'); 136 } 137 138} 139