mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
PDF Output: Fix crash when running with the latest release of PyQt/SIP. See #1471083 (Error in convert epub to pdf on archlinux)
Apparently, direct attribute access of mapped C++ classes does not work anymore (regression in PyQt/SIP?). So we change the code to return Python objects directly. Makes it a bit longer, but also faster, since the conversion to python is now hand coded instead of relying on SIP.
This commit is contained in:
parent
589a9022f1
commit
003a7c0aa3
@ -10,9 +10,8 @@ __docformat__ = 'restructuredtext en'
|
||||
import sys, traceback, math
|
||||
from collections import namedtuple
|
||||
from functools import wraps, partial
|
||||
from future_builtins import map
|
||||
from future_builtins import map, zip
|
||||
|
||||
import sip
|
||||
from PyQt5.Qt import (QPaintEngine, QPaintDevice, Qt, QTransform, QBrush)
|
||||
|
||||
from calibre.constants import plugins
|
||||
@ -24,6 +23,7 @@ from calibre.utils.fonts.sfnt.metrics import FontMetrics
|
||||
|
||||
Point = namedtuple('Point', 'x y')
|
||||
ColorState = namedtuple('ColorState', 'color opacity do')
|
||||
GlyphInfo = namedtuple('GlyphInfo', 'name size stretch positions indices')
|
||||
|
||||
def repr_transform(t):
|
||||
vals = map(fmtnum, (t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy()))
|
||||
@ -242,11 +242,10 @@ class PdfEngine(QPaintEngine):
|
||||
def drawTextItem(self, point, text_item):
|
||||
# return super(PdfEngine, self).drawTextItem(point, text_item)
|
||||
self.apply_graphics_state()
|
||||
gi = self.qt_hack.get_glyphs(point, text_item)
|
||||
gi = GlyphInfo(*self.qt_hack.get_glyphs(point, text_item))
|
||||
if not gi.indices:
|
||||
sip.delete(gi)
|
||||
return
|
||||
name = hash(bytes(gi.name))
|
||||
name = hash(gi.name)
|
||||
if name not in self.fonts:
|
||||
try:
|
||||
self.fonts[name] = self.create_sfnt(text_item)
|
||||
@ -260,14 +259,12 @@ class PdfEngine(QPaintEngine):
|
||||
pass
|
||||
glyphs = []
|
||||
last_x = last_y = 0
|
||||
for i, pos in enumerate(gi.positions):
|
||||
x, y = pos.x(), pos.y()
|
||||
glyphs.append((x-last_x, last_y - y, gi.indices[i]))
|
||||
for glyph_index, (x, y) in zip(gi.indices, gi.positions):
|
||||
glyphs.append((x-last_x, last_y - y, glyph_index))
|
||||
last_x, last_y = x, y
|
||||
|
||||
self.pdf.draw_glyph_run([gi.stretch, 0, 0, -1, 0, 0], gi.size, metrics,
|
||||
glyphs)
|
||||
sip.delete(gi)
|
||||
|
||||
@store_error
|
||||
def drawPolygon(self, points, mode):
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include "private/qtextengine_p.h"
|
||||
#include "private/qfontengine_p.h"
|
||||
|
||||
GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) {
|
||||
PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item) {
|
||||
const quint32 *tag = reinterpret_cast<const quint32 *>("name");
|
||||
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
||||
QFontEngine *fe = ti.fontEngine;
|
||||
qreal size = ti.fontEngine->fontDef.pixelSize;
|
||||
@ -33,40 +34,49 @@ GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) {
|
||||
QVarLengthArray<QFixedPoint> positions;
|
||||
QTransform m = QTransform::fromTranslate(p.x(), p.y());
|
||||
fe->getGlyphPositions(ti.glyphs, m, ti.flags, glyphs, positions);
|
||||
QVector<QPointF> points = QVector<QPointF>(positions.count());
|
||||
|
||||
PyObject *points = NULL, *indices = NULL, *temp = NULL;
|
||||
|
||||
points = PyTuple_New(positions.count());
|
||||
if (points == NULL) return PyErr_NoMemory();
|
||||
for (int i = 0; i < positions.count(); i++) {
|
||||
points[i].setX(positions[i].x.toReal()/stretch);
|
||||
points[i].setY(positions[i].y.toReal());
|
||||
temp = Py_BuildValue("dd", positions[i].x.toReal()/stretch, positions[i].y.toReal());
|
||||
if (temp == NULL) { Py_DECREF(points); return NULL; }
|
||||
PyTuple_SET_ITEM(points, i, temp); temp = NULL;
|
||||
}
|
||||
|
||||
QVector<quint32> indices = QVector<quint32>(glyphs.count());
|
||||
for (int i = 0; i < glyphs.count(); i++)
|
||||
indices[i] = (quint32)glyphs[i];
|
||||
|
||||
const quint32 *tag = reinterpret_cast<const quint32 *>("name");
|
||||
|
||||
return new GlyphInfo(fe->getSfntTable(qToBigEndian(*tag)), size, stretch, points, indices);
|
||||
indices = PyTuple_New(glyphs.count());
|
||||
if (indices == NULL) { Py_DECREF(points); return PyErr_NoMemory(); }
|
||||
for (int i = 0; i < glyphs.count(); i++) {
|
||||
temp = PyInt_FromLong((long)glyphs[i]);
|
||||
if (temp == NULL) { Py_DECREF(indices); Py_DECREF(points); return PyErr_NoMemory(); }
|
||||
PyTuple_SET_ITEM(indices, i, temp); temp = NULL;
|
||||
}
|
||||
const QByteArray table(fe->getSfntTable(qToBigEndian(*tag)));
|
||||
return Py_BuildValue("s#ffOO", table.constData(), table.size(), size, stretch, points, indices);
|
||||
}
|
||||
|
||||
GlyphInfo::GlyphInfo(const QByteArray& name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<quint32> &indices) :name(name), positions(positions), size(size), stretch(stretch), indices(indices) {
|
||||
}
|
||||
|
||||
QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name) {
|
||||
PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name) {
|
||||
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
||||
const quint32 *tag = reinterpret_cast<const quint32 *>(tag_name);
|
||||
return ti.fontEngine->getSfntTable(qToBigEndian(*tag));
|
||||
const QByteArray table(ti.fontEngine->getSfntTable(qToBigEndian(*tag)));
|
||||
return Py_BuildValue("s#", table.constData());
|
||||
}
|
||||
|
||||
QVector<quint32>* get_glyph_map(const QTextItem &text_item) {
|
||||
PyObject* get_glyph_map(const QTextItem &text_item) {
|
||||
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
||||
QVector<quint32> *ans = new QVector<quint32>(0x10000);
|
||||
QGlyphLayoutArray<10> glyphs;
|
||||
int nglyphs = 10;
|
||||
PyObject *t = NULL, *ans = PyTuple_New(0x10000);
|
||||
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
|
||||
for (uint uc = 0; uc < 0x10000; ++uc) {
|
||||
QChar ch(uc);
|
||||
ti.fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
|
||||
(*ans)[uc] = glyphs.glyphs[0];
|
||||
t = PyInt_FromLong(glyphs.glyphs[0]);
|
||||
if (t == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); }
|
||||
PyTuple_SET_ITEM(ans, uc, t); t = NULL;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
@ -10,26 +10,11 @@
|
||||
#include <QGlyphRun>
|
||||
#include <QTextItem>
|
||||
#include <QPointF>
|
||||
#include <Python.h>
|
||||
|
||||
PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item);
|
||||
|
||||
class GlyphInfo {
|
||||
public:
|
||||
QByteArray name;
|
||||
QVector<QPointF> positions;
|
||||
qreal size;
|
||||
qreal stretch;
|
||||
QVector<quint32> indices;
|
||||
PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name);
|
||||
|
||||
GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<quint32> &indices);
|
||||
|
||||
private:
|
||||
GlyphInfo(const GlyphInfo&);
|
||||
GlyphInfo &operator=(const GlyphInfo&);
|
||||
};
|
||||
|
||||
GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item);
|
||||
|
||||
QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name);
|
||||
|
||||
QVector<quint32>* get_glyph_map(const QTextItem &text_item);
|
||||
PyObject* get_glyph_map(const QTextItem &text_item);
|
||||
|
||||
|
@ -5,25 +5,12 @@
|
||||
|
||||
%Import QtCore/QtCoremod.sip
|
||||
%Import QtGui/QtGuimod.sip
|
||||
|
||||
class GlyphInfo {
|
||||
%TypeHeaderCode
|
||||
%ModuleCode
|
||||
#include <qt_hack.h>
|
||||
%End
|
||||
public:
|
||||
QByteArray name;
|
||||
qreal size;
|
||||
qreal stretch;
|
||||
QVector<QPointF> &positions;
|
||||
QVector<quint32> indices;
|
||||
GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<quint32> &indices);
|
||||
private:
|
||||
GlyphInfo(const GlyphInfo& g);
|
||||
|
||||
};
|
||||
PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item);
|
||||
|
||||
GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item);
|
||||
PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name);
|
||||
|
||||
QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name);
|
||||
|
||||
QVector<quint32>* get_glyph_map(const QTextItem &text_item);
|
||||
PyObject* get_glyph_map(const QTextItem &text_item);
|
||||
|
Loading…
x
Reference in New Issue
Block a user