Update of /cvsroot/freevo/freevo/lib/pyimlib2
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31637/pyimlib2

Added Files:
        AUTHORS Imlib2.py Makefile README TODO display.c display.h 
        font.c font.h image.c image.h imlib2.c pyimlib2.spec 
        rawformats.c rawformats.h setup.py 
Log Message:
pyimlib2, an imlib2 wrapper for python

--- NEW FILE: rawformats.h ---
unsigned int get_raw_bytes_size(char *format);
unsigned char *get_raw_bytes(char *format, unsigned char *dstbuf);
unsigned char *convert_raw_rgba_bytes(char *from_format, char *to_format,
                  unsigned char *from_buf, unsigned char *to_buf,
                  int w, int h);
void init_rgb2yuv_tables();

--- NEW FILE: display.h ---
#include <X11/Xlib.h>

#define Display_PyObject_Check(v) ((v)->ob_type == &Display_PyObject_Type)

typedef struct {
        PyObject_HEAD

        Display *display;
        Window   window;
        Visual  *visual;
        Colormap cmap;
        int      depth;
} Display_PyObject;

extern PyTypeObject Display_PyObject_Type;
void Display_PyObject__dealloc(Display_PyObject *);
PyObject *Display_PyObject__getattr(Display_PyObject *, char *);

PyObject *display_new(int w, int h);

--- NEW FILE: image.h ---
#define Image_PyObject_Check(v) ((v)->ob_type == &Image_PyObject_Type)

extern key_t _imlib2_shm_key;
extern int _imlib2_shm_id;
extern char *_imlib2_shm_buf;

extern key_t _imlib2_sem_key;
extern int _imlib2_sem_id;

typedef struct {
        PyObject_HEAD
        Imlib_Image *image;
} Image_PyObject;

extern PyTypeObject Image_PyObject_Type;
void Image_PyObject__dealloc(Image_PyObject *);
PyObject *Image_PyObject__getattr(Image_PyObject *, char *);


--- NEW FILE: TODO ---
- Wrap the rest of the API
- Do a test suite

--- NEW FILE: display.c ---
#include <Python.h>
#include "display.h"
#include <Imlib2.h>
#include "image.h"

PyTypeObject Display_PyObject_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "_Imlib2.Display",             /*tp_name*/
    sizeof(Display_PyObject),    /*tp_basicsize*/
    0,                         /*tp_itemsize*/
        (destructor)Display_PyObject__dealloc, /* tp_dealloc */
    0,                         /*tp_print*/
        (getattrfunc)Display_PyObject__getattr, /* tp_getattr */
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
    "Imlib2 Display Object"           /* tp_doc */
};

void Display_PyObject__dealloc(Display_PyObject *self)
{
        PyMem_DEL(self);
}

void display_set_context(Display_PyObject *self)
{
        imlib_context_set_display(self->display);
        imlib_context_set_visual(self->visual);
        imlib_context_set_colormap(self->cmap);
        imlib_context_set_drawable(self->window);
}

PyObject *Display_PyObject__render(PyObject *self, PyObject *args)
{
    Image_PyObject *img;
        int dst_x = 0, dst_y = 0, src_x = 0, src_y = 0, 
            w = -1, h = -1, img_w, img_h, dither = 1, blend = 0;
    if (!PyArg_ParseTuple(args, "O!|(ii)(ii)(ii)ii", &Image_PyObject_Type, &img, 
&dst_x, &dst_y, &src_x, &src_y, &w, &h, &dither, &blend))
        return NULL;

        imlib_context_set_image(((Image_PyObject *)img)->image);
        img_w = imlib_image_get_width();
        img_h = imlib_image_get_height();

        if (w == -1) w = img_w;
        if (h == -1) h = img_h;

        display_set_context((Display_PyObject *)self);

        imlib_context_set_dither(dither);
        imlib_context_set_blend(blend);
        if (src_x == 0 && src_y == 0 && w == img_w && h == img_h)
                imlib_render_image_on_drawable(dst_x, dst_y);
        else
                imlib_render_image_part_on_drawable_at_size(src_x, src_y, w, h, dst_x, 
dst_y, w, h);

        Py_INCREF(Py_None);
        return Py_None;
}

PyMethodDef Display_PyObject_methods[] = {
        { "render", Display_PyObject__render, METH_VARARGS },
        { NULL, NULL }
};

PyObject *Display_PyObject__getattr(Display_PyObject *self, char *name)
{
        return Py_FindMethod(Display_PyObject_methods, (PyObject *)self, name);
}


PyObject *display_new(int w, int h)
{
        Display_PyObject *o;
        int screen;
        XEvent ev;

        o = PyObject_NEW(Display_PyObject, &Display_PyObject_Type);
        o->display = XOpenDisplay(NULL);
        screen = DefaultScreen(o->display);

        o->visual = DefaultVisual(o->display, screen);
        o->depth = DefaultDepth(o->display, screen);
        o->cmap = DefaultColormap(o->display, screen);

        o->window = XCreateSimpleWindow(o->display, 
                        DefaultRootWindow(o->display),
                        0, 0, w, h, 0, 0, 0);

        XSelectInput(o->display, o->window, ButtonPressMask | ButtonReleaseMask | 
                PointerMotionMask | ExposureMask);
        XMapWindow(o->display, o->window);

        do {
                XNextEvent(o->display, &ev);
        } while (XPending(o->display));

        return (PyObject *)o;
}

// vim: ts=4

--- NEW FILE: rawformats.c ---
#define X_DISPLAY_MISSING
#include <Imlib2.h>
#include <string.h>


/* RGB to YUV conversion tables pulled from speedy.c in tvtime.  Here
 * are the copyright notices on that file:
 *
 *   Copyright (c) 2002, 2003 Billy Biggs <[EMAIL PROTECTED]>.
 *   Copyright (C) 2001 Matthew J. Marjanovic <[EMAIL PROTECTED]>
 *
 * Lookup tables is not that much faster than doing the (integer)
 * arithmetic in the inner loop (7% by my calculations), but it is
 * presumably more correct and hey, 7% isn't that bad. :)
 */

#define rgb2y(R,G,B) ( (Y_R[ r ] + Y_G[ g ] + Y_B[ b ]) >> FP_BITS )
#define rgb2u(R,G,B) ( (U_R[ r ] + U_G[ g ] + U_B[ b ]) >> FP_BITS )
#define rgb2v(R,G,B) ( (V_R[ r ] + V_G[ g ] + V_B[ b ]) >> FP_BITS )
#define FP_BITS 18
static int Y_R[256], Y_G[256], Y_B[256],
           U_R[256], U_G[256], U_B[256],
           V_R[256], V_G[256], V_B[256];


static int 
myround(double n)
{
        if (n >= 0) return (int)(n + 0.5);
        else return (int)(n - 0.5);
}

