Commits

Mikhail Korobov committed b504627

initial import

Comments (0)

Files changed (8)

+#projects
+\.idea
+
+#temp files
+\.pyc
+\.orig
+
+#os files
+\.DS_Store
+Thumbs.db
+
+#project-specific files
+\.tox
+stuff
+MANIFEST$
+^build
+\.ipynb$
+^dist
+^packbits.egg-info
+^\.coverage$
+\.html$
+Copyright (c) 2012 Mikhail Korobov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+include *.rst
+PackBits encoder/decoder
+========================
+
+This module implements a PackBits encoder/decoder for Python 2.x and 3.x.
+
+PackBits encoding is used in PSD and TIFF files.
+
+Installation
+------------
+
+::
+
+    pip install packbits
+
+Usage
+-----
+
+Import ``packbits`` module; then use ``packbits.encode(data)`` and
+``packbits.decode(data)`` functions.
+
+Contributing
+------------
+
+Development happens at github and bitbucket:
+
+* https://github.com/kmike/packbits
+* https://bitbucket.org/kmike/packbits
+
+The main issue tracker is at github: https://github.com/kmike/packbits/issues
+
+Feel free to submit ideas, bugs, pull requests (git or hg) or regular patches.
+
+In order to run tests, install `tox <http://tox.testrun.org>`_ and type
+
+::
+
+    tox
+
+from the source checkout.
+
+The license is MIT.
+#!/usr/bin/env python
+from distutils.core import setup
+from distutils.extension import Extension
+
+import sys
+
+for cmd in ('egg_info', 'develop'):
+    if cmd in sys.argv:
+        from setuptools import setup
+
+setup_args = dict(
+    name = 'packbits',
+    version = '0.5',
+    author = 'Mikhail Korobov',
+    author_email = 'kmike84@gmail.com',
+    url = 'https://github.com/kmike/packbits',
+
+    description = 'PackBits encoder/decoder',
+    long_description = open('README.rst').read(),
+    license = 'MIT License',
+
+    package_dir = {'': 'src'},
+    py_modules = ['packbits'],
+
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: MIT License',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.2',
+        'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: Implementation :: CPython',
+        'Programming Language :: Python :: Implementation :: PyPy',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+    ],
+)
+
+setup(**setup_args)
+
+## ========== make extension optional (copied from coverage.py) =========
+#
+#compile_extension = True
+#
+#if sys.platform.startswith('java'):
+#    # Jython can't compile C extensions
+#    compile_extension = False
+#
+#if '__pypy__' in sys.builtin_module_names:
+#    # Cython extensions are slow under PyPy
+#    compile_extension = False
+#
+#if compile_extension:
+#    setup_args.update(dict(
+#        ext_modules = [
+#            Extension("_packbits", sources=["src/_packbits.c"])
+#        ],
+#    ))
+#
+## For a variety of reasons, it might not be possible to install the C
+## extension.  Try it with, and if it fails, try it without.
+#try:
+#    setup(**setup_args)
+#except:     # pylint: disable=W0702
+#    # When setup() can't compile, it tries to exit.  We'll catch SystemExit
+#    # here :-(, and try again.
+#    if 'install' not in sys.argv or 'ext_modules' not in setup_args:
+#        # We weren't trying to install an extension, so forget it.
+#        raise
+#    msg = "Couldn't install with extension module, trying without it..."
+#    exc = sys.exc_info()[1]
+#    exc_msg = "%s: %s" % (exc.__class__.__name__, exc)
+#    print("**\n** %s\n** %s\n**" % (msg, exc_msg))
+#
+#    del setup_args['ext_modules']
+#    setup(**setup_args)
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals, division, print_function
+
+def decode(data):
+    """
+    Decodes a PackBit encoded data.
+    """
+    data = bytearray(data) # <- python 2/3 compatibility fix
+    result = bytearray()
+    pos = 0
+    while pos < len(data):
+        header_byte = data[pos]
+        if header_byte > 127:
+            header_byte -= 256
+        pos += 1
+
+        if 0 <= header_byte <= 127:
+            result.extend(data[pos:pos+header_byte+1])
+            pos += header_byte+1
+        elif header_byte == -128:
+            pass
+        else:
+            result.extend([data[pos]] * (1 - header_byte))
+            pos += 1
+
+    return bytes(result)
+
+
+def encode(data):
+    """
+    Encodes data using PackBits encoding.
+    """
+    if len(data) == 0:
+        return data
+
+    if len(data) == 1:
+        return b'\x00' + data
+
+    data = bytearray(data)
+
+    state = 'RLE' if data[1] == data[0] else 'RAW'
+
+    result = bytearray()
+    buf = bytearray()
+    pos = 0
+    repeat_count = 0
+    MAX_LENGTH = 127
+
+    def finish_raw():
+        result.append(len(buf)-1)
+        result.extend(buf)
+        buf[:] = bytearray()
+
+    def finish_rle():
+        result.append(256-(repeat_count - 1))
+        result.append(data[pos])
+
+    while  pos < len(data)-1:
+        current_byte = data[pos]
+
+        if data[pos] == data[pos+1]:
+            if state == 'RAW':
+                # end of RAW data
+                finish_raw()
+                state = 'RLE'
+                repeat_count = 1
+            elif state == 'RLE':
+                if repeat_count == MAX_LENGTH:
+                    # restart the encoding
+                    finish_rle()
+                    repeat_count = 0
+                # move to next byte
+                repeat_count += 1
+
+        else:
+            if state == 'RLE':
+                repeat_count += 1
+                finish_rle()
+                state = 'RAW'
+                repeat_count = 0
+            elif state == 'RAW':
+                if len(buf) == MAX_LENGTH:
+                    # restart the encoding
+                    finish_raw()
+
+                buf.append(current_byte)
+
+        pos += 1
+
+    if state == 'RAW':
+        buf.append(data[pos])
+        finish_raw()
+    else:
+        repeat_count += 1
+        finish_rle()
+
+    return bytes(result)
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
+
+import packbits
+
+DATA = b'\xFE\xAA\x02\x80\x00\x2A\xFD\xAA\x03\x80\x00\x2A\x22\xF7\xAA'
+RESULT = b'\xAA\xAA\xAA\x80\x00\x2A\xAA\xAA\xAA\xAA\x80\x00\x2A\x22\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA'
+
+def test_decode():
+    decoded = packbits.decode(DATA)
+    assert decoded == RESULT
+
+def test_encode_decode():
+    encoded = packbits.encode(RESULT)
+    decoded = packbits.decode(encoded)
+    assert decoded == RESULT
+
+def test_encode_empty():
+    assert packbits.encode(b'') == b''
+
+def test_encode_single():
+    encoded = packbits.encode(b'X')
+    assert encoded == b'\x00X'
+    assert packbits.decode(encoded) == b'X'
+
+def test_raw():
+    encoded = packbits.encode(b'123')
+    assert encoded == b'\x02123'
+    assert packbits.decode(encoded) == b'123'
+
+def test_encode2():
+    encoded = packbits.encode(b'112112')
+    assert packbits.decode(encoded) == b'112112'
+
+def test_encode_long_rle():
+    data = b'1' * 126
+    encoded = packbits.encode(data)
+    assert packbits.decode(encoded) == data
+
+def test_encode_long_rle2():
+    data = b'1' * 127
+    encoded = packbits.encode(data)
+    assert packbits.decode(encoded) == data
+
+def test_encode_long_rle3():
+    data = b'1' * 128
+    encoded = packbits.encode(data)
+    assert packbits.decode(encoded) == data
+
+def test_restart_rle():
+    data = b'1' * 127 + b'foo'
+    encoded = packbits.encode(data)
+    assert packbits.decode(encoded) == data
+
+def test_encode_long_raw():
+    data = b'12345678' * 17
+    encoded = packbits.encode(data)
+    print(encoded)
+    assert packbits.decode(encoded) == data
+
+def test_encode_long_raw():
+    data = b'12345678' * 16
+    encoded = packbits.encode(data)
+    assert packbits.decode(encoded) == data
+
+def test_encode_long():
+    data = b'1' * 128 + b'12345678' * 17
+    encoded = packbits.encode(data)
+    assert packbits.decode(encoded) == data
+
+[tox]
+envlist = py26,py27,py32,py33,pypy
+
+[testenv]
+deps=
+    pytest
+
+commands=
+    py.test []
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.