summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTravis Oliphant <oliphant@enthought.com>2007-12-16 05:30:41 +0000
committerTravis Oliphant <oliphant@enthought.com>2007-12-16 05:30:41 +0000
commit25c161b20770bd9c00c106f21019d2593953dbfd (patch)
tree9bf29617b88aaeb298b9f987c2ee17c037fe3814 /src
parent22fbdc5c744674550be074550862645ddf423b31 (diff)
downloadnumpy-25c161b20770bd9c00c106f21019d2593953dbfd.tar.gz
Changes to io layer of NumPy
Diffstat (limited to 'src')
-rw-r--r--src/_compiled_base.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/_compiled_base.c b/src/_compiled_base.c
index 42c0183e8..1b02cd3fc 100644
--- a/src/_compiled_base.c
+++ b/src/_compiled_base.c
@@ -526,6 +526,225 @@ arr_add_docstring(PyObject *dummy, PyObject *args)
return Py_None;
}
+
+static char packbits_doc[] =
+"out = numpy.packbits(myarray)\n\n"
+" myarray = an array whose (assumed binary) elements you want to\n"
+" pack into bits (must be of integer type)\n\n"
+" This routine packs the elements of a binary-valued dataset into a\n"
+" 1-D NumPy array of type uint8 ('B') whose bits correspond to\n"
+" the logical (0 or nonzero) value of the input elements. \n\n"
+" If myarray has more dimensions than 2 it packs each slice (the last\n"
+" 2 dimensions --- rows*columns) separately. The number of elements\n"
+" per slice (rows*columns) is then important to know to be able to unpack\n"
+" the data later.\n\n"
+" Example:\n"
+" >>> a = array([[[1,0,1],\n"
+" ... [0,1,0]],\n"
+" ... [[1,1,0],\n"
+" ... [0,0,1]]])\n"
+" >>> b = numpy.packbits(a)\n"
+" >>> b\n"
+" array([168, 196], 'b')\n\n"
+" Note that 168 = 128 + 32 + 8\n"
+" 196 = 128 + 64 + 4";
+
+static char unpackbits_doc[] =
+"out = numpy.unpackbits(myarray, elements_per_slice {, out_type} )\n\n"
+" myarray = Array of integer type whose least\n"
+" significant byte is a bit-field for the\n"
+" resulting output array.\n\n"
+" elements_per_slice = Necessary for interpretation of myarray.\n"
+" This is how many elements in the\n "
+" rows*columns of original packed structure.\n\nOPTIONAL\n"
+" out_type = The type of output array to populate with 1's\n"
+" and 0's. Must be an integer type.\n\n\nThe output array\n"
+" will be a 1-D array of 1's and zero's";
+
+
+/* PACKBITS
+
+
+ This function packs binary (0 or 1) 1-bit per pixel images
+ into bytes for writing to disk.
+
+*/
+
+void packbits(
+ char In[],
+ int element_size, /* in bytes */
+ char Out[],
+ int total_elements,
+ int els_per_slice
+ )
+{
+ char build;
+ int i,index,slice,slices,out_bytes;
+ int maxi, remain, nonzero, j;
+ char *outptr,*inptr;
+
+ outptr = Out; /* pointer to output buffer */
+ inptr = In; /* pointer to input buffer */
+ slices = total_elements/els_per_slice;
+ out_bytes = ceil( (float) els_per_slice / 8); /* number of bytes in each slice */
+ remain = els_per_slice % 8; /* uneven bits */
+ if (remain == 0) remain = 8; /* */
+ /* printf("Start: %d %d %d %d %d\n",inM,MN,slices,out_bytes,remain);
+ */
+ for (slice = 0; slice < slices; slice++) {
+ for (index = 0; index < out_bytes; index++) {
+ build = 0;
+ maxi = (index != out_bytes - 1 ? 8 : remain);
+ for (i = 0; i < maxi ; i++) {
+ build <<= 1; /* shift bits left one bit */
+ nonzero = 0;
+ for (j = 0; j < element_size; j++) /* determine if this number is non-zero */
+ nonzero += (*(inptr++) != 0);
+ build += (nonzero > 0); /* add to this bit if the input value is non-zero */
+ }
+ if (index == out_bytes - 1) build <<= (8-remain);
+ /* printf("Here: %d %d %d %d\n",build,slice,index,maxi);
+ */
+ *(outptr++) = build;
+ }
+ }
+ return;
+}
+
+
+void unpackbits(
+ char In[],
+ int in_element_size,
+ char Out[],
+ int element_size,
+ int total_elements,
+ int els_per_slice
+ )
+{
+ unsigned char mask;
+ int i,index,slice,slices,out_bytes;
+ int maxi, remain;
+ char *outptr,*inptr;
+
+ outptr = Out;
+ inptr = In;
+ if (PyArray_ISNBO(PyArray_BIG)) {
+ outptr += (element_size - 1);
+ inptr += (in_element_size - 1);
+ }
+ slices = total_elements / els_per_slice;
+ out_bytes = ceil( (float) els_per_slice / 8);
+ remain = els_per_slice % 8;
+ if (remain == 0) remain = 8;
+ /* printf("Start: %d %d %d %d %d\n",inM,MN,slices,out_bytes,remain);
+ */
+ for (slice = 0; slice < slices; slice++) {
+ for (index = 0; index < out_bytes; index++) {
+ maxi = (index != out_bytes - 1 ? 8 : remain);
+ mask = 128;
+ for (i = 0; i < maxi ; i++) {
+ *outptr = ((mask & (unsigned char)(*inptr)) > 0);
+ outptr += element_size;
+ mask >>= 1;
+ }
+ /* printf("Here: %d %d %d %d\n",build,slice,index,maxi);
+ */
+ inptr += in_element_size;
+ }
+ }
+ return;
+}
+
+static PyObject *
+numpyio_pack(PyObject *self, PyObject *args) /* args: in */
+{
+ PyArrayObject *arr = NULL, *out = NULL;
+ PyObject *obj;
+ int els_per_slice;
+ int out_size;
+ int type;
+
+ if (!PyArg_ParseTuple( args, "O" , &obj))
+ return NULL;
+
+ type = PyArray_ObjectType(obj,0);
+ if ((arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,type,0,0)) == NULL)
+ return NULL;
+
+ if (!PyArray_ISINTEGER(arr))
+ PYSETERROR("Expecting an input array of integer data type");
+
+ /* Get size information from input array and make a 1-D output array of bytes */
+
+ els_per_slice = PyArray_DIM(arr, PyArray_NDIM(arr)-1);
+ if (PyArray_NDIM(arr) > 1)
+ els_per_slice = els_per_slice * PyArray_DIM(arr, PyArray_NDIM(arr)-2);
+
+ out_size = (PyArray_SIZE(arr)/els_per_slice)*ceil ( (float) els_per_slice / 8);
+
+ if ((out = (PyArrayObject *)PyArray_FromDims(1,&out_size,PyArray_UBYTE))==NULL) {
+ goto fail;
+ }
+
+ packbits(PyArray_DATA(arr),PyArray_ITEMSIZE(arr),PyArray_DATA(out),
+ PyArray_SIZE(arr), els_per_slice);
+
+ Py_DECREF(arr);
+ return out;
+
+ fail:
+ Py_XDECREF(arr);
+ return NULL;
+
+}
+
+static PyObject *
+numpyio_unpack(PyObject *self, PyObject *args) /* args: in, out_type */
+{
+ PyArrayObject *arr = NULL, *out=NULL;
+ PyObject *obj;
+ int els_per_slice, arrsize;
+ int out_size;
+
+ if (!PyArg_ParseTuple( args, "Oi|c" , &obj, &els_per_slice, &out_type))
+ return NULL;
+
+ if (els_per_slice < 1)
+ PYSETERROR("Second argument is elements_per_slice and it must be >= 1");
+
+ if ((arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,NPY_UBYTE,0,0)) == NULL)
+ return NULL;
+
+ arrsize = PyArray_SIZE(arr);
+
+ if ((arrsize % (int) (ceil( (float) els_per_slice / 8))) != 0)
+ PYSETERROR("That cannot be the number of elements per slice for this array size");
+
+ if (!PyArray_ISINTEGER(arr))
+ PYSETERROR("Can only unpack arrays that are of integer type");
+
+ /* Make an 1-D output array of type out_type */
+
+ out_size = els_per_slice * arrsize / ceil( (float) els_per_slice / 8);
+
+ if ((out = (PyArrayObject *)PyArray_FromDims(1,&out_size,out_type))==NULL)
+ goto fail;
+
+ if (out->descr->type_num > PyArray_LONG) {
+ PYSETERROR("Can only unpack bits into integer type.");
+ }
+
+ unpackbits(arr->data,arr->descr->elsize,out->data,out->descr->elsize,out_size,els_per_slice);
+
+ Py_DECREF(arr);
+ return PyArray_Return(out);
+
+ fail:
+ Py_XDECREF(out);
+ Py_XDECREF(arr);
+ return NULL;
+}
+
static struct PyMethodDef methods[] = {
{"_insert", (PyCFunction)arr_insert, METH_VARARGS | METH_KEYWORDS,
arr_insert__doc__},
@@ -537,6 +756,8 @@ static struct PyMethodDef methods[] = {
NULL},
{"add_docstring", (PyCFunction)arr_add_docstring, METH_VARARGS,
NULL},
+ {"packbits", numpyio_pack, 1, packbits_doc},
+ {"unpackbits", numpyio_unpack, 1, unpackbits_doc},
{NULL, NULL} /* sentinel */
};