custom metadata
This commit is contained in:
committed by
Guillaume Ayoub
parent
9ec1ca465c
commit
b6d403315a
@@ -1140,6 +1140,7 @@ def assert_meta(html, **meta):
|
||||
meta.setdefault('attachments', [])
|
||||
meta.setdefault('lang', None)
|
||||
meta.setdefault('custom', {})
|
||||
meta.setdefault('rdf_metadata_generator', None)
|
||||
assert vars(FakeHTML(string=html).render().metadata) == meta
|
||||
|
||||
|
||||
|
||||
@@ -716,3 +716,35 @@ def test_bleed(style, media, bleed, trim):
|
||||
assert f'/MediaBox {str(media).replace(",", "")}'.encode() in pdf
|
||||
assert f'/BleedBox {str(bleed).replace(",", "")}'.encode() in pdf
|
||||
assert f'/TrimBox {str(trim).replace(",", "")}'.encode() in pdf
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_default_rdf_metadata() -> None:
|
||||
pdf_document = FakeHTML(string='<body>test</body>').render()
|
||||
|
||||
pdf_document.metadata.title = None
|
||||
|
||||
pdf_bytes = pdf_document.write_pdf(
|
||||
pdf_variant='pdf/a-3b',
|
||||
pdf_identifier=b'example-bytes',
|
||||
uncompressed_pdf=True,
|
||||
)
|
||||
assert b'<rdf:RDF xmlns:pdf="http://ns.adobe.com/pdf/1.3/"' in pdf_bytes
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_custom_rdf_metadata() -> None:
|
||||
def rdf_metadata_generator(*args, **kwargs) -> bytes:
|
||||
return b'TEST_METADATA'
|
||||
|
||||
pdf_document = FakeHTML(string='<body>test</body>').render()
|
||||
|
||||
pdf_document.metadata.title = None
|
||||
pdf_document.metadata.rdf_metadata_generator = rdf_metadata_generator
|
||||
|
||||
pdf_bytes = pdf_document.write_pdf(
|
||||
pdf_variant='pdf/a-3b',
|
||||
pdf_identifier=b'example-bytes',
|
||||
uncompressed_pdf=True,
|
||||
)
|
||||
assert b'TEST_METADATA' in pdf_bytes
|
||||
|
||||
+30
-5
@@ -4,8 +4,9 @@ import functools
|
||||
import io
|
||||
from hashlib import md5
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional
|
||||
|
||||
from . import CSS, DEFAULT_OPTIONS
|
||||
from . import CSS, DEFAULT_OPTIONS, Attachment
|
||||
from .anchors import gather_anchors, make_page_bookmark_tree
|
||||
from .css import get_all_computed_styles
|
||||
from .css.counters import CounterStyle
|
||||
@@ -105,12 +106,33 @@ class DocumentMetadata:
|
||||
"""Meta-information belonging to a whole :class:`Document`.
|
||||
|
||||
New attributes may be added in future versions of WeasyPrint.
|
||||
|
||||
"""
|
||||
title: Optional[str]
|
||||
authors: list[str]
|
||||
description: Optional[str]
|
||||
keywords: list[str]
|
||||
generator: Optional[str]
|
||||
created: Optional[str]
|
||||
modified: Optional[str]
|
||||
attachments: list[Attachment]
|
||||
lang: Optional[str]
|
||||
custom: dict
|
||||
rdf_metadata_generator: Optional[Callable] = None
|
||||
|
||||
def __init__(self, title=None, authors=None, description=None,
|
||||
keywords=None, generator=None, created=None, modified=None,
|
||||
attachments=None, lang=None, custom=None):
|
||||
def __init__(
|
||||
self,
|
||||
title: Optional[str] = None,
|
||||
authors: Optional[list[str]] = None,
|
||||
description: Optional[str] = None,
|
||||
keywords: Optional[list[str]] = None,
|
||||
generator: Optional[str] = None,
|
||||
created: Optional[str] = None,
|
||||
modified: Optional[str] = None,
|
||||
attachments: Optional[list[Attachment]] = None,
|
||||
lang: Optional[str] = None,
|
||||
custom: Optional[dict] = None,
|
||||
rdf_metadata_generator: Optional[Callable] = None,
|
||||
):
|
||||
#: The title of the document, as a string or :obj:`None`.
|
||||
#: Extracted from the ``<title>`` element in HTML
|
||||
#: and written to the ``/Title`` info field in PDF.
|
||||
@@ -156,6 +178,9 @@ class DocumentMetadata:
|
||||
#: Custom metadata, as a dict whose keys are the metadata names and
|
||||
#: values are the metadata values.
|
||||
self.custom = custom or {}
|
||||
#: Custom RDF metadata generator, which will replace the default generator.
|
||||
#: The function should return bytes containing an RDF XML.
|
||||
self.rdf_metadata_generator = rdf_metadata_generator
|
||||
|
||||
|
||||
class DiskCache:
|
||||
|
||||
+50
-13
@@ -1,13 +1,20 @@
|
||||
"""PDF metadata stream generation."""
|
||||
"""
|
||||
PDF metadata stream generation.
|
||||
"""
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from xml.etree.ElementTree import Element, SubElement, register_namespace, tostring
|
||||
|
||||
import pydyf
|
||||
|
||||
from .. import __version__
|
||||
from weasyprint import __version__
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from weasyprint.document import DocumentMetadata
|
||||
|
||||
|
||||
# XML namespaces used for metadata
|
||||
NS = {
|
||||
NS: dict[str, str] = {
|
||||
'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'dc': 'http://purl.org/dc/elements/1.1/',
|
||||
'xmp': 'http://ns.adobe.com/xap/1.0/',
|
||||
@@ -19,13 +26,50 @@ for key, value in NS.items():
|
||||
register_namespace(key, value)
|
||||
|
||||
|
||||
def add_metadata(pdf, metadata, variant, version, conformance, compress):
|
||||
def add_metadata(
|
||||
pdf: pydyf.PDF,
|
||||
metadata: 'DocumentMetadata',
|
||||
variant: str,
|
||||
version: str,
|
||||
conformance: str,
|
||||
compress: bool,
|
||||
) -> None:
|
||||
"""Add PDF stream of metadata.
|
||||
|
||||
Described in ISO-32000-1:2008, 14.3.2.
|
||||
|
||||
"""
|
||||
# Add metadata
|
||||
# Add metadata. If `DocumentMetadata` has a generator, we will use it,
|
||||
# otherwise we will use the default generator.
|
||||
if metadata.rdf_metadata_generator is None:
|
||||
xml_data = generate_rdf_metadata(metadata, variant, version, conformance)
|
||||
else:
|
||||
xml_data = metadata.rdf_metadata_generator(
|
||||
metadata=metadata,
|
||||
variant=variant,
|
||||
version=version,
|
||||
conformance=conformance,
|
||||
)
|
||||
|
||||
header = b'<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>'
|
||||
footer = b'<?xpacket end="r"?>'
|
||||
stream_content = b'\n'.join((header, xml_data, footer))
|
||||
extra = {'Type': '/Metadata', 'Subtype': '/XML'}
|
||||
metadata = pydyf.Stream([stream_content], extra, compress)
|
||||
pdf.add_object(metadata)
|
||||
pdf.catalog['Metadata'] = metadata.reference
|
||||
|
||||
|
||||
def generate_rdf_metadata(
|
||||
metadata: 'DocumentMetadata',
|
||||
variant: str,
|
||||
version: str,
|
||||
conformance: str,
|
||||
) -> bytes:
|
||||
"""Generates RDF metadata. Might be replaced by
|
||||
DocumentMetadata.rdf_matadata_generator().
|
||||
|
||||
"""
|
||||
namespace = f'pdf{variant}id'
|
||||
rdf = Element(f'{{{NS["rdf"]}}}RDF')
|
||||
|
||||
@@ -82,11 +126,4 @@ def add_metadata(pdf, metadata, variant, version, conformance, compress):
|
||||
element.attrib[f'{{{NS["rdf"]}}}about'] = ''
|
||||
element = SubElement(element, f'{{{NS["xmp"]}}}ModifyDate')
|
||||
element.text = metadata.modified
|
||||
xml = tostring(rdf, encoding='utf-8')
|
||||
header = b'<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>'
|
||||
footer = b'<?xpacket end="r"?>'
|
||||
stream_content = b'\n'.join((header, xml, footer))
|
||||
extra = {'Type': '/Metadata', 'Subtype': '/XML'}
|
||||
metadata = pydyf.Stream([stream_content], extra, compress)
|
||||
pdf.add_object(metadata)
|
||||
pdf.catalog['Metadata'] = metadata.reference
|
||||
return tostring(rdf, encoding='utf-8')
|
||||
|
||||
Reference in New Issue
Block a user