mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-11 09:13:57 -04:00
Fix #1058531 (When editing metadata, the 'year' field is displayed like '101' instead of 2012)
This commit is contained in:
parent
728668f980
commit
87dd325842
@ -151,28 +151,32 @@ class PDFOutput(OutputFormatPlugin):
|
||||
oeb_output.convert(oeb_book, oeb_dir, self.input_plugin, self.opts, self.log)
|
||||
|
||||
if iswindows:
|
||||
from calibre.utils.fonts.utils import remove_embed_restriction
|
||||
# from calibre.utils.fonts.utils import remove_embed_restriction
|
||||
# On windows Qt generates an image based PDF if the html uses
|
||||
# embedded fonts. See https://launchpad.net/bugs/1053906
|
||||
for f in walk(oeb_dir):
|
||||
if f.rpartition('.')[-1].lower() in {'ttf', 'otf'}:
|
||||
fixed = False
|
||||
with open(f, 'r+b') as s:
|
||||
raw = s.read()
|
||||
try:
|
||||
raw = remove_embed_restriction(raw)
|
||||
except:
|
||||
self.log.exception('Failed to remove embedding'
|
||||
' restriction from font %s, ignoring it'%
|
||||
os.path.basename(f))
|
||||
else:
|
||||
s.seek(0)
|
||||
s.truncate()
|
||||
s.write(raw)
|
||||
fixed = True
|
||||
os.remove(f)
|
||||
# It's not the font embedding restriction that causes
|
||||
# this, even after removing the restriction, Qt still
|
||||
# generates an image based document. Theoretically, it
|
||||
# fixed = False
|
||||
# with open(f, 'r+b') as s:
|
||||
# raw = s.read()
|
||||
# try:
|
||||
# raw = remove_embed_restriction(raw)
|
||||
# except:
|
||||
# self.log.exception('Failed to remove embedding'
|
||||
# ' restriction from font %s, ignoring it'%
|
||||
# os.path.basename(f))
|
||||
# else:
|
||||
# s.seek(0)
|
||||
# s.truncate()
|
||||
# s.write(raw)
|
||||
# fixed = True
|
||||
|
||||
if not fixed:
|
||||
os.remove(f)
|
||||
# if not fixed:
|
||||
# os.remove(f)
|
||||
|
||||
opfpath = glob.glob(os.path.join(oeb_dir, '*.opf'))[0]
|
||||
opf = OPF(opfpath, os.path.dirname(opfpath))
|
||||
|
@ -9,10 +9,11 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import textwrap, re, os, errno, shutil
|
||||
|
||||
from PyQt4.Qt import (Qt, QDateTimeEdit, pyqtSignal, QMessageBox,
|
||||
QIcon, QToolButton, QWidget, QLabel, QGridLayout, QApplication,
|
||||
QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu,
|
||||
QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox, QAction)
|
||||
from PyQt4.Qt import (Qt, QDateTimeEdit, pyqtSignal, QMessageBox, QIcon,
|
||||
QToolButton, QWidget, QLabel, QGridLayout, QApplication,
|
||||
QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu,
|
||||
QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox,
|
||||
QAction, QCalendarWidget, QDate)
|
||||
|
||||
from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView
|
||||
from calibre.utils.icu import sort_key
|
||||
@ -1371,7 +1372,15 @@ class PublisherEdit(EditWithComplete): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class DateEdit(QDateTimeEdit): # {{{
|
||||
# DateEdit {{{
|
||||
|
||||
class CalendarWidget(QCalendarWidget):
|
||||
|
||||
def showEvent(self, ev):
|
||||
if self.selectedDate().year() == UNDEFINED_DATE.year:
|
||||
self.setSelectedDate(QDate.currentDate())
|
||||
|
||||
class DateEdit(QDateTimeEdit):
|
||||
|
||||
TOOLTIP = ''
|
||||
LABEL = _('&Date:')
|
||||
@ -1388,6 +1397,8 @@ class DateEdit(QDateTimeEdit): # {{{
|
||||
fmt = self.FMT
|
||||
self.setDisplayFormat(fmt)
|
||||
self.setCalendarPopup(True)
|
||||
self.cw = CalendarWidget(self)
|
||||
self.setCalendarWidget(self.cw)
|
||||
self.setMinimumDateTime(UNDEFINED_QDATETIME)
|
||||
self.setSpecialValueText(_('Undefined'))
|
||||
self.clear_button = QToolButton(parent)
|
||||
|
@ -18,23 +18,23 @@ def is_truetype_font(raw):
|
||||
sfnt_version = raw[:4]
|
||||
return (sfnt_version in {b'\x00\x01\x00\x00', b'OTTO'}, sfnt_version)
|
||||
|
||||
def get_table(raw, name):
|
||||
''' Get the raw table bytes for the specified table in the font '''
|
||||
def get_tables(raw):
|
||||
num_tables = struct.unpack_from(b'>H', raw, 4)[0]
|
||||
offset = 4*3 # start of the table record entries
|
||||
table_offset = table_checksum = table_length = table_index = table = None
|
||||
name = bytes(name.lower())
|
||||
for i in xrange(num_tables):
|
||||
table_tag = raw[offset:offset+4]
|
||||
if table_tag.lower() == name:
|
||||
table_checksum, table_offset, table_length = struct.unpack_from(
|
||||
b'>3L', raw, offset+4)
|
||||
table_index = offset
|
||||
break
|
||||
table_tag, table_checksum, table_offset, table_length = struct.unpack_from(
|
||||
b'>4s3L', raw, offset)
|
||||
yield (table_tag, raw[table_offset:table_offset+table_length], offset,
|
||||
table_offset, table_checksum)
|
||||
offset += 4*4
|
||||
if table_offset is not None:
|
||||
table = raw[table_offset:table_offset+table_length]
|
||||
return table, table_index, table_offset, table_checksum
|
||||
|
||||
def get_table(raw, name):
|
||||
''' Get the raw table bytes for the specified table in the font '''
|
||||
name = bytes(name.lower())
|
||||
for table_tag, table, table_index, table_offset, table_checksum in get_tables(raw):
|
||||
if table_tag.lower() == name:
|
||||
return table, table_index, table_offset, table_checksum
|
||||
return None, None, None, None
|
||||
|
||||
def get_font_characteristics(raw):
|
||||
'''
|
||||
@ -154,13 +154,59 @@ def get_font_names(raw):
|
||||
|
||||
return family_name, subfamily_name, full_name
|
||||
|
||||
def checksum_of_block(raw):
|
||||
extra = 4 - len(raw)%4
|
||||
raw += b'\0'*extra
|
||||
num = len(raw)//4
|
||||
return sum(struct.unpack(b'>%dI'%num, raw)) % (1<<32)
|
||||
|
||||
def verify_checksums(raw):
|
||||
head_table = None
|
||||
for table_tag, table, table_index, table_offset, table_checksum in get_tables(raw):
|
||||
if table_tag.lower() == b'head':
|
||||
version, fontrev, checksum_adj = struct.unpack_from(b'>ffL', table)
|
||||
head_table = table
|
||||
offset = table_offset
|
||||
checksum = table_checksum
|
||||
elif checksum_of_block(table) != table_checksum:
|
||||
raise ValueError('The %r table has an incorrect checksum'%table_tag)
|
||||
|
||||
if head_table is not None:
|
||||
table = head_table
|
||||
table = table[:8] + struct.pack(b'>I', 0) + table[12:]
|
||||
raw = raw[:offset] + table + raw[offset+len(table):]
|
||||
# Check the checksum of the head table
|
||||
if checksum_of_block(table) != checksum:
|
||||
raise ValueError('Checksum of head table not correct')
|
||||
# Check the checksum of the entire font
|
||||
checksum = checksum_of_block(raw)
|
||||
q = (0xB1B0AFBA - checksum) & 0xffffffff
|
||||
if q != checksum_adj:
|
||||
raise ValueError('Checksum of entire font incorrect')
|
||||
|
||||
def set_checksum_adjustment(f):
|
||||
offset = get_table(f.getvalue(), 'head')[2]
|
||||
offset += 8
|
||||
f.seek(offset)
|
||||
f.write(struct.pack(b'>I', 0))
|
||||
checksum = checksum_of_block(f.getvalue())
|
||||
q = (0xB1B0AFBA - checksum) & 0xffffffff
|
||||
f.seek(offset)
|
||||
f.write(struct.pack(b'>I', q))
|
||||
|
||||
def set_table_checksum(f, name):
|
||||
table, table_index, table_offset, table_checksum = get_table(f.getvalue(), name)
|
||||
checksum = checksum_of_block(table)
|
||||
if checksum != table_checksum:
|
||||
f.seek(table_index + 4)
|
||||
f.write(struct.pack(b'>I', checksum))
|
||||
|
||||
def remove_embed_restriction(raw):
|
||||
ok, sig = is_truetype_font(raw)
|
||||
if not ok:
|
||||
raise UnsupportedFont('Not a supported font, sfnt_version: %r'%sig)
|
||||
|
||||
table, table_index, table_offset = get_table(raw, 'os/2')
|
||||
table, table_index, table_offset = get_table(raw, 'os/2')[:3]
|
||||
if table is None:
|
||||
raise UnsupportedFont('Not a supported font, has no OS/2 table')
|
||||
|
||||
@ -172,7 +218,12 @@ def remove_embed_restriction(raw):
|
||||
f = BytesIO(raw)
|
||||
f.seek(fs_type_offset + table_offset)
|
||||
f.write(struct.pack(b'>H', 0))
|
||||
return f.getvalue()
|
||||
|
||||
set_table_checksum(f, 'os/2')
|
||||
set_checksum_adjustment(f)
|
||||
raw = f.getvalue()
|
||||
verify_checksums(raw)
|
||||
return raw
|
||||
|
||||
def test():
|
||||
import sys, os
|
||||
@ -181,6 +232,9 @@ def test():
|
||||
raw = open(f, 'rb').read()
|
||||
print (get_font_names(raw))
|
||||
print (get_font_characteristics(raw))
|
||||
verify_checksums(raw)
|
||||
remove_embed_restriction(raw)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
|
Loading…
x
Reference in New Issue
Block a user