Differences Between: [Versions 310 and 400] [Versions 39 and 400]
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\PdfReader; 12 13 use setasign\Fpdi\PdfParser\Filter\FilterException; 14 use setasign\Fpdi\PdfParser\PdfParser; 15 use setasign\Fpdi\PdfParser\PdfParserException; 16 use setasign\Fpdi\PdfParser\Type\PdfArray; 17 use setasign\Fpdi\PdfParser\Type\PdfDictionary; 18 use setasign\Fpdi\PdfParser\Type\PdfIndirectObject; 19 use setasign\Fpdi\PdfParser\Type\PdfNull; 20 use setasign\Fpdi\PdfParser\Type\PdfNumeric; 21 use setasign\Fpdi\PdfParser\Type\PdfStream; 22 use setasign\Fpdi\PdfParser\Type\PdfType; 23 use setasign\Fpdi\PdfParser\Type\PdfTypeException; 24 use setasign\Fpdi\PdfReader\DataStructure\Rectangle; 25 use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException; 26 27 /** 28 * Class representing a page of a PDF document 29 */ 30 class Page 31 { 32 /** 33 * @var PdfIndirectObject 34 */ 35 protected $pageObject; 36 37 /** 38 * @var PdfDictionary 39 */ 40 protected $pageDictionary; 41 42 /** 43 * @var PdfParser 44 */ 45 protected $parser; 46 47 /** 48 * Inherited attributes 49 * 50 * @var null|array 51 */ 52 protected $inheritedAttributes; 53 54 /** 55 * Page constructor. 56 * 57 * @param PdfIndirectObject $page 58 * @param PdfParser $parser 59 */ 60 public function __construct(PdfIndirectObject $page, PdfParser $parser) 61 { 62 $this->pageObject = $page; 63 $this->parser = $parser; 64 } 65 66 /** 67 * Get the indirect object of this page. 68 * 69 * @return PdfIndirectObject 70 */ 71 public function getPageObject() 72 { 73 return $this->pageObject; 74 } 75 76 /** 77 * Get the dictionary of this page. 78 * 79 * @return PdfDictionary 80 * @throws PdfParserException 81 * @throws PdfTypeException 82 * @throws CrossReferenceException 83 */ 84 public function getPageDictionary() 85 { 86 if (null === $this->pageDictionary) { 87 $this->pageDictionary = PdfDictionary::ensure(PdfType::resolve($this->getPageObject(), $this->parser)); 88 } 89 90 return $this->pageDictionary; 91 } 92 93 /** 94 * Get a page attribute. 95 * 96 * @param string $name 97 * @param bool $inherited 98 * @return PdfType|null 99 * @throws PdfParserException 100 * @throws PdfTypeException 101 * @throws CrossReferenceException 102 */ 103 public function getAttribute($name, $inherited = true) 104 { 105 $dict = $this->getPageDictionary(); 106 107 if (isset($dict->value[$name])) { 108 return $dict->value[$name]; 109 } 110 111 $inheritedKeys = ['Resources', 'MediaBox', 'CropBox', 'Rotate']; 112 if ($inherited && \in_array($name, $inheritedKeys, true)) { 113 if ($this->inheritedAttributes === null) { 114 $this->inheritedAttributes = []; 115 $inheritedKeys = \array_filter($inheritedKeys, function ($key) use ($dict) { 116 return !isset($dict->value[$key]); 117 }); 118 119 if (\count($inheritedKeys) > 0) { 120 $parentDict = PdfType::resolve(PdfDictionary::get($dict, 'Parent'), $this->parser); 121 while ($parentDict instanceof PdfDictionary) { 122 foreach ($inheritedKeys as $index => $key) { 123 if (isset($parentDict->value[$key])) { 124 $this->inheritedAttributes[$key] = $parentDict->value[$key]; 125 unset($inheritedKeys[$index]); 126 } 127 } 128 129 /** @noinspection NotOptimalIfConditionsInspection */ 130 if (isset($parentDict->value['Parent']) && \count($inheritedKeys) > 0) { 131 $parentDict = PdfType::resolve(PdfDictionary::get($parentDict, 'Parent'), $this->parser); 132 } else { 133 break; 134 } 135 } 136 } 137 } 138 139 if (isset($this->inheritedAttributes[$name])) { 140 return $this->inheritedAttributes[$name]; 141 } 142 } 143 144 return null; 145 } 146 147 /** 148 * Get the rotation value. 149 * 150 * @return int 151 * @throws PdfParserException 152 * @throws PdfTypeException 153 * @throws CrossReferenceException 154 */ 155 public function getRotation() 156 { 157 $rotation = $this->getAttribute('Rotate'); 158 if (null === $rotation) { 159 return 0; 160 } 161 162 $rotation = PdfNumeric::ensure(PdfType::resolve($rotation, $this->parser))->value % 360; 163 164 if ($rotation < 0) { 165 $rotation += 360; 166 } 167 168 return $rotation; 169 } 170 171 /** 172 * Get a boundary of this page. 173 * 174 * @param string $box 175 * @param bool $fallback 176 * @return bool|Rectangle 177 * @throws PdfParserException 178 * @throws PdfTypeException 179 * @throws CrossReferenceException 180 * @see PageBoundaries 181 */ 182 public function getBoundary($box = PageBoundaries::CROP_BOX, $fallback = true) 183 { 184 $value = $this->getAttribute($box); 185 186 if ($value !== null) { 187 return Rectangle::byPdfArray($value, $this->parser); 188 } 189 190 if ($fallback === false) { 191 return false; 192 } 193 194 switch ($box) { 195 case PageBoundaries::BLEED_BOX: 196 case PageBoundaries::TRIM_BOX: 197 case PageBoundaries::ART_BOX: 198 return $this->getBoundary(PageBoundaries::CROP_BOX, true); 199 case PageBoundaries::CROP_BOX: 200 return $this->getBoundary(PageBoundaries::MEDIA_BOX, true); 201 } 202 203 return false; 204 } 205 206 /** 207 * Get the width and height of this page. 208 * 209 * @param string $box 210 * @param bool $fallback 211 * @return array|bool 212 * @throws PdfParserException 213 * @throws PdfTypeException 214 * @throws CrossReferenceException 215 */ 216 public function getWidthAndHeight($box = PageBoundaries::CROP_BOX, $fallback = true) 217 { 218 $boundary = $this->getBoundary($box, $fallback); 219 if ($boundary === false) { 220 return false; 221 } 222 223 $rotation = $this->getRotation(); 224 $interchange = ($rotation / 90) % 2; 225 226 return [ 227 $interchange ? $boundary->getHeight() : $boundary->getWidth(), 228 $interchange ? $boundary->getWidth() : $boundary->getHeight() 229 ]; 230 } 231 232 /** 233 * Get the raw content stream. 234 * 235 * @return string 236 * @throws PdfReaderException 237 * @throws PdfTypeException 238 * @throws FilterException 239 * @throws PdfParserException 240 */ 241 public function getContentStream() 242 { 243 $dict = $this->getPageDictionary(); 244 $contents = PdfType::resolve(PdfDictionary::get($dict, 'Contents'), $this->parser); 245 if ($contents instanceof PdfNull) { 246 return ''; 247 } 248 249 if ($contents instanceof PdfArray) { 250 $result = []; 251 foreach ($contents->value as $content) { 252 $content = PdfType::resolve($content, $this->parser); 253 if (!($content instanceof PdfStream)) { 254 continue; 255 } 256 $result[] = $content->getUnfilteredStream(); 257 } 258 259 return \implode("\n", $result); 260 } 261 262 if ($contents instanceof PdfStream) { 263 return $contents->getUnfilteredStream(); 264 } 265 266 throw new PdfReaderException( 267 'Array or stream expected.', 268 PdfReaderException::UNEXPECTED_DATA_TYPE 269 ); 270 } 271 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body