mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -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
|
import sys, traceback, math
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from functools import wraps, partial
|
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 PyQt5.Qt import (QPaintEngine, QPaintDevice, Qt, QTransform, QBrush)
|
||||||
|
|
||||||
from calibre.constants import plugins
|
from calibre.constants import plugins
|
||||||
@ -24,6 +23,7 @@ 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')
|
||||||
|
GlyphInfo = namedtuple('GlyphInfo', 'name size stretch positions indices')
|
||||||
|
|
||||||
def repr_transform(t):
|
def repr_transform(t):
|
||||||
vals = map(fmtnum, (t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy()))
|
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):
|
def drawTextItem(self, point, text_item):
|
||||||
# return super(PdfEngine, self).drawTextItem(point, text_item)
|
# return super(PdfEngine, self).drawTextItem(point, text_item)
|
||||||
self.apply_graphics_state()
|
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:
|
if not gi.indices:
|
||||||
sip.delete(gi)
|
|
||||||
return
|
return
|
||||||
name = hash(bytes(gi.name))
|
name = hash(gi.name)
|
||||||
if name not in self.fonts:
|
if name not in self.fonts:
|
||||||
try:
|
try:
|
||||||
self.fonts[name] = self.create_sfnt(text_item)
|
self.fonts[name] = self.create_sfnt(text_item)
|
||||||
@ -260,14 +259,12 @@ class PdfEngine(QPaintEngine):
|
|||||||
pass
|
pass
|
||||||
glyphs = []
|
glyphs = []
|
||||||
last_x = last_y = 0
|
last_x = last_y = 0
|
||||||
for i, pos in enumerate(gi.positions):
|
for glyph_index, (x, y) in zip(gi.indices, gi.positions):
|
||||||
x, y = pos.x(), pos.y()
|
glyphs.append((x-last_x, last_y - y, glyph_index))
|
||||||
glyphs.append((x-last_x, last_y - y, gi.indices[i]))
|
|
||||||
last_x, last_y = x, y
|
last_x, last_y = x, y
|
||||||
|
|
||||||
self.pdf.draw_glyph_run([gi.stretch, 0, 0, -1, 0, 0], gi.size, metrics,
|
self.pdf.draw_glyph_run([gi.stretch, 0, 0, -1, 0, 0], gi.size, metrics,
|
||||||
glyphs)
|
glyphs)
|
||||||
sip.delete(gi)
|
|
||||||
|
|
||||||
@store_error
|
@store_error
|
||||||
def drawPolygon(self, points, mode):
|
def drawPolygon(self, points, mode):
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
#include "private/qtextengine_p.h"
|
#include "private/qtextengine_p.h"
|
||||||
#include "private/qfontengine_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);
|
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
||||||
QFontEngine *fe = ti.fontEngine;
|
QFontEngine *fe = ti.fontEngine;
|
||||||
qreal size = ti.fontEngine->fontDef.pixelSize;
|
qreal size = ti.fontEngine->fontDef.pixelSize;
|
||||||
@ -33,40 +34,49 @@ GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) {
|
|||||||
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());
|
|
||||||
|
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++) {
|
for (int i = 0; i < positions.count(); i++) {
|
||||||
points[i].setX(positions[i].x.toReal()/stretch);
|
temp = Py_BuildValue("dd", positions[i].x.toReal()/stretch, positions[i].y.toReal());
|
||||||
points[i].setY(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());
|
indices = PyTuple_New(glyphs.count());
|
||||||
for (int i = 0; i < glyphs.count(); i++)
|
if (indices == NULL) { Py_DECREF(points); return PyErr_NoMemory(); }
|
||||||
indices[i] = (quint32)glyphs[i];
|
for (int i = 0; i < glyphs.count(); i++) {
|
||||||
|
temp = PyInt_FromLong((long)glyphs[i]);
|
||||||
const quint32 *tag = reinterpret_cast<const quint32 *>("name");
|
if (temp == NULL) { Py_DECREF(indices); Py_DECREF(points); return PyErr_NoMemory(); }
|
||||||
|
PyTuple_SET_ITEM(indices, i, temp); temp = NULL;
|
||||||
return new GlyphInfo(fe->getSfntTable(qToBigEndian(*tag)), size, stretch, points, indices);
|
}
|
||||||
|
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) {
|
PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name) {
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name) {
|
|
||||||
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
||||||
const quint32 *tag = reinterpret_cast<const quint32 *>(tag_name);
|
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);
|
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
|
||||||
QVector<quint32> *ans = new QVector<quint32>(0x10000);
|
|
||||||
QGlyphLayoutArray<10> glyphs;
|
QGlyphLayoutArray<10> glyphs;
|
||||||
int nglyphs = 10;
|
int nglyphs = 10;
|
||||||
|
PyObject *t = NULL, *ans = PyTuple_New(0x10000);
|
||||||
|
|
||||||
|
if (ans == NULL) return PyErr_NoMemory();
|
||||||
|
|
||||||
for (uint uc = 0; uc < 0x10000; ++uc) {
|
for (uint uc = 0; uc < 0x10000; ++uc) {
|
||||||
QChar ch(uc);
|
QChar ch(uc);
|
||||||
ti.fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
|
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;
|
return ans;
|
||||||
}
|
}
|
||||||
|
@ -10,26 +10,11 @@
|
|||||||
#include <QGlyphRun>
|
#include <QGlyphRun>
|
||||||
#include <QTextItem>
|
#include <QTextItem>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item);
|
||||||
|
|
||||||
class GlyphInfo {
|
PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name);
|
||||||
public:
|
|
||||||
QByteArray name;
|
|
||||||
QVector<QPointF> positions;
|
|
||||||
qreal size;
|
|
||||||
qreal stretch;
|
|
||||||
QVector<quint32> indices;
|
|
||||||
|
|
||||||
GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<quint32> &indices);
|
PyObject* get_glyph_map(const QTextItem &text_item);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
@ -5,25 +5,12 @@
|
|||||||
|
|
||||||
%Import QtCore/QtCoremod.sip
|
%Import QtCore/QtCoremod.sip
|
||||||
%Import QtGui/QtGuimod.sip
|
%Import QtGui/QtGuimod.sip
|
||||||
|
%ModuleCode
|
||||||
class GlyphInfo {
|
|
||||||
%TypeHeaderCode
|
|
||||||
#include <qt_hack.h>
|
#include <qt_hack.h>
|
||||||
%End
|
%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);
|
PyObject* get_glyph_map(const QTextItem &text_item);
|
||||||
|
|
||||||
QVector<quint32>* get_glyph_map(const QTextItem &text_item);
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user