379 lines
15 KiB
C++
379 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <string_view>
|
|
|
|
#include <pdf/XmpMetadata.hxx>
|
|
#include <tools/XmlWriter.hxx>
|
|
|
|
namespace vcl::pdf
|
|
{
|
|
namespace
|
|
{
|
|
constexpr const char* constPadding = " "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
"\n";
|
|
}
|
|
|
|
XmpMetadata::XmpMetadata()
|
|
: mbWritten(false)
|
|
, mnPDF_A(0)
|
|
, mbPDF_UA(false)
|
|
{
|
|
}
|
|
|
|
void XmpMetadata::write()
|
|
{
|
|
mpMemoryStream = std::make_unique<SvMemoryStream>(4096 /*Initial*/, 64 /*Resize*/);
|
|
|
|
// Header
|
|
mpMemoryStream->WriteOString(std::string_view(reinterpret_cast<char const*>(
|
|
u8"<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n")));
|
|
|
|
{
|
|
tools::XmlWriter aXmlWriter(mpMemoryStream.get());
|
|
aXmlWriter.startDocument(2, false);
|
|
aXmlWriter.startElement("x"_ostr, "xmpmeta"_ostr, "adobe:ns:meta/"_ostr);
|
|
aXmlWriter.startElement("rdf"_ostr, "RDF"_ostr,
|
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#"_ostr);
|
|
|
|
// PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
|
|
if (mnPDF_A > 0)
|
|
{
|
|
OString sPdfVersion = OString::number(mnPDF_A);
|
|
|
|
aXmlWriter.startElement("rdf:Description");
|
|
aXmlWriter.attribute("rdf:about", ""_ostr);
|
|
aXmlWriter.attribute("xmlns:pdfaid", "http://www.aiim.org/pdfa/ns/id/"_ostr);
|
|
|
|
aXmlWriter.startElement("pdfaid:part");
|
|
aXmlWriter.content(sPdfVersion);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.startElement("pdfaid:conformance");
|
|
aXmlWriter.content("B"_ostr);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.endElement();
|
|
}
|
|
|
|
// Dublin Core properties
|
|
if (!msTitle.isEmpty() || !msAuthor.isEmpty() || !msSubject.isEmpty()
|
|
|| !maContributor.empty() || !msCoverage.isEmpty() || !msIdentifier.isEmpty()
|
|
|| !maPublisher.empty() || !maRelation.empty() || !msRights.isEmpty()
|
|
|| !msSource.isEmpty() || !msType.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("rdf:Description");
|
|
aXmlWriter.attribute("rdf:about", ""_ostr);
|
|
aXmlWriter.attribute("xmlns:dc", "http://purl.org/dc/elements/1.1/"_ostr);
|
|
|
|
aXmlWriter.startElement("dc:format");
|
|
aXmlWriter.content("application/pdf"_ostr);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.startElement("dc:date");
|
|
aXmlWriter.startElement("rdf:Seq");
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.content(m_sCreateDate);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
|
|
if (!msTitle.isEmpty())
|
|
{
|
|
// this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
|
|
aXmlWriter.startElement("dc:title");
|
|
aXmlWriter.startElement("rdf:Alt");
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("xml:lang", "x-default"_ostr);
|
|
aXmlWriter.content(msTitle);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msAuthor.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:creator");
|
|
aXmlWriter.startElement("rdf:Seq");
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.content(msAuthor);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msSubject.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:description");
|
|
aXmlWriter.startElement("rdf:Alt");
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("xml:lang", "x-default"_ostr);
|
|
aXmlWriter.content(msSubject);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!maContributor.empty())
|
|
{
|
|
aXmlWriter.startElement("dc:contributor");
|
|
aXmlWriter.startElement("rdf:Bag");
|
|
for (const OString& rContributor : maContributor)
|
|
{
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.content(rContributor);
|
|
aXmlWriter.endElement();
|
|
}
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msCoverage.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:coverage");
|
|
aXmlWriter.content(msCoverage);
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msIdentifier.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:identifier");
|
|
aXmlWriter.content(msIdentifier);
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!maPublisher.empty())
|
|
{
|
|
aXmlWriter.startElement("dc:publisher");
|
|
aXmlWriter.startElement("rdf:Bag");
|
|
for (const OString& rPublisher : maPublisher)
|
|
{
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.content(rPublisher);
|
|
aXmlWriter.endElement();
|
|
}
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!maRelation.empty())
|
|
{
|
|
aXmlWriter.startElement("dc:relation");
|
|
aXmlWriter.startElement("rdf:Bag");
|
|
for (const OString& rRelation : maRelation)
|
|
{
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.content(rRelation);
|
|
aXmlWriter.endElement();
|
|
}
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msRights.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:rights");
|
|
aXmlWriter.startElement("rdf:Alt");
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("xml:lang", "x-default"_ostr);
|
|
aXmlWriter.content(msRights);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msSource.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:source");
|
|
aXmlWriter.content(msSource);
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msType.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("dc:type");
|
|
aXmlWriter.content(msType);
|
|
aXmlWriter.endElement();
|
|
}
|
|
aXmlWriter.endElement();
|
|
}
|
|
|
|
// PDF/UA
|
|
if (mbPDF_UA)
|
|
{
|
|
if (mnPDF_A != 0)
|
|
{ // tdf#157517 PDF/A extension schema is required
|
|
aXmlWriter.startElement("rdf:Description");
|
|
aXmlWriter.attribute("rdf:about", ""_ostr);
|
|
aXmlWriter.attribute("xmlns:pdfaExtension",
|
|
"http://www.aiim.org/pdfa/ns/extension/"_ostr);
|
|
aXmlWriter.attribute("xmlns:pdfaSchema",
|
|
"http://www.aiim.org/pdfa/ns/schema#"_ostr);
|
|
aXmlWriter.attribute("xmlns:pdfaProperty",
|
|
"http://www.aiim.org/pdfa/ns/property#"_ostr);
|
|
aXmlWriter.startElement("pdfaExtension:schemas");
|
|
aXmlWriter.startElement("rdf:Bag");
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("rdf:parseType", "Resource"_ostr);
|
|
aXmlWriter.startElement("pdfaSchema:namespaceURI");
|
|
aXmlWriter.content("http://www.aiim.org/pdfua/ns/id/"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaSchema:prefix");
|
|
aXmlWriter.content("pdfuaid"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaSchema:schema");
|
|
aXmlWriter.content("PDF/UA identification schema"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaSchema:property");
|
|
aXmlWriter.startElement("rdf:Seq");
|
|
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("rdf:parseType", "Resource"_ostr);
|
|
aXmlWriter.startElement("pdfaProperty:category");
|
|
aXmlWriter.content("internal"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:description");
|
|
aXmlWriter.content("PDF/UA version identifier"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:name");
|
|
aXmlWriter.content("part"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:valueType");
|
|
aXmlWriter.content("Integer"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement(); // rdf:li
|
|
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("rdf:parseType", "Resource"_ostr);
|
|
aXmlWriter.startElement("pdfaProperty:category");
|
|
aXmlWriter.content("internal"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:description");
|
|
aXmlWriter.content("PDF/UA amendment identifier"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:name");
|
|
aXmlWriter.content("amd"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:valueType");
|
|
aXmlWriter.content("Text"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement(); // rdf:li
|
|
|
|
aXmlWriter.startElement("rdf:li");
|
|
aXmlWriter.attribute("rdf:parseType", "Resource"_ostr);
|
|
aXmlWriter.startElement("pdfaProperty:category");
|
|
aXmlWriter.content("internal"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:description");
|
|
aXmlWriter.content("PDF/UA corrigenda identifier"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:name");
|
|
aXmlWriter.content("corr"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.startElement("pdfaProperty:valueType");
|
|
aXmlWriter.content("Text"_ostr);
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement(); // rdf:li
|
|
|
|
aXmlWriter.endElement(); // rdf:Seq
|
|
aXmlWriter.endElement(); // pdfaSchema:property
|
|
aXmlWriter.endElement(); // rdf:li
|
|
aXmlWriter.endElement(); // rdf:Bag
|
|
aXmlWriter.endElement(); // pdfaExtension:schemas
|
|
aXmlWriter.endElement(); // rdf:Description
|
|
}
|
|
OString sPdfUaVersion = OString::number(1);
|
|
aXmlWriter.startElement("rdf:Description");
|
|
aXmlWriter.attribute("rdf:about", ""_ostr);
|
|
aXmlWriter.attribute("xmlns:pdfuaid", "http://www.aiim.org/pdfua/ns/id/"_ostr);
|
|
|
|
aXmlWriter.startElement("pdfuaid:part");
|
|
aXmlWriter.content(sPdfUaVersion);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.endElement();
|
|
}
|
|
|
|
// PDF properties
|
|
if (!msProducer.isEmpty() || !msKeywords.isEmpty() || !msPDFVersion.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("rdf:Description");
|
|
aXmlWriter.attribute("rdf:about", ""_ostr);
|
|
aXmlWriter.attribute("xmlns:pdf", "http://ns.adobe.com/pdf/1.3/"_ostr);
|
|
if (!msProducer.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("pdf:Producer");
|
|
aXmlWriter.content(msProducer);
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msKeywords.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("pdf:Keywords");
|
|
aXmlWriter.content(msKeywords);
|
|
aXmlWriter.endElement();
|
|
}
|
|
if (!msPDFVersion.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("pdf:PDFVersion");
|
|
aXmlWriter.content(msPDFVersion);
|
|
aXmlWriter.endElement();
|
|
}
|
|
aXmlWriter.endElement();
|
|
}
|
|
|
|
// XMP Basic schema
|
|
aXmlWriter.startElement("rdf:Description");
|
|
aXmlWriter.attribute("rdf:about", ""_ostr);
|
|
aXmlWriter.attribute("xmlns:xmp", "http://ns.adobe.com/xap/1.0/"_ostr);
|
|
if (!m_sCreatorTool.isEmpty())
|
|
{
|
|
aXmlWriter.startElement("xmp:CreatorTool");
|
|
aXmlWriter.content(m_sCreatorTool);
|
|
aXmlWriter.endElement();
|
|
}
|
|
aXmlWriter.startElement("xmp:CreateDate");
|
|
aXmlWriter.content(m_sCreateDate);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.startElement("xmp:ModifyDate");
|
|
aXmlWriter.content(m_sCreateDate);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.startElement("xmp:MetadataDate");
|
|
aXmlWriter.content(m_sCreateDate);
|
|
aXmlWriter.endElement();
|
|
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endElement();
|
|
aXmlWriter.endDocument();
|
|
}
|
|
|
|
// add padding (needed so the metadata can be changed in-place"
|
|
for (sal_Int32 nSpaces = 1; nSpaces <= 21; nSpaces++)
|
|
mpMemoryStream->WriteOString(constPadding);
|
|
|
|
mpMemoryStream->WriteOString("<?xpacket end=\"w\"?>\n");
|
|
mbWritten = true;
|
|
}
|
|
|
|
sal_uInt64 XmpMetadata::getSize()
|
|
{
|
|
if (!mbWritten)
|
|
write();
|
|
return mpMemoryStream->GetSize();
|
|
}
|
|
|
|
const void* XmpMetadata::getData()
|
|
{
|
|
if (!mbWritten)
|
|
write();
|
|
return mpMemoryStream->GetData();
|
|
}
|
|
|
|
} // end vcl::pdf
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|