mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix serialization of floating point numbers
This commit is contained in:
parent
40539ca292
commit
836a623b5f
@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
import codecs, zlib
|
import codecs, zlib
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from struct import pack
|
from struct import pack
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
EOL = b'\n'
|
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 {{{
|
# 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):
|
def serialize(o, stream):
|
||||||
if hasattr(o, 'pdf_serialize'):
|
if hasattr(o, 'pdf_serialize'):
|
||||||
o.pdf_serialize(stream)
|
o.pdf_serialize(stream)
|
||||||
elif isinstance(o, bool):
|
elif isinstance(o, bool):
|
||||||
stream.write(b'true' if o else b'false')
|
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'))
|
stream.write(type(u'')(o).encode('ascii'))
|
||||||
|
elif isinstance(o, float):
|
||||||
|
stream.write(format_float(o).encode('ascii'))
|
||||||
elif o is None:
|
elif o is None:
|
||||||
stream.write(b'null')
|
stream.write(b'null')
|
||||||
else:
|
else:
|
||||||
|
@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
import sys, traceback
|
import sys, traceback
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
|
from future_builtins import map
|
||||||
|
|
||||||
import sip
|
import sip
|
||||||
from PyQt4.Qt import (QPaintEngine, QPaintDevice, Qt, QApplication, QPainter,
|
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.constants import plugins
|
||||||
from calibre.ebooks.pdf.render.serialize import (Color, PDFStream, Path)
|
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.container import Sfnt
|
||||||
from calibre.utils.fonts.sfnt.metrics import FontMetrics
|
from calibre.utils.fonts.sfnt.metrics import FontMetrics
|
||||||
|
|
||||||
Point = namedtuple('Point', 'x y')
|
Point = namedtuple('Point', 'x y')
|
||||||
ColorState = namedtuple('ColorState', 'color opacity do')
|
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):
|
def store_error(func):
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
|
@ -15,7 +15,7 @@ from collections import namedtuple
|
|||||||
from calibre.constants import (__appname__, __version__)
|
from calibre.constants import (__appname__, __version__)
|
||||||
from calibre.ebooks.pdf.render.common import (
|
from calibre.ebooks.pdf.render.common import (
|
||||||
Reference, EOL, serialize, Stream, Dictionary, String, Name, Array,
|
Reference, EOL, serialize, Stream, Dictionary, String, Name, Array,
|
||||||
GlyphIndex)
|
GlyphIndex, fmtnum)
|
||||||
from calibre.ebooks.pdf.render.fonts import FontManager
|
from calibre.ebooks.pdf.render.fonts import FontManager
|
||||||
from calibre.ebooks.pdf.render.links import Links
|
from calibre.ebooks.pdf.render.links import Links
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ class Text(object):
|
|||||||
stream.write_line('BT ')
|
stream.write_line('BT ')
|
||||||
serialize(Name(font_name), stream)
|
serialize(Name(font_name), stream)
|
||||||
stream.write(' %g Tf '%self.size)
|
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:
|
if self.horizontal_scale != self.default_horizontal_scale:
|
||||||
stream.write('%g Tz '%self.horizontal_scale)
|
stream.write('%g Tz '%self.horizontal_scale)
|
||||||
if self.word_spacing != self.default_word_spacing:
|
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()]
|
vals = [m.m11(), m.m12(), m.m21(), m.m22(), m.dx(), m.dy()]
|
||||||
else:
|
else:
|
||||||
vals = args
|
vals = args
|
||||||
cm = ' '.join(map(type(u''), vals))
|
cm = ' '.join(map(fmtnum, vals))
|
||||||
self.current_page.write_line(cm + ' cm')
|
self.current_page.write_line(cm + ' cm')
|
||||||
|
|
||||||
def set_rgb_colorspace(self):
|
def set_rgb_colorspace(self):
|
||||||
@ -355,7 +355,8 @@ class PDFStream(object):
|
|||||||
if i != 0:
|
if i != 0:
|
||||||
self.current_page.write_line()
|
self.current_page.write_line()
|
||||||
for x in op:
|
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'):
|
def draw_path(self, path, stroke=True, fill=False, fill_rule='winding'):
|
||||||
if not path.ops: return
|
if not path.ops: return
|
||||||
@ -394,7 +395,7 @@ class PDFStream(object):
|
|||||||
op = Dictionary({'Type':Name('ExtGState'), 'CA': opacity})
|
op = Dictionary({'Type':Name('ExtGState'), 'CA': opacity})
|
||||||
self.stroke_opacities[opacity] = self.objects.add(op)
|
self.stroke_opacities[opacity] = self.objects.add(op)
|
||||||
self.current_page.set_opacity(self.stroke_opacities[opacity])
|
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):
|
def set_fill_color(self, color):
|
||||||
opacity = color.opacity
|
opacity = color.opacity
|
||||||
@ -402,7 +403,7 @@ class PDFStream(object):
|
|||||||
op = Dictionary({'Type':Name('ExtGState'), 'ca': opacity})
|
op = Dictionary({'Type':Name('ExtGState'), 'ca': opacity})
|
||||||
self.fill_opacities[opacity] = self.objects.add(op)
|
self.fill_opacities[opacity] = self.objects.add(op)
|
||||||
self.current_page.set_opacity(self.fill_opacities[opacity])
|
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):
|
def end_page(self):
|
||||||
pageref = self.current_page.end(self.objects, self.stream)
|
pageref = self.current_page.end(self.objects, self.stream)
|
||||||
@ -424,7 +425,7 @@ class PDFStream(object):
|
|||||||
self.current_page.write(b'BT ')
|
self.current_page.write(b'BT ')
|
||||||
serialize(Name(name), self.current_page)
|
serialize(Name(name), self.current_page)
|
||||||
self.current_page.write(' %g Tf '%size)
|
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:
|
for x, y, glyph_id in glyphs:
|
||||||
self.current_page.write('%g %g Td '%(x, y))
|
self.current_page.write('%g %g Td '%(x, y))
|
||||||
serialize(GlyphIndex(glyph_id), self.current_page)
|
serialize(GlyphIndex(glyph_id), self.current_page)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user