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.
32 char *WRasterLibVersion
= "0.9";
34 int RErrorCode
= RERR_NONE
;
36 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
38 #define MAX_WIDTH 20000
39 #define MAX_HEIGHT 20000
42 RImage
*RCreateImage(unsigned width
, unsigned height
, int alpha
)
46 assert(width
> 0 && height
> 0);
48 if (width
> MAX_WIDTH
|| height
> MAX_HEIGHT
) {
49 RErrorCode
= RERR_NOMEMORY
;
53 image
= malloc(sizeof(RImage
));
55 RErrorCode
= RERR_NOMEMORY
;
59 memset(image
, 0, sizeof(RImage
));
61 image
->height
= height
;
62 image
->format
= alpha
? RRGBAFormat
: RRGBFormat
;
65 /* the +4 is to give extra bytes at the end of the buffer,
66 * so that we can optimize image conversion for MMX(tm).. see convert.c
68 image
->data
= malloc(width
* height
* (alpha
? 4 : 3) + 4);
70 RErrorCode
= RERR_NOMEMORY
;
79 RImage
*RRetainImage(RImage
* image
)
87 void RReleaseImage(RImage
* image
)
89 assert(image
!= NULL
);
93 if (image
->refCount
< 1) {
99 RImage
*RCloneImage(RImage
* image
)
103 assert(image
!= NULL
);
105 new_image
= RCreateImage(image
->width
, image
->height
, HAS_ALPHA(image
));
109 new_image
->background
= image
->background
;
110 memcpy(new_image
->data
, image
->data
, image
->width
* image
->height
* (HAS_ALPHA(image
) ? 4 : 3));
115 RImage
*RGetSubImage(RImage
* image
, int x
, int y
, unsigned width
, unsigned height
)
119 unsigned total_line_size
, line_size
;
121 assert(image
!= NULL
);
122 assert(x
>= 0 && y
>= 0);
123 assert(x
< image
->width
&& y
< image
->height
);
124 assert(width
> 0 && height
> 0);
126 if (x
+ width
> image
->width
)
127 width
= image
->width
- x
;
128 if (y
+ height
> image
->height
)
129 height
= image
->height
- y
;
131 new_image
= RCreateImage(width
, height
, HAS_ALPHA(image
));
135 new_image
->background
= image
->background
;
137 total_line_size
= image
->width
* (HAS_ALPHA(image
) ? 4 : 3);
138 line_size
= width
* (HAS_ALPHA(image
) ? 4 : 3);
140 ofs
= x
* (HAS_ALPHA(image
) ? 4 : 3) + y
* total_line_size
;;
142 for (i
= 0; i
< height
; i
++) {
143 memcpy(&new_image
->data
[i
* line_size
], &image
->data
[i
* total_line_size
+ ofs
], line_size
);
149 *----------------------------------------------------------------------
151 * Combines two equal sized images with alpha image. The second
152 * image will be placed on top of the first one.
153 *----------------------------------------------------------------------
155 void RCombineImages(RImage
* image
, RImage
* src
)
157 assert(image
->width
== src
->width
);
158 assert(image
->height
== src
->height
);
160 if (!HAS_ALPHA(src
)) {
161 if (!HAS_ALPHA(image
)) {
162 memcpy(image
->data
, src
->data
, image
->height
* image
->width
* 3);
165 unsigned char *d
, *s
;
169 for (y
= 0; y
< image
->height
; y
++) {
170 for (x
= 0; x
< image
->width
; x
++) {
187 if (!HAS_ALPHA(image
)) {
188 for (i
= 0; i
< image
->height
* image
->width
; i
++) {
190 calpha
= 255 - alpha
;
191 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
194 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
197 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
203 for (i
= 0; i
< image
->height
* image
->width
; i
++) {
205 calpha
= 255 - alpha
;
206 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
209 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
212 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
221 void RCombineImagesWithOpaqueness(RImage
* image
, RImage
* src
, int opaqueness
)
228 assert(image
->width
== src
->width
);
229 assert(image
->height
== src
->height
);
234 c_opaqueness
= 255 - opaqueness
;
236 #define OP opaqueness
237 #define COP c_opaqueness
239 if (!HAS_ALPHA(src
)) {
240 int dalpha
= HAS_ALPHA(image
);
241 for (i
= 0; i
< image
->width
* image
->height
; i
++) {
242 *d
= (((int)*d
* (int)COP
) + ((int)*s
* (int)OP
)) / 256;
245 *d
= (((int)*d
* (int)COP
) + ((int)*s
* (int)OP
)) / 256;
248 *d
= (((int)*d
* (int)COP
) + ((int)*s
* (int)OP
)) / 256;
258 if (!HAS_ALPHA(image
)) {
259 for (i
= 0; i
< image
->width
* image
->height
; i
++) {
260 tmp
= (*(s
+ 3) * opaqueness
) / 256;
261 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
264 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
267 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
273 for (i
= 0; i
< image
->width
* image
->height
; i
++) {
274 tmp
= (*(s
+ 3) * opaqueness
) / 256;
275 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
278 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
281 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
294 static int calculateCombineArea(RImage
*des
, int *sx
, int *sy
, unsigned int *swidth
,
295 unsigned int *sheight
, int *dx
, int *dy
)
297 int width
= (int)*swidth
, height
= (int)*sheight
;
305 if (*dx
+ width
> des
->width
) {
306 width
= des
->width
- *dx
;
311 height
= height
+ *dy
;
315 if (*dy
+ height
> des
->height
) {
316 height
= des
->height
- *dy
;
319 if (height
> 0 && width
> 0) {
328 void RCombineArea(RImage
* image
, RImage
* src
, int sx
, int sy
, unsigned width
, unsigned height
, int dx
, int dy
)
335 if (!calculateCombineArea(image
, &sx
, &sy
, &width
, &height
, &dx
, &dy
))
338 if (!HAS_ALPHA(src
)) {
339 if (!HAS_ALPHA(image
)) {
340 swi
= src
->width
* 3;
341 dwi
= image
->width
* 3;
343 s
= src
->data
+ (sy
* (int)src
->width
+ sx
) * 3;
344 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 3;
346 for (y
= 0; y
< height
; y
++) {
347 memcpy(d
, s
, width
* 3);
352 swi
= (src
->width
- width
) * 3;
353 dwi
= (image
->width
- width
) * 4;
355 s
= src
->data
+ (sy
* (int)src
->width
+ sx
) * 3;
356 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 4;
358 for (y
= 0; y
< height
; y
++) {
359 for (x
= 0; x
< width
; x
++) {
370 int dalpha
= HAS_ALPHA(image
);
372 swi
= (src
->width
- width
) * 4;
373 s
= src
->data
+ (sy
* (int)src
->width
+ sx
) * 4;
375 dwi
= (image
->width
- width
) * 4;
376 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 4;
378 dwi
= (image
->width
- width
) * 3;
379 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 3;
382 for (y
= 0; y
< height
; y
++) {
383 for (x
= 0; x
< width
; x
++) {
385 calpha
= 255 - alpha
;
386 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
389 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
392 *d
= (((int)*d
* calpha
) + ((int)*s
* alpha
)) / 256;
405 void RCopyArea(RImage
* image
, RImage
* src
, int sx
, int sy
, unsigned width
, unsigned height
, int dx
, int dy
)
411 if (!calculateCombineArea(image
, &sx
, &sy
, &width
, &height
, &dx
, &dy
))
414 if (!HAS_ALPHA(src
)) {
415 if (!HAS_ALPHA(image
)) {
416 swi
= src
->width
* 3;
417 dwi
= image
->width
* 3;
419 s
= src
->data
+ (sy
* (int)src
->width
+ sx
) * 3;
420 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 3;
422 for (y
= 0; y
< height
; y
++) {
423 memcpy(d
, s
, width
* 3);
428 swi
= (src
->width
- width
) * 3;
429 dwi
= (image
->width
- width
) * 4;
431 s
= src
->data
+ (sy
* (int)src
->width
+ sx
) * 3;
432 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 4;
434 for (y
= 0; y
< height
; y
++) {
435 for (x
= 0; x
< width
; x
++) {
446 int dalpha
= HAS_ALPHA(image
);
448 swi
= src
->width
* 4;
449 s
= src
->data
+ (sy
* (int)src
->width
+ sx
) * 4;
451 dwi
= image
->width
* 4;
452 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 4;
454 dwi
= image
->width
* 3;
455 d
= image
->data
+ (dy
* (int)image
->width
+ dx
) * 3;
459 for (y
= 0; y
< height
; y
++) {
460 memcpy(d
, s
, width
* 4);
465 for (y
= 0; y
< height
; y
++) {
466 for (x
= 0; x
< width
; x
++) {
480 RCombineAreaWithOpaqueness(RImage
* image
, RImage
* src
, int sx
, int sy
,
481 unsigned width
, unsigned height
, int dx
, int dy
, int opaqueness
)
485 unsigned char *s
, *d
;
486 int dalpha
= HAS_ALPHA(image
);
487 int dch
= (dalpha
? 4 : 3);
489 if (!calculateCombineArea(image
, &sx
, &sy
, &width
, &height
, &dx
, &dy
))
492 d
= image
->data
+ (dy
* image
->width
+ dx
) * dch
;
493 dwi
= (image
->width
- width
) * dch
;
495 c_opaqueness
= 255 - opaqueness
;
497 #define OP opaqueness
498 #define COP c_opaqueness
500 if (!HAS_ALPHA(src
)) {
502 s
= src
->data
+ (sy
* src
->width
+ sx
) * 3;
503 swi
= (src
->width
- width
) * 3;
505 for (y
= 0; y
< height
; y
++) {
506 for (x
= 0; x
< width
; x
++) {
507 *d
= (((int)*d
* (int)COP
) + ((int)*s
* (int)OP
)) / 256;
510 *d
= (((int)*d
* (int)COP
) + ((int)*s
* (int)OP
)) / 256;
513 *d
= (((int)*d
* (int)COP
) + ((int)*s
* (int)OP
)) / 256;
525 s
= src
->data
+ (sy
* src
->width
+ sx
) * 4;
526 swi
= (src
->width
- width
) * 4;
528 for (y
= 0; y
< height
; y
++) {
529 for (x
= 0; x
< width
; x
++) {
530 tmp
= (*(s
+ 3) * opaqueness
) / 256;
531 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
534 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
537 *d
= (((int)*d
* (255 - tmp
)) + ((int)*s
* tmp
)) / 256;
552 void RCombineImageWithColor(RImage
* image
, RColor
* color
)
556 int alpha
, nalpha
, r
, g
, b
;
560 if (!HAS_ALPHA(image
)) {
561 /* Image has no alpha channel, so we consider it to be all 255.
562 * Thus there are no transparent parts to be filled. */
569 for (i
= 0; i
< image
->width
* image
->height
; i
++) {
571 nalpha
= 255 - alpha
;
573 *d
= (((int)*d
* alpha
) + (r
* nalpha
)) / 256;
575 *d
= (((int)*d
* alpha
) + (g
* nalpha
)) / 256;
577 *d
= (((int)*d
* alpha
) + (b
* nalpha
)) / 256;
583 RImage
*RMakeTiledImage(RImage
* tile
, unsigned width
, unsigned height
)
587 unsigned long tile_size
= tile
->width
* tile
->height
;
588 unsigned long tx
= 0;
590 unsigned char *s
, *d
;
592 if (width
== tile
->width
&& height
== tile
->height
)
593 image
= RCloneImage(tile
);
594 else if (width
<= tile
->width
&& height
<= tile
->height
)
595 image
= RGetSubImage(tile
, 0, 0, width
, height
);
597 int has_alpha
= HAS_ALPHA(tile
);
599 image
= RCreateImage(width
, height
, has_alpha
);
604 for (y
= 0; y
< height
; y
++) {
605 for (x
= 0; x
< width
; x
+= tile
->width
) {
607 w
= (width
- x
< tile
->width
) ? width
- x
: tile
->width
;
611 memcpy(d
, s
+ tx
* 4, w
);
614 memcpy(d
, s
+ tx
* 3, w
);
619 tx
= (tx
+ tile
->width
) % tile_size
;
625 RImage
*RMakeCenteredImage(RImage
* image
, unsigned width
, unsigned height
, RColor
* color
)
627 int x
, y
, w
, h
, sx
, sy
;
630 tmp
= RCreateImage(width
, height
, False
);
635 RClearImage(tmp
, color
);
637 if (image
->height
< height
) {
639 y
= (height
- h
) / 2;
642 sy
= (image
->height
- height
) / 2;
646 if (image
->width
< width
) {
651 sx
= (image
->width
- width
) / 2;
655 RCombineArea(tmp
, image
, sx
, sy
, w
, h
, x
, y
);