void
init_rgb2yuv_tables()
{
        int i;
        for (i = 0; i < 256; i++) {
                Y_R[i] = myround(0.299 * (double)i * 219.0 / 255.0 * 
(double)(1<<FP_BITS));
                Y_G[i] = myround(0.587 * (double)i * 219.0 / 255.0 * 
(double)(1<<FP_BITS));
                Y_B[i] = myround((0.114 * (double)i * 219.0 / 255.0 * 
(double)(1<<FP_BITS)) + (double)(1<<(FP_BITS-1)) + (16.0 * (double)(1<<FP_BITS)));
                                                                                
                U_R[i] = myround(-0.168736 * (double)i * 224.0 / 255.0 * 
(double)(1<<FP_BITS));
                U_G[i] = myround(-0.331264 * (double)i * 224.0 / 255.0 * 
(double)(1<<FP_BITS));
                U_B[i] = myround((0.500 * (double)i * 224.0 / 255.0 * 
(double)(1<<FP_BITS)) + (double)(1<<(FP_BITS-1)) + (128.0 * (double)(1<<FP_BITS))); 

                V_R[i] = myround(0.500 * (double)i * 224.0 / 255.0 * 
(double)(1<<FP_BITS));
                V_G[i] = myround(-0.418688 * (double)i * 224.0 / 255.0 * 
(double)(1<<FP_BITS));
                V_B[i] = myround((-0.081312 * (double)i * 224.0 / 255.0 * 
(double)(1<<FP_BITS)) + (double)(1<<(FP_BITS-1)) + (128.0 * (double)(1<<FP_BITS))); 
        }

}

// End of code ripped off from speedy.c :)
///////////////////////////////////////////////////////////////////////

unsigned int
get_raw_bytes_size(char *format)
{
        unsigned int w = imlib_image_get_width(),
                     h = imlib_image_get_height();
        
        if (!strcmp(format, "YV12A"))
                return w * h * 2 + ((w * h / 4) * 2);
        else if (!strcmp(format, "YV12"))
                return w * h + ((w * h / 4) * 2);
        else 
                // assume combination of RGBA or RGB
                return w * h * strlen(format);
}


unsigned char *
convert_raw_rgba_bytes(char *from_format, char *to_format,
                  unsigned char *from_buf, unsigned char *to_buf,
                  int w, int h)
{
        int from_bpp, to_bpp, i;
        unsigned char fr, fb, fg, fa, tr, tb, tg, ta, *from_ptr, *to_ptr;
        from_bpp = strlen(from_format);
        to_bpp = strlen(to_format);

        if (to_buf == 0)
                to_buf = (unsigned char *)malloc(w*h*to_bpp);


#define LOOP_START \
        for (from_ptr = from_buf, to_ptr = to_buf; from_ptr < from_buf + w*h*from_bpp; 
from_ptr += from_bpp)


        // FIXME: pointless code duplication follows.

        /* Hard code the common cases of BGRA -> RGB/A.  This is pretty much
         * as fast as memcpy.  I don't think it gets much faster without
         * MMX.
         */
        if (!strcmp(from_format, "BGRA") && !strcmp(to_format, "RGB")) {
                LOOP_START {
                        *(to_ptr++) = *(from_ptr + 2); *(to_ptr++) = *(from_ptr + 1);
                        *(to_ptr++) = *(from_ptr + 0);
                }
        return to_buf;
        } 
        if (!strcmp(from_format, "BGRA") && !strcmp(to_format, "RGBA")) {
                LOOP_START {
                        *(to_ptr++) = *(from_ptr + 2); *(to_ptr++) = *(from_ptr + 1);
                        *(to_ptr++) = *(from_ptr + 0); *(to_ptr++) = *(from_ptr + 3);
                }
        return to_buf;
        } 


        for (i = 0; i < to_bpp; i ++) {
                if (to_format[i] == 'R') tr = i;
                else if (to_format[i] == 'G') tg = i;
                else if (to_format[i] == 'B') tb = i;
                else if (to_format[i] == 'A') ta = i;
        }
        for (i = 0; i < from_bpp; i ++) {
                if (from_format[i] == 'R') fr = i;
                else if (from_format[i] == 'G') fg = i;
                else if (from_format[i] == 'B') fb = i;
                else if (from_format[i] == 'A') fa = i;
        }

        LOOP_START {
                *(to_ptr + tr) = *(from_ptr + fr);
                *(to_ptr + tg) = *(from_ptr + fg);
                *(to_ptr + tb) = *(from_ptr + fb);
                if (to_bpp == 4) 
                        *(to_ptr + ta) = (from_bpp==4)?*(from_ptr + fa):255;

                to_ptr += to_bpp;
        } 
        return to_buf;
}


/* Convert the imlib data (which is BGRA) to planar YV12 plus an
   8bpp alpha plane.  This function is ugly but it should be
   reasonably tight.
*/
unsigned char *_get_yv12_image(int w, int h, unsigned char *srcbuf,
                               unsigned char *dstbuf)
{
        unsigned char *src_ptr, *y_ptr, *u_ptr, *v_ptr, *a_ptr;
        unsigned char r, g, b, a, Ar, Ab, Ag;
        int pos;

        y_ptr = dstbuf;         pos = w * h;
        u_ptr = dstbuf + pos;   pos += (w * h) / 4;
        v_ptr = dstbuf + pos;   pos += (w * h) / 4;
        a_ptr = dstbuf + pos;

        int stride = w*4;
        // Calculate luma plane
        for (src_ptr = srcbuf; src_ptr < srcbuf + stride*h;) {
                b = *(src_ptr++); g = *(src_ptr++); r = *(src_ptr++);
                *(y_ptr++) = rgb2y(r, g, b);
                *(a_ptr++) = *(src_ptr++);
        }

        /* Calculate chroma planes.
         * This macro nonsense is to handle the case where the image's
         * width is odd.  We don't want to put the if (image is odd)
         * comparison in the inner loop since that's pointlessly slow.
         * Given a block of 2x2 pixels:
         *    A  B
     *    C  D
     * We calculate the chroma values by averaging the RGB values between
         * A and C.  This follows MPEG2 spec, and it may not be correct in
         * all cases but it's a good default.
         */
 
#define YV12_LOOP(expr) { \
        for (src_ptr = srcbuf + stride; src_ptr < srcbuf-4+stride*h; src_ptr+=4) { \
                Ab = *(src_ptr-stride); Ag = *(src_ptr-stride+1);  \
                Ar = *(src_ptr-stride+2); \
                b = *(src_ptr++); g = *(src_ptr++); r = *(src_ptr++); src_ptr++; \
                r=(r+Ar)>>1; g = (g+Ag)>>1; b = (b+Ab)>>1; \
                *(u_ptr++) = rgb2u(r, g, b); \
                *(v_ptr++) = rgb2v(r, g, b); \
                expr; \
        } }

        if (w & 1)
                YV12_LOOP( if ( (src_ptr-srcbuf) % stride == 0)
                                src_ptr += stride+4 )
        else
                YV12_LOOP( if ( ((src_ptr+4)-srcbuf) % stride == 0) src_ptr += stride; 
)
        return dstbuf;
}


unsigned char *
get_raw_bytes(char *format, unsigned char *dstbuf)
{
        unsigned int w, h, bufsize;
        unsigned char *srcbuf;

        w = imlib_image_get_width(),
        h = imlib_image_get_height(),
        bufsize = get_raw_bytes_size(format);

        imlib_image_set_has_alpha(1);
        srcbuf = (unsigned char *)imlib_image_get_data_for_reading_only();
        if (dstbuf == 0)
                dstbuf = (unsigned char *)malloc(bufsize);
        
        if (!strcmp(format, "YV12A"))
                _get_yv12_image(w, h, srcbuf, dstbuf);
        else if (!strcmp(format, "BGRA"))  {
                memcpy(dstbuf, srcbuf, bufsize);
        }
        else
                dstbuf = convert_raw_rgba_bytes("BGRA", format, srcbuf, dstbuf, w, h);
        return dstbuf;
}

// vim: ts=4

--- NEW FILE: Makefile ---
all:
        python setup.py build
# Copy the module to the cwd for easier testing
        cp -f build/lib*/_Imlib2module.so .

install:
        python setup.py install
clean:
        python setup.py clean
        rm -rf build _Imlib2module.so *.pyc

