Passed
Push — master ( a3df04...3cb3a5 )
by Konrad
02:12
created

PDFObject::cleanContent()   B

Complexity

Conditions 11
Paths 64

Size

Total Lines 57
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 11.0044

Importance

Changes 0
Metric Value
cc 11
eloc 31
c 0
b 0
f 0
nc 64
nop 2
dl 0
loc 57
ccs 29
cts 30
cp 0.9667
crap 11.0044
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @file
5
 *          This file is part of the PdfParser library.
6
 *
7
 * @author  Sébastien MALOT <[email protected]>
8
 * @date    2017-01-03
9
 *
10
 * @license LGPLv3
11
 * @url     <https://github.com/smalot/pdfparser>
12
 *
13
 *  PdfParser is a pdf library written in PHP, extraction oriented.
14
 *  Copyright (C) 2017 - Sébastien MALOT <[email protected]>
15
 *
16
 *  This program is free software: you can redistribute it and/or modify
17
 *  it under the terms of the GNU Lesser General Public License as published by
18
 *  the Free Software Foundation, either version 3 of the License, or
19
 *  (at your option) any later version.
20
 *
21
 *  This program is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU Lesser General Public License for more details.
25
 *
26
 *  You should have received a copy of the GNU Lesser General Public License
27
 *  along with this program.
28
 *  If not, see <http://www.pdfparser.org/sites/default/LICENSE.txt>.
29
 */
30
31
namespace Smalot\PdfParser;
32
33
use Smalot\PdfParser\XObject\Form;
34
use Smalot\PdfParser\XObject\Image;
35
36
/**
37
 * Class PDFObject
38
 */
