From 319081d874db3a864b8f2a24fbb8e83e80f10d16 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 19:14:22 +0200 Subject: [PATCH 01/14] Remove outdated reference to 'load_plugins' --- scikits/image/io/_plugins/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikits/image/io/_plugins/plugin.py b/scikits/image/io/_plugins/plugin.py index 58f51a7b..fa6b5d5a 100644 --- a/scikits/image/io/_plugins/plugin.py +++ b/scikits/image/io/_plugins/plugin.py @@ -71,7 +71,7 @@ def call(kind, *args, **kwargs): if len(plugin_funcs) == 0: raise RuntimeError('''No suitable plugin registered for %s. -You may load I/O plugins with the `scikits.image.io.load_plugin` +You may load I/O plugins with the `scikits.image.io.use_plugin` command. A list of all available plugins can be found using `scikits.image.io.plugins()`.''' % kind) From d061967cdb555e7f26cb063e1180aeb5d8a45008 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 22:48:44 +0200 Subject: [PATCH 02/14] Convert from CRLF line endings --- scikits/image/io/_plugins/freeimage_plugin.py | 1062 ++++++++--------- 1 file changed, 531 insertions(+), 531 deletions(-) diff --git a/scikits/image/io/_plugins/freeimage_plugin.py b/scikits/image/io/_plugins/freeimage_plugin.py index 3bde8ae9..d9492f83 100644 --- a/scikits/image/io/_plugins/freeimage_plugin.py +++ b/scikits/image/io/_plugins/freeimage_plugin.py @@ -1,531 +1,531 @@ -import ctypes -import numpy -import sys -import os -import os.path -from numpy.compat import asbytes - -def _load_library(libname, loader_path): - """ A small fork of numpy.ctypeslib.load_library - to support windll. - """ - if ctypes.__version__ < '1.0.1': - import warnings - warnings.warn("All features of ctypes interface may not work " \ - "with ctypes < 1.0.1") - - ext = os.path.splitext(libname)[1] - if not ext: - # Try to load library with platform-specific name, otherwise - # default to libname.[so|pyd]. Sometimes, these files are built - # erroneously on non-linux platforms. - libname_ext = ['%s.so' % libname, '%s.pyd' % libname] - if sys.platform == 'win32': - libname_ext.insert(0, '%s.dll' % libname) - elif sys.platform == 'darwin': - libname_ext.insert(0, '%s.dylib' % libname) - else: - libname_ext = [libname] - - loader_path = os.path.abspath(loader_path) - if not os.path.isdir(loader_path): - libdir = os.path.dirname(loader_path) - else: - libdir = loader_path - for ln in libname_ext: - try: - libpath = os.path.join(libdir, ln) - if sys.platform == 'win32': - return ctypes.windll[libpath] - else: - return ctypes.cdll[libpath] - except OSError, e: - pass - - raise e - -lib_dirs = [os.path.dirname(__file__), - '/lib', - '/usr/lib', - '/usr/local/lib', - '/opt/local/lib', - ] - -if 'HOME' in os.environ: - lib_dirs.append(os.path.join(os.environ['HOME'], 'lib')) - -API = { - 'FreeImage_Load': (ctypes.c_void_p, - [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]), - 'FreeImage_GetWidth': (ctypes.c_uint, - [ctypes.c_void_p]), - 'FreeImage_GetHeight': (ctypes.c_uint, - [ctypes.c_void_p]), - 'FreeImage_GetImageType': (ctypes.c_uint, - [ctypes.c_void_p]), - 'FreeImage_GetBPP': (ctypes.c_uint, - [ctypes.c_void_p]), - 'FreeImage_GetPitch': (ctypes.c_uint, - [ctypes.c_void_p]), - 'FreeImage_GetBits': (ctypes.c_void_p, - [ctypes.c_void_p]), - } - -# Albert's ctypes pattern -def register_api(lib,api): - for f, (restype, argtypes) in api.items(): - func = getattr(lib, f) - func.restype = restype - func.argtypes = argtypes - -_FI = None -for d in lib_dirs: - for libname in ('freeimage', 'FreeImage', - 'libfreeimage', 'libFreeImage'): - try: - _FI = _load_library(libname, d) - except OSError: - pass - else: - break - - if _FI is not None: - break - -if not _FI: - raise OSError('Could not find libFreeImage in any of the following ' - 'directories: \'%s\'' % '\', \''.join(lib_dirs)) - -register_api(_FI, API) - -if sys.platform == 'win32': - _functype = ctypes.WINFUNCTYPE -else: - _functype = ctypes.CFUNCTYPE - -@_functype(None, ctypes.c_int, ctypes.c_char_p) -def _error_handler(fif, message): - raise RuntimeError('FreeImage error: %s' % message) - -_FI.FreeImage_SetOutputMessage(_error_handler) - -class FI_TYPES(object): - FIT_UNKNOWN = 0 - FIT_BITMAP = 1 - FIT_UINT16 = 2 - FIT_INT16 = 3 - FIT_UINT32 = 4 - FIT_INT32 = 5 - FIT_FLOAT = 6 - FIT_DOUBLE = 7 - FIT_COMPLEX = 8 - FIT_RGB16 = 9 - FIT_RGBA16 = 10 - FIT_RGBF = 11 - FIT_RGBAF = 12 - - dtypes = { - FIT_BITMAP: numpy.uint8, - FIT_UINT16: numpy.uint16, - FIT_INT16: numpy.int16, - FIT_UINT32: numpy.uint32, - FIT_INT32: numpy.int32, - FIT_FLOAT: numpy.float32, - FIT_DOUBLE: numpy.float64, - FIT_COMPLEX: numpy.complex128, - FIT_RGB16: numpy.uint16, - FIT_RGBA16: numpy.uint16, - FIT_RGBF: numpy.float32, - FIT_RGBAF: numpy.float32 - } - - fi_types = { - (numpy.uint8, 1): FIT_BITMAP, - (numpy.uint8, 3): FIT_BITMAP, - (numpy.uint8, 4): FIT_BITMAP, - (numpy.uint16, 1): FIT_UINT16, - (numpy.int16, 1): FIT_INT16, - (numpy.uint32, 1): FIT_UINT32, - (numpy.int32, 1): FIT_INT32, - (numpy.float32, 1): FIT_FLOAT, - (numpy.float64, 1): FIT_DOUBLE, - (numpy.complex128, 1): FIT_COMPLEX, - (numpy.uint16, 3): FIT_RGB16, - (numpy.uint16, 4): FIT_RGBA16, - (numpy.float32, 3): FIT_RGBF, - (numpy.float32, 4): FIT_RGBAF - } - - extra_dims = { - FIT_UINT16: [], - FIT_INT16: [], - FIT_UINT32: [], - FIT_INT32: [], - FIT_FLOAT: [], - FIT_DOUBLE: [], - FIT_COMPLEX: [], - FIT_RGB16: [3], - FIT_RGBA16: [4], - FIT_RGBF: [3], - FIT_RGBAF: [4] - } - - @classmethod - def get_type_and_shape(cls, bitmap): - w = _FI.FreeImage_GetWidth(bitmap) - h = _FI.FreeImage_GetHeight(bitmap) - fi_type = _FI.FreeImage_GetImageType(bitmap) - if not fi_type: - raise ValueError('Unknown image pixel type') - dtype = cls.dtypes[fi_type] - if fi_type == cls.FIT_BITMAP: - bpp = _FI.FreeImage_GetBPP(bitmap) - if bpp == 8: - extra_dims = [] - elif bpp == 24: - extra_dims = [3] - elif bpp == 32: - extra_dims = [4] - else: - raise ValueError('Cannot convert %d BPP bitmap' % bpp) - else: - extra_dims = cls.extra_dims[fi_type] - return numpy.dtype(dtype), extra_dims + [w, h] - -class IO_FLAGS(object): - #Bmp - BMP_DEFAULT = 0 - BMP_SAVE_RLE = 1 - - #Png - PNG_DEFAULT = 0 - PNG_IGNOREGAMMA = 1 - - #Gif - GIF_DEFAULT = 0 - GIF_LOAD256 = 1 - GIF_PLAYBACK = 2 - - #Ico - ICO_DEFAULT = 0 - ICO_MAKEALPHA = 1 - - #Tiff - TIFF_DEFAULT = 0 - TIFF_CMYK = 0x0001 - TIFF_NONE = 0x0800 - TIFF_PACKBITS = 0x0100 - TIFF_DEFLATE = 0x0200 - TIFF_ADOBE_DEFLATE = 0x0400 - TIFF_CCITTFAX3 = 0x1000 - TIFF_CCITTFAX4 = 0x2000 - TIFF_LZW = 0x4000 - TIFF_JPEG = 0x8000 - - #Jpeg - JPEG_DEFAULT = 0 - JPEG_FAST = 1 - JPEG_ACCURATE = 2 - JPEG_QUALITYSUPERB = 0x80 - JPEG_QUALITYGOOD = 0x100 - JPEG_QUALITYNORMAL = 0x200 - JPEG_QUALITYAVERAGE = 0x400 - JPEG_QUALITYBAD = 0x800 - JPEG_CMYK = 0x1000 - JPEG_PROGRESSIVE = 0x2000 - - #Others... - CUT_DEFAULT = 0 - DDS_DEFAULT = 0 - HDR_DEFAULT = 0 - IFF_DEFAULT = 0 - KOALA_DEFAULT = 0 - LBM_DEFAULT = 0 - MNG_DEFAULT = 0 - PCD_DEFAULT = 0 - PCD_BASE = 1 - PCD_BASEDIV4 = 2 - PCD_BASEDIV16 = 3 - PCX_DEFAULT = 0 - PNM_DEFAULT = 0 - PNM_SAVE_RAW = 0 - PNM_SAVE_ASCII = 1 - PSD_DEFAULT = 0 - RAS_DEFAULT = 0 - TARGA_DEFAULT = 0 - TARGA_LOAD_RGB888 = 1 - WBMP_DEFAULT = 0 - XBM_DEFAULT = 0 - -class METADATA_MODELS(object): - FIMD_NODATA = -1 - FIMD_COMMENTS = 0 - FIMD_EXIF_MAIN = 1 - FIMD_EXIF_EXIF = 2 - FIMD_EXIF_GPS = 3 - FIMD_EXIF_MAKERNOTE = 4 - FIMD_EXIF_INTEROP = 5 - FIMD_IPTC = 6 - FIMD_XMP = 7 - FIMD_GEOTIFF = 8 - FIMD_ANIMATION = 9 - FIMD_CUSTOM = 10 - -def read(filename, flags=0): - """Read an image to a numpy array of shape (width, height) for - greyscale images, or shape (width, height, nchannels) for RGB or - RGBA images. - - """ - bitmap = _read_bitmap(filename, flags) - try: - return _array_from_bitmap(bitmap) - finally: - _FI.FreeImage_Unload(bitmap) - -def read_multipage(filename, flags=0): - """Read a multipage image to a list of numpy arrays, where each - array is of shape (width, height) for greyscale images, or shape - (nchannels, width, height) for RGB or RGBA images. - - """ - filename = asbytes(filename) - ftype = _FI.FreeImage_GetFileType(filename, 0) - if ftype == -1: - raise ValueError('Cannot determine type of file %s' % filename) - create_new = False - read_only = True - keep_cache_in_memory = True - multibitmap = _FI.FreeImage_OpenMultiBitmap(ftype, filename, create_new, - read_only, keep_cache_in_memory, - flags) - if not multibitmap: - raise ValueError('Could not open %s as multi-page image.' % filename) - try: - multibitmap = ctypes.c_void_p(multibitmap) - pages = _FI.FreeImage_GetPageCount(multibitmap) - arrays = [] - for i in range(pages): - bitmap = _FI.FreeImage_LockPage(multibitmap, i) - bitmap = ctypes.c_void_p(bitmap) - try: - arrays.append(_array_from_bitmap(bitmap)) - finally: - _FI.FreeImage_UnlockPage(multibitmap, bitmap, False) - return arrays - finally: - _FI.FreeImage_CloseMultiBitmap(multibitmap, 0) - -def _read_bitmap(filename, flags): - """Load a file to a FreeImage bitmap pointer""" - filename = asbytes(filename) - ftype = _FI.FreeImage_GetFileType(filename, 0) - if ftype == -1: - raise ValueError('Cannot determine type of file %s' % filename) - bitmap = _FI.FreeImage_Load(ftype, filename, flags) - if not bitmap: - raise ValueError('Could not load file %s' % filename) - return ctypes.c_void_p(bitmap) - -def _wrap_bitmap_bits_in_array(bitmap, shape, dtype): - """Return an ndarray view on the data in a FreeImage bitmap. Only - valid for as long as the bitmap is loaded (if single page) / locked - in memory (if multipage). - - """ - pitch = _FI.FreeImage_GetPitch(bitmap) - height = shape[-1] - byte_size = height * pitch - itemsize = dtype.itemsize - - if len(shape) == 3: - strides = (itemsize, shape[0]*itemsize, pitch) - else: - strides = (itemsize, pitch) - bits = _FI.FreeImage_GetBits(bitmap) - array = numpy.ndarray(shape, dtype=dtype, - buffer=(ctypes.c_char*byte_size).from_address(bits), - strides=strides) - return array - -def _array_from_bitmap(bitmap): - """Convert a FreeImage bitmap pointer to a numpy array - - """ - dtype, shape = FI_TYPES.get_type_and_shape(bitmap) - array = _wrap_bitmap_bits_in_array(bitmap, shape, dtype) - # swizzle the color components and flip the scanlines to go from - # FreeImage's BGR[A] and upside-down internal memory format to something - # more normal - def n(arr): - return arr[..., ::-1].T - if len(shape) == 3 and _FI.FreeImage_IsLittleEndian() and \ - dtype.type == numpy.uint8: - b = n(array[0]) - g = n(array[1]) - r = n(array[2]) - if shape[0] == 3: - return numpy.dstack( (r, g, b) ) - elif shape[0] == 4: - a = n(array[3]) - return numpy.dstack( (r, g, b, a) ) - else: - raise ValueError('Cannot handle images of shape %s' % shape) - - # We need to copy because array does *not* own its memory - # after bitmap is freed. - return n(array).copy() - -def string_tag(bitmap, key, model=METADATA_MODELS.FIMD_EXIF_MAIN): - """Retrieve the value of a metadata tag with the given string key as a - string.""" - tag = ctypes.c_int() - if not _FI.FreeImage_GetMetadata(model, bitmap, str(key), - ctypes.byref(tag)): - return - char_ptr = ctypes.c_char * _FI.FreeImage_GetTagLength(tag) - return char_ptr.from_address(_FI.FreeImage_GetTagValue(tag)).raw() - -def write(array, filename, flags=0): - """Write a (width, height) or (width, height, nchannels) array to - a greyscale, RGB, or RGBA image, with file type deduced from the - filename. - - """ - filename = asbytes(filename) - ftype = _FI.FreeImage_GetFIFFromFilename(filename) - if ftype == -1: - raise ValueError('Cannot determine type for %s' % filename) - bitmap, fi_type = _array_to_bitmap(array) - try: - if fi_type == FI_TYPES.FIT_BITMAP: - can_write = _FI.FreeImage_FIFSupportsExportBPP(ftype, - _FI.FreeImage_GetBPP(bitmap)) - else: - can_write = _FI.FreeImage_FIFSupportsExportType(ftype, fi_type) - if not can_write: - raise TypeError('Cannot save image of this format ' - 'to this file type') - res = _FI.FreeImage_Save(ftype, bitmap, filename, flags) - if not res: - raise RuntimeError('Could not save image properly.') - finally: - _FI.FreeImage_Unload(bitmap) - -def write_multipage(arrays, filename, flags=0): - """Write a list of (width, height) or (nchannels, width, height) - arrays to a multipage greyscale, RGB, or RGBA image, with file type - deduced from the filename. - - """ - filename = asbytes(filename) - ftype = _FI.FreeImage_GetFIFFromFilename(filename) - if ftype == -1: - raise ValueError('Cannot determine type of file %s' % filename) - create_new = True - read_only = False - keep_cache_in_memory = True - multibitmap = _FI.FreeImage_OpenMultiBitmap(ftype, filename, - create_new, read_only, - keep_cache_in_memory, 0) - if not multibitmap: - raise ValueError('Could not open %s for writing multi-page image.' % - filename) - try: - multibitmap = ctypes.c_void_p(multibitmap) - for array in arrays: - bitmap, fi_type = _array_to_bitmap(array) - _FI.FreeImage_AppendPage(multibitmap, bitmap) - finally: - _FI.FreeImage_CloseMultiBitmap(multibitmap, flags) - -# 4-byte quads of 0,v,v,v from 0,0,0,0 to 0,255,255,255 -_GREY_PALETTE = numpy.arange(0, 0x01000000, 0x00010101, dtype=numpy.uint32) - -def _array_to_bitmap(array): - """Allocate a FreeImage bitmap and copy a numpy array into it. - - """ - shape = array.shape - dtype = array.dtype - r,c = shape[:2] - if len(shape) == 2: - n_channels = 1 - w_shape = (c,r) - elif len(shape) == 3: - n_channels = shape[2] - w_shape = (n_channels,c,r) - else: - n_channels = shape[0] - try: - fi_type = FI_TYPES.fi_types[(dtype.type, n_channels)] - except KeyError: - raise ValueError('Cannot write arrays of given type and shape.') - - itemsize = array.dtype.itemsize - bpp = 8 * itemsize * n_channels - bitmap = _FI.FreeImage_AllocateT(fi_type, c, r, bpp, 0, 0, 0) - if not bitmap: - raise RuntimeError('Could not allocate image for storage') - try: - def n(arr): # normalise to freeimage's in-memory format - return arr.T[:,::-1] - bitmap = ctypes.c_void_p(bitmap) - wrapped_array = _wrap_bitmap_bits_in_array(bitmap, w_shape, dtype) - # swizzle the color components and flip the scanlines to go to - # FreeImage's BGR[A] and upside-down internal memory format - if len(shape) == 3 and _FI.FreeImage_IsLittleEndian() and \ - dtype.type == numpy.uint8: - wrapped_array[0] = n(array[:,:,2]) - wrapped_array[1] = n(array[:,:,1]) - wrapped_array[2] = n(array[:,:,0]) - if shape[2] == 4: - wrapped_array[3] = n(array[:,:,3]) - else: - wrapped_array[:] = n(array) - if len(shape) == 2 and dtype.type == numpy.uint8: - palette = _FI.FreeImage_GetPalette(bitmap) - if not palette: - raise RuntimeError('Could not get image palette') - ctypes.memmove(palette, _GREY_PALETTE.ctypes.data, 1024) - return bitmap, fi_type - except: - _FI.FreeImage_Unload(bitmap) - raise - - -def imread(filename, as_grey=False): - """ - img = imread(filename, as_grey=False) - - Reads an image from file `filename` - - Parameters - ---------- - filename : file name - as_grey : Whether to convert to grey scale image (default: no) - Returns - ------- - img : ndarray - """ - img = read(filename) - if as_grey and len(img) == 3: - # these are the values that wikipedia says are typical - transform = numpy.array([ 0.30, 0.59, 0.11]) - return numpy.dot(img, transform) - return img - -def imsave(filename, img): - ''' - imsave(filename, img) - - Save image to disk - - Image type is inferred from filename - - Parameters - ---------- - filename : file name - img : image to be saved as nd array - ''' - write(img, filename) +import ctypes +import numpy +import sys +import os +import os.path +from numpy.compat import asbytes + +def _load_library(libname, loader_path): + """ A small fork of numpy.ctypeslib.load_library + to support windll. + """ + if ctypes.__version__ < '1.0.1': + import warnings + warnings.warn("All features of ctypes interface may not work " \ + "with ctypes < 1.0.1") + + ext = os.path.splitext(libname)[1] + if not ext: + # Try to load library with platform-specific name, otherwise + # default to libname.[so|pyd]. Sometimes, these files are built + # erroneously on non-linux platforms. + libname_ext = ['%s.so' % libname, '%s.pyd' % libname] + if sys.platform == 'win32': + libname_ext.insert(0, '%s.dll' % libname) + elif sys.platform == 'darwin': + libname_ext.insert(0, '%s.dylib' % libname) + else: + libname_ext = [libname] + + loader_path = os.path.abspath(loader_path) + if not os.path.isdir(loader_path): + libdir = os.path.dirname(loader_path) + else: + libdir = loader_path + for ln in libname_ext: + try: + libpath = os.path.join(libdir, ln) + if sys.platform == 'win32': + return ctypes.windll[libpath] + else: + return ctypes.cdll[libpath] + except OSError, e: + pass + + raise e + +lib_dirs = [os.path.dirname(__file__), + '/lib', + '/usr/lib', + '/usr/local/lib', + '/opt/local/lib', + ] + +if 'HOME' in os.environ: + lib_dirs.append(os.path.join(os.environ['HOME'], 'lib')) + +API = { + 'FreeImage_Load': (ctypes.c_void_p, + [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]), + 'FreeImage_GetWidth': (ctypes.c_uint, + [ctypes.c_void_p]), + 'FreeImage_GetHeight': (ctypes.c_uint, + [ctypes.c_void_p]), + 'FreeImage_GetImageType': (ctypes.c_uint, + [ctypes.c_void_p]), + 'FreeImage_GetBPP': (ctypes.c_uint, + [ctypes.c_void_p]), + 'FreeImage_GetPitch': (ctypes.c_uint, + [ctypes.c_void_p]), + 'FreeImage_GetBits': (ctypes.c_void_p, + [ctypes.c_void_p]), + } + +# Albert's ctypes pattern +def register_api(lib,api): + for f, (restype, argtypes) in api.items(): + func = getattr(lib, f) + func.restype = restype + func.argtypes = argtypes + +_FI = None +for d in lib_dirs: + for libname in ('freeimage', 'FreeImage', + 'libfreeimage', 'libFreeImage'): + try: + _FI = _load_library(libname, d) + except OSError: + pass + else: + break + + if _FI is not None: + break + +if not _FI: + raise OSError('Could not find libFreeImage in any of the following ' + 'directories: \'%s\'' % '\', \''.join(lib_dirs)) + +register_api(_FI, API) + +if sys.platform == 'win32': + _functype = ctypes.WINFUNCTYPE +else: + _functype = ctypes.CFUNCTYPE + +@_functype(None, ctypes.c_int, ctypes.c_char_p) +def _error_handler(fif, message): + raise RuntimeError('FreeImage error: %s' % message) + +_FI.FreeImage_SetOutputMessage(_error_handler) + +class FI_TYPES(object): + FIT_UNKNOWN = 0 + FIT_BITMAP = 1 + FIT_UINT16 = 2 + FIT_INT16 = 3 + FIT_UINT32 = 4 + FIT_INT32 = 5 + FIT_FLOAT = 6 + FIT_DOUBLE = 7 + FIT_COMPLEX = 8 + FIT_RGB16 = 9 + FIT_RGBA16 = 10 + FIT_RGBF = 11 + FIT_RGBAF = 12 + + dtypes = { + FIT_BITMAP: numpy.uint8, + FIT_UINT16: numpy.uint16, + FIT_INT16: numpy.int16, + FIT_UINT32: numpy.uint32, + FIT_INT32: numpy.int32, + FIT_FLOAT: numpy.float32, + FIT_DOUBLE: numpy.float64, + FIT_COMPLEX: numpy.complex128, + FIT_RGB16: numpy.uint16, + FIT_RGBA16: numpy.uint16, + FIT_RGBF: numpy.float32, + FIT_RGBAF: numpy.float32 + } + + fi_types = { + (numpy.uint8, 1): FIT_BITMAP, + (numpy.uint8, 3): FIT_BITMAP, + (numpy.uint8, 4): FIT_BITMAP, + (numpy.uint16, 1): FIT_UINT16, + (numpy.int16, 1): FIT_INT16, + (numpy.uint32, 1): FIT_UINT32, + (numpy.int32, 1): FIT_INT32, + (numpy.float32, 1): FIT_FLOAT, + (numpy.float64, 1): FIT_DOUBLE, + (numpy.complex128, 1): FIT_COMPLEX, + (numpy.uint16, 3): FIT_RGB16, + (numpy.uint16, 4): FIT_RGBA16, + (numpy.float32, 3): FIT_RGBF, + (numpy.float32, 4): FIT_RGBAF + } + + extra_dims = { + FIT_UINT16: [], + FIT_INT16: [], + FIT_UINT32: [], + FIT_INT32: [], + FIT_FLOAT: [], + FIT_DOUBLE: [], + FIT_COMPLEX: [], + FIT_RGB16: [3], + FIT_RGBA16: [4], + FIT_RGBF: [3], + FIT_RGBAF: [4] + } + + @classmethod + def get_type_and_shape(cls, bitmap): + w = _FI.FreeImage_GetWidth(bitmap) + h = _FI.FreeImage_GetHeight(bitmap) + fi_type = _FI.FreeImage_GetImageType(bitmap) + if not fi_type: + raise ValueError('Unknown image pixel type') + dtype = cls.dtypes[fi_type] + if fi_type == cls.FIT_BITMAP: + bpp = _FI.FreeImage_GetBPP(bitmap) + if bpp == 8: + extra_dims = [] + elif bpp == 24: + extra_dims = [3] + elif bpp == 32: + extra_dims = [4] + else: + raise ValueError('Cannot convert %d BPP bitmap' % bpp) + else: + extra_dims = cls.extra_dims[fi_type] + return numpy.dtype(dtype), extra_dims + [w, h] + +class IO_FLAGS(object): + #Bmp + BMP_DEFAULT = 0 + BMP_SAVE_RLE = 1 + + #Png + PNG_DEFAULT = 0 + PNG_IGNOREGAMMA = 1 + + #Gif + GIF_DEFAULT = 0 + GIF_LOAD256 = 1 + GIF_PLAYBACK = 2 + + #Ico + ICO_DEFAULT = 0 + ICO_MAKEALPHA = 1 + + #Tiff + TIFF_DEFAULT = 0 + TIFF_CMYK = 0x0001 + TIFF_NONE = 0x0800 + TIFF_PACKBITS = 0x0100 + TIFF_DEFLATE = 0x0200 + TIFF_ADOBE_DEFLATE = 0x0400 + TIFF_CCITTFAX3 = 0x1000 + TIFF_CCITTFAX4 = 0x2000 + TIFF_LZW = 0x4000 + TIFF_JPEG = 0x8000 + + #Jpeg + JPEG_DEFAULT = 0 + JPEG_FAST = 1 + JPEG_ACCURATE = 2 + JPEG_QUALITYSUPERB = 0x80 + JPEG_QUALITYGOOD = 0x100 + JPEG_QUALITYNORMAL = 0x200 + JPEG_QUALITYAVERAGE = 0x400 + JPEG_QUALITYBAD = 0x800 + JPEG_CMYK = 0x1000 + JPEG_PROGRESSIVE = 0x2000 + + #Others... + CUT_DEFAULT = 0 + DDS_DEFAULT = 0 + HDR_DEFAULT = 0 + IFF_DEFAULT = 0 + KOALA_DEFAULT = 0 + LBM_DEFAULT = 0 + MNG_DEFAULT = 0 + PCD_DEFAULT = 0 + PCD_BASE = 1 + PCD_BASEDIV4 = 2 + PCD_BASEDIV16 = 3 + PCX_DEFAULT = 0 + PNM_DEFAULT = 0 + PNM_SAVE_RAW = 0 + PNM_SAVE_ASCII = 1 + PSD_DEFAULT = 0 + RAS_DEFAULT = 0 + TARGA_DEFAULT = 0 + TARGA_LOAD_RGB888 = 1 + WBMP_DEFAULT = 0 + XBM_DEFAULT = 0 + +class METADATA_MODELS(object): + FIMD_NODATA = -1 + FIMD_COMMENTS = 0 + FIMD_EXIF_MAIN = 1 + FIMD_EXIF_EXIF = 2 + FIMD_EXIF_GPS = 3 + FIMD_EXIF_MAKERNOTE = 4 + FIMD_EXIF_INTEROP = 5 + FIMD_IPTC = 6 + FIMD_XMP = 7 + FIMD_GEOTIFF = 8 + FIMD_ANIMATION = 9 + FIMD_CUSTOM = 10 + +def read(filename, flags=0): + """Read an image to a numpy array of shape (width, height) for + greyscale images, or shape (width, height, nchannels) for RGB or + RGBA images. + + """ + bitmap = _read_bitmap(filename, flags) + try: + return _array_from_bitmap(bitmap) + finally: + _FI.FreeImage_Unload(bitmap) + +def read_multipage(filename, flags=0): + """Read a multipage image to a list of numpy arrays, where each + array is of shape (width, height) for greyscale images, or shape + (nchannels, width, height) for RGB or RGBA images. + + """ + filename = asbytes(filename) + ftype = _FI.FreeImage_GetFileType(filename, 0) + if ftype == -1: + raise ValueError('Cannot determine type of file %s' % filename) + create_new = False + read_only = True + keep_cache_in_memory = True + multibitmap = _FI.FreeImage_OpenMultiBitmap(ftype, filename, create_new, + read_only, keep_cache_in_memory, + flags) + if not multibitmap: + raise ValueError('Could not open %s as multi-page image.' % filename) + try: + multibitmap = ctypes.c_void_p(multibitmap) + pages = _FI.FreeImage_GetPageCount(multibitmap) + arrays = [] + for i in range(pages): + bitmap = _FI.FreeImage_LockPage(multibitmap, i) + bitmap = ctypes.c_void_p(bitmap) + try: + arrays.append(_array_from_bitmap(bitmap)) + finally: + _FI.FreeImage_UnlockPage(multibitmap, bitmap, False) + return arrays + finally: + _FI.FreeImage_CloseMultiBitmap(multibitmap, 0) + +def _read_bitmap(filename, flags): + """Load a file to a FreeImage bitmap pointer""" + filename = asbytes(filename) + ftype = _FI.FreeImage_GetFileType(filename, 0) + if ftype == -1: + raise ValueError('Cannot determine type of file %s' % filename) + bitmap = _FI.FreeImage_Load(ftype, filename, flags) + if not bitmap: + raise ValueError('Could not load file %s' % filename) + return ctypes.c_void_p(bitmap) + +def _wrap_bitmap_bits_in_array(bitmap, shape, dtype): + """Return an ndarray view on the data in a FreeImage bitmap. Only + valid for as long as the bitmap is loaded (if single page) / locked + in memory (if multipage). + + """ + pitch = _FI.FreeImage_GetPitch(bitmap) + height = shape[-1] + byte_size = height * pitch + itemsize = dtype.itemsize + + if len(shape) == 3: + strides = (itemsize, shape[0]*itemsize, pitch) + else: + strides = (itemsize, pitch) + bits = _FI.FreeImage_GetBits(bitmap) + array = numpy.ndarray(shape, dtype=dtype, + buffer=(ctypes.c_char*byte_size).from_address(bits), + strides=strides) + return array + +def _array_from_bitmap(bitmap): + """Convert a FreeImage bitmap pointer to a numpy array + + """ + dtype, shape = FI_TYPES.get_type_and_shape(bitmap) + array = _wrap_bitmap_bits_in_array(bitmap, shape, dtype) + # swizzle the color components and flip the scanlines to go from + # FreeImage's BGR[A] and upside-down internal memory format to something + # more normal + def n(arr): + return arr[..., ::-1].T + if len(shape) == 3 and _FI.FreeImage_IsLittleEndian() and \ + dtype.type == numpy.uint8: + b = n(array[0]) + g = n(array[1]) + r = n(array[2]) + if shape[0] == 3: + return numpy.dstack( (r, g, b) ) + elif shape[0] == 4: + a = n(array[3]) + return numpy.dstack( (r, g, b, a) ) + else: + raise ValueError('Cannot handle images of shape %s' % shape) + + # We need to copy because array does *not* own its memory + # after bitmap is freed. + return n(array).copy() + +def string_tag(bitmap, key, model=METADATA_MODELS.FIMD_EXIF_MAIN): + """Retrieve the value of a metadata tag with the given string key as a + string.""" + tag = ctypes.c_int() + if not _FI.FreeImage_GetMetadata(model, bitmap, str(key), + ctypes.byref(tag)): + return + char_ptr = ctypes.c_char * _FI.FreeImage_GetTagLength(tag) + return char_ptr.from_address(_FI.FreeImage_GetTagValue(tag)).raw() + +def write(array, filename, flags=0): + """Write a (width, height) or (width, height, nchannels) array to + a greyscale, RGB, or RGBA image, with file type deduced from the + filename. + + """ + filename = asbytes(filename) + ftype = _FI.FreeImage_GetFIFFromFilename(filename) + if ftype == -1: + raise ValueError('Cannot determine type for %s' % filename) + bitmap, fi_type = _array_to_bitmap(array) + try: + if fi_type == FI_TYPES.FIT_BITMAP: + can_write = _FI.FreeImage_FIFSupportsExportBPP(ftype, + _FI.FreeImage_GetBPP(bitmap)) + else: + can_write = _FI.FreeImage_FIFSupportsExportType(ftype, fi_type) + if not can_write: + raise TypeError('Cannot save image of this format ' + 'to this file type') + res = _FI.FreeImage_Save(ftype, bitmap, filename, flags) + if not res: + raise RuntimeError('Could not save image properly.') + finally: + _FI.FreeImage_Unload(bitmap) + +def write_multipage(arrays, filename, flags=0): + """Write a list of (width, height) or (nchannels, width, height) + arrays to a multipage greyscale, RGB, or RGBA image, with file type + deduced from the filename. + + """ + filename = asbytes(filename) + ftype = _FI.FreeImage_GetFIFFromFilename(filename) + if ftype == -1: + raise ValueError('Cannot determine type of file %s' % filename) + create_new = True + read_only = False + keep_cache_in_memory = True + multibitmap = _FI.FreeImage_OpenMultiBitmap(ftype, filename, + create_new, read_only, + keep_cache_in_memory, 0) + if not multibitmap: + raise ValueError('Could not open %s for writing multi-page image.' % + filename) + try: + multibitmap = ctypes.c_void_p(multibitmap) + for array in arrays: + bitmap, fi_type = _array_to_bitmap(array) + _FI.FreeImage_AppendPage(multibitmap, bitmap) + finally: + _FI.FreeImage_CloseMultiBitmap(multibitmap, flags) + +# 4-byte quads of 0,v,v,v from 0,0,0,0 to 0,255,255,255 +_GREY_PALETTE = numpy.arange(0, 0x01000000, 0x00010101, dtype=numpy.uint32) + +def _array_to_bitmap(array): + """Allocate a FreeImage bitmap and copy a numpy array into it. + + """ + shape = array.shape + dtype = array.dtype + r,c = shape[:2] + if len(shape) == 2: + n_channels = 1 + w_shape = (c,r) + elif len(shape) == 3: + n_channels = shape[2] + w_shape = (n_channels,c,r) + else: + n_channels = shape[0] + try: + fi_type = FI_TYPES.fi_types[(dtype.type, n_channels)] + except KeyError: + raise ValueError('Cannot write arrays of given type and shape.') + + itemsize = array.dtype.itemsize + bpp = 8 * itemsize * n_channels + bitmap = _FI.FreeImage_AllocateT(fi_type, c, r, bpp, 0, 0, 0) + if not bitmap: + raise RuntimeError('Could not allocate image for storage') + try: + def n(arr): # normalise to freeimage's in-memory format + return arr.T[:,::-1] + bitmap = ctypes.c_void_p(bitmap) + wrapped_array = _wrap_bitmap_bits_in_array(bitmap, w_shape, dtype) + # swizzle the color components and flip the scanlines to go to + # FreeImage's BGR[A] and upside-down internal memory format + if len(shape) == 3 and _FI.FreeImage_IsLittleEndian() and \ + dtype.type == numpy.uint8: + wrapped_array[0] = n(array[:,:,2]) + wrapped_array[1] = n(array[:,:,1]) + wrapped_array[2] = n(array[:,:,0]) + if shape[2] == 4: + wrapped_array[3] = n(array[:,:,3]) + else: + wrapped_array[:] = n(array) + if len(shape) == 2 and dtype.type == numpy.uint8: + palette = _FI.FreeImage_GetPalette(bitmap) + if not palette: + raise RuntimeError('Could not get image palette') + ctypes.memmove(palette, _GREY_PALETTE.ctypes.data, 1024) + return bitmap, fi_type + except: + _FI.FreeImage_Unload(bitmap) + raise + + +def imread(filename, as_grey=False): + """ + img = imread(filename, as_grey=False) + + Reads an image from file `filename` + + Parameters + ---------- + filename : file name + as_grey : Whether to convert to grey scale image (default: no) + Returns + ------- + img : ndarray + """ + img = read(filename) + if as_grey and len(img) == 3: + # these are the values that wikipedia says are typical + transform = numpy.array([ 0.30, 0.59, 0.11]) + return numpy.dot(img, transform) + return img + +def imsave(filename, img): + ''' + imsave(filename, img) + + Save image to disk + + Image type is inferred from filename + + Parameters + ---------- + filename : file name + img : image to be saved as nd array + ''' + write(img, filename) From fc17f50d8bf66000b456da3af0986644b5e4dd51 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 19:55:12 +0200 Subject: [PATCH 03/14] Rework exception handling logic in freeimage_plugin.py --- scikits/image/io/_plugins/freeimage_plugin.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scikits/image/io/_plugins/freeimage_plugin.py b/scikits/image/io/_plugins/freeimage_plugin.py index d9492f83..8ae5c408 100644 --- a/scikits/image/io/_plugins/freeimage_plugin.py +++ b/scikits/image/io/_plugins/freeimage_plugin.py @@ -32,17 +32,20 @@ def _load_library(libname, loader_path): libdir = os.path.dirname(loader_path) else: libdir = loader_path + if sys.platform == 'win32': + loader = ctypes.windll + else: + loader = ctypes.cdll for ln in libname_ext: try: - libpath = os.path.join(libdir, ln) - if sys.platform == 'win32': - return ctypes.windll[libpath] - else: - return ctypes.cdll[libpath] - except OSError, e: + return loader[os.path.join(libdir, ln)] + except OSError: pass + # TODO: Setup errno and other bits to something correctly + raise OSError( + 'Unable to find library in any of the foloowing paths: %s' % + [os.path.join(libdir, ln) for ln in libname_ext]) - raise e lib_dirs = [os.path.dirname(__file__), '/lib', From 12c1829b78da1d8dfe9e67a4bcf561224557e4f8 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 19:56:06 +0200 Subject: [PATCH 04/14] Fix logic error in _load_library --- scikits/image/io/_plugins/freeimage_plugin.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/scikits/image/io/_plugins/freeimage_plugin.py b/scikits/image/io/_plugins/freeimage_plugin.py index 8ae5c408..d933eaef 100644 --- a/scikits/image/io/_plugins/freeimage_plugin.py +++ b/scikits/image/io/_plugins/freeimage_plugin.py @@ -32,19 +32,18 @@ def _load_library(libname, loader_path): libdir = os.path.dirname(loader_path) else: libdir = loader_path - if sys.platform == 'win32': - loader = ctypes.windll - else: - loader = ctypes.cdll - for ln in libname_ext: - try: - return loader[os.path.join(libdir, ln)] - except OSError: - pass - # TODO: Setup errno and other bits to something correctly - raise OSError( - 'Unable to find library in any of the foloowing paths: %s' % - [os.path.join(libdir, ln) for ln in libname_ext]) + if sys.platform == 'win32': + loader = ctypes.windll + else: + loader = ctypes.cdll + for ln in libname_ext: + try: + return loader[os.path.join(libdir, ln)] + except OSError: + pass + # TODO: Setup errno and other bits to something correctly + raise OSError('Unable to find library in any of the foloowing paths: %s' % + [os.path.join(libdir, ln) for ln in libname_ext]) lib_dirs = [os.path.dirname(__file__), From f64ddb1fd16000497ce137b2771b0753ef2a9d07 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 21:27:36 +0200 Subject: [PATCH 05/14] replace TemporaryFile with NamedTemporaryFile, for compatability with later python versions --- scikits/image/io/tests/test_sift.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scikits/image/io/tests/test_sift.py b/scikits/image/io/tests/test_sift.py index 9d04fa35..f2e9da95 100644 --- a/scikits/image/io/tests/test_sift.py +++ b/scikits/image/io/tests/test_sift.py @@ -2,12 +2,12 @@ import numpy as np from nose.tools import * from numpy.testing import assert_array_equal, assert_array_almost_equal, \ assert_equal, run_module_suite -from tempfile import TemporaryFile +from tempfile import NamedTemporaryFile from scikits.image.io import load_sift, load_surf def test_load_sift(): - f = TemporaryFile() + f = NamedTemporaryFile(delete=False) fname = f.name f.close() f = open(fname, 'wb') @@ -39,7 +39,7 @@ def test_load_sift(): assert_equal(features['column'][1], 99.75) def test_load_surf(): - f = TemporaryFile() + f = NamedTemporaryFile(delete=False) fname = f.name f.close() f = open(fname, 'wb') From 2409bbce9f7c578b6baa099049172839ac57270f Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 22:18:47 +0200 Subject: [PATCH 06/14] Only call MultiImage if PIL is available to ensure nose handles this case properly --- scikits/image/io/tests/test_collection.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scikits/image/io/tests/test_collection.py b/scikits/image/io/tests/test_collection.py index 2f74a89a..71fc0fde 100644 --- a/scikits/image/io/tests/test_collection.py +++ b/scikits/image/io/tests/test_collection.py @@ -64,7 +64,8 @@ class TestMultiImage(): def setUp(self): # This multipage TIF file was created with imagemagick: # convert im1.tif im2.tif -adjoin multipage.tif - self.img = MultiImage(os.path.join(data_dir, 'multipage.tif')) + if PIL_available: + self.img = MultiImage(os.path.join(data_dir, 'multipage.tif')) @skipif(not PIL_available) def test_len(self): From 1a48914811df2bf2861e7cc4fe6e7dc08a19e845 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Jul 2011 22:52:55 +0200 Subject: [PATCH 07/14] Remove temporary files --- scikits/image/io/tests/test_sift.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scikits/image/io/tests/test_sift.py b/scikits/image/io/tests/test_sift.py index f2e9da95..02e99856 100644 --- a/scikits/image/io/tests/test_sift.py +++ b/scikits/image/io/tests/test_sift.py @@ -3,6 +3,7 @@ from nose.tools import * from numpy.testing import assert_array_equal, assert_array_almost_equal, \ assert_equal, run_module_suite from tempfile import NamedTemporaryFile +import os from scikits.image.io import load_sift, load_surf @@ -32,6 +33,7 @@ def test_load_sift(): f = open(fname, 'rb') features = load_sift(f) f.close() + os.remove(fname) assert_equal(len(features), 2) assert_equal(len(features['data'][0]), 128) @@ -51,6 +53,7 @@ def test_load_surf(): f = open(fname, 'rb') features = load_surf(f) f.close() + os.remove(fname) assert_equal(len(features), 2) assert_equal(len(features['data'][0]), 64) From 26402a7e67266a47befe90bb736b4f35ba1d3c8a Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 16 Jul 2011 16:39:33 +0200 Subject: [PATCH 08/14] Replace old raise form --- scikits/image/color/colorconv.py | 6 +++--- scikits/image/io/collection.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 97b3af69..92c9a0cc 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -95,9 +95,9 @@ def convert_colorspace(arr, fromspace, tospace): fromspace = fromspace.upper() tospace = tospace.upper() if not fromspace in fromdict.keys(): - raise ValueError, 'fromspace needs to be one of %s'%fromdict.keys() + raise ValueError('fromspace needs to be one of %s'%fromdict.keys()) if not tospace in todict.keys(): - raise ValueError, 'tospace needs to be one of %s'%todict.keys() + raise ValueError('tospace needs to be one of %s'%todict.keys()) return todict[tospace](fromdict[fromspace](arr)) @@ -108,7 +108,7 @@ def _prepare_colorarray(arr, dtype=np.float32): if arr.ndim != 3 or arr.shape[2] != 3: msg = "the input array must be have a shape == (.,.,3))" - raise ValueError, msg + raise ValueError(msg) return arr.astype(dtype) diff --git a/scikits/image/io/collection.py b/scikits/image/io/collection.py index fb55b1a9..eb265d1e 100644 --- a/scikits/image/io/collection.py +++ b/scikits/image/io/collection.py @@ -128,7 +128,7 @@ class MultiImage(object): if -numframes <= n < numframes: n = n % numframes else: - raise IndexError, "There are only %s frames in the image"%numframes + raise IndexError("There are only %s frames in the image"%numframes) if self.conserve_memory: if not self._cached == n: @@ -289,7 +289,7 @@ class ImageCollection(object): if -num <= n < num: n = n % num else: - raise IndexError, "There are only %s images in the collection"%num + raise IndexError("There are only %s images in the collection"%num) return n def __iter__(self): From 8ceb250beeaaaafdc26bc5c859d9695d6afca352 Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 16 Jul 2011 21:53:30 +0200 Subject: [PATCH 09/14] Return correct type for as_grey with freeimage --- scikits/image/io/_plugins/freeimage_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikits/image/io/_plugins/freeimage_plugin.py b/scikits/image/io/_plugins/freeimage_plugin.py index d933eaef..0109e371 100644 --- a/scikits/image/io/_plugins/freeimage_plugin.py +++ b/scikits/image/io/_plugins/freeimage_plugin.py @@ -514,7 +514,7 @@ def imread(filename, as_grey=False): if as_grey and len(img) == 3: # these are the values that wikipedia says are typical transform = numpy.array([ 0.30, 0.59, 0.11]) - return numpy.dot(img, transform) + return numpy.dot(img, transform).astype('uint8') return img def imsave(filename, img): From 8f16ca124288da9f0c3e826f36286209bb1c4015 Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 16 Jul 2011 21:55:57 +0200 Subject: [PATCH 10/14] Pass as_grey to the imread plugins --- scikits/image/io/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikits/image/io/io.py b/scikits/image/io/io.py index ad83577c..dbcd9a34 100644 --- a/scikits/image/io/io.py +++ b/scikits/image/io/io.py @@ -69,7 +69,7 @@ def imread(fname, as_grey=False, plugin=None, flatten=None, if flatten is not None: as_grey = flatten - img = call_plugin('imread', fname, plugin=plugin, **plugin_args) + img = call_plugin('imread', fname, as_grey, plugin=plugin, **plugin_args) if as_grey and getattr(img, 'ndim', 0) >= 3: img = rgb2grey(img) From e7a69bbfc532559a3bd92c09fd48072a78bec909 Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 16 Jul 2011 22:14:00 +0200 Subject: [PATCH 11/14] Skip pil_plugin tests if PIL isn't available --- scikits/image/io/tests/test_pil.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scikits/image/io/tests/test_pil.py b/scikits/image/io/tests/test_pil.py index 501355d5..2115b795 100644 --- a/scikits/image/io/tests/test_pil.py +++ b/scikits/image/io/tests/test_pil.py @@ -1,15 +1,24 @@ import os.path import numpy as np from numpy.testing import * +from numpy.testing.decorators import skipif from tempfile import NamedTemporaryFile from scikits.image import data_dir from scikits.image.io import imread, imsave, use_plugin -from scikits.image.io._plugins.pil_plugin import _palette_is_grayscale -use_plugin('pil') +try: + from PIL import Image + from scikits.image.io._plugins.pil_plugin import _palette_is_grayscale + use_plugin('pil') +except ImportError: + PIL_available = False +else: + PIL_available = True + +@skipif(not PIL_available) def test_imread_flatten(): # a color image is flattened img = imread(os.path.join(data_dir, 'color.png'), flatten=True) @@ -19,12 +28,14 @@ def test_imread_flatten(): # check that flattening does not occur for an image that is grey already. assert np.sctype2char(img.dtype) in np.typecodes['AllInteger'] +@skipif(not PIL_available) def test_imread_palette(): img = imread(os.path.join(data_dir, 'palette_gray.png')) assert img.ndim == 2 img = imread(os.path.join(data_dir, 'palette_color.png')) assert img.ndim == 3 +@skipif(not PIL_available) def test_palette_is_gray(): from PIL import Image gray = Image.open(os.path.join(data_dir, 'palette_gray.png')) @@ -42,6 +53,7 @@ class TestSave: assert_array_almost_equal((x * scaling).astype(np.int32), y) + @skipif(not PIL_available) def test_imsave_roundtrip(self): for shape in [(10, 10), (10, 10, 3), (10, 10, 4)]: for dtype in (np.uint8, np.uint16, np.float32, np.float64): From b5c85b6eb81f0ef76078dd2e6c8db1efa3e51d6d Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 16 Jul 2011 23:01:42 +0200 Subject: [PATCH 12/14] Don't rely on pil for plugin_priority test. Skip test if neither pil or freeimage are available --- scikits/image/io/tests/test_plugin.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/scikits/image/io/tests/test_plugin.py b/scikits/image/io/tests/test_plugin.py index d4955397..305acf5e 100644 --- a/scikits/image/io/tests/test_plugin.py +++ b/scikits/image/io/tests/test_plugin.py @@ -2,9 +2,24 @@ from numpy.testing import * from scikits.image import io from scikits.image.io._plugins import plugin +from numpy.testing.decorators import skipif from copy import deepcopy +try: + io.use_plugin('pil') + PIL_available = True + priority_plugin = 'pil' +except ImportError: + PIL_available = False + +try: + io.use_plugin('freeimage') + FI_available = True + priority_plugin = 'freeimage' +except ImportError: + FI_available = False + def setup_module(self): self.backup_plugin_store = deepcopy(plugin.plugin_store) @@ -34,11 +49,12 @@ class TestPlugin: def test_failed_use(self): plugin.use('asd') + @skipif(not PIL_available and not FI_available) def test_use_priority(self): - plugin.use('pil') + plugin.use(priority_plugin) plug, func = plugin.plugin_store['imread'][0] print(plugin.plugin_store) - assert_equal(plug, 'pil') + assert_equal(plug, priority_plugin) plugin.use('test') plug, func = plugin.plugin_store['imread'][0] From 435a2dab55af647c52a73b28c9d7b2777e25a706 Mon Sep 17 00:00:00 2001 From: Neil Date: Sun, 17 Jul 2011 00:14:09 +0200 Subject: [PATCH 13/14] Revert "Pass as_grey to the imread plugins" This reverts commit 8f16ca124288da9f0c3e826f36286209bb1c4015, as the as_grey keyword should disappear from the plugins. --- scikits/image/io/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikits/image/io/io.py b/scikits/image/io/io.py index dbcd9a34..ad83577c 100644 --- a/scikits/image/io/io.py +++ b/scikits/image/io/io.py @@ -69,7 +69,7 @@ def imread(fname, as_grey=False, plugin=None, flatten=None, if flatten is not None: as_grey = flatten - img = call_plugin('imread', fname, as_grey, plugin=plugin, **plugin_args) + img = call_plugin('imread', fname, plugin=plugin, **plugin_args) if as_grey and getattr(img, 'ndim', 0) >= 3: img = rgb2grey(img) From a595f267fd02347c2226149789267406a31e4831 Mon Sep 17 00:00:00 2001 From: Neil Date: Sun, 17 Jul 2011 00:21:43 +0200 Subject: [PATCH 14/14] Remove as_grey from plugins --- scikits/image/io/_plugins/fits_plugin.py | 4 +--- scikits/image/io/_plugins/freeimage_plugin.py | 9 ++------- scikits/image/io/_plugins/pil_plugin.py | 6 +----- scikits/image/io/_plugins/test_plugin.py | 2 +- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/scikits/image/io/_plugins/fits_plugin.py b/scikits/image/io/_plugins/fits_plugin.py index 5c673bb3..84215d96 100644 --- a/scikits/image/io/_plugins/fits_plugin.py +++ b/scikits/image/io/_plugins/fits_plugin.py @@ -11,15 +11,13 @@ except ImportError: "for further instructions.") -def imread(fname, as_grey=True, dtype=None): +def imread(fname, dtype=None): """Load an image from a FITS file. Parameters ---------- fname : string Image file name, e.g. ``test.fits``. - as_grey : bool - For FITS images, this is ignored (treated as True). dtype : dtype, optional For FITS, this argument is ignored because Stefan is planning on removing the dtype argument from imread anyway. diff --git a/scikits/image/io/_plugins/freeimage_plugin.py b/scikits/image/io/_plugins/freeimage_plugin.py index 0109e371..8c67c888 100644 --- a/scikits/image/io/_plugins/freeimage_plugin.py +++ b/scikits/image/io/_plugins/freeimage_plugin.py @@ -496,25 +496,20 @@ def _array_to_bitmap(array): raise -def imread(filename, as_grey=False): +def imread(filename): """ - img = imread(filename, as_grey=False) + img = imread(filename) Reads an image from file `filename` Parameters ---------- filename : file name - as_grey : Whether to convert to grey scale image (default: no) Returns ------- img : ndarray """ img = read(filename) - if as_grey and len(img) == 3: - # these are the values that wikipedia says are typical - transform = numpy.array([ 0.30, 0.59, 0.11]) - return numpy.dot(img, transform).astype('uint8') return img def imsave(filename, img): diff --git a/scikits/image/io/_plugins/pil_plugin.py b/scikits/image/io/_plugins/pil_plugin.py index 5b87b34b..7fc3a0fc 100644 --- a/scikits/image/io/_plugins/pil_plugin.py +++ b/scikits/image/io/_plugins/pil_plugin.py @@ -9,7 +9,7 @@ except ImportError: "Please refer to http://pypi.python.org/pypi/PIL/ " "for further instructions.") -def imread(fname, as_grey=False, dtype=None): +def imread(fname, dtype=None): """Load an image from file. """ @@ -20,10 +20,6 @@ def imread(fname, as_grey=False, dtype=None): else: im = im.convert('RGB') - if as_grey and not \ - im.mode in ('1', 'L', 'I', 'F', 'I;16', 'I;16L', 'I;16B', 'LA'): - im = im.convert('F') - if 'A' in im.mode: im = im.convert('RGBA') diff --git a/scikits/image/io/_plugins/test_plugin.py b/scikits/image/io/_plugins/test_plugin.py index d17a91ec..2956f14f 100644 --- a/scikits/image/io/_plugins/test_plugin.py +++ b/scikits/image/io/_plugins/test_plugin.py @@ -1,7 +1,7 @@ # This mock-up is called by ../tests/test_plugin.py # to verify the behaviour of the plugin infrastructure -def imread(fname, as_grey=False, dtype=None): +def imread(fname, dtype=None): assert fname == 'test.png' assert dtype == 'i4'