fix overflow bug, try2
[wmaker-crm.git] / wrlib / raster.c
blob2048bdf9cc4c239451aa7509ff4863baaf56ad90
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 bla2 = bla1*4;
53 if (bla1/height != width || bla2/4 != bla1 || bla2 > INT_MAX-32) {
54 RErrorCode = RERR_NOMEMORY;
55 return NULL;
58 image = malloc(sizeof(RImage));
59 if (!image) {
60 RErrorCode = RERR_NOMEMORY;
61 return NULL;
64 memset(image, 0, sizeof(RImage));
65 image->width = width;
66 image->height = height;
67 image->format = alpha ? RRGBAFormat : RRGBFormat;
68 image->refCount = 1;
70 /* the +4 is to give extra bytes at the end of the buffer,
71 * so that we can optimize image conversion for MMX(tm).. see convert.c
73 image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
74 if (!image->data) {
75 RErrorCode = RERR_NOMEMORY;
76 free(image);
77 image = NULL;
80 return image;
84 RImage*
85 RRetainImage(RImage *image)
87 if (image)
88 image->refCount++;
90 return image;
94 void
95 RReleaseImage(RImage *image)
97 assert(image!=NULL);
99 image->refCount--;
101 if (image->refCount < 1) {
102 free(image->data);
103 free(image);
108 RImage*
109 RCloneImage(RImage *image)
111 RImage *new_image;
113 assert(image!=NULL);
115 new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
116 if (!new_image)
117 return NULL;
119 new_image->background = image->background;
120 memcpy(new_image->data, image->data,
121 image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
123 return new_image;
127 RImage*
128 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
130 int i, ofs;
131 RImage *new_image;
132 unsigned total_line_size, line_size;
134 assert(image!=NULL);
135 assert(x>=0 && y>=0);
136 assert(x<image->width && y<image->height);
137 assert(width>0 && height>0);
139 if (x+width > image->width)
140 width = image->width-x;
141 if (y+height > image->height)
142 height = image->height-y;
144 new_image = RCreateImage(width, height, HAS_ALPHA(image));
146 if (!new_image)
147 return NULL;
148 new_image->background = image->background;
150 total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
151 line_size = width * (HAS_ALPHA(image) ? 4 : 3);
153 ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
155 for (i=0; i<height; i++) {
156 memcpy(&new_image->data[i*line_size],
157 &image->data[i*total_line_size+ofs], line_size);
159 return new_image;
164 *----------------------------------------------------------------------
165 * RCombineImages-
166 * Combines two equal sized images with alpha image. The second
167 * image will be placed on top of the first one.
168 *----------------------------------------------------------------------
170 void
171 RCombineImages(RImage *image, RImage *src)
173 assert(image->width == src->width);
174 assert(image->height == src->height);
176 if (!HAS_ALPHA(src)) {
177 if (!HAS_ALPHA(image)) {
178 memcpy(image->data, src->data, image->height*image->width*3);
179 } else {
180 int x, y;
181 unsigned char *d, *s;
183 d = image->data;
184 s = src->data;
185 for (y = 0; y < image->height; y++) {
186 for (x = 0; x < image->width; x++) {
187 *d++ = *s++;
188 *d++ = *s++;
189 *d++ = *s++;
190 d++;
194 } else {
195 register int i;
196 unsigned char *d;
197 unsigned char *s;
198 int alpha, calpha;
200 d = image->data;
201 s = src->data;
203 if (!HAS_ALPHA(image)) {
204 for (i=0; i<image->height*image->width; i++) {
205 alpha = *(s+3);
206 calpha = 255 - alpha;
207 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
208 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
209 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
210 s++;
212 } else {
213 for (i=0; i<image->height*image->width; i++) {
214 alpha = *(s+3);
215 calpha = 255 - alpha;
216 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
217 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
218 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
219 *d++ |= *s++;
228 void
229 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
231 register int i;
232 unsigned char *d;
233 unsigned char *s;
234 int c_opaqueness;
236 assert(image->width == src->width);
237 assert(image->height == src->height);
239 d = image->data;
240 s = src->data;
242 c_opaqueness = 255 - opaqueness;
244 #define OP opaqueness
245 #define COP c_opaqueness
247 if (!HAS_ALPHA(src)) {
248 int dalpha = HAS_ALPHA(image);
249 for (i=0; i < image->width*image->height; i++) {
250 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
251 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
252 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
253 if (dalpha) {
254 d++;
257 } else {
258 int tmp;
260 if (!HAS_ALPHA(image)) {
261 for (i=0; i<image->width*image->height; i++) {
262 tmp = (*(s+3) * opaqueness)/256;
263 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
264 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
265 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
266 s++;
268 } else {
269 for (i=0; i<image->width*image->height; i++) {
270 tmp = (*(s+3) * opaqueness)/256;
271 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
272 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
273 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
274 *d |= tmp;
275 d++; s++;
279 #undef OP
280 #undef COP
284 calculateCombineArea(RImage *des, RImage *src, int *sx, int *sy,
285 int *swidth, int *sheight, int *dx, int *dy)
287 if (*dx < 0) {
288 *sx = -*dx;
289 *swidth = *swidth + *dx;
290 *dx = 0;
293 if (*dx + *swidth > des->width) {
294 *swidth = des->width - *dx;
297 if (*dy < 0) {
298 *sy = -*dy;
299 *sheight = *sheight + *dy;
300 *dy = 0;
303 if (*dy + *sheight > des->height) {
304 *sheight = des->height - *dy;
307 if (*sheight > 0 && *swidth > 0) {
308 return True;
309 } else return False;
312 void
313 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
314 unsigned height, int dx, int dy)
316 int x, y, dwi, swi;
317 unsigned char *d;
318 unsigned char *s;
319 int alpha, calpha;
321 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
322 return;
324 if (!HAS_ALPHA(src)) {
325 if (!HAS_ALPHA(image)) {
326 swi = src->width * 3;
327 dwi = image->width * 3;
329 s = src->data + (sy*(int)src->width + sx) * 3;
330 d = image->data + (dy*(int)image->width + dx) * 3;
332 for (y=0; y < height; y++) {
333 memcpy(d, s, width*3);
334 d += dwi;
335 s += swi;
337 } else {
338 swi = (src->width - width) * 3;
339 dwi = (image->width - width) * 4;
341 s = src->data + (sy*(int)src->width + sx) * 3;
342 d = image->data + (dy*(int)image->width + dx) * 4;
344 for (y=0; y < height; y++) {
345 for (x=0; x < width; x++) {
346 *d++ = *s++;
347 *d++ = *s++;
348 *d++ = *s++;
349 d++;
351 d += dwi;
352 s += swi;
355 } else {
356 int dalpha = HAS_ALPHA(image);
358 swi = (src->width - width) * 4;
359 s = src->data + (sy*(int)src->width + sx) * 4;
360 if (dalpha) {
361 dwi = (image->width - width) * 4;
362 d = image->data + (dy*(int)image->width + dx) * 4;
363 } else {
364 dwi = (image->width - width) * 3;
365 d = image->data + (dy*(int)image->width + dx) * 3;
368 for (y=0; y < height; y++) {
369 for (x=0; x < width; x++) {
370 alpha = *(s+3);
371 calpha = 255 - alpha;
372 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
373 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
374 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
375 s++;
376 if (dalpha)
377 d++;
379 d += dwi;
380 s += swi;
386 void
387 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
388 unsigned width, unsigned height, int dx, int dy,
389 int opaqueness)
391 int x, y, dwi, swi;
392 int c_opaqueness;
393 unsigned char *s, *d;
394 int dalpha = HAS_ALPHA(image);
395 int dch = (dalpha ? 4 : 3);
397 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
398 return;
400 d = image->data + (dy*image->width + dx) * dch;
401 dwi = (image->width - width)*dch;
403 c_opaqueness = 255 - opaqueness;
405 #define OP opaqueness
406 #define COP c_opaqueness
408 if (!HAS_ALPHA(src)) {
410 s = src->data + (sy*src->width + sx)*3;
411 swi = (src->width - width) * 3;
413 for (y=0; y < height; y++) {
414 for (x=0; x < width; x++) {
415 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
416 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
417 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
418 if (dalpha)
419 d++;
421 d += dwi; s += swi;
423 } else {
424 int tmp;
426 s = src->data + (sy*src->width + sx)*4;
427 swi = (src->width - width) * 4;
429 for (y=0; y < height; y++) {
430 for (x=0; x < width; x++) {
431 tmp = (*(s+3) * opaqueness)/256;
432 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
433 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
434 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
435 s++;
436 if (dalpha)
437 d++;
439 d += dwi; s += swi;
442 #undef OP
443 #undef COP
448 void
449 RCombineImageWithColor(RImage *image, RColor *color)
451 register int i;
452 unsigned char *d;
453 int alpha, nalpha, r, g, b;
455 d = image->data;
457 if (!HAS_ALPHA(image)) {
458 /* Image has no alpha channel, so we consider it to be all 255.
459 * Thus there are no transparent parts to be filled. */
460 return;
462 r = color->red;
463 g = color->green;
464 b = color->blue;
466 for (i=0; i < image->width*image->height; i++) {
467 alpha = *(d+3);
468 nalpha = 255 - alpha;
470 *d = (((int)*d * alpha) + (r * nalpha))/256; d++;
471 *d = (((int)*d * alpha) + (g * nalpha))/256; d++;
472 *d = (((int)*d * alpha) + (b * nalpha))/256; d++;
473 d++;
480 RImage*
481 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
483 int x, y;
484 unsigned w;
485 unsigned long tile_size = tile->width * tile->height;
486 unsigned long tx = 0;
487 RImage *image;
488 unsigned char *s, *d;
490 if (width == tile->width && height == tile->height)
491 image = RCloneImage(tile);
492 else if (width <= tile->width && height <= tile->height)
493 image = RGetSubImage(tile, 0, 0, width, height);
494 else {
495 int has_alpha = HAS_ALPHA(tile);
497 image = RCreateImage(width, height, has_alpha);
499 d = image->data;
500 s = tile->data;
502 for (y = 0; y < height; y++) {
503 for (x = 0; x < width; x += tile->width) {
505 w = (width - x < tile->width) ? width - x : tile->width;
507 if (has_alpha) {
508 w *= 4;
509 memcpy(d, s+tx*4, w);
510 } else {
511 w *= 3;
512 memcpy(d, s+tx*3, w);
514 d += w;
517 tx = (tx + tile->width) % tile_size;
520 return image;
524 RImage*
525 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
527 int x, y, w, h, sx, sy;
528 RImage *tmp;
530 tmp = RCreateImage(width, height, False);
531 if (!tmp) {
532 return NULL;
535 RClearImage(tmp, color);
537 if (image->height < height) {
538 h = image->height;
539 y = (height - h)/2;
540 sy = 0;
541 } else {
542 sy = (image->height - height)/2;
543 y = 0;
544 h = height;
546 if (image->width < width) {
547 w = image->width;
548 x = (width - w)/2;
549 sx = 0;
550 } else {
551 sx = (image->width - width)/2;
552 x = 0;
553 w = width;
555 RCombineArea(tmp, image, sx, sy, w, h, x, y);
557 return tmp;