39
class PDFObject
40
{
41
    const TYPE = 't';
42
43
    const OPERATOR = 'o';
44
45
    const COMMAND = 'c';
46
47
    /**
48
     * The recursion stack.
49
     *
50
     * @var array
51
     */
52
    public static $recursionStack = [];
53
54
    /**
55
     * @var Document
56
     */
57
    protected $document = null;
58
59
    /**
60
     * @var Header
61
     */
62
    protected $header = null;
63
64
    /**
65
     * @var string
66
     */
67
    protected $content = null;
68
69
    /**
70
     * @param Header $header
71
     * @param string $content
72
     */
73 30
    public function __construct(Document $document, Header $header = null, $content = null)
74
    {
75 30
        $this->document = $document;
76 30
        $this->header = null !== $header ? $header : new Header();
77 30
        $this->content = $content;
78 30
    }
79
80 26
    public function init()
81
    {
82 26
    }
83
84
    /**
85
     * @return Header|null
86
     */
87 26
    public function getHeader()
88
    {
89 26
        return $this->header;
90
    }
91
92
    /**
93
     * @param string $name
94
     *
95
     * @return Element|PDFObject
96
     */
97 21
    public function get($name)
98
    {
99 21
        return $this->header->get($name);
100
    }
101
102
    /**
103
     * @param string $name
104
     *
105
     * @return bool
106
     */
107 20
    public function has($name)
108
    {
109 20
        return $this->header->has($name);
110
    }
111
112
    /**
113
     * @param bool $deep
114
     *
115
     * @return array
116
     */
117 1
    public function getDetails($deep = true)
118
    {
119 1
        return $this->header->getDetails($deep);
120
    }
121
122
    /**
123
     * @return string|null
124
     */
125 18
    public function getContent()
126
    {
127 18
        return $this->content;
128
    }
129
130
    /**
131
     * @param string $content
132
     */
133 12
    public function cleanContent($content, $char = 'X')
134
    {
135 12
        $char = $char[0];
136 12
        $content = str_replace(['\\\\', '\\)', '\\('], $char.$char, $content);
137
138
        // Remove image bloc with binary content
139 12
        preg_match_all('/\s(BI\s.*?(\sID\s).*?(\sEI))\s/s', $content, $matches, PREG_OFFSET_CAPTURE);
140 12
        foreach ($matches[0] as $part) {
141
            $content = substr_replace($content, str_repeat($char, \strlen($part[0])), $part[1], \strlen($part[0]));
142
        }
143
144
        // Clean content in square brackets [.....]
145 12
        preg_match_all('/\[((\(.*?\)|[0-9\.\-\s]*)*)\]/s', $content, $matches, PREG_OFFSET_CAPTURE);
146 12
        foreach ($matches[1] as $part) {
147 10
            $content = substr_replace($content, str_repeat($char, \strlen($part[0])), $part[1], \strlen($part[0]));
148
        }
149
150
        // Clean content in round brackets (.....)
151 12
        preg_match_all('/\((.*?)\)/s', $content, $matches, PREG_OFFSET_CAPTURE);
152 12
        foreach ($matches[1] as $part) {
153 10
            $content = substr_replace($content, str_repeat($char, \strlen($part[0])), $part[1], \strlen($part[0]));
154
        }
155
156
        // Clean structure
157 12
        if ($parts = preg_split('/(<|>)/s', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)) {
158 12
            $content = '';
159 12
            $level = 0;
160 12
            foreach ($parts as $part) {
161 12
                if ('<' == $part) {
162 8
                    ++$level;
163
                }
164
165 12
                $content .= (0 == $level ? $part : str_repeat($char, \strlen($part)));
166
167 12
                if ('>' == $part) {
168 8
                    --$level;
169
                }
170
            }
171
        }
172
173
        // Clean BDC and EMC markup
174 12
        preg_match_all(
175 12
            '/(\/[A-Za-z0-9\_]*\s*'.preg_quote($char).'*BDC)/s',
176
            $content,
177
            $matches,
178 12
            PREG_OFFSET_CAPTURE
179
        );
180 12
        foreach ($matches[1] as $part) {
181 2
            $content = substr_replace($content, str_repeat($char, \strlen($part[0])), $part[1], \strlen($part[0]));
182
        }
183
184 12
        preg_match_all('/\s(EMC)\s/s', $content, $matches, PREG_OFFSET_CAPTURE);
185 12
        foreach ($matches[1] as $part) {
186 6
            $content = substr_replace($content, str_repeat($char, \strlen($part[0])), $part[1], \strlen($part[0]));
187
        }
188
189 12
        return $content;
190
    }
191
192
    /**
193
     * @param string $content
194
     *
195
     * @return array
196
     */
197 11
    public function getSectionsText($content)
198
    {
199 11
        $sections = [];
200 11
        $content = ' '.$content.' ';
201 11
        $textCleaned = $this->cleanContent($content, '_');
202
203
        // Extract text blocks.
204 11
        if (preg_match_all('/\s+BT[\s|\(|\[]+(.*?)\s*ET/s', $textCleaned, $matches, PREG_OFFSET_CAPTURE)) {
205 11
            foreach ($matches[1] as $part) {
206 11
                $text = $part[0];
207 11
                if ('' === $text) {
208
                    continue;
209
                }
210 11
                $offset = $part[1];
211 11
                $section = substr($content, $offset, \strlen($text));
212
213
                // Removes BDC and EMC markup.
214 11
                $section = preg_replace('/(\/[A-Za-z0-9]+\s*<<.*?)(>>\s*BDC)(.*?)(EMC\s+)/s', '${3}', $section.' ');
215
216 11
                $sections[] = $section;
217
            }
218
        }
219
220
        // Extract 'do' commands.
221 11
        if (preg_match_all('/(\/[A-Za-z0-9\.\-_]+\s+Do)\s/s', $textCleaned, $matches, PREG_OFFSET_CAPTURE)) {
222 2
            foreach ($matches[1] as $part) {
223 2
                $text = $part[0];
224 2
                $offset = $part[1];
225 2
                $section = substr($content, $offset, \strlen($text));
226
227 2
                $sections[] = $section;
228
            }
229
        }
230
231 11
        return $sections;
232
    }
233
234
    /**
235
     * @param Page $page
236
     *
237
     * @return string
238
     *
239
     * @throws \Exception
240
     */
241 4
    public function getText(Page $page = null)
242
    {
243 4
        $text = '';
244 4
        $sections = $this->getSectionsText($this->content);
245 4
        $current_font = null;
246
247 4
        foreach ($this->document->getObjects() as $obj) {
248 4
            if ($obj instanceof Font) {
249 4
                $current_font = $obj;
250 4
                break;
251
            }
252
        }
253
254 4
        if (null === $current_font) {
255
            $current_font = new Font($this->document);
256
        }
257
258 4
        $current_position_td = ['x' => false, 'y' => false];
259 4
        $current_position_tm = ['x' => false, 'y' => false];
260
261 4
        array_push(self::$recursionStack, $this->getUniqueId());
262
263 4
        foreach ($sections as $section) {
264 4
            $commands = $this->getCommandsText($section);
265
266 4
            foreach ($commands as $command) {
267 4
                switch ($command[self::OPERATOR]) {
268
                    // set character spacing
269 4
                    case 'Tc':
270 1
                        break;
271
272
                    // move text current point
273 4
                    case 'Td':
274 2
                        $args = preg_split('/\s/s', $command[self::COMMAND]);
275 2
                        $y = array_pop($args);
0 ignored issues
show
Bug introduced by
It seems like $args can also be of type false; however, parameter $array of array_pop() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

275
                        $y = array_pop(/** @scrutinizer ignore-type */ $args);
Loading history...
276 2
                        $x = array_pop($args);
277 2
                        if (((float) $x <= 0) ||
278 2
                            (false !== $current_position_td['y'] && (float) $y < (float) ($current_position_td['y']))
279
                        ) {
280
                            // vertical offset
281 2
                            $text .= "\n";
282 2
                        } elseif (false !== $current_position_td['x'] && (float) $x > (float) (
283 2
                                $current_position_td['x']
284
                            )
285
                        ) {
286
                            // horizontal offset
287 2
                            $text .= ' ';
288
                        }
289 2
                        $current_position_td = ['x' => $x, 'y' => $y];
290 2
                        break;
291
292
                    // move text current point and set leading
293 4
                    case 'TD':
294 1
                        $args = preg_split('/\s/s', $command[self::COMMAND]);
295 1
                        $y = array_pop($args);
296 1
                        $x = array_pop($args);
297 1
                        if ((float) $y < 0) {
298 1
                            $text .= "\n";
299
                        } elseif ((float) $x <= 0) {
300
                            $text .= ' ';
301
                        }
302 1
                        break;
303
304 4
                    case 'Tf':
305 4
                        list($id) = preg_split('/\s/s', $command[self::COMMAND]);
306 4
                        $id = trim($id, '/');
307 4
                        if (null !== $page) {
308 4
                            $current_font = $page->getFont($id);
309
                        }
310 4
                        break;
311
312 4
                    case "'":
313 4
                    case 'Tj':
314 2
                        $command[self::COMMAND] = [$command];
315
                        // no break
316 4
                    case 'TJ':
317
                        // Skip if not previously defined, should never happened.
318 4
                        if (null === $current_font) {
319
                            // Fallback
320
                            // TODO : Improve
321 1
                            $text .= $command[self::COMMAND][0][self::COMMAND];
322 1
                            break;
323
                        }
324
325 4
                        $sub_text = $current_font->decodeText($command[self::COMMAND]);
326 4
                        $text .= $sub_text;
327 4
                        break;
328
329
                    // set leading
330 4
                    case 'TL':
331 1
                        $text .= ' ';
332 1
                        break;
333
334 4
                    case 'Tm':
335 4
                        $args = preg_split('/\s/s', $command[self::COMMAND]);
336 4
                        $y = array_pop($args);
337 4
                        $x = array_pop($args);
338 4
                        if (false !== $current_position_tm['x']) {
339 4
                            $delta = abs((float) $x - (float) ($current_position_tm['x']));
340 4
                            if ($delta > 10) {
341 3
                                $text .= "\t";
342
                            }
343
                        }
344 4
                        if (false !== $current_position_tm['y']) {
345 4
                            $delta = abs((float) $y - (float) ($current_position_tm['y']));
346 4
                            if ($delta > 10) {
347 3
                                $text .= "\n";
348
                            }
349
                        }
350 4
                        $current_position_tm = ['x' => $x, 'y' => $y];
351 4
                        break;
352
353
                    // set super/subscripting text rise
354 4
                    case 'Ts':
355
                        break;
356
357
                    // set word spacing
358 4
                    case 'Tw':
359 1
                        break;
360
361
                    // set horizontal scaling
362 4
                    case 'Tz':
363
                        $text .= "\n";
364
                        break;
365
366
                    // move to start of next line
367 4
                    case 'T*':
368 2
                        $text .= "\n";
369 2
                        break;
370
371 3
                    case 'Da':
372
                        break;
373
374 3
                    case 'Do':
375 2
                        if (null !== $page) {
376 2
                            $args = preg_split('/\s/s', $command[self::COMMAND]);
377 2
                            $id = trim(array_pop($args), '/ ');
378 2
                            $xobject = $page->getXObject($id);
379
380
                            // @todo $xobject could be a ElementXRef object, which would then throw an error
381 2
                            if (\is_object($xobject) && $xobject instanceof self && !\in_array($xobject->getUniqueId(), self::$recursionStack)) {
382
                                // Not a circular reference.
383 2
                                $text .= $xobject->getText($page);
384
                            }
385
                        }
386 2
                        break;
387
388 3
                    case 'rg':
389 3
                    case 'RG':
390 1
                        break;
391
392 3
                    case 're':
393
                        break;
394
395 3
                    case 'co':
396
                        break;
397
398 3
                    case 'cs':
399 1
                        break;
400
401 3
                    case 'gs':
402 2
                        break;
403
404 3
                    case 'en':
405
                        break;
406
407 3
                    case 'sc':
408 3
                    case 'SC':
409
                        break;
410
411 3
                    case 'g':
412 3
                    case 'G':
413 2
                        break;
414
415 2
                    case 'V':
416
                        break;
417
418 2
                    case 'vo':
419 2
                    case 'Vo':
420
                        break;
421
422
                    default:
423
                }
424
            }
425
        }
426
427 4
        array_pop(self::$recursionStack);
428
429 4
        return $text.' ';
430
    }
431
432
    /**
433
     * @param Page $page
434
     *
435
     * @return array
436
     *
437
     * @throws \Exception
438
     */
439 3
    public function getTextArray(Page $page = null)
440
    {
441 3
        $text = [];
442 3
        $sections = $this->getSectionsText($this->content);
443 3
        $current_font = new Font($this->document);
444
445 3
        foreach ($sections as $section) {
446 3
            $commands = $this->getCommandsText($section);
447
448 3
            foreach ($commands as $command) {
449 3
                switch ($command[self::OPERATOR]) {
450
                    // set character spacing
451 3
                    case 'Tc':
452 2
                        break;
453
454
                    // move text current point
455 3
                    case 'Td':
456 3
                        break;
457
458
                    // move text current point and set leading
459 3
                    case 'TD':
460
                        break;
461
462 3
                    case 'Tf':
463 3
                        list($id) = preg_split('/\s/s', $command[self::COMMAND]);
464 3
                        $id = trim($id, '/');
465 3
                        $current_font = $page->getFont($id);
0 ignored issues
show
Bug introduced by
The method getFont() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

465
                        /** @scrutinizer ignore-call */ 
466
                        $current_font = $page->getFont($id);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
466 3
                        break;
467
468 3
                    case "'":
469 3
                    case 'Tj':
470 3
                        $command[self::COMMAND] = [$command];
471
                        // no break
472 3
                    case 'TJ':
473
                        // Skip if not previously defined, should never happened.
474 3
                        if (null === $current_font) {
475
                            // Fallback
476
                            // TODO : Improve
477
                            $text[] = $command[self::COMMAND][0][self::COMMAND];
478
                            break;
479
                        }
480
481 3
                        $sub_text = $current_font->decodeText($command[self::COMMAND]);
482 3
                        $text[] = $sub_text;
483 3
                        break;
484
485
                    // set leading
486 3
                    case 'TL':
487 2
                        break;
488
489 3
                    case 'Tm':
490 2
                        break;
491
492
                    // set super/subscripting text rise
493 3
                    case 'Ts':
494
                        break;
495
496
                    // set word spacing
497 3
                    case 'Tw':
498 1
                        break;
499
500
                    // set horizontal scaling
501 3
                    case 'Tz':
502
                        //$text .= "\n";
503
                        break;
504
505
                    // move to start of next line
506 3
                    case 'T*':
507
                        //$text .= "\n";
508 2
                        break;
509
510 3
                    case 'Da':
511
                        break;
512
513 3
                    case 'Do':
514
                        if (null !== $page) {
515
                            $args = preg_split('/\s/s', $command[self::COMMAND]);
516
                            $id = trim(array_pop($args), '/ ');
0 ignored issues
show
Bug introduced by
It seems like $args can also be of type false; however, parameter $array of array_pop() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

516
                            $id = trim(array_pop(/** @scrutinizer ignore-type */ $args), '/ ');
Loading history...
517
                            if ($xobject = $page->getXObject($id)) {
518
                                $text[] = $xobject->getText($page);
519
                            }
520
                        }
521
                        break;
522
523 3
                    case 'rg':
524 3
                    case 'RG':
525 2
                        break;
526
527 3
                    case 're':
528
                        break;
529
530 3
                    case 'co':
531
                        break;
532
533 3
                    case 'cs':
534
                        break;
535
536 3
                    case 'gs':
537
                        break;
538
539 3
                    case 'en':
540
                        break;
541
542 3
                    case 'sc':
543 3
                    case 'SC':
544
                        break;
545
546 3
                    case 'g':
547 3
                    case 'G':
548 2
                        break;
549
550 1
                    case 'V':
551
                        break;
552
553 1
                    case 'vo':
554 1
                    case 'Vo':
555
                        break;
556
557
                    default:
558
                }
559
            }
560
        }
561
562 3
        return $text;
563
    }
564
565
    /**
566
     * @param string $text_part
567
     * @param int    $offset
568
     *
569
     * @return array
570
     */
571 11
    public function getCommandsText($text_part, &$offset = 0)
572
    {
573 11
        $commands = $matches = [];
574
575 11
        while ($offset < \strlen($text_part)) {
576 11
            $offset += strspn($text_part, "\x00\x09\x0a\x0c\x0d\x20", $offset);
577 11
            $char = $text_part[$offset];
578
579 11
            $operator = '';
580 11
            $type = '';
581 11
            $command = false;
582
583 11
            switch ($char) {
584 11
                case '/':
585 11
                    $type = $char;
586 11
                    if (preg_match(
587 11
                        '/^\/([A-Z0-9\._,\+]+\s+[0-9.\-]+)\s+([A-Z]+)\s*/si',
588 11
                        substr($text_part, $offset),
589
                        $matches
590
                    )
591
                    ) {
592 11
                        $operator = $matches[2];
593 11
                        $command = $matches[1];
594 11
                        $offset += \strlen($matches[0]);
595
                    } elseif (preg_match(
596 3
                        '/^\/([A-Z0-9\._,\+]+)\s+([A-Z]+)\s*/si',
597 3
                        substr($text_part, $offset),
598
                        $matches
599
                    )
600
                    ) {
601 3
                        $operator = $matches[2];
602 3
                        $command = $matches[1];
603 3
                        $offset += \strlen($matches[0]);
604
                    }
605 11
                    break;
606
607 11
                case '[':
608 11
                case ']':
609
                    // array object
610 11
                    $type = $char;
611 11
                    if ('[' == $char) {
612 11
                        ++$offset;
613
                        // get elements
614 11
                        $command = $this->getCommandsText($text_part, $offset);
615
616 11
                        if (preg_match('/^\s*[A-Z]{1,2}\s*/si', substr($text_part, $offset), $matches)) {
617 11
                            $operator = trim($matches[0]);
618 11
                            $offset += \strlen($matches[0]);
619
                        }
620
                    } else {
621 11
                        ++$offset;
622 11
                        break;
623
                    }
624 11
                    break;
625
626 11
                case '<':
627 11
                case '>':
628
                    // array object
629 4
                    $type = $char;
630 4
                    ++$offset;
631 4
                    if ('<' == $char) {
632 4
                        $strpos = strpos($text_part, '>', $offset);
633 4
                        $command = substr($text_part, $offset, ($strpos - $offset));
634 4
                        $offset = $strpos + 1;
635
                    }
636
637 4
                    if (preg_match('/^\s*[A-Z]{1,2}\s*/si', substr($text_part, $offset), $matches)) {
638 3
                        $operator = trim($matches[0]);
639 3
                        $offset += \strlen($matches[0]);
640
                    }
641 4
                    break;
642
643 11
                case '(':
644 11
                case ')':
645 9
                    ++$offset;
646 9
                    $type = $char;
647 9
                    $strpos = $offset;
648 9
                    if ('(' == $char) {
649 9
                        $open_bracket = 1;
650 9
                        while ($open_bracket > 0) {
651 9
                            if (!isset($text_part[$strpos])) {
652
                                break;
653
                            }
654 9
                            $ch = $text_part[$strpos];
655 9
                            switch ($ch) {
656 9
                                case '\\':
657
                                 // REVERSE SOLIDUS (5Ch) (Backslash)
658
                                    // skip next character
659 8
                                    ++$strpos;
660 8
                                    break;
661
662 9
                                case '(':
663
                                 // LEFT PARENHESIS (28h)
664
                                    ++$open_bracket;
665
                                    break;
666
667 9
                                case ')':
668
                                 // RIGHT PARENTHESIS (29h)
669 9
                                    --$open_bracket;
670 9
                                    break;
671
                            }
672 9
                            ++$strpos;
673
                        }
674 9
                        $command = substr($text_part, $offset, ($strpos - $offset - 1));
675 9
                        $offset = $strpos;
676
677 9
                        if (preg_match('/^\s*([A-Z\']{1,2})\s*/si', substr($text_part, $offset), $matches)) {
678 8
                            $operator = $matches[1];
679 8
                            $offset += \strlen($matches[0]);
680
                        }
681
                    }
682 9
                    break;
683
684
                default:
685
686 11
                    if ('ET' == substr($text_part, $offset, 2)) {
687 1
                        break;
688
                    } elseif (preg_match(
689 11
                        '/^\s*(?P<data>([0-9\.\-]+\s*?)+)\s+(?P<id>[A-Z]{1,3})\s*/si',
690 11
                        substr($text_part, $offset),
691
                        $matches
692
                    )
693
                    ) {
694 11
                        $operator = trim($matches['id']);
695 11
                        $command = trim($matches['data']);
696 11
                        $offset += \strlen($matches[0]);
697 11
                    } elseif (preg_match('/^\s*([0-9\.\-]+\s*?)+\s*/si', substr($text_part, $offset), $matches)) {
698 11
                        $type = 'n';
699 11
                        $command = trim($matches[0]);
700 11
                        $offset += \strlen($matches[0]);
701 8
                    } elseif (preg_match('/^\s*([A-Z\*]+)\s*/si', substr($text_part, $offset), $matches)) {
702 8
                        $type = '';
703 8
                        $operator = $matches[1];
704 8
                        $command = '';
705 8
                        $offset += \strlen($matches[0]);
706
                    }
707
            }
708
709 11
            if (false !== $command) {
710 11
                $commands[] = [
711 11
                    self::TYPE => $type,
712 11
                    self::OPERATOR => $operator,
713 11
                    self::COMMAND => $command,
714
                ];
715
            } else {
716 11
                break;
717
            }
718
        }
719
720 11
        return $commands;
721
    }
722
723
    /**
724
     * @param string $content
725
     *
726
     * @return PDFObject
727
     */
728 18
    public static function factory(Document $document, Header $header, $content)
729
    {
730 18
        switch ($header->get('Type')->getContent()) {
731 18
            case 'XObject':
732 3
                switch ($header->get('Subtype')->getContent()) {
733 3
                    case 'Image':
734 2
                        return new Image($document, $header, $content);
735
736 2
                    case 'Form':
737 2
                        return new Form($document, $header, $content);
738
                }
739
740
                return new self($document, $header, $content);
741
742 18
            case 'Pages':
743 18
                return new Pages($document, $header, $content);
744
745 18
            case 'Page':
746 18
                return new Page($document, $header, $content);
747
748 18
            case 'Encoding':
749 2
                return new Encoding($document, $header, $content);
750
751 18
            case 'Font':
752 18
                $subtype = $header->get('Subtype')->getContent();
753 18
                $classname = '\Smalot\PdfParser\Font\Font'.$subtype;
754
755 18
                if (class_exists($classname)) {
756 18
                    return new $classname($document, $header, $content);
757
                }
758
759
                return new Font($document, $header, $content);
760
761
            default:
762 18
                return new self($document, $header, $content);
763
        }
764
    }
765
766
    /**
767
     * Returns unique id identifying the object.
768
     *
769
     * @return string
770
     */
771 4
    protected function getUniqueId()
772
    {
773 4
        return spl_object_hash($this);
774
    }
775
}
776