Skip to content

Commit 91a47d8

Browse files
committed
feat: add python display plugin interface
1 parent be702c5 commit 91a47d8

21 files changed

+574
-34
lines changed

src/hobbits-core/parameterdelegate.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ bool ParameterDelegate::validateAgainstInfos(const QJsonObject &parameters, QLis
101101
return false;
102102
}
103103
}
104+
else if (param.type == QJsonValue::Double && param.hasIntLimits) {
105+
int value = parameters.value(param.name).toInt();
106+
if (value > param.intMax || value < param.intMin) {
107+
return false;
108+
}
109+
}
104110
}
105111

106112
return true;

src/hobbits-core/parameterdelegate.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ class HOBBITSCORESHARED_EXPORT ParameterDelegate : public QEnableSharedFromThis<
3535
bool optional;
3636
QList<ParameterInfo> subInfos;
3737

38+
bool hasIntLimits;
39+
int intMin;
40+
int intMax;
41+
3842
ParameterInfo(QString name, QJsonValue::Type type, bool optional = true, QList<ParameterInfo> subInfos = {}):
39-
name{name}, type{type}, optional{optional}, subInfos{subInfos} {}
43+
name{name}, type{type}, optional{optional}, subInfos{subInfos}, hasIntLimits(false), intMin(0), intMax(INT_MAX) {}
4044

4145
ParameterInfo() = default;
4246
ParameterInfo(const ParameterInfo&) = default;

