diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 00:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 00:06:44 +0000 |
commit | 44cf8ec67278bd1ab6c7f83a9993f7a5686a9541 (patch) | |
tree | 5eec4b0d1a3f163d279c3c27c03324ba49fa235a /python/processor.c | |
parent | Initial commit. (diff) | |
download | zbar-44cf8ec67278bd1ab6c7f83a9993f7a5686a9541.tar.xz zbar-44cf8ec67278bd1ab6c7f83a9993f7a5686a9541.zip |
Adding upstream version 0.23.93.upstream/0.23.93upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'python/processor.c')
-rw-r--r-- | python/processor.c | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/python/processor.c b/python/processor.c new file mode 100644 index 0000000..a9e4c47 --- /dev/null +++ b/python/processor.c @@ -0,0 +1,456 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +static char processor_doc[] = + PyDoc_STR("low level decode of measured bar/space widths.\n" + "\n" + "FIXME."); + +static zbarProcessor *processor_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { "enable_threads", NULL }; + int threaded = -1; + zbarProcessor *self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, object_to_bool, + &threaded)) + return (NULL); + +#ifdef WITH_THREAD +#if (PY_MAJOR_VERSION < 3) || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9) + /* the processor creates a thread that calls back into python, + * so we must ensure that threads are initialized before attempting + * to manipulate the GIL (bug #3349199) + */ + PyEval_InitThreads(); +#endif +#else + if (threaded > 0 && + PyErr_WarnEx(NULL, "threading requested but not available", 1)) + return (NULL); + threaded = 0; +#endif + + self = (zbarProcessor *)type->tp_alloc(type, 0); + if (!self) + return (NULL); + + self->zproc = zbar_processor_create(threaded); + zbar_processor_set_userdata(self->zproc, self); + if (!self->zproc) { + Py_DECREF(self); + return (NULL); + } + return (self); +} + +static int processor_traverse(zbarProcessor *self, visitproc visit, void *arg) +{ + Py_VISIT(self->handler); + Py_VISIT(self->closure); + return (0); +} + +static int processor_clear(zbarProcessor *self) +{ + zbar_processor_set_data_handler(self->zproc, NULL, NULL); + zbar_processor_set_userdata(self->zproc, NULL); + Py_CLEAR(self->handler); + Py_CLEAR(self->closure); + return (0); +} + +static void processor_dealloc(zbarProcessor *self) +{ + processor_clear(self); + zbar_processor_destroy(self->zproc); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static PyObject *processor_get_bool(zbarProcessor *self, void *closure) +{ + int val; + switch ((intptr_t)closure) { + case 0: + val = zbar_processor_is_visible(self->zproc); + break; + default: + assert(0); + return (NULL); + } + if (val < 0) + return (zbarErr_Set((PyObject *)self)); + return (PyBool_FromLong(val)); +} + +static int processor_set_bool(zbarProcessor *self, PyObject *value, + void *closure) +{ + int rc, val; + + if (!value) { + PyErr_SetString(PyExc_TypeError, "cannot delete attribute"); + return (-1); + } + val = PyObject_IsTrue(value); + if (val < 0) + return (-1); + switch ((intptr_t)closure) { + case 0: + rc = zbar_processor_set_visible(self->zproc, val); + break; + case 1: + rc = zbar_processor_set_active(self->zproc, val); + break; + default: + assert(0); + return (-1); + } + if (rc < 0) { + zbarErr_Set((PyObject *)self); + return (-1); + } + return (0); +} + +static zbarSymbolSet *processor_get_results(zbarProcessor *self, void *closure) +{ + const zbar_symbol_set_t *zsyms = zbar_processor_get_results(self->zproc); + + return (zbarSymbolSet_FromSymbolSet(zsyms)); +} + +static int processor_set_request_size(zbarProcessor *self, PyObject *value, + void *closure) +{ + int dims[2]; + + if (!value) { + zbar_processor_request_size(self->zproc, 0, 0); + return (0); + } + + if (parse_dimensions(value, dims, 2) || dims[0] < 0 || dims[1] < 0) { + PyErr_SetString(PyExc_ValueError, + "request_size must be a sequence of two positive ints"); + return (-1); + } + + zbar_processor_request_size(self->zproc, dims[0], dims[1]); + return (0); +} + +static PyGetSetDef processor_getset[] = { + { "visible", (getter)processor_get_bool, (setter)processor_set_bool, NULL, + (void *)0 }, + { "active", NULL, (setter)processor_set_bool, NULL, (void *)1 }, + { + "results", + (getter)processor_get_results, + }, + { + "request_size", + NULL, + (setter)processor_set_request_size, + }, + { + NULL, + }, +}; + +static PyObject *processor_set_config(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + zbar_symbol_type_t sym = ZBAR_NONE; + zbar_config_t cfg = ZBAR_CFG_ENABLE; + int val = 1; + static char *kwlist[] = { "symbology", "config", "value", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iii", kwlist, &sym, &cfg, + &val)) + return (NULL); + + if (zbar_processor_set_config(self->zproc, sym, cfg, val)) { + PyErr_SetString(PyExc_ValueError, "invalid configuration setting"); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject *processor_init_(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + const char *dev = ""; + int disp = 1; + static char *kwlist[] = { "video_device", "enable_display", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO&", kwlist, &dev, + object_to_bool, &disp)) + return (NULL); + + if (zbar_processor_init(self->zproc, dev, disp)) + return (zbarErr_Set((PyObject *)self)); + Py_RETURN_NONE; +} + +static PyObject *processor_parse_config(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + const char *cfg = NULL; + static char *kwlist[] = { "config", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &cfg)) + return (NULL); + + if (zbar_processor_parse_config(self->zproc, cfg)) { + PyErr_Format(PyExc_ValueError, "invalid configuration setting: %s", + cfg); + return (NULL); + } + Py_RETURN_NONE; +} + +static int object_to_timeout(PyObject *obj, int *val) +{ + long tmp; + + if (PyFloat_Check(obj)) + tmp = PyFloat_AS_DOUBLE(obj) * 1000; + else +#if PY_MAJOR_VERSION >= 3 + tmp = PyLong_AsLong(obj) * 1000; +#else + tmp = PyInt_AsLong(obj) * 1000; +#endif + if (tmp < 0 && PyErr_Occurred()) + return (0); + *val = tmp; + return (1); +} + +static PyObject *processor_user_wait(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + int timeout = -1; + int rc = -1; + static char *kwlist[] = { "timeout", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, + object_to_timeout, &timeout)) + return (NULL); + + Py_BEGIN_ALLOW_THREADS rc = zbar_processor_user_wait(self->zproc, timeout); + Py_END_ALLOW_THREADS + + if (rc < 0) return (zbarErr_Set((PyObject *)self)); +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(rc)); +#else + return (PyInt_FromLong(rc)); +#endif +} + +static PyObject *processor_process_one(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + int timeout = -1; + int rc = -1; + static char *kwlist[] = { "timeout", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, + object_to_timeout, &timeout)) + return (NULL); + + Py_BEGIN_ALLOW_THREADS rc = zbar_process_one(self->zproc, timeout); + Py_END_ALLOW_THREADS + + if (rc < 0) return (zbarErr_Set((PyObject *)self)); +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(rc)); +#else + return (PyInt_FromLong(rc)); +#endif +} + +static PyObject *processor_process_image(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + zbarImage *img = NULL; + static char *kwlist[] = { "image", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &zbarImage_Type, + &img)) + return (NULL); + + if (zbarImage_validate(img)) + return (NULL); + + int n = -1; + Py_BEGIN_ALLOW_THREADS n = zbar_process_image(self->zproc, img->zimg); + Py_END_ALLOW_THREADS + + if (n < 0) return (zbarErr_Set((PyObject *)self)); +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(n)); +#else + return (PyInt_FromLong(n)); +#endif +} + +void process_handler(zbar_image_t *zimg, const void *userdata) +{ + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + zbarImage *img; + + zbarProcessor *self = (zbarProcessor *)userdata; + assert(self); + assert(self->handler); + assert(self->closure); + + img = zbar_image_get_userdata(zimg); + if (!img || img->zimg != zimg) { + img = zbarImage_FromImage(zimg); + if (!img) { + PyErr_NoMemory(); + goto done; + } + } else + Py_INCREF(img); + + PyObject *args = PyTuple_New(3); + Py_INCREF(self); + Py_INCREF(self->closure); + PyTuple_SET_ITEM(args, 0, (PyObject *)self); + PyTuple_SET_ITEM(args, 1, (PyObject *)img); + PyTuple_SET_ITEM(args, 2, self->closure); + + PyObject *junk = PyObject_Call(self->handler, args, NULL); + if (junk) + Py_DECREF(junk); + else { + PySys_WriteStderr("in ZBar Processor data_handler:\n"); + assert(PyErr_Occurred()); + PyErr_Print(); + } + Py_DECREF(args); + +done: + PyGILState_Release(gstate); +} + +static PyObject *processor_set_data_handler(zbarProcessor *self, PyObject *args, + PyObject *kwds) +{ + PyObject *handler = Py_None; + PyObject *closure = Py_None; + + static char *kwlist[] = { "handler", "closure", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &handler, + &closure)) + return (NULL); + + if (handler != Py_None && !PyCallable_Check(handler)) { + PyErr_Format(PyExc_ValueError, "handler %.50s is not callable", + handler->ob_type->tp_name); + return (NULL); + } + Py_CLEAR(self->handler); + Py_CLEAR(self->closure); + + if (handler != Py_None) { + Py_INCREF(handler); + self->handler = handler; + + Py_INCREF(closure); + self->closure = closure; + + zbar_processor_set_data_handler(self->zproc, process_handler, self); + } else { + self->handler = self->closure = NULL; + zbar_processor_set_data_handler(self->zproc, NULL, self); + } + Py_RETURN_NONE; +} + +static PyMethodDef processor_methods[] = { + { + "init", + (PyCFunction)processor_init_, + METH_VARARGS | METH_KEYWORDS, + }, + { + "set_config", + (PyCFunction)processor_set_config, + METH_VARARGS | METH_KEYWORDS, + }, + { + "parse_config", + (PyCFunction)processor_parse_config, + METH_VARARGS | METH_KEYWORDS, + }, + { + "user_wait", + (PyCFunction)processor_user_wait, + METH_VARARGS | METH_KEYWORDS, + }, + { + "process_one", + (PyCFunction)processor_process_one, + METH_VARARGS | METH_KEYWORDS, + }, + { + "process_image", + (PyCFunction)processor_process_image, + METH_VARARGS | METH_KEYWORDS, + }, + { + "set_data_handler", + (PyCFunction)processor_set_data_handler, + METH_VARARGS | METH_KEYWORDS, + }, + { + NULL, + }, +}; + +PyTypeObject zbarProcessor_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Processor", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = processor_doc, + .tp_basicsize = sizeof(zbarProcessor), + .tp_new = (newfunc)processor_new, + .tp_traverse = (traverseproc)processor_traverse, + .tp_clear = (inquiry)processor_clear, + .tp_dealloc = (destructor)processor_dealloc, + .tp_getset = processor_getset, + .tp_methods = processor_methods, +}; |