├── MANIFEST.in ├── .travis.yml ├── tifffile ├── __init__.py └── _tifffile.c ├── .gitignore ├── HISTORY.rst ├── Makefile ├── LICENSE ├── test_tifffile.py ├── setup.py └── README.rst /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include HISTORY.rst 2 | include LICENSE 3 | include README.rst 4 | include tifffile/_tifffile.c 5 | 6 | 7 | recursive-exclude * __pycache__ 8 | recursive-exclude * *.py[co] 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # vim ft=yaml 2 | 3 | # After changing this file, check it on: 4 | # http://yaml-online-parser.appspot.com/ 5 | 6 | language: python 7 | sudo: false 8 | 9 | python: 10 | - 2.7 11 | - 3.5 12 | 13 | before_install: 14 | - pip install -U pip 15 | - pip install numpy 16 | - pip install -e . 17 | 18 | script: 19 | - make test 20 | -------------------------------------------------------------------------------- /tifffile/__init__.py: -------------------------------------------------------------------------------- 1 | from .tifffile import imsave, imread, imshow, TiffFile, TiffWriter, TiffSequence, FileHandle, lazyattr, natural_sorted, decode_lzw, stripnull, memmap, stripnull, format_size, squeeze_axes, create_output, repeat_nd, product 2 | 3 | __version__ = '0.15.1' 4 | __all__ = ( 5 | 'imsave', 'imread', 'imshow', 'TiffFile', 'TiffWriter', 'TiffSequence', 6 | # utility functions used in oiffile and czifile 7 | 'FileHandle', 'lazyattr', 'natural_sorted', 'decode_lzw', 'stripnull', 8 | 'memmap', 'stripnull', 'format_size', 'squeeze_axes', 'create_output', 'repeat_nd', 'product' 9 | ) 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Packages 9 | *.egg 10 | *.egg-info 11 | dist 12 | build 13 | eggs 14 | parts 15 | bin 16 | var 17 | sdist 18 | develop-eggs 19 | .installed.cfg 20 | lib 21 | lib64 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | htmlcov 31 | 32 | # Translations 33 | *.mo 34 | 35 | # Mr Developer 36 | .mr.developer.cfg 37 | .project 38 | .pydevproject 39 | 40 | # Complexity 41 | output/*.html 42 | output/*/index.html 43 | 44 | # Sphinx 45 | docs/_build 46 | 47 | MANIFEST 48 | 49 | *.tif 50 | 51 | .DS_Store 52 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | .. :changelog: 2 | 3 | History 4 | ------- 5 | 6 | 7 | 0.6.0 (2015-06-14) 8 | --------------------- 9 | * Make tifffile a package, fix handling of _tifffile.c files 10 | 11 | 12 | 0.4.0 (2014-12-13) 13 | --------------------- 14 | * Do not require importlib to use tifffile.c 15 | * Fix SSIZE_MAX bug for mingw 16 | 17 | 18 | 0.3.0 (2014-10-12) 19 | --------------------- 20 | * Install as a top-level python and compiled file. 21 | 22 | 23 | 0.2.0 (2014-10-12) 24 | --------------------- 25 | * Add __version__ attribute and update PyPI classifiers. 26 | 27 | 28 | 0.1.0 (2014-10-11) 29 | --------------------- 30 | 31 | * First release on PyPI. 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Note: This is meant for tifffile developer use only 2 | .PHONY: all clean test release update 3 | 4 | export TEST_ARGS=--exe -v 5 | export NAME=tifffile 6 | export VERSION=`python -c "import $(NAME); print($(NAME).__version__)"` 7 | export SITE=http://www.lfd.uci.edu/~gohlke/code/ 8 | 9 | all: clean 10 | python setup.py build_ext -i 11 | python setup.py install 12 | 13 | clean: 14 | rm -rf build 15 | rm -rf dist 16 | find . -name "*.so" -o -name "*.pyc" | xargs rm -f 17 | 18 | test: clean 19 | python setup.py build_ext -i 20 | export PYTHONWARNINGS="all"; nosetests $(TEST_ARGS) 21 | make clean 22 | 23 | release: test 24 | pip install twine 25 | git tag v$(VERSION); true 26 | git commit -a -m "Release $(VERSION)"; true 27 | git push origin --all; true 28 | git push origin --tags; true 29 | rm -rf dist 30 | python setup.py register 31 | python setup.py sdist 32 | twine upload dist/* 33 | printf '\nUpgrade tifffile-feedstock with release and sha256 sum:' 34 | shasum -a 256 dist/*.tar.gz 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2014, Christoph Gohlke 2 | Copyright (c) 2008-2014, The Regents of the University of California 3 | Produced at the Laboratory for Fluorescence Dynamics 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | * Neither the name of the copyright holders nor the names of any 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /test_tifffile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import sys 4 | 5 | try: 6 | import skimage as si 7 | except Exception: 8 | si = None 9 | 10 | from numpy.testing import ( 11 | assert_array_equal, assert_array_almost_equal, run_module_suite) 12 | from numpy.testing.decorators import skipif 13 | 14 | from tempfile import NamedTemporaryFile 15 | from tifffile import imread, imsave 16 | 17 | 18 | np.random.seed(0) 19 | 20 | 21 | @skipif(si is None) 22 | def test_imread_uint16(): 23 | expected = np.load(os.path.join(si.data_dir, 'chessboard_GRAY_U8.npy')) 24 | img = imread(os.path.join(si.data_dir, 'chessboard_GRAY_U16.tif')) 25 | assert img.dtype == np.uint16 26 | assert_array_almost_equal(img, expected) 27 | 28 | 29 | @skipif(si is None) 30 | def test_imread_uint16_big_endian(): 31 | expected = np.load(os.path.join(si.data_dir, 'chessboard_GRAY_U8.npy')) 32 | img = imread(os.path.join(si.data_dir, 'chessboard_GRAY_U16B.tif')) 33 | assert img.dtype == np.uint16 34 | assert_array_almost_equal(img, expected) 35 | 36 | 37 | @skipif(sys.version.startswith('2.6') or sys.version.startswith('3.2')) 38 | def test_extension(): 39 | from tifffile.tifffile import decode_lzw 40 | import types 41 | assert isinstance(decode_lzw, types.BuiltinFunctionType), type(decode_lzw) 42 | 43 | 44 | class TestSave: 45 | 46 | def roundtrip(self, dtype, x): 47 | f = NamedTemporaryFile(suffix='.tif') 48 | fname = f.name 49 | f.close() 50 | imsave(fname, x) 51 | y = imread(fname) 52 | assert_array_equal(x, y) 53 | 54 | def test_imsave_roundtrip(self): 55 | for shape in [(10, 10), (10, 10, 3), (10, 10, 4)]: 56 | for dtype in (np.uint8, np.uint16, np.float32, np.int16, 57 | np.float64): 58 | x = np.random.rand(*shape) 59 | 60 | if not np.issubdtype(dtype, float): 61 | x = (x * np.iinfo(dtype).max).astype(dtype) 62 | else: 63 | x = x.astype(dtype) 64 | yield self.roundtrip, dtype, x 65 | 66 | 67 | if __name__ == "__main__": 68 | run_module_suite() 69 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | 6 | from setuptools import find_packages, setup 7 | from setuptools.command.build_ext import build_ext as _build_ext 8 | from setuptools.extension import Extension 9 | 10 | with open('README.rst') as f: 11 | readme = f.read() 12 | 13 | with open('tifffile/__init__.py') as f: 14 | text = f.read() 15 | 16 | version = re.search("__version__ = '(.*?)'", text).groups()[0] 17 | 18 | 19 | # See https://stackoverflow.com/a/21621689/3622042 20 | class build_ext(_build_ext): 21 | def finalize_options(self): 22 | _build_ext.finalize_options(self) 23 | 24 | # Prevent numpy from thinking it is still in its setup process: 25 | __builtins__.__NUMPY_SETUP__ = False 26 | 27 | import numpy 28 | self.include_dirs.append(numpy.get_include()) 29 | 30 | 31 | ext_modules = [Extension('tifffile._tifffile', ['tifffile/_tifffile.c'])] 32 | 33 | 34 | setup( 35 | name='tifffile', 36 | version=version, 37 | description='Read and write image data from and to TIFF files.', 38 | long_description=readme, 39 | author='Steven Silvester', 40 | author_email='steven.silvester@ieee.org', 41 | url='https://github.com/blink1073/tifffile', 42 | include_package_data=True, 43 | setup_requires=[ 44 | 'numpy>=1.8.2' 45 | ], 46 | install_requires=[ 47 | 'numpy>=1.8.2', 48 | 'pathlib;python_version<"3.0"', 49 | 'enum34;python_version<"3.0"', 50 | 'futures; python_version == "2.7"' 51 | ], 52 | license="BSD", 53 | zip_safe=False, 54 | packages=find_packages(), 55 | cmdclass={ 56 | 'build_ext': build_ext 57 | }, 58 | ext_modules=ext_modules, 59 | keywords='tifffile', 60 | classifiers=[ 61 | 'Development Status :: 4 - Beta', 62 | 'Intended Audience :: Developers', 63 | 'License :: OSI Approved :: BSD License', 64 | 'Operating System :: OS Independent', 65 | "Programming Language :: C", 66 | "Programming Language :: Python :: 2", 67 | 'Programming Language :: Python :: 2.7', 68 | 'Programming Language :: Python :: 3', 69 | 'Programming Language :: Python :: 3.4', 70 | ], 71 | ) 72 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============================================================================================= 2 | This repository is deprecated and not directly tied to the released package on PyPI. 3 | ============================================================================================= 4 | 5 | =============================== 6 | Tifffile 7 | =============================== 8 | 9 | .. image:: https://badge.fury.io/py/tifffile.png 10 | :target: http://badge.fury.io/py/tifffile 11 | 12 | .. image:: https://pypip.in/d/tifffile/badge.png 13 | :target: https://pypi.python.org/pypi/tifffile 14 | 15 | 16 | Read and write image data from and to TIFF files. 17 | 18 | Image and metadata can be read from TIFF, BigTIFF, OME-TIFF, STK, LSM, NIH, 19 | SGI, ImageJ, MicroManager, FluoView, SEQ and GEL files. 20 | Only a subset of the TIFF specification is supported, mainly uncompressed 21 | and losslessly compressed 2**(0 to 6) bit integer, 16, 32 and 64-bit float, 22 | grayscale and RGB(A) images, which are commonly used in bio-scientific imaging. 23 | Specifically, reading JPEG and CCITT compressed image data or EXIF, IPTC, GPS, 24 | and XMP metadata is not implemented. 25 | Only primary info records are read for STK, FluoView, MicroManager, and 26 | NIH image formats. 27 | 28 | TIFF, the Tagged Image File Format, is under the control of Adobe Systems. 29 | BigTIFF allows for files greater than 4 GB. STK, LSM, FluoView, SGI, SEQ, GEL, 30 | and OME-TIFF, are custom extensions defined by Molecular Devices (Universal 31 | Imaging Corporation), Carl Zeiss MicroImaging, Olympus, Silicon Graphics 32 | International, Media Cybernetics, Molecular Dynamics, and the Open Microscopy 33 | Environment consortium respectively. 34 | 35 | For command line usage run ``python tifffile.py --help`` 36 | 37 | :Author: 38 | `Christoph Gohlke `_ 39 | 40 | :Organization: 41 | Laboratory for Fluorescence Dynamics, University of California, Irvine 42 | 43 | :Version: 2017.01.12 44 | 45 | Requirements 46 | ------------ 47 | * `CPython 2.7 or 3.4 `_ 48 | * `Numpy 1.11 `_ 49 | * `Matplotlib 1.5 `_ (optional for plotting) 50 | 51 | Installation 52 | ------------ 53 | * If using conda, `conda install tifffile -c conda-forge`. 54 | * Otherwise, `pip install tifffile`. 55 | 56 | Notes 57 | ----- 58 | This is a mirror of the code at http://www.lfd.uci.edu/~gohlke/code/tifffile.py.html. For any development concerns, please email Christoph Gohlke at 59 | ``cgohlke at uci.edu``. 60 | 61 | The API is not stable yet and might change between revisions. 62 | 63 | Tested on little-endian platforms only. 64 | 65 | Other Python packages and modules for reading bio-scientific TIFF files: 66 | 67 | * `Imread `_ 68 | * `PyLibTiff `_ 69 | * `SimpleITK `_ 70 | * `PyLSM `_ 71 | * `PyMca.TiffIO.py `_ (same as fabio.TiffIO) 72 | * `BioImageXD.Readers `_ 73 | * `Cellcognition.io `_ 74 | * `CellProfiler.bioformats 75 | `_ 76 | 77 | Acknowledgements 78 | ---------------- 79 | * Egor Zindy, University of Manchester, for cz_lsm_scan_info specifics. 80 | * Wim Lewis for a bug fix and some read_cz_lsm functions. 81 | * Hadrien Mary for help on reading MicroManager files. 82 | 83 | References 84 | ---------- 85 | (1) TIFF 6.0 Specification and Supplements. Adobe Systems Incorporated. 86 | http://partners.adobe.com/public/developer/tiff/ 87 | (2) TIFF File Format FAQ. http://www.awaresystems.be/imaging/tiff/faq.html 88 | (3) MetaMorph Stack (STK) Image File Format. 89 | http://support.meta.moleculardevices.com/docs/t10243.pdf 90 | (4) Image File Format Description LSM 5/7 Release 6.0 (ZEN 2010). 91 | Carl Zeiss MicroImaging GmbH. BioSciences. May 10, 2011 92 | (5) File Format Description - LSM 5xx Release 2.0. 93 | http://ibb.gsf.de/homepage/karsten.rodenacker/IDL/Lsmfile.doc 94 | (6) The OME-TIFF format. 95 | http://www.openmicroscopy.org/site/support/file-formats/ome-tiff 96 | (7) UltraQuant(r) Version 6.0 for Windows Start-Up Guide. 97 | http://www.ultralum.com/images%20ultralum/pdf/UQStart%20Up%20Guide.pdf 98 | (8) Micro-Manager File Formats. 99 | http://www.micro-manager.org/wiki/Micro-Manager_File_Formats 100 | (9) Tags for TIFF and Related Specifications. Digital Preservation. 101 | http://www.digitalpreservation.gov/formats/content/tiff_tags.shtml 102 | 103 | Examples 104 | -------- 105 | 106 | >>> data = numpy.random.rand(5, 301, 219) 107 | >>> imsave('temp.tif', data) 108 | 109 | >>> image = imread('temp.tif') 110 | >>> numpy.testing.assert_array_equal(image, data) 111 | 112 | >>> with TiffFile('temp.tif') as tif: 113 | ... images = tif.asarray() 114 | ... for page in tif: 115 | ... for tag in page.tags.values(): 116 | ... t = tag.name, tag.value 117 | ... image = page.asarray() 118 | 119 | 120 | Known build errors 121 | ------------------ 122 | On Windows, the error `Error:unable to find vcvarsall.bat` means that distutils is not correctly configured to use the C compiler. Modify (or create, if not existing) the configuration file `distutils.cfg` (located for example at `C:\\Python27\\Lib\\distutils\\distutils.cfg`) to contain:: 123 | 124 | [build] 125 | compiler=mingw32 126 | 127 | -------------------------------------------------------------------------------- /tifffile/_tifffile.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* tifffile.c 4 | 5 | A Python C extension module for decoding PackBits and LZW encoded TIFF data. 6 | 7 | Refer to the tifffile.py module for documentation and tests. 8 | 9 | :Author: 10 | `Christoph Gohlke `_ 11 | 12 | :Organization: 13 | Laboratory for Fluorescence Dynamics, University of California, Irvine 14 | 15 | :Version: 2018.02.10 16 | 17 | Requirements 18 | ------------ 19 | * `CPython 2.7 or 3.6 `_ 20 | * `Numpy 1.13 `_ 21 | * A Python distutils compatible C compiler (build) 22 | * `stdint.h `_ for msvc9 compiler 23 | 24 | Install 25 | ------- 26 | Use this Python distutils setup script to build the extension module:: 27 | 28 | # setup.py 29 | # Usage: ``python setup.py build_ext --inplace`` 30 | from distutils.core import setup, Extension 31 | import numpy 32 | setup(name='_tifffile', 33 | ext_modules=[Extension('_tifffile', ['tifffile.c'], 34 | include_dirs=[numpy.get_include()])]) 35 | 36 | License 37 | ------- 38 | Copyright (c) 2008-2018, Christoph Gohlke 39 | Copyright (c) 2008-2018, The Regents of the University of California 40 | Produced at the Laboratory for Fluorescence Dynamics 41 | All rights reserved. 42 | 43 | Redistribution and use in source and binary forms, with or without 44 | modification, are permitted provided that the following conditions are met: 45 | 46 | * Redistributions of source code must retain the above copyright 47 | notice, this list of conditions and the following disclaimer. 48 | * Redistributions in binary form must reproduce the above copyright 49 | notice, this list of conditions and the following disclaimer in the 50 | documentation and/or other materials provided with the distribution. 51 | * Neither the name of the copyright holders nor the names of any 52 | contributors may be used to endorse or promote products derived 53 | from this software without specific prior written permission. 54 | 55 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 56 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 59 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 | POSSIBILITY OF SUCH DAMAGE. 66 | */ 67 | 68 | #define _VERSION_ "2018.02.10" 69 | 70 | #define WIN32_LEAN_AND_MEAN 71 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 72 | 73 | #include "Python.h" 74 | #include "string.h" 75 | #include "numpy/arrayobject.h" 76 | 77 | #include 78 | 79 | /* little endian by default */ 80 | #ifndef MSB 81 | #define MSB 1 82 | #endif 83 | 84 | #if MSB 85 | #define LSB 0 86 | #define BOC '<' 87 | #else 88 | #define LSB 1 89 | #define BOC '>' 90 | #endif 91 | 92 | #define NO_ERROR 0 93 | #define VALUE_ERROR -1 94 | 95 | #ifndef SSIZE_MAX 96 | #define SSIZE_MAX INTPTR_MAX 97 | #endif 98 | 99 | #define SWAP2BYTES(x) \ 100 | ((((x) >> 8) & 0x00FF) | (((x) & 0x00FF) << 8)) 101 | 102 | #define SWAP4BYTES(x) \ 103 | ((((x) >> 24) & 0x00FF) | (((x)&0x00FF) << 24) | \ 104 | (((x) >> 8 ) & 0xFF00) | (((x)&0xFF00) << 8)) 105 | 106 | #define SWAP8BYTES(x) \ 107 | ((((x) >> 56) & 0x00000000000000FF) | (((x) >> 40) & 0x000000000000FF00) | \ 108 | (((x) >> 24) & 0x0000000000FF0000) | (((x) >> 8) & 0x00000000FF000000) | \ 109 | (((x) << 8) & 0x000000FF00000000) | (((x) << 24) & 0x0000FF0000000000) | \ 110 | (((x) << 40) & 0x00FF000000000000) | (((x) << 56) & 0xFF00000000000000)) 111 | 112 | typedef union { 113 | uint8_t b[2]; 114 | uint16_t i; 115 | } u_uint16; 116 | 117 | typedef union { 118 | uint8_t b[4]; 119 | uint32_t i; 120 | } u_uint32; 121 | 122 | typedef union { 123 | uint8_t b[8]; 124 | uint64_t i; 125 | } u_uint64; 126 | 127 | typedef struct { 128 | ssize_t len; 129 | char* str; 130 | } string_t; 131 | 132 | /*****************************************************************************/ 133 | /* C functions */ 134 | 135 | /* Return mask for itemsize bits */ 136 | unsigned char bitmask(const int itemsize) { 137 | unsigned char result = 0; 138 | unsigned char power = 1; 139 | int i; 140 | for (i = 0; i < itemsize; i++) { 141 | result += power; 142 | power *= 2; 143 | } 144 | return result << (8 - itemsize); 145 | } 146 | 147 | /** Unpack sequence of tigthly packed 1-32 bit integers. 148 | 149 | Native byte order will be returned. 150 | 151 | Input data array should be padded to the next 16, 32 or 64-bit boundary 152 | if itemsize not in (1, 2, 4, 8, 16, 24, 32, 64). 153 | 154 | */ 155 | int unpackbits( 156 | unsigned char* data, 157 | const ssize_t size, /** size of data in bytes */ 158 | const int itemsize, /** number of bits in integer */ 159 | ssize_t numitems, /** number of items to unpack */ 160 | unsigned char* result /** buffer to store unpacked items */ 161 | ) 162 | { 163 | ssize_t i, j, k, storagesize; 164 | unsigned char value; 165 | /* Input validation is done in wrapper function */ 166 | storagesize = (ssize_t)(ceil(itemsize / 8.0)); 167 | storagesize = storagesize < 3 ? storagesize : storagesize > 4 ? 8 : 4; 168 | switch (itemsize) { 169 | case 8: 170 | case 16: 171 | case 32: 172 | case 64: 173 | memcpy(result, data, numitems*storagesize); 174 | return NO_ERROR; 175 | case 1: 176 | for (i = 0, j = 0; i < numitems/8; i++) { 177 | value = data[i]; 178 | result[j++] = (value & (unsigned char)(128)) >> 7; 179 | result[j++] = (value & (unsigned char)(64)) >> 6; 180 | result[j++] = (value & (unsigned char)(32)) >> 5; 181 | result[j++] = (value & (unsigned char)(16)) >> 4; 182 | result[j++] = (value & (unsigned char)(8)) >> 3; 183 | result[j++] = (value & (unsigned char)(4)) >> 2; 184 | result[j++] = (value & (unsigned char)(2)) >> 1; 185 | result[j++] = (value & (unsigned char)(1)); 186 | } 187 | if (numitems % 8) { 188 | value = data[i]; 189 | switch (numitems % 8) { 190 | case 7: result[j+6] = (value & (unsigned char)(2)) >> 1; 191 | case 6: result[j+5] = (value & (unsigned char)(4)) >> 2; 192 | case 5: result[j+4] = (value & (unsigned char)(8)) >> 3; 193 | case 4: result[j+3] = (value & (unsigned char)(16)) >> 4; 194 | case 3: result[j+2] = (value & (unsigned char)(32)) >> 5; 195 | case 2: result[j+1] = (value & (unsigned char)(64)) >> 6; 196 | case 1: result[j] = (value & (unsigned char)(128)) >> 7; 197 | } 198 | } 199 | return NO_ERROR; 200 | case 2: 201 | for (i = 0, j = 0; i < numitems/4; i++) { 202 | value = data[i]; 203 | result[j++] = (value & (unsigned char)(192)) >> 6; 204 | result[j++] = (value & (unsigned char)(48)) >> 4; 205 | result[j++] = (value & (unsigned char)(12)) >> 2; 206 | result[j++] = (value & (unsigned char)(3)); 207 | } 208 | if (numitems % 4) { 209 | value = data[i]; 210 | switch (numitems % 4) { 211 | case 3: result[j+2] = (value & (unsigned char)(12)) >> 2; 212 | case 2: result[j+1] = (value & (unsigned char)(48)) >> 4; 213 | case 1: result[j] = (value & (unsigned char)(192)) >> 6; 214 | } 215 | } 216 | return NO_ERROR; 217 | case 4: 218 | for (i = 0, j = 0; i < numitems/2; i++) { 219 | value = data[i]; 220 | result[j++] = (value & (unsigned char)(240)) >> 4; 221 | result[j++] = (value & (unsigned char)(15)); 222 | } 223 | if (numitems % 2) { 224 | value = data[i]; 225 | result[j] = (value & (unsigned char)(240)) >> 4; 226 | } 227 | return NO_ERROR; 228 | case 24: 229 | j = k = 0; 230 | for (i = 0; i < numitems; i++) { 231 | result[j++] = 0; 232 | result[j++] = data[k++]; 233 | result[j++] = data[k++]; 234 | result[j++] = data[k++]; 235 | } 236 | return NO_ERROR; 237 | } 238 | /* 3, 5, 6, 7 */ 239 | if (itemsize < 8) { 240 | int shr = 16; 241 | u_uint16 value, mask, tmp; 242 | j = k = 0; 243 | value.b[MSB] = data[j++]; 244 | value.b[LSB] = data[j++]; 245 | mask.b[MSB] = bitmask(itemsize); 246 | mask.b[LSB] = 0; 247 | for (i = 0; i < numitems; i++) { 248 | shr -= itemsize; 249 | tmp.i = (value.i & mask.i) >> shr; 250 | result[k++] = tmp.b[LSB]; 251 | if (shr < itemsize) { 252 | value.b[MSB] = value.b[LSB]; 253 | value.b[LSB] = data[j++]; 254 | mask.i <<= 8 - itemsize; 255 | shr += 8; 256 | } else { 257 | mask.i >>= itemsize; 258 | } 259 | } 260 | return NO_ERROR; 261 | } 262 | /* 9, 10, 11, 12, 13, 14, 15 */ 263 | if (itemsize < 16) { 264 | int shr = 32; 265 | u_uint32 value, mask, tmp; 266 | mask.i = 0; 267 | j = k = 0; 268 | #if MSB 269 | for (i = 3; i >= 0; i--) { 270 | value.b[i] = data[j++]; 271 | } 272 | mask.b[3] = 0xFF; 273 | mask.b[2] = bitmask(itemsize-8); 274 | for (i = 0; i < numitems; i++) { 275 | shr -= itemsize; 276 | tmp.i = (value.i & mask.i) >> shr; 277 | result[k++] = tmp.b[0]; /* swap bytes */ 278 | result[k++] = tmp.b[1]; 279 | if (shr < itemsize) { 280 | value.b[3] = value.b[1]; 281 | value.b[2] = value.b[0]; 282 | value.b[1] = j < size ? data[j++] : 0; 283 | value.b[0] = j < size ? data[j++] : 0; 284 | mask.i <<= 16 - itemsize; 285 | shr += 16; 286 | } else { 287 | mask.i >>= itemsize; 288 | } 289 | } 290 | #else 291 | /* not implemented */ 292 | #endif 293 | return NO_ERROR; 294 | } 295 | /* 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31 */ 296 | if (itemsize < 32) { 297 | int shr = 64; 298 | u_uint64 value, mask, tmp; 299 | mask.i = 0; 300 | j = k = 0; 301 | #if MSB 302 | for (i = 7; i >= 0; i--) { 303 | value.b[i] = data[j++]; 304 | } 305 | mask.b[7] = 0xFF; 306 | mask.b[6] = 0xFF; 307 | mask.b[5] = itemsize > 23 ? 0xFF : bitmask(itemsize-16); 308 | mask.b[4] = itemsize < 24 ? 0x00 : bitmask(itemsize-24); 309 | for (i = 0; i < numitems; i++) { 310 | shr -= itemsize; 311 | tmp.i = (value.i & mask.i) >> shr; 312 | result[k++] = tmp.b[0]; /* swap bytes */ 313 | result[k++] = tmp.b[1]; 314 | result[k++] = tmp.b[2]; 315 | result[k++] = tmp.b[3]; 316 | if (shr < itemsize) { 317 | value.b[7] = value.b[3]; 318 | value.b[6] = value.b[2]; 319 | value.b[5] = value.b[1]; 320 | value.b[4] = value.b[0]; 321 | value.b[3] = j < size ? data[j++] : 0; 322 | value.b[2] = j < size ? data[j++] : 0; 323 | value.b[1] = j < size ? data[j++] : 0; 324 | value.b[0] = j < size ? data[j++] : 0; 325 | mask.i <<= 32 - itemsize; 326 | shr += 32; 327 | } else { 328 | mask.i >>= itemsize; 329 | } 330 | } 331 | #else 332 | /* Not implemented */ 333 | #endif 334 | return NO_ERROR; 335 | } 336 | return VALUE_ERROR; 337 | } 338 | 339 | /*****************************************************************************/ 340 | /* Python functions */ 341 | 342 | 343 | /** Reverse bits in bytes of byte string or ndarray. */ 344 | char py_reverse_bitorder_doc[] = 345 | "Reverse bits in each byte of byte string or numpy array."; 346 | 347 | static PyObject* 348 | py_reverse_bitorder(PyObject* obj, PyObject* args) 349 | { 350 | PyObject* dataobj = NULL; 351 | PyObject* result = NULL; 352 | PyArray_Descr* dtype = NULL; 353 | PyArrayIterObject* iter = NULL; 354 | unsigned char* dataptr = NULL; 355 | unsigned char* resultptr = NULL; 356 | Py_ssize_t size, stride; 357 | Py_ssize_t i, j; 358 | int axis = -1; 359 | 360 | if (!PyArg_ParseTuple(args, "O", &dataobj)) 361 | return NULL; 362 | 363 | Py_INCREF(dataobj); 364 | 365 | if (PyBytes_Check(dataobj)) { 366 | dataptr = (unsigned char*)PyBytes_AS_STRING(dataobj); 367 | size = PyBytes_GET_SIZE(dataobj); 368 | 369 | result = PyBytes_FromStringAndSize(NULL, size); 370 | if (result == NULL) { 371 | PyErr_Format(PyExc_MemoryError, "unable to allocate result"); 372 | goto _fail; 373 | } 374 | resultptr = (unsigned char*)PyBytes_AS_STRING(result); 375 | 376 | Py_BEGIN_ALLOW_THREADS 377 | for (i = 0; i < size; i++) { 378 | /* http://graphics.stanford.edu/~seander/bithacks.html 379 | #ReverseByteWith64Bits */ 380 | *resultptr++ = (unsigned char)(((*dataptr++ * 0x80200802ULL) & 381 | 0x0884422110ULL) * 0x0101010101ULL >> 32); 382 | } 383 | Py_END_ALLOW_THREADS 384 | 385 | Py_DECREF(dataobj); 386 | return result; 387 | } 388 | else if (PyArray_Check(dataobj)) { 389 | dtype = PyArray_DTYPE((PyArrayObject*) dataobj); 390 | if (dtype->elsize == 0) { 391 | PyErr_Format(PyExc_ValueError, "can not handle dtype"); 392 | goto _fail; 393 | } 394 | iter = (PyArrayIterObject*)PyArray_IterAllButAxis(dataobj, &axis); 395 | size = PyArray_DIM((PyArrayObject*)dataobj, axis); 396 | stride = PyArray_STRIDE((PyArrayObject*)dataobj, axis); 397 | stride -= dtype->elsize; 398 | 399 | Py_BEGIN_ALLOW_THREADS 400 | while (iter->index < iter->size) { 401 | dataptr = (unsigned char*)iter->dataptr; 402 | for(i = 0; i < size; i++) { 403 | for(j = 0; j < dtype->elsize; j++) { 404 | *dataptr = (unsigned char)(((*dataptr * 0x80200802ULL) & 405 | 0x0884422110ULL) * 0x0101010101ULL >> 32); 406 | dataptr++; 407 | } 408 | dataptr += stride; 409 | } 410 | PyArray_ITER_NEXT(iter); 411 | } 412 | Py_END_ALLOW_THREADS 413 | 414 | Py_DECREF(iter); 415 | Py_DECREF(dataobj); 416 | Py_RETURN_NONE; 417 | } else { 418 | PyErr_Format(PyExc_TypeError, "not a byte string or ndarray"); 419 | goto _fail; 420 | } 421 | 422 | _fail: 423 | Py_XDECREF(dataobj); 424 | Py_XDECREF(result); 425 | Py_XDECREF(iter); 426 | return NULL; 427 | } 428 | 429 | 430 | /** Unpack tightly packed integers. */ 431 | char py_unpackints_doc[] = "Unpack groups of bits into numpy array."; 432 | 433 | static PyObject* 434 | py_unpackints(PyObject* obj, PyObject* args, PyObject* kwds) 435 | { 436 | PyObject* byteobj = NULL; 437 | PyArrayObject* result = NULL; 438 | PyArray_Descr* dtype = NULL; 439 | char* encoded = NULL; 440 | char* decoded = NULL; 441 | Py_ssize_t encoded_len = 0; 442 | Py_ssize_t decoded_len = 0; 443 | Py_ssize_t runlen = 0; 444 | Py_ssize_t i; 445 | int storagesize, bytesize; 446 | int itemsize = 0; 447 | int skipbits = 0; 448 | static char* kwlist[] = {"data", "dtype", "itemsize", "runlen", NULL}; 449 | 450 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&i|i", kwlist, 451 | &byteobj, PyArray_DescrConverter, &dtype, &itemsize, &runlen)) 452 | return NULL; 453 | 454 | Py_INCREF(byteobj); 455 | 456 | if (((itemsize < 1) || (itemsize > 32)) && (itemsize != 64)) { 457 | PyErr_Format(PyExc_ValueError, "itemsize out of range"); 458 | goto _fail; 459 | } 460 | 461 | if (!PyBytes_Check(byteobj)) { 462 | PyErr_Format(PyExc_TypeError, "expected byte string as input"); 463 | goto _fail; 464 | } 465 | 466 | encoded = PyBytes_AS_STRING(byteobj); 467 | encoded_len = PyBytes_GET_SIZE(byteobj); 468 | bytesize = (int)ceil(itemsize / 8.0); 469 | storagesize = bytesize < 3 ? bytesize : bytesize > 4 ? 8 : 4; 470 | if ((encoded_len < bytesize) || (encoded_len > SSIZE_MAX / storagesize)) { 471 | PyErr_Format(PyExc_ValueError, "data size out of range"); 472 | goto _fail; 473 | } 474 | if (dtype->elsize != storagesize) { 475 | PyErr_Format(PyExc_TypeError, "dtype.elsize does not fit itemsize"); 476 | goto _fail; 477 | } 478 | 479 | if (runlen == 0) { 480 | runlen = (Py_ssize_t)(((uint64_t)encoded_len*8) / (uint64_t)itemsize); 481 | } 482 | skipbits = (Py_ssize_t)(((uint64_t)runlen * (uint64_t)itemsize) % 8); 483 | if (skipbits > 0) { 484 | skipbits = 8 - skipbits; 485 | } 486 | decoded_len = (Py_ssize_t)((uint64_t)runlen * (((uint64_t)encoded_len*8) / 487 | ((uint64_t)runlen*(uint64_t)itemsize + (uint64_t)skipbits))); 488 | 489 | result = (PyArrayObject*)PyArray_SimpleNew(1, &decoded_len, 490 | dtype->type_num); 491 | if (result == NULL) { 492 | PyErr_Format(PyExc_MemoryError, "unable to allocate output array"); 493 | goto _fail; 494 | } 495 | decoded = (char*)PyArray_DATA(result); 496 | 497 | encoded_len = (ssize_t)(((uint64_t)runlen * (uint64_t)itemsize + 498 | (uint64_t)skipbits) / 8); 499 | 500 | for (i = 0; i < decoded_len; i+=runlen) { 501 | if (NO_ERROR != unpackbits((unsigned char*) encoded, 502 | (ssize_t) encoded_len, 503 | (int) itemsize, 504 | (ssize_t) runlen, 505 | (unsigned char*) decoded)) { 506 | PyErr_Format(PyExc_ValueError, "unpackbits() failed"); 507 | goto _fail; 508 | } 509 | encoded += encoded_len; 510 | decoded += runlen * storagesize; 511 | } 512 | 513 | if ((dtype->byteorder != BOC) && (itemsize % 8 == 0)) { 514 | switch (dtype->elsize) { 515 | case 2: { 516 | uint16_t* d = (uint16_t*)PyArray_DATA(result); 517 | for (i = 0; i < PyArray_SIZE(result); i++) { 518 | *d = SWAP2BYTES(*d); 519 | d++; 520 | } 521 | break; } 522 | case 4: { 523 | uint32_t* d = (uint32_t*)PyArray_DATA(result); 524 | for (i = 0; i < PyArray_SIZE(result); i++) { 525 | *d = SWAP4BYTES(*d); 526 | d++; 527 | } 528 | break; } 529 | case 8: { 530 | uint64_t* d = (uint64_t*)PyArray_DATA(result); 531 | for (i = 0; i < PyArray_SIZE(result); i++) { 532 | *d = SWAP8BYTES(*d); 533 | d++; 534 | } 535 | break; } 536 | } 537 | } 538 | Py_DECREF(byteobj); 539 | Py_DECREF(dtype); 540 | return PyArray_Return(result); 541 | 542 | _fail: 543 | Py_XDECREF(byteobj); 544 | Py_XDECREF(result); 545 | Py_XDECREF(dtype); 546 | return NULL; 547 | } 548 | 549 | 550 | /** Decode TIFF PackBits encoded string. */ 551 | char py_decodepackbits_doc[] = "Return TIFF PackBits decoded string."; 552 | 553 | static PyObject* 554 | py_decodepackbits(PyObject* obj, PyObject* args) 555 | { 556 | int n; 557 | char e; 558 | char* decoded = NULL; 559 | char* encoded = NULL; 560 | char* encoded_end = NULL; 561 | char* encoded_pos = NULL; 562 | unsigned int encoded_len; 563 | unsigned int decoded_len; 564 | PyObject* byteobj = NULL; 565 | PyObject* result = NULL; 566 | 567 | if (!PyArg_ParseTuple(args, "O", &byteobj)) 568 | return NULL; 569 | 570 | if (!PyBytes_Check(byteobj)) { 571 | PyErr_Format(PyExc_TypeError, "expected byte string as input"); 572 | goto _fail; 573 | } 574 | 575 | Py_INCREF(byteobj); 576 | encoded = PyBytes_AS_STRING(byteobj); 577 | encoded_len = (unsigned int)PyBytes_GET_SIZE(byteobj); 578 | 579 | /* release GIL: byte/string objects are immutable */ 580 | Py_BEGIN_ALLOW_THREADS 581 | 582 | /* determine size of decoded string */ 583 | encoded_pos = encoded; 584 | encoded_end = encoded + encoded_len; 585 | decoded_len = 0; 586 | while (encoded_pos < encoded_end) { 587 | n = (int)*encoded_pos++; 588 | if (n >= 0) { 589 | n++; 590 | if (encoded_pos+n > encoded_end) 591 | n = (int)(encoded_end - encoded_pos); 592 | encoded_pos += n; 593 | decoded_len += n; 594 | } else if (n > -128) { 595 | encoded_pos++; 596 | decoded_len += 1-n; 597 | } 598 | } 599 | Py_END_ALLOW_THREADS 600 | 601 | result = PyBytes_FromStringAndSize(NULL, decoded_len); 602 | if (result == NULL) { 603 | PyErr_Format(PyExc_MemoryError, "failed to allocate decoded string"); 604 | goto _fail; 605 | } 606 | decoded = PyBytes_AS_STRING(result); 607 | 608 | Py_BEGIN_ALLOW_THREADS 609 | 610 | /* decode string */ 611 | encoded_end = encoded + encoded_len; 612 | while (encoded < encoded_end) { 613 | n = (int)*encoded++; 614 | if (n >= 0) { 615 | n++; 616 | if (encoded+n > encoded_end) 617 | n = (int)(encoded_end - encoded); 618 | /* memmove(decoded, encoded, n); decoded += n; encoded += n; */ 619 | while (n--) 620 | *decoded++ = *encoded++; 621 | } else if (n > -128) { 622 | n = 1 - n; 623 | e = *encoded++; 624 | /* memset(decoded, e, n); decoded += n; */ 625 | while (n--) 626 | *decoded++ = e; 627 | } 628 | } 629 | Py_END_ALLOW_THREADS 630 | 631 | Py_DECREF(byteobj); 632 | return result; 633 | 634 | _fail: 635 | Py_XDECREF(byteobj); 636 | Py_XDECREF(result); 637 | return NULL; 638 | } 639 | 640 | 641 | /** Decode TIFF LZW encoded string. */ 642 | char py_decodelzw_doc[] = "Return TIFF LZW decoded string."; 643 | 644 | #define GET_NEXT_CODE \ 645 | { \ 646 | const uint8_t* bytes = (uint8_t*)((void*)(encoded + (bitcount>>3))); \ 647 | code = (uint32_t) bytes[0]; \ 648 | code <<= 8; \ 649 | code |= (uint32_t) bytes[1]; \ 650 | code <<= 8; \ 651 | if ((bitcount + 24) <= encoded_size) \ 652 | code |= (uint32_t) bytes[2]; \ 653 | code <<= 8; \ 654 | code <<= (uint32_t)(bitcount % 8); \ 655 | code &= mask; \ 656 | code >>= shr; \ 657 | bitcount += bitw; \ 658 | } 659 | 660 | 661 | static PyObject* 662 | py_decodelzw(PyObject* obj, PyObject* args) 663 | { 664 | PyObject* byteobj = NULL; 665 | PyObject* decoded = NULL; 666 | string_t* table = NULL; 667 | char* encoded = NULL; 668 | char* buffer = NULL; 669 | char* pbuffer = NULL; 670 | char* pdecoded = NULL; 671 | char* pstr = NULL; 672 | int little_endian; 673 | uint32_t code, oldcode, mask, shr, table_size; 674 | ssize_t i, decoded_size, buffersize, buffer_size; 675 | uint64_t bitcount, bitw, encoded_size; 676 | 677 | if (!PyArg_ParseTuple(args, "O", &byteobj)) 678 | return NULL; 679 | 680 | if (!PyBytes_Check(byteobj)) { 681 | PyErr_Format(PyExc_TypeError, "expected byte string as input"); 682 | goto _fail; 683 | } 684 | 685 | Py_INCREF(byteobj); 686 | encoded = PyBytes_AS_STRING(byteobj); 687 | encoded_size = (uint64_t)PyBytes_GET_SIZE(byteobj); 688 | /* 689 | if (encoded_size >= 512 * 1024 * 1024) { 690 | PyErr_Format(PyExc_ValueError, "encoded data > 512 MB not supported"); 691 | goto _fail; 692 | } 693 | */ 694 | encoded_size *= 8; /* bits */ 695 | 696 | if (*encoded == 0) { 697 | /* TODO: old style LZW codes are written in reversed bit order */ 698 | PyErr_Format(PyExc_ValueError, "can not decode old-style LZW"); 699 | goto _fail; 700 | } 701 | 702 | if ((*encoded != -128) || ((*(encoded+1) & 128))) { 703 | PyErr_Format(PyExc_ValueError, "strip must begin with CLEAR code"); 704 | goto _fail; 705 | } 706 | little_endian = (*(uint16_t*)encoded) & 128; 707 | 708 | table = PyMem_Malloc(4096 * sizeof(string_t)); 709 | if (table == NULL) { 710 | PyErr_Format(PyExc_MemoryError, "failed to allocate table"); 711 | goto _fail; 712 | } 713 | for (i = 0; i < 4096; i++) { 714 | table[i].len = 1; 715 | } 716 | 717 | /* determine length of output and string buffer */ 718 | table_size = 258; 719 | bitw = 9; 720 | shr = 23; 721 | mask = 4286578688u; 722 | bitcount = 0; 723 | decoded_size = 0; 724 | buffer_size = 0; 725 | buffersize = 0; 726 | code = 0; 727 | oldcode = 0; 728 | 729 | Py_BEGIN_ALLOW_THREADS 730 | while ((bitcount + bitw) <= encoded_size) { 731 | /* read next code */ 732 | GET_NEXT_CODE 733 | 734 | if (code == 257) break; /* end of information */ 735 | 736 | if (code == 256) { /* clearcode */ 737 | /* initialize table and switch to 9-bit */ 738 | table_size = 258; 739 | bitw = 9; 740 | shr = 23; 741 | mask = 4286578688u; 742 | if (buffersize > buffer_size) 743 | buffer_size = buffersize; 744 | buffersize = 0; 745 | 746 | /* read next code, skip clearcodes */ 747 | do { GET_NEXT_CODE } while (code == 256); 748 | 749 | if (code == 257) break; /* end of information */ 750 | 751 | decoded_size++; 752 | } else { 753 | if (code < table_size) { 754 | /* code is in table */ 755 | decoded_size += table[code].len; 756 | buffersize += table[oldcode].len + 1; 757 | } else { 758 | /* code is not in table */ 759 | decoded_size += table[oldcode].len + 1; 760 | } 761 | table[table_size++].len = table[oldcode].len + 1; 762 | 763 | /* increase bit-width if necessary */ 764 | switch (table_size) { 765 | case 511: 766 | bitw = 10; shr = 22; mask = 4290772992u; 767 | break; 768 | case 1023: 769 | bitw = 11; shr = 21; mask = 4292870144u; 770 | break; 771 | case 2047: 772 | bitw = 12; shr = 20; mask = 4293918720u; 773 | } 774 | } 775 | oldcode = code; 776 | } 777 | Py_END_ALLOW_THREADS 778 | 779 | if (buffersize > buffer_size) 780 | buffer_size = buffersize; 781 | 782 | if (code != 257) { 783 | /* 784 | PyErr_WarnEx( 785 | NULL, "py_decodelzw encountered unexpected end of stream", 1); 786 | */ 787 | } 788 | 789 | /* allocate output and buffer string */ 790 | decoded = PyBytes_FromStringAndSize(0, decoded_size); 791 | if (decoded == NULL) { 792 | PyErr_Format(PyExc_MemoryError, "failed to allocate decoded string"); 793 | goto _fail; 794 | } 795 | pdecoded = PyBytes_AS_STRING(decoded); 796 | 797 | buffer = PyMem_Malloc(buffer_size); 798 | if (buffer == NULL) { 799 | PyErr_Format(PyExc_MemoryError, "failed to allocate string buffer"); 800 | goto _fail; 801 | } 802 | 803 | /* decode input to output string */ 804 | table_size = 258; 805 | bitw = 9; 806 | shr = 23; 807 | mask = 4286578688u; 808 | bitcount = 0; 809 | pbuffer = buffer; 810 | 811 | Py_BEGIN_ALLOW_THREADS 812 | while ((bitcount + bitw) <= encoded_size) { 813 | /* read next code */ 814 | GET_NEXT_CODE 815 | 816 | if (code == 257) break; /* end of information */ 817 | 818 | if (code == 256) { /* clearcode */ 819 | /* initialize table and switch to 9-bit */ 820 | table_size = 258; 821 | bitw = 9; 822 | shr = 23; 823 | mask = 4286578688u; 824 | pbuffer = buffer; 825 | 826 | /* read next code, skip clearcodes */ 827 | do { GET_NEXT_CODE } while (code == 256); 828 | 829 | if (code == 257) break; /* end of information */ 830 | 831 | *pdecoded++ = code; 832 | } else { 833 | if (code < table_size) { 834 | /* code is in table */ 835 | /* decoded.append(table[code]) */ 836 | if (code < 256) { 837 | *pdecoded++ = code; 838 | } else { 839 | pstr = table[code].str; 840 | for (i = 0; i < table[code].len; i++) { 841 | *pdecoded++ = *pstr++; 842 | } 843 | } 844 | /* table.append(table[oldcode] + table[code][0]) */ 845 | table[table_size].str = pbuffer; 846 | if (oldcode < 256) { 847 | *pbuffer++ = oldcode; 848 | } else { 849 | pstr = table[oldcode].str; 850 | for (i = 0; i < table[oldcode].len; i++) { 851 | *pbuffer++ = *pstr++; 852 | } 853 | } 854 | if (code < 256) { 855 | *pbuffer++ = code; 856 | } else { 857 | *pbuffer++ = table[code].str[0]; 858 | } 859 | } else { 860 | /* code is not in table */ 861 | /* outstring = table[oldcode] + table[oldcode][0] */ 862 | /* decoded.append(outstring) */ 863 | /* table.append(outstring) */ 864 | table[table_size].str = pdecoded; 865 | if (oldcode < 256) { 866 | *pdecoded++ = oldcode; 867 | *pdecoded++ = oldcode; 868 | } else { 869 | pstr = table[oldcode].str; 870 | for (i = 0; i < table[oldcode].len; i++) { 871 | *pdecoded++ = *pstr++; 872 | } 873 | *pdecoded++ = table[oldcode].str[0]; 874 | } 875 | } 876 | table[table_size++].len = table[oldcode].len + 1; 877 | 878 | /* increase bit-width if necessary */ 879 | switch (table_size) { 880 | case 511: 881 | bitw = 10; shr = 22; mask = 4290772992u; 882 | break; 883 | case 1023: 884 | bitw = 11; shr = 21; mask = 4292870144u; 885 | break; 886 | case 2047: 887 | bitw = 12; shr = 20; mask = 4293918720u; 888 | } 889 | } 890 | oldcode = code; 891 | } 892 | Py_END_ALLOW_THREADS 893 | 894 | PyMem_Free(buffer); 895 | PyMem_Free(table); 896 | Py_DECREF(byteobj); 897 | return decoded; 898 | 899 | _fail: 900 | 901 | if (table) 902 | PyMem_Free(table); 903 | if (buffer) 904 | PyMem_Free(buffer); 905 | 906 | Py_XDECREF(byteobj); 907 | Py_XDECREF(decoded); 908 | 909 | return NULL; 910 | } 911 | 912 | /*****************************************************************************/ 913 | /* Create Python module */ 914 | 915 | char module_doc[] = 916 | "A Python C extension module for decoding PackBits and LZW encoded " 917 | "TIFF data.\n\n" 918 | "Refer to the tifffile.py module for documentation and tests.\n\n" 919 | "Authors:\n Christoph Gohlke \n" 920 | " Laboratory for Fluorescence Dynamics, University of California, Irvine." 921 | "\n\nVersion: %s\n"; 922 | 923 | static PyMethodDef module_methods[] = { 924 | #if MSB 925 | {"unpack_ints", (PyCFunction)py_unpackints, METH_VARARGS|METH_KEYWORDS, 926 | py_unpackints_doc}, 927 | #endif 928 | {"decode_lzw", (PyCFunction)py_decodelzw, METH_VARARGS, 929 | py_decodelzw_doc}, 930 | {"decode_packbits", (PyCFunction)py_decodepackbits, METH_VARARGS, 931 | py_decodepackbits_doc}, 932 | {"reverse_bitorder", (PyCFunction)py_reverse_bitorder, METH_VARARGS, 933 | py_reverse_bitorder_doc}, 934 | {NULL, NULL, 0, NULL} /* Sentinel */ 935 | }; 936 | 937 | #if PY_MAJOR_VERSION >= 3 938 | 939 | struct module_state { 940 | PyObject* error; 941 | }; 942 | 943 | #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) 944 | 945 | static int module_traverse(PyObject* m, visitproc visit, void *arg) { 946 | Py_VISIT(GETSTATE(m)->error); 947 | return 0; 948 | } 949 | 950 | static int module_clear(PyObject* m) { 951 | Py_CLEAR(GETSTATE(m)->error); 952 | return 0; 953 | } 954 | 955 | static struct PyModuleDef moduledef = { 956 | PyModuleDef_HEAD_INIT, 957 | "_tifffile", 958 | NULL, 959 | sizeof(struct module_state), 960 | module_methods, 961 | NULL, 962 | module_traverse, 963 | module_clear, 964 | NULL 965 | }; 966 | 967 | #define INITERROR return NULL 968 | 969 | PyMODINIT_FUNC 970 | PyInit__tifffile(void) 971 | 972 | #else 973 | 974 | #define INITERROR return 975 | 976 | PyMODINIT_FUNC 977 | init_tifffile(void) 978 | 979 | #endif 980 | { 981 | PyObject* module; 982 | 983 | char* doc = (char*)PyMem_Malloc(sizeof(module_doc) + sizeof(_VERSION_)); 984 | PyOS_snprintf(doc, sizeof(module_doc) + sizeof(_VERSION_), 985 | module_doc, _VERSION_); 986 | 987 | #if PY_MAJOR_VERSION >= 3 988 | moduledef.m_doc = doc; 989 | module = PyModule_Create(&moduledef); 990 | #else 991 | module = Py_InitModule3("_tifffile", module_methods, doc); 992 | #endif 993 | 994 | PyMem_Free(doc); 995 | 996 | if (module == NULL) 997 | INITERROR; 998 | 999 | if (_import_array() < 0) { 1000 | Py_DECREF(module); 1001 | INITERROR; 1002 | } 1003 | 1004 | { 1005 | #if PY_MAJOR_VERSION < 3 1006 | PyObject* s = PyString_FromString(_VERSION_); 1007 | #else 1008 | PyObject* s = PyUnicode_FromString(_VERSION_); 1009 | #endif 1010 | PyObject* dict = PyModule_GetDict(module); 1011 | PyDict_SetItemString(dict, "__version__", s); 1012 | Py_DECREF(s); 1013 | } 1014 | 1015 | #if PY_MAJOR_VERSION >= 3 1016 | return module; 1017 | #endif 1018 | } 1019 | 1020 | --------------------------------------------------------------------------------