diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..8b09587 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,21 @@ +MANIFEST +MANIFEST.in +README +decoder.c +enum.c +exception.c +image.c +imagescanner.c +processor.c +scanner.c +setup.py +symbol.c +symboliter.c +symbolset.c +zbarmodule.c +zbarmodule.h +examples/processor.py +examples/read_one.py +examples/scan_image.py +test/barcode.png +test/test_zbar.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..93acc53 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include MANIFEST MANIFEST.in zbarmodule.h test/barcode.png +recursive-include examples *.py diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..dc7eb68 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,64 @@ +Metadata-Version: 1.0 +Name: zbar +Version: 0.10 +Summary: read barcodes from images or video +Home-page: http://zbar.sourceforge.net +Author: Jeff Brown +Author-email: spadix@users.sourceforge.net +License: LGPL +Description: ========================================== + zbar -- read barcodes from images or video + ========================================== + + The ZBar Bar Code Reader is a library for scanning and decoding bar + codes from various sources such as video streams, image files or raw + intensity sensors. It supports EAN, UPC, Code 128, Code 39 and + Interleaved 2 of 5. These are the Python bindings for the library. + + Check the ZBar project home page for the latest release, mailing + lists, etc. + + * http://zbar.sourceforge.net/ + + + 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: + + * http://zbar.sourceforge.net/ + + Examples + -------- + + TBD + + 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-2009 (c) Jeff Brown + +Platform: UNKNOWN +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: Environment :: Console +Classifier: Environment :: X11 Applications +Classifier: Environment :: Win32 (MS Windows) +Classifier: Operating System :: POSIX +Classifier: Operating System :: Unix +Classifier: Operating System :: Microsoft :: Windows +Classifier: Topic :: Communications +Classifier: Topic :: Multimedia :: Graphics +Classifier: Topic :: Software Development :: Libraries diff --git a/README b/README new file mode 100644 index 0000000..b33fde1 --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +========================================== +zbar -- read barcodes from images or video +========================================== + +The ZBar Bar Code Reader is a library for scanning and decoding bar +codes from various sources such as video streams, image files or raw +intensity sensors. It supports EAN, UPC, Code 128, Code 39 and +Interleaved 2 of 5. These are the Python bindings for the library. + +Check the ZBar project home page for the latest release, mailing +lists, etc. + +* http://zbar.sourceforge.net/ + + +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: + +* http://zbar.sourceforge.net/ + +Examples +-------- + +TBD + +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-2009 (c) Jeff Brown diff --git a/decoder.c b/decoder.c new file mode 100644 index 0000000..26cb8a8 --- /dev/null +++ b/decoder.c @@ -0,0 +1,291 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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); + zbarEnumItem *color = 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 */ + Py_INCREF((PyObject*)symbol_NONE); + return(symbol_NONE); + } + return(zbarSymbol_LookupEnum(sym)); +} + +static PyObject* +decoder_get_data (zbarDecoder *self, + void *closure) +{ + return(PyString_FromStringAndSize(zbar_decoder_get_data(self->zdcode), + zbar_decoder_get_data_length(self->zdcode))); +} + +static PyGetSetDef decoder_getset[] = { + { "color", (getter)decoder_get_color, }, + { "type", (getter)decoder_get_type, }, + { "data", (getter)decoder_get_data, }, + { 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_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 */ + Py_INCREF((PyObject*)symbol_NONE); + return(symbol_NONE); + } + return(zbarSymbol_LookupEnum(sym)); +} + +static PyMethodDef decoder_methods[] = { + { "set_config", (PyCFunction)decoder_set_config, + 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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Decoder", + .tp_doc = decoder_doc, + .tp_basicsize = sizeof(zbarDecoder), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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/enum.c b/enum.c new file mode 100644 index 0000000..8a51532 --- /dev/null +++ b/enum.c @@ -0,0 +1,194 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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); + + self->val.ob_ival = val; + 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); +} + +static int +enumitem_print (zbarEnumItem *self, + FILE *fp, + int flags) +{ + return(self->name->ob_type->tp_print(self->name, fp, flags)); +} + +static PyObject* +enumitem_repr (zbarEnumItem *self) +{ + PyObject *name = PyObject_Repr(self->name); + if(!name) + return(NULL); + char *namestr = PyString_AsString(name); + PyObject *repr = + PyString_FromFormat("%s(%ld, %s)", + ((PyObject*)self)->ob_type->tp_name, + self->val.ob_ival, namestr); + Py_DECREF(name); + return((PyObject*)repr); +} + +PyTypeObject zbarEnumItem_Type = { + PyObject_HEAD_INIT(NULL) + .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, + .tp_print = (printfunc)enumitem_print, + .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); + self->val.ob_ival = val; + self->name = PyString_FromString(name); + 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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Enum", + .tp_doc = enum_doc, + .tp_basicsize = sizeof(zbarEnum), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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); +} diff --git a/examples/processor.py b/examples/processor.py new file mode 100755 index 0000000..52996d1 --- /dev/null +++ b/examples/processor.py @@ -0,0 +1,35 @@ +#!/usr/bin/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, e: + pass diff --git a/examples/read_one.py b/examples/read_one.py new file mode 100755 index 0000000..426b999 --- /dev/null +++ b/examples/read_one.py @@ -0,0 +1,29 @@ +#!/usr/bin/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/examples/scan_image.py b/examples/scan_image.py new file mode 100755 index 0000000..2a80759 --- /dev/null +++ b/examples/scan_image.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +from sys import argv +import zbar +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.tostring() + +# 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/exception.c b/exception.c new file mode 100644 index 0000000..47432b0 --- /dev/null +++ b/exception.c @@ -0,0 +1,145 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Exception", + .tp_basicsize = sizeof(zbarException), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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, +}; + +PyObject* +zbarErr_Set (PyObject *self) +{ + const void *zobj = ((zbarProcessor*)self)->zproc; + zbar_error_t err = _zbar_get_error_code(zobj); + + if(err == ZBAR_ERR_NOMEM) + PyErr_NoMemory(); + else if(err < ZBAR_ERR_NUM) { + PyObject *type = zbar_exc[err]; + assert(type); + PyErr_SetObject(type, self); + } + else + PyErr_SetObject(zbar_exc[0], self); + return(NULL); +} diff --git a/image.c b/image.c new file mode 100644 index 0000000..d0d778d --- /dev/null +++ b/image.c @@ -0,0 +1,431 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" +#ifdef HAVE_INTTYPES_H +# include +#endif + +static char 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); + return(PyString_FromStringAndSize((char*)&format, 4)); +} + +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; + Py_ssize_t len; + if(PyString_AsStringAndSize(value, &format, &len) || + !format || len != 4) { + PyErr_Format(PyExc_ValueError, + "format '%.50s' is not a valid four character code", + format); + return(-1); + } + zbar_image_set_format(self->zimg,*((unsigned long*)format)); + return(0); +} + +static PyObject* +image_get_size (zbarImage *self, + void *closure) +{ + unsigned int width = zbar_image_get_width(self->zimg); + unsigned int height = zbar_image_get_height(self->zimg); + return(PyTuple_Pack(2, PyInt_FromLong(width), PyInt_FromLong(height))); +} + +static int +image_set_size (zbarImage *self, + PyObject *value, + void *closure) +{ + if(!value) { + PyErr_SetString(PyExc_TypeError, "cannot delete size attribute"); + return(-1); + } + int rc = -1; + PyObject *wobj = NULL, *hobj = NULL; + if(!PySequence_Check(value) || + PySequence_Size(value) != 2) + goto error; + wobj = PySequence_GetItem(value, 0); + hobj = PySequence_GetItem(value, 1); + if(!wobj || !hobj) + goto error; + + int width = PyInt_AsSsize_t(wobj); + if(width == -1 && PyErr_Occurred()) + goto error; + + int height = PyInt_AsSsize_t(hobj); + if(height == -1 && PyErr_Occurred()) + goto error; + + zbar_image_set_size(self->zimg, width, height); + rc = 0; + +error: + Py_XDECREF(wobj); + Py_XDECREF(hobj); + if(rc) + PyErr_SetString(PyExc_ValueError, + "size must be a sequence of two ints"); + return(rc); +} + +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); + } + return(PyInt_FromLong(val)); +} + +static int +image_set_int (zbarImage *self, + PyObject *value, + void *closure) +{ + unsigned int tmp, val = PyInt_AsSsize_t(value); + 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); + } + + self->data = PyBuffer_FromMemory((void*)data, datalen); + 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(PyString_AsStringAndSize(value, &data, &datalen)) + return(-1); + + 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, }, + { "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); + } + + 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, + *((unsigned long*)format), + width, height); + else + img->zimg = zbar_image_convert(self->zimg, *((unsigned long*)format)); + + 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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Image", + .tp_doc = image_doc, + .tp_basicsize = sizeof(zbarImage), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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/imagescanner.c b/imagescanner.c new file mode 100644 index 0000000..e7f7f09 --- /dev/null +++ b/imagescanner.c @@ -0,0 +1,187 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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, }, +}; + +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); + } + return(PyInt_FromLong(n)); +} + +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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.ImageScanner", + .tp_doc = imagescanner_doc, + .tp_basicsize = sizeof(zbarImageScanner), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = (newfunc)imagescanner_new, + .tp_dealloc = (destructor)imagescanner_dealloc, + .tp_getset = imagescanner_getset, + .tp_methods = imagescanner_methods, +}; diff --git a/processor.c b/processor.c new file mode 100644 index 0000000..c42d918 --- /dev/null +++ b/processor.c @@ -0,0 +1,374 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" +#ifdef HAVE_INTTYPES_H +# include +#endif + +static char processor_doc[] = PyDoc_STR( + "low level decode of measured bar/space widths.\n" + "\n" + "FIXME."); + +static zbarProcessor* +processor_new (PyTypeObject *type, + PyObject *args, + PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if(!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) + return(NULL); + + zbarProcessor *self = (zbarProcessor*)type->tp_alloc(type, 0); + if(!self) + return(NULL); + + self->zproc = zbar_processor_create(0/*FIXME*/); + 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) +{ + if(!value) { + PyErr_SetString(PyExc_TypeError, "cannot delete attribute"); + return(-1); + } + int rc, 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 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, }, + { 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) +{ + int tmp; + if(PyFloat_Check(obj)) + tmp = PyFloat_AS_DOUBLE(obj) * 1000; + else + tmp = PyInt_AsLong(obj) * 1000; + 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; + static char *kwlist[] = { "timeout", NULL }; + if(!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, + object_to_timeout, &timeout)) + return(NULL); + + int rc = zbar_processor_user_wait(self->zproc, timeout); + if(rc < 0) + return(zbarErr_Set((PyObject*)self)); + return(PyInt_FromLong(rc)); +} + +static PyObject* +processor_process_one (zbarProcessor *self, + PyObject *args, + PyObject *kwds) +{ + int timeout = -1; + static char *kwlist[] = { "timeout", NULL }; + if(!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, + object_to_timeout, &timeout)) + return(NULL); + + int rc = zbar_process_one(self->zproc, timeout); + if(rc < 0) + return(zbarErr_Set((PyObject*)self)); + return(PyInt_FromLong(rc)); +} + +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 = zbar_process_image(self->zproc, img->zimg); + if(n < 0) + return(zbarErr_Set((PyObject*)self)); + return(PyInt_FromLong(n)); +} + +void +process_handler (zbar_image_t *zimg, + const void *userdata) +{ + zbarProcessor *self = (zbarProcessor*)userdata; + assert(self); + assert(self->handler); + assert(self->closure); + + zbarImage *img = zbar_image_get_userdata(zimg); + if(!img || img->zimg != zimg) { + img = zbarImage_FromImage(zimg); + if(!img) { + PyErr_NoMemory(); + return; + } + } + 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); + Py_XDECREF(junk); + Py_DECREF(args); +} + +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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Processor", + .tp_doc = processor_doc, + .tp_basicsize = sizeof(zbarProcessor), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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/scanner.c b/scanner.c new file mode 100644 index 0000000..b0b4c21 --- /dev/null +++ b/scanner.c @@ -0,0 +1,183 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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); + return(PyInt_FromLong(width)); +} + +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); + zbarEnumItem *color = 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 */ + Py_INCREF((PyObject*)symbol_NONE); + return(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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Scanner", + .tp_doc = scanner_doc, + .tp_basicsize = sizeof(zbarScanner), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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/setup.py b/setup.py new file mode 100755 index 0000000..f7639c5 --- /dev/null +++ b/setup.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +from distutils.core import setup, Extension + +setup( + name = 'zbar', + version = '0.10', + 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' ], + ), + ], +) diff --git a/symbol.c b/symbol.c new file mode 100644 index 0000000..6c91274 --- /dev/null +++ b/symbol.c @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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_long (zbarSymbol *self, + void *closure) +{ + int val; + if(!closure) + val = zbar_symbol_get_quality(self->zsym); + else + val = zbar_symbol_get_count(self->zsym); + return(PyInt_FromLong(val)); +} + +static PyObject* +symbol_get_data (zbarSymbol *self, + void *closure) +{ + if(!self->data) { + /* FIXME this could be a buffer now */ + self->data = + PyString_FromStringAndSize(zbar_symbol_get_data(self->zsym), + zbar_symbol_get_data_length(self->zsym)); + 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; + x = PyInt_FromLong(zbar_symbol_get_loc_x(self->zsym, i)); + y = PyInt_FromLong(zbar_symbol_get_loc_y(self->zsym, i)); + PyTuple_SET_ITEM(self->loc, i, PyTuple_Pack(2, x, y)); + } + } + Py_INCREF(self->loc); + return(self->loc); +} + +static PyGetSetDef symbol_getset[] = { + { "type", (getter)symbol_get_type, }, + { "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, }, + { "components", (getter)symbol_get_components, }, + { NULL, }, +}; + +PyTypeObject zbarSymbol_Type = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.Symbol", + .tp_doc = symbol_doc, + .tp_basicsize = sizeof(zbarSymbol), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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) +{ + PyObject *key = PyInt_FromLong(type); + zbarEnumItem *e = (zbarEnumItem*)PyDict_GetItem(symbol_enum, key); + if(!e) + return((zbarEnumItem*)key); + Py_INCREF((PyObject*)e); + Py_DECREF(key); + return(e); +} diff --git a/symboliter.c b/symboliter.c new file mode 100644 index 0000000..e1e04d0 --- /dev/null +++ b/symboliter.c @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.SymbolIter", + .tp_doc = symboliter_doc, + .tp_basicsize = sizeof(zbarSymbolIter), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + .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/symbolset.c b/symbolset.c new file mode 100644 index 0000000..634a807 --- /dev/null +++ b/symbolset.c @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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 = { + PyObject_HEAD_INIT(NULL) + .tp_name = "zbar.SymbolSet", + .tp_doc = symbolset_doc, + .tp_basicsize = sizeof(zbarSymbolSet), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .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/test/barcode.png b/test/barcode.png new file mode 100644 index 0000000..72846ce Binary files /dev/null and b/test/barcode.png differ diff --git a/test/test_zbar.py b/test/test_zbar.py new file mode 100755 index 0000000..2772152 --- /dev/null +++ b/test/test_zbar.py @@ -0,0 +1,397 @@ +#!/usr/bin/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...) +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.tostring(), image.size) + +# FIXME this could be integrated w/fixture creation +(data, size) = load_image() + +encoded_widths = \ + '9 111 212241113121211311141132 11111 311213121312121332111132 111 9' + +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.assert_(isinstance(ver, tuple)) + self.assertEqual(len(ver), 2) + for v in ver: + self.assert_(isinstance(v, int)) + + def test_verbosity(self): + zbar.increase_verbosity() + zbar.set_verbosity(16) + + def test_exceptions(self): + self.assert_(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.assert_(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.POSITION, + zbar.Config.X_DENSITY, + zbar.Config.Y_DENSITY): + self.assert_(isinstance(cfg, zbar.EnumItem)) + self.assert_(int(cfg) >= 0) + self.assert_(is_identifier.match(str(cfg))) + + 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.I25, + zbar.Symbol.CODE39, + zbar.Symbol.PDF417, + zbar.Symbol.QRCODE, + zbar.Symbol.CODE128): + self.assert_(isinstance(sym, zbar.EnumItem)) + self.assert_(int(sym) >= 0) + self.assert_(is_identifier.match(str(sym))) + +class TestScanner(ut.TestCase): + def setUp(self): + self.scn = zbar.Scanner() + + def tearDown(self): + del(self.scn) + + def test_type(self): + self.assert_(isinstance(self.scn, zbar.Scanner)) + self.assert_(callable(self.scn.reset)) + self.assert_(callable(self.scn.new_scan)) + self.assert_(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.assert_(isinstance(self.dcode, zbar.Decoder)) + self.assert_(callable(self.dcode.set_config)) + self.assert_(callable(self.dcode.parse_config)) + self.assert_(callable(self.dcode.reset)) + self.assert_(callable(self.dcode.new_scan)) + self.assert_(callable(self.dcode.set_handler)) + self.assert_(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') + + def test_width(self): + sym = self.dcode.decode_width(5) + self.assert_(sym is zbar.Symbol.NONE) + self.assert_(not sym) + self.assertEqual(str(sym), 'NONE') + + typ = self.dcode.type + self.assert_(sym is typ) + + def test_reset(self): + self.assert_(self.dcode.color is zbar.SPACE) + sym = self.dcode.decode_width(1) + self.assert_(self.dcode.color is zbar.BAR) + self.dcode.reset() + self.assert_(self.dcode.color is zbar.SPACE) + + def test_decode(self): + inline_sym = [ -1 ] + def handler(dcode, closure): + self.assert_(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.assert_(sym is zbar.Symbol.NONE or + sym is zbar.Symbol.PARTIAL) + else: + self.assert_(sym is zbar.Symbol.EAN13) + + self.assertEqual(self.dcode.data, '6268964977804') + self.assert_(self.dcode.color is zbar.BAR) + self.assert_(sym is zbar.Symbol.EAN13) + self.assert_(inline_sym[0] is zbar.Symbol.EAN13) + self.assertEqual(explicit_closure, [ 2 ]) + + # 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.assert_(isinstance(self.image, zbar.Image)) + self.assert_(callable(self.image.convert)) + + def test_new(self): + self.assertEqual(self.image.format, 'Y800') + self.assertEqual(self.image.size, (123, 456)) + + image = zbar.Image() + self.assert_(isinstance(image, zbar.Image)) + self.assertEqual(image.format, '\0\0\0\0') + self.assertEqual(image.size, (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) + +class TestImageScanner(ut.TestCase): + def setUp(self): + self.scn = zbar.ImageScanner() + + def tearDown(self): + del(self.scn) + + def test_type(self): + self.assert_(isinstance(self.scn, zbar.ImageScanner)) + self.assert_(callable(self.scn.set_config)) + self.assert_(callable(self.scn.parse_config)) + self.assert_(callable(self.scn.enable_cache)) + self.assert_(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.assert_(isinstance(syms, zbar.SymbolSet)) + self.assertEqual(len(syms), 1) + + i = iter(self.image) + j = iter(syms) + self.assert_(isinstance(i, zbar.SymbolIter)) + self.assert_(isinstance(j, zbar.SymbolIter)) + symi = i.next() + symj = j.next() + 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.assert_(isinstance(sym, zbar.Symbol)) + self.assert_(sym.type is zbar.Symbol.EAN13) + self.assert_(sym.type is sym.EAN13) + self.assertEqual(str(sym.type), 'EAN13') + self.assert_(sym.quality > 0) + self.assertEqual(sym.count, 0) + + # FIXME put a nice QR S-A in here + comps = sym.components + self.assert_(isinstance(comps, zbar.SymbolSet)) + self.assertEqual(len(comps), 0) + self.assert_(not comps) + self.assert_(tuple(comps) is ()) + + data = sym.data + self.assertEqual(data, '9876543210128') + + loc = sym.location + self.assert_(len(loc) >= 4) # FIXME + self.assert_(isinstance(loc, tuple)) + for pt in loc: + self.assert_(isinstance(pt, tuple)) + self.assertEqual(len(pt), 2) + # FIXME test values (API currently in flux) + + self.assert_(data is sym.data) + self.assert_(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_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.assert_(isinstance(self.proc, zbar.Processor)) + self.assert_(callable(self.proc.init)) + self.assert_(callable(self.proc.set_config)) + self.assert_(callable(self.proc.parse_config)) + self.assert_(callable(self.proc.set_data_handler)) + self.assert_(callable(self.proc.user_wait)) + self.assert_(callable(self.proc.process_one)) + self.assert_(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_processing(self): + self.proc.init(VIDEO_DEVICE) + self.assert_(self.proc.visible is False) + self.proc.visible = 1 + self.assert_(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.assert_(proc is self.proc) + self.assert_(image is self.image) + self.assertEqual(count[0], 0) + count[0] += 1 + + symiter = iter(image) + self.assert_(isinstance(symiter, zbar.SymbolIter)) + + symbols = tuple(image) + self.assertEqual(len(symbols), 1) + for symbol in symbols: + self.assert_(isinstance(symbol, zbar.Symbol)) + self.assert_(symbol.type is zbar.Symbol.EAN13) + self.assertEqual(symbol.data, '9876543210128') + self.assert_(symbol.quality > 0) + 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/zbarmodule.c b/zbarmodule.c new file mode 100644 index 0000000..27cce34 --- /dev/null +++ b/zbarmodule.c @@ -0,0 +1,198 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "zbarmodule.h" + +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", +}; + +int +object_to_bool (PyObject *obj, + int *val) +{ + int tmp = PyObject_IsTrue(obj); + if(tmp < 0) + return(0); + *val = tmp; + return(1); +} + +PyObject *zbar_exc[ZBAR_ERR_NUM]; +zbarEnumItem *color_enum[2]; +zbarEnum *config_enum; +PyObject *symbol_enum; +zbarEnumItem *symbol_NONE; + +static PyObject* +version (PyObject *self, + PyObject *args) +{ + if(!PyArg_ParseTuple(args, "")) + return(NULL); + + unsigned int major, minor; + zbar_version(&major, &minor); + + return(Py_BuildValue("II", major, minor)); +} + +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, }, +}; + +PyMODINIT_FUNC +initzbar (void) +{ + /* initialize constant containers */ + config_enum = zbarEnum_New(); + symbol_enum = PyDict_New(); + if(!config_enum || !symbol_enum) + return; + + /* initialize types */ + zbarEnumItem_Type.tp_base = &PyInt_Type; + zbarException_Type.tp_base = (PyTypeObject*)PyExc_Exception; + + if(PyType_Ready(&zbarException_Type) < 0 || + 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) + return; + + zbar_exc[0] = (PyObject*)&zbarException_Type; + zbar_exc[ZBAR_ERR_NOMEM] = NULL; + zbar_error_t ei; + for(ei = ZBAR_ERR_INTERNAL; ei < ZBAR_ERR_NUM; ei++) { + zbar_exc[ei] = PyErr_NewException(exc_names[ei], zbar_exc[0], NULL); + if(!zbar_exc[ei]) + return; + } + + /* internally created/read-only type overrides */ + zbarEnum_Type.tp_new = NULL; + zbarEnum_Type.tp_setattr = NULL; + zbarEnum_Type.tp_setattro = NULL; + + /* initialize module */ + PyObject *mod = Py_InitModule("zbar", zbar_functions); + if(!mod) + return; + + /* add types to module */ + PyModule_AddObject(mod, "EnumItem", (PyObject*)&zbarEnumItem_Type); + PyModule_AddObject(mod, "Image", (PyObject*)&zbarImage_Type); + PyModule_AddObject(mod, "Config", (PyObject*)config_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(zbar_exc[ei]) + PyModule_AddObject(mod, exc_names[ei] + 5, zbar_exc[ei]); + + /* add constants */ + PyObject *dict = PyModule_GetDict(mod); + color_enum[ZBAR_SPACE] = + zbarEnumItem_New(dict, NULL, ZBAR_SPACE, "SPACE"); + color_enum[ZBAR_BAR] = + zbarEnumItem_New(dict, NULL, ZBAR_BAR, "BAR"); + + zbarEnum_Add(config_enum, ZBAR_CFG_ENABLE, "ENABLE"); + zbarEnum_Add(config_enum, ZBAR_CFG_ADD_CHECK, "ADD_CHECK"); + zbarEnum_Add(config_enum, ZBAR_CFG_EMIT_CHECK, "EMIT_CHECK"); + zbarEnum_Add(config_enum, ZBAR_CFG_ASCII, "ASCII"); + zbarEnum_Add(config_enum, ZBAR_CFG_MIN_LEN, "MIN_LEN"); + zbarEnum_Add(config_enum, ZBAR_CFG_MAX_LEN, "MAX_LEN"); + zbarEnum_Add(config_enum, ZBAR_CFG_X_DENSITY, "POSITION"); + zbarEnum_Add(config_enum, ZBAR_CFG_X_DENSITY, "X_DENSITY"); + zbarEnum_Add(config_enum, ZBAR_CFG_Y_DENSITY, "Y_DENSITY"); + + PyObject *tp_dict = zbarSymbol_Type.tp_dict; + symbol_NONE = + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_NONE, "NONE"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_PARTIAL, "PARTIAL"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_EAN8, "EAN8"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_UPCE, "UPCE"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_ISBN10, "ISBN10"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_UPCA, "UPCA"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_EAN13, "EAN13"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_ISBN13, "ISBN13"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_I25, "I25"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_CODE39, "CODE39"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_PDF417, "PDF417"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_QRCODE, "QRCODE"); + zbarEnumItem_New(tp_dict, symbol_enum, ZBAR_CODE128, "CODE128"); +} diff --git a/zbarmodule.h b/zbarmodule.h new file mode 100644 index 0000000..b6b660f --- /dev/null +++ b/zbarmodule.h @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include +#include +#include + +#ifndef _ZBARMODULE_H_ +#define _ZBARMODULE_H_ + +typedef struct { + PyBaseExceptionObject base; + PyObject *obj; +} zbarException; + +extern PyTypeObject zbarException_Type; +extern PyObject *zbar_exc[ZBAR_ERR_NUM]; + +extern PyObject *zbarErr_Set(PyObject *self); + +typedef struct { + PyIntObject val; /* integer value is super type */ + 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); + +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 zbarEnumItem *color_enum[2]; +extern zbarEnum *config_enum; +extern PyObject *symbol_enum; +extern zbarEnumItem *symbol_NONE; + +int object_to_bool(PyObject *obj, + int *val); + +#endif