--- NEW FILE: image.c ---
/* Imlib2 module for python.
   Written by Jason Tackaberry <[EMAIL PROTECTED]> and released under the LGPL.

   This is a quick hack.  It is not complete.
   See Imlib2.py for usage details.
*/

#include <Python.h>
#define X_DISPLAY_MISSING
#include <Imlib2.h>

#include "image.h"
#include "rawformats.h"
#include "font.h"

#include <sys/mman.h>
#include <fcntl.h>

static int _shm_ctr = 0;

PyTypeObject Image_PyObject_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "_Imlib2.Image",             /*tp_name*/
    sizeof(Image_PyObject),    /*tp_basicsize*/
    0,                         /*tp_itemsize*/
        (destructor)Image_PyObject__dealloc, /* tp_dealloc */
    0,                         /*tp_print*/
        (getattrfunc)Image_PyObject__getattr, /* tp_getattr */
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
    "Imlib2 Image Object"           /* tp_doc */
};

void Image_PyObject__dealloc(Image_PyObject *self)
{
        imlib_context_set_image(self->image);
//      fprintf(stderr, "IMLIB free image %s\n", imlib_image_get_filename());
        imlib_free_image();
        PyMem_DEL(self);
}

PyObject *Image_PyObject__clear(PyObject *self, PyObject *args)
{ 
        int x, y, w, h, max_w, max_h, cur_y;
        unsigned char *data;
        

        if (!PyArg_ParseTuple(args, "iiii", &x, &y, &w, &h))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        data = (unsigned char *)imlib_image_get_data();
        max_w = imlib_image_get_width();
        max_h = imlib_image_get_height();
        if (x < 0) x = 0;
        if (y < 0) y = 0;
        if (x+w > max_w) w = max_w-x;
        if (y+h > max_h) h = max_h-y;

        // TODO: make this faster.
        for (cur_y = y; cur_y < y + h; cur_y++)
                memset(&data[cur_y*max_w*4+(x*4)], 0, 4*w);

        imlib_image_put_back_data((DATA32 *)data);
        Py_INCREF(Py_None);
        return Py_None;
}

PyObject *Image_PyObject__scale(PyObject *self, PyObject *args)
{ 
        int dst_w, dst_h, src_w, src_h;
        Imlib_Image *image;
        Image_PyObject *o;

        if (!PyArg_ParseTuple(args, "ii", &dst_w, &dst_h))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        src_w = imlib_image_get_width();
        src_h = imlib_image_get_height();
        image = imlib_create_cropped_scaled_image(0, 0, src_w, src_h, dst_w, dst_h);
        if (!image) {
                PyErr_Format(PyExc_RuntimeError, "Failed scaling image (%d, %d)", 
dst_w, dst_h);
                return NULL;
        }
        
        o = PyObject_NEW(Image_PyObject, &Image_PyObject_Type);
        o->image = image;
        return (PyObject *)o;
}

PyObject *Image_PyObject__crop(PyObject *self, PyObject *args)
{ 
        int x, y, w, h, src_w, src_h;
        Imlib_Image *image;
        Image_PyObject *o;

        if (!PyArg_ParseTuple(args, "iiii", &x, &y, &w, &h))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        src_w = imlib_image_get_width();
        src_h = imlib_image_get_height();
        if (w > src_w) w = src_w;
        if (h > src_h) h = src_h;
        if (x > src_w) x = 0;
        if (y > src_h) y = 0;

        // Errmm, why imlib_Create_cropped_image terribly broken?
        //image = imlib_create_cropped_image(x, y, w, h);

        image = imlib_create_cropped_scaled_image(x, y, w, h, w, h);
        if (!image) {
                PyErr_Format(PyExc_RuntimeError, "Failed cropping image (%d, %d), (%d, 
%d)", x, y, w, h);
                return NULL;
        }
        
        o = PyObject_NEW(Image_PyObject, &Image_PyObject_Type);
        o->image = image;
        return (PyObject *)o;
}

PyObject *Image_PyObject__rotate(PyObject *self, PyObject *args)
{ 
        Imlib_Image *image;
        Image_PyObject *o;
        double angle;

        if (!PyArg_ParseTuple(args, "d", &angle))
                return NULL;

        fprintf(stderr, "Rotate image by %f\n", angle);
        imlib_context_set_image(((Image_PyObject *)self)->image);

        image = imlib_create_rotated_image(angle);
        if (!image) {
                PyErr_Format(PyExc_RuntimeError, "Failed rotating image (%f) degrees", 
angle);
                return NULL;
        }
        
        o = PyObject_NEW(Image_PyObject, &Image_PyObject_Type);
        o->image = image;
        return (PyObject *)o;
}

PyObject *Image_PyObject__clone(PyObject *self, PyObject *args)
{ 
        int dst_w, dst_h, src_w, src_h;
        Imlib_Image *image;
        Image_PyObject *o;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        image = imlib_clone_image();
        if (!image) {
                PyErr_Format(PyExc_RuntimeError, "Failed to clone image");
                return NULL;
        }
        
        o = PyObject_NEW(Image_PyObject, &Image_PyObject_Type);
        o->image = image;
        return (PyObject *)o;
}


PyObject *Image_PyObject__blend(PyObject *self, PyObject *args)
{ 
        int dst_x, dst_y, src_alpha = 255, merge_alpha = 1,
            src_w, src_h, src_x = 0, src_y = 0;
        Image_PyObject *src;
        Imlib_Image *src_img;
        Imlib_Color_Modifier cmod;

        if (!PyArg_ParseTuple(args, "O!(ii)(ii)(ii)ii", &Image_PyObject_Type, &src, 
&dst_x, &dst_y, &src_x, &src_y, &src_w, &src_h, &src_alpha, &merge_alpha))
                return NULL;

        Py_INCREF(Py_None);

        if (src_alpha == 0)
                return Py_None;

        src_img = ((Image_PyObject *)src)->image;

        // This yields incorrect results.  We would need to duplicate
        // the image and apply the color modifer to it for this to
        // have the correct result, but that's actually slower than the
        // above code.
        if (src_alpha < 255) {
                unsigned char a[256], linear[256];
                int i;
                for (i = 0; i < 256; i++) {
                        int temp = (i * src_alpha) + 0x80;
                        a[i] = ((temp + (temp >> 8)) >> 8);
                        linear[i] = i;
                }
                cmod = imlib_create_color_modifier();
                imlib_context_set_color_modifier(cmod);
                imlib_set_color_modifier_tables(linear, linear, linear, a);
        }

        imlib_context_set_image(((Image_PyObject *)self)->image);

//      imlib_context_set_operation(IMLIB_OP_SUBTRACT);
        imlib_context_set_blend( src_alpha == 256 ? 0 : 1);
        imlib_blend_image_onto_image(src_img, merge_alpha, src_x, src_y, 
                        src_w, src_h, dst_x, dst_y,
                        src_w, src_h);
        imlib_context_set_blend(1);
        imlib_context_set_color_modifier(NULL);

        return Py_None;
}

