argh! buffer overflow fix, try 3 :P
[wmaker-crm.git] / wrlib / raster.c
blob0cfd2a9fe2e4901d330dfab7d6853387766ff79f
1 /* raster.c - main and other misc stuff
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1997-2002 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 <limits.h>
28 #include <X11/Xlib.h>
29 #include "wraster.h"
31 #include <assert.h>
34 char *WRasterLibVersion="0.9";
36 int RErrorCode=RERR_NONE;
39 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
42 RImage*
43 RCreateImage(unsigned width, unsigned height, int alpha)
45 RImage *image=NULL;
46 unsigned bla1, bla2;
48 assert(width>0 && height>0);
50 /* detect overflow (gr33tz to ruda :D) */
51 bla1 = width*height;
52 if (bla1 / height != width) {
53 RErrorCode = RERR_NOMEMORY;
54 return NULL;
57 bla2 = bla1*4;
58 if (bla2/4 != bla1) {
59 RErrorCode = RERR_NOMEMORY;
60 return NULL;
63 if (bla2 > INT_MAX - 4) {
64 RErrorCode = RERR_NOMEMORY;
65 return NULL;
68 image = malloc(sizeof(RImage));
69 if (!image) {
70 RErrorCode = RERR_NOMEMORY;
71 return NULL;
74 memset(image, 0, sizeof(RImage));
75 image->width = width;
76 image->height = height;
77 image->format = alpha ? RRGBAFormat : RRGBFormat;
78 image->refCount = 1;
80 /* the +4 is to give extra bytes at the end of the buffer,
81 * so that we can optimize image conversion for MMX(tm).. see convert.c
83 image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
84 if (!image->data) {
85 RErrorCode = RERR_NOMEMORY;
86 free(image);
87 image = NULL;
90 return image;
95 RImage*
96 RRetainImage(RImage *image)
98 if (image)
99 image->refCount++;
101 return image;
105 void
106 RReleaseImage(RImage *image)
108 assert(image!=NULL);
110 image->refCount--;
112 if (image->refCount < 1) {
113 free(image->data);
114 free(image);
119 RImage*
120 RCloneImage(RImage *image)
122 RImage *new_image;
124 assert(image!=NULL);
126 new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
127 if (!new_image)
128 return NULL;
130 new_image->background = image->background;
131 memcpy(new_image->data, image->data,
132 image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
134 return new_image;
138 RImage*
139 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
141 int i, ofs;
142 RImage *new_image;
143 unsigned total_line_size, line_size;
145 assert(image!=NULL);
146 assert(x>=0 && y>=0);
147 assert(x<image->width && y<image->height);
148 assert(width>0 && height>0);
150 if (x+width > image->width)
151 width = image->width-x;
152 if (y+height > image->height)
153 height = image->height-y;
155 new_image = RCreateImage(width, height, HAS_ALPHA(image));
157 if (!new_image)
158 return NULL;
159 new_image->background = image->background;
161 total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
162 line_size = width * (HAS_ALPHA(image) ? 4 : 3);
164 ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
166 for (i=0; i<height; i++) {
167 memcpy(&new_image->data[i*line_size],
168 &image->data[i*total_line_size+ofs], line_size);
170 return new_image;
175 *----------------------------------------------------------------------
176 * RCombineImages-
177 * Combines two equal sized images with alpha image. The second
178 * image will be placed on top of the first one.
179 *----------------------------------------------------------------------
181 void
182 RCombineImages(RImage *image, RImage *src)
184 assert(image->width == src->width);
185 assert(image->height == src->height);
187 if (!HAS_ALPHA(src)) {
188 if (!HAS_ALPHA(image)) {
189 memcpy(image->data, src->data, image->height*image->width*3);
190 } else {
191 int x, y;
192 unsigned char *d, *s;
194 d = image->data;
195 s = src->data;
196 for (y = 0; y < image->height; y++) {
197 for (x = 0; x < image->width; x++) {
198 *d++ = *s++;
199 *d++ = *s++;
200 *d++ = *s++;
201 d++;
205 } else {
206 register int i;
207 unsigned char *d;
208 unsigned char *s;
209 int alpha, calpha;
211 d = image->data;
212 s = src->data;
214 if (!HAS_ALPHA(image)) {
215 for (i=0; i<image->height*image->width; i++) {
216 alpha = *(s+3);
217 calpha = 255 - alpha;
218 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
219 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
220 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
221 s++;
223 } else {
224 for (i=0; i<image->height*image->width; i++) {
225 alpha = *(s+3);
226 calpha = 255 - alpha;
227 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
228 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
229 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
230 *d++ |= *s++;
239 void
240 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
242 register int i;
243 unsigned char *d;
244 unsigned char *s;
245 int c_opaqueness;
247 assert(image->width == src->width);
248 assert(image->height == src->height);
250 d = image->data;
251 s = src->data;
253 c_opaqueness = 255 - opaqueness;
255 #define OP opaqueness
256 #define COP c_opaqueness
258 if (!HAS_ALPHA(src)) {
259 int dalpha = HAS_ALPHA(image);
260 for (i=0; i < image->width*image->height; i++) {
261 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
262 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
263 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
264 if (dalpha) {
265 d++;
268 } else {
269 int tmp;
271 if (!HAS_ALPHA(image)) {
272 for (i=0; i<image->width*image->height; i++) {
273 tmp = (*(s+3) * opaqueness)/256;
274 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
275 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
276 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
277 s++;
279 } else {
280 for (i=0; i<image->width*image->height; i++) {
281 tmp = (*(s+3) * opaqueness)/256;
282 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
283 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
284 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
285 *d |= tmp;
286 d++; s++;
290 #undef OP
291 #undef COP
295 calculateCombineArea(RImage *des, RImage *src, int *sx, int *sy,
296 int *swidth, int *sheight, int *dx, int *dy)
298 if (*dx < 0) {
299 *sx = -*dx;
300 *swidth = *swidth + *dx;
301 *dx = 0;
304 if (*dx + *swidth > des->width) {
305 *swidth = des->width - *dx;
308 if (*dy < 0) {
309 *sy = -*dy;
310 *sheight = *sheight + *dy;
311 *dy = 0;
314 if (*dy + *sheight > des->height) {
315 *sheight = des->height - *dy;
318 if (*sheight > 0 && *swidth > 0) {
319 return True;
320 } else return False;
323 void
324 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
325 unsigned height, int dx, int dy)
327 int x, y, dwi, swi;
328 unsigned char *d;
329 unsigned char *s;
330 int alpha, calpha;
332 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
333 return;
335 if (!HAS_ALPHA(src)) {
336 if (!HAS_ALPHA(image)) {
337 swi = src->width * 3;
338 dwi = image->width * 3;
340 s = src->data + (sy*(int)src->width + sx) * 3;
341 d = image->data + (dy*(int)image->width + dx) * 3;
343 for (y=0; y < height; y++) {
344 memcpy(d, s, width*3);
345 d += dwi;
346 s += swi;
348 } else {
349 swi = (src->width - width) * 3;
350 dwi = (image->width - width) * 4;
352 s = src->data + (sy*(int)src->width + sx) * 3;
353 d = image->data + (dy*(int)image->width + dx) * 4;
355 for (y=0; y < height; y++) {
356 for (x=0; x < width; x++) {
357 *d++ = *s++;
358 *d++ = *s++;
359 *d++ = *s++;
360 d++;
362 d += dwi;
363 s += swi;
366 } else {
367 int dalpha = HAS_ALPHA(image);
369 swi = (src->width - width) * 4;
370 s = src->data + (sy*(int)src->width + sx) * 4;
371 if (dalpha) {
372 dwi = (image->width - width) * 4;
373 d = image->data + (dy*(int)image->width + dx) * 4;
374 } else {
375 dwi = (image->width - width) * 3;
376 d = image->data + (dy*(int)image->width + dx) * 3;
379 for (y=0; y < height; y++) {
380 for (x=0; x < width; x++) {
381 alpha = *(s+3);
382 calpha = 255 - alpha;
383 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
384 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
385 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
386 s++;
387 if (dalpha)
388 d++;
390 d += dwi;
391 s += swi;
397 void
398 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
399 unsigned width, unsigned height, int dx, int dy,
400 int opaqueness)
402 int x, y, dwi, swi;
403 int c_opaqueness;
404 unsigned char *s, *d;
405 int dalpha = HAS_ALPHA(image);
406 int dch = (dalpha ? 4 : 3);
408 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
409 return;
411 d = image->data + (dy*image->width + dx) * dch;
412 dwi = (image->width - width)*dch;
414 c_opaqueness = 255 - opaqueness;
416 #define OP opaqueness
417 #define COP c_opaqueness
419 if (!HAS_ALPHA(src)) {
421 s = src->data + (sy*src->width + sx)*3;
422 swi = (src->width - width) * 3;
424 for (y=0; y < height; y++) {
425 for (x=0; x < width; x++) {
426 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
427 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
428 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
429 if (dalpha)
430 d++;
432 d += dwi; s += swi;
434 } else {
435 int tmp;
437 s = src->data + (sy*src->width + sx)*4;
438 swi = (src->width - width) * 4;
440 for (y=0; y < height; y++) {
441 for (x=0; x < width; x++) {
442 tmp = (*(s+3) * opaqueness)/256;
443 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
444 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
445 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
446 s++;
447 if (dalpha)
448 d++;
450 d += dwi; s += swi;
453 #undef OP
454 #undef COP
459 void
460 RCombineImageWithColor(RImage *image, RColor *color)
462 register int i;
463 unsigned char *d;
464 int alpha, nalpha, r, g, b;
466 d = image->data;
468 if (!HAS_ALPHA(image)) {
469 /* Image has no alpha channel, so we consider it to be all 255.
470 * Thus there are no transparent parts to be filled. */
471 return;
473 r = color->red;
474 g = color->green;
475 b = color->blue;
477 for (i=0; i < image->width*image->height; i++) {
478 alpha = *(d+3);
479 nalpha = 255 - alpha;
481 *d = (((int)*d * alpha) + (r * nalpha))/256; d++;
482 *d = (((int)*d * alpha) + (g * nalpha))/256; d++;
483 *d = (((int)*d * alpha) + (b * nalpha))/256; d++;
484 d++;
491 RImage*
492 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
494 int x, y;
495 unsigned w;
496 unsigned long tile_size = tile->width * tile->height;
497 unsigned long tx = 0;
498 RImage *image;
499 unsigned char *s, *d;
501 if (width == tile->width && height == tile->height)
502 image = RCloneImage(tile);
503 else if (width <= tile->width && height <= tile->height)
504 image = RGetSubImage(tile, 0, 0, width, height);
505 else {
506 int has_alpha = HAS_ALPHA(tile);
508 image = RCreateImage(width, height, has_alpha);
510 d = image->data;
511 s = tile->data;
513 for (y = 0; y < height; y++) {
514 for (x = 0; x < width; x += tile->width) {
516 w = (width - x < tile->width) ? width - x : tile->width;
518 if (has_alpha) {
519 w *= 4;
520 memcpy(d, s+tx*4, w);
521 } else {
522 w *= 3;
523 memcpy(d, s+tx*3, w);
525 d += w;
528 tx = (tx + tile->width) % tile_size;
531 return image;
535 RImage*
536 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
538 int x, y, w, h, sx, sy;
539 RImage *tmp;
541 tmp = RCreateImage(width, height, False);
542 if (!tmp) {
543 return NULL;
546 RClearImage(tmp, color);
548 if (image->height < height) {
549 h = image->height;
550 y = (height - h)/2;
551 sy = 0;
552 } else {
553 sy = (image->height - height)/2;
554 y = 0;
555 h = height;
557 if (image->width < width) {
558 w = image->width;
559 x = (width - w)/2;
560 sx = 0;
561 } else {
562 sx = (image->width - width)/2;
563 x = 0;
564 w = width;
566 RCombineArea(tmp, image, sx, sy, w, h, x, y);
568 return tmp;