From 12e67e781ec728a6b81b08b9d514d098204b7831 Mon Sep 17 00:00:00 2001 From: Zach Pincus Date: Thu, 2 Feb 2012 11:05:27 -0500 Subject: [PATCH] ENH: Clarify FreeImage IO flags, improve tests, and fix documentation --- skimage/io/_plugins/freeimage_plugin.py | 169 ++++++++++++++++-------- skimage/io/_plugins/test_freeimage.py | 26 +++- 2 files changed, 133 insertions(+), 62 deletions(-) diff --git a/skimage/io/_plugins/freeimage_plugin.py b/skimage/io/_plugins/freeimage_plugin.py index a549d6c6..7f071595 100644 --- a/skimage/io/_plugins/freeimage_plugin.py +++ b/skimage/io/_plugins/freeimage_plugin.py @@ -214,70 +214,115 @@ class FI_TYPES(object): return numpy.dtype(dtype), extra_dims + [w, h] class IO_FLAGS(object): - #Bmp + FIF_LOAD_NOPIXELS = 0x8000 # loading: load the image header only + # (not supported by all plugins) + 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 + EXR_DEFAULT = 0 # save data as half with piz-based wavelet compression + EXR_FLOAT = 0x0001 # save data as float instead of as half (not recommended) + EXR_NONE = 0x0002 # save with no compression + EXR_ZIP = 0x0004 # save with zlib compression, in blocks of 16 scan lines + EXR_PIZ = 0x0008 # save with piz-based wavelet compression + EXR_PXR24 = 0x0010 # save with lossy 24-bit float compression + EXR_B44 = 0x0020 # save with lossy 44% float compression + # - goes to 22% when combined with EXR_LC + EXR_LC = 0x0040 # save images with one luminance and two chroma channels, + # rather than as RGB (lossy compression) + FAXG3_DEFAULT = 0 + GIF_DEFAULT = 0 + GIF_LOAD256 = 1 # Load the image as a 256 color image with ununsed + # palette entries, if it's 16 or 2 color + GIF_PLAYBACK = 2 # 'Play' the GIF to generate each frame (as 32bpp) + # instead of returning raw frame data when loading HDR_DEFAULT = 0 + ICO_DEFAULT = 0 + ICO_MAKEALPHA = 1 # convert to 32bpp and create an alpha channel from the + # AND-mask when loading IFF_DEFAULT = 0 + J2K_DEFAULT = 0 # save with a 16:1 rate + JP2_DEFAULT = 0 # save with a 16:1 rate + JPEG_DEFAULT = 0 # loading (see JPEG_FAST); + # saving (see JPEG_QUALITYGOOD|JPEG_SUBSAMPLING_420) + JPEG_FAST = 0x0001 # load the file as fast as possible, + # sacrificing some quality + JPEG_ACCURATE = 0x0002 # load the file with the best quality, + # sacrificing some speed + JPEG_CMYK = 0x0004 # load separated CMYK "as is" + # (use | to combine with other load flags) + JPEG_EXIFROTATE = 0x0008 # load and rotate according to + # Exif 'Orientation' tag if available + JPEG_QUALITYSUPERB = 0x80 # save with superb quality (100:1) + JPEG_QUALITYGOOD = 0x0100 # save with good quality (75:1) + JPEG_QUALITYNORMAL = 0x0200 # save with normal quality (50:1) + JPEG_QUALITYAVERAGE = 0x0400 # save with average quality (25:1) + JPEG_QUALITYBAD = 0x0800 # save with bad quality (10:1) + JPEG_PROGRESSIVE = 0x2000 # save as a progressive-JPEG + # (use | to combine with other save flags) + JPEG_SUBSAMPLING_411 = 0x1000 # save with high 4x1 chroma + # subsampling (4:1:1) + JPEG_SUBSAMPLING_420 = 0x4000 # save with medium 2x2 medium chroma + # subsampling (4:2:0) - default value + JPEG_SUBSAMPLING_422 = 0x8000 # save with low 2x1 chroma subsampling (4:2:2) + JPEG_SUBSAMPLING_444 = 0x10000 # save with no chroma subsampling (4:4:4) + JPEG_OPTIMIZE = 0x20000 # on saving, compute optimal Huffman coding tables + # (can reduce a few percent of file size) + JPEG_BASELINE = 0x40000 # save basic JPEG, without metadata or any markers KOALA_DEFAULT = 0 LBM_DEFAULT = 0 MNG_DEFAULT = 0 PCD_DEFAULT = 0 - PCD_BASE = 1 - PCD_BASEDIV4 = 2 - PCD_BASEDIV16 = 3 + PCD_BASE = 1 # load the bitmap sized 768 x 512 + PCD_BASEDIV4 = 2 # load the bitmap sized 384 x 256 + PCD_BASEDIV16 = 3 # load the bitmap sized 192 x 128 PCX_DEFAULT = 0 + PFM_DEFAULT = 0 + PICT_DEFAULT = 0 + PNG_DEFAULT = 0 + PNG_IGNOREGAMMA = 1 # loading: avoid gamma correction + PNG_Z_BEST_SPEED = 0x0001 # save using ZLib level 1 compression flag + # (default value is 6) + PNG_Z_DEFAULT_COMPRESSION = 0x0006 # save using ZLib level 6 compression + # flag (default recommended value) + PNG_Z_BEST_COMPRESSION = 0x0009 # save using ZLib level 9 compression flag + # (default value is 6) + PNG_Z_NO_COMPRESSION = 0x0100 # save without ZLib compression + PNG_INTERLACED = 0x0200 # save using Adam7 interlacing (use | to combine + # with other save flags) PNM_DEFAULT = 0 - PNM_SAVE_RAW = 0 - PNM_SAVE_ASCII = 1 + PNM_SAVE_RAW = 0 # Writer saves in RAW format (i.e. P4, P5 or P6) + PNM_SAVE_ASCII = 1 # Writer saves in ASCII format (i.e. P1, P2 or P3) PSD_DEFAULT = 0 + PSD_CMYK = 1 # reads tags for separated CMYK (default is conversion to RGB) + PSD_LAB = 2 # reads tags for CIELab (default is conversion to RGB) RAS_DEFAULT = 0 + RAW_DEFAULT = 0 # load the file as linear RGB 48-bit + RAW_PREVIEW = 1 # try to load the embedded JPEG preview with included + # Exif Data or default to RGB 24-bit + RAW_DISPLAY = 2 # load the file as RGB 24-bit + SGI_DEFAULT = 0 TARGA_DEFAULT = 0 - TARGA_LOAD_RGB888 = 1 + TARGA_LOAD_RGB888 = 1 # Convert RGB555 and ARGB8888 -> RGB888. + TARGA_SAVE_RLE = 2 # Save with RLE compression + TIFF_DEFAULT = 0 + TIFF_CMYK = 0x0001 # reads/stores tags for separated CMYK + # (use | to combine with compression flags) + TIFF_PACKBITS = 0x0100 # save using PACKBITS compression + TIFF_DEFLATE = 0x0200 # save using DEFLATE (a.k.a. ZLIB) compression + TIFF_ADOBE_DEFLATE = 0x0400 # save using ADOBE DEFLATE compression + TIFF_NONE = 0x0800 # save without any compression + TIFF_CCITTFAX3 = 0x1000 # save using CCITT Group 3 fax encoding + TIFF_CCITTFAX4 = 0x2000 # save using CCITT Group 4 fax encoding + TIFF_LZW = 0x4000 # save using LZW compression + TIFF_JPEG = 0x8000 # save using JPEG compression + TIFF_LOGLUV = 0x10000 # save using LogLuv compression WBMP_DEFAULT = 0 XBM_DEFAULT = 0 + XPM_DEFAULT = 0 + class METADATA_MODELS(object): FIMD_COMMENTS = 0 FIMD_EXIF_MAIN = 1 @@ -342,19 +387,23 @@ def _process_bitmap(filename, flags, process_func): _FI.FreeImage_Unload(bitmap) 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 + """Read an image to a numpy array of shape (height, width) for + greyscale images, or shape (height, width, nchannels) for RGB or RGBA images. + The `flags` parameter should be one or more values from the IO_FLAGS + class defined in this module, or-ed together with | as appropriate. + (See the source-code comments for more details.) """ return _process_bitmap(filename, flags, _array_from_bitmap) -def read_metadata(filename, flags=0): +def read_metadata(filename): """Return a dict containing all image metadata. Returned dict maps (metadata_model, tag_name) keys to tag values, where metadata_model is a string name based on the FreeImage "metadata models" defined in the class METADATA_MODELS. """ + flags = IO_FLAGS.FIF_LOAD_NOPIXELS return _process_bitmap(filename, flags, _read_metadata) def _process_multipage(filename, flags, process_func): @@ -390,15 +439,19 @@ def _process_multipage(filename, flags, process_func): 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 - (width, height, nchannels) for RGB or RGBA images. + array is of shape (height, width) for greyscale images, or shape + (height, width, nchannels) for RGB or RGBA images. + The `flags` parameter should be one or more values from the IO_FLAGS + class defined in this module, or-ed together with | as appropriate. + (See the source-code comments for more details.) """ return _process_multipage(filename, flags, _array_from_bitmap) -def read_multipage_metadata(filename, flags=0): +def read_multipage_metadata(filename): """Read a multipage image to a list of metadata dicts, one dict for each page. The dict format is as in read_metadata(). """ + flags = IO_FLAGS.FIF_LOAD_NOPIXELS return _process_multipage(filename, flags, _read_metadata) def _wrap_bitmap_bits_in_array(bitmap, shape, dtype): @@ -481,10 +534,12 @@ def _read_metadata(bitmap): return metadata def write(array, filename, flags=0): - """Write a (width, height) or (width, height, nchannels) array to + """Write a (height, width) or (height, width, nchannels) array to a greyscale, RGB, or RGBA image, with file type deduced from the filename. - + The `flags` parameter should be one or more values from the IO_FLAGS + class defined in this module, or-ed together with | as appropriate. + (See the source-code comments for more details.) """ array = numpy.asarray(array) filename = asbytes(filename) @@ -508,10 +563,12 @@ def write(array, filename, flags=0): _FI.FreeImage_Unload(bitmap) def write_multipage(arrays, filename, flags=0): - """Write a list of (width, height) or (width, height, nchannels) + """Write a list of (height, width) or (height, width, nchannels) arrays to a multipage greyscale, RGB, or RGBA image, with file type deduced from the filename. - + The `flags` parameter should be one or more values from the IO_FLAGS + class defined in this module, or-ed together with | as appropriate. + (See the source-code comments for more details.) """ filename = asbytes(filename) ftype = _FI.FreeImage_GetFIFFromFilename(filename) diff --git a/skimage/io/_plugins/test_freeimage.py b/skimage/io/_plugins/test_freeimage.py index a8ff86cf..d33163ee 100644 --- a/skimage/io/_plugins/test_freeimage.py +++ b/skimage/io/_plugins/test_freeimage.py @@ -1,13 +1,27 @@ import os - import skimage as si import skimage.io as sio +import skimage.io._plugins.freeimage_plugin as fi -sio.use_plugin('matplotlib', 'imshow') -sio.use_plugin('freeimage', 'imread') +from numpy.testing import * -img = sio.imread(os.path.join(si.data_dir, 'color.png')) -sio.imshow(img) -sio.show() +def test_read(): + sio.use_plugin('freeimage', 'imread') + img = sio.imread(os.path.join(si.data_dir, 'color.png')) + assert img.shape == (370, 371, 3) + assert all(img[274,135] == [0, 130, 253]) +def test_metadata(): + meta = fi.read_metadata(os.path.join(si.data_dir, 'multipage.tif')) + assert meta[('EXIF_MAIN', 'BitsPerSample')] == 8 + assert meta[('EXIF_MAIN', 'Software')].startswith('ImageMagick') + + meta = fi.read_multipage_metadata(os.path.join(si.data_dir, 'multipage.tif')) + assert len(meta) == 2 + assert meta[0][('EXIF_MAIN', 'BitsPerSample')] == 8 + assert meta[1][('EXIF_MAIN', 'Software')].startswith('ImageMagick') + + +if __name__ == "__main__": + run_module_suite()