Initial revision
[wmaker-crm.git] / wrlib / raster.c
blob9fbad280f3d678d48a749a301d0fe9091fc11558
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>
32 #define MAXERRLEN 512
35 char *WRasterLibVersion="0.2";
37 char RErrorString[MAXERRLEN];
41 RImage*
42 RCreateImage(unsigned width, unsigned height, int alpha)
44 RImage *image=NULL;
45 int i;
47 assert(width>0 && height>0);
49 image = malloc(sizeof(RImage));
50 if (!image) {
51 sprintf(RErrorString, "out of memory");
52 return NULL;
55 memset(image, 0, sizeof(RImage));
56 image->width = width;
57 image->height = height;
58 for (i=0; i<3+(alpha?1:0); i++) {
59 image->data[i] = malloc(width*height);
60 if (!image->data[i])
61 goto error;
63 return image;
65 error:
66 for (i=0; i<4; i++) {
67 if (image->data[i])
68 free(image->data[i]);
70 if (image)
71 free(image);
72 sprintf(RErrorString, "out of memory");
73 return NULL;
78 RImage*
79 RCloneImage(RImage *image)
81 RImage *new_image;
83 assert(image!=NULL);
85 new_image = RCreateImage(image->width, image->height, image->data[3]!=NULL);
86 if (!new_image)
87 return NULL;
89 new_image->background = image->background;
90 memcpy(new_image->data[0], image->data[0], image->width*image->height);
91 memcpy(new_image->data[1], image->data[1], image->width*image->height);
92 memcpy(new_image->data[2], image->data[2], image->width*image->height);
93 if (image->data[3])
94 memcpy(new_image->data[3], image->data[3], image->width*image->height);
96 return new_image;
100 RImage*
101 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
103 int i, ofs;
104 RImage *new_image;
105 unsigned char *sr, *sg, *sb, *sa;
106 unsigned char *dr, *dg, *db, *da;
108 assert(image!=NULL);
109 assert(x>=0 && y>=0);
110 assert(x<image->width && y<image->height);
111 assert(width>0 && height>0);
113 if (x+width > image->width)
114 width = image->width-x;
115 if (y+height > image->height)
116 height = image->height-y;
118 new_image = RCreateImage(width, height, image->data[3]!=NULL);
119 if (!new_image)
120 return NULL;
121 new_image->background = image->background;
122 ofs = image->width*y+x;
124 sr = image->data[0]+ofs;
125 sg = image->data[1]+ofs;
126 sb = image->data[2]+ofs;
127 sa = image->data[3]+ofs;
129 dr = new_image->data[0];
130 dg = new_image->data[1];
131 db = new_image->data[2];
132 da = new_image->data[3];
134 for (i=0; i<height; i++) {
135 memcpy(dr, sr, width);
136 memcpy(dg, sg, width);
137 memcpy(db, sb, width);
138 sr += image->width;
139 sg += image->width;
140 sb += image->width;
141 dr += width;
142 dg += width;
143 db += width;
144 if (da) {
145 memcpy(da, sa, width);
146 sa += image->width;
147 da += width;
150 return new_image;
154 void
155 RDestroyImage(RImage *image)
157 int i;
159 assert(image!=NULL);
161 for (i=0; i<4; i++) {
162 if (image->data[i])
163 free(image->data[i]);
165 free(image);
170 *----------------------------------------------------------------------
171 * RCombineImages-
172 * Combines two equal sized images with alpha image. The second
173 * image will be placed on top of the first one.
174 *----------------------------------------------------------------------
176 void
177 RCombineImages(RImage *image, RImage *src)
179 register int i;
180 unsigned char *dr, *dg, *db, *da;
181 unsigned char *sr, *sg, *sb, *sa;
182 int alpha, calpha;
185 assert(image->width == src->width);
186 assert(image->height == src->height);
188 dr = image->data[0];
189 dg = image->data[1];
190 db = image->data[2];
191 da = image->data[3];
193 sr = src->data[0];
194 sg = src->data[1];
195 sb = src->data[2];
196 sa = src->data[3];
198 if (!sa) {
199 memcpy(dr, sr, image->height*image->width);
200 memcpy(dg, sg, image->height*image->width);
201 memcpy(db, sb, image->height*image->width);
202 } else {
203 for (i=0; i<image->height*image->width; i++) {
204 alpha = *sa;
205 calpha = 255 - *sa;
206 *dr = (((int)*dr * calpha) + ((int)*sr * alpha))/256;
207 *dg = (((int)*dg * calpha) + ((int)*sg * alpha))/256;
208 *db = (((int)*db * calpha) + ((int)*sb * alpha))/256;
209 if (image->data[3])
210 *da |= *sa;
211 dr++; dg++; db++;
212 sr++; sg++; sb++;
213 sa++;
214 da++;
222 void
223 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
225 register int i;
226 unsigned char *dr, *dg, *db;
227 unsigned char *sr, *sg, *sb, *sa;
228 int c_opaqueness;
231 assert(image->width == src->width);
232 assert(image->height == src->height);
234 dr = image->data[0];
235 dg = image->data[1];
236 db = image->data[2];
238 sr = src->data[0];
239 sg = src->data[1];
240 sb = src->data[2];
241 sa = src->data[3];
243 c_opaqueness = 255 - opaqueness;
244 #define OP opaqueness
245 if (!src->data[3]) {
246 #define COP c_opaqueness
247 for (i=0; i<image->width*image->height; i++) {
248 *dr = (((int)*dr *(int)COP) + ((int)*sr *(int)OP))/256;
249 *dg = (((int)*dg *(int)COP) + ((int)*sg *(int)OP))/256;
250 *db = (((int)*db *(int)COP) + ((int)*sb *(int)OP))/256;
251 dr++; dg++; db++;
252 sr++; sg++; sb++;
254 #undef COP
255 } else {
256 int tmp;
258 for (i=0; i<image->width*image->height; i++) {
259 tmp= (*sa * opaqueness)/256;
260 *dr = (((int)*dr *(int)(255-tmp)) + ((int)*sr *(int)tmp))/256;
261 *dg = (((int)*dg *(int)(255-tmp)) + ((int)*sg *(int)tmp))/256;
262 *db = (((int)*db *(int)(255-tmp)) + ((int)*sb *(int)tmp))/256;
263 dr++; dg++; db++;
264 sr++; sg++; sb++;
265 sa++;
268 #undef OP
272 void
273 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
274 unsigned height, int dx, int dy)
276 int x, y, dwi, swi;
277 unsigned char *dr, *dg, *db;
278 unsigned char *sr, *sg, *sb, *sa;
279 int alpha, calpha;
282 assert(dy < image->height);
283 assert(dx < image->width);
285 assert(sy + height <= src->height);
286 assert(sx + width <= src->width);
288 dr = image->data[0] + dy*(int)image->width + dx;
289 dg = image->data[1] + dy*(int)image->width + dx;
290 db = image->data[2] + dy*(int)image->width + dx;
292 sr = src->data[0] + sy*(int)src->width + sx;
293 sg = src->data[1] + sy*(int)src->width + sx;
294 sb = src->data[2] + sy*(int)src->width + sx;
295 sa = src->data[3] + sy*(int)src->width + sx;
297 swi = src->width - width;
298 dwi = image->width - width;
300 if (height > image->height - dy)
301 height = image->height - dy;
303 if (!src->data[3]) {
304 for (y=sy; y<height+sy; y++) {
305 for (x=sx; x<width+sx; x++) {
306 *(dr++) = *(sr++);
307 *(dg++) = *(sg++);
308 *(db++) = *(sb++);
310 dr += dwi; dg += dwi; db += dwi;
311 sr += swi; sg += swi; sb += swi;
313 } else {
314 for (y=sy; y<height+sy; y++) {
315 for (x=sx; x<width+sx; x++) {
316 alpha = *sa;
317 calpha = 255 - alpha;
318 *dr = (((int)*dr * calpha) + ((int)*sr * alpha))/256;
319 *dg = (((int)*dg * calpha) + ((int)*sg * alpha))/256;
320 *db = (((int)*db * calpha) + ((int)*sb * alpha))/256;
321 dr++; dg++; db++;
322 sr++; sg++; sb++;
323 sa++;
325 dr += dwi; dg += dwi; db += dwi;
326 sr += swi; sg += swi; sb += swi;
327 sa += swi;
333 void
334 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
335 unsigned width, unsigned height, int dx, int dy,
336 int opaqueness)
338 int x, y, dwi, swi;
339 int c_opaqueness;
340 unsigned char *dr, *dg, *db;
341 unsigned char *sr, *sg, *sb, *sa;
343 assert(dy <= image->height);
344 assert(dx <= image->width);
346 assert(sy <= height);
347 assert(sx <= width);
349 dr = image->data[0] + dy*image->width + dx;
350 dg = image->data[1] + dy*image->width + dx;
351 db = image->data[2] + dy*image->width + dx;
353 sr = src->data[0] + sy*src->width;
354 sg = src->data[1] + sy*src->width;
355 sb = src->data[2] + sy*src->width;
356 sa = src->data[3] + sy*src->width;
358 swi = src->width - width;
359 dwi = image->width - width;
361 /* clip */
362 width -= sx;
363 height -= sy;
365 if (height > image->height - dy)
366 height = image->height - dy;
368 c_opaqueness = 255 - opaqueness;
369 #define OP opaqueness
370 if (!src->data[3]) {
371 #define COP c_opaqueness
372 for (y=0; y<height; y++) {
373 for (x=0; x<width; x++) {
374 *dr = (((int)*dr *(int)COP) + ((int)*sr *(int)OP))/256;
375 *dg = (((int)*dg *(int)COP) + ((int)*sg *(int)OP))/256;
376 *db = (((int)*db *(int)COP) + ((int)*sb *(int)OP))/256;
377 dr++; dg++; db++;
378 sr++; sg++; sb++;
380 dr += dwi; dg += dwi; db += dwi;
381 sr += swi; sg += swi; sb += swi;
383 #undef COP
384 } else {
385 int tmp;
387 for (y=0; y<height; y++) {
388 for (x=0; x<width; x++) {
389 tmp= (*sa * opaqueness)/256;
390 *dr = (((int)*dr *(int)(255-tmp)) + ((int)*sr *(int)tmp))/256;
391 *dg = (((int)*dg *(int)(255-tmp)) + ((int)*sg *(int)tmp))/256;
392 *db = (((int)*db *(int)(255-tmp)) + ((int)*sb *(int)tmp))/256;
393 dr++; dg++; db++;
394 sr++; sg++; sb++;
395 sa++;
397 dr += dwi; dg += dwi; db += dwi;
398 sr += swi; sg += swi; sb += swi;
399 sa += swi;
402 #undef OP
408 void
409 RCombineImageWithColor(RImage *image, RColor *color)
411 register int i;
412 unsigned char *dr, *dg, *db, *da;
413 int alpha, nalpha, r, g, b;
415 dr = image->data[0];
416 dg = image->data[1];
417 db = image->data[2];
418 da = image->data[3];
420 if (!da) {
421 /* Image has no alpha channel, so we consider it to be all 255 */
422 return;
424 r = color->red;
425 g = color->green;
426 b = color->blue;
428 for (i=0; i<image->width*image->height; i++) {
429 alpha = *da;
430 nalpha = 255 - alpha;
432 *dr = (((int)*dr * alpha) + (r * nalpha))/256;
433 *dg = (((int)*dg * alpha) + (g * nalpha))/256;
434 *db = (((int)*db * alpha) + (b * nalpha))/256;
435 dr++; dg++; db++; da++;
440 RImage*
441 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
443 int x, y;
444 unsigned w;
445 unsigned long tile_size = tile->width * tile->height;
446 unsigned long tx = 0;
447 int have_alpha = (tile->data[3]!=NULL);
448 RImage *image;
449 unsigned char *sr, *sg, *sb, *sa;
450 unsigned char *dr, *dg, *db, *da;
452 if (width == tile->width && height == tile->height)
453 image = RCloneImage(tile);
454 else if (width <= tile->width && height <= tile->height)
455 image = RGetSubImage(tile, 0, 0, width, height);
456 else {
458 image = RCreateImage(width, height, have_alpha);
460 dr = image->data[0];
461 dg = image->data[1];
462 db = image->data[2];
463 da = image->data[3];
465 sr = tile->data[0];
466 sg = tile->data[1];
467 sb = tile->data[2];
468 sa = tile->data[3];
470 for (y = 0; y < height; y++) {
471 for (x = 0; x < width; x += tile->width) {
473 w = (width - x < tile->width) ? width - x : tile->width;
475 memcpy(dr, sr+tx, w);
476 memcpy(dg, sg+tx, w);
477 memcpy(db, sb+tx, w);
478 if (have_alpha) {
479 memcpy(da, sa+tx, w);
480 da += w;
483 dr += w;
484 dg += w;
485 db += w;
488 tx = (tx + tile->width) % tile_size;
491 return image;
495 RImage*
496 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
498 int x, y, w, h, sx, sy;
499 RImage *tmp;
501 tmp = RCreateImage(width, height, False);
502 if (!tmp) {
503 return NULL;
506 RClearImage(tmp, color);
508 if (image->height < height) {
509 h = image->height;
510 y = (height - h)/2;
511 sy = 0;
512 } else {
513 sy = (image->height - height)/2;
514 y = 0;
515 h = height;
517 if (image->width < width) {
518 w = image->width;
519 x = (width - w)/2;
520 sx = 0;
521 } else {
522 sx = (image->width - width)/2;
523 x = 0;
524 w = width;
526 RCombineArea(tmp, image, sx, sy, w, h, x, y);
528 return tmp;