summaryrefslogtreecommitdiffstats
path: root/python/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'python/image.c')
-rw-r--r--python/image.c482
1 files changed, 482 insertions, 0 deletions
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);
+}