diff --git a/src/FpdfTrait.php b/src/FpdfTrait.php index 0b56288..67fa561 100644 --- a/src/FpdfTrait.php +++ b/src/FpdfTrait.php @@ -14,6 +14,7 @@ use setasign\Fpdi\PdfParser\PdfParserException; use setasign\Fpdi\PdfParser\Type\PdfIndirectObject; use setasign\Fpdi\PdfParser\Type\PdfNull; +use setasign\Fpdi\PdfParser\Type\PdfType; /** * This trait is used for the implementation of FPDI in FPDF and tFPDF. @@ -142,20 +143,6 @@ protected function _putlinks($n) $this->_put('/A <_textstring($pl[4]) . '>>'); if (isset($pl['importedLink'])) { $values = $pl['importedLink']['pdfObject']->value; - unset( - $values['P'], - $values['NM'], - $values['AP'], - $values['AS'], - $values['Type'], - $values['Subtype'], - $values['Rect'], - $values['A'], - $values['QuadPoints'], - $values['Rotate'], - $values['M'], - $values['StructParent'] - ); foreach ($values as $name => $entry) { $this->_put('/' . $name . ' ', false); diff --git a/src/PdfReader/Page.php b/src/PdfReader/Page.php index 337c1a7..ad3c0c2 100644 --- a/src/PdfReader/Page.php +++ b/src/PdfReader/Page.php @@ -381,6 +381,29 @@ public function getExternalLinks($box = PageBoundaries::CROP_BOX) } } + // we remove unsupported/unneeded values here + unset( + $annotation->value['P'], + $annotation->value['NM'], + $annotation->value['AP'], + $annotation->value['AS'], + $annotation->value['Type'], + $annotation->value['Subtype'], + $annotation->value['Rect'], + $annotation->value['A'], + $annotation->value['QuadPoints'], + $annotation->value['Rotate'], + $annotation->value['M'], + $annotation->value['StructParent'], + $annotation->value['OC'] + ); + + // ...and flatten the PDF object to eliminate any indirect references. + // Indirect references are a problem when writing the output in FPDF + // because FPDF uses pre-calculated object numbers while FPDI creates + // them at runtime. + $annotation = PdfType::flatten($annotation, $this->parser); + $links[] = [ 'rect' => $normalizedRect, 'quadPoints' => $normalizedQuadPoints, diff --git a/src/Tcpdf/Fpdi.php b/src/Tcpdf/Fpdi.php index f82c690..e790b51 100644 --- a/src/Tcpdf/Fpdi.php +++ b/src/Tcpdf/Fpdi.php @@ -303,21 +303,8 @@ protected function adjustLastLink($externalLink, $xPt, $scaleX, $yPt, $newHeight // ensure we have a default value - otherwise TCPDF will set it to 4 throughout $lastAnnotationOpt['f'] = 0; + // values in this dictonary are all direct objects and we don't need to resolve them here again. $values = $externalLink['pdfObject']->value; - unset( - $values['P'], - $values['NM'], - $values['AP'], - $values['AS'], - $values['Type'], - $values['Subtype'], - $values['Rect'], - $values['A'], - $values['QuadPoints'], - $values['Rotate'], - $values['M'], - $values['StructParent'] - ); foreach ($values as $key => $value) { try { @@ -326,17 +313,17 @@ protected function adjustLastLink($externalLink, $xPt, $scaleX, $yPt, $newHeight $value = PdfDictionary::ensure($value); $bs = []; if (isset($value->value['W'])) { - $bs['w'] = PdfNumeric::ensure(PdfType::resolve($value->value['W'], $parser))->value; + $bs['w'] = PdfNumeric::ensure($value->value['W'])->value; } if (isset($value->value['S'])) { - $bs['s'] = PdfName::ensure(PdfType::resolve($value->value['S'], $parser))->value; + $bs['s'] = PdfName::ensure($value->value['S'])->value; } if (isset($value->value['D'])) { $d = []; - foreach (PdfArray::ensure(PdfType::resolve($value->value['D'], $parser))->value as $item) { - $d[] = PdfNumeric::ensure(PdfType::resolve($item, $parser))->value; + foreach (PdfArray::ensure($value->value['D'])->value as $item) { + $d[] = PdfNumeric::ensure($item)->value; } $bs['d'] = $d; } @@ -345,20 +332,20 @@ protected function adjustLastLink($externalLink, $xPt, $scaleX, $yPt, $newHeight break; case 'Border': - $borderArray = PdfArray::ensure(PdfType::resolve($value, $parser))->value; + $borderArray = PdfArray::ensure($value)->value; if (count($borderArray) < 3) { continue 2; } $border = [ - PdfNumeric::ensure(PdfType::resolve($borderArray[0], $parser))->value, - PdfNumeric::ensure(PdfType::resolve($borderArray[1], $parser))->value, - PdfNumeric::ensure(PdfType::resolve($borderArray[2], $parser))->value, + PdfNumeric::ensure($borderArray[0])->value, + PdfNumeric::ensure($borderArray[1])->value, + PdfNumeric::ensure($borderArray[2])->value, ]; if (isset($borderArray[3])) { $dashArray = []; - foreach (PdfArray::ensure(PdfType::resolve($borderArray[3], $parser))->value as $item) { - $dashArray[] = PdfNumeric::ensure(PdfType::resolve($item, $parser))->value; + foreach (PdfArray::ensure($borderArray[3])->value as $item) { + $dashArray[] = PdfNumeric::ensure($item)->value; } $border[] = $dashArray; } @@ -371,7 +358,7 @@ protected function adjustLastLink($externalLink, $xPt, $scaleX, $yPt, $newHeight $colors = PdfArray::ensure(PdfType::resolve($value, $parser))->value; $m = count($colors) === 4 ? 100 : 255; foreach ($colors as $item) { - $c[] = PdfNumeric::ensure(PdfType::resolve($item, $parser))->value * $m; + $c[] = PdfNumeric::ensure($item)->value * $m; } $lastAnnotationOpt['c'] = $c; break; diff --git a/tests/functional/LinkHandling/AbstractTest.php b/tests/functional/LinkHandling/AbstractTest.php index c16303b..11f7f1e 100644 --- a/tests/functional/LinkHandling/AbstractTest.php +++ b/tests/functional/LinkHandling/AbstractTest.php @@ -33,7 +33,6 @@ protected function compatAssertEqualsWithDelta($expected, $actual, $message = '' } } - protected function save($pdf) { return $pdf->Output('S'); @@ -131,11 +130,11 @@ public function testDoNotImportLinks() * This test simply imports a page with several links including quad-points * and place it resized and compressed onto a new page. */ - public function testLinkHandling1() + public function testLinkHandling1($filename = __DIR__ . '/../../_files/pdfs/links/links.pdf') { $pdf = $this->getInstance(); $pdf->AddPage(); - $pdf->setSourceFile(__DIR__ . '/../../_files/pdfs/links/links.pdf'); + $pdf->setSourceFile($filename); $tplId = $pdf->importPage(1, PageBoundaries::CROP_BOX, true, true); $pdf->useTemplate($tplId, [ 'x' => 20, @@ -235,6 +234,18 @@ public function testLinkHandling1() return $pdfString; } + /** + * This test imports annotations with indirect references in their properties which should be flattened. + * + * The original file links.pdf was modified appropriately. + * + * @return void + */ + public function testLinkHandlingWithIndirectReferencesInAnnotation() + { + $this->testLinkHandling1(__DIR__ . '/../../_files/pdfs/links/links-with-indirect-references.pdf'); + } + /** * Take the result of testLinkHandling1 and re-place it with the same settings. * @depends testLinkHandling1