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 | |
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')
-rw-r--r-- | python/MANIFEST.in | 2 | ||||
-rw-r--r-- | python/Makefile.am.inc | 13 | ||||
-rw-r--r-- | python/README | 60 | ||||
-rw-r--r-- | python/decoder.c | 360 | ||||
-rw-r--r-- | python/enum.c | 259 | ||||
-rw-r--r-- | python/examples/processor.py | 35 | ||||
-rw-r--r-- | python/examples/read_one.py | 29 | ||||
-rw-r--r-- | python/examples/scan_image.py | 31 | ||||
-rw-r--r-- | python/exception.c | 123 | ||||
-rw-r--r-- | python/image.c | 482 | ||||
-rw-r--r-- | python/imagescanner.c | 195 | ||||
-rw-r--r-- | python/processor.c | 456 | ||||
-rw-r--r-- | python/scanner.c | 193 | ||||
-rw-r--r-- | python/setup.py | 45 | ||||
-rw-r--r-- | python/symbol.c | 230 | ||||
-rw-r--r-- | python/symboliter.c | 103 | ||||
-rw-r--r-- | python/symbolset.c | 85 | ||||
-rw-r--r-- | python/test/barcode.png | bin | 0 -> 1182 bytes | |||
-rwxr-xr-x | python/test/test_zbar.py | 506 | ||||
-rw-r--r-- | python/zbarmodule.c | 340 | ||||
-rw-r--r-- | python/zbarmodule.h | 164 |
21 files changed, 3711 insertions, 0 deletions
diff --git a/python/MANIFEST.in b/python/MANIFEST.in new file mode 100644 index 0000000..93acc53 --- /dev/null +++ b/python/MANIFEST.in @@ -0,0 +1,2 @@ +include MANIFEST MANIFEST.in zbarmodule.h test/barcode.png +recursive-include examples *.py diff --git a/python/Makefile.am.inc b/python/Makefile.am.inc new file mode 100644 index 0000000..f1f30a4 --- /dev/null +++ b/python/Makefile.am.inc @@ -0,0 +1,13 @@ +pyexec_LTLIBRARIES += python/zbar.la +python_zbar_la_CPPFLAGS = $(PYTHON_CFLAGS) $(AM_CPPFLAGS) +python_zbar_la_LDFLAGS = -shared -module -avoid-version -export-dynamic \ + -export-symbols-regex '(initzbar|PyInit_zbar)' $(PYTHON_LDFLAGS) +python_zbar_la_LIBADD = zbar/libzbar.la $(AM_LIBADD) + +python_zbar_la_SOURCES = python/zbarmodule.c python/zbarmodule.h \ + python/enum.c python/exception.c python/symbol.c python/symbolset.c \ + python/symboliter.c python/image.c \ + python/processor.c python/imagescanner.c python/decoder.c python/scanner.c + +EXTRA_DIST += python/test/barcode.png python/test/test_zbar.py \ + python/examples/processor.py python/examples/read_one.py diff --git a/python/README b/python/README new file mode 100644 index 0000000..876b0c3 --- /dev/null +++ b/python/README @@ -0,0 +1,60 @@ +========================================== +zbar -- read barcodes from images or video +========================================== + +ZBar Bar Code Reader is an open source software suite for reading bar +codes from various sources, such as video streams, image files and raw +intensity sensors. It supports EAN-13/UPC-A, UPC-E, EAN-8, Code 128, +Code 93, Code 39, Codabar, Interleaved 2 of 5 and QR Code. These are +the Python bindings for the library. + +Check the ZBar project home page for the latest release, mailing +lists, etc. + +* https://github.com/mchehab/zbar + +Installation +------------ + +To install this module type the following:: + + python setup.py install + +Dependencies +------------ + +This module requires the ZBar Bar Code Reader, which may be obtained +from: + +* https://github.com/mchehab/zbar + +Windows users please note: the module *will NOT load* unless the ZBar +library DLL (currently libzbar-0.dll) is available in your Windows system +PATH! + +Examples +-------- + +To scan an image, wrap the raw image data in a ``zbar.Image`` and feed +it to a ``zbar.ImageScanner``:: + + import zbar + scanner = zbar.ImageScanner() + image = zbar.Image(width, height, 'Y800', raw_data) + scanner.scan(image) + for symbol in image: + print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data + +Complete, runnable examples may be found in the source distribution, +under the ``examples/`` directory. A couple of HOWTOs_ that cover +programming with the library may be found on the project wiki. + +.. _HOWTOs: http://sourceforge.net/apps/mediawiki/zbar/index.php?title=Category:HOWTOs + +Copyright and License +--------------------- + +Licensed under the GNU Lesser General Public License, version 2.1. +http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt + +Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net> diff --git a/python/decoder.c b/python/decoder.c new file mode 100644 index 0000000..e75ee9f --- /dev/null +++ b/python/decoder.c @@ -0,0 +1,360 @@ +/*------------------------------------------------------------------------ + * Copyright 2009-2010 (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" + +static char decoder_doc[] = + PyDoc_STR("low level decode of measured bar/space widths.\n" + "\n" + "FIXME."); + +static zbarDecoder *decoder_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return (NULL); + + zbarDecoder *self = (zbarDecoder *)type->tp_alloc(type, 0); + if (!self) + return (NULL); + + self->zdcode = zbar_decoder_create(); + zbar_decoder_set_userdata(self->zdcode, self); + if (!self->zdcode) { + Py_DECREF(self); + return (NULL); + } + + return (self); +} + +static int decoder_traverse(zbarDecoder *self, visitproc visit, void *arg) +{ + Py_VISIT(self->handler); + Py_VISIT(self->args); + return (0); +} + +static int decoder_clear(zbarDecoder *self) +{ + zbar_decoder_set_handler(self->zdcode, NULL); + zbar_decoder_set_userdata(self->zdcode, NULL); + Py_CLEAR(self->handler); + Py_CLEAR(self->args); + return (0); +} + +static void decoder_dealloc(zbarDecoder *self) +{ + decoder_clear(self); + zbar_decoder_destroy(self->zdcode); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static zbarEnumItem *decoder_get_color(zbarDecoder *self, void *closure) +{ + zbar_color_t zcol = zbar_decoder_get_color(self->zdcode); + assert(zcol == ZBAR_BAR || zcol == ZBAR_SPACE); + + struct module_state *st = GETMODSTATE(); + zbarEnumItem *color = st->color_enum[zcol]; + Py_INCREF((PyObject *)color); + return (color); +} + +static zbarEnumItem *decoder_get_type(zbarDecoder *self, void *closure) +{ + zbar_symbol_type_t sym = zbar_decoder_get_type(self->zdcode); + if (sym == ZBAR_NONE) { + /* hardcode most common case */ + struct module_state *st = GETMODSTATE(); + Py_INCREF((PyObject *)st->symbol_NONE); + return (st->symbol_NONE); + } + return (zbarSymbol_LookupEnum(sym)); +} + +static PyObject *decoder_get_configs(zbarDecoder *self, void *closure) +{ + struct module_state *st = GETMODSTATE(); + unsigned int sym = zbar_decoder_get_type(self->zdcode); + unsigned int mask = zbar_decoder_get_configs(self->zdcode, sym); + return (zbarEnum_SetFromMask(st->config_enum, mask)); +} + +static PyObject *decoder_get_modifiers(zbarDecoder *self, void *closure) +{ + unsigned int mask = zbar_decoder_get_modifiers(self->zdcode); + struct module_state *st = GETMODSTATE(); + return (zbarEnum_SetFromMask(st->modifier_enum, mask)); +} + +static PyObject *decoder_get_data(zbarDecoder *self, void *closure) +{ +#if PY_MAJOR_VERSION >= 3 + return (PyUnicode_FromStringAndSize(zbar_decoder_get_data(self->zdcode), + zbar_decoder_get_data_length( + self->zdcode))); +#else + return ( + PyString_FromStringAndSize(zbar_decoder_get_data(self->zdcode), + zbar_decoder_get_data_length(self->zdcode))); +#endif +} + +static PyObject *decoder_get_direction(zbarDecoder *self, void *closure) +{ +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(zbar_decoder_get_direction(self->zdcode))); +#else + return (PyInt_FromLong(zbar_decoder_get_direction(self->zdcode))); +#endif +} + +static PyGetSetDef decoder_getset[] = { + { + "color", + (getter)decoder_get_color, + }, + { + "type", + (getter)decoder_get_type, + }, + { + "configs", + (getter)decoder_get_configs, + }, + { + "modifiers", + (getter)decoder_get_modifiers, + }, + { + "data", + (getter)decoder_get_data, + }, + { "direction", (getter)decoder_get_direction }, + { + NULL, + }, +}; + +static PyObject *decoder_set_config(zbarDecoder *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_decoder_set_config(self->zdcode, sym, cfg, val)) { + PyErr_SetString(PyExc_ValueError, "invalid configuration setting"); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject *decoder_get_configs_meth(zbarDecoder *self, PyObject *args, + PyObject *kwds) +{ + zbar_symbol_type_t sym = ZBAR_NONE; + static char *kwlist[] = { "symbology", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &sym)) + return (NULL); + + if (sym == ZBAR_NONE) + sym = zbar_decoder_get_type(self->zdcode); + + struct module_state *st = GETMODSTATE(); + unsigned int mask = zbar_decoder_get_configs(self->zdcode, sym); + return (zbarEnum_SetFromMask(st->config_enum, mask)); +} + +static PyObject *decoder_parse_config(zbarDecoder *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_decoder_parse_config(self->zdcode, cfg)) { + PyErr_Format(PyExc_ValueError, "invalid configuration setting: %s", + cfg); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject *decoder_reset(zbarDecoder *self, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return (NULL); + + zbar_decoder_reset(self->zdcode); + Py_RETURN_NONE; +} + +static PyObject *decoder_new_scan(zbarDecoder *self, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return (NULL); + + zbar_decoder_new_scan(self->zdcode); + Py_RETURN_NONE; +} + +void decode_handler(zbar_decoder_t *zdcode) +{ + assert(zdcode); + zbarDecoder *self = zbar_decoder_get_userdata(zdcode); + assert(self); + assert(self->zdcode == zdcode); + assert(self->handler); + assert(self->args); + PyObject *junk = PyObject_Call(self->handler, self->args, NULL); + Py_XDECREF(junk); +} + +static PyObject *decoder_set_handler(zbarDecoder *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->args); + + if (handler != Py_None) { + self->args = PyTuple_New(2); + if (!self->args) + return (NULL); + Py_INCREF(self); + Py_INCREF(closure); + PyTuple_SET_ITEM(self->args, 0, (PyObject *)self); + PyTuple_SET_ITEM(self->args, 1, closure); + + Py_INCREF(handler); + self->handler = handler; + + zbar_decoder_set_handler(self->zdcode, decode_handler); + } else { + self->handler = self->args = NULL; + zbar_decoder_set_handler(self->zdcode, NULL); + } + Py_RETURN_NONE; +} + +static zbarEnumItem *decoder_decode_width(zbarDecoder *self, PyObject *args, + PyObject *kwds) +{ + unsigned int width = 0; + static char *kwlist[] = { "width", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", kwlist, &width)) + return (NULL); + + zbar_symbol_type_t sym = zbar_decode_width(self->zdcode, width); + if (PyErr_Occurred()) + /* propagate errors during callback */ + return (NULL); + if (sym == ZBAR_NONE) { + /* hardcode most common case */ + struct module_state *st = GETMODSTATE(); + Py_INCREF((PyObject *)st->symbol_NONE); + return (st->symbol_NONE); + } + return (zbarSymbol_LookupEnum(sym)); +} + +static PyMethodDef decoder_methods[] = { + { + "set_config", + (PyCFunction)decoder_set_config, + METH_VARARGS | METH_KEYWORDS, + }, + { + "get_configs", + (PyCFunction)decoder_get_configs_meth, + METH_VARARGS | METH_KEYWORDS, + }, + { + "parse_config", + (PyCFunction)decoder_parse_config, + METH_VARARGS | METH_KEYWORDS, + }, + { + "reset", + (PyCFunction)decoder_reset, + METH_VARARGS | METH_KEYWORDS, + }, + { + "new_scan", + (PyCFunction)decoder_new_scan, + METH_VARARGS | METH_KEYWORDS, + }, + { + "set_handler", + (PyCFunction)decoder_set_handler, + METH_VARARGS | METH_KEYWORDS, + }, + { + "decode_width", + (PyCFunction)decoder_decode_width, + METH_VARARGS | METH_KEYWORDS, + }, + { + NULL, + }, +}; + +PyTypeObject zbarDecoder_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Decoder", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = decoder_doc, + .tp_basicsize = sizeof(zbarDecoder), + .tp_new = (newfunc)decoder_new, + .tp_traverse = (traverseproc)decoder_traverse, + .tp_clear = (inquiry)decoder_clear, + .tp_dealloc = (destructor)decoder_dealloc, + .tp_getset = decoder_getset, + .tp_methods = decoder_methods, +}; diff --git a/python/enum.c b/python/enum.c new file mode 100644 index 0000000..b57a880 --- /dev/null +++ b/python/enum.c @@ -0,0 +1,259 @@ +/*------------------------------------------------------------------------ + * Copyright 2009-2010 (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" + +static char enumitem_doc[] = + PyDoc_STR("simple enumeration item.\n" + "\n" + "associates an int value with a name for printing."); + +static zbarEnumItem *enumitem_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + int val = 0; + PyObject *name = NULL; + static char *kwlist[] = { "value", "name", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "iS", kwlist, &val, &name)) + return (NULL); + + zbarEnumItem *self = (zbarEnumItem *)type->tp_alloc(type, 0); + if (!self) + return (NULL); + +#if PY_MAJOR_VERSION >= 3 + PyLongObject *longval = (PyLongObject *)PyLong_FromLong(val); + if (!longval) { + Py_DECREF(self); + return (NULL); + } + + /* we assume the "fast path" for a single-digit ints (see longobject.c) */ + /* this also holds if we get a small_int preallocated long */ +#if PY_VERSION_HEX >= 0x030900A4 + Py_SET_SIZE(&self->val, Py_SIZE(longval)); +#else + Py_SIZE(&self->val) = Py_SIZE(longval); +#endif +#if PY_VERSION_HEX >= 0x030c0000 + self->val.long_value.ob_digit[0] = longval->long_value.ob_digit[0]; +#else + self->val.ob_digit[0] = longval->ob_digit[0]; +#endif + Py_DECREF(longval); +#else + self->val.ob_ival = val; +#endif + self->name = name; + return (self); +} + +static void enumitem_dealloc(zbarEnumItem *self) +{ + Py_CLEAR(self->name); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static PyObject *enumitem_str(zbarEnumItem *self) +{ + Py_INCREF(self->name); + return (self->name); +} + +#if PY_MAJOR_VERSION < 3 +/* tp_print was dropped on Python 3.9 */ +static int enumitem_print(zbarEnumItem *self, FILE *fp, int flags) +{ + return (self->name->ob_type->tp_print(self->name, fp, flags)); +} +#endif + +static PyObject *enumitem_repr(zbarEnumItem *self) +{ + PyObject *name = PyObject_Repr(self->name); + if (!name) + return (NULL); +#if PY_MAJOR_VERSION >= 3 + PyObject *repr = PyUnicode_FromFormat("%s(%ld, %U)", + ((PyObject *)self)->ob_type->tp_name, + PyLong_AsLong((PyObject *)self), + name); +#else + char *namestr = PyString_AsString(name); + PyObject *repr = PyString_FromFormat("%s(%ld, %s)", + ((PyObject *)self)->ob_type->tp_name, + self->val.ob_ival, namestr); +#endif + Py_DECREF(name); + return ((PyObject *)repr); +} + +PyTypeObject zbarEnumItem_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.EnumItem", + .tp_doc = enumitem_doc, + .tp_basicsize = sizeof(zbarEnumItem), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = (newfunc)enumitem_new, + .tp_dealloc = (destructor)enumitem_dealloc, + .tp_str = (reprfunc)enumitem_str, +#if PY_MAJOR_VERSION < 3 + .tp_print = (printfunc)enumitem_print, +#endif + .tp_repr = (reprfunc)enumitem_repr, +}; + +zbarEnumItem *zbarEnumItem_New(PyObject *byname, PyObject *byvalue, int val, + const char *name) +{ + zbarEnumItem *self = PyObject_New(zbarEnumItem, &zbarEnumItem_Type); + if (!self) + return (NULL); +#if PY_MAJOR_VERSION >= 3 + PyLongObject *longval = (PyLongObject *)PyLong_FromLong(val); + if (!longval) { + Py_DECREF(self); + return (NULL); + } + + /* we assume the "fast path" for a single-digit ints (see longobject.c) */ + /* this also holds if we get a small_int preallocated long */ +#if PY_VERSION_HEX >= 0x030900A4 + Py_SET_SIZE(&self->val, Py_SIZE(longval)); +#else + Py_SIZE(&self->val) = Py_SIZE(longval); +#endif +#if PY_VERSION_HEX >= 0x030c0000 + self->val.long_value.ob_digit[0] = longval->long_value.ob_digit[0]; +#else + self->val.ob_digit[0] = longval->ob_digit[0]; +#endif + Py_DECREF(longval); + + self->name = PyUnicode_FromString(name); +#else + self->val.ob_ival = val; + self->name = PyString_FromString(name); +#endif + if (!self->name || + (byname && PyDict_SetItem(byname, self->name, (PyObject *)self)) || + (byvalue && + PyDict_SetItem(byvalue, (PyObject *)self, (PyObject *)self))) { + Py_DECREF((PyObject *)self); + return (NULL); + } + return (self); +} + +static char enum_doc[] = PyDoc_STR("enumeration container for EnumItems.\n" + "\n" + "exposes items as read-only attributes"); + +/* FIXME add iteration */ + +static int enum_traverse(zbarEnum *self, visitproc visit, void *arg) +{ + Py_VISIT(self->byname); + Py_VISIT(self->byvalue); + return (0); +} + +static int enum_clear(zbarEnum *self) +{ + Py_CLEAR(self->byname); + Py_CLEAR(self->byvalue); + return (0); +} + +static void enum_dealloc(zbarEnum *self) +{ + enum_clear(self); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +PyTypeObject zbarEnum_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Enum", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = enum_doc, + .tp_basicsize = sizeof(zbarEnum), + .tp_dictoffset = offsetof(zbarEnum, byname), + .tp_traverse = (traverseproc)enum_traverse, + .tp_clear = (inquiry)enum_clear, + .tp_dealloc = (destructor)enum_dealloc, +}; + +zbarEnum *zbarEnum_New() +{ + zbarEnum *self = PyObject_GC_New(zbarEnum, &zbarEnum_Type); + if (!self) + return (NULL); + self->byname = PyDict_New(); + self->byvalue = PyDict_New(); + if (!self->byname || !self->byvalue) { + Py_DECREF(self); + return (NULL); + } + return (self); +} + +int zbarEnum_Add(zbarEnum *self, int val, const char *name) +{ + zbarEnumItem *item; + item = zbarEnumItem_New(self->byname, self->byvalue, val, name); + if (!item) + return (-1); + return (0); +} + +zbarEnumItem *zbarEnum_LookupValue(zbarEnum *self, int val) +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *key = PyLong_FromLong(val); +#else + PyObject *key = PyInt_FromLong(val); +#endif + zbarEnumItem *e = (zbarEnumItem *)PyDict_GetItem(self->byvalue, key); + if (!e) + return ((zbarEnumItem *)key); + Py_INCREF((PyObject *)e); + Py_DECREF(key); + return (e); +} + +PyObject *zbarEnum_SetFromMask(zbarEnum *self, unsigned int mask) +{ + PyObject *result = PySet_New(NULL); + PyObject *key, *item; + Py_ssize_t i = 0; + while (PyDict_Next(self->byvalue, &i, &key, &item)) { +#if PY_MAJOR_VERSION >= 3 + unsigned long val = (unsigned long)PyLong_AsLong(item); +#else + int val = PyInt_AsLong(item); +#endif + if (val < sizeof(mask) * 8 && ((mask >> val) & 1)) + PySet_Add(result, item); + } + return (result); +} diff --git a/python/examples/processor.py b/python/examples/processor.py new file mode 100644 index 0000000..b8f20f0 --- /dev/null +++ b/python/examples/processor.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +from sys import argv +import zbar + +# create a Processor +proc = zbar.Processor() + +# configure the Processor +proc.parse_config('enable') + +# initialize the Processor +device = '/dev/video0' +if len(argv) > 1: + device = argv[1] +proc.init(device) + +# setup a callback +def my_handler(proc, image, closure): + # extract results + for symbol in image.symbols: + # do something useful with results + print('decoded', symbol.type, 'symbol', '"%s"' % symbol.data) + +proc.set_data_handler(my_handler) + +# enable the preview window +proc.visible = True + +# initiate scanning +proc.active = True +try: + # keep scanning until user provides key/mouse input + proc.user_wait() +except zbar.WindowClosed as e: + pass diff --git a/python/examples/read_one.py b/python/examples/read_one.py new file mode 100644 index 0000000..7a18c99 --- /dev/null +++ b/python/examples/read_one.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +from sys import argv +import zbar + +# create a Processor +proc = zbar.Processor() + +# configure the Processor +proc.parse_config('enable') + +# initialize the Processor +device = '/dev/video0' +if len(argv) > 1: + device = argv[1] +proc.init(device) + +# enable the preview window +proc.visible = True + +# read at least one barcode (or until window closed) +proc.process_one() + +# hide the preview window +proc.visible = False + +# extract results +for symbol in proc.results: + # do something useful with results + print('decoded', symbol.type, 'symbol', '"%s"' % symbol.data) diff --git a/python/examples/scan_image.py b/python/examples/scan_image.py new file mode 100644 index 0000000..e26cb42 --- /dev/null +++ b/python/examples/scan_image.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +from sys import argv +import zbar +from PIL import Image + +if len(argv) < 2: exit(1) + +# create a reader +scanner = zbar.ImageScanner() + +# configure the reader +scanner.parse_config('enable') + +# obtain image data +pil = Image.open(argv[1]).convert('L') +width, height = pil.size +raw = pil.tobytes() + +# wrap image data +image = zbar.Image(width, height, 'Y800', raw) + +# scan the image for barcodes +scanner.scan(image) + +# extract results +for symbol in image: + # do something useful with results + print('decoded', symbol.type, 'symbol', '"%s"' % symbol.data) + +# clean up +del(image) diff --git a/python/exception.c b/python/exception.c new file mode 100644 index 0000000..2edc722 --- /dev/null +++ b/python/exception.c @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------ + * 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" + +#if PY_MAJOR_VERSION < 3 + +static inline PyObject *exc_get_message(zbarException *self, void *closure) +{ + PyBaseExceptionObject *super = (PyBaseExceptionObject *)self; + if (!PyString_Size(super->message)) { + Py_CLEAR(super->message); + if (!self->obj || !zbarProcessor_Check(self->obj)) + super->message = PyString_FromString("unknown zbar error"); + else { + const void *zobj = ((zbarProcessor *)self->obj)->zproc; + super->message = PyString_FromString(_zbar_error_string(zobj, 1)); + } + } + Py_INCREF(super->message); + return (super->message); +} + +static int exc_init(zbarException *self, PyObject *args, PyObject *kwds) +{ + if (!_PyArg_NoKeywords(self->base.ob_type->tp_name, kwds)) + return (-1); + PyBaseExceptionObject *super = (PyBaseExceptionObject *)self; + Py_CLEAR(super->args); + Py_INCREF(args); + super->args = args; + + if (PyTuple_GET_SIZE(args) == 1) { + Py_CLEAR(self->obj); + self->obj = PyTuple_GET_ITEM(args, 0); + Py_INCREF(self->obj); + } + return (0); +} + +static int exc_traverse(zbarException *self, visitproc visit, void *arg) +{ + Py_VISIT(self->obj); + PyTypeObject *base = (PyTypeObject *)PyExc_Exception; + return (base->tp_traverse((PyObject *)self, visit, arg)); +} + +static int exc_clear(zbarException *self) +{ + Py_CLEAR(self->obj); + ((PyTypeObject *)PyExc_Exception)->tp_clear((PyObject *)self); + return (0); +} + +static void exc_dealloc(zbarException *self) +{ + exc_clear(self); + ((PyTypeObject *)PyExc_Exception)->tp_dealloc((PyObject *)self); +} + +static PyObject *exc_str(zbarException *self) +{ + return (exc_get_message(self, NULL)); +} + +static int exc_set_message(zbarException *self, PyObject *value, void *closure) +{ + PyBaseExceptionObject *super = (PyBaseExceptionObject *)self; + Py_CLEAR(super->message); + if (!value) + value = PyString_FromString(""); + else + Py_INCREF(value); + super->message = value; + return (0); +} + +static PyGetSetDef exc_getset[] = { + { + "message", + (getter)exc_get_message, + (setter)exc_set_message, + }, + { + NULL, + }, +}; + +PyTypeObject zbarException_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Exception", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_basicsize = sizeof(zbarException), + .tp_init = (initproc)exc_init, + .tp_traverse = (traverseproc)exc_traverse, + .tp_clear = (inquiry)exc_clear, + .tp_dealloc = (destructor)exc_dealloc, + .tp_str = (reprfunc)exc_str, + .tp_getset = exc_getset, +}; + +#endif diff --git a/python/image.c b/python/image.c new file mode 100644 index 0000000..b3ff5cd --- /dev/null +++ b/python/image.c @@ -0,0 +1,482 @@ +/*------------------------------------------------------------------------ + * Copyright 2009-2010 (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 image_doc[] = PyDoc_STR( + "image object.\n" + "\n" + "stores image data samples along with associated format and size metadata."); + +static zbarImage *image_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + zbarImage *self = (zbarImage *)type->tp_alloc(type, 0); + if (!self) + return (NULL); + + self->zimg = zbar_image_create(); + if (!self->zimg) { + Py_DECREF(self); + return (NULL); + } + zbar_image_set_userdata(self->zimg, self); + return (self); +} + +static int image_traverse(zbarImage *self, visitproc visit, void *arg) +{ + Py_VISIT(self->data); + return (0); +} + +static int image_clear(zbarImage *self) +{ + zbar_image_t *zimg = self->zimg; + self->zimg = NULL; + if (zimg) { + assert(zbar_image_get_userdata(zimg) == self); + if (self->data) { + /* attach data directly to zbar image */ + zbar_image_set_userdata(zimg, self->data); + self->data = NULL; + } else + zbar_image_set_userdata(zimg, NULL); + zbar_image_destroy(zimg); + } + return (0); +} + +static void image_dealloc(zbarImage *self) +{ + image_clear(self); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static zbarSymbolSet *image_get_symbols(zbarImage *self, void *closure) +{ + const zbar_symbol_set_t *zsyms = zbar_image_get_symbols(self->zimg); + return (zbarSymbolSet_FromSymbolSet(zsyms)); +} + +static int image_set_symbols(zbarImage *self, PyObject *value, void *closure) +{ + const zbar_symbol_set_t *zsyms; + if (!value || value == Py_None) + zsyms = NULL; + else if (zbarSymbolSet_Check(value)) + zsyms = ((zbarSymbolSet *)value)->zsyms; + else { + PyErr_Format(PyExc_TypeError, + "must set image symbols to a zbar.SymbolSet, not '%.50s'", + value->ob_type->tp_name); + return (-1); + } + + zbar_image_set_symbols(self->zimg, zsyms); + return (0); +} + +static zbarSymbolIter *image_iter(zbarImage *self) +{ + zbarSymbolSet *syms = image_get_symbols(self, NULL); + if (!syms) + return (NULL); + return (zbarSymbolIter_FromSymbolSet(syms)); +} + +static PyObject *image_get_format(zbarImage *self, void *closure) +{ + unsigned long format = zbar_image_get_format(self->zimg); +#if PY_MAJOR_VERSION >= 3 + return (PyBytes_FromStringAndSize((char *)&format, 4)); +#else + return (PyString_FromStringAndSize((char *)&format, 4)); +#endif +} + +static int image_set_format(zbarImage *self, PyObject *value, void *closure) +{ + if (!value) { + PyErr_SetString(PyExc_TypeError, "cannot delete format attribute"); + return (-1); + } + char *format = NULL; + Py_ssize_t len; +#if PY_MAJOR_VERSION >= 3 + PyObject *bytes; + + if (PyUnicode_Check(value)) + bytes = PyUnicode_AsEncodedString(value, "utf-8", "surrogateescape"); + else + bytes = value; + if (PyBytes_AsStringAndSize(bytes, &format, &len) < 0 || !format || + len != 4) { +#else + if (PyString_AsStringAndSize(value, &format, &len) || !format || len != 4) { +#endif + if (!format) + format = "(nil)"; + PyErr_Format(PyExc_ValueError, + "format '%.50s' is not a valid four character code", + format); + return (-1); + } + zbar_image_set_format(self->zimg, zbar_fourcc_parse(format)); + return (0); +} + +static PyObject *image_get_size(zbarImage *self, void *closure) +{ + unsigned int w, h; + zbar_image_get_size(self->zimg, &w, &h); +#if PY_MAJOR_VERSION >= 3 + return (PyTuple_Pack(2, PyLong_FromLong(w), PyLong_FromLong(h))); +#else + return (PyTuple_Pack(2, PyInt_FromLong(w), PyInt_FromLong(h))); +#endif +} + +static int image_set_size(zbarImage *self, PyObject *value, void *closure) +{ + if (!value) { + PyErr_SetString(PyExc_TypeError, "cannot delete size attribute"); + return (-1); + } + + int dims[2]; + if (parse_dimensions(value, dims, 2) || dims[0] < 0 || dims[1] < 0) { + PyErr_SetString(PyExc_ValueError, + "size must be a sequence of two positive ints"); + return (-1); + } + + zbar_image_set_size(self->zimg, dims[0], dims[1]); + return (0); +} + +static PyObject *image_get_crop(zbarImage *self, void *closure) +{ + unsigned int x, y, w, h; + zbar_image_get_crop(self->zimg, &x, &y, &w, &h); +#if PY_MAJOR_VERSION >= 3 + return (PyTuple_Pack(4, PyLong_FromLong(x), PyLong_FromLong(y), + PyLong_FromLong(w), PyLong_FromLong(h))); +#else + return (PyTuple_Pack(4, PyInt_FromLong(x), PyInt_FromLong(y), + PyInt_FromLong(w), PyInt_FromLong(h))); +#endif +} + +static int image_set_crop(zbarImage *self, PyObject *value, void *closure) +{ + unsigned w, h; + zbar_image_get_size(self->zimg, &w, &h); + if (!value) { + zbar_image_set_crop(self->zimg, 0, 0, w, h); + return (0); + } + + int dims[4]; + if (parse_dimensions(value, dims, 4) || dims[2] < 0 || dims[3] < 0) { + PyErr_SetString(PyExc_ValueError, + "crop must be a sequence of four positive ints"); + return (-1); + } + + if (dims[0] < 0) { + dims[2] += dims[0]; + dims[0] = 0; + } + if (dims[1] < 0) { + dims[3] += dims[1]; + dims[1] = 0; + } + + zbar_image_set_crop(self->zimg, dims[0], dims[1], dims[2], dims[3]); + return (0); +} + +static PyObject *image_get_int(zbarImage *self, void *closure) +{ + unsigned int val = -1; + switch ((intptr_t)closure) { + case 0: + val = zbar_image_get_width(self->zimg); + break; + case 1: + val = zbar_image_get_height(self->zimg); + break; + case 2: + val = zbar_image_get_sequence(self->zimg); + break; + default: + assert(0); + } +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(val)); +#else + return (PyInt_FromLong(val)); +#endif +} + +static int image_set_int(zbarImage *self, PyObject *value, void *closure) +{ + unsigned int tmp; +#if PY_MAJOR_VERSION >= 3 + long val = PyLong_AsLong(value); +#else + unsigned int val = PyInt_AsSsize_t(value); +#endif + if (val == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "expecting an integer"); + return (-1); + } + switch ((intptr_t)closure) { + case 0: + tmp = zbar_image_get_height(self->zimg); + zbar_image_set_size(self->zimg, val, tmp); + break; + case 1: + tmp = zbar_image_get_width(self->zimg); + zbar_image_set_size(self->zimg, tmp, val); + break; + case 2: + zbar_image_set_sequence(self->zimg, val); + default: + assert(0); + } + return (0); +} + +static PyObject *image_get_data(zbarImage *self, void *closure) +{ + assert(zbar_image_get_userdata(self->zimg) == self); + if (self->data) { + Py_INCREF(self->data); + return (self->data); + } + + const char *data = zbar_image_get_data(self->zimg); + unsigned long datalen = zbar_image_get_data_length(self->zimg); + if (!data || !datalen) { + Py_INCREF(Py_None); + return (Py_None); + } + +#if PY_MAJOR_VERSION >= 3 + self->data = PyMemoryView_FromMemory((void *)data, datalen, PyBUF_READ); +#else + self->data = PyBuffer_FromMemory((void *)data, datalen); +#endif + Py_INCREF(self->data); + return (self->data); +} + +void image_cleanup(zbar_image_t *zimg) +{ + PyObject *data = zbar_image_get_userdata(zimg); + zbar_image_set_userdata(zimg, NULL); + if (!data) + return; /* FIXME internal error */ + if (PyObject_TypeCheck(data, &zbarImage_Type)) { + zbarImage *self = (zbarImage *)data; + assert(self->zimg == zimg); + Py_CLEAR(self->data); + } else + Py_DECREF(data); +} + +static int image_set_data(zbarImage *self, PyObject *value, void *closure) +{ + if (!value) { + zbar_image_free_data(self->zimg); + return (0); + } + char *data; + Py_ssize_t datalen; +#if PY_MAJOR_VERSION >= 3 + PyObject *bytes; + + if (PyUnicode_Check(value)) + bytes = PyUnicode_AsEncodedString(value, "utf-8", "surrogateescape"); + else + bytes = value; + if (PyBytes_AsStringAndSize(bytes, &data, &datalen)) + return (-1); +#else + if (PyString_AsStringAndSize(value, &data, &datalen)) + return (-1); +#endif + + Py_INCREF(value); + zbar_image_set_data(self->zimg, data, datalen, image_cleanup); + assert(!self->data); + self->data = value; + zbar_image_set_userdata(self->zimg, self); + return (0); +} + +static PyGetSetDef image_getset[] = { + { + "format", + (getter)image_get_format, + (setter)image_set_format, + }, + { + "size", + (getter)image_get_size, + (setter)image_set_size, + }, + { + "crop", + (getter)image_get_crop, + (setter)image_set_crop, + }, + { "width", (getter)image_get_int, (setter)image_set_int, NULL, (void *)0 }, + { "height", (getter)image_get_int, (setter)image_set_int, NULL, (void *)1 }, + { "sequence", (getter)image_get_int, (setter)image_set_int, NULL, + (void *)2 }, + { + "data", + (getter)image_get_data, + (setter)image_set_data, + }, + { + "symbols", + (getter)image_get_symbols, + (setter)image_set_symbols, + }, + { + NULL, + }, +}; + +static int image_init(zbarImage *self, PyObject *args, PyObject *kwds) +{ + int width = -1, height = -1; + PyObject *format = NULL, *data = NULL; + static char *kwlist[] = { "width", "height", "format", "data", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiOO", kwlist, &width, + &height, &format, &data)) + return (-1); + + if (width > 0 && height > 0) + zbar_image_set_size(self->zimg, width, height); + if (format && image_set_format(self, format, NULL)) + return (-1); + if (data && image_set_data(self, data, NULL)) + return (-1); + return (0); +} + +static zbarImage *image_convert(zbarImage *self, PyObject *args, PyObject *kwds) +{ + const char *format = NULL; + int width = -1, height = -1; + static char *kwlist[] = { "format", "width", "height", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|ii", kwlist, &format, + &width, &height)) + return (NULL); + assert(format); + + if (strlen(format) != 4) { + PyErr_Format(PyExc_ValueError, + "format '%.50s' is not a valid four character code", + format); + return (NULL); + } + unsigned long fourcc = zbar_fourcc_parse(format); + + zbarImage *img = PyObject_GC_New(zbarImage, &zbarImage_Type); + if (!img) + return (NULL); + img->data = NULL; + if (width > 0 && height > 0) + img->zimg = + zbar_image_convert_resize(self->zimg, fourcc, width, height); + else + img->zimg = zbar_image_convert(self->zimg, fourcc); + + if (!img->zimg) { + /* FIXME propagate exception */ + Py_DECREF(img); + return (NULL); + } + zbar_image_set_userdata(img->zimg, img); + + return (img); +} + +static PyMethodDef image_methods[] = { + { + "convert", + (PyCFunction)image_convert, + METH_VARARGS | METH_KEYWORDS, + }, + { + NULL, + }, +}; + +PyTypeObject zbarImage_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Image", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = image_doc, + .tp_basicsize = sizeof(zbarImage), + .tp_new = (newfunc)image_new, + .tp_init = (initproc)image_init, + .tp_traverse = (traverseproc)image_traverse, + .tp_clear = (inquiry)image_clear, + .tp_dealloc = (destructor)image_dealloc, + .tp_getset = image_getset, + .tp_methods = image_methods, + .tp_iter = (getiterfunc)image_iter, +}; + +zbarImage *zbarImage_FromImage(zbar_image_t *zimg) +{ + zbarImage *self = PyObject_GC_New(zbarImage, &zbarImage_Type); + if (!self) + return (NULL); + zbar_image_ref(zimg, 1); + zbar_image_set_userdata(zimg, self); + self->zimg = zimg; + self->data = NULL; + return (self); +} + +int zbarImage_validate(zbarImage *img) +{ + if (!zbar_image_get_width(img->zimg) || !zbar_image_get_height(img->zimg) || + !zbar_image_get_data(img->zimg) || + !zbar_image_get_data_length(img->zimg)) { + PyErr_Format(PyExc_ValueError, "image size and data must be defined"); + return (-1); + } + return (0); +} diff --git a/python/imagescanner.c b/python/imagescanner.c new file mode 100644 index 0000000..54966b7 --- /dev/null +++ b/python/imagescanner.c @@ -0,0 +1,195 @@ +/*------------------------------------------------------------------------ + * 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" + +static char imagescanner_doc[] = + PyDoc_STR("scan images for barcodes.\n" + "\n" + "attaches symbols to image for each decoded result."); + +static zbarImageScanner *imagescanner_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return (NULL); + + zbarImageScanner *self = (zbarImageScanner *)type->tp_alloc(type, 0); + if (!self) + return (NULL); + + self->zscn = zbar_image_scanner_create(); + if (!self->zscn) { + Py_DECREF(self); + return (NULL); + } + + return (self); +} + +static void imagescanner_dealloc(zbarImageScanner *self) +{ + zbar_image_scanner_destroy(self->zscn); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static zbarSymbolSet *imagescanner_get_results(zbarImageScanner *self, + void *closure) +{ + const zbar_symbol_set_t *zsyms = zbar_image_scanner_get_results(self->zscn); + return (zbarSymbolSet_FromSymbolSet(zsyms)); +} + +static PyGetSetDef imagescanner_getset[] = { + { "results", (getter)imagescanner_get_results, NULL, NULL, NULL }, + { NULL } /* Sentinel */ +}; + +static PyObject *imagescanner_set_config(zbarImageScanner *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_image_scanner_set_config(self->zscn, sym, cfg, val)) { + PyErr_SetString(PyExc_ValueError, "invalid configuration setting"); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject *imagescanner_parse_config(zbarImageScanner *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_image_scanner_parse_config(self->zscn, cfg)) { + PyErr_Format(PyExc_ValueError, "invalid configuration setting: %s", + cfg); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject *imagescanner_enable_cache(zbarImageScanner *self, + PyObject *args, PyObject *kwds) +{ + unsigned char enable = 1; + static char *kwlist[] = { "enable", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, object_to_bool, + &enable)) + return (NULL); + + zbar_image_scanner_enable_cache(self->zscn, enable); + Py_RETURN_NONE; +} + +static PyObject *imagescanner_recycle(zbarImageScanner *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); + + zbar_image_scanner_recycle_image(self->zscn, img->zimg); + Py_RETURN_NONE; +} + +static PyObject *imagescanner_scan(zbarImageScanner *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 = zbar_scan_image(self->zscn, img->zimg); + if (n < 0) { + PyErr_Format(PyExc_ValueError, "unsupported image format"); + return (NULL); + } +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(n)); +#else + return (PyInt_FromLong(n)); +#endif +} + +static PyMethodDef imagescanner_methods[] = { + { + "set_config", + (PyCFunction)imagescanner_set_config, + METH_VARARGS | METH_KEYWORDS, + }, + { + "parse_config", + (PyCFunction)imagescanner_parse_config, + METH_VARARGS | METH_KEYWORDS, + }, + { + "enable_cache", + (PyCFunction)imagescanner_enable_cache, + METH_VARARGS | METH_KEYWORDS, + }, + { + "recycle", + (PyCFunction)imagescanner_recycle, + METH_VARARGS | METH_KEYWORDS, + }, + { + "scan", + (PyCFunction)imagescanner_scan, + METH_VARARGS | METH_KEYWORDS, + }, + { + NULL, + }, +}; + +PyTypeObject zbarImageScanner_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.ImageScanner", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = imagescanner_doc, + .tp_basicsize = sizeof(zbarImageScanner), + .tp_new = (newfunc)imagescanner_new, + .tp_dealloc = (destructor)imagescanner_dealloc, + .tp_getset = imagescanner_getset, + .tp_methods = imagescanner_methods, +}; 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, +}; diff --git a/python/scanner.c b/python/scanner.c new file mode 100644 index 0000000..e5ad8bf --- /dev/null +++ b/python/scanner.c @@ -0,0 +1,193 @@ +/*------------------------------------------------------------------------ + * 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" + +static char scanner_doc[] = PyDoc_STR( + "low level intensity sample stream scanner. identifies \"bar\" edges" + "and measures width between them.\n" + "\n" + "FIXME."); + +static zbarScanner *scanner_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + zbarDecoder *decoder = NULL; + static char *kwlist[] = { "decoder", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", kwlist, &decoder, + zbarDecoder_Type)) + return (NULL); + + zbarScanner *self = (zbarScanner *)type->tp_alloc(type, 0); + if (!self) + return (NULL); + + zbar_decoder_t *zdcode = NULL; + if (decoder) { + Py_INCREF(decoder); + self->decoder = decoder; + zdcode = decoder->zdcode; + } + self->zscn = zbar_scanner_create(zdcode); + if (!self->zscn) { + Py_DECREF(self); + return (NULL); + } + + return (self); +} + +static int scanner_traverse(zbarScanner *self, visitproc visit, void *arg) +{ + Py_VISIT(self->decoder); + return (0); +} + +static int scanner_clear(zbarScanner *self) +{ + Py_CLEAR(self->decoder); + return (0); +} + +static void scanner_dealloc(zbarScanner *self) +{ + scanner_clear(self); + zbar_scanner_destroy(self->zscn); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static PyObject *scanner_get_width(zbarScanner *self, void *closure) +{ + unsigned int width = zbar_scanner_get_width(self->zscn); +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(width)); +#else + return (PyInt_FromLong(width)); +#endif +} + +static zbarEnumItem *scanner_get_color(zbarScanner *self, void *closure) +{ + zbar_color_t zcol = zbar_scanner_get_color(self->zscn); + assert(zcol == ZBAR_BAR || zcol == ZBAR_SPACE); + struct module_state *st = GETMODSTATE(); + zbarEnumItem *color = st->color_enum[zcol]; + Py_INCREF((PyObject *)color); + return (color); +} + +static PyGetSetDef scanner_getset[] = { + { + "color", + (getter)scanner_get_color, + }, + { + "width", + (getter)scanner_get_width, + }, + { + NULL, + }, +}; + +static PyObject *scanner_reset(zbarScanner *self, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return (NULL); + + zbar_scanner_reset(self->zscn); + Py_RETURN_NONE; +} + +static PyObject *scanner_new_scan(zbarScanner *self, PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return (NULL); + + zbar_scanner_new_scan(self->zscn); + Py_RETURN_NONE; +} + +static zbarEnumItem *scanner_scan_y(zbarScanner *self, PyObject *args, + PyObject *kwds) +{ + /* FIXME should accept sequence of values */ + int y = 0; + static char *kwlist[] = { "y", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &y)) + return (NULL); + + zbar_symbol_type_t sym = zbar_scan_y(self->zscn, y); + if (PyErr_Occurred()) + /* propagate errors during callback */ + return (NULL); + if (sym == ZBAR_NONE) { + /* hardcode most common case */ + struct module_state *st = GETMODSTATE(); + Py_INCREF((PyObject *)st->symbol_NONE); + return (st->symbol_NONE); + } + return (zbarSymbol_LookupEnum(sym)); +} + +static PyMethodDef scanner_methods[] = { + { + "reset", + (PyCFunction)scanner_reset, + METH_VARARGS | METH_KEYWORDS, + }, + { + "new_scan", + (PyCFunction)scanner_new_scan, + METH_VARARGS | METH_KEYWORDS, + }, + { + "scan_y", + (PyCFunction)scanner_scan_y, + METH_VARARGS | METH_KEYWORDS, + }, + { + NULL, + }, +}; + +PyTypeObject zbarScanner_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Scanner", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = scanner_doc, + .tp_basicsize = sizeof(zbarScanner), + .tp_new = (newfunc)scanner_new, + .tp_traverse = (traverseproc)scanner_traverse, + .tp_clear = (inquiry)scanner_clear, + .tp_dealloc = (destructor)scanner_dealloc, + .tp_getset = scanner_getset, + .tp_methods = scanner_methods, +}; diff --git a/python/setup.py b/python/setup.py new file mode 100644 index 0000000..5c27951 --- /dev/null +++ b/python/setup.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +from distutils.core import setup, Extension + +setup( + name = 'zbar', + version = '0.22.2', + author = 'Jeff Brown', + author_email = 'spadix@users.sourceforge.net', + url = 'http://zbar.sourceforge.net', + description = 'read barcodes from images or video', + license = 'LGPL', + long_description = open('README').read(), + classifiers = [ + 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Environment :: Console', + 'Environment :: X11 Applications', + 'Environment :: Win32 (MS Windows)', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Operating System :: Microsoft :: Windows', + 'Topic :: Communications', + 'Topic :: Multimedia :: Graphics', + 'Topic :: Software Development :: Libraries', + ], + ext_modules = [ + Extension('zbar', [ + 'zbarmodule.c', + 'enum.c', + 'exception.c', + 'symbol.c', + 'symbolset.c', + 'symboliter.c', + 'image.c', + 'processor.c', + 'imagescanner.c', + 'decoder.c', + 'scanner.c', + ], + libraries = [ 'zbar' ], + include_dirs = ['../include'] + ), + ], +) diff --git a/python/symbol.c b/python/symbol.c new file mode 100644 index 0000000..cc7cb83 --- /dev/null +++ b/python/symbol.c @@ -0,0 +1,230 @@ +/*------------------------------------------------------------------------ + * Copyright 2009-2010 (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" + +static char symbol_doc[] = + PyDoc_STR("symbol result object.\n" + "\n" + "data and associated information about a successful decode."); + +static int symbol_traverse(zbarSymbol *self, visitproc visit, void *arg) +{ + return (0); +} + +static int symbol_clear(zbarSymbol *self) +{ + if (self->zsym) { + zbar_symbol_t *zsym = (zbar_symbol_t *)self->zsym; + self->zsym = NULL; + zbar_symbol_ref(zsym, -1); + } + Py_CLEAR(self->data); + Py_CLEAR(self->loc); + return (0); +} + +static void symbol_dealloc(zbarSymbol *self) +{ + symbol_clear(self); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static zbarSymbolSet *symbol_get_components(zbarSymbol *self, void *closure) +{ + const zbar_symbol_set_t *zsyms = zbar_symbol_get_components(self->zsym); + return (zbarSymbolSet_FromSymbolSet(zsyms)); +} + +static zbarSymbolIter *symbol_iter(zbarSymbol *self) +{ + zbarSymbolSet *syms = symbol_get_components(self, NULL); + zbarSymbolIter *iter = zbarSymbolIter_FromSymbolSet(syms); + Py_XDECREF(syms); + return (iter); +} + +static zbarEnumItem *symbol_get_type(zbarSymbol *self, void *closure) +{ + return (zbarSymbol_LookupEnum(zbar_symbol_get_type(self->zsym))); +} + +static PyObject *symbol_get_configs(zbarSymbol *self, void *closure) +{ + unsigned int mask = zbar_symbol_get_configs(self->zsym); + struct module_state *st = GETMODSTATE(); + return (zbarEnum_SetFromMask(st->config_enum, mask)); +} + +static PyObject *symbol_get_modifiers(zbarSymbol *self, void *closure) +{ + unsigned int mask = zbar_symbol_get_modifiers(self->zsym); + struct module_state *st = GETMODSTATE(); + return (zbarEnum_SetFromMask(st->modifier_enum, mask)); +} + +static PyObject *symbol_get_long(zbarSymbol *self, void *closure) +{ + int val; + if (!closure) + val = zbar_symbol_get_quality(self->zsym); + else + val = zbar_symbol_get_count(self->zsym); +#if PY_MAJOR_VERSION >= 3 + return (PyLong_FromLong(val)); +#else + return (PyInt_FromLong(val)); +#endif +} + +static PyObject *symbol_get_data(zbarSymbol *self, void *closure) +{ + if (!self->data) { +#if PY_MAJOR_VERSION >= 3 + self->data = PyUnicode_FromStringAndSize( + zbar_symbol_get_data(self->zsym), + zbar_symbol_get_data_length(self->zsym)); +#else + /* FIXME this could be a buffer now */ + self->data = + PyString_FromStringAndSize(zbar_symbol_get_data(self->zsym), + zbar_symbol_get_data_length(self->zsym)); +#endif + if (!self->data) + return (NULL); + } + Py_INCREF(self->data); + return (self->data); +} + +static PyObject *symbol_get_location(zbarSymbol *self, void *closure) +{ + if (!self->loc) { + /* build tuple of 2-tuples representing location polygon */ + unsigned int n = zbar_symbol_get_loc_size(self->zsym); + self->loc = PyTuple_New(n); + unsigned int i; + for (i = 0; i < n; i++) { + PyObject *x, *y; +#if PY_MAJOR_VERSION >= 3 + x = PyLong_FromLong(zbar_symbol_get_loc_x(self->zsym, i)); + y = PyLong_FromLong(zbar_symbol_get_loc_y(self->zsym, i)); +#else + x = PyInt_FromLong(zbar_symbol_get_loc_x(self->zsym, i)); + y = PyInt_FromLong(zbar_symbol_get_loc_y(self->zsym, i)); +#endif + PyTuple_SET_ITEM(self->loc, i, PyTuple_Pack(2, x, y)); + } + } + Py_INCREF(self->loc); + return (self->loc); +} + +static zbarEnumItem *symbol_get_orientation(zbarSymbol *self, void *closure) +{ + struct module_state *st = GETMODSTATE(); + return (zbarEnum_LookupValue(st->orient_enum, + zbar_symbol_get_orientation(self->zsym))); +} + +static PyGetSetDef symbol_getset[] = { + { + "type", + (getter)symbol_get_type, + }, + { + "configs", + (getter)symbol_get_configs, + }, + { + "modifiers", + (getter)symbol_get_modifiers, + }, + { "quality", (getter)symbol_get_long, NULL, NULL, (void *)0 }, + { "count", (getter)symbol_get_long, NULL, NULL, (void *)1 }, + { + "data", + (getter)symbol_get_data, + }, + { + "location", + (getter)symbol_get_location, + }, + { + "orientation", + (getter)symbol_get_orientation, + }, + { + "components", + (getter)symbol_get_components, + }, + { + NULL, + }, +}; + +PyTypeObject zbarSymbol_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Symbol", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = symbol_doc, + .tp_basicsize = sizeof(zbarSymbol), + .tp_traverse = (traverseproc)symbol_traverse, + .tp_clear = (inquiry)symbol_clear, + .tp_dealloc = (destructor)symbol_dealloc, + .tp_iter = (getiterfunc)symbol_iter, + .tp_getset = symbol_getset, +}; + +zbarSymbol *zbarSymbol_FromSymbol(const zbar_symbol_t *zsym) +{ + /* FIXME symbol object recycle cache */ + zbarSymbol *self = PyObject_GC_New(zbarSymbol, &zbarSymbol_Type); + if (!self) + return (NULL); + assert(zsym); + zbar_symbol_t *zs = (zbar_symbol_t *)zsym; + zbar_symbol_ref(zs, 1); + self->zsym = zsym; + self->data = NULL; + self->loc = NULL; + return (self); +} + +zbarEnumItem *zbarSymbol_LookupEnum(zbar_symbol_type_t type) +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *key = PyLong_FromLong(type); +#else + PyObject *key = PyInt_FromLong(type); +#endif + struct module_state *st = GETMODSTATE(); + zbarEnumItem *e = (zbarEnumItem *)PyDict_GetItem(st->symbol_enum, key); + if (!e) + return ((zbarEnumItem *)key); + Py_INCREF((PyObject *)e); + Py_DECREF(key); + return (e); +} diff --git a/python/symboliter.c b/python/symboliter.c new file mode 100644 index 0000000..6ebd040 --- /dev/null +++ b/python/symboliter.c @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------ + * 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" + +static char symboliter_doc[] = + PyDoc_STR("symbol iterator.\n" + "\n" + "iterates over decode results attached to an image."); + +static int symboliter_traverse(zbarSymbolIter *self, visitproc visit, void *arg) +{ + Py_VISIT(self->syms); + return (0); +} + +static int symboliter_clear(zbarSymbolIter *self) +{ + if (self->zsym) { + zbar_symbol_t *zsym = (zbar_symbol_t *)self->zsym; + self->zsym = NULL; + zbar_symbol_ref(zsym, -1); + } + Py_CLEAR(self->syms); + return (0); +} + +static void symboliter_dealloc(zbarSymbolIter *self) +{ + symboliter_clear(self); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static zbarSymbolIter *symboliter_iter(zbarSymbolIter *self) +{ + Py_INCREF(self); + return (self); +} + +static zbarSymbol *symboliter_iternext(zbarSymbolIter *self) +{ + if (self->zsym) { + zbar_symbol_t *zsym = (zbar_symbol_t *)self->zsym; + zbar_symbol_ref(zsym, -1); + self->zsym = zbar_symbol_next(self->zsym); + } else if (self->syms->zsyms) + self->zsym = zbar_symbol_set_first_symbol(self->syms->zsyms); + else + self->zsym = NULL; + + zbar_symbol_t *zsym = (zbar_symbol_t *)self->zsym; + if (!zsym) + return (NULL); + zbar_symbol_ref(zsym, 1); + return (zbarSymbol_FromSymbol(self->zsym)); +} + +PyTypeObject zbarSymbolIter_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.SymbolIter", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + + .tp_doc = symboliter_doc, + .tp_basicsize = sizeof(zbarSymbolIter), + .tp_traverse = (traverseproc)symboliter_traverse, + .tp_clear = (inquiry)symboliter_clear, + .tp_dealloc = (destructor)symboliter_dealloc, + .tp_iter = (getiterfunc)symboliter_iter, + .tp_iternext = (iternextfunc)symboliter_iternext, +}; + +zbarSymbolIter *zbarSymbolIter_FromSymbolSet(zbarSymbolSet *syms) +{ + zbarSymbolIter *self; + self = PyObject_GC_New(zbarSymbolIter, &zbarSymbolIter_Type); + if (!self) + return (NULL); + + Py_INCREF(syms); + self->syms = syms; + self->zsym = NULL; + return (self); +} diff --git a/python/symbolset.c b/python/symbolset.c new file mode 100644 index 0000000..9d65e80 --- /dev/null +++ b/python/symbolset.c @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------ + * 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" + +static char symbolset_doc[] = PyDoc_STR("symbol result container.\n" + "\n" + "collection of symbols."); + +static int symbolset_clear(zbarSymbolSet *self) +{ + if (self->zsyms) { + zbar_symbol_set_t *zsyms = (zbar_symbol_set_t *)self->zsyms; + self->zsyms = NULL; + zbar_symbol_set_ref(zsyms, -1); + } + return (0); +} + +static void symbolset_dealloc(zbarSymbolSet *self) +{ + symbolset_clear(self); + ((PyObject *)self)->ob_type->tp_free((PyObject *)self); +} + +static zbarSymbolIter *symbolset_iter(zbarSymbolSet *self) +{ + return (zbarSymbolIter_FromSymbolSet(self)); +} + +Py_ssize_t symbolset_length(zbarSymbolSet *self) +{ + if (self->zsyms) + return (zbar_symbol_set_get_size(self->zsyms)); + return (0); +} + +static PySequenceMethods symbolset_as_sequence = { + .sq_length = (lenfunc)symbolset_length, +}; + +PyTypeObject zbarSymbolSet_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.SymbolSet", + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = symbolset_doc, + .tp_basicsize = sizeof(zbarSymbolSet), + .tp_dealloc = (destructor)symbolset_dealloc, + .tp_iter = (getiterfunc)symbolset_iter, + .tp_as_sequence = &symbolset_as_sequence, +}; + +zbarSymbolSet *zbarSymbolSet_FromSymbolSet(const zbar_symbol_set_t *zsyms) +{ + zbarSymbolSet *self = PyObject_New(zbarSymbolSet, &zbarSymbolSet_Type); + if (!self) + return (NULL); + if (zsyms) { + zbar_symbol_set_t *ncsyms = (zbar_symbol_set_t *)zsyms; + zbar_symbol_set_ref(ncsyms, 1); + } + self->zsyms = zsyms; + return (self); +} diff --git a/python/test/barcode.png b/python/test/barcode.png Binary files differnew file mode 100644 index 0000000..72846ce --- /dev/null +++ b/python/test/barcode.png diff --git a/python/test/test_zbar.py b/python/test/test_zbar.py new file mode 100755 index 0000000..5b63de4 --- /dev/null +++ b/python/test/test_zbar.py @@ -0,0 +1,506 @@ +#!/usr/bin/env python +import sys, os, re +import unittest as ut +import zbar + +# FIXME this needs to be conditional +# would be even better to auto-select PIL or ImageMagick (or...) +from PIL import Image + +data = None +size = (0, 0) + +def load_image(): + image = Image.open(os.path.join(sys.path[0], "barcode.png")).convert('L') + return(image.tobytes(), image.size) + +# FIXME this could be integrated w/fixture creation +(data, size) = load_image() + +encoded_widths = \ + '9 111 212241113121211311141132 11111 311213121312121332111132 111 9' + +databar_widths = \ + '11 31111333 13911 31131231 11214222 11553 21231313 1' + +VIDEO_DEVICE = None +if 'VIDEO_DEVICE' in os.environ: + VIDEO_DEVICE = os.environ['VIDEO_DEVICE'] + +is_identifier = re.compile(r'^[A-Z][A-Z_0-9]*$') + +class TestZBarFunctions(ut.TestCase): + def test_version(self): + ver = zbar.version() + self.assertTrue(isinstance(ver, tuple)) + self.assertEqual(len(ver), 2) + for v in ver: + self.assertTrue(isinstance(v, int)) + + def test_verbosity(self): + zbar.increase_verbosity() + zbar.set_verbosity(16) + + def test_exceptions(self): + self.assertTrue(isinstance(zbar.Exception, type)) + for err in (zbar.InternalError, + zbar.UnsupportedError, + zbar.InvalidRequestError, + zbar.SystemError, + zbar.LockingError, + zbar.BusyError, + zbar.X11DisplayError, + zbar.X11ProtocolError, + zbar.WindowClosed, + zbar.WinAPIError): + self.assertTrue(issubclass(err, zbar.Exception)) + + def test_configs(self): + for cfg in (zbar.Config.ENABLE, + zbar.Config.ADD_CHECK, + zbar.Config.EMIT_CHECK, + zbar.Config.ASCII, + zbar.Config.MIN_LEN, + zbar.Config.MAX_LEN, + zbar.Config.UNCERTAINTY, + zbar.Config.POSITION, + zbar.Config.X_DENSITY, + zbar.Config.Y_DENSITY): + self.assertTrue(isinstance(cfg, zbar.EnumItem)) + self.assertTrue(int(cfg) >= 0) + self.assertTrue(is_identifier.match(str(cfg))) + + def test_modifiers(self): + for mod in (zbar.Modifier.GS1, + zbar.Modifier.AIM): + self.assertTrue(isinstance(mod, zbar.EnumItem)) + self.assertTrue(int(mod) >= 0) + self.assertTrue(is_identifier.match(str(mod))) + + def test_symbologies(self): + for sym in (zbar.Symbol.NONE, + zbar.Symbol.PARTIAL, + zbar.Symbol.EAN8, + zbar.Symbol.UPCE, + zbar.Symbol.ISBN10, + zbar.Symbol.UPCA, + zbar.Symbol.EAN13, + zbar.Symbol.ISBN13, + zbar.Symbol.DATABAR, + zbar.Symbol.DATABAR_EXP, + zbar.Symbol.I25, + zbar.Symbol.CODABAR, + zbar.Symbol.CODE39, + zbar.Symbol.PDF417, + zbar.Symbol.QRCODE, + zbar.Symbol.CODE93, + zbar.Symbol.CODE128): + self.assertTrue(isinstance(sym, zbar.EnumItem)) + self.assertTrue(int(sym) >= 0) + self.assertTrue(is_identifier.match(str(sym))) + + def test_orientations(self): + for orient in (zbar.Orient.UNKNOWN, + zbar.Orient.UP, + zbar.Orient.RIGHT, + zbar.Orient.DOWN, + zbar.Orient.LEFT): + self.assertTrue(isinstance(orient, zbar.EnumItem)) + self.assertTrue(-1 <= int(orient) <= 3) + self.assertTrue(is_identifier.match(str(orient))) + +class TestScanner(ut.TestCase): + def setUp(self): + self.scn = zbar.Scanner() + + def tearDown(self): + del(self.scn) + + def test_type(self): + self.assertTrue(isinstance(self.scn, zbar.Scanner)) + self.assertTrue(callable(self.scn.reset)) + self.assertTrue(callable(self.scn.new_scan)) + self.assertTrue(callable(self.scn.scan_y)) + + def set_color(color): + self.scn.color = color + self.assertRaises(AttributeError, set_color, zbar.BAR) + + def set_width(width): + self.scn.width = width + self.assertRaises(AttributeError, set_width, 1) + + # FIXME more scanner tests + +class TestDecoder(ut.TestCase): + def setUp(self): + self.dcode = zbar.Decoder() + + def tearDown(self): + del(self.dcode) + + def test_type(self): + self.assertTrue(isinstance(self.dcode, zbar.Decoder)) + self.assertTrue(callable(self.dcode.set_config)) + self.assertTrue(callable(self.dcode.parse_config)) + self.assertTrue(callable(self.dcode.reset)) + self.assertTrue(callable(self.dcode.new_scan)) + self.assertTrue(callable(self.dcode.set_handler)) + self.assertTrue(callable(self.dcode.decode_width)) + + def set_type(typ): + self.dcode.type = typ + self.assertRaises(AttributeError, set_type, zbar.Symbol.CODE128) + + def set_color(color): + self.dcode.color = color + self.assertRaises(AttributeError, set_color, zbar.BAR) + + def set_data(data): + self.dcode.data = data + self.assertRaises(AttributeError, set_data, 'yomama') + + self.assertRaises(AttributeError, + self.dcode.__setattr__, 'direction', -1) + + def test_width(self): + sym = self.dcode.decode_width(5) + self.assertTrue(sym is zbar.Symbol.NONE) + self.assertTrue(not sym) + self.assertEqual(str(sym), 'NONE') + + typ = self.dcode.type + self.assertTrue(sym is typ) + + def test_reset(self): + self.assertTrue(self.dcode.color is zbar.SPACE) + sym = self.dcode.decode_width(1) + self.assertTrue(self.dcode.color is zbar.BAR) + self.dcode.reset() + self.assertTrue(self.dcode.color is zbar.SPACE) + self.assertEqual(self.dcode.direction, 0) + + def test_decode(self): + inline_sym = [ -1 ] + def handler(dcode, closure): + self.assertTrue(dcode is self.dcode) + if dcode.type > zbar.Symbol.PARTIAL: + inline_sym[0] = dcode.type + closure[0] += 1 + + explicit_closure = [ 0 ] + self.dcode.set_handler(handler, explicit_closure) + self.dcode.set_config(zbar.Symbol.QRCODE, zbar.Config.ENABLE, 0) + + for (i, width) in enumerate(encoded_widths): + if width == ' ': continue + sym = self.dcode.decode_width(int(width)) + if i < len(encoded_widths) - 1: + self.assertTrue(sym is zbar.Symbol.NONE or + sym is zbar.Symbol.PARTIAL) + else: + self.assertTrue(sym is zbar.Symbol.EAN13) + + self.assertEqual(self.dcode.configs, + set((zbar.Config.ENABLE, zbar.Config.EMIT_CHECK))) + self.assertEqual(self.dcode.modifiers, set()) + self.assertEqual(self.dcode.data, '6268964977804') + self.assertTrue(self.dcode.color is zbar.BAR) + self.assertEqual(self.dcode.direction, 1) + self.assertTrue(sym is zbar.Symbol.EAN13) + self.assertTrue(inline_sym[0] is zbar.Symbol.EAN13) + self.assertEqual(explicit_closure, [ 2 ]) + + def test_databar(self): + self.dcode.set_config(zbar.Symbol.QRCODE, zbar.Config.ENABLE, 0) + for (i, width) in enumerate(databar_widths): + if width == ' ': continue + sym = self.dcode.decode_width(int(width)) + if i < len(databar_widths) - 1: + self.assertTrue(sym is zbar.Symbol.NONE or + sym is zbar.Symbol.PARTIAL) + + self.assertTrue(sym is zbar.Symbol.DATABAR) + self.assertEqual(self.dcode.get_configs(zbar.Symbol.EAN13), + set((zbar.Config.ENABLE, zbar.Config.EMIT_CHECK))) + self.assertEqual(self.dcode.modifiers, set((zbar.Modifier.GS1,))) + self.assertEqual(self.dcode.data, '0124012345678905') + self.assertTrue(self.dcode.color is zbar.BAR) + self.assertEqual(self.dcode.direction, 1) + + # FIXME test exception during callback + +class TestImage(ut.TestCase): + def setUp(self): + self.image = zbar.Image(123, 456, 'Y800') + + def tearDown(self): + del(self.image) + + def test_type(self): + self.assertTrue(isinstance(self.image, zbar.Image)) + self.assertTrue(callable(self.image.convert)) + + def test_new(self): + self.assertEqual(self.image.format, 'Y800') + self.assertEqual(self.image.size, (123, 456)) + self.assertEqual(self.image.crop, (0, 0, 123, 456)) + + image = zbar.Image() + self.assertTrue(isinstance(image, zbar.Image)) + self.assertEqual(image.format, '\0\0\0\0') + self.assertEqual(image.size, (0, 0)) + self.assertEqual(image.crop, (0, 0, 0, 0)) + + def test_format(self): + def set_format(fmt): + self.image.format = fmt + self.assertRaises(ValueError, set_format, 10) + self.assertEqual(self.image.format, 'Y800') + self.image.format = 'gOOb' + self.assertEqual(self.image.format, 'gOOb') + self.assertRaises(ValueError, set_format, 'yomama') + self.assertEqual(self.image.format, 'gOOb') + self.assertRaises(ValueError, set_format, 'JPG') + self.assertEqual(self.image.format, 'gOOb') + + def test_size(self): + def set_size(sz): + self.image.size = sz + self.assertRaises(ValueError, set_size, (1,)) + self.assertRaises(ValueError, set_size, 1) + self.image.size = (12, 6) + self.assertRaises(ValueError, set_size, (1, 2, 3)) + self.assertEqual(self.image.size, (12, 6)) + self.assertRaises(ValueError, set_size, "foo") + self.assertEqual(self.image.size, (12, 6)) + self.assertEqual(self.image.width, 12) + self.assertEqual(self.image.height, 6) + self.image.width = 81 + self.assertEqual(self.image.size, (81, 6)) + self.image.height = 64 + self.assertEqual(self.image.size, (81, 64)) + self.assertEqual(self.image.width, 81) + self.assertEqual(self.image.height, 64) + + def test_crop(self): + def set_crop(crp): + self.image.crop = crp + self.assertRaises(ValueError, set_crop, (1,)) + self.assertRaises(ValueError, set_crop, 1) + self.image.crop = (1, 2, 100, 200) + self.assertRaises(ValueError, set_crop, (1, 2, 3, 4, 5)) + self.assertEqual(self.image.crop, (1, 2, 100, 200)) + self.assertRaises(ValueError, set_crop, "foo") + self.assertEqual(self.image.crop, (1, 2, 100, 200)) + self.image.crop = (-100, -100, 400, 700) + self.assertEqual(self.image.crop, (0, 0, 123, 456)) + self.image.crop = (40, 50, 60, 70) + self.assertEqual(self.image.crop, (40, 50, 60, 70)) + self.image.size = (82, 65) + self.assertEqual(self.image.crop, (0, 0, 82, 65)) + +class TestImageScanner(ut.TestCase): + def setUp(self): + self.scn = zbar.ImageScanner() + + def tearDown(self): + del(self.scn) + + def test_type(self): + self.assertTrue(isinstance(self.scn, zbar.ImageScanner)) + self.assertTrue(callable(self.scn.set_config)) + self.assertTrue(callable(self.scn.parse_config)) + self.assertTrue(callable(self.scn.enable_cache)) + self.assertTrue(callable(self.scn.scan)) + + def test_set_config(self): + self.scn.set_config() + self.assertRaises(ValueError, self.scn.set_config, -1) + self.assertRaises(TypeError, self.scn.set_config, "yomama") + self.scn.set_config() + + def test_parse_config(self): + self.scn.parse_config("disable") + self.assertRaises(ValueError, self.scn.set_config, -1) + self.scn.set_config() + +class TestImageScan(ut.TestCase): + def setUp(self): + self.scn = zbar.ImageScanner() + self.image = zbar.Image(size[0], size[1], 'Y800', data) + + def tearDown(self): + del(self.image) + del(self.scn) + + def test_scan(self): + n = self.scn.scan(self.image) + self.assertEqual(n, 1) + + syms = self.image.symbols + self.assertTrue(isinstance(syms, zbar.SymbolSet)) + self.assertEqual(len(syms), 1) + + i = iter(self.image) + j = iter(syms) + self.assertTrue(isinstance(i, zbar.SymbolIter)) + self.assertTrue(isinstance(j, zbar.SymbolIter)) + symi = next(i) + symj = next(j) + self.assertRaises(StopIteration, i.__next__) + self.assertRaises(StopIteration, j.__next__) + + # this is the only way to obtain a Symbol, + # so test Symbol here + for sym in (symi, symj): + self.assertTrue(isinstance(sym, zbar.Symbol)) + self.assertTrue(sym.type is zbar.Symbol.EAN13) + self.assertTrue(sym.type is sym.EAN13) + self.assertEqual(str(sym.type), 'EAN13') + + cfgs = sym.configs + self.assertTrue(isinstance(cfgs, set)) + for cfg in cfgs: + self.assertTrue(isinstance(cfg, zbar.EnumItem)) + self.assertEqual(cfgs, + set((zbar.Config.ENABLE, zbar.Config.EMIT_CHECK))) + + mods = sym.modifiers + self.assertTrue(isinstance(mods, set)) + for mod in mods: + self.assertTrue(isinstance(mod, zbar.EnumItem)) + self.assertEqual(mods, set()) + + self.assertTrue(sym.quality > 0) + self.assertEqual(sym.count, 0) + + # FIXME put a nice QR S-A in here + comps = sym.components + self.assertTrue(isinstance(comps, zbar.SymbolSet)) + self.assertEqual(len(comps), 0) + self.assertTrue(not comps) + self.assertTrue(tuple(comps) is ()) + + data = sym.data + self.assertEqual(data, '9876543210128') + + loc = sym.location + self.assertTrue(len(loc) >= 4) # FIXME + self.assertTrue(isinstance(loc, tuple)) + for pt in loc: + self.assertTrue(isinstance(pt, tuple)) + self.assertEqual(len(pt), 2) + # FIXME test values (API currently in flux) + + self.assertTrue(sym.orientation is zbar.Orient.UP) + self.assertTrue(data is sym.data) + self.assertTrue(loc is sym.location) + + def set_symbols(syms): + self.image.symbols = syms + self.assertRaises(TypeError, set_symbols, ()) + + self.scn.recycle(self.image) + self.assertEqual(len(self.image.symbols), 0) + + def test_scan_crop(self): + self.image.crop = (0, 71, 114, 9) + self.assertEqual(self.image.crop, (0, 71, 114, 9)) + n = self.scn.scan(self.image) + self.assertEqual(n, 0) + + self.image.crop = (12, 24, 90, 12) + self.assertEqual(self.image.crop, (12, 24, 90, 12)) + n = self.scn.scan(self.image) + self.assertEqual(n, 0) + + self.image.crop = (9, 24, 96, 12) + self.assertEqual(self.image.crop, (9, 24, 96, 12)) + self.test_scan() + + def test_scan_again(self): + self.test_scan() + +class TestProcessor(ut.TestCase): + def setUp(self): + self.proc = zbar.Processor() + + def tearDown(self): + del(self.proc) + + def test_type(self): + self.assertTrue(isinstance(self.proc, zbar.Processor)) + self.assertTrue(callable(self.proc.init)) + self.assertTrue(callable(self.proc.set_config)) + self.assertTrue(callable(self.proc.parse_config)) + self.assertTrue(callable(self.proc.set_data_handler)) + self.assertTrue(callable(self.proc.user_wait)) + self.assertTrue(callable(self.proc.process_one)) + self.assertTrue(callable(self.proc.process_image)) + + def test_set_config(self): + self.proc.set_config() + self.assertRaises(ValueError, self.proc.set_config, -1) + self.assertRaises(TypeError, self.proc.set_config, "yomama") + self.proc.set_config() + + def test_parse_config(self): + self.proc.parse_config("disable") + self.assertRaises(ValueError, self.proc.set_config, -1) + self.proc.set_config() + + def test_request_size(self): + def set_size(sz): + self.proc.request_size = sz + self.assertRaises(ValueError, set_size, (1,)) + self.assertRaises(ValueError, set_size, 1) + self.proc.request_size = (12, 6) + self.assertRaises(ValueError, set_size, (1, 2, 3)) + self.assertRaises(ValueError, set_size, "foo") + + def test_processing(self): + self.proc.init(VIDEO_DEVICE) + self.assertTrue(self.proc.visible is False) + self.proc.visible = 1 + self.assertTrue(self.proc.visible is True) + self.assertEqual(self.proc.user_wait(1.1), 0) + + self.image = zbar.Image(size[0], size[1], 'Y800', data) + + count = [ 0 ] + def data_handler(proc, image, closure): + self.assertTrue(proc is self.proc) + self.assertTrue(image is self.image) + self.assertEqual(count[0], 0) + count[0] += 1 + + symiter = iter(image) + self.assertTrue(isinstance(symiter, zbar.SymbolIter)) + + syms = tuple(image) + self.assertEqual(len(syms), 1) + for sym in syms: + self.assertTrue(isinstance(sym, zbar.Symbol)) + self.assertTrue(sym.type is zbar.Symbol.EAN13) + self.assertEqual(sym.data, '9876543210128') + self.assertTrue(sym.quality > 0) + self.assertTrue(sym.orientation is zbar.Orient.UP) + closure[0] += 1 + + explicit_closure = [ 0 ] + self.proc.set_data_handler(data_handler, explicit_closure) + + rc = self.proc.process_image(self.image) + self.assertEqual(rc, 0) + self.assertEqual(len(self.image.symbols), 1) + del(self.image.symbols) + self.assertEqual(len(self.image.symbols), 0) + + self.assertEqual(self.proc.user_wait(.9), 0) + + self.assertEqual(explicit_closure, [ 1 ]) + self.proc.set_data_handler() + +if __name__ == '__main__': + ut.main() diff --git a/python/zbarmodule.c b/python/zbarmodule.c new file mode 100644 index 0000000..e8e68ef --- /dev/null +++ b/python/zbarmodule.c @@ -0,0 +1,340 @@ +/*------------------------------------------------------------------------ + * Copyright 2009-2010 (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" + +typedef struct enumdef { + const char *strval; + int intval; +} enumdef; + +static char *exc_names[] = { + "zbar.Exception", NULL, + "zbar.InternalError", "zbar.UnsupportedError", + "zbar.InvalidRequestError", "zbar.SystemError", + "zbar.LockingError", "zbar.BusyError", + "zbar.X11DisplayError", "zbar.X11ProtocolError", + "zbar.WindowClosed", "zbar.WinAPIError", +}; + +static const enumdef symbol_defs[] = { { "NONE", ZBAR_NONE }, + { "PARTIAL", ZBAR_PARTIAL }, + { "EAN8", ZBAR_EAN8 }, + { "UPCE", ZBAR_UPCE }, + { "ISBN10", ZBAR_ISBN10 }, + { "UPCA", ZBAR_UPCA }, + { "EAN13", ZBAR_EAN13 }, + { "ISBN13", ZBAR_ISBN13 }, + { "DATABAR", ZBAR_DATABAR }, + { "DATABAR_EXP", ZBAR_DATABAR_EXP }, + { "I25", ZBAR_I25 }, + { "CODABAR", ZBAR_CODABAR }, + { "CODE39", ZBAR_CODE39 }, + { "PDF417", ZBAR_PDF417 }, + { "QRCODE", ZBAR_QRCODE }, + { "SQCODE", ZBAR_SQCODE }, + { "CODE93", ZBAR_CODE93 }, + { "CODE128", ZBAR_CODE128 }, + { + NULL, + } }; + +static const enumdef config_defs[] = { { "ENABLE", ZBAR_CFG_ENABLE }, + { "ADD_CHECK", ZBAR_CFG_ADD_CHECK }, + { "EMIT_CHECK", ZBAR_CFG_EMIT_CHECK }, + { "ASCII", ZBAR_CFG_ASCII }, + { "BINARY", ZBAR_CFG_BINARY }, + { "MIN_LEN", ZBAR_CFG_MIN_LEN }, + { "MAX_LEN", ZBAR_CFG_MAX_LEN }, + { "UNCERTAINTY", ZBAR_CFG_UNCERTAINTY }, + { "POSITION", ZBAR_CFG_POSITION }, + { "X_DENSITY", ZBAR_CFG_X_DENSITY }, + { "Y_DENSITY", ZBAR_CFG_Y_DENSITY }, + { + NULL, + } }; + +static const enumdef modifier_defs[] = { { "GS1", ZBAR_MOD_GS1 }, + { "AIM", ZBAR_MOD_AIM }, + { + NULL, + } }; + +static const enumdef orient_defs[] = { { "UNKNOWN", ZBAR_ORIENT_UNKNOWN }, + { "UP", ZBAR_ORIENT_UP }, + { "RIGHT", ZBAR_ORIENT_RIGHT }, + { "DOWN", ZBAR_ORIENT_DOWN }, + { "LEFT", ZBAR_ORIENT_LEFT }, + { + NULL, + } }; + +#if PY_MAJOR_VERSION < 3 +struct module_state zbar_state; +#endif + +int object_to_bool(PyObject *obj, int *val) +{ + int tmp = PyObject_IsTrue(obj); + if (tmp < 0) + return (0); + *val = tmp; + return (1); +} + +int parse_dimensions(PyObject *seq, int *dims, int n) +{ + if (!PySequence_Check(seq) || PySequence_Size(seq) != n) + return (-1); + + int i; + for (i = 0; i < n; i++, dims++) { + PyObject *dim = PySequence_GetItem(seq, i); + if (!dim) + return (-1); +#if PY_MAJOR_VERSION >= 3 + *dims = PyLong_AsSsize_t(dim); +#else + *dims = PyInt_AsSsize_t(dim); +#endif + Py_DECREF(dim); + if (*dims == -1 && PyErr_Occurred()) + return (-1); + } + return (0); +} + +static PyObject *version(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return (NULL); + + unsigned int major, minor, patch; + zbar_version(&major, &minor, &patch); + + return (Py_BuildValue("III", major, minor, patch)); +} + +static PyObject *set_verbosity(PyObject *self, PyObject *args) +{ + int verbosity; + if (!PyArg_ParseTuple(args, "i", &verbosity)) + return (NULL); + + zbar_set_verbosity(verbosity); + + Py_INCREF(Py_None); + return (Py_None); +} + +static PyObject *increase_verbosity(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return (NULL); + + zbar_increase_verbosity(); + + Py_INCREF(Py_None); + return (Py_None); +} + +static PyMethodDef zbar_functions[] = { + { "version", version, METH_VARARGS, NULL }, + { "set_verbosity", set_verbosity, METH_VARARGS, NULL }, + { "increase_verbosity", increase_verbosity, METH_VARARGS, NULL }, + { + NULL, + }, +}; + +#if PY_MAJOR_VERSION >= 3 + +static int zbar_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(GETSTATE(m)->zbar_exc[0]); + return 0; +} + +static int zbar_clear(PyObject *m) +{ + Py_CLEAR(GETSTATE(m)->zbar_exc[0]); + return 0; +} + +struct PyModuleDef zbar_moduledef = { PyModuleDef_HEAD_INIT, + "zbar", + NULL, + sizeof(struct module_state), + zbar_functions, + NULL, + zbar_traverse, + zbar_clear, + NULL }; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit_zbar(void) + +#else +#define INITERROR return + +PyMODINIT_FUNC initzbar(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + /* initialize types */ + zbarEnumItem_Type.tp_base = &PyLong_Type; +#else + zbarEnumItem_Type.tp_base = &PyInt_Type; + zbarException_Type.tp_base = (PyTypeObject *)PyExc_Exception; + + if (PyType_Ready(&zbarException_Type) < 0) + INITERROR; +#endif + + if (PyType_Ready(&zbarEnumItem_Type) < 0 || + PyType_Ready(&zbarEnum_Type) < 0 || PyType_Ready(&zbarImage_Type) < 0 || + PyType_Ready(&zbarSymbol_Type) < 0 || + PyType_Ready(&zbarSymbolSet_Type) < 0 || + PyType_Ready(&zbarSymbolIter_Type) < 0 || + PyType_Ready(&zbarProcessor_Type) < 0 || + PyType_Ready(&zbarImageScanner_Type) < 0 || + PyType_Ready(&zbarDecoder_Type) < 0 || + PyType_Ready(&zbarScanner_Type) < 0) + INITERROR; + + /* initialize module */ +#if PY_MAJOR_VERSION >= 3 + PyObject *mod = PyModule_Create(&zbar_moduledef); +#else + PyObject *mod = Py_InitModule("zbar", zbar_functions); +#endif + if (!mod) + INITERROR; + +#if PY_MAJOR_VERSION >= 3 + if (PyState_AddModule(mod, &zbar_moduledef)) { + Py_DECREF(mod); + INITERROR; + } +#endif + + struct module_state *st = GETSTATE(mod); + + /* initialize constant containers */ + st->config_enum = zbarEnum_New(); + st->modifier_enum = zbarEnum_New(); + st->symbol_enum = PyDict_New(); + st->orient_enum = zbarEnum_New(); + if (!st->config_enum || !st->modifier_enum || !st->symbol_enum || + !st->orient_enum) { + Py_DECREF(mod); + INITERROR; + } + + /* internally created/read-only type overrides */ + zbarEnum_Type.tp_new = NULL; + zbarEnum_Type.tp_setattr = NULL; + zbarEnum_Type.tp_setattro = NULL; + + /* zbar internal exception objects */ +#if PY_MAJOR_VERSION >= 3 + st->zbar_exc[0] = PyErr_NewException("zbar.Exception", NULL, NULL); +#else + st->zbar_exc[0] = (PyObject *)&zbarException_Type; +#endif + if (st->zbar_exc[0] == NULL) { + Py_DECREF(mod); + INITERROR; + } + + st->zbar_exc[ZBAR_ERR_NOMEM] = NULL; + zbar_error_t ei; + for (ei = ZBAR_ERR_INTERNAL; ei < ZBAR_ERR_NUM; ei++) { + st->zbar_exc[ei] = + PyErr_NewException(exc_names[ei], st->zbar_exc[0], NULL); + if (!st->zbar_exc[ei]) { + Py_DECREF(mod); + INITERROR; + } + } + + /* add types to module */ + PyModule_AddObject(mod, "EnumItem", (PyObject *)&zbarEnumItem_Type); + PyModule_AddObject(mod, "Image", (PyObject *)&zbarImage_Type); + PyModule_AddObject(mod, "Config", (PyObject *)st->config_enum); + PyModule_AddObject(mod, "Modifier", (PyObject *)st->modifier_enum); + PyModule_AddObject(mod, "Orient", (PyObject *)st->orient_enum); + PyModule_AddObject(mod, "Symbol", (PyObject *)&zbarSymbol_Type); + PyModule_AddObject(mod, "SymbolSet", (PyObject *)&zbarSymbolSet_Type); + PyModule_AddObject(mod, "SymbolIter", (PyObject *)&zbarSymbolIter_Type); + PyModule_AddObject(mod, "Processor", (PyObject *)&zbarProcessor_Type); + PyModule_AddObject(mod, "ImageScanner", (PyObject *)&zbarImageScanner_Type); + PyModule_AddObject(mod, "Decoder", (PyObject *)&zbarDecoder_Type); + PyModule_AddObject(mod, "Scanner", (PyObject *)&zbarScanner_Type); + + for (ei = 0; ei < ZBAR_ERR_NUM; ei++) + if (st->zbar_exc[ei]) + PyModule_AddObject(mod, exc_names[ei] + 5, st->zbar_exc[ei]); + + /* add constants */ + PyObject *dict = PyModule_GetDict(mod); + st->color_enum[ZBAR_SPACE] = + zbarEnumItem_New(dict, NULL, ZBAR_SPACE, "SPACE"); + st->color_enum[ZBAR_BAR] = zbarEnumItem_New(dict, NULL, ZBAR_BAR, "BAR"); + + const enumdef *item; + for (item = config_defs; item->strval; item++) + zbarEnum_Add(st->config_enum, item->intval, item->strval); + for (item = modifier_defs; item->strval; item++) + zbarEnum_Add(st->modifier_enum, item->intval, item->strval); + for (item = orient_defs; item->strval; item++) + zbarEnum_Add(st->orient_enum, item->intval, item->strval); + + PyObject *tp_dict = zbarSymbol_Type.tp_dict; + for (item = symbol_defs; item->strval; item++) + zbarEnumItem_New(tp_dict, st->symbol_enum, item->intval, item->strval); + st->symbol_NONE = zbarSymbol_LookupEnum(ZBAR_NONE); + +#if PY_MAJOR_VERSION >= 3 + return mod; +#endif +} + +PyObject *zbarErr_Set(PyObject *self) +{ + const void *zobj = ((zbarProcessor *)self)->zproc; + zbar_error_t err = _zbar_get_error_code(zobj); + + struct module_state *st = GETMODSTATE(); + + if (err == ZBAR_ERR_NOMEM) + PyErr_NoMemory(); + else if (err < ZBAR_ERR_NUM) { + PyObject *type = st->zbar_exc[err]; + assert(type); + PyErr_SetObject(type, self); + } else + PyErr_SetObject(st->zbar_exc[0], self); + return (NULL); +} diff --git a/python/zbarmodule.h b/python/zbarmodule.h new file mode 100644 index 0000000..d61c381 --- /dev/null +++ b/python/zbarmodule.h @@ -0,0 +1,164 @@ +/*------------------------------------------------------------------------ + * Copyright 2009-2010 (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 <Python.h> +#include <stddef.h> +#include <zbar.h> + +#ifndef _ZBARMODULE_H_ +#define _ZBARMODULE_H_ + +#if PY_MAJOR_VERSION < 3 +typedef struct { + PyBaseExceptionObject base; + PyObject *obj; +} zbarException; + +extern PyTypeObject zbarException_Type; +#endif + +extern struct PyModuleDef zbar_moduledef; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state *)PyModule_GetState(m)) +#define GETMODSTATE() (GETSTATE(PyState_FindModule(&zbar_moduledef))) +#else +extern struct module_state zbar_state; +#define GETSTATE(m) (&zbar_state) +#define GETMODSTATE() (&zbar_state) +#endif + +extern PyObject *zbarErr_Set(PyObject *self); + +typedef struct { +#if PY_MAJOR_VERSION >= 3 + PyLongObject val; /* parent type is the long type */ +#else + PyIntObject val; /* integer value is super type */ +#endif + PyObject *name; /* associated string name */ +} zbarEnumItem; + +extern PyTypeObject zbarEnumItem_Type; + +extern zbarEnumItem *zbarEnumItem_New(PyObject *byname, PyObject *byvalue, + int val, const char *name); + +typedef struct { + PyObject_HEAD PyObject *byname, + *byvalue; /* zbarEnumItem content dictionaries */ +} zbarEnum; + +extern PyTypeObject zbarEnum_Type; + +extern zbarEnum *zbarEnum_New(void); +extern int zbarEnum_Add(zbarEnum *self, int val, const char *name); +extern zbarEnumItem *zbarEnum_LookupValue(zbarEnum *self, int val); +extern PyObject *zbarEnum_SetFromMask(zbarEnum *self, unsigned int mask); + +typedef struct { + PyObject_HEAD zbar_image_t *zimg; + PyObject *data; +} zbarImage; + +extern PyTypeObject zbarImage_Type; + +extern zbarImage *zbarImage_FromImage(zbar_image_t *zimg); +extern int zbarImage_validate(zbarImage *image); + +typedef struct { + PyObject_HEAD const zbar_symbol_set_t *zsyms; +} zbarSymbolSet; + +extern PyTypeObject zbarSymbolSet_Type; + +extern zbarSymbolSet * +zbarSymbolSet_FromSymbolSet(const zbar_symbol_set_t *zsyms); + +#define zbarSymbolSet_Check(obj) PyObject_TypeCheck(obj, &zbarSymbolSet_Type) + +typedef struct { + PyObject_HEAD const zbar_symbol_t *zsym; + PyObject *data; + PyObject *loc; +} zbarSymbol; + +extern PyTypeObject zbarSymbol_Type; + +extern zbarSymbol *zbarSymbol_FromSymbol(const zbar_symbol_t *zsym); +extern zbarEnumItem *zbarSymbol_LookupEnum(zbar_symbol_type_t type); + +typedef struct { + PyObject_HEAD const zbar_symbol_t *zsym; + zbarSymbolSet *syms; +} zbarSymbolIter; + +extern PyTypeObject zbarSymbolIter_Type; + +extern zbarSymbolIter *zbarSymbolIter_FromSymbolSet(zbarSymbolSet *syms); + +typedef struct { + PyObject_HEAD zbar_processor_t *zproc; + PyObject *handler; + PyObject *closure; +} zbarProcessor; + +extern PyTypeObject zbarProcessor_Type; + +#define zbarProcessor_Check(obj) PyObject_TypeCheck(obj, &zbarProcessor_Type) + +typedef struct { + PyObject_HEAD zbar_image_scanner_t *zscn; +} zbarImageScanner; + +extern PyTypeObject zbarImageScanner_Type; + +typedef struct { + PyObject_HEAD zbar_decoder_t *zdcode; + PyObject *handler; + PyObject *args; +} zbarDecoder; + +extern PyTypeObject zbarDecoder_Type; + +typedef struct { + PyObject_HEAD zbar_scanner_t *zscn; + zbarDecoder *decoder; +} zbarScanner; + +extern PyTypeObject zbarScanner_Type; + +extern int object_to_bool(PyObject *obj, int *val); +extern int parse_dimensions(PyObject *seq, int *dims, int n); + +struct module_state { + PyObject *zbar_exc[ZBAR_ERR_NUM]; + zbarEnumItem *color_enum[2]; + zbarEnum *config_enum; + zbarEnum *modifier_enum; + PyObject *symbol_enum; + zbarEnumItem *symbol_NONE; + zbarEnum *orient_enum; +}; + +#endif |