mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
AZW3: Preserve the page-progression-direction property when converting/editing/polishing AZW3 files
This commit is contained in:
parent
9de2a1f781
commit
944310a7e2
@ -32,6 +32,7 @@ class EXTHHeader(object): # {{{
|
|||||||
left = self.num_items
|
left = self.num_items
|
||||||
self.kf8_header = None
|
self.kf8_header = None
|
||||||
self.uuid = self.cdetype = None
|
self.uuid = self.cdetype = None
|
||||||
|
self.page_progression_direction = None
|
||||||
|
|
||||||
self.decode = lambda x : clean_ascii_chars(x.decode(codec, 'replace'))
|
self.decode = lambda x : clean_ascii_chars(x.decode(codec, 'replace'))
|
||||||
|
|
||||||
@ -81,6 +82,13 @@ class EXTHHeader(object): # {{{
|
|||||||
self.mi.language = lang
|
self.mi.language = lang
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
elif idx == 527:
|
||||||
|
try:
|
||||||
|
ppd = content.decode(codec)
|
||||||
|
if ppd:
|
||||||
|
self.page_progression_direction = ppd
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
# else:
|
# else:
|
||||||
# print 'unknown record', idx, repr(content)
|
# print 'unknown record', idx, repr(content)
|
||||||
if title:
|
if title:
|
||||||
|
@ -20,7 +20,7 @@ from calibre.ebooks.mobi.reader.ncx import read_ncx, build_toc
|
|||||||
from calibre.ebooks.mobi.reader.markup import expand_mobi8_markup
|
from calibre.ebooks.mobi.reader.markup import expand_mobi8_markup
|
||||||
from calibre.ebooks.metadata.opf2 import Guide, OPFCreator
|
from calibre.ebooks.metadata.opf2 import Guide, OPFCreator
|
||||||
from calibre.ebooks.metadata.toc import TOC
|
from calibre.ebooks.metadata.toc import TOC
|
||||||
from calibre.ebooks.mobi.utils import read_font_record, read_resc_record
|
from calibre.ebooks.mobi.utils import read_font_record
|
||||||
from calibre.ebooks.oeb.parse_utils import parse_html
|
from calibre.ebooks.oeb.parse_utils import parse_html
|
||||||
from calibre.ebooks.oeb.base import XPath, XHTML, xml2text
|
from calibre.ebooks.oeb.base import XPath, XHTML, xml2text
|
||||||
from calibre.utils.imghdr import what
|
from calibre.utils.imghdr import what
|
||||||
@ -66,7 +66,6 @@ class Mobi8Reader(object):
|
|||||||
self.mobi6_reader, self.log = mobi6_reader, log
|
self.mobi6_reader, self.log = mobi6_reader, log
|
||||||
self.header = mobi6_reader.book_header
|
self.header = mobi6_reader.book_header
|
||||||
self.encrypted_fonts = []
|
self.encrypted_fonts = []
|
||||||
self.resc_data = {}
|
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
self.mobi6_reader.check_for_drm()
|
self.mobi6_reader.check_for_drm()
|
||||||
@ -398,10 +397,8 @@ class Mobi8Reader(object):
|
|||||||
typ = data[:4]
|
typ = data[:4]
|
||||||
href = None
|
href = None
|
||||||
if typ in {b'FLIS', b'FCIS', b'SRCS', b'\xe9\x8e\r\n', b'BOUN',
|
if typ in {b'FLIS', b'FCIS', b'SRCS', b'\xe9\x8e\r\n', b'BOUN',
|
||||||
b'FDST', b'DATP', b'AUDI', b'VIDE'}:
|
b'FDST', b'DATP', b'AUDI', b'VIDE', b'RESC', b'CMET'}:
|
||||||
pass # Ignore these records
|
pass # Ignore these records
|
||||||
elif typ == b'RESC':
|
|
||||||
self.resc_data = read_resc_record(data)
|
|
||||||
elif typ == b'FONT':
|
elif typ == b'FONT':
|
||||||
font = read_font_record(data)
|
font = read_font_record(data)
|
||||||
href = "fonts/%05d.%s" % (fname_idx, font['ext'])
|
href = "fonts/%05d.%s" % (fname_idx, font['ext'])
|
||||||
@ -480,8 +477,8 @@ class Mobi8Reader(object):
|
|||||||
entry.mime_type = 'application/xhtml+xml'
|
entry.mime_type = 'application/xhtml+xml'
|
||||||
opf.create_spine(spine)
|
opf.create_spine(spine)
|
||||||
opf.set_toc(toc)
|
opf.set_toc(toc)
|
||||||
ppd = self.resc_data.get('page-progression-direction', None)
|
ppd = getattr(self.header.exth, 'page_progression_direction', None)
|
||||||
if ppd:
|
if ppd in {'ltr', 'rtl', 'default'}:
|
||||||
opf.page_progression_direction = ppd
|
opf.page_progression_direction = ppd
|
||||||
|
|
||||||
with open('metadata.opf', 'wb') as of, open('toc.ncx', 'wb') as ncx:
|
with open('metadata.opf', 'wb') as of, open('toc.ncx', 'wb') as ncx:
|
||||||
|
@ -7,7 +7,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import struct, string, zlib, os, re
|
import struct, string, zlib, os
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
@ -395,15 +395,6 @@ def mobify_image(data):
|
|||||||
data = im.export('gif')
|
data = im.export('gif')
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def read_resc_record(data):
|
|
||||||
ans = {}
|
|
||||||
match = re.search(br'''<spine [^>]*page-progression-direction=['"](.+?)['"]''', data)
|
|
||||||
if match is not None:
|
|
||||||
ppd = match.group(1).lower()
|
|
||||||
if ppd in {b'ltr', b'rtl'}:
|
|
||||||
ans['page-progression-direction'] = ppd.decode('ascii')
|
|
||||||
return ans
|
|
||||||
|
|
||||||
# Font records {{{
|
# Font records {{{
|
||||||
def read_font_record(data, extent=1040):
|
def read_font_record(data, extent=1040):
|
||||||
'''
|
'''
|
||||||
|
@ -40,6 +40,7 @@ EXTH_CODES = {
|
|||||||
'lastupdatetime': 502,
|
'lastupdatetime': 502,
|
||||||
'title': 503,
|
'title': 503,
|
||||||
'language': 524,
|
'language': 524,
|
||||||
|
'page_progression_direction': 527,
|
||||||
}
|
}
|
||||||
|
|
||||||
COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
|
COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
|
||||||
@ -47,7 +48,8 @@ COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
|
|||||||
def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
||||||
share_not_sync=True, cover_offset=None, thumbnail_offset=None,
|
share_not_sync=True, cover_offset=None, thumbnail_offset=None,
|
||||||
start_offset=None, mobi_doctype=2, num_of_resources=None,
|
start_offset=None, mobi_doctype=2, num_of_resources=None,
|
||||||
kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=None):
|
kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=None,
|
||||||
|
page_progression_direction=None):
|
||||||
exth = BytesIO()
|
exth = BytesIO()
|
||||||
nrecs = 0
|
nrecs = 0
|
||||||
|
|
||||||
@ -205,6 +207,12 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
|||||||
kf8_unknown_count))
|
kf8_unknown_count))
|
||||||
nrecs += 1
|
nrecs += 1
|
||||||
|
|
||||||
|
if page_progression_direction in {'rtl', 'ltr', 'default'}:
|
||||||
|
ppd = bytes(page_progression_direction)
|
||||||
|
exth.write(pack(b'>II', EXTH_CODES['page_progression_direction'], len(ppd) + 8))
|
||||||
|
exth.write(ppd)
|
||||||
|
nrecs += 1
|
||||||
|
|
||||||
exth = exth.getvalue()
|
exth = exth.getvalue()
|
||||||
trail = len(exth) % 4
|
trail = len(exth) % 4
|
||||||
pad = b'\0' * (4 - trail) # Always pad w/ at least 1 byte
|
pad = b'\0' * (4 - trail) # Always pad w/ at least 1 byte
|
||||||
|
@ -219,6 +219,7 @@ class KF8Book(object):
|
|||||||
def __init__(self, writer, for_joint=False):
|
def __init__(self, writer, for_joint=False):
|
||||||
self.build_records(writer, for_joint)
|
self.build_records(writer, for_joint)
|
||||||
self.used_images = writer.used_images
|
self.used_images = writer.used_images
|
||||||
|
self.page_progression_direction = writer.oeb.spine.page_progression_direction
|
||||||
|
|
||||||
def build_records(self, writer, for_joint):
|
def build_records(self, writer, for_joint):
|
||||||
metadata = writer.oeb.metadata
|
metadata = writer.oeb.metadata
|
||||||
@ -297,15 +298,18 @@ class KF8Book(object):
|
|||||||
code to customize various values after build_records() has been
|
code to customize various values after build_records() has been
|
||||||
called'''
|
called'''
|
||||||
opts = self.opts
|
opts = self.opts
|
||||||
self.exth = build_exth(self.metadata,
|
self.exth = build_exth(
|
||||||
prefer_author_sort=opts.prefer_author_sort,
|
self.metadata,
|
||||||
is_periodical=opts.mobi_periodical,
|
prefer_author_sort=opts.prefer_author_sort,
|
||||||
share_not_sync=opts.share_not_sync,
|
is_periodical=opts.mobi_periodical,
|
||||||
cover_offset=self.cover_offset,
|
share_not_sync=opts.share_not_sync,
|
||||||
thumbnail_offset=self.thumbnail_offset,
|
cover_offset=self.cover_offset,
|
||||||
num_of_resources=self.num_of_resources,
|
thumbnail_offset=self.thumbnail_offset,
|
||||||
kf8_unknown_count=self.kuc, be_kindlegen2=True,
|
num_of_resources=self.num_of_resources,
|
||||||
start_offset=self.start_offset, mobi_doctype=self.book_type)
|
kf8_unknown_count=self.kuc, be_kindlegen2=True,
|
||||||
|
start_offset=self.start_offset, mobi_doctype=self.book_type,
|
||||||
|
page_progression_direction=self.page_progression_direction
|
||||||
|
)
|
||||||
|
|
||||||
kwargs = {field:getattr(self, field) for field in HEADER_FIELDS}
|
kwargs = {field:getattr(self, field) for field in HEADER_FIELDS}
|
||||||
return MOBIHeader()(**kwargs)
|
return MOBIHeader()(**kwargs)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user