/* Copyright (C) 2001 Johan Rydberg. All Rights Reserved. This file is part of Crust. This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU 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. */ #include "GFImage.h" #include #include /* Create a new image. We allocate pixel buffer for image. */ GFImageRef GFImageCreate (int width, int height, int samples, int bits, GFImageAlphaInfo alpha) { GFImageRef image; image = malloc (sizeof (struct GFImage)); image->x0 = 0; image->y0 = 0; image->x1 = width; image->y1 = height; image->samples = samples; image->bits = bits; image->alpha = alpha; image->rowstride = (image->bits * image->samples / 8) * width; image->pixels = malloc (GFImageRowStride (image) * height); return image; } GFImageRef GFImageCreateWithData (void *pixels, int x, int y, int width, int height, int samples, int bits, int rowstride, GFImageAlphaInfo alpha) { GFImageRef image; image = malloc (sizeof (struct GFImage)); image->x0 = x; image->y0 = y; image->x1 = x + width; image->y1 = y + height; image->samples = samples; image->bits = bits; image->alpha = alpha; image->pixels = pixels; image->rowstride = rowstride; return image; } /* Copy bits from SRC_IMG into DST_IMG. (DX, DY) is destination point. */ void GFImageCopyBits (GFImageRef dst_img, GFImageRef src_img, int dx, int dy, int sx, int sy, int width, int height) { int dst_rowpitch, src_rowpitch, i; int dst_pixpitch, src_pixpitch; unsigned char *dst_buf, *src_buf; src_pixpitch = GFImagePixelStride (src_img); src_rowpitch = GFImageRowStride (src_img); src_buf = src_img->pixels + (src_rowpitch * (sy + src_img->y0)) + (src_pixpitch * (sx + src_img->x0)); dst_pixpitch = GFImagePixelStride (dst_img); dst_rowpitch = GFImageRowStride (dst_img); dst_buf = dst_img->pixels + (dst_rowpitch * (dy + dst_img->y0)) + (dst_pixpitch * (dx + dst_img->x0)); for (i = 0; i < height; i++) { memcpy (dst_buf, src_buf, src_pixpitch * width); src_buf += src_rowpitch; dst_buf += dst_rowpitch; } } /* Set all color channels to VALUE in SCR_IMG. Leave alpha channel untouched. */ void GFImageClearColors (GFImageRef src_img, int value) { int src_rowpitch, src_pixpitch, src_rgba; unsigned char *src_buf, *src; int i, n, j; src_pixpitch = GFImagePixelStride (src_img); src_rowpitch = GFImageRowStride (src_img); src_buf = src_img->pixels + (src_rowpitch * (src_img->y0)) + (src_pixpitch * (src_img->x0)); for (n = 0; n < GFImageHeight (src_img); n++) { src = src_buf; for (i = 0; i < GFImageWidth (src_img); i++) { for (j = 0; j < 3; j++) src [j] = value; src += src_pixpitch; } src_buf += src_rowpitch; } } /* Composite RGBA image over RGBA buffer. ??? add support for non-compatible images, optimize the common-case. ??? add support for alpha channel placement. ??? optimize case when this is non-scale operation. */ void GFImageComposite (GFImageRef dst_img, GFImageRef src_img, int x, int y, int width, int height) { int ydest, c, dst_rowpitch, src_rowpitch, toy, i, px, py; unsigned char *dst_buf, *src_buf; int dst_pixpitch, src_pixpitch; unsigned int src_rgba, dst_rgba; unsigned char src_alpha, dst_alpha; unsigned char *src; unsigned char *dst; /* Stretch vectors */ int *stx; int *sty; /* We only need to use floating point to determine the correct stretch vector for one line's worth. */ double accum; /* First of all check so that the images are compatible. ??? add support for non-compatible images. */ if (dst_img->samples != src_img->samples || dst_img->bits != src_img->bits || dst_img->alpha != src_img->alpha) return; stx = (int *) malloc (sizeof (int) * GFImageWidth (src_img)); sty = (int *) malloc (sizeof (int) * GFImageHeight (src_img)); for (i = 0, accum = 0; i < GFImageWidth (src_img); i++) { int got; accum += (double) width / (double) GFImageWidth (src_img); got = (int) floor (accum); stx[i] = got; accum -= got; } for (i = 0, accum = 0; i < GFImageHeight (src_img); i++) { int got; accum += (double) height / (double) GFImageHeight (src_img); got = (int) floor (accum); sty[i] = got; accum -= got; } src_pixpitch = GFImagePixelStride (src_img); src_rowpitch = GFImageRowStride (src_img); src_buf = src_img->pixels; dst_pixpitch = GFImagePixelStride (dst_img); dst_rowpitch = GFImageRowStride (dst_img); dst_buf = dst_img->pixels + (dst_rowpitch * (y + dst_img->y0)) + (dst_pixpitch * (x + dst_img->x0)); toy = y; for (py = 0; py < GFImageHeight (src_img); py++) { for (ydest = 0; ydest < sty [py]; ydest++) { src = src_buf; dst = dst_buf; for (px = 0; px < GFImageWidth (src_img); px++) { if (! stx [px]) continue; #ifdef WORDS_BIGENDIAN src_rgba = ((unsigned int *) src) [0]; src_alpha = src_rgba & 0xff; #else src_rgba = ((unsigned int *) src) [0]; src_alpha = src_rgba >> 24; #endif for (i = 0; i < stx [px]; i++) { #ifdef WORDS_BIGENDIAN dst_rgba = ((unsigned int *) dst) [0]; dst_alpha = dst_rgba & 0xff; #else dst_rgba = ((unsigned int *) dst) [0]; dst_alpha = dst_rgba >> 24; #endif if (src_alpha) { if (src_alpha == 0xff || dst_alpha == 0) ((unsigned int *) dst) [0] = src_rgba; else { int r, g, b, a; int src_r, src_g, src_b; int dst_r, dst_g, dst_b; int tmp; tmp = (255 - src_alpha) * (255 - dst_alpha) + 0x80; a = 255 - ((tmp + (tmp >> 8)) >> 8); c = ((src_alpha << 16) + (a >> 1)) / a; #ifdef WORDS_BIGENDIAN src_r = (src_rgba >> 24) & 0xff; src_g = (src_rgba >> 16) & 0xff; src_b = (src_rgba >> 8) & 0xff; dst_r = (dst_rgba >> 24) & 0xff; dst_g = (dst_rgba >> 16) & 0xff; dst_b = (dst_rgba >> 8) & 0xff; #else src_r = src_rgba & 0xff; src_g = (src_rgba >> 8) & 0xff; src_b = (src_rgba >> 16) & 0xff; dst_r = dst_rgba & 0xff; dst_g = (dst_rgba >> 8) & 0xff; dst_b = (dst_rgba >> 16) & 0xff; #endif r = dst_r + (((src_r - dst_r) * c + 0x8000) >> 16); g = dst_g + (((src_g - dst_g) * c + 0x8000) >> 16); b = dst_b + (((src_b - dst_b) * c + 0x8000) >> 16); #ifdef WORDS_BIGENDIAN ((unsigned int *)dst)[0] = (r << 24) | (g << 16) | (b << 8) | a; #else ((unsigned int *)dst)[0] = (a << 24) | (b << 16) | (g << 8) | r; #endif } } dst += dst_pixpitch; } src += src_pixpitch; } dst_buf += dst_rowpitch; } src_buf += src_rowpitch; } free (stx); free (sty); } void GFImageFill (GFImageRef dst_img, int red, int green, int blue, int alpha) { int dst_pixpitch, dst_rowpitch; unsigned char src_alpha = alpha, dst_alpha; unsigned int dst_rgba, src_rgba, i, n, c; void *dst_buf; dst_pixpitch = GFImagePixelStride (dst_img); dst_rowpitch = GFImageRowStride (dst_img); dst_buf = dst_img->pixels + (dst_rowpitch * (dst_img->y0)) + (dst_pixpitch * (dst_img->x0)); #ifdef WORDS_BIGENDIAN src_rgba = (red << 24) | (green << 16) | (blue << 8) | alpha; #else src_rgba = (alpha << 24) | (blue << 16) | (green << 8) | red; #endif for (n = 0; n < GFImageHeight (dst_img) / 2; n++) { for (i = 0; i < GFImageWidth (dst_img); i++) { #ifdef WORDS_BIGENDIAN dst_rgba = ((unsigned int *) dst_buf) [i]; dst_alpha = dst_rgba & 0xff; #else dst_rgba = ((unsigned int *) dst_buf) [i]; dst_alpha = dst_rgba >> 24; #endif if (alpha == 0xff || dst_alpha == 0) ((unsigned int *) dst_buf) [i] = src_rgba; else { int r, g, b, a; int src_r, src_g, src_b; int dst_r, dst_g, dst_b; int tmp; tmp = (255 - src_alpha) * (255 - dst_alpha) + 0x80; a = 255 - ((tmp + (tmp >> 8)) >> 8); c = ((src_alpha << 16) + (a >> 1)) / a; #ifdef WORDS_BIGENDIAN src_r = (src_rgba >> 24) & 0xff; src_g = (src_rgba >> 16) & 0xff; src_b = (src_rgba >> 8) & 0xff; dst_r = (dst_rgba >> 24) & 0xff; dst_g = (dst_rgba >> 16) & 0xff; dst_b = (dst_rgba >> 8) & 0xff; #else src_r = src_rgba & 0xff; src_g = (src_rgba >> 8) & 0xff; src_b = (src_rgba >> 16) & 0xff; dst_r = dst_rgba & 0xff; dst_g = (dst_rgba >> 8) & 0xff; dst_b = (dst_rgba >> 16) & 0xff; #endif r = dst_r + (((src_r - dst_r) * c + 0x8000) >> 16); g = dst_g + (((src_g - dst_g) * c + 0x8000) >> 16); b = dst_b + (((src_b - dst_b) * c + 0x8000) >> 16); #ifdef WORDS_BIGENDIAN ((unsigned int *)dst_buf)[i] = (r << 24) | (g << 16) | (b << 8) | a; #else ((unsigned int *)dst_buf)[i] = (a << 24) | (b << 16) | (g << 8) | r; #endif } } dst_buf += dst_rowpitch; } }