Fixed crashes in 24 and 32bpp after introduction of hermeslib support
[wmaker-crm.git] / wrlib / raster.c
blob6c9432476a16ba9b768ad8dff031636d881392f2
1 /* raster.c - main and other misc stuff
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1997-2000 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <config.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <X11/Xlib.h>
28 #include "wraster.h"
30 #include <assert.h>
33 char *WRasterLibVersion="0.9";
35 int RErrorCode=RERR_NONE;
38 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
41 RImage*
42 RCreateImage(unsigned width, unsigned height, int alpha)
44 RImage *image=NULL;
46 assert(width>0 && height>0);
48 image = malloc(sizeof(RImage));
49 if (!image) {
50 RErrorCode = RERR_NOMEMORY;
51 return NULL;
54 memset(image, 0, sizeof(RImage));
55 image->width = width;
56 image->height = height;
57 image->format = alpha ? RRGBAFormat : RRGBFormat;
59 /* the +4 is to give extra bytes at the end of the buffer,
60 * so that we can optimize image conversion for MMX(tm).. see convert.c
62 image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
63 if (!image->data) {
64 RErrorCode = RERR_NOMEMORY;
65 free(image);
66 image = NULL;
69 return image;
74 RImage*
75 RCloneImage(RImage *image)
77 RImage *new_image;
79 assert(image!=NULL);
81 new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
82 if (!new_image)
83 return NULL;
85 new_image->background = image->background;
86 memcpy(new_image->data, image->data,
87 image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
89 return new_image;
93 RImage*
94 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
96 int i, ofs;
97 RImage *new_image;
98 unsigned total_line_size, line_size;
100 assert(image!=NULL);
101 assert(x>=0 && y>=0);
102 assert(x<image->width && y<image->height);
103 assert(width>0 && height>0);
105 if (x+width > image->width)
106 width = image->width-x;
107 if (y+height > image->height)
108 height = image->height-y;
110 new_image = RCreateImage(width, height, HAS_ALPHA(image));
112 if (!new_image)
113 return NULL;
114 new_image->background = image->background;
116 total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
117 line_size = width * (HAS_ALPHA(image) ? 4 : 3);
119 ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
121 for (i=0; i<height; i++) {
122 memcpy(&new_image->data[i*line_size],
123 &image->data[i*total_line_size+ofs], line_size);
125 return new_image;
129 void
130 RDestroyImage(RImage *image)
132 assert(image!=NULL);
134 free(image->data);
135 free(image);
140 *----------------------------------------------------------------------
141 * RCombineImages-
142 * Combines two equal sized images with alpha image. The second
143 * image will be placed on top of the first one.
144 *----------------------------------------------------------------------
146 void
147 RCombineImages(RImage *image, RImage *src)
149 assert(image->width == src->width);
150 assert(image->height == src->height);
152 if (!HAS_ALPHA(src)) {
153 if (!HAS_ALPHA(image)) {
154 memcpy(image->data, src->data, image->height*image->width*3);
155 } else {
156 int x, y;
157 unsigned char *d, *s;
159 d = image->data;
160 s = src->data;
161 for (y = 0; y < image->height; y++) {
162 for (x = 0; x < image->width; x++) {
163 *d++ = *s++;
164 *d++ = *s++;
165 *d++ = *s++;
166 d++;
170 } else {
171 register int i;
172 unsigned char *d;
173 unsigned char *s;
174 int alpha, calpha;
176 d = image->data;
177 s = src->data;
179 if (!HAS_ALPHA(image)) {
180 for (i=0; i<image->height*image->width; i++) {
181 alpha = *(s+3);
182 calpha = 255 - alpha;
183 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
184 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
185 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
186 s++;
188 } else {
189 for (i=0; i<image->height*image->width; i++) {
190 alpha = *(s+3);
191 calpha = 255 - alpha;
192 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
193 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
194 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
195 *d++ |= *s++;
204 void
205 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
207 register int i;
208 unsigned char *d;
209 unsigned char *s;
210 int c_opaqueness;
212 assert(image->width == src->width);
213 assert(image->height == src->height);
215 d = image->data;
216 s = src->data;
218 c_opaqueness = 255 - opaqueness;
220 #define OP opaqueness
221 #define COP c_opaqueness
223 if (!HAS_ALPHA(src)) {
224 int dalpha = HAS_ALPHA(image);
225 for (i=0; i < image->width*image->height; i++) {
226 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
227 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
228 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
229 if (dalpha) {
230 d++;
233 } else {
234 int tmp;
236 if (!HAS_ALPHA(image)) {
237 for (i=0; i<image->width*image->height; i++) {
238 tmp = (*(s+3) * opaqueness)/256;
239 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
240 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
241 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
242 s++;
244 } else {
245 for (i=0; i<image->width*image->height; i++) {
246 tmp = (*(s+3) * opaqueness)/256;
247 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
248 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
249 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
250 *d |= tmp;
251 d++; s++;
255 #undef OP
256 #undef COP
260 calculateCombineArea(RImage *des, RImage *src, int *sx, int *sy,
261 int *swidth, int *sheight, int *dx, int *dy)
263 if (*dx < 0) {
264 *sx = -*dx;
265 *swidth = *swidth + *dx;
266 *dx = 0;
269 if (*dx + *swidth > des->width) {
270 *swidth = des->width - *dx;
273 if (*dy < 0) {
274 *sy = -*dy;
275 *sheight = *sheight + *dy;
276 *dy = 0;
279 if (*dy + *sheight > des->height) {
280 *sheight = des->height - *dy;
283 if (*sheight > 0 && *swidth > 0) {
284 return True;
285 } else return False;
288 void
289 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
290 unsigned height, int dx, int dy)
292 int x, y, dwi, swi;
293 unsigned char *d;
294 unsigned char *s;
295 int alpha, calpha;
297 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
298 return;
300 if (!HAS_ALPHA(src)) {
301 if (!HAS_ALPHA(image)) {
302 swi = src->width * 3;
303 dwi = image->width * 3;
305 s = src->data + (sy*(int)src->width + sx) * 3;
306 d = image->data + (dy*(int)image->width + dx) * 3;
308 for (y=0; y < height; y++) {
309 memcpy(d, s, width*3);
310 d += dwi;
311 s += swi;
313 } else {
314 swi = (src->width - width) * 3;
315 dwi = (image->width - width) * 4;
317 s = src->data + (sy*(int)src->width + sx) * 3;
318 d = image->data + (dy*(int)image->width + dx) * 4;
320 for (y=0; y < height; y++) {
321 for (x=0; x < width; x++) {
322 *d++ = *s++;
323 *d++ = *s++;
324 *d++ = *s++;
325 d++;
327 d += dwi;
328 s += swi;
331 } else {
332 int dalpha = HAS_ALPHA(image);
334 swi = (src->width - width) * 4;
335 s = src->data + (sy*(int)src->width + sx) * 4;
336 if (dalpha) {
337 dwi = (image->width - width) * 4;
338 d = image->data + (dy*(int)image->width + dx) * 4;
339 } else {
340 dwi = (image->width - width) * 3;
341 d = image->data + (dy*(int)image->width + dx) * 3;
344 for (y=0; y < height; y++) {
345 for (x=0; x < width; x++) {
346 alpha = *(s+3);
347 calpha = 255 - alpha;
348 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
349 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
350 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
351 s++;
352 if (dalpha)
353 d++;
355 d += dwi;
356 s += swi;
362 void
363 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
364 unsigned width, unsigned height, int dx, int dy,
365 int opaqueness)
367 int x, y, dwi, swi;
368 int c_opaqueness;
369 unsigned char *s, *d;
370 int dalpha = HAS_ALPHA(image);
371 int dch = (dalpha ? 4 : 3);
373 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
374 return;
376 d = image->data + (dy*image->width + dx) * dch;
377 dwi = (image->width - width)*dch;
379 c_opaqueness = 255 - opaqueness;
381 #define OP opaqueness
382 #define COP c_opaqueness
384 if (!HAS_ALPHA(src)) {
386 s = src->data + sy*src->width*3;
387 swi = (src->width - width) * 3;
389 for (y=0; y < height; y++) {
390 for (x=0; x < width; x++) {
391 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
392 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
393 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
394 if (dalpha)
395 d++;
397 d += dwi; s += swi;
399 } else {
400 int tmp;
402 s = src->data + sy*src->width*4;
403 swi = (src->width - width) * 4;
405 for (y=0; y < height; y++) {
406 for (x=0; x < width; x++) {
407 tmp = (*(s+3) * opaqueness)/256;
408 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
409 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
410 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
411 s++;
412 if (dalpha)
413 d++;
415 d += dwi; s += swi;
418 #undef OP
419 #undef COP
424 void
425 RCombineImageWithColor(RImage *image, RColor *color)
427 register int i;
428 unsigned char *d;
429 int alpha, nalpha, r, g, b;
431 d = image->data;
433 if (!HAS_ALPHA(image)) {
434 /* Image has no alpha channel, so we consider it to be all 255.
435 * Thus there are no transparent parts to be filled. */
436 return;
438 r = color->red;
439 g = color->green;
440 b = color->blue;
442 for (i=0; i < image->width*image->height; i++) {
443 alpha = *(d+3);
444 nalpha = 255 - alpha;
446 *d = (((int)*d * alpha) + (r * nalpha))/256; d++;
447 *d = (((int)*d * alpha) + (g * nalpha))/256; d++;
448 *d = (((int)*d * alpha) + (b * nalpha))/256; d++;
449 d++;
456 RImage*
457 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
459 int x, y;
460 unsigned w;
461 unsigned long tile_size = tile->width * tile->height;
462 unsigned long tx = 0;
463 RImage *image;
464 unsigned char *s, *d;
466 if (width == tile->width && height == tile->height)
467 image = RCloneImage(tile);
468 else if (width <= tile->width && height <= tile->height)
469 image = RGetSubImage(tile, 0, 0, width, height);
470 else {
471 int has_alpha = HAS_ALPHA(tile);
473 image = RCreateImage(width, height, has_alpha);
475 d = image->data;
476 s = tile->data;
478 for (y = 0; y < height; y++) {
479 for (x = 0; x < width; x += tile->width) {
481 w = (width - x < tile->width) ? width - x : tile->width;
483 if (has_alpha) {
484 w *= 4;
485 memcpy(d, s+tx*4, w);
486 } else {
487 w *= 3;
488 memcpy(d, s+tx*3, w);
490 d += w;
493 tx = (tx + tile->width) % tile_size;
496 return image;
500 RImage*
501 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
503 int x, y, w, h, sx, sy;
504 RImage *tmp;
506 tmp = RCreateImage(width, height, False);
507 if (!tmp) {
508 return NULL;
511 RClearImage(tmp, color);
513 if (image->height < height) {
514 h = image->height;
515 y = (height - h)/2;
516 sy = 0;
517 } else {
518 sy = (image->height - height)/2;
519 y = 0;
520 h = height;
522 if (image->width < width) {
523 w = image->width;
524 x = (width - w)/2;
525 sx = 0;
526 } else {
527 sx = (image->width - width)/2;
528 x = 0;
529 w = width;
531 RCombineArea(tmp, image, sx, sy, w, h, x, y);
533 return tmp;