build/pypng/exnumpy.py
 author Irving Reid Wed, 04 Apr 2012 09:13:35 -0400 changeset 11568 014d81b1029f033d20453ba500b53024838e8e86 parent 8729 923b924c9422bddc54a3d8c08b765da58dddeedd permissions -rw-r--r--
Bug 734080 - Port clang warning suppression from m-c. r=dbienvenu
```
#!/usr/bin/env python
# \$Rev: 126 \$

# Numpy example.
# Original code created by Mel Raab, modified by David Jones.

'''
Example code integrating RGB PNG files, PyPNG and NumPy
(abstracted from Mel Raab's functioning code)
'''

# http://www.python.org/doc/2.4.4/lib/module-itertools.html
import itertools

import numpy
import png

''' If you have a PNG file for an RGB image,
and want to create a numpy array of data from it.
'''
# class can take a filename, a file-like object, or the byte data
# directly; this suggests alternatives such as using urllib to read
# an image from the internet:
# Tuple unpacking, using multiple assignment, is very useful for the
# result of asDirect (and other methods).
# See
# http://docs.python.org/tutorial/introduction.html#first-steps-towards-programming
row_count, column_count, pngdata, meta = pngReader.asDirect()
bitdepth=meta['bitdepth']
plane_count=meta['planes']

# Make sure we're dealing with RGB files
assert plane_count == 3

''' Boxed row flat pixel:
list([R,G,B, R,G,B, R,G,B],
[R,G,B, R,G,B, R,G,B])
Array dimensions for this example:  (2,9)

Create `image_2d` as a two-dimensional NumPy array by stacking a
sequence of 1-dimensional arrays (rows).
The NumPy array mimics PyPNG's (boxed row flat pixel) representation;
it will have dimensions ``(row_count,column_count*plane_count)``.
'''
# The use of ``numpy.uint16``, below, is to convert each row to a NumPy
# array with data type ``numpy.uint16``.  This is a feature of NumPy,
# discussed further in
# http://docs.scipy.org/doc/numpy/user/basics.types.html .
# You can use avoid the explicit conversion with
# ``numpy.vstack(pngdata)``, but then NumPy will pick the array's data
# type; in practice it seems to pick ``numpy.int32``, which is large enough
# to hold any pixel value for any PNG image but uses 4 bytes per value when
# 1 or 2 would be enough.
# --- extract 001 start
image_2d = numpy.vstack(itertools.imap(numpy.uint16, pngdata))
# --- extract 001 end
# Do not be tempted to use ``numpy.asarray``; when passed an iterator
# (`pngdata` is often an iterator) it will attempt to create a size 1
# array with the iterator as its only element.
# An alternative to the above is to create the target array of the right
# shape, then populate it row by row:
if 0:
image_2d = numpy.zeros((row_count,plane_count*column_count),
dtype=numpy.uint16)
for row_index, one_boxed_row_flat_pixels in enumerate(pngdata):
image_2d[row_index,:]=one_boxed_row_flat_pixels

del pngdata

''' Reconfigure for easier referencing, similar to
Boxed row boxed pixel:
list([ (R,G,B), (R,G,B), (R,G,B) ],
[ (R,G,B), (R,G,B), (R,G,B) ])
Array dimensions for this example:  (2,3,3)

``image_3d`` will contain the image as a three-dimensional numpy
array, having dimensions ``(row_count,column_count,plane_count)``.
'''
# --- extract 002 start
image_3d = numpy.reshape(image_2d,
(row_count,column_count,plane_count))
# --- extract 002 end

''' ============= '''

''' Convert NumPy image_3d array to PNG image file.

If the data is three-dimensional, as it is above, the best thing
to do is reshape it into a two-dimensional array with a shape of
``(row_count, column_count*plane_count)``.  Because a
two-dimensional numpy array is an iterator, it can be passed
directly to the ``png.Writer.write`` method.
'''

row_count, column_count, plane_count = image_3d.shape
assert plane_count==3

pngfile = open('picture_out.png', 'wb')
try:
# This example assumes that you have 16-bit pixel values in the data
# array (that's what the ``bitdepth=16`` argument is for).
# If you don't, then the resulting PNG file will likely be
# very dark.  Hey, it's only an example.
pngWriter = png.Writer(column_count, row_count,
greyscale=False,
alpha=False,
bitdepth=16)
# As of 2009-04-13 passing a numpy array that has an element type
# that is a numpy integer type (for example, the `image_3d` array has an
# element type of ``numpy.uint16``) generates a deprecation warning.
# This is probably a bug in numpy; it may go away in the future.
# The code still works despite the warning.