Fixed big memory leak in color panel code (patch from Pascal).
[wmaker-crm.git] / wrlib / raster.c
blob708797142c713da715d017f6f0dd15ea4fea2623
1 /* raster.c - main and other misc stuff
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1997 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;
39 RImage*
40 RCreateImage(unsigned width, unsigned height, int alpha)
42 RImage *image=NULL;
43 int i;
45 assert(width>0 && height>0);
47 image = malloc(sizeof(RImage));
48 if (!image) {
49 RErrorCode = RERR_NOMEMORY;
50 return NULL;
53 memset(image, 0, sizeof(RImage));
54 image->width = width;
55 image->height = height;
56 for (i=0; i<3+(alpha?1:0); i++) {
57 image->data[i] = malloc(width*height);
58 if (!image->data[i])
59 goto error;
61 return image;
63 error:
64 for (i=0; i<4; i++) {
65 if (image->data[i])
66 free(image->data[i]);
68 if (image)
69 free(image);
70 RErrorCode = RERR_NOMEMORY;
71 return NULL;
76 RImage*
77 RCloneImage(RImage *image)
79 RImage *new_image;
81 assert(image!=NULL);
83 new_image = RCreateImage(image->width, image->height, image->data[3]!=NULL);
84 if (!new_image)
85 return NULL;
87 new_image->background = image->background;
88 memcpy(new_image->data[0], image->data[0], image->width*image->height);
89 memcpy(new_image->data[1], image->data[1], image->width*image->height);
90 memcpy(new_image->data[2], image->data[2], image->width*image->height);
91 if (image->data[3])
92 memcpy(new_image->data[3], image->data[3], image->width*image->height);
94 return new_image;
98 RImage*
99 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
101 int i, ofs;
102 RImage *new_image;
103 unsigned char *sr, *sg, *sb, *sa;
104 unsigned char *dr, *dg, *db, *da;
106 assert(image!=NULL);
107 assert(x>=0 && y>=0);
108 assert(x<image->width && y<image->height);
109 assert(width>0 && height>0);
111 if (x+width > image->width)
112 width = image->width-x;
113 if (y+height > image->height)
114 height = image->height-y;
116 new_image = RCreateImage(width, height, image->data[3]!=NULL);
117 if (!new_image)
118 return NULL;
119 new_image->background = image->background;
120 ofs = image->width*y+x;
122 sr = image->data[0]+ofs;
123 sg = image->data[1]+ofs;
124 sb = image->data[2]+ofs;
125 sa = image->data[3]+ofs;
127 dr = new_image->data[0];
128 dg = new_image->data[1];
129 db = new_image->data[2];
130 da = new_image->data[3];
132 for (i=0; i<height; i++) {
133 memcpy(dr, sr, width);
134 memcpy(dg, sg, width);
135 memcpy(db, sb, width);
136 sr += image->width;
137 sg += image->width;
138 sb += image->width;
139 dr += width;
140 dg += width;
141 db += width;
142 if (da) {
143 memcpy(da, sa, width);
144 sa += image->width;
145 da += width;
148 return new_image;
152 void
153 RDestroyImage(RImage *image)
155 int i;
157 assert(image!=NULL);
159 for (i=0; i<4; i++) {
160 if (image->data[i])
161 free(image->data[i]);
163 free(image);
168 *----------------------------------------------------------------------
169 * RCombineImages-
170 * Combines two equal sized images with alpha image. The second
171 * image will be placed on top of the first one.
172 *----------------------------------------------------------------------
174 void
175 RCombineImages(RImage *image, RImage *src)
177 register int i;
178 unsigned char *dr, *dg, *db, *da;
179 unsigned char *sr, *sg, *sb, *sa;
180 int alpha, calpha;
183 assert(image->width == src->width);
184 assert(image->height == src->height);
186 dr = image->data[0];
187 dg = image->data[1];
188 db = image->data[2];
189 da = image->data[3];
191 sr = src->data[0];
192 sg = src->data[1];
193 sb = src->data[2];
194 sa = src->data[3];
196 if (!sa) {
197 memcpy(dr, sr, image->height*image->width);
198 memcpy(dg, sg, image->height*image->width);
199 memcpy(db, sb, image->height*image->width);
200 } else {
201 for (i=0; i<image->height*image->width; i++) {
202 alpha = *sa;
203 calpha = 255 - *sa;
204 *dr = (((int)*dr * calpha) + ((int)*sr * alpha))/256;
205 *dg = (((int)*dg * calpha) + ((int)*sg * alpha))/256;
206 *db = (((int)*db * calpha) + ((int)*sb * alpha))/256;
207 if (image->data[3])
208 *da++ |= *sa;
209 dr++; dg++; db++;
210 sr++; sg++; sb++;
211 sa++;
219 void
220 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
222 register int i;
223 unsigned char *dr, *dg, *db, *da;
224 unsigned char *sr, *sg, *sb, *sa;
225 int c_opaqueness;
228 assert(image->width == src->width);
229 assert(image->height == src->height);
231 dr = image->data[0];
232 dg = image->data[1];
233 db = image->data[2];
234 da = image->data[3];
236 sr = src->data[0];
237 sg = src->data[1];
238 sb = src->data[2];
239 sa = src->data[3];
241 c_opaqueness = 255 - opaqueness;
242 #define OP opaqueness
243 if (!src->data[3]) {
244 #define COP c_opaqueness
245 for (i=0; i<image->width*image->height; i++) {
246 *dr = (((int)*dr *(int)COP) + ((int)*sr *(int)OP))/256;
247 *dg = (((int)*dg *(int)COP) + ((int)*sg *(int)OP))/256;
248 *db = (((int)*db *(int)COP) + ((int)*sb *(int)OP))/256;
249 dr++; dg++; db++;
250 sr++; sg++; sb++;
252 #undef COP
253 } else {
254 int tmp;
256 if (image->data[3]) {
257 for (i=0; i<image->width*image->height; i++) {
258 tmp = (*sa * opaqueness)/256;
259 *dr = (((int)*dr * (255-tmp)) + ((int)*sr * tmp))/256;
260 *dg = (((int)*dg * (255-tmp)) + ((int)*sg * tmp))/256;
261 *db = (((int)*db * (255-tmp)) + ((int)*sb * tmp))/256;
262 *da |= tmp;
264 dr++; dg++; db++;
265 sr++; sg++; sb++;
266 sa++;
267 da++;
269 } else {
270 for (i=0; i<image->width*image->height; i++) {
271 tmp = (*sa * opaqueness)/256;
272 *dr = (((int)*dr * (255-tmp)) + ((int)*sr * tmp))/256;
273 *dg = (((int)*dg * (255-tmp)) + ((int)*sg * tmp))/256;
274 *db = (((int)*db * (255-tmp)) + ((int)*sb * tmp))/256;
276 dr++; dg++; db++;
277 sr++; sg++; sb++;
278 sa++;
282 #undef OP
286 void
287 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
288 unsigned height, int dx, int dy)
290 int x, y, dwi, swi;
291 unsigned char *dr, *dg, *db;
292 unsigned char *sr, *sg, *sb, *sa;
293 int alpha, calpha;
296 assert(dy < image->height);
297 assert(dx < image->width);
299 assert(sy + height <= src->height);
300 assert(sx + width <= src->width);
302 dr = image->data[0] + dy*(int)image->width + dx;
303 dg = image->data[1] + dy*(int)image->width + dx;
304 db = image->data[2] + dy*(int)image->width + dx;
306 sr = src->data[0] + sy*(int)src->width + sx;
307 sg = src->data[1] + sy*(int)src->width + sx;
308 sb = src->data[2] + sy*(int)src->width + sx;
309 sa = src->data[3] + sy*(int)src->width + sx;
311 swi = src->width - width;
312 dwi = image->width - width;
314 if (height > image->height - dy)
315 height = image->height - dy;
317 if (!src->data[3]) {
318 for (y=sy; y<height+sy; y++) {
319 for (x=sx; x<width+sx; x++) {
320 *(dr++) = *(sr++);
321 *(dg++) = *(sg++);
322 *(db++) = *(sb++);
324 dr += dwi; dg += dwi; db += dwi;
325 sr += swi; sg += swi; sb += swi;
327 } else {
328 for (y=sy; y<height+sy; y++) {
329 for (x=sx; x<width+sx; x++) {
330 alpha = *sa;
331 calpha = 255 - alpha;
332 *dr = (((int)*dr * calpha) + ((int)*sr * alpha))/256;
333 *dg = (((int)*dg * calpha) + ((int)*sg * alpha))/256;
334 *db = (((int)*db * calpha) + ((int)*sb * alpha))/256;
335 dr++; dg++; db++;
336 sr++; sg++; sb++;
337 sa++;
339 dr += dwi; dg += dwi; db += dwi;
340 sr += swi; sg += swi; sb += swi;
341 sa += swi;
347 void
348 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
349 unsigned width, unsigned height, int dx, int dy,
350 int opaqueness)
352 int x, y, dwi, swi;
353 int c_opaqueness;
354 unsigned char *dr, *dg, *db;
355 unsigned char *sr, *sg, *sb, *sa;
357 assert(dy <= image->height);
358 assert(dx <= image->width);
360 assert(sy <= height);
361 assert(sx <= width);
363 dr = image->data[0] + dy*image->width + dx;
364 dg = image->data[1] + dy*image->width + dx;
365 db = image->data[2] + dy*image->width + dx;
367 sr = src->data[0] + sy*src->width;
368 sg = src->data[1] + sy*src->width;
369 sb = src->data[2] + sy*src->width;
370 sa = src->data[3] + sy*src->width;
372 swi = src->width - width;
373 dwi = image->width - width;
375 /* clip */
376 width -= sx;
377 height -= sy;
379 if (height > image->height - dy)
380 height = image->height - dy;
382 c_opaqueness = 255 - opaqueness;
383 #define OP opaqueness
384 if (!src->data[3]) {
385 #define COP c_opaqueness
386 for (y=0; y<height; y++) {
387 for (x=0; x<width; x++) {
388 *dr = (((int)*dr *(int)COP) + ((int)*sr *(int)OP))/256;
389 *dg = (((int)*dg *(int)COP) + ((int)*sg *(int)OP))/256;
390 *db = (((int)*db *(int)COP) + ((int)*sb *(int)OP))/256;
391 dr++; dg++; db++;
392 sr++; sg++; sb++;
394 dr += dwi; dg += dwi; db += dwi;
395 sr += swi; sg += swi; sb += swi;
397 #undef COP
398 } else {
399 int tmp;
401 for (y=0; y<height; y++) {
402 for (x=0; x<width; x++) {
403 tmp= (*sa * opaqueness)/256;
404 *dr = (((int)*dr *(int)(255-tmp)) + ((int)*sr *(int)tmp))/256;
405 *dg = (((int)*dg *(int)(255-tmp)) + ((int)*sg *(int)tmp))/256;
406 *db = (((int)*db *(int)(255-tmp)) + ((int)*sb *(int)tmp))/256;
407 dr++; dg++; db++;
408 sr++; sg++; sb++;
409 sa++;
411 dr += dwi; dg += dwi; db += dwi;
412 sr += swi; sg += swi; sb += swi;
413 sa += swi;
416 #undef OP
422 void
423 RCombineImageWithColor(RImage *image, RColor *color)
425 register int i;
426 unsigned char *dr, *dg, *db, *da;
427 int alpha, nalpha, r, g, b;
429 dr = image->data[0];
430 dg = image->data[1];
431 db = image->data[2];
432 da = image->data[3];
434 if (!da) {
435 /* Image has no alpha channel, so we consider it to be all 255 */
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 = *da;
444 nalpha = 255 - alpha;
446 *dr = (((int)*dr * alpha) + (r * nalpha))/256;
447 *dg = (((int)*dg * alpha) + (g * nalpha))/256;
448 *db = (((int)*db * alpha) + (b * nalpha))/256;
449 dr++; dg++; db++; da++;
454 RImage*
455 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
457 int x, y;
458 unsigned w;
459 unsigned long tile_size = tile->width * tile->height;
460 unsigned long tx = 0;
461 int have_alpha = (tile->data[3]!=NULL);
462 RImage *image;
463 unsigned char *sr, *sg, *sb, *sa;
464 unsigned char *dr, *dg, *db, *da;
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 {
472 image = RCreateImage(width, height, have_alpha);
474 dr = image->data[0];
475 dg = image->data[1];
476 db = image->data[2];
477 da = image->data[3];
479 sr = tile->data[0];
480 sg = tile->data[1];
481 sb = tile->data[2];
482 sa = tile->data[3];
484 for (y = 0; y < height; y++) {
485 for (x = 0; x < width; x += tile->width) {
487 w = (width - x < tile->width) ? width - x : tile->width;
489 memcpy(dr, sr+tx, w);
490 memcpy(dg, sg+tx, w);
491 memcpy(db, sb+tx, w);
492 if (have_alpha) {
493 memcpy(da, sa+tx, w);
494 da += w;
497 dr += w;
498 dg += w;
499 db += w;
502 tx = (tx + tile->width) % tile_size;
505 return image;
509 RImage*
510 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
512 int x, y, w, h, sx, sy;
513 RImage *tmp;
515 tmp = RCreateImage(width, height, False);
516 if (!tmp) {
517 return NULL;
520 RClearImage(tmp, color);
522 if (image->height < height) {
523 h = image->height;
524 y = (height - h)/2;
525 sy = 0;
526 } else {
527 sy = (image->height - height)/2;
528 y = 0;
529 h = height;
531 if (image->width < width) {
532 w = image->width;
533 x = (width - w)/2;
534 sx = 0;
535 } else {
536 sx = (image->width - width)/2;
537 x = 0;
538 w = width;
540 RCombineArea(tmp, image, sx, sy, w, h, x, y);
542 return tmp;