diff --git a/src/FpdiTrait.php b/src/FpdiTrait.php index 0e6af47..6d57b99 100644 --- a/src/FpdiTrait.php +++ b/src/FpdiTrait.php @@ -596,7 +596,7 @@ protected function writePdfType(PdfType $value) } elseif ($value instanceof PdfString) { $this->_put('(' . $value->value . ')', false); } elseif ($value instanceof PdfHexString) { - $this->_put('<' . $value->value . '>'); + $this->_put('<' . $value->value . '>', false); } elseif ($value instanceof PdfBoolean) { $this->_put($value->value ? 'true ' : 'false ', false); } elseif ($value instanceof PdfArray) { @@ -615,11 +615,8 @@ protected function writePdfType(PdfType $value) } elseif ($value instanceof PdfToken) { $this->_put($value->value); } elseif ($value instanceof PdfNull) { - $this->_put('null '); + $this->_put('null ', false); } elseif ($value instanceof PdfStream) { - /** - * @var $value PdfStream - */ $this->writePdfType($value->value); $this->_put('stream'); $this->_put($value->getStream()); @@ -636,12 +633,22 @@ protected function writePdfType(PdfType $value) $this->_put($this->objectMap[$this->currentReaderId][$value->value] . ' 0 R ', false); } elseif ($value instanceof PdfIndirectObject) { - /** - * @var PdfIndirectObject $value - */ $n = $this->objectMap[$this->currentReaderId][$value->objectNumber]; $this->_newobj($n); $this->writePdfType($value->value); + + // add newline before "endobj" for all objects in view to PDF/A conformance + if ( + !( + ($value->value instanceof PdfArray) || + ($value->value instanceof PdfDictionary) || + ($value->value instanceof PdfToken) || + ($value->value instanceof PdfStream) + ) + ) { + $this->_put("\n", false); + } + $this->_put('endobj'); } } diff --git a/tests/functional/FpdiTraitTest.php b/tests/functional/FpdiTraitTest.php index 2c2ff28..395ba8a 100644 --- a/tests/functional/FpdiTraitTest.php +++ b/tests/functional/FpdiTraitTest.php @@ -4,6 +4,19 @@ use PHPUnit\Framework\TestCase; use setasign\Fpdi\Fpdi; +use setasign\Fpdi\PdfParser\Type\PdfArray; +use setasign\Fpdi\PdfParser\Type\PdfBoolean; +use setasign\Fpdi\PdfParser\Type\PdfDictionary; +use setasign\Fpdi\PdfParser\Type\PdfHexString; +use setasign\Fpdi\PdfParser\Type\PdfIndirectObject; +use setasign\Fpdi\PdfParser\Type\PdfIndirectObjectReference; +use setasign\Fpdi\PdfParser\Type\PdfName; +use setasign\Fpdi\PdfParser\Type\PdfNull; +use setasign\Fpdi\PdfParser\Type\PdfNumeric; +use setasign\Fpdi\PdfParser\Type\PdfStream; +use setasign\Fpdi\PdfParser\Type\PdfString; +use setasign\Fpdi\PdfParser\Type\PdfToken; +use setasign\Fpdi\PdfParser\Type\PdfType; class FpdiTraitTest extends TestCase { @@ -168,4 +181,184 @@ public function testFaultyStructures($path, $pageNo = 1) $id = $pdf->importPage($pageNo); $this->assertTrue(isset($id)); } + + public function writePdfTypeProvider() + { + return [ + [ + PdfBoolean::create(true), + 'true ' + ], + [ + PdfHexString::create('48656c6c6f20576f726c64'), + '<48656c6c6f20576f726c64>' + ], + [ + PdfString::create('Hello FPDI'), + '(Hello FPDI)' + ], + [ + PdfName::create('FPDI'), + '/FPDI ' + ], + [ + new PdfNull(), + 'null ' + ], + [ + PdfNumeric::create(1.234566), + '1.23457 ' + ], + [ + PdfNumeric::create('1.00000'), + '1 ' + ], + [ + PdfNumeric::create('01234'), + '1234 ' + ], + [ + PdfIndirectObjectReference::create(123, 0), + '1 0 R ' // this is correct because the imported objects will be remapped to new object ids. + ], + [ + PdfToken::create('AnyToken'), + "AnyToken\n" + ], + [ + PdfArray::create([ + PdfNumeric::create(1), + PdfString::create('Hey') + ]), + "[1 (Hey)]\n" + ], + [ + PdfDictionary::create([ + 'A' => PdfName::create('Ok'), + 'B' => PdfArray::create([ + + ]), + 'C' => PdfString::create('C') + ]), + "<>\n" + ], + [ + PdfStream::create(PdfDictionary::create(), 'Testen'), + "<<>>\n" . + "stream\n" . + "Testen\n" . + "endstream\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfArray::create()), + "1 0 obj\n" . + "[]\n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfBoolean::create(false)), + "1 0 obj\n" . + "false \n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfDictionary::create()), + "1 0 obj\n" . + "<<>>\n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfHexString::create('')), + "1 0 obj\n" . + "<>\n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfIndirectObjectReference::create(2, 0)), + "1 0 obj\n" . + "2 0 R \n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfName::create('FPDI')), + "1 0 obj\n" . + "/FPDI \n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, new PdfNull()), + "1 0 obj\n" . + "null \n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfNumeric::create(123)), + "1 0 obj\n" . + "123 \n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfStream::create(PdfDictionary::create(), 'Test')), + "1 0 obj\n" . + "<<>>\n" . + "stream\n" . + "Test\n" . + "endstream\n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfString::create('FPDI')), + "1 0 obj\n" . + "(FPDI)\n" . + "endobj\n" + ], + [ + PdfIndirectObject::create(1, 0, PdfToken::create('AnyToken')), + "1 0 obj\n" . + "AnyToken\n" . + "endobj\n" + ], + ]; + } + + /** + * @param $value + * @param $expected + * @return void + * @dataProvider writePdfTypeProvider + */ + public function testWritePdfType($value, $expected) + { + $instance = new FpdiTraitTestClass(); + $result = $instance->simulateWritePdfType($value); + $this->assertSame($expected, $result); + } + + public function testWritingOfIndirectObjectsAndReferences() + { + $instance = new FpdiTraitTestClass(); + $result = $instance->simulateWritePdfType(PdfIndirectObjectReference::create(123, 0)); + $this->assertSame('1 0 R ', $result); + + $result = $instance->simulateWritePdfType(PdfIndirectObjectReference::create(124, 0)); + $this->assertSame('2 0 R ', $result); + + $result = $instance->simulateWritePdfType(PdfIndirectObject::create(123, 0, new PdfNull())); + $this->assertSame( + "1 0 obj\n" . + "null \n" . + "endobj\n", + $result + ); + + $result = $instance->simulateWritePdfType(PdfIndirectObject::create(124, 0, new PdfNull())); + $this->assertSame( + "2 0 obj\n" . + "null \n" . + "endobj\n", + $result + ); + + } } \ No newline at end of file diff --git a/tests/functional/FpdiTraitTestClass.php b/tests/functional/FpdiTraitTestClass.php new file mode 100644 index 0000000..bb19fc9 --- /dev/null +++ b/tests/functional/FpdiTraitTestClass.php @@ -0,0 +1,41 @@ +n; + } + + $this->_put($n . ' 0 obj'); + } + + public function simulateWritePdfType(PdfType $value) + { + // If the object was not referenced before we need to add an object number here + if ($value instanceof PdfIndirectObject) { + if (!isset($this->objectMap[$this->currentReaderId][$value->objectNumber])) { + $this->objectMap[$this->currentReaderId][$value->objectNumber] = ++$this->n; + } + } + + $this->buffer = ''; + $this->writePdfType($value); + return $this->buffer; + } +}