PyObject *Image_PyObject__draw_mask(PyObject *self, PyObject *args)
{ 
        int dst_x, dst_y, mask_w, mask_h, dst_w, dst_h;
        Image_PyObject *mask;
        unsigned long xpos, ypos, dst_pos, mask_pos;
        unsigned char *dst_data, *mask_data;

        if (!PyArg_ParseTuple(args, "O!ii", &Image_PyObject_Type, &mask, &dst_x, 
&dst_y))
                return NULL;

        Py_INCREF(Py_None);

        imlib_context_set_image(((Image_PyObject *)mask)->image);
        mask_w = imlib_image_get_width();
        mask_h = imlib_image_get_height();
        mask_data = (unsigned char *)imlib_image_get_data_for_reading_only();

        imlib_context_set_image(((Image_PyObject *)self)->image);
        dst_w = imlib_image_get_width();
        dst_h = imlib_image_get_height();
        dst_data = (unsigned char *)imlib_image_get_data();

        // Use the passed image as a mask.  Again, no obvious way to do this in
        // Imlib natively.
        for (ypos = 0; ypos < mask_h; ypos++) {
                if (ypos + dst_y >= dst_h) break;
                for (xpos = 0; xpos < mask_w; xpos++) {
                        if (xpos + dst_x >= dst_w) break;
                        mask_pos = (xpos << 2) + (ypos * mask_w << 2);
                        dst_pos = ((dst_x + xpos) << 2) + ((dst_y + ypos) * dst_w << 
2);
                        
                        unsigned char *mask_chunk = &mask_data[mask_pos],
                                      *dst_chunk = &dst_data[dst_pos],
                                      // Any way to optimize this?
                                      avg = (mask_chunk[0] + mask_chunk[1] + 
mask_chunk[2]) / 3;

                        // Blend average (grayscale) pixel from the mask with the 
alpha channel of the image
                        int temp = (dst_chunk[3] * avg) + 0x80;
                        dst_chunk[3] = ((temp + (temp >> 8)) >> 8);
                        dst_chunk[3] = dst_chunk[3] >> 1;
                }
        }
        imlib_image_put_back_data((DATA32 *)dst_data);
                        
        return Py_None;
}

PyObject *Image_PyObject__draw_text(PyObject *self, PyObject *args)
{ 
        int x, y, w, h, advance_w, advance_h, r, g, b, a, descent, inset;
        char *text;
        Font_PyObject *font;

        if (!PyArg_ParseTuple(args, "O!iis(iiii)", &Font_PyObject_Type, &font, &x, &y, 
&text, &r, &g, &b, &a))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        imlib_context_set_font(((Font_PyObject *)font)->font);
        
        imlib_context_set_color(r, g, b, a);
        //descent = imlib_get_maximum_font_descent();
        //inset = imlib_get_text_inset(text);
//      y = y + descent + inset + 2;
        //printf("TEXT INSET: %d ASC %d  DESC %d\n", imlib_get_text_inset(text), 
imlib_get_font_ascent(), imlib_get_font_descent());
        imlib_text_draw_with_return_metrics(x, y, text, &w, &h, &advance_w, 
&advance_h);
        return Py_BuildValue("(llll)", w, h, advance_w, advance_h);
}

PyObject *Image_PyObject__draw_rectangle(PyObject *self, PyObject *args)
{ 
        int x, y, w, h, r, g, b, a, fill = 0;

        if (!PyArg_ParseTuple(args, "iiii(iiii)|i", &x, &y, &w, &h, &r, &g, &b, &a, 
&fill))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        imlib_image_set_has_alpha(1);
//      imlib_context_set_operation(IMLIB_OP_SUBTRACT);
        imlib_context_set_color(r, g, b, a);
        if (!fill)
                imlib_image_draw_rectangle(x, y, w, h);
        else
                imlib_image_fill_rectangle(x, y, w, h);

//      imlib_image_set_has_alpha(1);
        Py_INCREF(Py_None);
        return Py_None;
}

PyObject *Image_PyObject__draw_ellipse(PyObject *self, PyObject *args)
{ 
        int xc, yc, ea, eb, r, g, b, a, fill = 0;

        if (!PyArg_ParseTuple(args, "iiii(iiii)|i", &xc, &yc, &ea, &eb, &r, &g, &b, 
&a, &fill))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        imlib_context_set_color(r, g, b, a);
        imlib_context_set_anti_alias(1);
        if (!fill)
                imlib_image_draw_ellipse(xc, yc, ea, eb);
        else
                imlib_image_fill_ellipse(xc, yc, ea, eb);

        Py_INCREF(Py_None);
        return Py_None;
}

PyObject *Image_PyObject__copy_rect(PyObject *self, PyObject *args)
{ 
        int src_x, src_y, w, h, dst_x, dst_y;
        if (!PyArg_ParseTuple(args, "(ii)(ii)(ii)", &src_x, &src_y, &w, &h, &dst_x, 
&dst_y))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        imlib_image_copy_rect(src_x, src_y, w, h, dst_x, dst_y);
        Py_INCREF(Py_None);
        return Py_None;
}


PyObject *Image_PyObject__move_to_shmem(PyObject *self, PyObject *args)
{
        char *shmem_name, *buf, *format = "BGRA";
        unsigned long size, w, h;
        int fd;

        if (!PyArg_ParseTuple(args, "|ss", &format, &shmem_name))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        size = get_raw_bytes_size(format);

        fd = shm_open(shmem_name, O_RDWR|O_CREAT, 0777);
        if (fd == -1) {
                Py_INCREF(Py_None);
                return Py_None;
        }
        ftruncate(fd, size);
        buf = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (!buf)
                return NULL;

        get_raw_bytes(format, buf);

        // FIXME: need some error checking here.

        close(fd);
        munmap(buf, size);
        return Py_BuildValue("s", shmem_name);
}

PyObject *Image_PyObject__get_bytes(PyObject *self, PyObject *args)
{
        unsigned char *format = "BGRA", *buffer;
        unsigned long size, w, h;
        PyObject *ret;

        if (!PyArg_ParseTuple(args, "|s", &format))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        size = get_raw_bytes_size(format);
        if (!strcmp(format, "BGRA")) {
                unsigned char *bytes = imlib_image_get_data_for_reading_only();
                // Imlib2 docs say we're not supposed to do this.  It seems to
                // work though. :)
                ret = PyBuffer_FromReadWriteMemory(bytes, size);
                return Py_BuildValue("(Ol)", ret, 0);
        }
        buffer = get_raw_bytes(format, NULL);
        ret = PyBuffer_FromMemory(buffer, size);

        // XXX: WARNING!  This function creates a buffer from memory allocated
        // by get_raw_bytes().  It's the responsibility of the wrapper to
        // free this buffer by calling _Imlib2.free_buffer().
        return Py_BuildValue("(Ol)", ret, buffer);
}

////////////////////////////////////////////////////////////////////////////


PyObject *Image_PyObject__save(PyObject *self, PyObject *args)
{
        unsigned char *filename;

        if (!PyArg_ParseTuple(args, "s", &filename))
                return NULL;

        imlib_context_set_image(((Image_PyObject *)self)->image);
        // TODO: call imlib_save_image_with_error_return
        imlib_save_image(filename);
        Py_INCREF(Py_None);
        return Py_None;
}
PyMethodDef Image_PyObject_methods[] = {
        { "draw_rectangle", Image_PyObject__draw_rectangle, METH_VARARGS },
        { "draw_ellipse", Image_PyObject__draw_ellipse, METH_VARARGS },
        { "draw_text", Image_PyObject__draw_text, METH_VARARGS },
        { "draw_mask", Image_PyObject__draw_mask, METH_VARARGS },
        { "clear", Image_PyObject__clear, METH_VARARGS },
        { "copy_rect", Image_PyObject__copy_rect, METH_VARARGS },
        { "clone", Image_PyObject__clone, METH_VARARGS },
        { "scale", Image_PyObject__scale, METH_VARARGS },
        { "crop", Image_PyObject__crop, METH_VARARGS },
        { "rotate", Image_PyObject__rotate, METH_VARARGS },
        { "blend", Image_PyObject__blend, METH_VARARGS },
        { "move_to_shmem", Image_PyObject__move_to_shmem, METH_VARARGS },
        { "get_bytes", Image_PyObject__get_bytes, METH_VARARGS },
        { "save", Image_PyObject__save, METH_VARARGS },
        { NULL, NULL }
};