src/hobbits-plugins/importerexporters/DisplayPrint/displayprint.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,14 @@ QSharedPointer<ExportResult> DisplayPrint::exportBits(QSharedPointer<const BitCo
9494
QSharedPointer<DisplayHandle> displayHandle(new DisplayHandle(containerManager));
9595
displayPlugin->setDisplayHandle(displayHandle);
9696

97-
//TODO: make this less hacky
9897
auto noConstContainer = BitContainer::create(container->bits(), container->info());
9998
containerManager->addContainer(noConstContainer);
10099
containerManager->selectContainer(noConstContainer);
101100

102101
QJsonObject displayParams = parameters.value("display_params").toObject();
103102

104103
QImage display = displayPlugin->renderDisplay(QSize(imageWidth, imageHeight), displayParams, progress);
105-
QImage overlay = displayPlugin->renderDisplay(QSize(imageWidth, imageHeight), displayParams, progress);
104+
QImage overlay = displayPlugin->renderOverlay(QSize(imageWidth, imageHeight), displayParams);
106105

107106
QPixmap pixmap(imageWidth, imageHeight);
108107
QPainter painter(&pixmap);

src/hobbits-plugins/importerexporters/HttpData/httpdata.cpp

-13
Original file line numberDiff line numberDiff line change
@@ -113,19 +113,6 @@ QSharedPointer<ExportResult> HttpData::exportBits(QSharedPointer<const BitContai
113113
QJsonObject parameters,
114114
QSharedPointer<PluginActionProgress> progress)
115115
{
116-
// TODO: make this part of post-result reporting
117-
// if (container->bits()->sizeInBytes() > 10000000) {
118-
// QMessageBox::StandardButton reply;
119-
// reply = QMessageBox::question(
120-
// nullptr,
121-
// "Data Truncation Warning",
122-
// QString("Uploaded data will be truncated at 10MB. Do you want to proceed anyways?"),
123-
// QMessageBox::Yes | QMessageBox::No);
124-
// if (reply != QMessageBox::Yes) {
125-
// return ExportResult::nullResult();
126-
// }
127-
// }
128-
129116
if (!m_exportDelegate->validate(parameters)) {
130117
return ExportResult::error("Invalid parameters passed to HTTP Import");
131118
}

src/hobbits-python/hobbits-python.pro

+4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ DEFINES += QT_DEPRECATED_WARNINGS
2323

2424
SOURCES += \
2525
hobbitspython.cpp \
26+
imagebuffer.cpp \
2627
py_actionprogress.cpp \
2728
py_bitarray.cpp \
2829
py_bitcontainer.cpp \
2930
py_bitinfo.cpp \
31+
py_displayhandle.cpp \
3032
py_hobbits.cpp \
3133
pythonanalyzer.cpp \
3234
pythonarg.cpp \
@@ -41,10 +43,12 @@ SOURCES += \
4143
HEADERS += \
4244
hobbitspython.h \
4345
hobbits-python_global.h \
46+
imagebuffer.h \
4447
py_actionprogress.h \
4548
py_bitarray.h \
4649
py_bitcontainer.h \
4750
py_bitinfo.h \
51+
py_displayhandle.h \
4852
py_hobbits.h \
4953
pythonanalyzer.h \
5054
pythonarg.h \

src/hobbits-python/hobbitspython.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ QString HobbitsPython::pythonVersion()
2222
return version;
2323
}
2424

25+
void HobbitsPython::waitForInterpreterLock()
26+
{
27+
PythonInterpreter::waitForLock();
28+
}
29+
2530
QSharedPointer<PluginActionWatcher<QSharedPointer<PythonResult> > > HobbitsPython::runProcessScript(
2631
QSharedPointer<PythonRequest> request,
2732
bool includeActionProgressArg)

src/hobbits-python/hobbitspython.h

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class HOBBITSPYTHONSHARED_EXPORT HobbitsPython : public QObject
1717
public:
1818
static HobbitsPython& getInstance();
1919
static QString pythonVersion();
20+
static void waitForInterpreterLock();
2021

2122
QSharedPointer<PluginActionWatcher<QSharedPointer<PythonResult>>> runProcessScript(
2223
QSharedPointer<PythonRequest> request,

src/hobbits-python/imagebuffer.cpp

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#include "imagebuffer.h"
2+
#include <structmember.h>
3+
#include "math.h"
4+
5+
typedef struct {
6+
PyObject_HEAD
7+
PyObject* memview;
8+
unsigned int width;
9+
unsigned int height;
10+
} ImageBufferPyObj;
11+
12+
static void ImageBuffer_dealloc(ImageBufferPyObj *self)
13+
{
14+
Py_XDECREF(self->memview);
15+
Py_TYPE(self)->tp_free((PyObject*) self);
16+
}
17+
18+
static PyObject* ImageBuffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
19+
{
20+
ImageBufferPyObj *self;
21+
self = reinterpret_cast<ImageBufferPyObj*>(type->tp_alloc(type, 0));
22+
if (self != nullptr) {
23+
self->memview = nullptr;
24+
}
25+
return (PyObject*) self;
26+
}
27+
28+
static int ImageBuffer_init(ImageBufferPyObj *self, PyObject *args, PyObject *kwds)
29+
{
30+
PyObject *memview;
31+
unsigned int width;
32+
unsigned int height;
33+
if (!PyArg_ParseTuple(args, "OII", &memview, &width, &height)) {
34+
PyErr_SetString(PyExc_TypeError, "invalid arguments - requires a memoryview, width, and height");
35+
return -1;
36+
}
37+
38+
if (!PyMemoryView_Check(memview)) {
39+
PyErr_SetString(PyExc_TypeError, "invalid arguments - hobbits.ImageBuffer must be initialized with a memoryview");
40+
return -1;
41+
}
42+
43+
if (width < 1 || height < 1) {
44+
PyErr_SetString(PyExc_TypeError, "invalid arguments - requires non-zero width and height");
45+
return -1;
46+
}
47+
48+
Py_buffer * buffer = PyMemoryView_GET_BUFFER(memview);
49+
50+
if (width * height * 4 != buffer->len) {
51+
PyErr_SetString(PyExc_TypeError, "invalid arguments - memoryview length must be equal to width * height * 4 (4 bytes per pixel)");
52+
return -1;
53+
}
54+
55+
PyBuffer_Release(buffer);
56+
57+
Py_INCREF(memview);
58+
self->memview = memview;
59+
self->width = width;
60+
self->height = height;
61+
return 0;
62+
}
63+
64+
static PyObject* ImageBuffer_set_bytes(ImageBufferPyObj *self, PyObject *args)
65+
{
66+
Py_buffer buffer;
67+
if (!PyArg_ParseTuple(args, "y*", &buffer)) {
68+
PyErr_SetString(PyExc_TypeError, "invalid arguments - requires a bytes-like object");
69+
return nullptr;
70+
}
71+
72+
Py_buffer* memviewBuffer = PyMemoryView_GET_BUFFER(self->memview);
73+
74+
int toCopy = buffer.len;
75+
if (toCopy > memviewBuffer->len) {
76+
toCopy = memviewBuffer->len;
77+
}
78+
79+
memcpy(memviewBuffer->buf, buffer.buf, toCopy);
80+
81+
PyBuffer_Release(&buffer);
82+
PyBuffer_Release(memviewBuffer);
83+
Py_RETURN_NONE;
84+
}
85+
86+
static PyObject* ImageBuffer_get_width(ImageBufferPyObj *self, void *Py_UNUSED(closure))
87+
{
88+
return PyLong_FromUnsignedLong(self->width);
89+
}
90+
91+
static PyObject* ImageBuffer_get_height(ImageBufferPyObj *self, void *Py_UNUSED(closure))
92+
{
93+
return PyLong_FromUnsignedLong(self->height);
94+
}
95+
96+
static PyMethodDef ImageBuffer_methods[] = {
97+
{ "set_bytes", PyCFunction(ImageBuffer_set_bytes), METH_VARARGS, nullptr },
98+
{} /* Sentinel */
99+
};
100+
101+
static PyMemberDef ImageBuffer_members[] = {
102+
{} /* Sentinel */
103+
};
104+
105+
static PyGetSetDef ImageBuffer_getsets[] = {
106+
{"width", getter(ImageBuffer_get_width), nullptr, nullptr, nullptr},
107+
{"height", getter(ImageBuffer_get_height), nullptr, nullptr, nullptr},
108+
{} /* Sentinel */
109+
};
110+
111+
extern PyTypeObject ImageBuffer = {
112+
PyVarObject_HEAD_INIT(nullptr, 0)
113+
114+
"hobbits.ImageBuffer", // const char *tp_name; /* For printing, in format "<module>.<name>" */
115+
sizeof(ImageBufferPyObj), // Py_ssize_t tp_basicsize, ; /* For allocation */
116+
0, //tp_itemsize
117+
118+
/* Methods to implement standard operations */
119+
120+
destructor(ImageBuffer_dealloc), // destructor tp_dealloc;
121+
0, // Py_ssize_t tp_vectorcall_offset;
122+
nullptr, // getattrfunc tp_getattr;
123+
nullptr, // setattrfunc tp_setattr;
124+
nullptr, // PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2) or tp_reserved (Python 3) */
125+
nullptr, // reprfunc tp_repr;
126+
127+
/* Method suites for standard classes */
128+
129+
nullptr, // PyNumberMethods *tp_as_number;
130+
nullptr, // PySequenceMethods *tp_as_sequence;
131+
nullptr, // PyMappingMethods *tp_as_mapping;
132+
133+
/* More standard operations (here for binary compatibility) */
134+
135+
nullptr, // hashfunc tp_hash;
136+
nullptr, // ternaryfunc tp_call;
137+
nullptr, // reprfunc tp_str;
138+
nullptr, // getattrofunc tp_getattro;
139+
nullptr, // setattrofunc tp_setattro;
140+
141+
/* Functions to access object as input/output buffer */
142+
nullptr, // PyBufferProcs *tp_as_buffer;
143+
144+
/* Flags to define presence of optional/expanded features */
145+
Py_TPFLAGS_DEFAULT, // unsigned long tp_flags;
146+
147+
"Hobbits Bit Array", // const char *tp_doc; /* Documentation string */
148+
149+
/* Assigned meaning in release 2.0 */
150+
/* call function for all accessible objects */
151+
nullptr, // traverseproc tp_traverse;
152+
153+
/* delete references to contained objects */
154+
nullptr, // inquiry tp_clear;
155+
156+
/* Assigned meaning in release 2.1 */
157+
/* rich comparisons */
158+
nullptr, // richcmpfunc tp_richcompare;
159+
160+
/* weak reference enabler */
161+
0, // Py_ssize_t tp_weaklistoffset;
162+
163+
/* Iterators */
164+
nullptr, // getiterfunc tp_iter;
165+
nullptr, // iternextfunc tp_iternext;
166+
167+
/* Attribute descriptor and subclassing stuff */
168+
ImageBuffer_methods, // struct PyMethodDef *tp_methods;
169+
ImageBuffer_members, // struct PyMemberDef *tp_members;
170+
ImageBuffer_getsets, // struct PyGetSetDef *tp_getset;
171+
nullptr, // struct _typeobject *tp_base;
172+
nullptr, // PyObject *tp_dict;
173+
nullptr, // descrgetfunc tp_descr_get;
174+
nullptr, // descrsetfunc tp_descr_set;
175+
0, // Py_ssize_t tp_dictoffset;
176+
initproc(ImageBuffer_init), // initproc tp_init;
177+
nullptr, // allocfunc tp_alloc;
178+
ImageBuffer_new, // newfunc tp_new;
179+
nullptr, // freefunc tp_free; /* Low-level free-memory routine */
180+
nullptr, // inquiry tp_is_gc; /* For PyObject_IS_GC */
181+
nullptr, // PyObject *tp_bases;
182+
nullptr, // PyObject *tp_mro; /* method resolution order */
183+
nullptr, // PyObject *tp_cache;
184+
nullptr, // PyObject *tp_subclasses;
185+
nullptr, // PyObject *tp_weaklist;
186+
nullptr, // destructor tp_del;
187+
188+
/* Type attribute cache version tag. Added in version 2.6 */
189+
0, // unsigned int tp_version_tag;
190+
191+
nullptr, // destructor tp_finalize;
192+
nullptr, // vectorcallfunc tp_vectorcall;
193+
// Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
194+
};

src/hobbits-python/imagebuffer.h

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef IMAGEBUFFER_H
2+
#define IMAGEBUFFER_H
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include <Python.h>
6+
7+
8+
extern "C" {
9+
10+
extern PyTypeObject ImageBuffer;
11+
12+
}
13+
14+
#endif // IMAGEBUFFER_H

0 commit comments

Comments
 (0)