Search code examples
pythonimagecompressiondxt

DXT Compression for Python


I am currently working with Images and some are DXT compressed, I need a easy way of decompressing and compressing of these files with Python. Unfortunatly I was unable to find any library which does that for me.

Does anyone know a good DXT-Compression library for Python, or an interface to a compresion library?

-- dav1d

Edit:

libsquish was the way to go here, but unfortunatly the Python-Bindings don't work, so here the solution.

Make a squish-Wrapper in C++ which exports functions which internally access libsquish:

#include <squish.h>

typedef unsigned char u8;

extern "C" {
    void CompressMasked( u8 const* rgba, int mask, void* block, int flags ) {
        squish::CompressMasked(rgba, mask, block, flags);
    }

    void Compress( u8 const* rgba, void* block, int flags ) {
        squish::Compress(rgba, block, flags);
    }

    void Decompress( u8* rgba, void const* block, int flags ) {
        squish::Decompress(rgba, block, flags);
    }

    int GetStorageRequirements( int width, int height, int flags ) {
        return squish::GetStorageRequirements(width, height, flags);
    }

    void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags ) {
        squish::CompressImage(rgba, width, height, blocks, flags);
    }

    void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags ) {
        squish::DecompressImage(rgba, width, height, blocks, flags);
    }
}

Create a dynamic library (a dll on windows, or a so on linux, I called it libsquishc.so) and open it with ctypes.

My approach (just exports the functions I need):

from ctypes import CDLL, c_int, byref, create_string_buffer
import os.path

libsquish_path = os.path.join(os.path.split(os.path.abspath(__file__))[0], 'libsquishc.so')
libsquish = CDLL(libsquish_path)


DXT1 = 1 << 0 
DXT3 = 1 << 1 
DXT5 = 1 << 2 

COLOR_ITERATIVE_CLUSTER_FIT = 1 << 8    
COLOR_CLUSTER_FIT = 1 << 3    
COLOR_RANGE_FIT = 1 << 4
WEIGHT_COLOR_BY_ALPHA = 1 << 7


GetStorageRequirements = libsquish.GetStorageRequirements
GetStorageRequirements.argtypes = [c_int, c_int, c_int]
GetStorageRequirements.restype = c_int

def compress_image(rgba, width, height, flags):
    rgba = create_string_buffer(rgba)

    c = GetStorageRequirements(width, height, flags)
    buffer = create_string_buffer(c)

    libsquish.Compress(byref(rgba), byref(buffer), c_int(flags))

    return buffer.raw

def decompress_image(block, width, height, flags):
    block = create_string_buffer(block)

    c = width*height*4
    rgba = create_string_buffer(c)

    libsquish.DecompressImage(byref(rgba), c_int(width), c_int(height), byref(block), c_int(flags))

    return rgba.raw

Solution

  • libSquish has a patch to add Python bindings.

    Edit: Installation procedure seems to be

    1. download squish-1.11.zip
    2. unpack and compile - should result in a libsquish.a file
    3. download and install Cython (sounds like you did this)
    4. create a temporary directory and "apply" the patch - it drops a bunch of new files which are the binding code
    5. run setup (sudo python setup.py install)

    If you did this and still have errors then maybe you should (a) share the actual error messages so we can figure out why, or (b) contact the patch author directly - mat (at) kivy.org

    Edit2: the compile error is short enough that I will include it here:

    running install
    running build
    running build_ext
    skipping 'squish.c' Cython extension (up-to-date)
    building 'squish' extension
    gcc -pthread -fno-strict-aliasing -march=i686 -mtune=generic -O2 -pipe -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 -DNDEBUG -march=i686 -mtune=generic -O2 -pipe -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 -fPIC -I.. -I/usr/include/python2.7 -c squish.c -o build/temp.linux-i686-2.7/squish.o
    In file included from squish.c:274:0:
    /usr/include/squish.h:32:1: error: unknown type name 'namespace'
    /usr/include/squish.h:32:18: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
    squish.c: In function '__pyx_pf_6squish_compressImage':
    squish.c:790:22: error: 'squish' undeclared (first use in this function)
    squish.c:790:22: note: each undeclared identifier is reported only once for each function it appears in
    squish.c:790:28: error: expected ';' before ':' token
    squish.c:866:10: error: expected expression before ':' token
    squish.c: In function '__pyx_pf_6squish_2decompressImage':
    squish.c:1202:10: error: expected expression before ':' token
    error: command 'gcc' failed with exit status 1
    

    The relevant section of squish.h looks like

    #ifndef SQUISH_H
    #define SQUISH_H
    
    //! All squish API functions live in this namespace.
    namespace squish {
    
    // -----------------------------------------------------------------------------
    

    and it looks like it's choking on the namespace keyword, which I'd say means it's compiling as C when it should be compiled as C++.