PyObject *Image_PyObject__getattr(Image_PyObject *self, char *name)
{
        imlib_context_set_image(self->image);
        if (!strcmp(name, "width"))
                return Py_BuildValue("l", imlib_image_get_width());
        else if (!strcmp(name, "height"))
                return Py_BuildValue("l", imlib_image_get_height());
        else if (!strcmp(name, "format"))
                return Py_BuildValue("s", imlib_image_format());
        else if (!strcmp(name, "mode"))
                return Py_BuildValue("s", "BGRA");
        else if (!strcmp(name, "filename"))
                return Py_BuildValue("s", imlib_image_get_filename());

        return Py_FindMethod(Image_PyObject_methods, (PyObject *)self, name);
}

// vim: ts=4

--- NEW FILE: imlib2.c ---
/* Imlib2 module for python.
   Written by Jason Tackaberry <[EMAIL PROTECTED]> and released under the LGPL.

   This is a quick hack.  It is not complete.
   See Imlib2.py for usage details.
*/

#include <Python.h>
#define X_DISPLAY_MISSING
#include <Imlib2.h>

#include "image.h"
#include "rawformats.h"
#include "font.h"
#include "display.h"

PyObject *imlib2_create(PyObject *self, PyObject *args)
{
        int w, h, num_bytes;
        unsigned char *bytes = NULL, *from_format = "BGRA";
        Imlib_Image *image;
        Image_PyObject *o;

        if (!PyArg_ParseTuple(args, "(ii)|s#s", &w, &h, &bytes, &num_bytes, 
&from_format))
                return NULL;

        if (bytes) {
                printf("Convert from format: %s\n", from_format);
                if (!strcmp(from_format, "BGRA"))
                        image = imlib_create_image_using_copied_data(w, h, (void 
*)bytes);
                else {
                        bytes = convert_raw_rgba_bytes(from_format, "BGRA", bytes, 
NULL, w, h);
                        image = imlib_create_image_using_copied_data(w, h, (void 
*)bytes);
                        free(bytes);
                }
                imlib_context_set_image(image);
                imlib_image_set_has_alpha(1);
        } else {
                image = imlib_create_image(w, h);
                imlib_context_set_image(image);
                imlib_image_set_has_alpha(1);
                imlib_image_clear_color(0, 0, 0, 0);
        }
        if (!image) {
                PyErr_Format(PyExc_RuntimeError, "Failed to create image");
                return NULL;
        }

        o = PyObject_NEW(Image_PyObject, &Image_PyObject_Type);
        o->image = image;
        return (PyObject *)o;

}

PyObject *imlib2_open(PyObject *self, PyObject *args)
{
        char *file;
        Imlib_Image *image;
        Image_PyObject *o;

        if (!PyArg_ParseTuple(args, "s", &file))
                return NULL;
                
        // FIXME: use imlib_load_image_with_error_return instead.
        image = imlib_load_image(file);
        if (!image) {
                PyErr_Format(PyExc_IOError, "Could not open %s", file);
                return NULL;
        }
        imlib_context_set_image(image);
        imlib_image_set_has_alpha(1);
        imlib_image_get_data_for_reading_only();
        o = PyObject_NEW(Image_PyObject, &Image_PyObject_Type);
        o->image = image;
        return (PyObject *)o;
} 

PyObject *imlib2_add_font_path(PyObject *self, PyObject *args)
{
        char *font_path;

        if (!PyArg_ParseTuple(args, "s", &font_path))
                return NULL;

        imlib_add_path_to_font_path(font_path);
        Py_INCREF(Py_None);
        return Py_None;
} 
PyObject *imlib2_load_font(PyObject *self, PyObject *args)
{
        char *font_spec;
        Imlib_Font *font;
        Font_PyObject *o;

        if (!PyArg_ParseTuple(args, "s", &font_spec))
                return NULL;

        font = imlib_load_font(font_spec);
        if (!font) {
                PyErr_Format(PyExc_IOError, "Couldn't open font: %s", font_spec);
                return NULL;
        }
        o = PyObject_NEW(Font_PyObject, &Font_PyObject_Type);
        o->font = font;
        return (PyObject *)o;
} 

PyObject *imlib2_new_display(PyObject *self, PyObject *args)
{
        int w, h;

        if (!PyArg_ParseTuple(args, "ii", &w, &h))
                return NULL;

        return display_new(w, h);
} 
PyObject *imlib2__shm_unlink(PyObject *self, PyObject *args)
{
        char *name;

        if (!PyArg_ParseTuple(args, "s", &name))
                return NULL;

        shm_unlink(name);
        Py_INCREF(Py_None);
        return Py_None;
} 

PyObject *imlib2__free_buffer(PyObject *self, PyObject *args)
{
        void *buffer;

        if (!PyArg_ParseTuple(args, "l", &buffer))
                return NULL;
        
        if (buffer)
                free(buffer);
        
        Py_INCREF(Py_None);
        return Py_None;
} 

PyMethodDef Imlib2_methods[] = {
    { "new_display", imlib2_new_display, METH_VARARGS }, 
    { "add_font_path", imlib2_add_font_path, METH_VARARGS }, 
    { "load_font", imlib2_load_font, METH_VARARGS }, 
    { "create", imlib2_create, METH_VARARGS }, 
    { "open", imlib2_open, METH_VARARGS }, 
    { "_shm_unlink", imlib2__shm_unlink, METH_VARARGS }, 
    { "_free_buffer", imlib2__free_buffer, METH_VARARGS }, 
        { NULL }
};

void init_Imlib2()
{
        PyObject *m;

        init_rgb2yuv_tables();
        m = Py_InitModule("_Imlib2", Imlib2_methods);
    Image_PyObject_Type.tp_new = PyType_GenericNew;
    if (PyType_Ready(&Image_PyObject_Type) < 0)
        return;
    PyModule_AddObject(m, "Image", (PyObject *)&Image_PyObject_Type);
        imlib_set_cache_size(1024*1024*4);
        imlib_set_font_cache_size(1024*1024*2);
}

// vim: ts=4

--- NEW FILE: Imlib2.py ---
import _Imlib2, types, math, os

# Counter for auto-generated shared memory names.
_imlib2_shmem_ctr = 0

def utf8(text):
        """
        Returns a UTF-8 string, converting from latin-1 if necessary.  This does a
        pretty good job Doing the Right Thing, converting only when it's really
        latin-1.  Of course it's not foolproof, but it works in practice.
        """
        try:
                text.decode("utf-8")
        except:
                try:
                        text = text.decode("latin-1").encode("utf-8")
                except:
                        pass

        return text


