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)
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))

View File

@ -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)

View File

@ -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()