fixed bug with RCreateImageFromXImage() with mask and image of != sizes
[wmaker-crm.git] / wrlib / gradient.c
blob22b4eba9f7814f34d4750535268293d0085468ed
1 /* gradient.c - renders gradients
3 * Raster graphics library
5 * Copyright (c) 1997-2000 Alfredo K. Kojima
6 * Copyright (c) 1998-2000 Dan Pascu
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <config.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
29 #include <assert.h>
31 #include "wraster.h"
34 static RImage *renderHGradient(unsigned width, unsigned height,
35 int r0, int g0, int b0,
36 int rf, int gf, int bf);
37 static RImage *renderVGradient(unsigned width, unsigned height,
38 int r0, int g0, int b0,
39 int rf, int gf, int bf);
40 static RImage *renderDGradient(unsigned width, unsigned height,
41 int r0, int g0, int b0,
42 int rf, int gf, int bf);
44 static RImage *renderMHGradient(unsigned width, unsigned height,
45 RColor **colors, int count);
46 static RImage *renderMVGradient(unsigned width, unsigned height,
47 RColor **colors, int count);
48 static RImage *renderMDGradient(unsigned width, unsigned height,
49 RColor **colors, int count);
51 RImage*
52 RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style)
54 int count;
56 count = 0;
57 while (colors[count]!=NULL) count++;
59 if (count > 2) {
60 switch (style) {
61 case RHorizontalGradient:
62 return renderMHGradient(width, height, colors, count);
63 case RVerticalGradient:
64 return renderMVGradient(width, height, colors, count);
65 case RDiagonalGradient:
66 return renderMDGradient(width, height, colors, count);
68 } else if (count > 1) {
69 return RRenderGradient(width, height, colors[0], colors[1], style);
70 } else if (count > 0) {
71 return RRenderGradient(width, height, colors[0], colors[0], style);
73 assert(0);
74 return NULL;
79 RImage*
80 RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to,
81 int style)
83 switch (style) {
84 case RHorizontalGradient:
85 return renderHGradient(width, height, from->red, from->green,
86 from->blue, to->red, to->green, to->blue);
87 case RVerticalGradient:
88 return renderVGradient(width, height, from->red, from->green,
89 from->blue, to->red, to->green, to->blue);
91 case RDiagonalGradient:
92 return renderDGradient(width, height, from->red, from->green,
93 from->blue, to->red, to->green, to->blue);
95 assert(0);
96 return NULL;
101 *----------------------------------------------------------------------
102 * renderHGradient--
103 * Renders a horizontal linear gradient of the specified size in the
104 * RImage format with a border of the specified type.
106 * Returns:
107 * A 24bit RImage with the gradient (no alpha channel).
109 * Side effects:
110 * None
111 *----------------------------------------------------------------------
113 static RImage*
114 renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0,
115 int rf, int gf, int bf)
117 int i;
118 unsigned long r, g, b, dr, dg, db;
119 RImage *image;
120 unsigned char *ptr;
122 image = RCreateImage(width, height, False);
123 if (!image) {
124 return NULL;
126 ptr = image->data;
128 r = r0 << 16;
129 g = g0 << 16;
130 b = b0 << 16;
132 dr = ((rf-r0)<<16)/(int)width;
133 dg = ((gf-g0)<<16)/(int)width;
134 db = ((bf-b0)<<16)/(int)width;
135 /* render the first line */
136 for (i=0; i<width; i++) {
137 *(ptr++) = (unsigned char)(r>>16);
138 *(ptr++) = (unsigned char)(g>>16);
139 *(ptr++) = (unsigned char)(b>>16);
140 r += dr;
141 g += dg;
142 b += db;
145 /* copy the first line to the other lines */
146 for (i=1; i<height; i++) {
147 memcpy(&(image->data[i*width*3]), image->data, width*3);
149 return image;
153 *----------------------------------------------------------------------
154 * renderVGradient--
155 * Renders a vertical linear gradient of the specified size in the
156 * RImage format with a border of the specified type.
158 * Returns:
159 * A 24bit RImage with the gradient (no alpha channel).
161 * Side effects:
162 * None
163 *----------------------------------------------------------------------
165 static RImage*
166 renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
167 int rf, int gf, int bf)
169 int i, j;
170 unsigned long r, g, b, dr, dg, db;
171 RImage *image;
172 unsigned char *ptr;
173 unsigned int *iptr;
174 unsigned char rr, gg, bb;
176 image = RCreateImage(width, height, False);
177 if (!image) {
178 return NULL;
180 iptr = (unsigned int*)ptr = image->data;
182 r = r0<<16;
183 g = g0<<16;
184 b = b0<<16;
186 dr = ((rf-r0)<<16)/(int)height;
187 dg = ((gf-g0)<<16)/(int)height;
188 db = ((bf-b0)<<16)/(int)height;
191 for (i=0; i<height; i++) {
192 rr = r>>16;
193 gg = g>>16;
194 bb = b>>16;
195 for (j=0; j<width/4; j++) {
196 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
197 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
198 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
199 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
201 switch (width%4) {
202 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
203 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
204 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
206 r+=dr;
207 g+=dg;
208 b+=db;
210 return image;
215 *----------------------------------------------------------------------
216 * renderDGradient--
217 * Renders a diagonal linear gradient of the specified size in the
218 * RImage format with a border of the specified type.
220 * Returns:
221 * A 24bit RImage with the gradient (no alpha channel).
223 * Side effects:
224 * None
225 *----------------------------------------------------------------------
229 static RImage*
230 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
231 int rf, int gf, int bf)
233 RImage *image, *tmp;
234 unsigned long a;
235 int i, j, offset;
237 if (width == 1)
238 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
239 else if (height == 1)
240 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
242 image = RCreateImage(width, height, False);
243 if (!image) {
244 return NULL;
247 tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
248 if (!tmp) {
249 RDestroyImage(image);
250 return NULL;
253 a = (((width - 1)<<16) / (height - 1));
255 width *= 3;
256 /* copy the first line to the other lines with corresponding offset */
257 for (i=0, j=0, offset = 0; i<height; i++, j+= width) {
258 offset += a;
259 memcpy(&(image->data[j]), &(tmp->data[(offset>>16)*3]), width);
261 RDestroyImage(tmp);
262 return image;
266 static RImage*
267 renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
269 int i, j, k;
270 unsigned long r, g, b, dr, dg, db;
271 RImage *image;
272 unsigned char *ptr;
273 unsigned width2;
276 assert(count > 2);
278 image = RCreateImage(width, height, False);
279 if (!image) {
280 return NULL;
282 ptr = image->data;
284 if (count > width)
285 count = width;
287 if (count > 1)
288 width2 = width/(count-1);
289 else
290 width2 = width;
292 k = 0;
294 r = colors[0]->red << 16;
295 g = colors[0]->green << 16;
296 b = colors[0]->blue << 16;
298 /* render the first line */
299 for (i=1; i<count; i++) {
300 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)width2;
301 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
302 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2;
303 for (j=0; j<width2; j++) {
304 *ptr++ = (unsigned char)(r>>16);
305 *ptr++ = (unsigned char)(g>>16);
306 *ptr++ = (unsigned char)(b>>16);
307 r += dr;
308 g += dg;
309 b += db;
310 k++;
312 r = colors[i]->red << 16;
313 g = colors[i]->green << 16;
314 b = colors[i]->blue << 16;
316 for (j=k; j<width; j++) {
317 *ptr++ = (unsigned char)(r>>16);
318 *ptr++ = (unsigned char)(g>>16);
319 *ptr++ = (unsigned char)(b>>16);
322 /* copy the first line to the other lines */
323 for (i=1; i<height; i++) {
324 memcpy(&(image->data[i*width*3]), image->data, width*3);
326 return image;
332 static RImage*
333 renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
335 int i, j, k;
336 unsigned long r, g, b, dr, dg, db;
337 RImage *image;
338 unsigned char *ptr, *tmp;
339 unsigned height2;
340 int x;
341 unsigned char rr, gg, bb;
344 assert(count > 2);
346 image = RCreateImage(width, height, False);
347 if (!image) {
348 return NULL;
350 ptr = image->data;
352 if (count > height)
353 count = height;
355 if (count > 1)
356 height2 = height/(count-1);
357 else
358 height2 = height;
360 k = 0;
362 r = colors[0]->red << 16;
363 g = colors[0]->green << 16;
364 b = colors[0]->blue << 16;
366 for (i=1; i<count; i++) {
367 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)height2;
368 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
369 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2;
371 for (j=0; j<height2; j++) {
372 rr = r>>16;
373 gg = g>>16;
374 bb = b>>16;
376 for (x=0; x<width/4; x++) {
377 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
378 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
379 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
380 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
382 switch (width%4) {
383 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
384 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
385 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
387 r += dr;
388 g += dg;
389 b += db;
390 k++;
392 r = colors[i]->red << 16;
393 g = colors[i]->green << 16;
394 b = colors[i]->blue << 16;
397 rr = r>>16;
398 gg = g>>16;
399 bb = b>>16;
401 if (k<height) {
402 tmp = ptr;
403 for (x=0; x<width/4; x++) {
404 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
405 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
406 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
407 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
409 switch (width%4) {
410 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
411 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
412 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
413 default: break;
416 for (j=k+1; j<height; j++) {
417 memcpy(ptr, tmp, width*3);
418 ptr += width*3;
422 return image;
426 static RImage*
427 renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
429 RImage *image, *tmp;
430 float a;
431 int i, offset;
433 assert(count > 2);
435 if (width == 1)
436 return renderMVGradient(width, height, colors, count);
437 else if (height == 1)
438 return renderMHGradient(width, height, colors, count);
440 image = RCreateImage(width, height, False);
441 if (!image) {
442 return NULL;
445 if (count > width)
446 count = width;
447 if (count > height)
448 count = height;
450 if (count > 2)
451 tmp = renderMHGradient(2*width-1, 1, colors, count);
452 else
453 tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
454 colors[0]->green<<8, colors[0]->blue<<8,
455 colors[1]->red<<8, colors[1]->green<<8,
456 colors[1]->blue<<8);
458 if (!tmp) {
459 RDestroyImage(image);
460 return NULL;
463 a = ((float)(width - 1))/((float)(height - 1));
465 /* copy the first line to the other lines with corresponding offset */
466 for (i=0; i<height; i++) {
467 offset = (int)(a*i+0.5)*3;
468 memcpy(&(image->data[i*width*3]), &(tmp->data[offset]), width*3);
470 RDestroyImage(tmp);
471 return image;