class Image:
        def __init__(self, image_or_filename):
                """
                Create a new Image object.

                Arguments:
                  image_or_filename: Instantiate the image from another Image
                                     instance, an instance of the backend's image
                                     class or type, or a file name from which to load
                                     the image.             
                """
                if type(image_or_filename) in types.StringTypes:
                        self._image = _Imlib2.open(image_or_filename)
                elif isinstance(image_or_filename, Image):
                        self._image = image_or_filename.copy()._image
                elif type(image_or_filename) == _Imlib2.Image:
                        self._image = image_or_filename
                else:
                        raise ValueError, "Unsupported image type", type(image)

                self.font = None

        def __getattr__(self, attr):
                """
                Supports these attributes:

                      size: tuple containing the width and height of the image
                     width: width of the image
                    height: height of the image
                    format: format of the image if loaded from file (e.g. PNG, JPEG)
                  filename: filename if loaded from file
                """
                if attr == "width": 
                        return self._image.width
                elif attr == "height": 
                        return self._image.height
                elif attr == "size": 
                        return (self._image.width, self._image.height)
                elif attr == "format": 
                        return self._image.format
                elif attr == "mode": 
                        return self._image.mode
                elif attr == "filename": 
                        return self._image.filename

                if attr not in self.__dict__:
                        raise AttributeError, attr
                return self.__dict__[attr]


        # Functions for pickling.
        def __getstate__(self):
                return (self.size, str(self.get_bytes()))

        def __setstate__(self, state):
                self._image = _Imlib2.create(state[0], state[1])


        def get_bytes(self, format = "BGRA"):
                """
                Returns raw image data.

                Arguments:
                  format: pixel format of the raw data to be returned.  If 'format' is
                          not a supported format, ValueError is raised.  Format
                          can be any combination of RGB or RGBA.  YV12A is also
                          supported, which returns a planar 4:2:0 plus a 8bpp
                          alpha plane.  (YV12A isn't a fourcc notation; I just
                          made it up.)

                Returns: A buffer object containing the raw image data.
                """
                bytes, buffer_addr = self._image.get_bytes(format)
                if buffer_addr == 0:
                        return bytes
                return BufferProxy(bytes, _Imlib2._free_buffer, buffer_addr)


        def scale(self, (w, h)):
                """
                Scale the image and return a new image.

                Arguments:
                  w, h: the width and height of the new image.  If either argument
                        is -1, that dimension is calculated from the other dimension
                        while retaining the original aspect ratio.

                Returns: a new Image instance representing the scaled image.
                """
                aspect = float(self.width) / float(self.height)
                if w == -1:
                        w = round(h * aspect)
                elif h == -1:
                        h = round(w / aspect)
                return Image(self._image.scale(int(w), int(h)))


        def crop(self, (x, y), (w, h)):
                """
                Crop the image and return a new image.

                Arguments:
                  x, y, w, h: represents the left, top, width, height region in
                              the image.

                Returns: a new Image instance representing the cropped image.
                """
                return Image(self._image.crop(int(x), int(y), int(w), int(h)))

        def rotate(self, angle):
                """
                Rotate the image and return a new image.

                Arguments:
                  angle: the angle in degrees by which to rotate the image.

                Return: a new Image instance representing the rotated image.

                FIXME: imlib2's rotate works all wonky.  Doesn't act how I expect.
                """
                return Image(self._image.rotate(angle * math.pi / 180))
                

        def scale_preserve_aspect(self, (w, h)):
                """
                Scales the image while retaining the original aspect ratio and return
                a new image.

                Arguments:
                  w, h: the maximum size of the new image.  The new image will be as
                        large as possible, using w, h as the upper limits, while
                        retaining the original aspect ratio.

                Return: a new Image insatnce represented the scaled image.
                """
                aspect = float(self.width) / float(self.height)
                if aspect >= 1.0:
                        img = self._image.scale(w, h / aspect)
                else:
                        img = self._image.scale(w * aspect, h)

                return img


        def thumbnail(self, (w, h)):
                """
                Generates a thumbnail of the image, REPLACING the current image.
                This simulates the PIL thumbnail function.
                """
                if self.width < w and self.height < h:
                        return

                self._image = self.scale_preserve_aspect( (w, h) )


        def copy_rect(self, src_pos, size, dst_pos):
                """
                Copies a region within the image.

                Arguments:
                  src_pos: a tuple holding the x, y coordinates marking the top left
                           of the region to be moved.
                     size: a tuple holding the width and height of the region to move.
                           If either dimension is -1, then that dimension extends to
                           the far edge of the image.
                  dst_pos: a tuple holding the x, y coordinates within the image
                           where the region will be moved to.
                Returns: None
            """
                return self._image.copy_rect(src_pos, size, dst_pos)

        def blend(self, src, dst_pos = (0, 0), src_pos = (0, 0), 
                  src_size = (-1, -1), alpha = 255, merge_alpha = True):
                """
                Blends one image onto another.  

                Arguments:
                          src: the image being blended onto 'self'
                      dst_pos: a tuple holding the x, y coordinates where the source
                               image will be blended onto the destination image.
                      src_pos: a tuple holding the x, y coordinates within the source
                               image where blending will start.
                     src_size: a tuple holding the width and height of the source
                               image to be blended.  A value of -1 for either one
                               indicates the full dimension of the source image.
                        alpha: the "layer" alpha that is applied to all pixels of the
                               image.  If an individual pixel has an alpha of 128 and
                               this value is 128, the resulting pixel will have an
                               alpha of 64 before it is blended to the destination
                               image.  0 is fully transparent and 255 is fully opaque,
                               and 256 is a special value that means alpha blending is
                               disabled.
                  merge_alpha: if True, the alpha channel is also blended.  If False,
                               the destination image's alpha channel is untouched and
                               the RGB values are compensated

                Returns: None.
                """

                if src_size[0] == -1:
                        src_size = src.width, src_size[1]
                if src_size[1] == -1:
                        src_size = src_size[0], src.height
                return self._image.blend(src._image, dst_pos, src_pos, src_size, 
                                         int(alpha), merge_alpha)


        def clear(self, (x, y) = (0, 0), (w, h) = (-1, -1)):
                """
                Clears the image at the specified rectangle, resetting all pixels in
                that rectangle to fully transparent.

                Arguments:
                  x, y: left and top coordinates of the rectangle to be cleared.
                        Default is the top left corner.
                  w, h: width and height of the rectangle to be cleared.  If either
                        value is -1 then the image is cleared to the far edge.

                Returns: None
                """
                x = max(0, min(self.width, x))
                y = max(0, min(self.height, y))
                if w == -1: w = self.width - x
                if h == -1: h = self.height - y
                w = min(w, self.width-x)
                h = min(h, self.height-y)
                self._image.clear(x, y, w, h)

        def draw_mask(self, maskimg, (x, y)):
                """
                Applies the luma channel of maskimg to the alpha channel of the
                the current image.

                Arguments:
                  maskimg: the image from which to read the luma channel
                     x, y: the top left coordinates within the current image where the
                           alpha channel will be modified.  The mask is drawn to the
                           full width/height of maskimg.

                Returns: None
                """

                return self._image.draw_mask(maskimg._image, int(x), int(y))


        def copy(self):
                """
                Creates a copy of the current image.

                Returns: a new Image instance with a copy of the current image.
                """
                return Image(self._image.clone())


        def set_font(self, font):
                """
                Sets the font context to font_or_font_name.  Subsequent calls to
                draw_text() will be rendered using this font.

                Arguments:
                  font_or_fontname: either a Font object, or a string containing the
                                    font's name and size.  This string is in the
                                    form "Fontname/Size" such as "Arial/16"


                Returns: a Font instance represent the specified font.  It
                         'font_or_fontname' is already a Font instance, it is simply
                         returned back to the caller.
                """
                if type(font) in types.StringTypes:
                        self.font = Font(font)
                else:
                        self.font = font
                return self.font

        def get_font(self):
                """
                Gets the current Font context.

                Returns: A Font instance as created by set_font() or None if no font
                         context is defined.
                """
                return self.font

        def draw_text(self, (x, y), text, color = None, font_or_fontname = None):
                """
                Draws text on the image.

                Arguments:
                              x, y: the left/top coordinates within the current image
                                    where the text will be rendered.
                              text: a string holding the text to be rendered.
                             color: a 3- or 4-tuple holding the red, green, blue, and
                                    alpha values of the color in which to render the
                                    font.  If color is a 3-tuple, the implied alpha
                                    is 255.  If color is None, the color of the font
                                    context, as specified by set_font(), is used.
                  font_or_fontname: either a Font object, or a string containing the
                                    font's name and size.  This string is in the
                                    form "Fontname/Size" such as "Arial/16".  If this
                                    parameter is none, the font context is used, as
                                    specified by set_font().

                Returns: a 4-tuple representing the width, height, horizontal advance,
                         and vertical advance of the rendered text.
                """
                if not font_or_fontname:
                        font = self.font
                elif type(font_or_fontname) in types.StringTypes:
                        font = Font(font)
                else:
                        font = font_or_fontname

                if not color:
                        color = font.color
                if len(color) == 3:
                        color = color + (255,)

                return self._image.draw_text(font._font, int(x), int(y), 
                                             utf8(text), color)


        def draw_rectangle(self, (x, y), (w, h), color, fill = True):
                """
                Draws a rectangle on the image.

                Arguments:
                   x, y: the top left corner of the rectangle.
                   w, h: the width and height of the rectangle.
                  color: a 3- or 4-tuple holding the red, green, blue, and alpha 
                         values of the color in which to draw the rectangle.  If 
                         color is a 3-tuple, the implied alpha is 255.
                   fill: whether the rectangle should be filled or not.  The default
                         is true.

                Returns: None
                """
                if len(color) == 3:
                        color = color + (255,)
                return self._image.draw_rectangle(int(x), int(y), int(w), int(h), 
                                                  color, fill)

        def draw_ellipse(self, (xc, yc), (a, b), color, fill = True):
                """
                Draws an ellipse on the image.

                Arguments:
                  xc, yc: the x, y coordinates of the center of the ellipse.
                    a, b: the horizontal and veritcal amplitude of the ellipse.
                   color: a 3- or 4-tuple holding the red, green, blue, and alpha 
                          values of the color in which to draw the ellipse.  If 
                          color is a 3-tuple, the implied alpha is 255.
                    fill: whether the ellipse should be filled or not.  The default
                          is true.

                Returns: None
                """
                if len(color) == 3:
                        color = color + (255,)
                return self._image.draw_ellipse(int(xc), int(yc), int(a), int(b), 
color, fill)

        def move_to_shmem(self, format = "BGRA", id = None):
                """
                Creates a POSIX shared memory object and copy the image's raw data.  

                Arguments:
                  format: the format of the raw data to copy to shared memory.  If
                          the specified format is not supported, raises ValueError.
                      id: the name of the shared memory object (as passed to 
                          shm_open(3)).  If id is None, a suitable unique id is
                          generated.

                Returns: the id of the shared memory object.
                """

                if not id:
                        global _imlib2_shmem_ctr
                        id = "pyimlib2-image-%d-%d" % (os.getpid(), _imlib2_shmem_ctr)
                        _imlib2_shmem_ctr += 1

                return self._image.move_to_shmem(format, id)

        def save(self, filename, format = None):
                """
                Saves the image to a file.

                Arguments:
                  format: the format of the written file (jpg, png, etc.).  If format
                          is None, the format is gotten from the filename extension.

                Returns: None.
                """
                return self._image.save(filename)

