Fix serialization of floating point numbers

This commit is contained in:
Kovid Goyal 2012-12-30 00:22:23 +05:30
parent 40539ca292
commit 836a623b5f
3 changed files with 33 additions and 9 deletions

View File

@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en'
import codecs, zlib
from io import BytesIO
from struct import pack
from decimal import Decimal
EOL = b'\n'
@ -51,13 +52,30 @@ PAPER_SIZES = {k:globals()[k.upper()] for k in ('a0 a1 a2 a3 a4 a5 a6 b0 b1 b2'
# Basic PDF datatypes {{{
def format_float(f):
if abs(f) < 1e-7:
return '0'
places = 6
a, b = type(u'')(Decimal(f).quantize(Decimal(10)**-places)).partition('.')[0::2]
b = b.rstrip('0')
if not b:
return '0' if a == '-0' else a
return '%s.%s'%(a, b)
def fmtnum(o):
if isinstance(o, (int, long)):
return type(u'')(o)
return format_float(o)
def serialize(o, stream):
if hasattr(o, 'pdf_serialize'):
o.pdf_serialize(stream)
elif isinstance(o, bool):
stream.write(b'true' if o else b'false')
elif isinstance(o, (int, long, float)):
elif isinstance(o, (int, long)):
stream.write(type(u'')(o).encode('ascii'))
elif isinstance(o, float):
stream.write(format_float(o).encode('ascii'))
elif o is None:
stream.write(b'null')
else:

View File

@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en'
import sys, traceback
from collections import namedtuple
from functools import wraps, partial
from future_builtins import map
import sip
from PyQt4.Qt import (QPaintEngine, QPaintDevice, Qt, QApplication, QPainter,
@ -18,13 +19,17 @@ from PyQt4.Qt import (QPaintEngine, QPaintDevice, Qt, QApplication, QPainter,
from calibre.constants import plugins
from calibre.ebooks.pdf.render.serialize import (Color, PDFStream, Path)
from calibre.ebooks.pdf.render.common import inch, A4
from calibre.ebooks.pdf.render.common import inch, A4, fmtnum
from calibre.utils.fonts.sfnt.container import Sfnt
from calibre.utils.fonts.sfnt.metrics import FontMetrics
Point = namedtuple('Point', 'x y')
ColorState = namedtuple('ColorState', 'color opacity do')
def repr_transform(t):
vals = map(fmtnum, (t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy()))
return '[%s]'%' '.join(vals)
def store_error(func):
@wraps(func)

View File

@ -15,7 +15,7 @@ from collections import namedtuple
from calibre.constants import (__appname__, __version__)
from calibre.ebooks.pdf.render.common import (
Reference, EOL, serialize, Stream, Dictionary, String, Name, Array,
GlyphIndex)
GlyphIndex, fmtnum)
from calibre.ebooks.pdf.render.fonts import FontManager
from calibre.ebooks.pdf.render.links import Links
@ -180,7 +180,7 @@ class Text(object):
stream.write_line('BT ')
serialize(Name(font_name), stream)
stream.write(' %g Tf '%self.size)
stream.write(' '.join(map(type(u''), self.transform)) + ' Tm ')
stream.write(' '.join(map(fmtnum, self.transform)) + ' Tm ')
if self.horizontal_scale != self.default_horizontal_scale:
stream.write('%g Tz '%self.horizontal_scale)
if self.word_spacing != self.default_word_spacing:
@ -331,7 +331,7 @@ class PDFStream(object):
vals = [m.m11(), m.m12(), m.m21(), m.m22(), m.dx(), m.dy()]
else:
vals = args
cm = ' '.join(map(type(u''), vals))
cm = ' '.join(map(fmtnum, vals))
self.current_page.write_line(cm + ' cm')
def set_rgb_colorspace(self):
@ -355,7 +355,8 @@ class PDFStream(object):
if i != 0:
self.current_page.write_line()
for x in op:
self.current_page.write(type(u'')(x) + ' ')
self.current_page.write(
(fmtnum(x) if isinstance(x, (int, long, float)) else x) + ' ')
def draw_path(self, path, stroke=True, fill=False, fill_rule='winding'):
if not path.ops: return
@ -394,7 +395,7 @@ class PDFStream(object):
op = Dictionary({'Type':Name('ExtGState'), 'CA': opacity})
self.stroke_opacities[opacity] = self.objects.add(op)
self.current_page.set_opacity(self.stroke_opacities[opacity])
self.current_page.write_line(' '.join(map(type(u''), color[:3])) + ' SC')
self.current_page.write_line(' '.join(map(fmtnum, color[:3])) + ' SC')
def set_fill_color(self, color):
opacity = color.opacity
@ -402,7 +403,7 @@ class PDFStream(object):
op = Dictionary({'Type':Name('ExtGState'), 'ca': opacity})
self.fill_opacities[opacity] = self.objects.add(op)
self.current_page.set_opacity(self.fill_opacities[opacity])
self.current_page.write_line(' '.join(map(type(u''), color[:3])) + ' sc')
self.current_page.write_line(' '.join(map(fmtnum, color[:3])) + ' sc')
def end_page(self):
pageref = self.current_page.end(self.objects, self.stream)
@ -424,7 +425,7 @@ class PDFStream(object):
self.current_page.write(b'BT ')
serialize(Name(name), self.current_page)
self.current_page.write(' %g Tf '%size)
self.current_page.write('%s Tm '%' '.join(map(type(u''), transform)))
self.current_page.write('%s Tm '%' '.join(map(fmtnum, transform)))
for x, y, glyph_id in glyphs:
self.current_page.write('%g %g Td '%(x, y))
serialize(GlyphIndex(glyph_id), self.current_page)