/* gradient.c - renders gradients * * Raster graphics library * * Copyright (c) 1997-2000 Alfredo K. Kojima * Copyright (c) 1998-2000 Dan Pascu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "xrtools.h" static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf); static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf); static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf); static RImage *renderMHGradient(unsigned width, unsigned height, RColor **colors, int count); static RImage *renderMVGradient(unsigned width, unsigned height, RColor **colors, int count); static RImage *renderMDGradient(unsigned width, unsigned height, RColor **colors, int count); RImage* RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style) { int count; count = 0; while (colors[count]!=NULL) count++; if (count > 2) { switch (style) { case RHorizontalGradient: return renderMHGradient(width, height, colors, count); case RVerticalGradient: return renderMVGradient(width, height, colors, count); case RDiagonalGradient: return renderMDGradient(width, height, colors, count); } } else if (count > 1) { return RRenderGradient(width, height, colors[0], colors[1], style); } else if (count > 0) { return RRenderGradient(width, height, colors[0], colors[0], style); } assert(0); return NULL; } RImage* RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to, int style) { switch (style) { case RHorizontalGradient: return renderHGradient(width, height, from->red, from->green, from->blue, to->red, to->green, to->blue); case RVerticalGradient: return renderVGradient(width, height, from->red, from->green, from->blue, to->red, to->green, to->blue); case RDiagonalGradient: return renderDGradient(width, height, from->red, from->green, from->blue, to->red, to->green, to->blue); } assert(0); return NULL; } /* *---------------------------------------------------------------------- * renderHGradient-- * Renders a horizontal linear gradient of the specified size in the * RImage format with a border of the specified type. * * Returns: * A 24bit RImage with the gradient (no alpha channel). * * Side effects: * None *---------------------------------------------------------------------- */ static RImage* renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf) { int i; unsigned long r, g, b, dr, dg, db; RImage *image; unsigned char *ptr; image = RCreateImage(width, height, False); if (!image) { return NULL; } ptr = image->data; r = r0 << 16; g = g0 << 16; b = b0 << 16; dr = ((rf-r0)<<16)/(int)width; dg = ((gf-g0)<<16)/(int)width; db = ((bf-b0)<<16)/(int)width; /* render the first line */ for (i=0; i>16); *(ptr++) = (unsigned char)(g>>16); *(ptr++) = (unsigned char)(b>>16); r += dr; g += dg; b += db; } /* copy the first line to the other lines */ for (i=1; idata[i*width*3]), image->data, width*3); } return image; } /* *---------------------------------------------------------------------- * renderVGradient-- * Renders a vertical linear gradient of the specified size in the * RImage format with a border of the specified type. * * Returns: * A 24bit RImage with the gradient (no alpha channel). * * Side effects: * None *---------------------------------------------------------------------- */ static RImage* renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf) { int i, j; unsigned long r, g, b, dr, dg, db; RImage *image; unsigned char *ptr; unsigned int *iptr; unsigned char rr, gg, bb; image = RCreateImage(width, height, False); if (!image) { return NULL; } iptr = (unsigned int*)ptr = image->data; r = r0<<16; g = g0<<16; b = b0<<16; dr = ((rf-r0)<<16)/(int)height; dg = ((gf-g0)<<16)/(int)height; db = ((bf-b0)<<16)/(int)height; for (i=0; i>16; gg = g>>16; bb = b>>16; for (j=0; jdata; a = ((float)(width - 1))/((float)(height - 1)); width = width * 3; /* copy the first line to the other lines with corresponding offset */ for (j=0, offset=0.0; jdata[j]), &ptr[3*(int)offset], width); offset += a; } RDestroyImage(tmp); return image; } static RImage* renderMHGradient(unsigned width, unsigned height, RColor **colors, int count) { int i, j, k; unsigned long r, g, b, dr, dg, db; RImage *image; unsigned char *ptr; unsigned width2; assert(count > 2); image = RCreateImage(width, height, False); if (!image) { return NULL; } ptr = image->data; if (count > width) count = width; if (count > 1) width2 = width/(count-1); else width2 = width; k = 0; r = colors[0]->red << 16; g = colors[0]->green << 16; b = colors[0]->blue << 16; /* render the first line */ for (i=1; ired - colors[i-1]->red) <<16)/(int)width2; dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2; db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2; for (j=0; j>16); *ptr++ = (unsigned char)(g>>16); *ptr++ = (unsigned char)(b>>16); r += dr; g += dg; b += db; k++; } r = colors[i]->red << 16; g = colors[i]->green << 16; b = colors[i]->blue << 16; } for (j=k; j>16); *ptr++ = (unsigned char)(g>>16); *ptr++ = (unsigned char)(b>>16); } /* copy the first line to the other lines */ for (i=1; idata[i*width*3]), image->data, width*3); } return image; } static RImage* renderMVGradient(unsigned width, unsigned height, RColor **colors, int count) { int i, j, k; unsigned long r, g, b, dr, dg, db; RImage *image; unsigned char *ptr, *tmp; unsigned height2; int x; unsigned char rr, gg, bb; assert(count > 2); image = RCreateImage(width, height, False); if (!image) { return NULL; } ptr = image->data; if (count > height) count = height; if (count > 1) height2 = height/(count-1); else height2 = height; k = 0; r = colors[0]->red << 16; g = colors[0]->green << 16; b = colors[0]->blue << 16; for (i=1; ired - colors[i-1]->red) <<16)/(int)height2; dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2; db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2; for (j=0; j>16; gg = g>>16; bb = b>>16; for (x=0; xred << 16; g = colors[i]->green << 16; b = colors[i]->blue << 16; } rr = r>>16; gg = g>>16; bb = b>>16; if (k 2); if (width == 1) return renderMVGradient(width, height, colors, count); else if (height == 1) return renderMHGradient(width, height, colors, count); image = RCreateImage(width, height, False); if (!image) { return NULL; } if (count > width) count = width; if (count > height) count = height; if (count > 2) tmp = renderMHGradient(2*width-1, 1, colors, count); else tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8, colors[0]->green<<8, colors[0]->blue<<8, colors[1]->red<<8, colors[1]->green<<8, colors[1]->blue<<8); if (!tmp) { RDestroyImage(image); return NULL; } ptr = tmp->data; a = ((float)(width - 1))/((float)(height - 1)); width = width * 3; /* copy the first line to the other lines with corresponding offset */ for (j=0, offset=0; jdata[j]), &ptr[3*(int)offset], width); offset += a; } RDestroyImage(tmp); return image; }