|
9 | 9 | import pypdf.xmp
|
10 | 10 | from pypdf import PdfReader, PdfWriter
|
11 | 11 | from pypdf.errors import PdfReadError
|
| 12 | +from pypdf.generic import NameObject, StreamObject |
| 13 | +from pypdf.xmp import XmpInformation |
12 | 14 |
|
13 | 15 | from . import get_data_from_url
|
14 | 16 |
|
@@ -325,3 +327,91 @@ def test_dc_language__no_bag_container():
|
325 | 327 |
|
326 | 328 | assert reader.xmp_metadata is not None
|
327 | 329 | assert reader.xmp_metadata.dc_language == ["x-unknown"]
|
| 330 | + |
| 331 | + |
| 332 | +def test_reading_does_not_destroy_root_object(): |
| 333 | + """Test for #3391.""" |
| 334 | + writer = PdfWriter(clone_from=RESOURCE_ROOT / "commented-xmp.pdf") |
| 335 | + xmp = writer.xmp_metadata |
| 336 | + assert xmp is not None |
| 337 | + assert not isinstance(writer.root_object["/Metadata"], XmpInformation) |
| 338 | + assert isinstance(writer.root_object["/Metadata"].get_object(), StreamObject) |
| 339 | + |
| 340 | + output = BytesIO() |
| 341 | + writer.write(output) |
| 342 | + output_bytes = output.getvalue() |
| 343 | + assert b"\n/Metadata 27 0 R\n" in output_bytes |
| 344 | + |
| 345 | + |
| 346 | +def test_xmp_information__write_to_stream(): |
| 347 | + writer = PdfWriter(clone_from=RESOURCE_ROOT / "commented-xmp.pdf") |
| 348 | + xmp = writer.xmp_metadata |
| 349 | + |
| 350 | + output = BytesIO() |
| 351 | + with pytest.warns( |
| 352 | + DeprecationWarning, |
| 353 | + match=( |
| 354 | + r"^XmpInformation\.write_to_stream is deprecated and will be removed in pypdf 6\.0\.0\. " |
| 355 | + r"Use PdfWriter\.xmp_metadata instead\.$" |
| 356 | + ) |
| 357 | + ): |
| 358 | + xmp.write_to_stream(output) |
| 359 | + output_bytes = output.getvalue() |
| 360 | + assert output_bytes.startswith(b"<<\n/Type /Metadata\n/Subtype /XML\n/Length 2786\n>>\nstream\n<?xpacket begin") |
| 361 | + |
| 362 | + |
| 363 | +def test_pdf_writer__xmp_metadata_setter(): |
| 364 | + # Clear existing metadata. |
| 365 | + writer = PdfWriter(clone_from=RESOURCE_ROOT / "commented-xmp.pdf") |
| 366 | + assert writer.xmp_metadata is not None |
| 367 | + original_metadata = writer.xmp_metadata.stream.get_data() |
| 368 | + writer.xmp_metadata = None |
| 369 | + output = BytesIO() |
| 370 | + writer.write(output) |
| 371 | + output_bytes = output.getvalue() |
| 372 | + reader = PdfReader(BytesIO(output_bytes)) |
| 373 | + assert reader.xmp_metadata is None |
| 374 | + |
| 375 | + # Attempt to clear again. |
| 376 | + writer = PdfWriter(clone_from=reader) |
| 377 | + assert writer.xmp_metadata is None |
| 378 | + writer.xmp_metadata = None |
| 379 | + output = BytesIO() |
| 380 | + writer.write(output) |
| 381 | + output_bytes = output.getvalue() |
| 382 | + reader = PdfReader(BytesIO(output_bytes)) |
| 383 | + assert reader.xmp_metadata is None |
| 384 | + |
| 385 | + # Set new metadata from bytes. |
| 386 | + writer = PdfWriter(clone_from=reader) |
| 387 | + assert writer.xmp_metadata is None |
| 388 | + writer.xmp_metadata = original_metadata |
| 389 | + output = BytesIO() |
| 390 | + writer.write(output) |
| 391 | + output_bytes = output.getvalue() |
| 392 | + reader = PdfReader(BytesIO(output_bytes)) |
| 393 | + assert get_all_tiff(reader.xmp_metadata) == {"tiff:Artist": ["me"]} |
| 394 | + |
| 395 | + # Set metadata from XmpInformation. |
| 396 | + writer = PdfWriter(clone_from=reader) |
| 397 | + xmp_metadata = writer.xmp_metadata |
| 398 | + assert get_all_tiff(xmp_metadata) == {"tiff:Artist": ["me"]} |
| 399 | + new_metadata = original_metadata.replace(b"<tiff:Artist>me</tiff:Artist>", b"<tiff:Artist>Foo Bar</tiff:Artist>") |
| 400 | + xmp_metadata.stream.set_data(new_metadata) |
| 401 | + output = BytesIO() |
| 402 | + writer.write(output) |
| 403 | + output_bytes = output.getvalue() |
| 404 | + reader = PdfReader(BytesIO(output_bytes)) |
| 405 | + assert get_all_tiff(reader.xmp_metadata) == {"tiff:Artist": ["Foo Bar"]} |
| 406 | + |
| 407 | + # Fix metadata not being an IndirectObject before. |
| 408 | + writer = PdfWriter(clone_from=RESOURCE_ROOT / "commented-xmp.pdf") |
| 409 | + writer.root_object[NameObject("/Metadata")] = writer.root_object["/Metadata"].get_object() |
| 410 | + assert "/XML" in str(writer.root_object) |
| 411 | + writer.xmp_metadata = new_metadata |
| 412 | + output = BytesIO() |
| 413 | + writer.write(output) |
| 414 | + output_bytes = output.getvalue() |
| 415 | + reader = PdfReader(BytesIO(output_bytes)) |
| 416 | + assert get_all_tiff(reader.xmp_metadata) == {"tiff:Artist": ["Foo Bar"]} |
| 417 | + assert "/XML" not in str(writer.root_object) |
0 commit comments