/*------------------------------------------------------------------------ * Copyright 2009 (c) Jeff Brown * * 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 #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, };