- Fixed text in info panel for multibyte (Seiichi SATO <ssato@sh.rim.or.jp>)
[wmaker-crm.git] / wrlib / raster.c
bloba6340d1a800c5dbb4de6f373ad8e38db1a3c455f
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 <X11/Xlib.h>
28 #include "wraster.h"
30 #include <assert.h>
33 char *WRasterLibVersion="0.9";
35 int RErrorCode=RERR_NONE;
38 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
41 RImage*
42 RCreateImage(unsigned width, unsigned height, int alpha)
44 RImage *image=NULL;
46 assert(width>0 && height>0);
48 image = malloc(sizeof(RImage));
49 if (!image) {
50 RErrorCode = RERR_NOMEMORY;
51 return NULL;
54 memset(image, 0, sizeof(RImage));
55 image->width = width;
56 image->height = height;
57 image->format = alpha ? RRGBAFormat : RRGBFormat;
58 image->refCount = 1;
60 /* the +4 is to give extra bytes at the end of the buffer,
61 * so that we can optimize image conversion for MMX(tm).. see convert.c
63 image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
64 if (!image->data) {
65 RErrorCode = RERR_NOMEMORY;
66 free(image);
67 image = NULL;
70 return image;
74 RImage*
75 RRetainImage(RImage *image)
77 if (image)
78 image->refCount++;
80 return image;
84 void
85 RReleaseImage(RImage *image)
87 assert(image!=NULL);
89 image->refCount--;
91 if (image->refCount < 1) {
92 free(image->data);
93 free(image);
98 /* Obsoleted function. Use RReleaseImage() instead. This was kept only to
99 * allow a smoother transition and to avoid breaking existing programs, but
100 * it will be removed in a future release. Right now is just an alias to
101 * RReleaseImage(). Do _NOT_ use RDestroyImage() anymore in your programs.
102 * Being an alias to RReleaseImage() this function no longer actually
103 * destroys the image, unless the image is no longer retained in some other
104 * place.
106 void
107 RDestroyImage(RImage *image)
109 RReleaseImage(image);
113 RImage*
114 RCloneImage(RImage *image)
116 RImage *new_image;
118 assert(image!=NULL);
120 new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
121 if (!new_image)
122 return NULL;
124 new_image->background = image->background;
125 memcpy(new_image->data, image->data,
126 image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
128 return new_image;
132 RImage*
133 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
135 int i, ofs;
136 RImage *new_image;
137 unsigned total_line_size, line_size;
139 assert(image!=NULL);
140 assert(x>=0 && y>=0);
141 assert(x<image->width && y<image->height);
142 assert(width>0 && height>0);
144 if (x+width > image->width)
145 width = image->width-x;
146 if (y+height > image->height)
147 height = image->height-y;
149 new_image = RCreateImage(width, height, HAS_ALPHA(image));
151 if (!new_image)
152 return NULL;
153 new_image->background = image->background;
155 total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
156 line_size = width * (HAS_ALPHA(image) ? 4 : 3);
158 ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
160 for (i=0; i<height; i++) {
161 memcpy(&new_image->data[i*line_size],
162 &image->data[i*total_line_size+ofs], line_size);
164 return new_image;
169 *----------------------------------------------------------------------
170 * RCombineImages-
171 * Combines two equal sized images with alpha image. The second
172 * image will be placed on top of the first one.
173 *----------------------------------------------------------------------
175 void
176 RCombineImages(RImage *image, RImage *src)
178 assert(image->width == src->width);
179 assert(image->height == src->height);
181 if (!HAS_ALPHA(src)) {
182 if (!HAS_ALPHA(image)) {
183 memcpy(image->data, src->data, image->height*image->width*3);
184 } else {
185 int x, y;
186 unsigned char *d, *s;
188 d = image->data;
189 s = src->data;
190 for (y = 0; y < image->height; y++) {
191 for (x = 0; x < image->width; x++) {
192 *d++ = *s++;
193 *d++ = *s++;
194 *d++ = *s++;
195 d++;
199 } else {
200 register int i;
201 unsigned char *d;
202 unsigned char *s;
203 int alpha, calpha;
205 d = image->data;
206 s = src->data;
208 if (!HAS_ALPHA(image)) {
209 for (i=0; i<image->height*image->width; i++) {
210 alpha = *(s+3);
211 calpha = 255 - alpha;
212 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
213 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
214 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
215 s++;
217 } else {
218 for (i=0; i<image->height*image->width; i++) {
219 alpha = *(s+3);
220 calpha = 255 - alpha;
221 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
222 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
223 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; d++; s++;
224 *d++ |= *s++;
233 void
234 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
236 register int i;
237 unsigned char *d;
238 unsigned char *s;
239 int c_opaqueness;
241 assert(image->width == src->width);
242 assert(image->height == src->height);
244 d = image->data;
245 s = src->data;
247 c_opaqueness = 255 - opaqueness;
249 #define OP opaqueness
250 #define COP c_opaqueness
252 if (!HAS_ALPHA(src)) {
253 int dalpha = HAS_ALPHA(image);
254 for (i=0; i < image->width*image->height; i++) {
255 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
256 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
257 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; d++; s++;
258 if (dalpha) {
259 d++;
262 } else {
263 int tmp;
265 if (!HAS_ALPHA(image)) {
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 s++;
273 } else {
274 for (i=0; i<image->width*image->height; i++) {
275 tmp = (*(s+3) * opaqueness)/256;
276 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
277 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
278 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
279 *d |= tmp;
280 d++; s++;
284 #undef OP
285 #undef COP
289 calculateCombineArea(RImage *des, RImage *src, int *sx, int *sy,
290 int *swidth, int *sheight, int *dx, int *dy)
292 if (*dx < 0) {
293 *sx = -*dx;
294 *swidth = *swidth + *dx;
295 *dx = 0;
298 if (*dx + *swidth > des->width) {
299 *swidth = des->width - *dx;
302 if (*dy < 0) {
303 *sy = -*dy;
304 *sheight = *sheight + *dy;
305 *dy = 0;
308 if (*dy + *sheight > des->height) {
309 *sheight = des->height - *dy;
312 if (*sheight > 0 && *swidth > 0) {
313 return True;
314 } else return False;
317 void
318 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
319 unsigned height, int dx, int dy)
321 int x, y, dwi, swi;
322 unsigned char *d;
323 unsigned char *s;
324 int alpha, calpha;
326 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
327 return;
329 if (!HAS_ALPHA(src)) {
330 if (!HAS_ALPHA(image)) {
331 swi = src->width * 3;
332 dwi = image->width * 3;
334 s = src->data + (sy*(int)src->width + sx) * 3;
335 d = image->data + (dy*(int)image->width + dx) * 3;
337 for (y=0; y < height; y++) {
338 memcpy(d, s, width*3);
339 d += dwi;
340 s += swi;
342 } else {
343 swi = (src->width - width) * 3;
344 dwi = (image->width - width) * 4;
346 s = src->data + (sy*(int)src->width + sx) * 3;
347 d = image->data + (dy*(int)image->width + dx) * 4;
349 for (y=0; y < height; y++) {
350 for (x=0; x < width; x++) {
351 *d++ = *s++;
352 *d++ = *s++;
353 *d++ = *s++;
354 d++;
356 d += dwi;
357 s += swi;
360 } else {
361 int dalpha = HAS_ALPHA(image);
363 swi = (src->width - width) * 4;
364 s = src->data + (sy*(int)src->width + sx) * 4;
365 if (dalpha) {
366 dwi = (image->width - width) * 4;
367 d = image->data + (dy*(int)image->width + dx) * 4;
368 } else {
369 dwi = (image->width - width) * 3;
370 d = image->data + (dy*(int)image->width + dx) * 3;
373 for (y=0; y < height; y++) {
374 for (x=0; x < width; x++) {
375 alpha = *(s+3);
376 calpha = 255 - alpha;
377 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
378 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
379 *d = (((int)*d * calpha) + ((int)*s * alpha))/256; s++; d++;
380 s++;
381 if (dalpha)
382 d++;
384 d += dwi;
385 s += swi;
391 void
392 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
393 unsigned width, unsigned height, int dx, int dy,
394 int opaqueness)
396 int x, y, dwi, swi;
397 int c_opaqueness;
398 unsigned char *s, *d;
399 int dalpha = HAS_ALPHA(image);
400 int dch = (dalpha ? 4 : 3);
402 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
403 return;
405 d = image->data + (dy*image->width + dx) * dch;
406 dwi = (image->width - width)*dch;
408 c_opaqueness = 255 - opaqueness;
410 #define OP opaqueness
411 #define COP c_opaqueness
413 if (!HAS_ALPHA(src)) {
415 s = src->data + (sy*src->width + sx)*3;
416 swi = (src->width - width) * 3;
418 for (y=0; y < height; y++) {
419 for (x=0; x < width; x++) {
420 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
421 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
422 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; s++; d++;
423 if (dalpha)
424 d++;
426 d += dwi; s += swi;
428 } else {
429 int tmp;
431 s = src->data + (sy*src->width + sx)*4;
432 swi = (src->width - width) * 4;
434 for (y=0; y < height; y++) {
435 for (x=0; x < width; x++) {
436 tmp = (*(s+3) * opaqueness)/256;
437 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
438 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
439 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; d++; s++;
440 s++;
441 if (dalpha)
442 d++;
444 d += dwi; s += swi;
447 #undef OP
448 #undef COP
453 void
454 RCombineImageWithColor(RImage *image, RColor *color)
456 register int i;
457 unsigned char *d;
458 int alpha, nalpha, r, g, b;
460 d = image->data;
462 if (!HAS_ALPHA(image)) {
463 /* Image has no alpha channel, so we consider it to be all 255.
464 * Thus there are no transparent parts to be filled. */
465 return;
467 r = color->red;
468 g = color->green;
469 b = color->blue;
471 for (i=0; i < image->width*image->height; i++) {
472 alpha = *(d+3);
473 nalpha = 255 - alpha;
475 *d = (((int)*d * alpha) + (r * nalpha))/256; d++;
476 *d = (((int)*d * alpha) + (g * nalpha))/256; d++;
477 *d = (((int)*d * alpha) + (b * nalpha))/256; d++;
478 d++;
485 RImage*
486 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
488 int x, y;
489 unsigned w;
490 unsigned long tile_size = tile->width * tile->height;
491 unsigned long tx = 0;
492 RImage *image;
493 unsigned char *s, *d;
495 if (width == tile->width && height == tile->height)
496 image = RCloneImage(tile);
497 else if (width <= tile->width && height <= tile->height)
498 image = RGetSubImage(tile, 0, 0, width, height);
499 else {
500 int has_alpha = HAS_ALPHA(tile);
502 image = RCreateImage(width, height, has_alpha);
504 d = image->data;
505 s = tile->data;
507 for (y = 0; y < height; y++) {
508 for (x = 0; x < width; x += tile->width) {
510 w = (width - x < tile->width) ? width - x : tile->width;
512 if (has_alpha) {
513 w *= 4;
514 memcpy(d, s+tx*4, w);
515 } else {
516 w *= 3;
517 memcpy(d, s+tx*3, w);
519 d += w;
522 tx = (tx + tile->width) % tile_size;
525 return image;
529 RImage*
530 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
532 int x, y, w, h, sx, sy;
533 RImage *tmp;
535 tmp = RCreateImage(width, height, False);
536 if (!tmp) {
537 return NULL;
540 RClearImage(tmp, color);
542 if (image->height < height) {
543 h = image->height;
544 y = (height - h)/2;
545 sy = 0;
546 } else {
547 sy = (image->height - height)/2;
548 y = 0;
549 h = height;
551 if (image->width < width) {
552 w = image->width;
553 x = (width - w)/2;
554 sx = 0;
555 } else {
556 sx = (image->width - width)/2;
557 x = 0;
558 w = width;
560 RCombineArea(tmp, image, sx, sy, w, h, x, y);
562 return tmp;