/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2010 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/

#include "../include/scol_gtk_pixbuf.h"

/* TODO but not urgent */
gchar ** scol_gtk_pixbuf_get_infos (GdkPixbufFormat *format)
{
    gchar **result = NULL;
    gint size = 8;
    gint sizedatemax = 64;

    if (format == NULL)
        return result;

    result = (gchar **) g_malloc (sizeof (gchar *) * size);
    result[0] = (gchar *) g_malloc (sizeof (gchar) * (sizedatemax + 1));
    g_strlcpy (result[0], gdk_pixbuf_format_get_name (format), sizedatemax);
    result[1] = (gchar *) g_malloc (sizeof (gchar) * (sizedatemax + 1));
    g_strlcpy (result[0], gdk_pixbuf_format_get_description (format), sizedatemax);
    result[2] = (gchar *) g_malloc (sizeof (gchar) * (sizedatemax + 1));
    g_strlcpy (result[0], gdk_pixbuf_format_get_license (format), sizedatemax);
    result[3] = (gchar *) g_malloc (sizeof (gchar) * (sizedatemax + 1));
    g_strlcpy (result[0], gdk_pixbuf_format_get_name (format), sizedatemax);
    result[4] = (gchar *) g_malloc (sizeof (gchar) * (sizedatemax + 1));
    g_strlcpy (result[0], gdk_pixbuf_format_get_name (format), sizedatemax);

    g_message ("%s", result[0]);
    g_message ("%s", result[1]);
    g_message ("%s", result[2]);
    g_message ("%s", result[3]);

    return result;
}

/**
 * \brief Internal function. Load an image from a local file
 *
 * \param GdkPixbuf * : the pixbuf. It should be NULL.
 * \param const gchar * : the filename to load
 * \param int : the width if needed, or -1 for no scale
 * \param int : the height if needed, or -1 for no scale
 * \param gboolean : ratio for the scale, if needed
 * \return gboolean : TRUE if the file has been loaded, else FALSE
 */
gboolean scol_gtk_pixbuf_load (GdkPixbuf **pix, const gchar *filename, int width, int height, gboolean ratio)
{
    GError *err = NULL;

    (*pix) = gdk_pixbuf_new_from_file_at_scale (filename, width, height, ratio, &err);
    if (err != NULL)
    {
        g_warning ("scol_gtk_pixbuf_load error : could not load the file %s, error : %d -> %s", filename, err->code, err->message);
        g_error_free (err);
        return FALSE;
    }
    return TRUE;
}

gboolean scol_gtk_pixbuf_load_url (GdkPixbuf **pix, const gchar *url)
{
    GFileInputStream *stream;
    GFile* gfile = NULL;
    GError *err = NULL;

    gfile = g_file_new_for_path (url);
    stream = g_file_read (gfile, NULL, &err);
    if (err != NULL)
    {
        g_warning ("scol_gtk_pixbuf_load_url error : couldn't read the data : %d -> %s", err->code, err->message);
        g_error_free (err);
        return FALSE;
    }
    (*pix) = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &err);
    if (err != NULL)
    {
        g_warning ("scol_gtk_pixbuf_load_url error : couldn't create the pix : %d -> %s", err->code, err->message);
        g_error_free (err);
        return FALSE;
    }
    g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
    return TRUE;
}

/**
 * \brief Internal function. Gets infos to any image file
 *
 * \param const gchar * : a filename
 * \param gint * : variable to put the width, or NULL if unknown
 * \param gint * : variable to put the height, or NULL if unknown
 * \param GdkPixbufFormat * : structure containing the infos
 * \return gboolean : TRUE if success, else FALSE (typically, a bad file)
 *
 * Note : format shouldn't be freed
 */
gboolean scol_gtk_pixbuf_get_info (const gchar *filename, gint *width, gint *height, GdkPixbufFormat *format)
{
    format = gdk_pixbuf_get_file_info (filename, width, height);
    if (format == NULL)
        return FALSE;
    return TRUE;
}

/*void scol_gtk_pixbuf_get_formats_availables2 (gpointer data, gpointer user_data)
{
    GdkPixbufFormat *format = (GdkPixbufFormat*) data;
    GSList **list = (GSList**) user_data;

    *list = g_slist_prepend (*list,  format->name);
    return;
}*/

void scol_gtk_pixbuf_get_formats_availables (GSList **list)
{
    GSList *formats = NULL;
    gchar *format_name;

    formats = gdk_pixbuf_get_formats ();

    for (; formats != NULL; formats = formats->next)
    {
        format_name = gdk_pixbuf_format_get_name (formats->data);
        *list = g_slist_prepend (*list, format_name);
        /*g_free (format_name);*/
    }
    g_slist_free (formats);
    return;
}

void scol_gtk_pixbuf_get_mimetypes_availables (GSList **list)
{
    GSList *formats = NULL;
    gchar **format_type;

    formats = gdk_pixbuf_get_formats ();
    for (; formats != NULL; formats = formats->next)
    {
        format_type = gdk_pixbuf_format_get_mime_types (formats->data);
        *list = g_slist_prepend (*list, format_type);
        g_message ("description : %s", gdk_pixbuf_format_get_description (formats->data));
        g_message ("licence : %s", gdk_pixbuf_format_get_license (formats->data));
        /*g_strfreev (format_type);*/
    }
    g_slist_free (formats);
    return;
}

void scol_gtk_pixbuf_get_formats_full (GSList **list)
{
    GSList *formats = NULL;
    GSList *datas = NULL;

    formats = gdk_pixbuf_get_formats ();
    for (; formats != NULL; formats = formats->next)
    {
        datas = g_slist_prepend (datas, (gpointer) gdk_pixbuf_format_is_disabled (formats->data));
        datas = g_slist_prepend (datas, gdk_pixbuf_format_get_name (formats->data));
        datas = g_slist_prepend (datas, gdk_pixbuf_format_get_mime_types (formats->data));
        datas = g_slist_prepend (datas, gdk_pixbuf_format_get_extensions (formats->data));
        datas = g_slist_prepend (datas, gdk_pixbuf_format_get_description (formats->data));
        datas = g_slist_prepend (datas, gdk_pixbuf_format_get_license (formats->data));
        *list = g_slist_prepend (*list, datas);
    }
    g_slist_free (formats);
    return;
}

