fixed buffer overrun bug in wrlib when creating or loading images
[wmaker-crm.git] / wrlib / raster.c
blobbb885c8012a8790d6058cd5f4292f972628f3631
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;
47 assert(width>0 && height>0);
49 /* check for too large images (cap on INT_MAX just to be sure :P) */
50 if (width > (INT_MAX/4)/height+4) {
51 RErrorCode = RERR_NOMEMORY;
52 return NULL;
55 image = malloc(sizeof(RImage));
56 if (!image) {
57 RErrorCode = RERR_NOMEMORY;
58 return NULL;
61 memset(image, 0, sizeof(RImage));
62 image->width = width;
63 image->height = height;
64 image->format = alpha ? RRGBAFormat : RRGBFormat;
65 image->refCount = 1;
67 /* the +4 is to give extra bytes at the end of the buffer,
68 * so that we can optimize image conversion for MMX(tm).. see convert.c
70 image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
71 if (!image->data) {
72 RErrorCode = RERR_NOMEMORY;
73 free(image);
74 image = NULL;
77 return image;
81 RImage*
82 RRetainImage(RImage *image)
84 if (image)
85 image->refCount++;
87 return image;
91 void
92 RReleaseImage(RImage *image)
94 assert(image!=NULL);
96 image->refCount--;
98 if (image->refCount < 1) {
99 free(image->data);
100 free(image);
105 RImage*
106 RCloneImage(RImage *image)
108 RImage *new_image;
110 assert(image!=NULL);
112 new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
113 if (!new_image)
114 return NULL;
116 new_image->background = image->background;
117 memcpy(new_image->data, image->data,
118 image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
120 return new_image;
124 RImage*
125 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
127 int i, ofs;
128 RImage *new_image;
129 unsigned total_line_size, line_size;
131 assert(image!=NULL);
132 assert(x>=0 && y>=0);
133 assert(x<image->width && y<image->height);
134 assert(width>0 && height>0);
136 if (x+width > image->width)
137 width = image->width-x;
138 if (y+height > image->height)
139 height = image->height-y;
141 new_image = RCreateImage(width, height, HAS_ALPHA(image));
143 if (!new_image)
144 return NULL;
145 new_image->background = image->background;
147 total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
148 line_size = width * (HAS_ALPHA(image) ? 4 : 3);
150 ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
152 for (i=0; i<height; i++) {
153 memcpy(&new_image->data[i*line_size],
154 &image->data[i*total_line_size+ofs], line_size);
156 return new_image;
161 *----------------------------------------------------------------------
162 * RCombineImages-
163 * Combines two equal sized images with alpha image. The second
164 * image will be placed on top of the first one.
165 *----------------------------------------------------------------------
167 void
168 RCombineImages(RImage *image, RImage *src)
170 assert(image->width == src->width);
171 assert(image->height == src->height);
173 if (!HAS_ALPHA(src)) {
174 if (!HAS_ALPHA(image)) {
175 memcpy(image->data, src->data, image->height*image->width*3);
176 } else {
177 int x, y;
178 unsigned char *d, *s;
180 d = image->data;
181 s = src->data;
182 for (y = 0; y < image->height; y++) {
183 for (x = 0; x < image->width; x++) {
184 *d++ = *s++;
185 *d++ = *s++;
186 *d++ = *s++;
187 d++;
191 } else {
192 register int i;
193 unsigned char *d;
194 unsigned char *s;
195 int alpha, calpha;
197 d = image->data;
198 s = src->data;
200 if (!HAS_ALPHA(image)) {
201 for (i=0; i<image->height*image->width; i++) {
202 alpha = *(s+3);
203 calpha = 255 - alpha;
204 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
205 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
206 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
207 s++;
209 } else {
210 for (i=0; i<image->height*image->width; i++) {
211 alpha = *(s+3);
212 calpha = 255 - alpha;
213 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
214 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
215 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
216 *d++ |= *s++;
225 void
226 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
228 register int i;
229 unsigned char *d;
230 unsigned char *s;
231 int c_opaqueness;
233 assert(image->width == src->width);
234 assert(image->height == src->height);
236 d = image->data;
237 s = src->data;
239 c_opaqueness = 255 - opaqueness;
241 #define OP opaqueness
242 #define COP c_opaqueness
244 if (!HAS_ALPHA(src)) {
245 int dalpha = HAS_ALPHA(image);
246 for (i=0; i < image->width*image->height; i++) {
247 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
248 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
249 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
250 if (dalpha) {
251 d++;
254 } else {
255 int tmp;
257 if (!HAS_ALPHA(image)) {
258 for (i=0; i<image->width*image->height; i++) {
259 tmp = (*(s+3) * opaqueness)/256;
260 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
261 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
262 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
263 s++;
265 } else {
266 for (i=0; i<image->width*image->height; i++) {
267 tmp = (*(s+3) * opaqueness)/256;
268 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
269 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
270 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
271 *d |= tmp;
272 d++; s++;
276 #undef OP
277 #undef COP
281 calculateCombineArea(RImage *des, RImage *src, int *sx, int *sy,
282 int *swidth, int *sheight, int *dx, int *dy)
284 if (*dx < 0) {
285 *sx = -*dx;
286 *swidth = *swidth + *dx;
287 *dx = 0;
290 if (*dx + *swidth > des->width) {
291 *swidth = des->width - *dx;
294 if (*dy < 0) {
295 *sy = -*dy;
296 *sheight = *sheight + *dy;
297 *dy = 0;
300 if (*dy + *sheight > des->height) {
301 *sheight = des->height - *dy;
304 if (*sheight > 0 && *swidth > 0) {
305 return True;
306 } else return False;
309 void
310 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
311 unsigned height, int dx, int dy)
313 int x, y, dwi, swi;
314 unsigned char *d;
315 unsigned char *s;
316 int alpha, calpha;
318 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
319 return;
321 if (!HAS_ALPHA(src)) {
322 if (!HAS_ALPHA(image)) {
323 swi = src->width * 3;
324 dwi = image->width * 3;
326 s = src->data + (sy*(int)src->width + sx) * 3;
327 d = image->data + (dy*(int)image->width + dx) * 3;
329 for (y=0; y < height; y++) {
330 memcpy(d, s, width*3);
331 d += dwi;
332 s += swi;
334 } else {
335 swi = (src->width - width) * 3;
336 dwi = (image->width - width) * 4;
338 s = src->data + (sy*(int)src->width + sx) * 3;
339 d = image->data + (dy*(int)image->width + dx) * 4;
341 for (y=0; y < height; y++) {
342 for (x=0; x < width; x++) {
343 *d++ = *s++;
344 *d++ = *s++;
345 *d++ = *s++;
346 d++;
348 d += dwi;
349 s += swi;
352 } else {
353 int dalpha = HAS_ALPHA(image);
355 swi = (src->width - width) * 4;
356 s = src->data + (sy*(int)src->width + sx) * 4;
357 if (dalpha) {
358 dwi = (image->width - width) * 4;
359 d = image->data + (dy*(int)image->width + dx) * 4;
360 } else {
361 dwi = (image->width - width) * 3;
362 d = image->data + (dy*(int)image->width + dx) * 3;
365 for (y=0; y < height; y++) {
366 for (x=0; x < width; x++) {
367 alpha = *(s+3);
368 calpha = 255 - alpha;
369 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
370 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
371 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
372 s++;
373 if (dalpha)
374 d++;
376 d += dwi;
377 s += swi;
383 void
384 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
385 unsigned width, unsigned height, int dx, int dy,
386 int opaqueness)
388 int x, y, dwi, swi;
389 int c_opaqueness;
390 unsigned char *s, *d;
391 int dalpha = HAS_ALPHA(image);
392 int dch = (dalpha ? 4 : 3);
394 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
395 return;
397 d = image->data + (dy*image->width + dx) * dch;
398 dwi = (image->width - width)*dch;
400 c_opaqueness = 255 - opaqueness;
402 #define OP opaqueness
403 #define COP c_opaqueness
405 if (!HAS_ALPHA(src)) {
407 s = src->data + (sy*src->width + sx)*3;
408 swi = (src->width - width) * 3;
410 for (y=0; y < height; y++) {
411 for (x=0; x < width; x++) {
412 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
413 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
414 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
415 if (dalpha)
416 d++;
418 d += dwi; s += swi;
420 } else {
421 int tmp;
423 s = src->data + (sy*src->width + sx)*4;
424 swi = (src->width - width) * 4;
426 for (y=0; y < height; y++) {
427 for (x=0; x < width; x++) {
428 tmp = (*(s+3) * opaqueness)/256;
429 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
430 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
431 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
432 s++;
433 if (dalpha)
434 d++;
436 d += dwi; s += swi;
439 #undef OP
440 #undef COP
445 void
446 RCombineImageWithColor(RImage *image, RColor *color)
448 register int i;
449 unsigned char *d;
450 int alpha, nalpha, r, g, b;
452 d = image->data;
454 if (!HAS_ALPHA(image)) {
455 /* Image has no alpha channel, so we consider it to be all 255.
456 * Thus there are no transparent parts to be filled. */
457 return;
459 r = color->red;
460 g = color->green;
461 b = color->blue;
463 for (i=0; i < image->width*image->height; i++) {
464 alpha = *(d+3);
465 nalpha = 255 - alpha;
467 *d = (((int)*d * alpha) + (r * nalpha))/256; d++;
468 *d = (((int)*d * alpha) + (g * nalpha))/256; d++;
469 *d = (((int)*d * alpha) + (b * nalpha))/256; d++;
470 d++;
477 RImage*
478 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
480 int x, y;
481 unsigned w;
482 unsigned long tile_size = tile->width * tile->height;
483 unsigned long tx = 0;
484 RImage *image;
485 unsigned char *s, *d;
487 if (width == tile->width && height == tile->height)
488 image = RCloneImage(tile);
489 else if (width <= tile->width && height <= tile->height)
490 image = RGetSubImage(tile, 0, 0, width, height);
491 else {
492 int has_alpha = HAS_ALPHA(tile);
494 image = RCreateImage(width, height, has_alpha);
496 d = image->data;
497 s = tile->data;
499 for (y = 0; y < height; y++) {
500 for (x = 0; x < width; x += tile->width) {
502 w = (width - x < tile->width) ? width - x : tile->width;
504 if (has_alpha) {
505 w *= 4;
506 memcpy(d, s+tx*4, w);
507 } else {
508 w *= 3;
509 memcpy(d, s+tx*3, w);
511 d += w;
514 tx = (tx + tile->width) % tile_size;
517 return image;
521 RImage*
522 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
524 int x, y, w, h, sx, sy;
525 RImage *tmp;
527 tmp = RCreateImage(width, height, False);
528 if (!tmp) {
529 return NULL;
532 RClearImage(tmp, color);
534 if (image->height < height) {
535 h = image->height;
536 y = (height - h)/2;
537 sy = 0;
538 } else {
539 sy = (image->height - height)/2;
540 y = 0;
541 h = height;
543 if (image->width < width) {
544 w = image->width;
545 x = (width - w)/2;
546 sx = 0;
547 } else {
548 sx = (image->width - width)/2;
549 x = 0;
550 w = width;
552 RCombineArea(tmp, image, sx, sy, w, h, x, y);
554 return tmp;