1 /* raster.c - main and other misc stuff
3 * Raster graphics library
5 * Copyright (c) 1997-2003 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.
33 char *WRasterLibVersion
="0.9";
35 int RErrorCode
=RERR_NONE
;
38 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
41 #define MAX_WIDTH 20000
42 #define MAX_HEIGHT 20000
47 RCreateImage(unsigned width
, unsigned height
, int alpha
)
51 assert(width
>0 && height
>0);
53 if (width
> MAX_WIDTH
|| height
> MAX_HEIGHT
) {
54 RErrorCode
= RERR_NOMEMORY
;
58 image
= malloc(sizeof(RImage
));
60 RErrorCode
= RERR_NOMEMORY
;
64 memset(image
, 0, sizeof(RImage
));
66 image
->height
= height
;
67 image
->format
= alpha
? RRGBAFormat
: RRGBFormat
;
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);
75 RErrorCode
= RERR_NOMEMORY
;
86 RRetainImage(RImage
*image
)
96 RReleaseImage(RImage
*image
)
102 if (image
->refCount
< 1) {
110 RCloneImage(RImage
*image
)
116 new_image
= RCreateImage(image
->width
, image
->height
, HAS_ALPHA(image
));
120 new_image
->background
= image
->background
;
121 memcpy(new_image
->data
, image
->data
,
122 image
->width
*image
->height
*(HAS_ALPHA(image
) ? 4 : 3));
129 RGetSubImage(RImage
*image
, int x
, int y
, unsigned width
, unsigned height
)
133 unsigned total_line_size
, line_size
;
136 assert(x
>=0 && y
>=0);
137 assert(x
<image
->width
&& y
<image
->height
);
138 assert(width
>0 && height
>0);
140 if (x
+width
> image
->width
)
141 width
= image
->width
-x
;
142 if (y
+height
> image
->height
)
143 height
= image
->height
-y
;
145 new_image
= RCreateImage(width
, height
, HAS_ALPHA(image
));
149 new_image
->background
= image
->background
;
151 total_line_size
= image
->width
* (HAS_ALPHA(image
) ? 4 : 3);
152 line_size
= width
* (HAS_ALPHA(image
) ? 4 : 3);
154 ofs
= x
*(HAS_ALPHA(image
) ? 4 : 3) + y
*total_line_size
;;
156 for (i
=0; i
<height
; i
++) {
157 memcpy(&new_image
->data
[i
*line_size
],
158 &image
->data
[i
*total_line_size
+ofs
], line_size
);
165 *----------------------------------------------------------------------
167 * Combines two equal sized images with alpha image. The second
168 * image will be placed on top of the first one.
169 *----------------------------------------------------------------------
172 RCombineImages(RImage
*image
, RImage
*src
)
174 assert(image
->width
== src
->width
);
175 assert(image
->height
== src
->height
);
177 if (!HAS_ALPHA(src
)) {
178 if (!HAS_ALPHA(image
)) {
179 memcpy(image
->data
, src
->data
, image
->height
*image
->width
*3);
182 unsigned char *d
, *s
;
186 for (y
= 0; y
< image
->height
; y
++) {
187 for (x
= 0; x
< image
->width
; x
++) {
204 if (!HAS_ALPHA(image
)) {
205 for (i
=0; i
<image
->height
*image
->width
; i
++) {
207 calpha
= 255 - alpha
;
208 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; d
++; s
++;
209 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; d
++; s
++;
210 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; d
++; s
++;
214 for (i
=0; i
<image
->height
*image
->width
; i
++) {
216 calpha
= 255 - alpha
;
217 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; d
++; s
++;
218 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; d
++; s
++;
219 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; d
++; s
++;
230 RCombineImagesWithOpaqueness(RImage
*image
, RImage
*src
, int opaqueness
)
237 assert(image
->width
== src
->width
);
238 assert(image
->height
== src
->height
);
243 c_opaqueness
= 255 - opaqueness
;
245 #define OP opaqueness
246 #define COP c_opaqueness
248 if (!HAS_ALPHA(src
)) {
249 int dalpha
= HAS_ALPHA(image
);
250 for (i
=0; i
< image
->width
*image
->height
; i
++) {
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 *d
= (((int)*d
*(int)COP
) + ((int)*s
*(int)OP
))/256; d
++; s
++;
261 if (!HAS_ALPHA(image
)) {
262 for (i
=0; i
<image
->width
*image
->height
; i
++) {
263 tmp
= (*(s
+3) * opaqueness
)/256;
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 *d
= (((int)*d
* (255-tmp
)) + ((int)*s
* tmp
))/256; d
++; s
++;
270 for (i
=0; i
<image
->width
*image
->height
; i
++) {
271 tmp
= (*(s
+3) * opaqueness
)/256;
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
= (((int)*d
* (255-tmp
)) + ((int)*s
* tmp
))/256; d
++; s
++;
285 calculateCombineArea(RImage
*des
, RImage
*src
, int *sx
, int *sy
,
286 int *swidth
, int *sheight
, int *dx
, int *dy
)
290 *swidth
= *swidth
+ *dx
;
294 if (*dx
+ *swidth
> des
->width
) {
295 *swidth
= des
->width
- *dx
;
300 *sheight
= *sheight
+ *dy
;
304 if (*dy
+ *sheight
> des
->height
) {
305 *sheight
= des
->height
- *dy
;
308 if (*sheight
> 0 && *swidth
> 0) {
314 RCombineArea(RImage
*image
, RImage
*src
, int sx
, int sy
, unsigned width
,
315 unsigned height
, int dx
, int dy
)
322 if(!calculateCombineArea(image
, src
, &sx
, &sy
, &width
, &height
, &dx
, &dy
))
325 if (!HAS_ALPHA(src
)) {
326 if (!HAS_ALPHA(image
)) {
327 swi
= src
->width
* 3;
328 dwi
= image
->width
* 3;
330 s
= src
->data
+ (sy
*(int)src
->width
+ sx
) * 3;
331 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 3;
333 for (y
=0; y
< height
; y
++) {
334 memcpy(d
, s
, width
*3);
339 swi
= (src
->width
- width
) * 3;
340 dwi
= (image
->width
- width
) * 4;
342 s
= src
->data
+ (sy
*(int)src
->width
+ sx
) * 3;
343 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 4;
345 for (y
=0; y
< height
; y
++) {
346 for (x
=0; x
< width
; x
++) {
357 int dalpha
= HAS_ALPHA(image
);
359 swi
= (src
->width
- width
) * 4;
360 s
= src
->data
+ (sy
*(int)src
->width
+ sx
) * 4;
362 dwi
= (image
->width
- width
) * 4;
363 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 4;
365 dwi
= (image
->width
- width
) * 3;
366 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 3;
369 for (y
=0; y
< height
; y
++) {
370 for (x
=0; x
< width
; x
++) {
372 calpha
= 255 - alpha
;
373 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; s
++; d
++;
374 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; s
++; d
++;
375 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
))/256; s
++; d
++;
388 RCopyArea(RImage
*image
, RImage
*src
, int sx
, int sy
, unsigned width
,
389 unsigned height
, int dx
, int dy
)
395 if(!calculateCombineArea(image
, src
, &sx
, &sy
, &width
, &height
, &dx
, &dy
))
398 if (!HAS_ALPHA(src
)) {
399 if (!HAS_ALPHA(image
)) {
400 swi
= src
->width
* 3;
401 dwi
= image
->width
* 3;
403 s
= src
->data
+ (sy
*(int)src
->width
+ sx
) * 3;
404 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 3;
406 for (y
=0; y
< height
; y
++) {
407 memcpy(d
, s
, width
*3);
412 swi
= (src
->width
- width
) * 3;
413 dwi
= (image
->width
- width
) * 4;
415 s
= src
->data
+ (sy
*(int)src
->width
+ sx
) * 3;
416 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 4;
418 for (y
=0; y
< height
; y
++) {
419 for (x
=0; x
< width
; x
++) {
430 int dalpha
= HAS_ALPHA(image
);
432 swi
= src
->width
* 4;
433 s
= src
->data
+ (sy
*(int)src
->width
+ sx
) * 4;
435 dwi
= image
->width
* 4;
436 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 4;
438 dwi
= image
->width
* 3;
439 d
= image
->data
+ (dy
*(int)image
->width
+ dx
) * 3;
443 for (y
=0; y
< height
; y
++) {
444 memcpy(d
, s
, width
*4);
449 for (y
=0; y
< height
; y
++) {
450 for (x
=0; x
< width
; x
++) {
465 RCombineAreaWithOpaqueness(RImage
*image
, RImage
*src
, int sx
, int sy
,
466 unsigned width
, unsigned height
, int dx
, int dy
,
471 unsigned char *s
, *d
;
472 int dalpha
= HAS_ALPHA(image
);
473 int dch
= (dalpha
? 4 : 3);
475 if(!calculateCombineArea(image
, src
, &sx
, &sy
, &width
, &height
, &dx
, &dy
))
478 d
= image
->data
+ (dy
*image
->width
+ dx
) * dch
;
479 dwi
= (image
->width
- width
)*dch
;
481 c_opaqueness
= 255 - opaqueness
;
483 #define OP opaqueness
484 #define COP c_opaqueness
486 if (!HAS_ALPHA(src
)) {
488 s
= src
->data
+ (sy
*src
->width
+ sx
)*3;
489 swi
= (src
->width
- width
) * 3;
491 for (y
=0; y
< height
; y
++) {
492 for (x
=0; x
< width
; x
++) {
493 *d
= (((int)*d
*(int)COP
) + ((int)*s
*(int)OP
))/256; s
++; d
++;
494 *d
= (((int)*d
*(int)COP
) + ((int)*s
*(int)OP
))/256; s
++; d
++;
495 *d
= (((int)*d
*(int)COP
) + ((int)*s
*(int)OP
))/256; s
++; d
++;
504 s
= src
->data
+ (sy
*src
->width
+ sx
)*4;
505 swi
= (src
->width
- width
) * 4;
507 for (y
=0; y
< height
; y
++) {
508 for (x
=0; x
< width
; x
++) {
509 tmp
= (*(s
+3) * opaqueness
)/256;
510 *d
= (((int)*d
* (255-tmp
)) + ((int)*s
* tmp
))/256; d
++; s
++;
511 *d
= (((int)*d
* (255-tmp
)) + ((int)*s
* tmp
))/256; d
++; s
++;
512 *d
= (((int)*d
* (255-tmp
)) + ((int)*s
* tmp
))/256; d
++; s
++;
527 RCombineImageWithColor(RImage
*image
, RColor
*color
)
531 int alpha
, nalpha
, r
, g
, b
;
535 if (!HAS_ALPHA(image
)) {
536 /* Image has no alpha channel, so we consider it to be all 255.
537 * Thus there are no transparent parts to be filled. */
544 for (i
=0; i
< image
->width
*image
->height
; i
++) {
546 nalpha
= 255 - alpha
;
548 *d
= (((int)*d
* alpha
) + (r
* nalpha
))/256; d
++;
549 *d
= (((int)*d
* alpha
) + (g
* nalpha
))/256; d
++;
550 *d
= (((int)*d
* alpha
) + (b
* nalpha
))/256; d
++;
559 RMakeTiledImage(RImage
*tile
, unsigned width
, unsigned height
)
563 unsigned long tile_size
= tile
->width
* tile
->height
;
564 unsigned long tx
= 0;
566 unsigned char *s
, *d
;
568 if (width
== tile
->width
&& height
== tile
->height
)
569 image
= RCloneImage(tile
);
570 else if (width
<= tile
->width
&& height
<= tile
->height
)
571 image
= RGetSubImage(tile
, 0, 0, width
, height
);
573 int has_alpha
= HAS_ALPHA(tile
);
575 image
= RCreateImage(width
, height
, has_alpha
);
580 for (y
= 0; y
< height
; y
++) {
581 for (x
= 0; x
< width
; x
+= tile
->width
) {
583 w
= (width
- x
< tile
->width
) ? width
- x
: tile
->width
;
587 memcpy(d
, s
+tx
*4, w
);
590 memcpy(d
, s
+tx
*3, w
);
595 tx
= (tx
+ tile
->width
) % tile_size
;
603 RMakeCenteredImage(RImage
*image
, unsigned width
, unsigned height
, RColor
*color
)
605 int x
, y
, w
, h
, sx
, sy
;
608 tmp
= RCreateImage(width
, height
, False
);
613 RClearImage(tmp
, color
);
615 if (image
->height
< height
) {
620 sy
= (image
->height
- height
)/2;
624 if (image
->width
< width
) {
629 sx
= (image
->width
- width
)/2;
633 RCombineArea(tmp
, image
, sx
, sy
, w
, h
, x
, y
);