class Display:
        def __init__(self, (w, h), dither = True, blend = False):
                self._display = _Imlib2.new_display(w, h)
                self.size = (w, h)
                self.width = w
                self.height = h
                self.blend = blend
                self.dither = dither

        def render(self, image, dst_pos = (0, 0), src_pos = (0, 0),
                  src_size = (-1, -1), dither = None, blend = None):
                if blend == None:
                        blend = self.blend
                if dither == None:
                        dither = self.dither

                if not isinstance(image, Image):
                        raise ValueError, image
                return self._display.render(image._image, dst_pos, src_pos, src_size,  
dither, blend)

class Font:
        def __init__(self, fontdesc, color=(255,255,255,255)):
                """
                Create a new Font object.

                Arguments:
                  fontdesc: the description of the font, in the form "Fontname/Size".
                            Only TrueType fonts are supported, and the .ttf file must
                            exist in a registered font path.  Font paths can be
                            registered by calling Imlib2.add_font_path().
                     color: a 3- or 4-tuple holding the red, green, blue, and alpha 
                            values of the color in which to render text with this 
                            font context.  If color is a 3-tuple, the implied alpha 
                            is 255.  If color is not specified, the default is fully
                            opaque white.
                """

                self._font = _Imlib2.load_font(fontdesc)
                sep = fontdesc.index("/")
                self.fontname = fontdesc[:sep]
                self.size = fontdesc[sep + 1:]
                self.set_color(color)


        def get_text_size(self, text):
                """
                Get the font metrics for the specified text as rendered by the 
                current font.

                Arguments:
                  text: the text for which to retrieve the metric.

                Returns: a 4-tuple containing the width, height, horizontal advance,
                         and vertical advance of the text when rendered.
                """
                return self._font.get_text_size(utf8(text))

        def set_color(self, color):
                """
                Sets the default color for text rendered with this font.

                Arguments:
                  color: a 3- or 4-tuple holding the red, green, blue, and alpha 
                         values of the color in which to render text with this 
                         font context.  If color is a 3-tuple, the implied alpha 
                         is 255.
                """
                if len(color) == 3:
                        self.color = color + (255,)
                else:
                        self.color = color

        def __getattr__(self, attr):
                """
                These attributes are available:

                       ascent: the current font's ascent value in pixels.
                      descent: the current font's descent value in pixels.
                  max_descent: the current font's maximum descent extent.
                   max_ascent: the current font's maximum ascent extent.
                """
                if attr == "ascent": 
                        return self._font.ascent
                elif attr == "descent": 
                        return self._font.descent
                elif attr == "max_ascent": 
                        return self._font.max_ascent
                elif attr == "max_descent": 
                        return self._font.max_descent
                if attr not in self.__dict__:
                        raise AttributeError, attr
                return self.__dict__[attr]


class BufferProxy:
        def __init__(self, buffer, callback = None, args = None):
                self._buffer = buffer
                self._callback = callback
                self._cbargs = args

        def __del__(self):
                if self._callback:
                        self._callback(self._cbargs)

        def __repr__(self):
                return "<Proxy for %s>" % repr(self._buffer)

        def __str__(self):
                return str(self._buffer)

        def __getitem__(self, index):
                return self._buffer[index]

        def __getslice__(self, start, end):
                return self._buffer[start:end]

        def __len__(self):
                return len(self._buffer)


# Implement a crude image cache.
#
# Imlib2 maintains its own cache, but I don't think it caches
# the raw image data, since this ends up being faster.  So think
# of this as L1 cache, and Imlib's cache as L2 cache.  (Of course
# our L1 cache is much bigger :))

_image_cache = {
        "images": {},
        "order": [],
        "size": 0,
        "max-size": 16*1024   # 16 MB
}

def open(file):
        """
        Create a new image object from the file 'file'.
        """
        if file in _image_cache["images"]:
                return _image_cache["images"][file].copy()

        image = Image(file)
        _image_cache["images"][file] = image
        _image_cache["order"].insert(0, file)
        _image_cache["size"] += image.width * image.height * 4 / 1024

        while _image_cache["size"] > _image_cache["max-size"]:
                file = _image_cache["order"].pop()
                expired = _image_cache["images"][file]
                del _image_cache["images"][file]
                _image_cache["size"] -= expired.width * expired.height * 4 / 1024

        return image