void scol_gtk_pixbuf_search_format_from_name (char *name, GdkPixbufFormat **format)
{
    GSList *formats = NULL;
    gchar *s;
    formats = gdk_pixbuf_get_formats ();
    for (; formats != NULL; formats = formats->next)
    {
        s = gdk_pixbuf_format_get_name (formats->data);
        if (!(strcasecmp (s, name)))
        {
            *format = formats->data;
            break;
        }
    }
    g_slist_free (formats);
    return;
}












/* SCOL API */

/**
 * \brief _gtkPixNew : create a new pix object
 * fun [Chn P I [I I I]] ObjGtkPix
 * \param Chn : a channel
 * \param P : a filename
 * \param I : mode. Should be at 0.
 * \param [I I I] : the width (or nil to not constraint it), the height (or nil to not constraint it), the ratio (1 to keep it)
 * \return ObjGtkPix : a new pix or nil if error
 */
int SCOL_gtkPixNew (mmachine m)
{
    int mchannel, mstring, mflag, mparams;
    int width, height, ratio;
    gboolean b, bratio = FALSE;
    GdkPixbuf *pix;

    g_message ("SCOL_gtkPixNew : entering");

    mparams = MTOP (MMpull (m));
    mflag = MTOI (MMpull (m));
    mstring = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkPixNew error : channel is nil !");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    if (mstring == NIL)
    {
        g_warning ("SCOL_gtkPixNew error : data is nil !");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    width = MTOI (MMfetch (m, mparams, 0));
    if (width < -1)
        width = -1;
    height = MTOI (MMfetch (m, mparams, 1));
    if (height < -1)
        height = -1;
    ratio = MTOI (MMfetch (m, mparams, 2));
    if (ratio)
        bratio = TRUE;

    b = scol_gtk_pixbuf_load (&pix, MMstartstr (m, MTOP (mstring)), width, height, bratio);
    if (b == FALSE)
        return MMpush (m, NIL);
    return SCOL_gtk_memory_createObjectTAB (m, pix, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
}

/**
 * \brief _gtkPixFree : destroy a pix object
 * fun [ObjGtkPix] I
 * \param ObjGtkPix : a pix object
 * \return I : 0 if success
 */
int SCOL_gtkPixFree (mmachine m)
{
    int mpix;
    GdkPixbuf *pix;

    g_message ("SCOL_gtkPixFree : entering");

    mpix = MMpull (m);
    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixFree error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    g_object_unref (G_OBJECT (pix));
    OBJdelTM (m, ObjGtkWidgetType, MTOP (mpix));
    MMpush (m, ITOM (0));
    return 0;
}

/**
 * \brief _gtkPixScale : scale
 * fun [ObjGtkPix I I I I] ObjGtkPix
 * \param ObjGtkPix : a pix object
 * \param I : new width
 * \param I : new height
 * \param I : mode : SCOL_GTK_PIX_INTERP_BILINEAR (default), SCOL_GTK_PIX_INTERP_NEAREST, SCOL_GTK_PIX_INTERP_TILES, SCOL_GTK_PIX_INTERP_HYPER
 * \param I : flag : if 1, the pix object will be destroyed. If 0, the pix object will be kept.
 * \return ObjGtkPix : a new pix object or nil if error
 */
int SCOL_gtkPixScale (mmachine m)
{
    int mpix, mwidth, mheight, mmode, mflag;
    int flag = 1;
    GdkInterpType mode = GDK_INTERP_BILINEAR;
    GdkPixbuf *pixsrc, *pixdest;

    g_message ("SCOL_gtkPixScale : entering");

    mflag = MTOI (MMpull (m));
    mmode = MTOI (MMpull (m));
    mheight = MTOI (MMpull (m));
    mwidth = MTOI (MMpull (m));
    /*mpix = MMpull (m);*/
    mpix = MMget (m, 0);

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixScale error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pixsrc = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    switch (mmode)
    {
        case (INTERP_NEAREST) :
            mode = GDK_INTERP_NEAREST;
            break;
        case (INTERP_TILES) :
            mode = GDK_INTERP_TILES;
            break;
        case (INTERP_HYPER) :
            mode = GDK_INTERP_HYPER;
            break;
        default :
            mode = GDK_INTERP_BILINEAR;
    }
    if (mwidth < 1)
        mwidth = 32;
    if (mheight < 1)
        mheight = 32;
    pixdest = gdk_pixbuf_scale_simple (pixsrc, mwidth, mheight, mode);

    if (!mflag)
        flag = 0;
    if (flag)
    {
        g_object_unref (G_OBJECT (pixsrc));
        /*OBJdelTM (m, ObjGtkWidgetType, MTOP (mpix));*/
        MMstore (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE, (int) pixdest);
        /*MMset (m, mpix, 0);*/
    }
    MMpush (m, MMgetglobal (m, OFFSCCUR));
    return SCOL_gtk_memory_createObjectTAB (m, pixdest, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
}

/**
 * \brief _gtkPixScaleEx : not implemented yet
 * fun [] ObjGtkPix
 * \param
 * \return ObjGtkPix : always nil
 */
int SCOL_gtkPixScaleEx (mmachine m)
{
    MMpush (m, NIL);
    return 0;
}

/**
 * \brief _gtkPixRotate : rotates a pixbuf by a multiple of 90 degrees
 * fun [ObjGtkPix I I] ObjGtkPix
 * \param ObjGtkPix : a pix object
 * \param I : 0, 90, 180 or 270. Other value is ignored.
 * \param I : 0 if a new pix Scol object is created, 1 if the new pix replaces the pix in the curent pix object
 * \return ObjGtkPix : a new pix in the pix object or the same pix object if the value is bad or nil if an error occurs
 */
int SCOL_gtkPixRotate (mmachine m)
{
    int mpix, mang, mflag;
    int flag = 1;
    GdkPixbuf *pix, *newpix;

    g_message ("SCOL_gtkPixRotate : entering");

    mflag = MTOI (MMpull (m));
    mang = MTOI (MMpull (m));
    /*mpix = MMpull (m);*/
    mpix = MMget (m, 0);

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixRotate error : object is nil");
        /*MMpush (m, NIL);*/
        MMset (m, 0, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    newpix = gdk_pixbuf_rotate_simple (pix, mang);

    if (!mflag)
        flag = 0;
    if (flag)
    {
        g_object_unref (G_OBJECT (pix));
        MMstore (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE, (int) newpix);
        /*MMpush (m, mpix);*/
    }
    else
    {
        MMstore (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE, (int) pix);
        g_object_ref (G_OBJECT (pix));
    }

    MMpush (m, MMgetglobal (m, OFFSCCUR));
    SCOL_gtk_memory_createObjectTAB (m, newpix, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);

    return 0;
}

/**
 * \brief _gtkPixFlip : performs a flip to a pixbuf
 * fun [ObjGtkPix I I] ObjGtkPix
 * \param ObjGtkPix : a pix object
 * \param I : SCOL_GTK_PIX_FLIP_HORIZONTAL or SCOL_GTK_PIX_FLIP_VERTICAL. Other value are ignored.
 * \param I : 0 if a new pix Scol object is created, 1 if the new pix replaces the pix in the curent pix object
 * \return ObjGtkPix : a new pix in the pix object or the same pix object if the value is bad or nil if an error occurs
 */
int SCOL_gtkPixFlip (mmachine m)
{
    int mpix, mflip, mflag;
    int flag = 1;
    GdkPixbuf *pix, *newpix;

    g_message ("SCOL_gtkPixFlip : entering");

    mflag = MTOI (MMpull (m));
    mflip = MTOI (MMpull (m));
    /*mpix = MMpull (m);*/
    mpix = MMget (m, 0);

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixFlip error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    switch (mflip)
    {
        case (FLIP_HORIZONTAL) :
            newpix = gdk_pixbuf_flip (pix, TRUE);
            break;
        case (FLIP_VERTICAL) :
            newpix = gdk_pixbuf_flip (pix, FALSE);
            break;
         default :
            return MMpush (m, mpix);
    }

    if (newpix == NULL)
    {
        g_warning ("SCOL_gtkPixFlip error : pix can not be created!");
        MMpush (m, NIL);
        return 0;
    }
    if (!mflag)
        flag = 0;
    if (flag)
    {
        g_object_unref (G_OBJECT (pix));
        MMstore (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE, (int) newpix);
    }
    else
    {
        MMpush (m, MMgetglobal (m, OFFSCCUR));
        SCOL_gtk_memory_createObjectTAB (m, newpix, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
    }
    return 0;
}

/**
 * \brief _gtkPixAddAlpha : adds an alpha channel to an existing pix object
 * fun [ObjGtkPix [I I I] I] ObjGtkPix
 * If the tuple is not nil, then the color specified by it will be assigned zero opacity.
 * For example, if the tuple is equals at [255, 255, 255], all white pixels will become fully transparent.
 * \param ObjGtkPix : an existing pix object
 * \param [I I I] : Red value, Green value, Blue value.
 * \param I : 0 if a new pix Scol object is created, 1 if the new pix replaces the pix in the curent pix object
 * \return ObjGtkPix : a new pix in the pix object or the same pix object if the value is bad or nil if an error occurs
 */
int SCOL_gtkPixAddAlpha (mmachine m)
{
    int mpix, mrgb, mflag;
    GdkPixbuf *pix, *newpix;
    guchar r = 0, g = 0, b = 0;
    int flag = 1;
    gboolean bmode;

    g_message ("SCOL_gtkPixAddAlpha : entering");

    mflag = MTOI (MMpull (m));
    mrgb = MMpull (m);
    /*mpix = MMpull (m);*/
    mpix = MMget (m, 0);

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixAddAlpha error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    (mrgb == NIL) ? (bmode = FALSE) : (bmode = TRUE);

    r = (guchar) MTOI (MMfetch (m, MTOP (mrgb), 0));
    g = (guchar) MTOI (MMfetch (m, MTOP (mrgb), 1));
    b = (guchar) MTOI (MMfetch (m, MTOP (mrgb), 2));
    newpix = gdk_pixbuf_add_alpha (pix, bmode, r, g, b);
    if (newpix == NULL)
    {
        g_warning ("SCOL_gtkPixAddAlpha error : pix can not be created!");
        MMpush (m, NIL);
        return 0;
    }
    if (!mflag)
        flag = 0;
    if (flag)
    {
        g_object_unref (G_OBJECT (pix));
        MMstore (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE, (int) newpix);
    }
    else
    {
        MMpush (m, MMgetglobal (m, OFFSCCUR));
        SCOL_gtk_memory_createObjectTAB (m, newpix, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
    }
    return 0;
}

/**
 * \brief _gtkPixCopyArea : Copies a rectangular area from src to dest.
 * fun [ObjGtkPix I I I I ObjGtkPix I I] ObjGtkPix
 * \param ObjGtkPix : source pix object
 * \param I : source x coordinate
 * \param I : source y coordinate
 * \param I : source width
 * \param I : source height
 * \param ObjGtkPix : destination pix object. Can be nil; in this case, a new pix object will be created
 * \param I : destination x coordinate
 * \param I : destination y coordinate
 * \return ObjGtkPix : the destination pix object or nil if error
 */
int SCOL_gtkPixCopyArea (mmachine m)
{
    int mpixsrc, mxsrc, mysrc, mwsrc, mhsrc, mpixdest, mxdest, mydest;
    GdkPixbuf *pixsrc, *pixdest;

    g_message ("SCOL_gtkPixCopyArea : entering");

    mydest = MTOI (MMpull (m));
    mxdest = MTOI (MMpull (m));
    mpixdest = MMpull (m);
    mhsrc = MTOI (MMpull (m));
    mwsrc = MTOI (MMpull (m));
    mysrc = MTOI (MMpull (m));
    mxsrc = MTOI (MMpull (m));
    mpixsrc = MMpull (m);

    if (mpixsrc == NIL)
    {
        g_warning ("SCOL_gtkPixCopyArea error : source object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pixsrc = (GdkPixbuf*) MMfetch (m, MTOP (mpixsrc), OBJ2DGTK_PIX_HANDLE);

    if (mxsrc < 0)
        mxsrc = 0;
    if (mysrc < 0)
        mysrc = 0;
    if (mwsrc < 0)
        mwsrc = 1;
    if (mhsrc < 0)
        mhsrc = 1;
    if (mxdest < 0)
        mxdest = 0;
    if (mydest < 0)
        mydest = 0;

    if (mpixdest == NIL)
        pixdest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 8, TRUE, mwsrc, mhsrc);
    else
        pixdest = (GdkPixbuf*) MMfetch (m, MTOP (mpixdest), OBJ2DGTK_PIX_HANDLE);
    if (pixdest == NULL)
    {
        g_warning ("SCOL_gtkPixCopyArea error : destination object is null");
        MMpush (m, NIL);
        return 0;
    }

    gdk_pixbuf_copy_area (pixsrc, mxsrc, mysrc, mwsrc, mhsrc, pixdest, mxdest, mydest);

    if (mpixdest == NIL)
    {
        MMpush (m, MMgetglobal (m, OFFSCCUR));
        return SCOL_gtk_memory_createObjectTAB (m, pixdest, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
    }
    return MMpush (m, mpixdest);
}

/**
 * \brief _gtkPixCopy : Copies a pix into another pix
 * fun [ObjGtkPix ObjGtkPix] ObjGtkPix
 */
int SCOL_gtkPixCopy (mmachine m)
{
    int mpixdest, mpixsrc;
    GdkPixbuf *pixsrc, *pixdest;

    g_message ("SCOL_gtkPixCopy : entering");

    mpixdest = MMpull (m);
    mpixsrc = MMpull (m);

    if (mpixsrc == NIL)
    {
        g_warning ("SCOL_gtkPixCopy error : source object is nil");
        MMpush (m, NIL);
        return 0;
    }

    pixsrc = (GdkPixbuf*) MMfetch (m, MTOP (mpixsrc), OBJ2DGTK_PIX_HANDLE);
    g_object_ref (pixsrc);

    if (mpixdest != NIL)
    {
        pixdest = (GdkPixbuf*) MMfetch (m, MTOP (mpixdest), OBJ2DGTK_PIX_HANDLE);
        g_object_unref (pixdest);
        MMstore (m, MTOP (mpixdest), OBJ2DGTK_PIX_HANDLE, (int) pixsrc);
        return 0;
    }

    MMpush (m, MMgetglobal (m, OFFSCCUR));
    return SCOL_gtk_memory_createObjectTAB (m, pixsrc, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
}


/**
 * \brief _gtkPixSaturation : Modifies the saturation to a pix object
 * fun [ObjPixGtk I] ObjGtkPix
 * \param ObjGtkPix : a pix object
 * \param I : value. Between -100 and 0, saturation is reduced (-> greyscale), between 0 and 100, the saturation is increased (vivid colors)
 * \return ObjGtkPix : the same pix or nil if error
 */
int SCOL_gtkPixSaturation (mmachine m)
{
    int mpix, mvalue;
    gfloat sat = 1.0;   /* equals at nothing */
    GdkPixbuf *pix;

    mvalue = MTOI (MMpull (m));
    mpix = MMpull (m);

    g_message ("SCOL_gtkPixSaturation : entering");

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixSaturation error : source object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);

    if ((mvalue > -100) && (mvalue < 0))
        sat = (-1.0) * (mvalue / 100.0);
    else if ((mvalue < 100) && (mvalue > 0))
        sat = mvalue / 100.0;

    gdk_pixbuf_saturate_and_pixelate (pix, pix, sat, FALSE);
    MMpush (m, mpix);
    return 0;
}

/**
 * \brief _gtkPixFill : fill a pix object to athe given color
 * fun [ObjGtkPix I] ObjGtkPix
 * \param ObjGtkPix : an existing pix object
 * \param I : value. Format is : RRGGBBAA. If pix hasn't an alpha channel, AA is ignored
 * \return ObjGtkPix : the same pix object or nil if error
 */
int SCOL_gtkPixFill (mmachine m)
{
    int mpix, mvalue;
    GdkPixbuf *pix;

    mvalue = MTOI (MMpull (m));
    mpix = MMpull (m);

    g_message ("SCOL_gtkPixFill : entering");

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixFill error : source object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    gdk_pixbuf_fill (pix, mvalue);
    MMpush (m, mpix);
    return 0;
}

/**
 * \brief _gtkPixGetSize : returns the size of a pix object
 * fun [ObjGtkPix] [I I]
 * \param ObjGtkPix : a pix object
 * \return [I I] : the width and the height, or nil if error
 */
int SCOL_gtkPixGetSize (mmachine m)
{
    int mpix;
    GdkPixbuf *pix;

    mpix = MMpull (m);

    g_message ("SCOL_gtkPixGetSize : entering");

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixGetSize error : source object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    MMpush (m, ITOM (gdk_pixbuf_get_width (pix)));
    MMpush (m, ITOM (gdk_pixbuf_get_height (pix)));
    MMpush (m, ITOM (2));
    MBdeftab (m);
    return 0;
}

/**
 * \brief _gtkPixGetChannels : returns infos on the colors channels
 * fun [ObjGtkPix] [I I I]
 * \param ObjGtkPix : a pix object
 * \return [I I I] : the number of channels of the pix object, if the pix object has an alpha channel and the number of bits per color
 */
int SCOL_gtkPixGetChannels (mmachine m)
{
    int mpix;
    GdkPixbuf *pix;

    mpix = MMpull (m);

    g_message ("SCOL_gtkPixGetChannels : entering");

    if (mpix == NIL)
    {
        g_warning ("SCOL_gtkPixGetChannels error : source object is nil");
        MMpush (m, NIL);
        return 0;
    }
    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);
    MMpush (m, ITOM (gdk_pixbuf_get_n_channels (pix)));
    MMpush (m, ITOM (gdk_pixbuf_get_has_alpha (pix)));
    MMpush (m, ITOM (gdk_pixbuf_get_bits_per_sample (pix)));
    MMpush (m, ITOM (2));
    MBdeftab (m);
    return 0;
}




/**
* \brief _gtkPixAnimLoad : loads an animated image file
* fun [Chn P] ObjGtkPix
* \param Chn : a channel
* \param P : a read reference file to load
* \return ObjGtkPix : a new pix object or nil if error
*/
int SCOL_gtkPixAnimLoad (mmachine m)
{
    int mchannel, mfilename;
    GdkPixbufAnimation *anim;
    GError *err;

    g_message ("SCOL_gtkPixAnimLoad : entering");

    mfilename = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkPixAnimLoad error : channel is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    if (mfilename == NIL)
    {
        g_warning ("SCOL_gtkPixAnimLoad error : filename is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    anim = gdk_pixbuf_animation_new_from_file (MMstartstr (m, mfilename), &err);
    if ((anim == NULL) || (err != NULL))
    {
        g_warning ("SCOL_gtkPixAnimLoad error : can not load the file : %d -> %s", err->code, err->message);
        g_error_free (err);
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    return SCOL_gtk_memory_createObjectTAB (m, anim, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
}

/**
 * \brief _gtkPixAnimNew : create a new animated pix from a list of static pix
 * fun [Chn [ObjGtkPix r1] I I I I] ObjGtkPix
 * \param Chn : a channel
 * \param [ObjGtkPix r1] : a list of static pix object. These pix must have the same width ad height than the animation, else are ignored
 * \param I : the width of the animated image
 * \param I : the height of the animated image
 * \param I : the speed of the animation, in frames per second
 * \param I : 1 (default) if the animation should loop indefinitely when it reaches the end, else 0
 * \return ObjGtkPix : a new pix object
 */
int SCOL_gtkPixAnimNew (mmachine m)
{
    int mchannel, mlist, mwidth, mheight, mrate, mloop;
    int melt, w, h;
    gint width = 100, height = 100;
    gfloat rate = 1;
    gboolean bloop = TRUE;
    GdkPixbufSimpleAnim *anim;
    GdkPixbuf *pix;

    g_message ("SCOL_gtkPixAnimNew : entering");

    mloop = MTOI (MMpull (m));
    mrate = MTOI (MMpull (m));
    mheight = MTOI (MMpull (m));
    mwidth = MTOI (MMpull (m));
    mlist = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkPixAnimLoad error : channel is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    if (mlist == NIL)
    {
        g_warning ("SCOL_gtkPixAnimNew error : list is nil");
        MMpush (m, NIL);
        return 0;
    }

    if (mwidth > 0)
        width = mwidth;
    if (mheight > 0)
        height = mheight;
    if (mrate > 0)
        rate = mrate;
    if (mloop == 0)
        bloop = FALSE;

    anim = gdk_pixbuf_simple_anim_new (width, height, rate);
    gdk_pixbuf_simple_anim_set_loop (anim, bloop);

    while (mlist != NIL)
    {
        melt = MMfetch (m, MTOP (mlist), 0);
        if (melt != NIL)
        {
            pix = (GdkPixbuf*) MMfetch (m, MTOP (melt), OBJ2DGTK_PIX_HANDLE);
            w = gdk_pixbuf_get_width (pix);
            h = gdk_pixbuf_get_height (pix);
            if ((width == w) && (height == h))
                gdk_pixbuf_simple_anim_add_frame (anim, pix);
        }
        mlist = MMfetch (m, MTOP (mlist), 1);
    }
    return SCOL_gtk_memory_createObjectTAB (m, anim, ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
}

/**
 * \brief _gtkPixAnimGetSize : returns the size of an animated pix
 * fun [ObjGtkPix] [I I]
 * \param ObjGtkPix : an animated pix object
 * \return [I I] : the width and the height or nil if error
 */
int SCOL_gtkPixAnimGetSize (mmachine m)
{
    int manim;
    GdkPixbufAnimation *anim;

    g_message ("SCOL_gtkPixAnimGetSize : entering");

    manim = MMpull (m);
    if (manim == NIL)
    {
        g_warning ("SCOL_gtkPixAnimGetSize error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    anim = (GdkPixbufAnimation*) MMfetch (m, MTOP (manim), OBJ2DGTK_PIX_HANDLE);
    MMpush (m, ITOM (gdk_pixbuf_animation_get_width (anim)));
    MMpush (m, ITOM (gdk_pixbuf_animation_get_height (anim)));
    MMpush (m, ITOM (2));
    MBdeftab (m);
    return 0;
}

/**
 * \brief _gtkPixAnimGetStatic : get the pix static object if the animated pix object is unanimated
 * fun [ObjGtkPix] ObjGtkPix
 * \param ObjGtkPix : an animated pix object
 * \return ObjGtkPix : the static pix object or nil (if error or if pix object is animated)
 */
int SCOL_gtkPixAnimGetStatic (mmachine m)
{
    int manim;
    GdkPixbufAnimation *anim;

    g_message ("SCOL_gtkPixAnimGetStatic : entering");

    manim = MMpull (m);
    if (manim == NIL)
    {
        g_warning ("SCOL_gtkPixAnimGetStatic error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    anim = (GdkPixbufAnimation*) MMfetch (m, MTOP (manim), OBJ2DGTK_PIX_HANDLE);
    if (TRUE == gdk_pixbuf_animation_is_static_image (anim))
        return SCOL_gtk_memory_createObjectTAB (m, gdk_pixbuf_animation_get_static_image (anim), ObjGtkPixType, OBJ2DGTK_PIX_HANDLE);
    else
        return MMpush (m, NIL);
}





/**
 * \brief _gtkPixFormats : returns a list of supported formats
 * fun [] [S r1]
 * \return [S r1] : this list
 */
int SCOL_gtkPixFormats (mmachine m)
{
    GSList *list = NULL;
    int i = 0;

    g_message ("SCOL_gtkPixFormats : entering");

    scol_gtk_pixbuf_get_formats_availables (&list);
    while (list != NULL)
    {
        Mpushstrbloc (m, (gchar *) list->data);
        i++;
        list = list->next;
    }
    MMpush (m, NIL);
    while (i > 0)
    {
        MMpush (m, 2*2);
        MBdeftab (m);
        i--;
    }
    return 0;
}

/**
 * \brief _gtkPixMimes : returns all mimes types supported
 * fun [] [[S r1] r1]
 */
int SCOL_gtkPixMimes (mmachine m)
{
    GSList *list = NULL;
    gchar **datas;
    int j, i = 0;

    g_message ("SCOL_gtkPixMimes : entering");

    scol_gtk_pixbuf_get_mimetypes_availables (&list);
    while (list != NULL)
    {
        datas = list->data;
        for (j = 0; datas[j] != NULL; j++)
            Mpushstrbloc (m, datas[j]);

        g_strfreev (datas);
        MMpush (m, NIL);
        for (; j > 0; j--)
        {
            MMpush (m, 2*2);
            MBdeftab (m);
        }
        i++;
        list = list->next;
    }
    MMpush (m, NIL);
    while (i > 0)
    {
        MMpush (m, 2*2);
        MBdeftab (m);
        i--;
    }
    return 0;
}

/**
 * \brief _gtkPixFormatsFull : returns info to a supported formats
 * fun [] [[S [S r1] [S r1] S S I] r1]
 * \return [[S [S r1] [S r1] S S I] r1] : for each, the name of the format, the list of the mimes types, the list of the extensions, the description and the license, if disabled (1) or not (0)
 */
int SCOL_gtkPixFormatsFull (mmachine m)
{
    GSList *list = NULL;
    GSList *datas = NULL;
    gchar *name, *description, *license;
    gchar **mimes, **extensions;
    int disabled, j, i;

    g_message ("SCOL_gtkPixFormatsFull : entering");

    scol_gtk_pixbuf_get_formats_full (&list);
    for (i = 0; list != NULL; i++)
    {
        datas = list->data;
        disabled = (int) g_slist_nth_data (datas, 5);
        name = (gchar*) g_slist_nth_data (datas, 4);
        mimes = (gchar**) g_slist_nth_data (datas, 3);
        extensions = (gchar**) g_slist_nth_data (datas, 2);
        description = (gchar*) g_slist_nth_data (datas, 1);
        license = (gchar*) g_slist_nth_data (datas, 0);

        Mpushstrbloc (m, name);
        for (j = 0; mimes[j] != NULL; j++)
            Mpushstrbloc (m, mimes[j]);
        g_strfreev (mimes);
        MMpush (m, NIL);
        for (; j > 0; j--)
        {
            MMpush (m, 2*2);
            MBdeftab (m);
        }
        for (j = 0; extensions[j] != NULL; j++)
            Mpushstrbloc (m, extensions[j]);
        g_strfreev (extensions);
        MMpush (m, NIL);
        for (; j > 0; j--)
        {
            MMpush (m, 2*2);
            MBdeftab (m);
        }
        Mpushstrbloc (m, description);
        Mpushstrbloc (m, license);
        MMpush (m, ITOM (disabled));

        MMpush (m, ITOM (6));
        MBdeftab (m);

        /*g_slist_free (datas);*/
        g_free (description);
        g_free (license);
        g_free (name);
        list = list->next;
    }
    MMpush (m, NIL);
    for (; i > 0; i--)
    {
        MMpush (m, 2*2);
        MBdeftab (m);
    }
    return 0;
}

/**
 * \brief _gtkPixFormatDisable : Disables or enables an image format.
 * fun [S I] I
 * \param S : the name of a format
 * \param I : 1 to disable, 0 to enable
 * \return I : the new state or nil if error
 */
int SCOL_gtkPixFormatDisable (mmachine m)
{
    int mname, mvalue;
    GdkPixbufFormat *format = NULL;

    g_message ("SCOL_gtkPixFormatDisable : entering");

    mvalue = MTOI (MMpull (m));
    mname = MMpull (m);
    if (mname == NIL)
    {
        g_warning ("SCOL_gtkPixFormatDisable : name is nil");
        MMpush (m, NIL);
        return 0;
    }

    scol_gtk_pixbuf_search_format_from_name (MMstartstr (m, MTOP (mname)), &format);
    if (format == NULL)
    {
        g_message ("SCOL_gtkPixFormatDisable : format not found");
        MMpush (m, NIL);
        return 0;
    }
    if (mvalue != 1)
        mvalue = 0;
    gdk_pixbuf_format_set_disabled (format, mvalue);
    MMpush (m, ITOM (gdk_pixbuf_format_is_disabled (format)));
    return 0;
}

/**
 * \brief _gtkPixGetInfo : returns some informations on an image file (typically before load it)
 * fun [P] [I I [S S I]]
 * \param P : a read referenced file
 * \return [I I [S S I]] : the width, the height and a tuple : the format (jpeg, png, ...), the license (format) and if this format is disabled (1) or not (0)
 */
int SCOL_gtkPixGetInfo (mmachine m)
{
    int mfilename;
    int w = 0, h = 0;
    GdkPixbufFormat *format;

    g_message ("SCOL_gtkPixGetInfo : entering");

    mfilename = MMpull (m);
    if (mfilename == NIL)
    {
        g_warning ("SCOL_gtkPixGetInfo : filename is nil");
        MMpush (m, NIL);
        return 0;
    }

    format = gdk_pixbuf_get_file_info (MMstartstr (m, MTOP (mfilename)), &w, &h);
    if (format == NULL)
    {
        g_message ("SCOL_gtkPixGetInfo : format not recognized");
        MMpush (m, NIL);
        return 0;
    }

    MMpush (m, ITOM (w));
    MMpush (m, ITOM (h));
    Mpushstrbloc (m, gdk_pixbuf_format_get_name (format));
    Mpushstrbloc (m, gdk_pixbuf_format_get_license (format));
    MMpush (m, (int) gdk_pixbuf_format_is_disabled (format));
    MMpush (m, ITOM (3));
    MBdeftab (m);
    MMpush (m, ITOM (3));
    MBdeftab (m);
    return 0;
}



/**
 * \brief _gtkPixSaveW : save a pix object to a physical file
 * fun [ObjGtkPix W S [[S S] r1]] ObjGtkPix
 * \param ObjGtkPix : a valid pix object. Can not be nil.
 * \param W : a write-referenced file. Can not be nil.
 * \param S : format, i.e. "tiff", "gif", .... Can be nil. In this last case, the format is "png"
 * \param [[S S] r1] : a list of options. Can be nil to get the default values.
 * \return ObjGtkPix : the same pix object or nil if error
 */
int SCOL_gtkPixSaveW (mmachine m)
{
    int mpix, mfilename, mformat, margs;
    int i = 0;
    int arg;
    gchar *option, *value;
    GdkPixbuf *pix;
    GError *err = NULL;
    #define MAX_PIX_SAVE 16
    gchar *options[MAX_PIX_SAVE], *values[MAX_PIX_SAVE];
    gchar *format;

    g_message ("SCOL_gtkPixSaveW : entering");

    margs = MMpull (m);
    mformat = MMpull (m);
    mfilename = MMpull (m);
    /*mpix = MMpull (m);*/
    mpix = MMget (m, 0);
    if ((mpix == NIL) || (mfilename == NIL))
    {
        g_warning ("SCOL_gtkPixSaveW : filename or pix object is nil");
        MMpush (m, NIL);
        return 0;
    }
    if (mformat == NIL)
        format = "png";
    else
        format = MMstartstr (m, MTOP (mformat));

    pix = (GdkPixbuf*) MMfetch (m, MTOP (mpix), OBJ2DGTK_PIX_HANDLE);

    if (margs == NIL)
    {
        gdk_pixbuf_save (pix, MMstartstr (m, MTOP (mfilename)), format, &err, NULL);
        if (err != NULL)
        {
            MMpush (m, NIL);
            g_warning ("SCOL_gtkPixSaveW error : pix can be saved : %d -> %s", err->code,err->message);
            g_error_free (err);
            return 0;
        }
        /*MMpush (m, mpix);*/
        return 0;
    }

    for (i = 0; margs != NIL; i++)
    {
        if (i >= MAX_PIX_SAVE-1)
            break;

        arg = MTOP (MMfetch (m, MTOP (margs), 0));
        if (arg == NIL)
            continue;
        option = SCOLUTF8 (MMstartstr (m, MTOP (MMfetch (m, arg, 0))));
        value = SCOLUTF8 (MMstartstr (m, MTOP (MMfetch (m, arg, 1))));
        options[i] = option;
        values[i] = value;
        g_free (option);
        g_free (value);
        margs = (MMfetch (m, MTOP (margs), 1));
    }
    options[i] = NULL;

    gdk_pixbuf_savev (pix, MMstartstr (m, MTOP (mfilename)), format, options, values, &err);
    /*g_strfreev (options);
    g_strfreev (values);*/
    if (err != NULL)
    {
        MMpush (m, NIL);
        g_warning ("SCOL_gtkPixSaveW error : pix can be saved : %d -> %s", err->code,err->message);
        g_error_free (err);
        return 0;
    }
    /*MMpush (m, mpix);*/
    return 0;
}




/* FLAGS */
int SCOL_GTK_PIX_INTERP_NEAREST (mmachine m) { MMpush (m, ITOM (INTERP_NEAREST)); return 0; }
int SCOL_GTK_PIX_INTERP_TILES (mmachine m) { MMpush (m, ITOM (INTERP_TILES)); return 0; }
int SCOL_GTK_PIX_INTERP_HYPER (mmachine m) { MMpush (m, ITOM (INTERP_HYPER)); return 0; }
int SCOL_GTK_PIX_INTERP_BILINEAR (mmachine m) { MMpush (m, ITOM (INTERP_BILINEAR)); return 0; }

int SCOL_GTK_PIX_FLIP_HORIZONTAL (mmachine m) { MMpush (m, ITOM (FLIP_HORIZONTAL)); return 0; }
int SCOL_GTK_PIX_FLIP_VERTICAL (mmachine m) { MMpush (m, ITOM (FLIP_VERTICAL)); return 0; }


/* API definitions : */

char* gtk_pb_name[GTK_PIXBUF_PKG_NB]=
{
    "SCOL_GTK_PIX_INTERP_NEAREST", "SCOL_GTK_PIX_INTERP_TILES", "SCOL_GTK_PIX_INTERP_HYPER",
    "SCOL_GTK_PIX_INTERP_BILINEAR",

    "SCOL_GTK_PIX_FLIP_HORIZONTAL", "SCOL_GTK_PIX_FLIP_VERTICAL",

    "_gtkPixFormats",
    "_gtkPixMimes",
    "_gtkPixFormatsFull",
    "_gtkPixFormatDisable",
    "_gtkPixGetInfo",

    "_gtkPixNew",
    "_gtkPixFree",
    "_gtkPixScale",
    "_gtkPixScaleEx",
    "_gtkPixRotate",
    "_gtkPixFlip",
    "_gtkPixAddAlpha",
    "_gtkPixCopyArea",
    "_gtkPixSaturation",
    "_gtkPixFill",
    "_gtkPixGetSize",
    "_gtkPixGetChannels",
    "_gtkPixCopy",  /* don't use ! */
    "_gtkPixSaveW",

    "_gtkPixAnimLoad",
    "_gtkPixAnimNew",
    "_gtkPixAnimGetSize",
    "_gtkPixAnimGetStatic"
};

int (*gtk_pb_fun[GTK_PIXBUF_PKG_NB])(mmachine m)=
{
    SCOL_GTK_PIX_INTERP_NEAREST, SCOL_GTK_PIX_INTERP_TILES, SCOL_GTK_PIX_INTERP_HYPER,
    SCOL_GTK_PIX_INTERP_BILINEAR,

    SCOL_GTK_PIX_FLIP_HORIZONTAL, SCOL_GTK_PIX_FLIP_VERTICAL,

    SCOL_gtkPixFormats,
    SCOL_gtkPixMimes,
    SCOL_gtkPixFormatsFull,
    SCOL_gtkPixFormatDisable,
    SCOL_gtkPixGetInfo,

    SCOL_gtkPixNew,
    SCOL_gtkPixFree,
    SCOL_gtkPixScale,
    SCOL_gtkPixScaleEx,
    SCOL_gtkPixRotate,
    SCOL_gtkPixFlip,
    SCOL_gtkPixAddAlpha,
    SCOL_gtkPixCopyArea,
    SCOL_gtkPixSaturation,
    SCOL_gtkPixFill,
    SCOL_gtkPixGetSize,
    SCOL_gtkPixGetChannels,
    SCOL_gtkPixCopy,
    SCOL_gtkPixSaveW,

    SCOL_gtkPixAnimLoad,
    SCOL_gtkPixAnimNew,
    SCOL_gtkPixAnimGetSize,
    SCOL_gtkPixAnimGetStatic
};

int gtk_pb_narg[GTK_PIXBUF_PKG_NB]=
{
    0, 0, 0,
    0,

    0, 0,

    0,       /* SCOL_gtkPixFormats */
    0,       /* SCOL_gtkPixMimes */
    0,       /* SCOL_gtkPixFormatsFull */
    2,       /* SCOL_gtkPixFormatDisable */
    1,       /* SCOL_gtkPixGetInfo */

    4,       /* SCOL_gtkPixNew */
    1,       /* SCOL_gtkPixFree */
    5,       /* SCOL_gtkPixScale */
    0,       /* SCOL_gtkPixScaleEx */
    3,       /* SCOL_gtkPixRotate */
    3,       /* SCOL_gtkPixFlip */
    3,       /* SCOL_gtkPixAddAlpha */
    8,       /* SCOL_gtkPixCopyArea */
    2,       /* SCOL_gtkPixSaturation */
    2,       /* SCOL_gtkPixFill */
    1,      /* SCOL_gtkPixGetSize */
    1,       /* SCOL_gtkPixGetChannels */
    2,       /* SCOL_gtkPixCopy */
    4,       /* SCOL_gtkPixSaveW */

    2,       /* SCOL_gtkPixAnimLoad */
    6,       /* SCOL_gtkPixAnimNew */
    1,       /* SCOL_gtkPixAnimGetSize */
    1       /* SCOL_gtkPixAnimGetStatic */
};

char* gtk_pb_type[GTK_PIXBUF_PKG_NB]=
{
    "fun [] I", "fun [] I", "fun [] I",
    "fun [] I",

    "fun [] I", "fun [] I",

    "fun [] [S r1]",                                         /* SCOL_gtkPixFormats */
    "fun [] [[S r1] r1]",                                    /* SCOL_gtkPixMimes */
    "fun [] [[S [S r1] [S r1] S S I] r1]",                   /* SCOL_gtkPixFormatsFull */
    "fun [S I] I",                                           /* SCOL_gtkPixFormatDisable */
    "fun [P] [I I [S S I]]",                                  /* SCOL_gtkPixGetInfo */

    "fun [Chn P I [I I I]] ObjGtkPix",                       /* SCOL_gtkPixNew */
    "fun [ObjGtkPix] I",                                     /* SCOL_gtkPixFree */
    "fun [ObjGtkPix I I I I] ObjGtkPix",                     /* SCOL_gtkPixScale */
    "fun [] ObjGtkPix",                                      /* SCOL_gtkPixScaleEx */
    "fun [ObjGtkPix I I] ObjGtkPix",                         /* SCOL_gtkPixRotate */
    "fun [ObjGtkPix I I] ObjGtkPix",                         /* SCOL_gtkPixFlip */
    "fun [ObjGtkPix [I I I] I] ObjGtkPix",                   /* SCOL_gtkPixAddAlpha */
    "fun [ObjGtkPix I I I I ObjGtkPix I I] ObjGtkPix",       /* SCOL_gtkPixCopyArea */
    "fun [ObjGtkPix I] ObjGtkPix",                           /* SCOL_gtkPixSaturation */
    "fun [ObjGtkPix I] ObjGtkPix",                           /* SCOL_gtkPixFill */
    "fun [ObjGtkPix] [I I]",                                 /* SCOL_gtkPixGetSize */
    "fun [ObjGtkPix] [I I I]",                               /* SCOL_gtkPixGetChannels */
    "fun [ObjGtkPix ObjGtkPix] ObjGtkPix",                   /* SCOL_gtkPixCopy */
    "fun [ObjGtkPix W S [[S S] r1]] ObjGtkPix",               /* SCOL_gtkPixSaveW */

    "fun [Chn P] ObjGtkPix",                                 /* SCOL_gtkPixAnimLoad */
    "fun [Chn [ObjGtkPix r1] I I I I] ObjGtkPix",            /* SCOL_gtkPixAnimNew */
    "fun [ObjGtkPix] [I I]",                                 /* SCOL_gtkPixAnimGetSize */
    "fun [ObjGtkPix] ObjGtkPix"                             /* SCOL_gtkPixAnimGetStatic */
};

int SCOLloadGTKpixbuf (mmachine m)
{
    int k;

    MMechostr (0, "SCOLloadGTKpixbuf : entering\n");

    k = PKhardpak (m, "GTK2DpixbufEngine", GTK_PIXBUF_PKG_NB, gtk_pb_name, gtk_pb_fun, gtk_pb_narg, gtk_pb_type);
    return k;
}

