Fix text rendering on windows (font size was incorrect throwing off intra-glyph spacing and line spacing)

This commit is contained in:
Kovid Goyal 2013-01-03 13:34:31 +05:30
parent f1863d3971
commit b33929bbae
5 changed files with 33 additions and 22 deletions

View File

@ -19,7 +19,7 @@ from calibre.constants import plugins
from calibre.ebooks.pdf.render.serialize import (PDFStream, Path) from calibre.ebooks.pdf.render.serialize import (PDFStream, Path)
from calibre.ebooks.pdf.render.common import inch, A4, fmtnum from calibre.ebooks.pdf.render.common import inch, A4, fmtnum
from calibre.ebooks.pdf.render.graphics import convert_path, Graphics from calibre.ebooks.pdf.render.graphics import convert_path, Graphics
from calibre.utils.fonts.sfnt.container import Sfnt from calibre.utils.fonts.sfnt.container import Sfnt, UnsupportedFont
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')
@ -224,7 +224,11 @@ class PdfEngine(QPaintEngine):
def create_sfnt(self, text_item): def create_sfnt(self, text_item):
get_table = partial(self.qt_hack.get_sfnt_table, text_item) get_table = partial(self.qt_hack.get_sfnt_table, text_item)
ans = Font(Sfnt(get_table)) try:
ans = Font(Sfnt(get_table))
except UnsupportedFont as e:
raise UnsupportedFont('The font %s is not a valid sfnt. Error: %s'%(
text_item.font().family(), e))
glyph_map = self.qt_hack.get_glyph_map(text_item) glyph_map = self.qt_hack.get_glyph_map(text_item)
gm = {} gm = {}
for uc, glyph_id in enumerate(glyph_map): for uc, glyph_id in enumerate(glyph_map):
@ -251,18 +255,14 @@ class PdfEngine(QPaintEngine):
except (KeyError, ValueError): except (KeyError, ValueError):
pass pass
glyphs = [] glyphs = []
pdf_pos = point last_x = last_y = 0
first_baseline = None
for i, pos in enumerate(gi.positions): for i, pos in enumerate(gi.positions):
if first_baseline is None: x, y = pos.x(), pos.y()
first_baseline = pos.y() glyphs.append((x-last_x, last_y - y, gi.indices[i]))
glyph_pos = pos last_x, last_y = x, y
delta = glyph_pos - pdf_pos
glyphs.append((delta.x(), pos.y()-first_baseline, gi.indices[i]))
pdf_pos = glyph_pos
self.pdf.draw_glyph_run([1, 0, 0, -1, point.x(), self.pdf.draw_glyph_run([gi.stretch, 0, 0, -1, 0, 0], gi.size, metrics,
point.y()], gi.size, metrics, glyphs) glyphs)
sip.delete(gi) sip.delete(gi)
@store_error @store_error

View File

