Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / raster.c
dissimilarity index 89%
index 4c1719c..e236085 100644 (file)
-/* raster.c - main and other misc stuff
- *
- * Raster graphics library
- *
- * Copyright (c) 1997-2003 Alfredo K. Kojima
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library 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
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public
- *  License along with this library; if not, write to the Free
- *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <config.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <X11/Xlib.h>
-#include "wraster.h"
-
-#include <assert.h>
-
-
-char *WRasterLibVersion="0.9";
-
-int RErrorCode=RERR_NONE;
-
-
-#define HAS_ALPHA(I)   ((I)->format == RRGBAFormat)
-
-
-#define MAX_WIDTH 20000
-#define MAX_HEIGHT 20000
-/* 20000^2*4 < 2G */
-
-
-RImage*
-RCreateImage(unsigned width, unsigned height, int alpha)
-{
-    RImage *image=NULL;
-
-    assert(width>0 && height>0);
-
-    if (width > MAX_WIDTH || height > MAX_HEIGHT) {
-        RErrorCode = RERR_NOMEMORY;
-        return NULL;
-    }
-
-    image = malloc(sizeof(RImage));
-    if (!image) {
-        RErrorCode = RERR_NOMEMORY;
-        return NULL;
-    }
-
-    memset(image, 0, sizeof(RImage));
-    image->width = width;
-    image->height = height;
-    image->format = alpha ? RRGBAFormat : RRGBFormat;
-    image->refCount = 1;
-
-    /* the +4 is to give extra bytes at the end of the buffer,
-     * so that we can optimize image conversion for MMX(tm).. see convert.c
-     */
-    image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
-    if (!image->data) {
-        RErrorCode = RERR_NOMEMORY;
-        free(image);
-        image = NULL;
-    }
-
-    return image;
-
-}
-
-
-RImage*
-RRetainImage(RImage *image)
-{
-    if (image)
-        image->refCount++;
-
-    return image;
-}
-
-
-void
-RReleaseImage(RImage *image)
-{
-    assert(image!=NULL);
-
-    image->refCount--;
-
-    if (image->refCount < 1) {
-        free(image->data);
-        free(image);
-    }
-}
-
-
-RImage*
-RCloneImage(RImage *image)
-{
-    RImage *new_image;
-
-    assert(image!=NULL);
-
-    new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
-    if (!new_image)
-        return NULL;
-
-    new_image->background = image->background;
-    memcpy(new_image->data, image->data,
-           image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
-
-    return new_image;
-}
-
-
-RImage*
-RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
-{
-    int i, ofs;
-    RImage *new_image;
-    unsigned total_line_size, line_size;
-
-    assert(image!=NULL);
-    assert(x>=0 && y>=0);
-    assert(x<image->width && y<image->height);
-    assert(width>0 && height>0);
-
-    if (x+width > image->width)
-        width = image->width-x;
-    if (y+height > image->height)
-        height = image->height-y;
-
-    new_image = RCreateImage(width, height, HAS_ALPHA(image));
-
-    if (!new_image)
-        return NULL;
-    new_image->background = image->background;
-
-    total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
-    line_size = width * (HAS_ALPHA(image) ? 4 : 3);
-
-    ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
-
-    for (i=0; i<height; i++) {
-        memcpy(&new_image->data[i*line_size],
-               &image->data[i*total_line_size+ofs], line_size);
-    }
-    return new_image;
-}
-
-
-/*
- *----------------------------------------------------------------------
- * RCombineImages-
- *     Combines two equal sized images with alpha image. The second
- * image will be placed on top of the first one.
- *----------------------------------------------------------------------
- */
-void
-RCombineImages(RImage *image, RImage *src)
-{
-    assert(image->width == src->width);
-    assert(image->height == src->height);
-
-    if (!HAS_ALPHA(src)) {
-        if (!HAS_ALPHA(image)) {
-            memcpy(image->data, src->data, image->height*image->width*3);
-        } else {
-            int x, y;
-            unsigned char *d, *s;
-
-            d = image->data;
-            s = src->data;
-            for (y = 0; y < image->height; y++) {
-                for (x = 0; x < image->width; x++) {
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    d++;
-                }
-            }
-        }
-    } else {
-        register int i;
-        unsigned char *d;
-        unsigned char *s;
-        int alpha, calpha;
-
-        d = image->data;
-        s = src->data;
-
-        if (!HAS_ALPHA(image)) {
-            for (i=0; i<image->height*image->width; i++) {
-                alpha = *(s+3);
-                calpha = 255 - alpha;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
-                s++;
-            }
-        } else {
-            for (i=0; i<image->height*image->width; i++) {
-                alpha = *(s+3);
-                calpha = 255 - alpha;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
-                *d++ |= *s++;
-            }
-        }
-    }
-}
-
-
-
-
-void
-RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
-{
-    register int i;
-    unsigned char *d;
-    unsigned char *s;
-    int c_opaqueness;
-
-    assert(image->width == src->width);
-    assert(image->height == src->height);
-
-    d = image->data;
-    s = src->data;
-
-    c_opaqueness = 255 - opaqueness;
-
-#define OP opaqueness
-#define COP c_opaqueness
-
-    if (!HAS_ALPHA(src)) {
-        int dalpha = HAS_ALPHA(image);
-        for (i=0; i < image->width*image->height; i++) {
-            *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
-            *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
-            *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
-            if (dalpha) {
-                d++;
-            }
-        }
-    } else {
-        int tmp;
-
-        if (!HAS_ALPHA(image)) {
-            for (i=0; i<image->width*image->height; i++) {
-                tmp = (*(s+3) * opaqueness)/256;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                s++;
-            }
-        } else {
-            for (i=0; i<image->width*image->height; i++) {
-                tmp = (*(s+3) * opaqueness)/256;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d |= tmp;
-                d++; s++;
-            }
-        }
-    }
-#undef OP
-#undef COP
-}
-
-int
-calculateCombineArea(RImage *des, RImage *src, int *sx, int *sy,
-                     unsigned int *swidth, unsigned int *sheight, int *dx, int *dy)
-{
-    int width = (int)*swidth, height = (int)*sheight;
-
-    if (*dx < 0) {
-        *sx = -*dx;
-        width = width + *dx;
-        *dx = 0;
-    }
-
-    if (*dx + width > des->width) {
-        width = des->width - *dx;
-    }
-
-    if (*dy < 0) {
-        *sy = -*dy;
-        height = height + *dy;
-        *dy = 0;
-    }
-
-    if (*dy + height > des->height) {
-        height = des->height - *dy;
-    }
-
-    if (height>0 && width>0) {
-        *swidth  = width;
-        *sheight = height;
-        return True;
-    }
-
-    return False;
-}
-
-void
-RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
-             unsigned height, int dx, int dy)
-{
-    int x, y, dwi, swi;
-    unsigned char *d;
-    unsigned char *s;
-    int alpha, calpha;
-
-    if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
-        return;
-
-    if (!HAS_ALPHA(src)) {
-        if (!HAS_ALPHA(image)) {
-            swi = src->width * 3;
-            dwi = image->width * 3;
-
-            s = src->data + (sy*(int)src->width + sx) * 3;
-            d = image->data + (dy*(int)image->width + dx) * 3;
-
-            for (y=0; y < height; y++) {
-                memcpy(d, s, width*3);
-                d += dwi;
-                s += swi;
-            }
-        } else {
-            swi = (src->width - width) * 3;
-            dwi = (image->width - width) * 4;
-
-            s = src->data + (sy*(int)src->width + sx) * 3;
-            d = image->data + (dy*(int)image->width + dx) * 4;
-
-            for (y=0; y < height; y++) {
-                for (x=0; x < width; x++) {
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    d++;
-                }
-                d += dwi;
-                s += swi;
-            }
-        }
-    } else {
-        int dalpha = HAS_ALPHA(image);
-
-        swi = (src->width - width) * 4;
-        s = src->data + (sy*(int)src->width + sx) * 4;
-        if (dalpha) {
-            dwi = (image->width - width) * 4;
-            d = image->data + (dy*(int)image->width + dx) * 4;
-        } else {
-            dwi = (image->width - width) * 3;
-            d = image->data + (dy*(int)image->width + dx) * 3;
-        }
-
-        for (y=0; y < height; y++) {
-            for (x=0; x < width; x++) {
-                alpha = *(s+3);
-                calpha = 255 - alpha;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
-                *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
-                s++;
-                if (dalpha)
-                    d++;
-            }
-            d += dwi;
-            s += swi;
-        }
-    }
-}
-
-
-void
-RCopyArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
-          unsigned height, int dx, int dy)
-{
-    int x, y, dwi, swi;
-    unsigned char *d;
-    unsigned char *s;
-
-    if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
-        return;
-
-    if (!HAS_ALPHA(src)) {
-        if (!HAS_ALPHA(image)) {
-            swi = src->width * 3;
-            dwi = image->width * 3;
-
-            s = src->data + (sy*(int)src->width + sx) * 3;
-            d = image->data + (dy*(int)image->width + dx) * 3;
-
-            for (y=0; y < height; y++) {
-                memcpy(d, s, width*3);
-                d += dwi;
-                s += swi;
-            }
-        } else {
-            swi = (src->width - width) * 3;
-            dwi = (image->width - width) * 4;
-
-            s = src->data + (sy*(int)src->width + sx) * 3;
-            d = image->data + (dy*(int)image->width + dx) * 4;
-
-            for (y=0; y < height; y++) {
-                for (x=0; x < width; x++) {
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    d++;
-                }
-                d += dwi;
-                s += swi;
-            }
-        }
-    } else {
-        int dalpha = HAS_ALPHA(image);
-
-        swi = src->width * 4;
-        s = src->data + (sy*(int)src->width + sx) * 4;
-        if (dalpha) {
-            dwi = image->width * 4;
-            d = image->data + (dy*(int)image->width + dx) * 4;
-        } else {
-            dwi = image->width * 3;
-            d = image->data + (dy*(int)image->width + dx) * 3;
-        }
-
-        if (dalpha) {
-            for (y=0; y < height; y++) {
-                memcpy(d, s, width*4);
-                d += dwi;
-                s += swi;
-            }
-        } else {
-            for (y=0; y < height; y++) {
-                for (x=0; x < width; x++) {
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    *d++ = *s++;
-                    s++;
-                }
-                d += dwi;
-                s += swi;
-            }
-        }
-    }
-}
-
-
-void
-RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
-                           unsigned width, unsigned height, int dx, int dy,
-                           int opaqueness)
-{
-    int x, y, dwi, swi;
-    int c_opaqueness;
-    unsigned char *s, *d;
-    int dalpha = HAS_ALPHA(image);
-    int dch = (dalpha ? 4 : 3);
-
-    if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
-        return;
-
-    d = image->data + (dy*image->width + dx) * dch;
-    dwi = (image->width - width)*dch;
-
-    c_opaqueness = 255 - opaqueness;
-
-#define OP opaqueness
-#define COP c_opaqueness
-
-    if (!HAS_ALPHA(src)) {
-
-        s = src->data + (sy*src->width + sx)*3;
-        swi = (src->width - width) * 3;
-
-        for (y=0; y < height; y++) {
-            for (x=0; x < width; x++) {
-                *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
-                *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
-                *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
-                if (dalpha)
-                    d++;
-            }
-            d += dwi; s += swi;
-        }
-    } else {
-        int tmp;
-
-        s = src->data + (sy*src->width + sx)*4;
-        swi = (src->width - width) * 4;
-
-        for (y=0; y < height; y++) {
-            for (x=0; x < width; x++) {
-                tmp = (*(s+3) * opaqueness)/256;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
-                s++;
-                if (dalpha)
-                    d++;
-            }
-            d += dwi; s += swi;
-        }
-    }
-#undef OP
-#undef COP
-}
-
-
-
-void
-RCombineImageWithColor(RImage *image, RColor *color)
-{
-    register int i;
-    unsigned char *d;
-    int alpha, nalpha, r, g, b;
-
-    d = image->data;
-
-    if (!HAS_ALPHA(image)) {
-        /* Image has no alpha channel, so we consider it to be all 255.
-         * Thus there are no transparent parts to be filled. */
-        return;
-    }
-    r = color->red;
-    g = color->green;
-    b = color->blue;
-
-    for (i=0; i < image->width*image->height; i++) {
-        alpha = *(d+3);
-        nalpha = 255 - alpha;
-
-        *d = (((int)*d * alpha) + (r * nalpha))/256; d++;
-        *d = (((int)*d * alpha) + (g * nalpha))/256; d++;
-        *d = (((int)*d * alpha) + (b * nalpha))/256; d++;
-        d++;
-    }
-}
-
-
-
-
-RImage*
-RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
-{
-    int x, y;
-    unsigned w;
-    unsigned long tile_size = tile->width * tile->height;
-    unsigned long tx = 0;
-    RImage *image;
-    unsigned char *s, *d;
-
-    if (width == tile->width && height == tile->height)
-        image = RCloneImage(tile);
-    else if (width <= tile->width && height <= tile->height)
-        image = RGetSubImage(tile, 0, 0, width, height);
-    else {
-        int has_alpha = HAS_ALPHA(tile);
-
-        image = RCreateImage(width, height, has_alpha);
-
-        d = image->data;
-        s = tile->data;
-
-        for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x += tile->width) {
-
-                w = (width - x < tile->width) ? width - x : tile->width;
-
-                if (has_alpha) {
-                    w *= 4;
-                    memcpy(d, s+tx*4, w);
-                } else {
-                    w *= 3;
-                    memcpy(d, s+tx*3, w);
-                }
-                d += w;
-            }
-
-            tx = (tx + tile->width) % tile_size;
-        }
-    }
-    return image;
-}
-
-
-RImage*
-RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
-{
-    int x, y, w, h, sx, sy;
-    RImage *tmp;
-
-    tmp = RCreateImage(width, height, False);
-    if (!tmp) {
-        return NULL;
-    }
-
-    RClearImage(tmp, color);
-
-    if (image->height < height) {
-        h = image->height;
-        y = (height - h)/2;
-        sy = 0;
-    } else {
-        sy = (image->height - height)/2;
-        y = 0;
-        h = height;
-    }
-    if (image->width < width) {
-        w = image->width;
-        x = (width - w)/2;
-        sx = 0;
-    } else {
-        sx = (image->width - width)/2;
-        x = 0;
-        w = width;
-    }
-    RCombineArea(tmp, image, sx, sy, w, h, x, y);
-
-    return tmp;
-}
-
+/* raster.c - main and other misc stuff
+ *
+ * Raster graphics library
+ *
+ * Copyright (c) 1997-2003 Alfredo K. Kojima
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include "wraster.h"
+
+#include <assert.h>
+
+char *WRasterLibVersion = "0.9";
+
+int RErrorCode = RERR_NONE;
+
+#define HAS_ALPHA(I)   ((I)->format == RRGBAFormat)
+
+#define MAX_WIDTH 20000
+#define MAX_HEIGHT 20000
+/* 20000^2*4 < 2G */
+
+RImage *RCreateImage(unsigned width, unsigned height, int alpha)
+{
+       RImage *image = NULL;
+
+       assert(width > 0 && height > 0);
+
+       if (width > MAX_WIDTH || height > MAX_HEIGHT) {
+               RErrorCode = RERR_NOMEMORY;
+               return NULL;
+       }
+
+       image = malloc(sizeof(RImage));
+       if (!image) {
+               RErrorCode = RERR_NOMEMORY;
+               return NULL;
+       }
+
+       memset(image, 0, sizeof(RImage));
+       image->width = width;
+       image->height = height;
+       image->format = alpha ? RRGBAFormat : RRGBFormat;
+       image->refCount = 1;
+
+       /* the +4 is to give extra bytes at the end of the buffer,
+        * so that we can optimize image conversion for MMX(tm).. see convert.c
+        */
+       image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
+       if (!image->data) {
+               RErrorCode = RERR_NOMEMORY;
+               free(image);
+               image = NULL;
+       }
+
+       return image;
+
+}
+
+RImage *RRetainImage(RImage * image)
+{
+       if (image)
+               image->refCount++;
+
+       return image;
+}
+
+void RReleaseImage(RImage * image)
+{
+       assert(image != NULL);
+
+       image->refCount--;
+
+       if (image->refCount < 1) {
+               free(image->data);
+               free(image);
+       }
+}
+
+RImage *RCloneImage(RImage * image)
+{
+       RImage *new_image;
+
+       assert(image != NULL);
+
+       new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
+       if (!new_image)
+               return NULL;
+
+       new_image->background = image->background;
+       memcpy(new_image->data, image->data, image->width * image->height * (HAS_ALPHA(image) ? 4 : 3));
+
+       return new_image;
+}
+
+RImage *RGetSubImage(RImage * image, int x, int y, unsigned width, unsigned height)
+{
+       int i, ofs;
+       RImage *new_image;
+       unsigned total_line_size, line_size;
+
+       assert(image != NULL);
+       assert(x >= 0 && y >= 0);
+       assert(x < image->width && y < image->height);
+       assert(width > 0 && height > 0);
+
+       if (x + width > image->width)
+               width = image->width - x;
+       if (y + height > image->height)
+               height = image->height - y;
+
+       new_image = RCreateImage(width, height, HAS_ALPHA(image));
+
+       if (!new_image)
+               return NULL;
+       new_image->background = image->background;
+
+       total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
+       line_size = width * (HAS_ALPHA(image) ? 4 : 3);
+
+       ofs = x * (HAS_ALPHA(image) ? 4 : 3) + y * total_line_size;;
+
+       for (i = 0; i < height; i++) {
+               memcpy(&new_image->data[i * line_size], &image->data[i * total_line_size + ofs], line_size);
+       }
+       return new_image;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * RCombineImages-
+ *     Combines two equal sized images with alpha image. The second
+ * image will be placed on top of the first one.
+ *----------------------------------------------------------------------
+ */
+void RCombineImages(RImage * image, RImage * src)
+{
+       assert(image->width == src->width);
+       assert(image->height == src->height);
+
+       if (!HAS_ALPHA(src)) {
+               if (!HAS_ALPHA(image)) {
+                       memcpy(image->data, src->data, image->height * image->width * 3);
+               } else {
+                       int x, y;
+                       unsigned char *d, *s;
+
+                       d = image->data;
+                       s = src->data;
+                       for (y = 0; y < image->height; y++) {
+                               for (x = 0; x < image->width; x++) {
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       d++;
+                               }
+                       }
+               }
+       } else {
+               register int i;
+               unsigned char *d;
+               unsigned char *s;
+               int alpha, calpha;
+
+               d = image->data;
+               s = src->data;
+
+               if (!HAS_ALPHA(image)) {
+                       for (i = 0; i < image->height * image->width; i++) {
+                               alpha = *(s + 3);
+                               calpha = 255 - alpha;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               d++;
+                               s++;
+                               s++;
+                       }
+               } else {
+                       for (i = 0; i < image->height * image->width; i++) {
+                               alpha = *(s + 3);
+                               calpha = 255 - alpha;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               d++;
+                               s++;
+                               *d++ |= *s++;
+                       }
+               }
+       }
+}
+
+void RCombineImagesWithOpaqueness(RImage * image, RImage * src, int opaqueness)
+{
+       register int i;
+       unsigned char *d;
+       unsigned char *s;
+       int c_opaqueness;
+
+       assert(image->width == src->width);
+       assert(image->height == src->height);
+
+       d = image->data;
+       s = src->data;
+
+       c_opaqueness = 255 - opaqueness;
+
+#define OP opaqueness
+#define COP c_opaqueness
+
+       if (!HAS_ALPHA(src)) {
+               int dalpha = HAS_ALPHA(image);
+               for (i = 0; i < image->width * image->height; i++) {
+                       *d = (((int)*d * (int)COP) + ((int)*s * (int)OP)) / 256;
+                       d++;
+                       s++;
+                       *d = (((int)*d * (int)COP) + ((int)*s * (int)OP)) / 256;
+                       d++;
+                       s++;
+                       *d = (((int)*d * (int)COP) + ((int)*s * (int)OP)) / 256;
+                       d++;
+                       s++;
+                       if (dalpha) {
+                               d++;
+                       }
+               }
+       } else {
+               int tmp;
+
+               if (!HAS_ALPHA(image)) {
+                       for (i = 0; i < image->width * image->height; i++) {
+                               tmp = (*(s + 3) * opaqueness) / 256;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               s++;
+                       }
+               } else {
+                       for (i = 0; i < image->width * image->height; i++) {
+                               tmp = (*(s + 3) * opaqueness) / 256;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d |= tmp;
+                               d++;
+                               s++;
+                       }
+               }
+       }
+#undef OP
+#undef COP
+}
+
+int
+calculateCombineArea(RImage * des, RImage * src, int *sx, int *sy,
+                    unsigned int *swidth, unsigned int *sheight, int *dx, int *dy)
+{
+       int width = (int)*swidth, height = (int)*sheight;
+
+       if (*dx < 0) {
+               *sx = -*dx;
+               width = width + *dx;
+               *dx = 0;
+       }
+
+       if (*dx + width > des->width) {
+               width = des->width - *dx;
+       }
+
+       if (*dy < 0) {
+               *sy = -*dy;
+               height = height + *dy;
+               *dy = 0;
+       }
+
+       if (*dy + height > des->height) {
+               height = des->height - *dy;
+       }
+
+       if (height > 0 && width > 0) {
+               *swidth = width;
+               *sheight = height;
+               return True;
+       }
+
+       return False;
+}
+
+void RCombineArea(RImage * image, RImage * src, int sx, int sy, unsigned width, unsigned height, int dx, int dy)
+{
+       int x, y, dwi, swi;
+       unsigned char *d;
+       unsigned char *s;
+       int alpha, calpha;
+
+       if (!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
+               return;
+
+       if (!HAS_ALPHA(src)) {
+               if (!HAS_ALPHA(image)) {
+                       swi = src->width * 3;
+                       dwi = image->width * 3;
+
+                       s = src->data + (sy * (int)src->width + sx) * 3;
+                       d = image->data + (dy * (int)image->width + dx) * 3;
+
+                       for (y = 0; y < height; y++) {
+                               memcpy(d, s, width * 3);
+                               d += dwi;
+                               s += swi;
+                       }
+               } else {
+                       swi = (src->width - width) * 3;
+                       dwi = (image->width - width) * 4;
+
+                       s = src->data + (sy * (int)src->width + sx) * 3;
+                       d = image->data + (dy * (int)image->width + dx) * 4;
+
+                       for (y = 0; y < height; y++) {
+                               for (x = 0; x < width; x++) {
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       d++;
+                               }
+                               d += dwi;
+                               s += swi;
+                       }
+               }
+       } else {
+               int dalpha = HAS_ALPHA(image);
+
+               swi = (src->width - width) * 4;
+               s = src->data + (sy * (int)src->width + sx) * 4;
+               if (dalpha) {
+                       dwi = (image->width - width) * 4;
+                       d = image->data + (dy * (int)image->width + dx) * 4;
+               } else {
+                       dwi = (image->width - width) * 3;
+                       d = image->data + (dy * (int)image->width + dx) * 3;
+               }
+
+               for (y = 0; y < height; y++) {
+                       for (x = 0; x < width; x++) {
+                               alpha = *(s + 3);
+                               calpha = 255 - alpha;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               s++;
+                               d++;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               s++;
+                               d++;
+                               *d = (((int)*d * calpha) + ((int)*s * alpha)) / 256;
+                               s++;
+                               d++;
+                               s++;
+                               if (dalpha)
+                                       d++;
+                       }
+                       d += dwi;
+                       s += swi;
+               }
+       }
+}
+
+void RCopyArea(RImage * image, RImage * src, int sx, int sy, unsigned width, unsigned height, int dx, int dy)
+{
+       int x, y, dwi, swi;
+       unsigned char *d;
+       unsigned char *s;
+
+       if (!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
+               return;
+
+       if (!HAS_ALPHA(src)) {
+               if (!HAS_ALPHA(image)) {
+                       swi = src->width * 3;
+                       dwi = image->width * 3;
+
+                       s = src->data + (sy * (int)src->width + sx) * 3;
+                       d = image->data + (dy * (int)image->width + dx) * 3;
+
+                       for (y = 0; y < height; y++) {
+                               memcpy(d, s, width * 3);
+                               d += dwi;
+                               s += swi;
+                       }
+               } else {
+                       swi = (src->width - width) * 3;
+                       dwi = (image->width - width) * 4;
+
+                       s = src->data + (sy * (int)src->width + sx) * 3;
+                       d = image->data + (dy * (int)image->width + dx) * 4;
+
+                       for (y = 0; y < height; y++) {
+                               for (x = 0; x < width; x++) {
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       d++;
+                               }
+                               d += dwi;
+                               s += swi;
+                       }
+               }
+       } else {
+               int dalpha = HAS_ALPHA(image);
+
+               swi = src->width * 4;
+               s = src->data + (sy * (int)src->width + sx) * 4;
+               if (dalpha) {
+                       dwi = image->width * 4;
+                       d = image->data + (dy * (int)image->width + dx) * 4;
+               } else {
+                       dwi = image->width * 3;
+                       d = image->data + (dy * (int)image->width + dx) * 3;
+               }
+
+               if (dalpha) {
+                       for (y = 0; y < height; y++) {
+                               memcpy(d, s, width * 4);
+                               d += dwi;
+                               s += swi;
+                       }
+               } else {
+                       for (y = 0; y < height; y++) {
+                               for (x = 0; x < width; x++) {
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       *d++ = *s++;
+                                       s++;
+                               }
+                               d += dwi;
+                               s += swi;
+                       }
+               }
+       }
+}
+
+void
+RCombineAreaWithOpaqueness(RImage * image, RImage * src, int sx, int sy,
+                          unsigned width, unsigned height, int dx, int dy, int opaqueness)
+{
+       int x, y, dwi, swi;
+       int c_opaqueness;
+       unsigned char *s, *d;
+       int dalpha = HAS_ALPHA(image);
+       int dch = (dalpha ? 4 : 3);
+
+       if (!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
+               return;
+
+       d = image->data + (dy * image->width + dx) * dch;
+       dwi = (image->width - width) * dch;
+
+       c_opaqueness = 255 - opaqueness;
+
+#define OP opaqueness
+#define COP c_opaqueness
+
+       if (!HAS_ALPHA(src)) {
+
+               s = src->data + (sy * src->width + sx) * 3;
+               swi = (src->width - width) * 3;
+
+               for (y = 0; y < height; y++) {
+                       for (x = 0; x < width; x++) {
+                               *d = (((int)*d * (int)COP) + ((int)*s * (int)OP)) / 256;
+                               s++;
+                               d++;
+                               *d = (((int)*d * (int)COP) + ((int)*s * (int)OP)) / 256;
+                               s++;
+                               d++;
+                               *d = (((int)*d * (int)COP) + ((int)*s * (int)OP)) / 256;
+                               s++;
+                               d++;
+                               if (dalpha)
+                                       d++;
+                       }
+                       d += dwi;
+                       s += swi;
+               }
+       } else {
+               int tmp;
+
+               s = src->data + (sy * src->width + sx) * 4;
+               swi = (src->width - width) * 4;
+
+               for (y = 0; y < height; y++) {
+                       for (x = 0; x < width; x++) {
+                               tmp = (*(s + 3) * opaqueness) / 256;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               *d = (((int)*d * (255 - tmp)) + ((int)*s * tmp)) / 256;
+                               d++;
+                               s++;
+                               s++;
+                               if (dalpha)
+                                       d++;
+                       }
+                       d += dwi;
+                       s += swi;
+               }
+       }
+#undef OP
+#undef COP
+}
+
+void RCombineImageWithColor(RImage * image, RColor * color)
+{
+       register int i;
+       unsigned char *d;
+       int alpha, nalpha, r, g, b;
+
+       d = image->data;
+
+       if (!HAS_ALPHA(image)) {
+               /* Image has no alpha channel, so we consider it to be all 255.
+                * Thus there are no transparent parts to be filled. */
+               return;
+       }
+       r = color->red;
+       g = color->green;
+       b = color->blue;
+
+       for (i = 0; i < image->width * image->height; i++) {
+               alpha = *(d + 3);
+               nalpha = 255 - alpha;
+
+               *d = (((int)*d * alpha) + (r * nalpha)) / 256;
+               d++;
+               *d = (((int)*d * alpha) + (g * nalpha)) / 256;
+               d++;
+               *d = (((int)*d * alpha) + (b * nalpha)) / 256;
+               d++;
+               d++;
+       }
+}
+
+RImage *RMakeTiledImage(RImage * tile, unsigned width, unsigned height)
+{
+       int x, y;
+       unsigned w;
+       unsigned long tile_size = tile->width * tile->height;
+       unsigned long tx = 0;
+       RImage *image;
+       unsigned char *s, *d;
+
+       if (width == tile->width && height == tile->height)
+               image = RCloneImage(tile);
+       else if (width <= tile->width && height <= tile->height)
+               image = RGetSubImage(tile, 0, 0, width, height);
+       else {
+               int has_alpha = HAS_ALPHA(tile);
+
+               image = RCreateImage(width, height, has_alpha);
+
+               d = image->data;
+               s = tile->data;
+
+               for (y = 0; y < height; y++) {
+                       for (x = 0; x < width; x += tile->width) {
+
+                               w = (width - x < tile->width) ? width - x : tile->width;
+
+                               if (has_alpha) {
+                                       w *= 4;
+                                       memcpy(d, s + tx * 4, w);
+                               } else {
+                                       w *= 3;
+                                       memcpy(d, s + tx * 3, w);
+                               }
+                               d += w;
+                       }
+
+                       tx = (tx + tile->width) % tile_size;
+               }
+       }
+       return image;
+}
+
+RImage *RMakeCenteredImage(RImage * image, unsigned width, unsigned height, RColor * color)
+{
+       int x, y, w, h, sx, sy;
+       RImage *tmp;
+
+       tmp = RCreateImage(width, height, False);
+       if (!tmp) {
+               return NULL;
+       }
+
+       RClearImage(tmp, color);
+
+       if (image->height < height) {
+               h = image->height;
+               y = (height - h) / 2;
+               sy = 0;
+       } else {
+               sy = (image->height - height) / 2;
+               y = 0;
+               h = height;
+       }
+       if (image->width < width) {
+               w = image->width;
+               x = (width - w) / 2;
+               sx = 0;
+       } else {
+               sx = (image->width - width) / 2;
+               x = 0;
+               w = width;
+       }
+       RCombineArea(tmp, image, sx, sy, w, h, x, y);
+
+       return tmp;
+}