%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/ebooks/pdf/render/ |
| Current File : //usr/lib/calibre/calibre/ebooks/pdf/render/links.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
from calibre.ebooks.pdf.render.common import Array, Name, Dictionary, String, UTF16String, current_log
from polyglot.builtins import iteritems
from polyglot.urllib import unquote, urlparse
class Destination(Array):
def __init__(self, start_page, pos, get_pageref):
pnum = start_page + max(0, pos['column'])
q = pnum
while q > -1:
try:
pref = get_pageref(q)
break
except IndexError:
pos['left'] = pos['top'] = 0
q -= 1
if q != pnum:
current_log().warn(f'Could not find page {pnum} for link destination, using page {q} instead')
super().__init__([
pref, Name('XYZ'), pos['left'], pos['top'], None
])
class Links:
def __init__(self, pdf, mark_links, page_size):
self.anchors = {}
self.links = []
self.start = {'top':page_size[1], 'column':0, 'left':0}
self.pdf = pdf
self.mark_links = mark_links
def add(self, base_path, start_page, links, anchors):
path = os.path.normcase(os.path.abspath(base_path))
self.anchors[path] = a = {}
a[None] = Destination(start_page, self.start, self.pdf.get_pageref)
for anchor, pos in iteritems(anchors):
a[anchor] = Destination(start_page, pos, self.pdf.get_pageref)
for link in links:
href, page, rect = link
p, frag = href.partition('#')[0::2]
try:
pref = self.pdf.get_pageref(page).obj
except IndexError:
try:
pref = self.pdf.get_pageref(page-1).obj
except IndexError:
self.pdf.debug('Unable to find page for link: %r, ignoring it' % link)
continue
self.pdf.debug('The link %s points to non-existent page, moving it one page back' % href)
self.links.append(((path, p, frag or None), pref, Array(rect)))
def add_links(self):
for link in self.links:
path, href, frag = link[0]
page, rect = link[1:]
combined_path = os.path.normcase(os.path.abspath(os.path.join(os.path.dirname(path), *unquote(href).split('/'))))
is_local = not href or combined_path in self.anchors
annot = Dictionary({
'Type':Name('Annot'), 'Subtype':Name('Link'),
'Rect':rect, 'Border':Array([0,0,0]),
})
if self.mark_links:
annot.update({'Border':Array([16, 16, 1]), 'C':Array([1.0, 0,
0])})
if is_local:
path = combined_path if href else path
try:
annot['Dest'] = self.anchors[path][frag]
except KeyError:
try:
annot['Dest'] = self.anchors[path][None]
except KeyError:
pass
else:
url = href + (('#'+frag) if frag else '')
try:
purl = urlparse(url)
except Exception:
self.pdf.debug('Ignoring unparsable URL: %r' % url)
continue
if purl.scheme and purl.scheme != 'file':
action = Dictionary({
'Type':Name('Action'), 'S':Name('URI'),
})
# Do not try to normalize/quote/unquote this URL as if it
# has a query part, it will get corrupted
action['URI'] = String(url)
annot['A'] = action
if 'A' in annot or 'Dest' in annot:
if 'Annots' not in page:
page['Annots'] = Array()
page['Annots'].append(self.pdf.objects.add(annot))
else:
self.pdf.debug('Could not find destination for link: %s in file %s'%
(href, path))
def add_outline(self, toc):
parent = Dictionary({'Type':Name('Outlines')})
parentref = self.pdf.objects.add(parent)
self.process_children(toc, parentref, parent_is_root=True)
self.pdf.catalog.obj['Outlines'] = parentref
def process_children(self, toc, parentref, parent_is_root=False):
childrefs = []
for child in toc:
childref = self.process_toc_item(child, parentref)
if childref is None:
continue
if childrefs:
childrefs[-1].obj['Next'] = childref
childref.obj['Prev'] = childrefs[-1]
childrefs.append(childref)
if len(child) > 0:
self.process_children(child, childref)
if childrefs:
parentref.obj['First'] = childrefs[0]
parentref.obj['Last'] = childrefs[-1]
if not parent_is_root:
parentref.obj['Count'] = -len(childrefs)
def process_toc_item(self, toc, parentref):
path = toc.abspath or None
frag = toc.fragment or None
if path is None:
return
path = os.path.normcase(os.path.abspath(path))
if path not in self.anchors:
return None
a = self.anchors[path]
dest = a.get(frag, a[None])
item = Dictionary({'Parent':parentref, 'Dest':dest,
'Title':UTF16String(toc.text or _('Unknown'))})
return self.pdf.objects.add(item)