@ -17,18 +17,23 @@ GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) {
QFontEngine *fe = ti.fontEngine; QFontEngine *fe = ti.fontEngine;
qreal size = ti.fontEngine->fontDef.pixelSize; qreal size = ti.fontEngine->fontDef.pixelSize;
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
if (ti.fontEngine->type() == QFontEngine::Win) { if (false && ti.fontEngine->type() == QFontEngine::Win) {
// This is used in the Qt sourcecode, but it gives incorrect results,
// so I have disabled it. I dont understand how it works in qpdf.cpp
QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine); QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
size = fe->tm.tmHeight; size = fe->tm.tmHeight;
} }
#endif #endif
int synthesized = ti.fontEngine->synthesized();
qreal stretch = synthesized & QFontEngine::SynthesizedStretch ? ti.fontEngine->fontDef.stretch/100. : 1.;
QVarLengthArray<glyph_t> glyphs; QVarLengthArray<glyph_t> glyphs;
QVarLengthArray<QFixedPoint> positions; QVarLengthArray<QFixedPoint> positions;
QTransform m = QTransform::fromTranslate(p.x(), p.y()); QTransform m = QTransform::fromTranslate(p.x(), p.y());
fe->getGlyphPositions(ti.glyphs, m, ti.flags, glyphs, positions); fe->getGlyphPositions(ti.glyphs, m, ti.flags, glyphs, positions);
QVector<QPointF> points = QVector<QPointF>(positions.count()); QVector<QPointF> points = QVector<QPointF>(positions.count());
for (int i = 0; i < positions.count(); i++) { for (int i = 0; i < positions.count(); i++) {
points[i].setX(positions[i].x.toReal()); points[i].setX(positions[i].x.toReal()/stretch);
points[i].setY(positions[i].y.toReal()); points[i].setY(positions[i].y.toReal());
} }
@ -38,10 +43,10 @@ GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) {
const quint32 *tag = reinterpret_cast<const quint32 *>("name"); const quint32 *tag = reinterpret_cast<const quint32 *>("name");
return new GlyphInfo(fe->getSfntTable(qToBigEndian(*tag)), size, points, indices); return new GlyphInfo(fe->getSfntTable(qToBigEndian(*tag)), size, stretch, points, indices);
} }
GlyphInfo::GlyphInfo(const QByteArray& name, qreal size, const QVector<QPointF> &positions, const QVector<unsigned int> &indices) :name(name), positions(positions), size(size), indices(indices) { GlyphInfo::GlyphInfo(const QByteArray& name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<unsigned int> &indices) :name(name), positions(positions), size(size), stretch(stretch), indices(indices) {
} }
QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name) { QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name) {

View File

@ -17,9 +17,10 @@ class GlyphInfo {
QByteArray name; QByteArray name;
QVector<QPointF> positions; QVector<QPointF> positions;
qreal size; qreal size;
qreal stretch;
QVector<unsigned int> indices; QVector<unsigned int> indices;
GlyphInfo(const QByteArray &name, qreal size, const QVector<QPointF> &positions, const QVector<unsigned int> &indices); GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<unsigned int> &indices);
private: private:
GlyphInfo(const GlyphInfo&); GlyphInfo(const GlyphInfo&);

View File

@ -13,9 +13,10 @@ class GlyphInfo {
public: public:
QByteArray name; QByteArray name;
qreal size; qreal size;
qreal stretch;
QVector<QPointF> &positions; QVector<QPointF> &positions;
QVector<unsigned int> indices; QVector<unsigned int> indices;
GlyphInfo(const QByteArray &name, qreal size, const QVector<QPointF> &positions, const QVector<unsigned int> &indices); GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<unsigned int> &indices);
private: private:
GlyphInfo(const GlyphInfo& g); GlyphInfo(const GlyphInfo& g);

View File

@ -8,7 +8,6 @@ __copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os
from tempfile import gettempdir
from PyQt4.Qt import (QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF, from PyQt4.Qt import (QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF,
QApplication, QPainter, Qt, QImage, QLinearGradient, QApplication, QPainter, Qt, QImage, QLinearGradient,
@ -99,14 +98,19 @@ def pen(p, xmax, ymax):
p.drawRect(0, xmax/3, xmax/3, xmax/2) p.drawRect(0, xmax/3, xmax/3, xmax/2)
def text(p, xmax, ymax): def text(p, xmax, ymax):
p.drawText(QPoint(0, ymax/3), 'Text') f = p.font()
f.setPixelSize(24)
f.setFamily('Candara')
p.setFont(f)
p.drawText(QPoint(0, 100),
'Test intra glyph spacing ffagain imceo')
def main(): def main():
app = QApplication([]) app = QApplication([])
app app
tdir = gettempdir() tdir = os.path.abspath('.')
pdf = os.path.join(tdir, 'painter.pdf') pdf = os.path.join(tdir, 'painter.pdf')
func = full func = text
dpi = 100 dpi = 100
with open(pdf, 'wb') as f: with open(pdf, 'wb') as f:
dev = PdfDevice(f, xdpi=dpi, ydpi=dpi, compress=False) dev = PdfDevice(f, xdpi=dpi, ydpi=dpi, compress=False)