Fix #1058531 (When editing metadata, the 'year' field is displayed like '101' instead of 2012)

This commit is contained in:
Kovid Goyal 2012-10-01 18:52:25 +05:30
parent 728668f980
commit 87dd325842
3 changed files with 106 additions and 37 deletions

View File

@ -151,28 +151,32 @@ class PDFOutput(OutputFormatPlugin):
oeb_output.convert(oeb_book, oeb_dir, self.input_plugin, self.opts, self.log) oeb_output.convert(oeb_book, oeb_dir, self.input_plugin, self.opts, self.log)
if iswindows: 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 # On windows Qt generates an image based PDF if the html uses
# embedded fonts. See https://launchpad.net/bugs/1053906 # embedded fonts. See https://launchpad.net/bugs/1053906
for f in walk(oeb_dir): for f in walk(oeb_dir):
if f.rpartition('.')[-1].lower() in {'ttf', 'otf'}: if f.rpartition('.')[-1].lower() in {'ttf', 'otf'}:
fixed = False os.remove(f)
with open(f, 'r+b') as s: # It's not the font embedding restriction that causes
raw = s.read() # this, even after removing the restriction, Qt still
try: # generates an image based document. Theoretically, it
raw = remove_embed_restriction(raw) # fixed = False
except: # with open(f, 'r+b') as s:
self.log.exception('Failed to remove embedding' # raw = s.read()
' restriction from font %s, ignoring it'% # try:
os.path.basename(f)) # raw = remove_embed_restriction(raw)
else: # except:
s.seek(0) # self.log.exception('Failed to remove embedding'
s.truncate() # ' restriction from font %s, ignoring it'%
s.write(raw) # os.path.basename(f))
fixed = True # else:
# s.seek(0)
# s.truncate()
# s.write(raw)
# fixed = True
if not fixed: # if not fixed:
os.remove(f) # os.remove(f)
opfpath = glob.glob(os.path.join(oeb_dir, '*.opf'))[0] opfpath = glob.glob(os.path.join(oeb_dir, '*.opf'))[0]
opf = OPF(opfpath, os.path.dirname(opfpath)) opf = OPF(opfpath, os.path.dirname(opfpath))

View File

@ -9,10 +9,11 @@ __docformat__ = 'restructuredtext en'
import textwrap, re, os, errno, shutil import textwrap, re, os, errno, shutil
from PyQt4.Qt import (Qt, QDateTimeEdit, pyqtSignal, QMessageBox, from PyQt4.Qt import (Qt, QDateTimeEdit, pyqtSignal, QMessageBox, QIcon,
QIcon, QToolButton, QWidget, QLabel, QGridLayout, QApplication, QToolButton, QWidget, QLabel, QGridLayout, QApplication,
QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu, QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu,
QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox, QAction) QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox,
QAction, QCalendarWidget, QDate)
from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView
from calibre.utils.icu import sort_key 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 = '' TOOLTIP = ''
LABEL = _('&Date:') LABEL = _('&Date:')
@ -1388,6 +1397,8 @@ class DateEdit(QDateTimeEdit): # {{{
fmt = self.FMT fmt = self.FMT
self.setDisplayFormat(fmt) self.setDisplayFormat(fmt)
self.setCalendarPopup(True) self.setCalendarPopup(True)
self.cw = CalendarWidget(self)
self.setCalendarWidget(self.cw)
self.setMinimumDateTime(UNDEFINED_QDATETIME) self.setMinimumDateTime(UNDEFINED_QDATETIME)
self.setSpecialValueText(_('Undefined')) self.setSpecialValueText(_('Undefined'))
self.clear_button = QToolButton(parent) self.clear_button = QToolButton(parent)

View File

@ -18,23 +18,23 @@ def is_truetype_font(raw):
sfnt_version = raw[:4] sfnt_version = raw[:4]
return (sfnt_version in {b'\x00\x01\x00\x00', b'OTTO'}, sfnt_version) return (sfnt_version in {b'\x00\x01\x00\x00', b'OTTO'}, sfnt_version)
def get_table(raw, name): def get_tables(raw):
''' Get the raw table bytes for the specified table in the font '''
num_tables = struct.unpack_from(b'>H', raw, 4)[0] num_tables = struct.unpack_from(b'>H', raw, 4)[0]
offset = 4*3 # start of the table record entries 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): for i in xrange(num_tables):
table_tag = raw[offset:offset+4] table_tag, table_checksum, table_offset, table_length = struct.unpack_from(
if table_tag.lower() == name: b'>4s3L', raw, offset)
table_checksum, table_offset, table_length = struct.unpack_from( yield (table_tag, raw[table_offset:table_offset+table_length], offset,
b'>3L', raw, offset+4) table_offset, table_checksum)
table_index = offset
break
offset += 4*4 offset += 4*4
if table_offset is not None:
table = raw[table_offset:table_offset+table_length] def get_table(raw, name):
return table, table_index, table_offset, table_checksum ''' 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): def get_font_characteristics(raw):
''' '''
@ -154,13 +154,59 @@ def get_font_names(raw):
return family_name, subfamily_name, full_name 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): def remove_embed_restriction(raw):
ok, sig = is_truetype_font(raw) ok, sig = is_truetype_font(raw)
if not ok: if not ok:
raise UnsupportedFont('Not a supported font, sfnt_version: %r'%sig) 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: if table is None:
raise UnsupportedFont('Not a supported font, has no OS/2 table') raise UnsupportedFont('Not a supported font, has no OS/2 table')
@ -172,7 +218,12 @@ def remove_embed_restriction(raw):
f = BytesIO(raw) f = BytesIO(raw)
f.seek(fs_type_offset + table_offset) f.seek(fs_type_offset + table_offset)
f.write(struct.pack(b'>H', 0)) 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(): def test():
import sys, os import sys, os
@ -181,6 +232,9 @@ def test():
raw = open(f, 'rb').read() raw = open(f, 'rb').read()
print (get_font_names(raw)) print (get_font_names(raw))
print (get_font_characteristics(raw)) print (get_font_characteristics(raw))
verify_checksums(raw)
remove_embed_restriction(raw)
if __name__ == '__main__': if __name__ == '__main__':
test() test()