PDF Output: Write XMP metadata when creating PDF files

This commit is contained in:
Kovid Goyal 2014-02-17 21:50:30 +05:30
parent 39287d31fe
commit 8b804f8811
3 changed files with 35 additions and 12 deletions

View File

@ -22,20 +22,21 @@ PAPER_SIZES = [u'a0', u'a1', u'a2', u'a3', u'a4', u'a5', u'a6', u'b0', u'b1',
u'b2', u'b3', u'b4', u'b5', u'b6', u'legal', u'letter'] u'b2', u'b3', u'b4', u'b5', u'b6', u'legal', u'letter']
class PDFMetadata(object): # {{{ class PDFMetadata(object): # {{{
def __init__(self, oeb_metadata=None): def __init__(self, mi=None):
from calibre import force_unicode from calibre import force_unicode
from calibre.ebooks.metadata import authors_to_string from calibre.ebooks.metadata import authors_to_string
self.title = _(u'Unknown') self.title = _(u'Unknown')
self.author = _(u'Unknown') self.author = _(u'Unknown')
self.tags = u'' self.tags = u''
self.mi = mi
if oeb_metadata is not None: if mi is not None:
if len(oeb_metadata.title) >= 1: if mi.title:
self.title = oeb_metadata.title[0].value self.title = mi.title
if len(oeb_metadata.creator) >= 1: if mi.authors:
self.author = authors_to_string([x.value for x in oeb_metadata.creator]) self.author = authors_to_string(mi.authors)
if oeb_metadata.subject: if mi.tags:
self.tags = u', '.join(map(unicode, oeb_metadata.subject)) self.tags = u', '.join(mi.tags)
self.title = force_unicode(self.title) self.title = force_unicode(self.title)
self.author = force_unicode(self.author) self.author = force_unicode(self.author)
@ -125,7 +126,15 @@ class PDFOutput(OutputFormatPlugin):
self.oeb = oeb_book self.oeb = oeb_book
self.input_plugin, self.opts, self.log = input_plugin, opts, log self.input_plugin, self.opts, self.log = input_plugin, opts, log
self.output_path = output_path self.output_path = output_path
self.metadata = oeb_book.metadata from calibre.ebooks.oeb.base import OPF, OPF2_NS
from lxml import etree
from io import BytesIO
package = etree.Element(OPF('package'),
attrib={'version': '2.0', 'unique-identifier': 'dummy'},
nsmap={None: OPF2_NS})
from calibre.ebooks.metadata.opf2 import OPF
self.oeb.metadata.to_opf2(package)
self.metadata = OPF(BytesIO(etree.tostring(package))).to_book_metadata()
self.cover_data = None self.cover_data = None
if input_plugin.is_image_collection: if input_plugin.is_image_collection:

View File

@ -209,7 +209,7 @@ class PDFWriter(QObject):
self.painter = QPainter(self.doc) self.painter = QPainter(self.doc)
self.doc.set_metadata(title=pdf_metadata.title, self.doc.set_metadata(title=pdf_metadata.title,
author=pdf_metadata.author, author=pdf_metadata.author,
tags=pdf_metadata.tags) tags=pdf_metadata.tags, mi=pdf_metadata.mi)
self.doc_title = pdf_metadata.title self.doc_title = pdf_metadata.title
self.doc_author = pdf_metadata.author self.doc_author = pdf_metadata.author
self.painter.save() self.painter.save()

View File

@ -20,7 +20,7 @@ from calibre.ebooks.pdf.render.fonts import FontManager
from calibre.ebooks.pdf.render.links import Links from calibre.ebooks.pdf.render.links import Links
from calibre.utils.date import utcnow from calibre.utils.date import utcnow
PDFVER = b'%PDF-1.3' PDFVER = b'%PDF-1.4' # 1.4 is needed for XMP metadata
class IndirectObjects(object): class IndirectObjects(object):
@ -239,6 +239,17 @@ class Image(Stream):
if self.soft_mask is not None: if self.soft_mask is not None:
d['SMask'] = self.soft_mask d['SMask'] = self.soft_mask
class Metadata(Stream):
def __init__(self, mi):
Stream.__init__(self)
from calibre.ebooks.metadata.xmp import metadata_to_xmp_packet
self.write(metadata_to_xmp_packet(mi))
def add_extra_keys(self, d):
d['Type'] = Name('Metadata')
d['Subtype'] = Name('XML')
class PDFStream(object): class PDFStream(object):
PATH_OPS = { PATH_OPS = {
@ -292,13 +303,16 @@ class PDFStream(object):
def get_pageref(self, pagenum): def get_pageref(self, pagenum):
return self.page_tree.obj.get_ref(pagenum) return self.page_tree.obj.get_ref(pagenum)
def set_metadata(self, title=None, author=None, tags=None): def set_metadata(self, title=None, author=None, tags=None, mi=None):
if title: if title:
self.info['Title'] = String(title) self.info['Title'] = String(title)
if author: if author:
self.info['Author'] = String(author) self.info['Author'] = String(author)
if tags: if tags:
self.info['Keywords'] = String(tags) self.info['Keywords'] = String(tags)
if mi is not None:
self.metadata = self.objects.add(Metadata(mi))
self.catalog.obj['Metadata'] = self.metadata
def write_line(self, byts=b''): def write_line(self, byts=b''):
byts = byts if isinstance(byts, bytes) else byts.encode('ascii') byts = byts if isinstance(byts, bytes) else byts.encode('ascii')