read(new FileBytes($bytes)); // 2. This operation traverses the entire tree: Count and Parent are checked, // Kids order is preserved, and the four inheritable attributes are resolved. // These limits bound indirect traversal independently of syntax depth. $tree = (new PageTreeReader($document, new PageTreeLimits(maxDepth: 64, maxNodes: 10000, maxPages: 5000)))->read(); printf("Verified pages: %d\n", count($tree)); $contentReader = new PageContentsReader($document, new PageContentLimits(maxStreams: 128)); foreach ($tree as $index => $page) { // 3. Effective values are core objects. The source dictionary retains only // its local entries; it is neither modified nor imported. printf( "Page %d (%s R): MediaBox %s; CropBox %s; Rotate %d (orientation %d); resource categories %d\n", $index + 1, $page->reference->identifier, $page->attributes->mediaBox, $page->attributes->cropBox, $page->attributes->rotate->integer(), $page->attributes->normalizedRotation(), count($page->attributes->resources), ); // 4. Contents belongs only to this page. Inspection preserves separate // streams in order, including their filters and encoded bytes. $contents = $contentReader->read($page); printf(" Content streams: %d\n", count($contents)); foreach ($contents as $ordinal => $stream) { // Decoding is requested here under the document's cumulative budgets. // The resulting bytes remain PDF instructions, without text extraction. $decoded = $document->streamData($stream); printf(" Stream %d: %d encoded bytes, %d decoded bytes\n", $ordinal + 1, strlen($stream->encodedBytes()), strlen($decoded)); } }