def new(size, bytes = None, from_format = "BGRA"):
        """
        Generates a new Image of size 'size', which is a tuple holding the width
        and height.  If 'bytes' is specified, the image is initialized from the
        raw BGRA data.
        """
        if bytes:
                if isinstance(bytes, BufferProxy):
                        bytes = bytes._buffer

                if False in map(lambda x: x in "RGBA", list(from_format)):
                        raise ValueError, "Converting from unsupported format:", 
from_format
                if len(bytes) < size[0]*size[1]*len(from_format):
                        raise ValueError, "Not enough bytes for converted format: 
expected %d, got %d" % (size[0]*size[1]*len(from_format), len(bytes))
                return Image(_Imlib2.create(size, bytes, from_format))
        else:
                return Image(_Imlib2.create(size))


def add_font_path(path):
        """
        Add the given path to the list of paths to scan when loading fonts.
        """
        _Imlib2.add_font_path(path)

def load_font(font, size):
        """
        Return a Font object from the given font specified in the form
        "FontName/Size", such as "Arial/16"
        """
        return Font(font + "/" + str(size))
        

def clean_stale_shmem():
        """
        Clean stale shmem segments left over from processes that might have
        crashed.

        FIXME: this is actually broken, because it could end up deleting shmem 
        objects from processes that are still running. 

        Must test the existence of pid before deleting the shmem object.
        It's not perfect, but it's better.
        """
        import glob, os
        for file in  glob.glob("/dev/shm/pyimlib2*"):
                path, file = os.path.split(file)
                _Imlib2._shm_unlink(file)


clean_stale_shmem()

# vim: ts=4

--- NEW FILE: pyimlib2.spec ---
Summary: Python wrapper for Imlib2
Name: pyimlib2
Version: 0.0.6
Release: 1
License: LGPL
Group: System Environment/Libraries

Source: http://sault.org/mebox/downloads/pyimlib2/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/root-%{name}-%{version}
Prefix: %{_prefix}

BuildRequires: imlib2-devel >= 1.1.0
BuildRequires: python >= 2.2

%description
pyimlib2 is small python module partially wrapping Imlib2. 

Imlib2 is an advanced replacement library for libraries like libXpm that
provides many more features with much greater flexibility and speed than
standard libraries, including font rasterization, rotation, RGBA space
rendering and blending, dynamic binary filters, scripting, and more.

%prep
%setup

%build
python setup.py build

%install
%{__rm} -rf %{buildroot}
python setup.py install --root=%{buildroot} --record=INSTALLED_FILES

cat >>INSTALLED_FILES << EOF
%doc README
EOF

%clean
%{__rm} -rf %{buildroot}

%files -f INSTALLED_FILES
%defattr(-, root, root, 0755)


%changelog
* Tue Feb 24 2004 Jason Tackaberry <[EMAIL PROTECTED]> - 0.0.1-1
- Initial package

--- NEW FILE: font.h ---
#define Font_PyObject_Check(v) ((v)->ob_type == &Font_PyObject_Type)

typedef struct {
        PyObject_HEAD
        Imlib_Font *font;
} Font_PyObject;

extern PyTypeObject Font_PyObject_Type;
void Font_PyObject__dealloc(Font_PyObject *);
PyObject *Font_PyObject__getattr(Font_PyObject *, char *);

--- NEW FILE: README ---
pyimlib2 - python module for Imlib2
=========================================

   NOTE: This isn't meant to be a formal release but rather just a demo
   of some of the stuff I'm working on.  As a result, it may suck
   unbelievably or be outright broken.


About
-----

Pyimlib2 is a python module for Imlib2.  It is terribly incomplete.  Its 
main raison d'ĂȘtre is to provide image manipulation routines for MeBox.

PyImlib2 requires Imlib2 1.1.1 or later, which can be gotten here:

   http://sourceforge.net/project/showfiles.php?group_id=2&package_id=11130

I've packaged RPMs for both Imlib2 and pyimlib2 for convenience.  You can 
download them, as well as the most recent version of pyimlib2 at:

   http://sault.org/mebox/downloads.php

Only a small part of the Imlib2 API has been wrapped.  If you want to help by
adding more methods, patches will be happily accepted.


Installation
------------

Assuming you already have Imlib2 installed, you can install pyimlib2 with:

        make && make install



License
-------

This code is released under the GNU GPL version 2.  Read it here:
                                                                                       
                                            
        http://www.gnu.org/licenses/gpl.html


   - Jason Tackaberry <[EMAIL PROTECTED]>

--- NEW FILE: setup.py ---
from distutils.core import setup, Extension
setup(name="_Imlib2", version="0.0.7", 
        ext_modules=[ 
                Extension("_Imlib2module", 
                        ["imlib2.c", "image.c", "font.c", "rawformats.c",
                         "display.c"],
                        library_dirs=["/usr/X11R6/lib"],
                        libraries=["Imlib2", "rt", "X11"])
        ],
        py_modules=["Imlib2"]
)

# vim: ts=4

--- NEW FILE: AUTHORS ---
Main Developer:
        Jason Tackaberry <[EMAIL PROTECTED]>

--- NEW FILE: font.c ---
/* Imlib2 module for python.
   Written by Jason Tackaberry <[EMAIL PROTECTED]> and released under the LGPL.

   This is a quick hack.  It is not complete.
   See Imlib2.py for usage details.
*/

#include <Python.h>
#define X_DISPLAY_MISSING
#include <Imlib2.h>

#include "font.h"

PyTypeObject Font_PyObject_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "_Imlib2.Font",             /*tp_name*/
    sizeof(Font_PyObject),    /*tp_basicsize*/
    0,                         /*tp_itemsize*/
        (destructor)Font_PyObject__dealloc, /* tp_dealloc */
    0,                         /*tp_print*/
        (getattrfunc)Font_PyObject__getattr, /* tp_getattr */
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
    "Imlib2 Font Object"           /* tp_doc */
};

void Font_PyObject__dealloc(Font_PyObject *self)
{
        imlib_context_set_font(self->font);
        imlib_free_font();
        PyMem_DEL(self);
}

PyObject *Font_PyObject__get_text_size(PyObject *self, PyObject *args)
{ 
        char *text;
        int w, h, advance_w, advance_h;

        if (!PyArg_ParseTuple(args, "s", &text))
                return NULL;

        imlib_context_set_font( ((Font_PyObject *)self)->font );
        imlib_get_text_size(text, &w, &h);
        imlib_get_text_advance(text, &advance_w, &advance_h);
        return Py_BuildValue("(llll)", w, h, advance_w, advance_h);
}

PyMethodDef Font_PyObject_methods[] = {
        { "get_text_size", Font_PyObject__get_text_size, METH_VARARGS },
        { NULL, NULL }
};

PyObject *Font_PyObject__getattr(Font_PyObject *self, char *name)
{
        imlib_context_set_font(self->font);
    if (!strcmp(name, "descent"))
        return Py_BuildValue("l", imlib_get_font_descent());
    else if (!strcmp(name, "ascent"))
        return Py_BuildValue("l", imlib_get_font_ascent());
    else if (!strcmp(name, "max_ascent"))
        return Py_BuildValue("l", imlib_get_maximum_font_ascent());
    else if (!strcmp(name, "max_descent"))
        return Py_BuildValue("l", imlib_get_maximum_font_descent());

        return Py_FindMethod(Font_PyObject_methods, (PyObject *)self, name);
}

// vim: ts=4



-------------------------------------------------------
SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media
100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33
Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift.
http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285
_______________________________________________
Freevo-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to