gimp/plug-ins/libgck/gck/gckcolor.c

3061 lines
78 KiB
C

/***************************************************************************/
/* GCK - The General Convenience Kit. Generally useful conveniece routines */
/* for GIMP plug-in writers and users of the GDK/GTK libraries. */
/* Copyright (C) 1996 Tom Bech */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program 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 General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/***************************************************************************/
/*************************************************************/
/* This file contains routines for creating and setting up */
/* visuals. There's also routines for converting RGB(A) data */
/* to whatever format the current visual is. */
/*************************************************************/
#include "stdlib.h"
#include "libgimp/gimpmath.h"
#include "gck.h"
#define RESERVED_COLORS 2
#define ROUND_TO_INT(val) ((val) + 0.5)
typedef struct
{
guchar ready;
GckRGB color;
} _GckSampleType;
const GckRGB gck_rgb_white = {1.0, 1.0, 1.0, 1.0};
const GckRGB gck_rgb_black = {0.0, 0.0, 0.0, 1.0};
const GckRGB gck_rgb_zero = {0.0, 0.0, 0.0, 0.0};
const GckRGB gck_rgb_full = {1.0, 1.0, 1.0, 1.0};
GckNamedRGB gck_named_colors[] =
{
{ 255,250,250, "snow" },
{ 248,248,255, "ghost white" },
{ 248,248,255, "GhostWhite" },
{ 245,245,245, "white smoke" },
{ 245,245,245, "WhiteSmoke" },
{ 220,220,220, "gainsboro" },
{ 255,250,240, "floral white" },
{ 255,250,240, "FloralWhite" },
{ 253,245,230, "old lace" },
{ 253,245,230, "OldLace" },
{ 250,240,230, "linen" },
{ 250,235,215, "antique white" },
{ 250,235,215, "AntiqueWhite" },
{ 255,239,213, "papaya whip" },
{ 255,239,213, "PapayaWhip" },
{ 255,235,205, "blanched almond" },
{ 255,235,205, "BlanchedAlmond" },
{ 255,228,196, "bisque" },
{ 255,218,185, "peach puff" },
{ 255,218,185, "PeachPuff" },
{ 255,222,173, "navajo white" },
{ 255,222,173, "NavajoWhite" },
{ 255,228,181, "moccasin" },
{ 255,248,220, "cornsilk" },
{ 255,255,240, "ivory" },
{ 255,250,205, "lemon chiffon" },
{ 255,250,205, "LemonChiffon" },
{ 255,245,238, "seashell" },
{ 240,255,240, "honeydew" },
{ 245,255,250, "mint cream" },
{ 245,255,250, "MintCream" },
{ 240,255,255, "azure" },
{ 240,248,255, "alice blue" },
{ 240,248,255, "AliceBlue" },
{ 230,230,250, "lavender" },
{ 255,240,245, "lavender blush" },
{ 255,240,245, "LavenderBlush" },
{ 255,228,225, "misty rose" },
{ 255,228,225, "MistyRose" },
{ 255,255,255, "white" },
{ 0, 0, 0, "black" },
{ 47, 79, 79, "dark slate gray" },
{ 47, 79, 79, "DarkSlateGray" },
{ 47, 79, 79, "dark slate grey" },
{ 47, 79, 79, "DarkSlateGrey" },
{ 105,105,105, "dim gray" },
{ 105,105,105, "DimGray" },
{ 105,105,105, "dim grey" },
{ 105,105,105, "DimGrey" },
{ 112,128,144, "slate gray" },
{ 112,128,144, "SlateGray" },
{ 112,128,144, "slate grey" },
{ 112,128,144, "SlateGrey" },
{ 119,136,153, "light slate gray" },
{ 119,136,153, "LightSlateGray" },
{ 119,136,153, "light slate grey" },
{ 119,136,153, "LightSlateGrey" },
{ 190,190,190, "gray" },
{ 190,190,190, "grey" },
{ 211,211,211, "light grey" },
{ 211,211,211, "LightGrey" },
{ 211,211,211, "light gray" },
{ 211,211,211, "LightGray" },
{ 25, 25,112, "midnight blue" },
{ 25, 25,112, "MidnightBlue" },
{ 0, 0,128, "navy" },
{ 0, 0,128, "navy blue" },
{ 0, 0,128, "NavyBlue" },
{ 100,149,237, "cornflower blue" },
{ 100,149,237, "CornflowerBlue" },
{ 72, 61,139, "dark slate blue" },
{ 72, 61,139, "DarkSlateBlue" },
{ 106, 90,205, "slate blue" },
{ 106, 90,205, "SlateBlue" },
{ 123,104,238, "medium slate blue" },
{ 123,104,238, "MediumSlateBlue" },
{ 132,112,255, "light slate blue" },
{ 132,112,255, "LightSlateBlue" },
{ 0, 0,205, "medium blue" },
{ 0, 0,205, "MediumBlue" },
{ 65,105,225, "royal blue" },
{ 65,105,225, "RoyalBlue" },
{ 0, 0,255, "blue" },
{ 30,144,255, "dodger blue" },
{ 30,144,255, "DodgerBlue" },
{ 0,191,255, "deep sky blue" },
{ 0,191,255, "DeepSkyBlue" },
{ 135,206,235, "sky blue" },
{ 135,206,235, "SkyBlue" },
{ 135,206,250, "light sky blue" },
{ 135,206,250, "LightSkyBlue" },
{ 70,130,180, "steel blue" },
{ 70,130,180, "SteelBlue" },
{ 176,196,222, "light steel blue" },
{ 176,196,222, "LightSteelBlue" },
{ 173,216,230, "light blue" },
{ 173,216,230, "LightBlue" },
{ 176,224,230, "powder blue" },
{ 176,224,230, "PowderBlue" },
{ 175,238,238, "pale turquoise" },
{ 175,238,238, "PaleTurquoise" },
{ 0,206,209, "dark turquoise" },
{ 0,206,209, "DarkTurquoise" },
{ 72,209,204, "medium turquoise" },
{ 72,209,204, "MediumTurquoise" },
{ 64,224,208, "turquoise" },
{ 0,255,255, "cyan" },
{ 224,255,255, "light cyan" },
{ 224,255,255, "LightCyan" },
{ 95,158,160, "cadet blue" },
{ 95,158,160, "CadetBlue" },
{ 102,205,170, "medium aquamarine" },
{ 102,205,170, "MediumAquamarine" },
{ 127,255,212, "aquamarine" },
{ 0,100, 0, "dark green" },
{ 0,100, 0, "DarkGreen" },
{ 85,107, 47, "dark olive green" },
{ 85,107, 47, "DarkOliveGreen" },
{ 143,188,143, "dark sea green" },
{ 143,188,143, "DarkSeaGreen" },
{ 46,139, 87, "sea green" },
{ 46,139, 87, "SeaGreen" },
{ 60,179,113, "medium sea green" },
{ 60,179,113, "MediumSeaGreen" },
{ 32,178,170, "light sea green" },
{ 32,178,170, "LightSeaGreen" },
{ 152,251,152, "pale green" },
{ 152,251,152, "PaleGreen" },
{ 0,255,127, "spring green" },
{ 0,255,127, "SpringGreen" },
{ 124,252, 0, "lawn green" },
{ 124,252, 0, "LawnGreen" },
{ 0,255, 0, "green" },
{ 127,255, 0, "chartreuse" },
{ 0,250,154, "medium spring green" },
{ 0,250,154, "MediumSpringGreen" },
{ 173,255, 47, "green yellow" },
{ 173,255, 47, "GreenYellow" },
{ 50,205, 50, "lime green" },
{ 50,205, 50, "LimeGreen" },
{ 154,205, 50, "yellow green" },
{ 154,205, 50, "YellowGreen" },
{ 34,139, 34, "forest green" },
{ 34,139, 34, "ForestGreen" },
{ 107,142, 35, "olive drab" },
{ 107,142, 35, "OliveDrab" },
{ 189,183,107, "dark khaki" },
{ 189,183,107, "DarkKhaki" },
{ 240,230,140, "khaki" },
{ 238,232,170, "pale goldenrod" },
{ 238,232,170, "PaleGoldenrod" },
{ 250,250,210, "light goldenrod yellow" },
{ 250,250,210, "LightGoldenrodYellow" },
{ 255,255,224, "light yellow" },
{ 255,255,224, "LightYellow" },
{ 255,255, 0, "yellow" },
{ 255,215, 0, "gold" },
{ 238,221,130, "light goldenrod" },
{ 238,221,130, "LightGoldenrod" },
{ 218,165, 32, "goldenrod" },
{ 184,134, 11, "dark goldenrod" },
{ 184,134, 11, "DarkGoldenrod" },
{ 188,143,143, "rosy brown" },
{ 188,143,143, "RosyBrown" },
{ 205, 92, 92, "indian red" },
{ 205, 92, 92, "IndianRed" },
{ 139, 69, 19, "saddle brown" },
{ 139, 69, 19, "SaddleBrown" },
{ 160, 82, 45, "sienna" },
{ 205,133, 63, "peru" },
{ 222,184,135, "burlywood" },
{ 245,245,220, "beige" },
{ 245,222,179, "wheat" },
{ 244,164, 96, "sandy brown" },
{ 244,164, 96, "SandyBrown" },
{ 210,180,140, "tan" },
{ 210,105, 30, "chocolate" },
{ 178, 34, 34, "firebrick" },
{ 165, 42, 42, "brown" },
{ 233,150,122, "dark salmon" },
{ 233,150,122, "DarkSalmon" },
{ 250,128,114, "salmon" },
{ 255,160,122, "light salmon" },
{ 255,160,122, "LightSalmon" },
{ 255,165, 0, "orange" },
{ 255,140, 0, "dark orange" },
{ 255,140, 0, "DarkOrange" },
{ 255,127, 80, "coral" },
{ 240,128,128, "light coral" },
{ 240,128,128, "LightCoral" },
{ 255, 99, 71, "tomato" },
{ 255, 69, 0, "orange red" },
{ 255, 69, 0, "OrangeRed" },
{ 255, 0, 0, "red" },
{ 255,105,180, "hot pink" },
{ 255,105,180, "HotPink" },
{ 255, 20,147, "deep pink" },
{ 255, 20,147, "DeepPink" },
{ 255,192,203, "pink" },
{ 255,182,193, "light pink" },
{ 255,182,193, "LightPink" },
{ 219,112,147, "pale violet red" },
{ 219,112,147, "PaleVioletRed" },
{ 176, 48, 96, "maroon" },
{ 199, 21,133, "medium violet red" },
{ 199, 21,133, "MediumVioletRed" },
{ 208, 32,144, "violet red" },
{ 208, 32,144, "VioletRed" },
{ 255, 0,255, "magenta" },
{ 238,130,238, "violet" },
{ 221,160,221, "plum" },
{ 218,112,214, "orchid" },
{ 186, 85,211, "medium orchid" },
{ 186, 85,211, "MediumOrchid" },
{ 153, 50,204, "dark orchid" },
{ 153, 50,204, "DarkOrchid" },
{ 148, 0,211, "dark violet" },
{ 148, 0,211, "DarkViolet" },
{ 138, 43,226, "blue violet" },
{ 138, 43,226, "BlueViolet" },
{ 160, 32,240, "purple" },
{ 147,112,219, "medium purple" },
{ 147,112,219, "MediumPurple" },
{ 216,191,216, "thistle" },
{ 255,250,250, "snow1" },
{ 238,233,233, "snow2" },
{ 205,201,201, "snow3" },
{ 139,137,137, "snow4" },
{ 255,245,238, "seashell1" },
{ 238,229,222, "seashell2" },
{ 205,197,191, "seashell3" },
{ 139,134,130, "seashell4" },
{ 255,239,219, "AntiqueWhite1" },
{ 238,223,204, "AntiqueWhite2" },
{ 205,192,176, "AntiqueWhite3" },
{ 139,131,120, "AntiqueWhite4" },
{ 255,228,196, "bisque1" },
{ 238,213,183, "bisque2" },
{ 205,183,158, "bisque3" },
{ 139,125,107, "bisque4" },
{ 255,218,185, "PeachPuff1" },
{ 238,203,173, "PeachPuff2" },
{ 205,175,149, "PeachPuff3" },
{ 139,119,101, "PeachPuff4" },
{ 255,222,173, "NavajoWhite1" },
{ 238,207,161, "NavajoWhite2" },
{ 205,179,139, "NavajoWhite3" },
{ 139,121, 94, "NavajoWhite4" },
{ 255,250,205, "LemonChiffon1" },
{ 238,233,191, "LemonChiffon2" },
{ 205,201,165, "LemonChiffon3" },
{ 139,137,112, "LemonChiffon4" },
{ 255,248,220, "cornsilk1" },
{ 238,232,205, "cornsilk2" },
{ 205,200,177, "cornsilk3" },
{ 139,136,120, "cornsilk4" },
{ 255,255,240, "ivory1" },
{ 238,238,224, "ivory2" },
{ 205,205,193, "ivory3" },
{ 139,139,131, "ivory4" },
{ 240,255,240, "honeydew1" },
{ 224,238,224, "honeydew2" },
{ 193,205,193, "honeydew3" },
{ 131,139,131, "honeydew4" },
{ 255,240,245, "LavenderBlush1" },
{ 238,224,229, "LavenderBlush2" },
{ 205,193,197, "LavenderBlush3" },
{ 139,131,134, "LavenderBlush4" },
{ 255,228,225, "MistyRose1" },
{ 238,213,210, "MistyRose2" },
{ 205,183,181, "MistyRose3" },
{ 139,125,123, "MistyRose4" },
{ 240,255,255, "azure1" },
{ 224,238,238, "azure2" },
{ 193,205,205, "azure3" },
{ 131,139,139, "azure4" },
{ 131,111,255, "SlateBlue1" },
{ 122,103,238, "SlateBlue2" },
{ 105, 89,205, "SlateBlue3" },
{ 71, 60,139, "SlateBlue4" },
{ 72,118,255, "RoyalBlue1" },
{ 67,110,238, "RoyalBlue2" },
{ 58, 95,205, "RoyalBlue3" },
{ 39, 64,139, "RoyalBlue4" },
{ 0, 0,255, "blue1" },
{ 0, 0,238, "blue2" },
{ 0, 0,205, "blue3" },
{ 0, 0,139, "blue4" },
{ 30,144,255, "DodgerBlue1" },
{ 28,134,238, "DodgerBlue2" },
{ 24,116,205, "DodgerBlue3" },
{ 16, 78,139, "DodgerBlue4" },
{ 99,184,255, "SteelBlue1" },
{ 92,172,238, "SteelBlue2" },
{ 79,148,205, "SteelBlue3" },
{ 54,100,139, "SteelBlue4" },
{ 0,191,255, "DeepSkyBlue1" },
{ 0,178,238, "DeepSkyBlue2" },
{ 0,154,205, "DeepSkyBlue3" },
{ 0,104,139, "DeepSkyBlue4" },
{ 135,206,255, "SkyBlue1" },
{ 126,192,238, "SkyBlue2" },
{ 108,166,205, "SkyBlue3" },
{ 74,112,139, "SkyBlue4" },
{ 176,226,255, "LightSkyBlue1" },
{ 164,211,238, "LightSkyBlue2" },
{ 141,182,205, "LightSkyBlue3" },
{ 96,123,139, "LightSkyBlue4" },
{ 198,226,255, "SlateGray1" },
{ 185,211,238, "SlateGray2" },
{ 159,182,205, "SlateGray3" },
{ 108,123,139, "SlateGray4" },
{ 202,225,255, "LightSteelBlue1" },
{ 188,210,238, "LightSteelBlue2" },
{ 162,181,205, "LightSteelBlue3" },
{ 110,123,139, "LightSteelBlue4" },
{ 191,239,255, "LightBlue1" },
{ 178,223,238, "LightBlue2" },
{ 154,192,205, "LightBlue3" },
{ 104,131,139, "LightBlue4" },
{ 224,255,255, "LightCyan1" },
{ 209,238,238, "LightCyan2" },
{ 180,205,205, "LightCyan3" },
{ 122,139,139, "LightCyan4" },
{ 187,255,255, "PaleTurquoise1" },
{ 174,238,238, "PaleTurquoise2" },
{ 150,205,205, "PaleTurquoise3" },
{ 102,139,139, "PaleTurquoise4" },
{ 152,245,255, "CadetBlue1" },
{ 142,229,238, "CadetBlue2" },
{ 122,197,205, "CadetBlue3" },
{ 83,134,139, "CadetBlue4" },
{ 0,245,255, "turquoise1" },
{ 0,229,238, "turquoise2" },
{ 0,197,205, "turquoise3" },
{ 0,134,139, "turquoise4" },
{ 0,255,255, "cyan1" },
{ 0,238,238, "cyan2" },
{ 0,205,205, "cyan3" },
{ 0,139,139, "cyan4" },
{ 151,255,255, "DarkSlateGray1" },
{ 141,238,238, "DarkSlateGray2" },
{ 121,205,205, "DarkSlateGray3" },
{ 82,139,139, "DarkSlateGray4" },
{ 127,255,212, "aquamarine1" },
{ 118,238,198, "aquamarine2" },
{ 102,205,170, "aquamarine3" },
{ 69,139,116, "aquamarine4" },
{ 193,255,193, "DarkSeaGreen1" },
{ 180,238,180, "DarkSeaGreen2" },
{ 155,205,155, "DarkSeaGreen3" },
{ 105,139,105, "DarkSeaGreen4" },
{ 84,255,159, "SeaGreen1" },
{ 78,238,148, "SeaGreen2" },
{ 67,205,128, "SeaGreen3" },
{ 46,139, 87, "SeaGreen4" },
{ 154,255,154, "PaleGreen1" },
{ 144,238,144, "PaleGreen2" },
{ 124,205,124, "PaleGreen3" },
{ 84,139, 84, "PaleGreen4" },
{ 0,255,127, "SpringGreen1" },
{ 0,238,118, "SpringGreen2" },
{ 0,205,102, "SpringGreen3" },
{ 0,139, 69, "SpringGreen4" },
{ 0,255, 0, "green1" },
{ 0,238, 0, "green2" },
{ 0,205, 0, "green3" },
{ 0,139, 0, "green4" },
{ 127,255, 0, "chartreuse1" },
{ 118,238, 0, "chartreuse2" },
{ 102,205, 0, "chartreuse3" },
{ 69,139, 0, "chartreuse4" },
{ 192,255, 62, "OliveDrab1" },
{ 179,238, 58, "OliveDrab2" },
{ 154,205, 50, "OliveDrab3" },
{ 105,139, 34, "OliveDrab4" },
{ 202,255,112, "DarkOliveGreen1" },
{ 188,238,104, "DarkOliveGreen2" },
{ 162,205, 90, "DarkOliveGreen3" },
{ 110,139, 61, "DarkOliveGreen4" },
{ 255,246,143, "khaki1" },
{ 238,230,133, "khaki2" },
{ 205,198,115, "khaki3" },
{ 139,134, 78, "khaki4" },
{ 255,236,139, "LightGoldenrod1" },
{ 238,220,130, "LightGoldenrod2" },
{ 205,190,112, "LightGoldenrod3" },
{ 139,129, 76, "LightGoldenrod4" },
{ 255,255,224, "LightYellow1" },
{ 238,238,209, "LightYellow2" },
{ 205,205,180, "LightYellow3" },
{ 139,139,122, "LightYellow4" },
{ 255,255, 0, "yellow1" },
{ 238,238, 0, "yellow2" },
{ 205,205, 0, "yellow3" },
{ 139,139, 0, "yellow4" },
{ 255,215, 0, "gold1" },
{ 238,201, 0, "gold2" },
{ 205,173, 0, "gold3" },
{ 139,117, 0, "gold4" },
{ 255,193, 37, "goldenrod1" },
{ 238,180, 34, "goldenrod2" },
{ 205,155, 29, "goldenrod3" },
{ 139,105, 20, "goldenrod4" },
{ 255,185, 15, "DarkGoldenrod1" },
{ 238,173, 14, "DarkGoldenrod2" },
{ 205,149, 12, "DarkGoldenrod3" },
{ 139,101, 8, "DarkGoldenrod4" },
{ 255,193,193, "RosyBrown1" },
{ 238,180,180, "RosyBrown2" },
{ 205,155,155, "RosyBrown3" },
{ 139,105,105, "RosyBrown4" },
{ 255,106,106, "IndianRed1" },
{ 238, 99, 99, "IndianRed2" },
{ 205, 85, 85, "IndianRed3" },
{ 139, 58, 58, "IndianRed4" },
{ 255,130, 71, "sienna1" },
{ 238,121, 66, "sienna2" },
{ 205,104, 57, "sienna3" },
{ 139, 71, 38, "sienna4" },
{ 255,211,155, "burlywood1" },
{ 238,197,145, "burlywood2" },
{ 205,170,125, "burlywood3" },
{ 139,115, 85, "burlywood4" },
{ 255,231,186, "wheat1" },
{ 238,216,174, "wheat2" },
{ 205,186,150, "wheat3" },
{ 139,126,102, "wheat4" },
{ 255,165, 79, "tan1" },
{ 238,154, 73, "tan2" },
{ 205,133, 63, "tan3" },
{ 139, 90, 43, "tan4" },
{ 255,127, 36, "chocolate1" },
{ 238,118, 33, "chocolate2" },
{ 205,102, 29, "chocolate3" },
{ 139, 69, 19, "chocolate4" },
{ 255, 48, 48, "firebrick1" },
{ 238, 44, 44, "firebrick2" },
{ 205, 38, 38, "firebrick3" },
{ 139, 26, 26, "firebrick4" },
{ 255, 64, 64, "brown1" },
{ 238, 59, 59, "brown2" },
{ 205, 51, 51, "brown3" },
{ 139, 35, 35, "brown4" },
{ 255,140,105, "salmon1" },
{ 238,130, 98, "salmon2" },
{ 205,112, 84, "salmon3" },
{ 139, 76, 57, "salmon4" },
{ 255,160,122, "LightSalmon1" },
{ 238,149,114, "LightSalmon2" },
{ 205,129, 98, "LightSalmon3" },
{ 139, 87, 66, "LightSalmon4" },
{ 255,165, 0, "orange1" },
{ 238,154, 0, "orange2" },
{ 205,133, 0, "orange3" },
{ 139, 90, 0, "orange4" },
{ 255,127, 0, "DarkOrange1" },
{ 238,118, 0, "DarkOrange2" },
{ 205,102, 0, "DarkOrange3" },
{ 139, 69, 0, "DarkOrange4" },
{ 255,114, 86, "coral1" },
{ 238,106, 80, "coral2" },
{ 205, 91, 69, "coral3" },
{ 139, 62, 47, "coral4" },
{ 255, 99, 71, "tomato1" },
{ 238, 92, 66, "tomato2" },
{ 205, 79, 57, "tomato3" },
{ 139, 54, 38, "tomato4" },
{ 255, 69, 0, "OrangeRed1" },
{ 238, 64, 0, "OrangeRed2" },
{ 205, 55, 0, "OrangeRed3" },
{ 139, 37, 0, "OrangeRed4" },
{ 255, 0, 0, "red1" },
{ 238, 0, 0, "red2" },
{ 205, 0, 0, "red3" },
{ 139, 0, 0, "red4" },
{ 255, 20,147, "DeepPink1" },
{ 238, 18,137, "DeepPink2" },
{ 205, 16,118, "DeepPink3" },
{ 139, 10, 80, "DeepPink4" },
{ 255,110,180, "HotPink1" },
{ 238,106,167, "HotPink2" },
{ 205, 96,144, "HotPink3" },
{ 139, 58, 98, "HotPink4" },
{ 255,181,197, "pink1" },
{ 238,169,184, "pink2" },
{ 205,145,158, "pink3" },
{ 139, 99,108, "pink4" },
{ 255,174,185, "LightPink1" },
{ 238,162,173, "LightPink2" },
{ 205,140,149, "LightPink3" },
{ 139, 95,101, "LightPink4" },
{ 255,130,171, "PaleVioletRed1" },
{ 238,121,159, "PaleVioletRed2" },
{ 205,104,137, "PaleVioletRed3" },
{ 139, 71, 93, "PaleVioletRed4" },
{ 255, 52,179, "maroon1" },
{ 238, 48,167, "maroon2" },
{ 205, 41,144, "maroon3" },
{ 139, 28, 98, "maroon4" },
{ 255, 62,150, "VioletRed1" },
{ 238, 58,140, "VioletRed2" },
{ 205, 50,120, "VioletRed3" },
{ 139, 34, 82, "VioletRed4" },
{ 255, 0,255, "magenta1" },
{ 238, 0,238, "magenta2" },
{ 205, 0,205, "magenta3" },
{ 139, 0,139, "magenta4" },
{ 255,131,250, "orchid1" },
{ 238,122,233, "orchid2" },
{ 205,105,201, "orchid3" },
{ 139, 71,137, "orchid4" },
{ 255,187,255, "plum1" },
{ 238,174,238, "plum2" },
{ 205,150,205, "plum3" },
{ 139,102,139, "plum4" },
{ 224,102,255, "MediumOrchid1" },
{ 209, 95,238, "MediumOrchid2" },
{ 180, 82,205, "MediumOrchid3" },
{ 122, 55,139, "MediumOrchid4" },
{ 191, 62,255, "DarkOrchid1" },
{ 178, 58,238, "DarkOrchid2" },
{ 154, 50,205, "DarkOrchid3" },
{ 104, 34,139, "DarkOrchid4" },
{ 155, 48,255, "purple1" },
{ 145, 44,238, "purple2" },
{ 125, 38,205, "purple3" },
{ 85, 26,139, "purple4" },
{ 171,130,255, "MediumPurple1" },
{ 159,121,238, "MediumPurple2" },
{ 137,104,205, "MediumPurple3" },
{ 93, 71,139, "MediumPurple4" },
{ 255,225,255, "thistle1" },
{ 238,210,238, "thistle2" },
{ 205,181,205, "thistle3" },
{ 139,123,139, "thistle4" },
{ 0, 0, 0, "gray0" },
{ 0, 0, 0, "grey0" },
{ 3, 3, 3, "gray1" },
{ 3, 3, 3, "grey1" },
{ 5, 5, 5, "gray2" },
{ 5, 5, 5, "grey2" },
{ 8, 8, 8, "gray3" },
{ 8, 8, 8, "grey3" },
{ 10, 10, 10, "gray4" },
{ 10, 10, 10, "grey4" },
{ 13, 13, 13, "gray5" },
{ 13, 13, 13, "grey5" },
{ 15, 15, 15, "gray6" },
{ 15, 15, 15, "grey6" },
{ 18, 18, 18, "gray7" },
{ 18, 18, 18, "grey7" },
{ 20, 20, 20, "gray8" },
{ 20, 20, 20, "grey8" },
{ 23, 23, 23, "gray9" },
{ 23, 23, 23, "grey9" },
{ 26, 26, 26, "gray10" },
{ 26, 26, 26, "grey10" },
{ 28, 28, 28, "gray11" },
{ 28, 28, 28, "grey11" },
{ 31, 31, 31, "gray12" },
{ 31, 31, 31, "grey12" },
{ 33, 33, 33, "gray13" },
{ 33, 33, 33, "grey13" },
{ 36, 36, 36, "gray14" },
{ 36, 36, 36, "grey14" },
{ 38, 38, 38, "gray15" },
{ 38, 38, 38, "grey15" },
{ 41, 41, 41, "gray16" },
{ 41, 41, 41, "grey16" },
{ 43, 43, 43, "gray17" },
{ 43, 43, 43, "grey17" },
{ 46, 46, 46, "gray18" },
{ 46, 46, 46, "grey18" },
{ 48, 48, 48, "gray19" },
{ 48, 48, 48, "grey19" },
{ 51, 51, 51, "gray20" },
{ 51, 51, 51, "grey20" },
{ 54, 54, 54, "gray21" },
{ 54, 54, 54, "grey21" },
{ 56, 56, 56, "gray22" },
{ 56, 56, 56, "grey22" },
{ 59, 59, 59, "gray23" },
{ 59, 59, 59, "grey23" },
{ 61, 61, 61, "gray24" },
{ 61, 61, 61, "grey24" },
{ 64, 64, 64, "gray25" },
{ 64, 64, 64, "grey25" },
{ 66, 66, 66, "gray26" },
{ 66, 66, 66, "grey26" },
{ 69, 69, 69, "gray27" },
{ 69, 69, 69, "grey27" },
{ 71, 71, 71, "gray28" },
{ 71, 71, 71, "grey28" },
{ 74, 74, 74, "gray29" },
{ 74, 74, 74, "grey29" },
{ 77, 77, 77, "gray30" },
{ 77, 77, 77, "grey30" },
{ 79, 79, 79, "gray31" },
{ 79, 79, 79, "grey31" },
{ 82, 82, 82, "gray32" },
{ 82, 82, 82, "grey32" },
{ 84, 84, 84, "gray33" },
{ 84, 84, 84, "grey33" },
{ 87, 87, 87, "gray34" },
{ 87, 87, 87, "grey34" },
{ 89, 89, 89, "gray35" },
{ 89, 89, 89, "grey35" },
{ 92, 92, 92, "gray36" },
{ 92, 92, 92, "grey36" },
{ 94, 94, 94, "gray37" },
{ 94, 94, 94, "grey37" },
{ 97, 97, 97, "gray38" },
{ 97, 97, 97, "grey38" },
{ 99, 99, 99, "gray39" },
{ 99, 99, 99, "grey39" },
{ 102,102,102, "gray40" },
{ 102,102,102, "grey40" },
{ 105,105,105, "gray41" },
{ 105,105,105, "grey41" },
{ 107,107,107, "gray42" },
{ 107,107,107, "grey42" },
{ 110,110,110, "gray43" },
{ 110,110,110, "grey43" },
{ 112,112,112, "gray44" },
{ 112,112,112, "grey44" },
{ 115,115,115, "gray45" },
{ 115,115,115, "grey45" },
{ 117,117,117, "gray46" },
{ 117,117,117, "grey46" },
{ 120,120,120, "gray47" },
{ 120,120,120, "grey47" },
{ 122,122,122, "gray48" },
{ 122,122,122, "grey48" },
{ 125,125,125, "gray49" },
{ 125,125,125, "grey49" },
{ 127,127,127, "gray50" },
{ 127,127,127, "grey50" },
{ 130,130,130, "gray51" },
{ 130,130,130, "grey51" },
{ 133,133,133, "gray52" },
{ 133,133,133, "grey52" },
{ 135,135,135, "gray53" },
{ 135,135,135, "grey53" },
{ 138,138,138, "gray54" },
{ 138,138,138, "grey54" },
{ 140,140,140, "gray55" },
{ 140,140,140, "grey55" },
{ 143,143,143, "gray56" },
{ 143,143,143, "grey56" },
{ 145,145,145, "gray57" },
{ 145,145,145, "grey57" },
{ 148,148,148, "gray58" },
{ 148,148,148, "grey58" },
{ 150,150,150, "gray59" },
{ 150,150,150, "grey59" },
{ 153,153,153, "gray60" },
{ 153,153,153, "grey60" },
{ 156,156,156, "gray61" },
{ 156,156,156, "grey61" },
{ 158,158,158, "gray62" },
{ 158,158,158, "grey62" },
{ 161,161,161, "gray63" },
{ 161,161,161, "grey63" },
{ 163,163,163, "gray64" },
{ 163,163,163, "grey64" },
{ 166,166,166, "gray65" },
{ 166,166,166, "grey65" },
{ 168,168,168, "gray66" },
{ 168,168,168, "grey66" },
{ 171,171,171, "gray67" },
{ 171,171,171, "grey67" },
{ 173,173,173, "gray68" },
{ 173,173,173, "grey68" },
{ 176,176,176, "gray69" },
{ 176,176,176, "grey69" },
{ 179,179,179, "gray70" },
{ 179,179,179, "grey70" },
{ 181,181,181, "gray71" },
{ 181,181,181, "grey71" },
{ 184,184,184, "gray72" },
{ 184,184,184, "grey72" },
{ 186,186,186, "gray73" },
{ 186,186,186, "grey73" },
{ 189,189,189, "gray74" },
{ 189,189,189, "grey74" },
{ 191,191,191, "gray75" },
{ 191,191,191, "grey75" },
{ 194,194,194, "gray76" },
{ 194,194,194, "grey76" },
{ 196,196,196, "gray77" },
{ 196,196,196, "grey77" },
{ 199,199,199, "gray78" },
{ 199,199,199, "grey78" },
{ 201,201,201, "gray79" },
{ 201,201,201, "grey79" },
{ 204,204,204, "gray80" },
{ 204,204,204, "grey80" },
{ 207,207,207, "gray81" },
{ 207,207,207, "grey81" },
{ 209,209,209, "gray82" },
{ 209,209,209, "grey82" },
{ 212,212,212, "gray83" },
{ 212,212,212, "grey83" },
{ 214,214,214, "gray84" },
{ 214,214,214, "grey84" },
{ 217,217,217, "gray85" },
{ 217,217,217, "grey85" },
{ 219,219,219, "gray86" },
{ 219,219,219, "grey86" },
{ 222,222,222, "gray87" },
{ 222,222,222, "grey87" },
{ 224,224,224, "gray88" },
{ 224,224,224, "grey88" },
{ 227,227,227, "gray89" },
{ 227,227,227, "grey89" },
{ 229,229,229, "gray90" },
{ 229,229,229, "grey90" },
{ 232,232,232, "gray91" },
{ 232,232,232, "grey91" },
{ 235,235,235, "gray92" },
{ 235,235,235, "grey92" },
{ 237,237,237, "gray93" },
{ 237,237,237, "grey93" },
{ 240,240,240, "gray94" },
{ 240,240,240, "grey94" },
{ 242,242,242, "gray95" },
{ 242,242,242, "grey95" },
{ 245,245,245, "gray96" },
{ 245,245,245, "grey96" },
{ 247,247,247, "gray97" },
{ 247,247,247, "grey97" },
{ 250,250,250, "gray98" },
{ 250,250,250, "grey98" },
{ 252,252,252, "gray99" },
{ 252,252,252, "grey99" },
{ 255,255,255, "gray100" },
{ 255,255,255, "grey100" },
{ 169,169,169, "dark grey" },
{ 169,169,169, "DarkGrey" },
{ 169,169,169, "dark gray" },
{ 169,169,169, "DarkGray" },
{ 0, 0,139, "dark blue" },
{ 0, 0,139, "DarkBlue" },
{ 0,139,139, "dark cyan" },
{ 0,139,139, "DarkCyan" },
{ 139, 0,139, "dark magenta" },
{ 139, 0,139, "DarkMagenta" },
{ 139, 0, 0, "dark red" },
{ 139, 0, 0, "DarkRed" },
{ 144,238,144, "light green" },
{ 144,238,144, "LightGreen" },
{ 0, 0, 0, NULL }
};
/******************/
/* Implementation */
/******************/
/********************************************************/
/* This routine tries to allocate a biggest possible */
/* color cube (used only on 8 bit pseudo color visuals) */
/* Shamelessly ripped from colormaps.c by S&P. */
/* I'm not sure if I'm going to use this or not. */
/********************************************************/
int gck_allocate_color_cube(GckVisualInfo * visinfo, int red, int green, int blue)
{
int init_r, init_g, init_b;
int total;
int success;
g_assert(visinfo!=NULL);
init_r = red;
init_g = green;
init_b = blue;
/* First, reduce number of total colors to fit a 8 bit LUT */
/* ======================================================= */
total = red * green * blue + RESERVED_COLORS;
while (total > 256)
{
if (blue >= red && blue >= green)
blue--;
else if (red >= green && red >= blue)
red--;
else
green--;
total = red * green * blue + RESERVED_COLORS;
}
/* Now, attempt to allocate the colors. If no success, reduce the */
/* color cube resolution and try again. */
/* ============================================================== */
success = gdk_colors_alloc(visinfo->colormap, 0, NULL, 0, visinfo->allocedpixels, total);
while (!success)
{
if (blue >= red && blue >= green)
blue--;
else if (red >= green && red >= blue)
red--;
else
green--;
total = red * green * blue + RESERVED_COLORS;
if (red <= 2 || green <= 2 || blue <= 2)
success = 1;
else
success = gdk_colors_alloc(visinfo->colormap, 0, NULL, 0, visinfo->allocedpixels, total);
}
/* If any shades value has been reduced to nothing, return error flag */
/* ================================================================== */
if (red > 1 && green > 1 && blue > 1)
{
success=TRUE;
visinfo->shades_r = red;
visinfo->shades_g = green;
visinfo->shades_b = blue;
visinfo->numcolors = total;
}
else success=FALSE;
return(success);
}
/**************************************************/
/* Create 8 bit RGB color cube. Also more or less */
/* ripped from colormaps.c by S&P. */
/**************************************************/
void gck_create_8bit_rgb(GckVisualInfo * visinfo)
{
unsigned int r, g, b;
unsigned int dr, dg, db;
int i = RESERVED_COLORS;
g_assert(visinfo!=NULL);
dr = (visinfo->shades_r > 1) ? (visinfo->shades_r - 1) : (1);
dg = (visinfo->shades_g > 1) ? (visinfo->shades_g - 1) : (1);
db = (visinfo->shades_b > 1) ? (visinfo->shades_b - 1) : (1);
for (r = 0; r < visinfo->shades_r; r++)
for (g = 0; g < visinfo->shades_g; g++)
for (b = 0; b < visinfo->shades_b; b++)
{
visinfo->colorcube[i] = visinfo->allocedpixels[i];
visinfo->rgbpalette[i].red = (guint) ROUND_TO_INT(255.0 * (double)(r * visinfo->visual->colormap_size) / (double)dr);
visinfo->rgbpalette[i].green = (guint) ROUND_TO_INT(255.0 * (double)(g * visinfo->visual->colormap_size) / (double)dg);
visinfo->rgbpalette[i].blue = (guint) ROUND_TO_INT(255.0 * (double)(b * visinfo->visual->colormap_size) / (double)db);
visinfo->rgbpalette[i].pixel = visinfo->allocedpixels[i];
visinfo->indextab[r][g][b] = (guchar) visinfo->allocedpixels[i];
i++;
}
/* Set up mapping tables */
/* ===================== */
for (i = 0; i < 256; i++)
{
visinfo->map_r[i] = (int)ROUND_TO_INT(((double)(visinfo->shades_r - 1) * ((double)i / 255.0)));
visinfo->map_g[i] = (int)ROUND_TO_INT(((double)(visinfo->shades_g - 1) * ((double)i / 255.0)));
visinfo->map_b[i] = (int)ROUND_TO_INT(((double)(visinfo->shades_b - 1) * ((double)i / 255.0)));
visinfo->invmap_r[i] = (double)visinfo->map_r[i]*(255.0/(double)(visinfo->shades_r - 1));
visinfo->invmap_g[i] = (double)visinfo->map_g[i]*(255.0/(double)(visinfo->shades_g - 1));
visinfo->invmap_b[i] = (double)visinfo->map_b[i]*(255.0/(double)(visinfo->shades_b - 1));
}
/* Create reserved colors */
/* ====================== */
visinfo->rgbpalette[0].red = 0;
visinfo->rgbpalette[0].green = 0;
visinfo->rgbpalette[0].blue = 0;
visinfo->rgbpalette[0].pixel = visinfo->allocedpixels[0];
visinfo->rgbpalette[1].red = 65535;
visinfo->rgbpalette[1].green = 65535;
visinfo->rgbpalette[1].blue = 65535;
visinfo->rgbpalette[1].pixel = visinfo->allocedpixels[1];
}
/**********************************/
/* Get visual and create colormap */
/**********************************/
GckVisualInfo *gck_visualinfo_new(void)
{
GckVisualInfo *visinfo;
visinfo = (GckVisualInfo *) g_malloc(sizeof(GckVisualInfo));
if (visinfo!=NULL)
{
visinfo->visual = gdk_visual_get_best();
visinfo->colormap = gdk_colormap_new(visinfo->visual, FALSE);
visinfo->dithermethod = DITHER_FLOYD_STEINBERG;
if (visinfo->visual->type == GDK_VISUAL_PSEUDO_COLOR)
{
/* Allocate colormap and create RGB map */
/* ==================================== */
if (gck_allocate_color_cube(visinfo, 6, 6, 6) == TRUE)
{
gck_create_8bit_rgb(visinfo);
gdk_colors_store(visinfo->colormap, visinfo->rgbpalette, visinfo->numcolors);
}
else
{
g_free(visinfo);
visinfo = NULL;
}
}
}
return (visinfo);
}
/***********************************************************/
/* Free memory associated with the GckVisualInfo structure */
/***********************************************************/
void gck_visualinfo_destroy(GckVisualInfo * visinfo)
{
g_assert(visinfo!=NULL);
gdk_colormap_unref(visinfo->colormap);
g_free(visinfo);
}
/*************************************************/
/* This converts from TrueColor RGB (24bpp) to */
/* whatever format the visual of our image uses. */
/*************************************************/
GckDitherType gck_visualinfo_get_dither(GckVisualInfo * visinfo)
{
g_assert(visinfo!=NULL);
return (visinfo->dithermethod);
}
void gck_visualinfo_set_dither(GckVisualInfo * visinfo, GckDitherType method)
{
g_assert(visinfo!=NULL);
visinfo->dithermethod = method;
}
/*******************/
/* GdkGC functions */
/*******************/
void gck_gc_set_foreground(GckVisualInfo *visinfo,GdkGC *gc,
guchar r, guchar g, guchar b)
{
g_assert(visinfo!=NULL);
g_assert(gc!=NULL);
gdk_gc_set_foreground(gc, gck_rgb_to_gdkcolor(visinfo,r,g,b));
}
void gck_gc_set_background(GckVisualInfo *visinfo,GdkGC *gc,
guchar r, guchar g, guchar b)
{
g_assert(visinfo!=NULL);
g_assert(gc!=NULL);
gdk_gc_set_background(gc, gck_rgb_to_gdkcolor(visinfo,r,g,b));
}
/*************************************************/
/* RGB to 8 bpp pseudocolor (indexed) functions. */
/*************************************************/
/*
* Non-reentrant function - GdkColor is a static storage
*/
static GdkColor *
gck_rgb_to_color8(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
static GdkColor color;
gint index;
g_assert(visinfo!=NULL);
r = visinfo->map_r[r];
g = visinfo->map_g[g];
b = visinfo->map_b[b];
index = visinfo->indextab[r][g][b];
color=visinfo->rgbpalette[index];
return (&color);
}
/*
* Reentrant function - GdkColor will be malloc'ed
*/
static GdkColor *
gck_rgb_to_color8_r(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
gint index;
GdkColor *color;
g_assert(visinfo!=NULL);
color=(GdkColor *)g_malloc(sizeof(GdkColor));
if (color==NULL)
return(NULL);
r = visinfo->map_r[r];
g = visinfo->map_g[g];
b = visinfo->map_b[b];
index = visinfo->indextab[r][g][b];
*color=visinfo->rgbpalette[index];
return (color);
}
/***************************************************/
/* RGB to 8 bpp pseudocolor using error-diffusion */
/* dithering using the weights proposed by Floyd */
/* and Steinberg (aka "Floyd-Steinberg dithering") */
/***************************************************/
static void
gck_rgb_to_image8_fs_dither(GckVisualInfo * visinfo, guchar * RGB_data, GdkImage * image,
int width, int height)
{
guchar *imagedata;
gint or, og, ob, mr, mg, mb, dr, dg, db;
gint *row1, *row2, *temp, rowcnt;
int xcnt, ycnt, diffx;
long count = 0, rowsize;
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
/* Allocate memory for FS errors */
/* ============================= */
rowsize = 3 * width;
row1 = (gint *) g_malloc(sizeof(gint) * (size_t) rowsize);
row2 = (gint *) g_malloc(sizeof(gint) * (size_t) rowsize);
/* Initialize to zero */
/* ================== */
memset(row1, 0, 3 * sizeof(gint) * width);
memset(row2, 0, 3 * sizeof(gint) * width);
if (width < image->width)
diffx = image->width - width;
else
diffx = 0;
if (image->width < width)
width = image->width;
if (image->height < height)
height = image->height;
imagedata = (guchar *) image->mem;
for (ycnt = 0; ycnt < height; ycnt++)
{
/* It's rec. to move from left to right on even */
/* rows and right to left on odd rows, so we do. */
/* ============================================= */
if ((ycnt % 1) == 0)
{
rowcnt = 0;
for (xcnt = 0; xcnt < width; xcnt++)
{
/* Get exact (original) value */
/* ========================== */
or = (gint) RGB_data[count + rowcnt];
og = (gint) RGB_data[count + rowcnt + 1];
ob = (gint) RGB_data[count + rowcnt + 2];
/* Extract and add the accumulated error for this pixel */
/* ==================================================== */
or = or + (row1[rowcnt] >> 4);
og = og + (row1[rowcnt + 1] >> 4);
ob = ob + (row1[rowcnt + 2] >> 4);
/* Make sure we don't run into an under- or overflow */
/* ================================================= */
if (or > 255)
or = 255;
else if (or < 0)
or = 0;
if (og > 255)
og = 255;
else if (og < 0)
og = 0;
if (ob > 255)
ob = 255;
else if (ob < 0)
ob = 0;
/* Compute difference */
/* ================== */
dr = or - (gint) visinfo->invmap_r[or];
dg = og - (gint) visinfo->invmap_g[og];
db = ob - (gint) visinfo->invmap_b[ob];
/* Spread the error to the neighboring pixels. */
/* We use the weights proposed by Floyd-Steinberg */
/* for 3x3 neighborhoods (1*, 3*, 5* and 7*1/16). */
/* ============================================== */
if (xcnt < width - 1)
{
row1[(rowcnt + 3)] += 7 * (gint) dr;
row1[(rowcnt + 3) + 1] += 7 * (gint) dg;
row1[(rowcnt + 3) + 2] += 7 * (gint) db;
if (ycnt < height - 1)
{
row2[(rowcnt + 3)] += (gint) dr;
row2[(rowcnt + 3) + 1] += (gint) dg;
row2[(rowcnt + 3) + 2] += (gint) db;
}
}
if (xcnt > 0 && ycnt < height - 1)
{
row2[(rowcnt - 3)] += 3 * (gint) dr;
row2[(rowcnt - 3) + 1] += 3 * (gint) dg;
row2[(rowcnt - 3) + 2] += 3 * (gint) db;
row2[rowcnt] += 5 * (gint) dr;
row2[rowcnt + 1] += 5 * (gint) dg;
row2[rowcnt + 2] += 5 * (gint) db;
}
/* Clear the errorvalues of the processed row */
/* ========================================== */
row1[rowcnt] = row1[rowcnt + 1] = row1[rowcnt + 2] = 0;
/* Map RGB values to color cube and write pixel */
/* ============================================ */
mr = visinfo->map_r[(guchar) or];
mg = visinfo->map_g[(guchar) og];
mb = visinfo->map_b[(guchar) ob];
imagedata[xcnt] = visinfo->indextab[mr][mg][mb];
rowcnt += 3;
}
}
else
{
rowcnt = rowsize - 3;
for (xcnt = width - 1; xcnt >= 0; xcnt--)
{
/* Same as above but in the other direction */
/* ======================================== */
or = (gint) RGB_data[count + rowcnt];
og = (gint) RGB_data[count + rowcnt + 1];
ob = (gint) RGB_data[count + rowcnt + 2];
or = or + (row1[rowcnt] >> 4);
og = og + (row1[rowcnt + 1] >> 4);
ob = ob + (row1[rowcnt + 2] >> 4);
if (or > 255)
or = 255;
else if (or < 0)
or = 0;
if (og > 255)
og = 255;
else if (og < 0)
og = 0;
if (ob > 255)
ob = 255;
else if (ob < 0)
ob = 0;
dr = or - (gint) visinfo->invmap_r[or];
dg = og - (gint) visinfo->invmap_g[og];
db = ob - (gint) visinfo->invmap_b[ob];
if (xcnt > 0)
{
row1[(rowcnt - 3)] += 7 * (gint) dr;
row1[(rowcnt - 3) + 1] += 7 * (gint) dg;
row1[(rowcnt - 3) + 2] += 7 * (gint) db;
if (ycnt < height - 1)
{
row2[(rowcnt - 3)] += (gint) dr;
row2[(rowcnt - 3) + 1] += (gint) dg;
row2[(rowcnt - 3) + 2] += (gint) db;
}
}
if (xcnt < width - 1 && ycnt < height - 1)
{
row2[(rowcnt + 3)] += 3 * (gint) dr;
row2[(rowcnt + 3) + 1] += 3 * (gint) dg;
row2[(rowcnt + 3) + 2] += 3 * (gint) db;
row2[rowcnt] += 5 * (gint) dr;
row2[rowcnt + 1] += 5 * (gint) dg;
row2[rowcnt + 2] += 5 * (gint) db;
}
row1[rowcnt] = row1[rowcnt + 1] = row1[rowcnt + 2] = 0;
mr = visinfo->map_r[(guchar) or];
mg = visinfo->map_g[(guchar) og];
mb = visinfo->map_b[(guchar) ob];
imagedata[xcnt] = visinfo->indextab[mr][mg][mb];
rowcnt -= 3;
}
}
/* We're finished with this row, swap row-pointers */
/* =============================================== */
temp = row1;
row1 = row2;
row2 = temp;
imagedata += width + diffx;
count += rowsize;
}
g_free(row1);
g_free(row2);
}
/***********************************************************/
/* Plain (no dithering) RGB to 8 bpp pseudocolor (indexed) */
/***********************************************************/
static void
gck_rgb_to_image8(GckVisualInfo * visinfo,
guchar * RGB_data,
GdkImage * image,
int width, int height)
{
guchar *imagedata, r, g, b;
int xcnt, ycnt, diffx;
long count = 0;
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
if (width < image->width)
diffx = image->width - width;
else
diffx = 0;
imagedata = (guchar *) image->mem;
for (ycnt = 0; ycnt < height; ycnt++)
{
for (xcnt = 0; xcnt < width; xcnt++)
{
if (xcnt < image->width && ycnt < image->height)
{
r = RGB_data[count];
g = RGB_data[count + 1];
b = RGB_data[count + 2];
r = visinfo->map_r[r];
g = visinfo->map_g[g];
b = visinfo->map_b[b];
*imagedata = visinfo->indextab[r][g][b];
imagedata++;
}
count += 3;
}
imagedata += diffx;
}
}
/************************************/
/* RGB to 16/15 bpp RGB ("HiColor") */
/************************************/
/*
* Non-reentrant function - GdkColor is a static storage
*/
static GdkColor *
gck_rgb_to_color16(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
static GdkColor color;
guint32 red, green, blue;
g_assert(visinfo!=NULL);
color.red = ((guint16) r) << 8;
color.green = ((guint16) g) << 8;
color.blue = ((guint16) b) << 8;
red = ((guint32) r) >> (8 - visinfo->visual->red_prec);
green = ((guint32) g) >> (8 - visinfo->visual->green_prec);
blue = ((guint32) b) >> (8 - visinfo->visual->blue_prec);
red = red << visinfo->visual->red_shift;
green = green << visinfo->visual->green_shift;
blue = blue << visinfo->visual->blue_shift;
color.pixel = red | green | blue;
return (&color);
}
/*
* Reentrant function - GdkColor will be malloc'ed
*/
static GdkColor *
gck_rgb_to_color16_r(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
guint32 red, green, blue;
GdkColor *color;
g_assert(visinfo!=NULL);
color=(GdkColor *)g_malloc(sizeof(GdkColor));
if (color==NULL)
return(NULL);
color->red = ((guint16) r) << 8;
color->green = ((guint16) g) << 8;
color->blue = ((guint16) b) << 8;
red = ((guint32) r) >> (8 - visinfo->visual->red_prec);
green = ((guint32) g) >> (8 - visinfo->visual->green_prec);
blue = ((guint32) b) >> (8 - visinfo->visual->blue_prec);
red = red << visinfo->visual->red_shift;
green = green << visinfo->visual->green_shift;
blue = blue << visinfo->visual->blue_shift;
color->pixel = red | green | blue;
return (color);
}
/***************************************************/
/* RGB to 16 bpp truecolor using error-diffusion */
/* dithering using the weights proposed by Floyd */
/* and Steinberg (aka "Floyd-Steinberg dithering") */
/***************************************************/
static void
gck_rgb_to_image16_fs_dither(GckVisualInfo * visinfo,
guchar * RGB_data,
GdkImage * image,
int width, int height)
{
guint16 *imagedata, pixel;
gint16 or, og, ob, dr, dg, db;
gint16 *row1, *row2, *temp, rowcnt, rmask, gmask, bmask;
int xcnt, ycnt, diffx;
long count = 0, rowsize;
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
/* Allocate memory for FS errors */
/* ============================= */
rowsize = 3 * width;
row1 = (gint16 *) g_malloc(sizeof(gint16) * (size_t) rowsize);
row2 = (gint16 *) g_malloc(sizeof(gint16) * (size_t) rowsize);
/* Initialize to zero */
/* ================== */
memset(row1, 0, 3 * sizeof(gint16) * width);
memset(row2, 0, 3 * sizeof(gint16) * width);
if (width < image->width)
diffx = image->width - width;
else
diffx = 0;
if (image->width < width)
width = image->width;
if (image->height < height)
height = image->height;
rmask = (0xff << (8 - visinfo->visual->red_prec)) & 0xff;
gmask = (0xff << (8 - visinfo->visual->green_prec)) & 0xff;
bmask = (0xff << (8 - visinfo->visual->blue_prec)) & 0xff;
imagedata = (guint16 *) image->mem;
for (ycnt = 0; ycnt < height; ycnt++)
{
/* It is rec. to move from left to right on even */
/* rows and right to left on odd rows, so we do. */
/* ============================================= */
if ((ycnt % 1) == 0)
{
rowcnt = 0;
for (xcnt = 0; xcnt < width; xcnt++)
{
/* Get exact (original) value */
/* ========================== */
pixel = 0;
or = (gint) RGB_data[count + rowcnt];
og = (gint) RGB_data[count + rowcnt + 1];
ob = (gint) RGB_data[count + rowcnt + 2];
/* Extract and add the accumulated error for this pixel */
/* ==================================================== */
or = or + (row1[rowcnt] >> 4);
og = og + (row1[rowcnt + 1] >> 4);
ob = ob + (row1[rowcnt + 2] >> 4);
/* Make sure we don't run into an under- or overflow */
/* ================================================= */
if (or > 255)
or = 255;
else if (or < 0)
or = 0;
if (og > 255)
og = 255;
else if (og < 0)
og = 0;
if (ob > 255)
ob = 255;
else if (ob < 0)
ob = 0;
/* Compute difference */
/* ================== */
dr = or - (or & rmask);
dg = og - (og & gmask);
db = ob - (ob & bmask);
/* Spread the error to the neighboring pixels. */
/* We use the weights proposed by Floyd-Steinberg */
/* for 3x3 neighborhoods (1*, 3*, 5* and 7*1/16). */
/* ============================================== */
if (xcnt < width - 1)
{
row1[(rowcnt + 3)] += 7 * (gint) dr;
row1[(rowcnt + 3) + 1] += 7 * (gint) dg;
row1[(rowcnt + 3) + 2] += 7 * (gint) db;
if (ycnt < height - 1)
{
row2[(rowcnt + 3)] += (gint) dr;
row2[(rowcnt + 3) + 1] += (gint) dg;
row2[(rowcnt + 3) + 2] += (gint) db;
}
}
if (xcnt > 0 && ycnt < height - 1)
{
row2[(rowcnt - 3)] += 3 * (gint) dr;
row2[(rowcnt - 3) + 1] += 3 * (gint) dg;
row2[(rowcnt - 3) + 2] += 3 * (gint) db;
row2[rowcnt] += 5 * (gint) dr;
row2[rowcnt + 1] += 5 * (gint) dg;
row2[rowcnt + 2] += 5 * (gint) db;
}
/* Clear the errorvalues of the processed row */
/* ========================================== */
row1[rowcnt] = row1[rowcnt + 1] = row1[rowcnt + 2] = 0;
or = or >> (8 - visinfo->visual->red_prec);
og = og >> (8 - visinfo->visual->green_prec);
ob = ob >> (8 - visinfo->visual->blue_prec);
or = or << visinfo->visual->red_shift;
og = og << visinfo->visual->green_shift;
ob = ob << visinfo->visual->blue_shift;
pixel = pixel | or | og | ob;
imagedata[xcnt] = pixel;
rowcnt += 3;
}
}
else
{
rowcnt = rowsize - 3;
for (xcnt = width - 1; xcnt >= 0; xcnt--)
{
/* Same as above but in the other direction */
/* ======================================== */
or = (gint) RGB_data[count + rowcnt];
og = (gint) RGB_data[count + rowcnt + 1];
ob = (gint) RGB_data[count + rowcnt + 2];
or = or + (row1[rowcnt] >> 4);
og = og + (row1[rowcnt + 1] >> 4);
ob = ob + (row1[rowcnt + 2] >> 4);
if (or > 255)
or = 255;
else if (or < 0)
or = 0;
if (og > 255)
og = 255;
else if (og < 0)
og = 0;
if (ob > 255)
ob = 255;
else if (ob < 0)
ob = 0;
dr = or - (or & rmask);
dg = og - (og & gmask);
db = ob - (ob & bmask);
if (xcnt > 0)
{
row1[(rowcnt - 3)] += 7 * (gint) dr;
row1[(rowcnt - 3) + 1] += 7 * (gint) dg;
row1[(rowcnt - 3) + 2] += 7 * (gint) db;
if (ycnt < height - 1)
{
row2[(rowcnt - 3)] += (gint) dr;
row2[(rowcnt - 3) + 1] += (gint) dg;
row2[(rowcnt - 3) + 2] += (gint) db;
}
}
if (xcnt < width - 1 && ycnt < height - 1)
{
row2[(rowcnt + 3)] += 3 * (gint) dr;
row2[(rowcnt + 3) + 1] += 3 * (gint) dg;
row2[(rowcnt + 3) + 2] += 3 * (gint) db;
row2[rowcnt] += 5 * (gint) dr;
row2[rowcnt + 1] += 5 * (gint) dg;
row2[rowcnt + 2] += 5 * (gint) db;
}
row1[rowcnt] = row1[rowcnt + 1] = row1[rowcnt + 2] = 0;
or = or >> (8 - visinfo->visual->red_prec);
og = og >> (8 - visinfo->visual->green_prec);
ob = ob >> (8 - visinfo->visual->blue_prec);
or = or << visinfo->visual->red_shift;
og = og << visinfo->visual->green_shift;
ob = ob << visinfo->visual->blue_shift;
pixel = pixel | or | og | ob;
imagedata[xcnt] = pixel;
rowcnt -= 3;
}
}
/* We're finished with this row, swap row-pointers */
/* =============================================== */
temp = row1;
row1 = row2;
row2 = temp;
imagedata += width + diffx;
count += rowsize;
}
g_free(row1);
g_free(row2);
}
static void
gck_rgb_to_image16(GckVisualInfo * visinfo,
guchar * RGB_data,
GdkImage * image,
int width, int height)
{
guint16 *imagedata, pixel, r, g, b;
int xcnt, ycnt, diffx;
long count = 0;
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
if (width < image->width)
diffx = image->width - width;
else
diffx = 0;
imagedata = (guint16 *) image->mem;
for (ycnt = 0; ycnt < height; ycnt++)
{
for (xcnt = 0; xcnt < width; xcnt++)
{
if (xcnt <= image->width && ycnt <= image->height)
{
pixel = 0;
r = ((guint16) RGB_data[count++]) >> (8 - visinfo->visual->red_prec);
g = ((guint16) RGB_data[count++]) >> (8 - visinfo->visual->green_prec);
b = ((guint16) RGB_data[count++]) >> (8 - visinfo->visual->blue_prec);
r = r << visinfo->visual->red_shift;
g = g << visinfo->visual->green_shift;
b = b << visinfo->visual->blue_shift;
pixel = pixel | r | g | b;
*imagedata = pixel;
imagedata++;
}
}
imagedata += diffx;
}
}
/************************/
/* RGB to RGB (sic!) :) */
/************************/
/*
* Non-reentrant function - GdkColor is a static storage
*/
static GdkColor *
gck_rgb_to_color24(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
static GdkColor color;
guint32 red, green, blue;
g_assert(visinfo!=NULL);
color.red = ((guint16) r) << 8;
color.green = ((guint16) g) << 8;
color.blue = ((guint16) b) << 8;
red = ((guint32) r << 16);
green = ((guint32) g) << 8;
blue = ((guint32) b);
color.pixel = red | green | blue;
return (&color);
}
/*
* Reentrant function - GdkColor will be malloc'ed
*/
static GdkColor *
gck_rgb_to_color24_r(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
guint32 red, green, blue;
GdkColor *color;
g_assert(visinfo!=NULL);
color=(GdkColor *)g_malloc(sizeof(GdkColor));
if (color==NULL)
return(NULL);
color->red = ((guint16) r) << 8;
color->green = ((guint16) g) << 8;
color->blue = ((guint16) b) << 8;
red = ((guint32) r << 16);
green = ((guint32) g) << 8;
blue = ((guint32) b);
color->pixel = red | green | blue;
return (color);
}
static void
gck_rgb_to_image24(GckVisualInfo * visinfo,
guchar * RGB_data,
GdkImage * image,
int width, int height)
{
guchar *imagedata;
int xcnt, ycnt, diffx;
long count = 0, count2 = 0;
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
if (width < image->width)
diffx = 3 * (image->width - width);
else
diffx = 0;
imagedata = (guchar *) image->mem;
for (ycnt = 0; ycnt < height; ycnt++)
{
for (xcnt = 0; xcnt < height; xcnt++)
{
if (xcnt < image->width && ycnt < image->height)
{
imagedata[count2++] = RGB_data[count + 2];
imagedata[count2++] = RGB_data[count + 1];
imagedata[count2++] = RGB_data[count];
}
count += 3;
}
count2 += diffx;
}
}
/***************/
/* RGB to RGBX */
/***************/
/*
* Non-reentrant function - GdkColor is a static storage
*/
static GdkColor *
gck_rgb_to_color32(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
static GdkColor color;
guint32 red, green, blue;
g_assert(visinfo!=NULL);
color.red = ((guint16) r) << 8;
color.green = ((guint16) g) << 8;
color.blue = ((guint16) b) << 8;
red = ((guint32) r) << 8;
green = ((guint32) g) << 16;
blue = ((guint32) b) << 24;
color.pixel = red | green | blue;
return (&color);
}
/*
* Reentrant function - GdkColor will be malloc'ed
*/
static GdkColor *
gck_rgb_to_color32_r(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
guint32 red, green, blue;
GdkColor *color;
g_assert(visinfo!=NULL);
color=(GdkColor *)g_malloc(sizeof(GdkColor));
if (color==NULL)
return(NULL);
color->red = ((guint16) r) << 8;
color->green = ((guint16) g) << 8;
color->blue = ((guint16) b) << 8;
red = ((guint32) r) << 8;
green = ((guint32) g) << 16;
blue = ((guint32) b) << 24;
color->pixel = red | green | blue;
return (color);
}
static void
gck_rgb_to_image32(GckVisualInfo * visinfo,
guchar * RGB_data,
GdkImage * image,
int width, int height)
{
guint32 *imagedata, pixel, r, g, b;
int xcnt, ycnt, diffx=0;
long count = 0;
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
if (width < image->width)
diffx = image->width - width;
imagedata = (guint32 *) image->mem;
for (ycnt = 0; ycnt < height; ycnt++)
{
for (xcnt = 0; xcnt < width; xcnt++)
{
if (xcnt < image->width && ycnt < image->height)
{
r = (guint32) RGB_data[count++];
g = (guint32) RGB_data[count++];
b = (guint32) RGB_data[count++];
/* changed to work on 32 bit displays */
r = r << 16;
g = g << 8;
b = b;
pixel = r | g | b;
*imagedata = pixel;
imagedata++;
}
}
imagedata += diffx;
}
}
/**************************/
/* Conversion dispatchers */
/**************************/
void gck_rgb_to_gdkimage(GckVisualInfo * visinfo,
guchar * RGB_data,
GdkImage * image,
int width, int height)
{
g_assert(visinfo!=NULL);
g_assert(RGB_data!=NULL);
g_assert(image!=NULL);
if (visinfo->visual->type == GDK_VISUAL_PSEUDO_COLOR)
{
if (visinfo->visual->depth == 8)
{
/* Standard 256 color display */
/* ========================== */
if (visinfo->dithermethod == DITHER_NONE)
gck_rgb_to_image8(visinfo, RGB_data, image, width, height);
else if (visinfo->dithermethod == DITHER_FLOYD_STEINBERG)
gck_rgb_to_image8_fs_dither(visinfo, RGB_data, image, width, height);
}
}
else if (visinfo->visual->type == GDK_VISUAL_TRUE_COLOR ||
visinfo->visual->type == GDK_VISUAL_DIRECT_COLOR)
{
if (visinfo->visual->depth == 15 || visinfo->visual->depth == 16)
{
/* HiColor modes */
/* ============= */
if (visinfo->dithermethod == DITHER_NONE)
gck_rgb_to_image16(visinfo, RGB_data, image, width, height);
else if (visinfo->dithermethod == DITHER_FLOYD_STEINBERG)
gck_rgb_to_image16_fs_dither(visinfo, RGB_data, image, width, height);
}
else if (visinfo->visual->depth == 24 && image->bpp==3)
{
/* Packed 24 bit mode */
/* ================== */
gck_rgb_to_image24(visinfo, RGB_data, image, width, height);
}
else if (visinfo->visual->depth == 32 || (visinfo->visual->depth == 24 && image->bpp==4))
{
/* 32 bpp mode */
/* =========== */
gck_rgb_to_image32(visinfo, RGB_data, image, width, height);
}
}
}
/*
* Non-reentrant function - GdkColor is a static storage
*/
GdkColor *gck_rgb_to_gdkcolor(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
GdkColor *color=NULL;
g_assert(visinfo!=NULL);
if (visinfo->visual->type == GDK_VISUAL_PSEUDO_COLOR)
{
if (visinfo->visual->depth == 8)
{
/* Standard 256 color display */
/* ========================== */
color=gck_rgb_to_color8(visinfo, r, g, b);
}
}
else if (visinfo->visual->type == GDK_VISUAL_TRUE_COLOR ||
visinfo->visual->type == GDK_VISUAL_DIRECT_COLOR)
{
if (visinfo->visual->depth == 15 || visinfo->visual->depth == 16)
{
/* HiColor modes */
/* ============= */
color=gck_rgb_to_color16(visinfo, r, g, b);
}
else if (visinfo->visual->depth == 24)
{
/* Normal 24 bit mode */
/* ================== */
color=gck_rgb_to_color24(visinfo, r, g, b);
}
else if (visinfo->visual->depth == 32)
{
/* 32 bpp mode */
/* =========== */
color=gck_rgb_to_color32(visinfo, r, g, b);
}
}
return (color);
}
/*
* Reentrant function - GdkColor will be malloc'ed
*/
GdkColor *gck_rgb_to_gdkcolor_r(GckVisualInfo * visinfo, guchar r, guchar g, guchar b)
{
GdkColor *color=NULL;
g_assert(visinfo!=NULL);
if (visinfo->visual->type == GDK_VISUAL_PSEUDO_COLOR)
{
if (visinfo->visual->depth == 8)
{
/* Standard 256 color display */
/* ========================== */
color=gck_rgb_to_color8_r(visinfo, r, g, b);
}
}
else if (visinfo->visual->type == GDK_VISUAL_TRUE_COLOR ||
visinfo->visual->type == GDK_VISUAL_DIRECT_COLOR)
{
if (visinfo->visual->depth == 15 || visinfo->visual->depth == 16)
{
/* HiColor modes */
/* ============= */
color=gck_rgb_to_color16_r(visinfo, r, g, b);
}
else if (visinfo->visual->depth == 24)
{
/* Normal 24 bit mode */
/* ================== */
color=gck_rgb_to_color24_r(visinfo, r, g, b);
}
else if (visinfo->visual->depth == 32)
{
/* 32 bpp mode */
/* =========== */
color=gck_rgb_to_color32_r(visinfo, r, g, b);
}
}
return (color);
}
/********************/
/* Color operations */
/********************/
/******************************************/
/* Bilinear interpolation stuff (Quartic) */
/******************************************/
double gck_bilinear(double x, double y, double *values)
{
double xx, yy, m0, m1;
g_assert(values!=NULL);
xx = fmod(x, 1.0);
yy = fmod(y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - xx) * values[0] + xx * values[1];
m1 = (1.0 - xx) * values[2] + xx * values[3];
return ((1.0 - yy) * m0 + yy * m1);
}
guchar gck_bilinear_8(double x, double y, guchar * values)
{
double xx, yy, m0, m1;
g_assert(values!=NULL);
xx = fmod(x, 1.0);
yy = fmod(y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - xx) * values[0] + xx * values[1];
m1 = (1.0 - xx) * values[2] + xx * values[3];
return ((guchar) ((1.0 - yy) * m0 + yy * m1));
}
guint16 gck_bilinear_16(double x, double y, guint16 * values)
{
double xx, yy, m0, m1;
g_assert(values!=NULL);
xx = fmod(x, 1.0);
yy = fmod(y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - xx) * values[0] + xx * values[1];
m1 = (1.0 - xx) * values[2] + xx * values[3];
return ((guint16) ((1.0 - yy) * m0 + yy * m1));
}
guint32 gck_bilinear_32(double x, double y, guint32 * values)
{
double xx, yy, m0, m1;
g_assert(values!=NULL);
xx = fmod(x, 1.0);
yy = fmod(y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - xx) * values[0] + xx * values[1];
m1 = (1.0 - xx) * values[2] + xx * values[3];
return ((guint32) ((1.0 - yy) * m0 + yy * m1));
}
GckRGB gck_bilinear_rgb(double x, double y, GckRGB *values)
{
double m0, m1;
double ix, iy;
GckRGB v;
g_assert(values!=NULL);
x = fmod(x, 1.0);
y = fmod(y, 1.0);
if (x < 0)
x += 1.0;
if (y < 0)
y += 1.0;
ix = 1.0 - x;
iy = 1.0 - y;
/* Red */
/* === */
m0 = ix * values[0].r + x * values[1].r;
m1 = ix * values[2].r + x * values[3].r;
v.r = iy * m0 + y * m1;
/* Green */
/* ===== */
m0 = ix * values[0].g + x * values[1].g;
m1 = ix * values[2].g + x * values[3].g;
v.g = iy * m0 + y * m1;
/* Blue */
/* ==== */
m0 = ix * values[0].b + x * values[1].b;
m1 = ix * values[2].b + x * values[3].b;
v.b = iy * m0 + y * m1;
return (v);
} /* bilinear */
GckRGB gck_bilinear_rgba(double x, double y, GckRGB *values)
{
double m0, m1;
double ix, iy;
GckRGB v;
g_assert(values!=NULL);
x = fmod(x, 1.0);
y = fmod(y, 1.0);
if (x < 0)
x += 1.0;
if (y < 0)
y += 1.0;
ix = 1.0 - x;
iy = 1.0 - y;
/* Red */
/* === */
m0 = ix * values[0].r + x * values[1].r;
m1 = ix * values[2].r + x * values[3].r;
v.r = iy * m0 + y * m1;
/* Green */
/* ===== */
m0 = ix * values[0].g + x * values[1].g;
m1 = ix * values[2].g + x * values[3].g;
v.g = iy * m0 + y * m1;
/* Blue */
/* ==== */
m0 = ix * values[0].b + x * values[1].b;
m1 = ix * values[2].b + x * values[3].b;
v.b = iy * m0 + y * m1;
/* Alpha */
/* ===== */
m0 = ix * values[0].a + x * values[1].a;
m1 = ix * values[2].a + x * values[3].a;
v.a = iy * m0 + y * m1;
return (v);
} /* bilinear */
/********************************/
/* Multiple channels operations */
/********************************/
void gck_rgb_add(GckRGB * p, GckRGB * q)
{
g_assert(p!=NULL);
g_assert(q!=NULL);
p->r = p->r + q->r;
p->g = p->g + q->g;
p->b = p->b + q->b;
}
void gck_rgb_sub(GckRGB * p, GckRGB * q)
{
g_assert(p!=NULL);
g_assert(q!=NULL);
p->r = p->r - q->r;
p->g = p->g - q->g;
p->b = p->b - q->b;
}
void gck_rgb_mul(GckRGB * p, double b)
{
g_assert(p!=NULL);
p->r = p->r * b;
p->g = p->g * b;
p->b = p->b * b;
}
double gck_rgb_dist(GckRGB * p, GckRGB * q)
{
g_assert(p!=NULL);
g_assert(q!=NULL);
return (fabs(p->r - q->r) + fabs(p->g - q->g) + fabs(p->b - q->b));
}
double gck_rgb_max(GckRGB * p)
{
double max;
g_assert(p!=NULL);
max = p->r;
if (p->g > max)
max = p->g;
if (p->b > max)
max = p->b;
return (max);
}
double gck_rgb_min(GckRGB * p)
{
double min;
g_assert(p!=NULL);
min=p->r;
if (p->g < min)
min = p->g;
if (p->b < min)
min = p->b;
return (min);
}
void gck_rgb_clamp(GckRGB * p)
{
g_assert(p!=NULL);
if (p->r > 1.0)
p->r = 1.0;
if (p->g > 1.0)
p->g = 1.0;
if (p->b > 1.0)
p->b = 1.0;
if (p->r < 0.0)
p->r = 0.0;
if (p->g < 0.0)
p->g = 0.0;
if (p->b < 0.0)
p->b = 0.0;
}
void gck_rgb_set(GckRGB * p, double r, double g, double b)
{
g_assert(p!=NULL);
p->r = r;
p->g = g;
p->b = b;
}
void gck_rgb_gamma(GckRGB * p, double gamma)
{
double ig;
g_assert(p!=NULL);
if (gamma != 0.0)
ig = 1.0 / gamma;
else
(ig = 0.0);
p->r = pow(p->r, ig);
p->g = pow(p->g, ig);
p->b = pow(p->b, ig);
}
void gck_rgba_add(GckRGB * p, GckRGB * q)
{
g_assert(p!=NULL);
g_assert(q!=NULL);
p->r = p->r + q->r;
p->g = p->g + q->g;
p->b = p->b + q->b;
p->a = p->a + q->a;
}
void gck_rgba_sub(GckRGB * p, GckRGB * q)
{
g_assert(p!=NULL);
g_assert(q!=NULL);
p->r = p->r - q->r;
p->g = p->g - q->g;
p->b = p->b - q->b;
p->a = p->a - q->a;
}
void gck_rgba_mul(GckRGB * p, double b)
{
g_assert(p!=NULL);
p->r = p->r * b;
p->g = p->g * b;
p->b = p->b * b;
p->a = p->a * b;
}
double gck_rgba_dist(GckRGB *p, GckRGB *q)
{
g_assert(p!=NULL);
g_assert(q!=NULL);
return (fabs(p->r - q->r) + fabs(p->g - q->g) +
fabs(p->b - q->b) + fabs(p->a - q->a));
}
/* These two are probably not needed */
double gck_rgba_max(GckRGB * p)
{
double max;
g_assert(p!=NULL);
max = p->r;
if (p->g > max)
max = p->g;
if (p->b > max)
max = p->b;
if (p->a > max)
max = p->a;
return (max);
}
double gck_rgba_min(GckRGB * p)
{
double min;
g_assert(p!=NULL);
min = p->r;
if (p->g < min)
min = p->g;
if (p->b < min)
min = p->b;
if (p->a < min)
min = p->a;
return (min);
}
void gck_rgba_clamp(GckRGB * p)
{
g_assert(p!=NULL);
if (p->r > 1.0)
p->r = 1.0;
if (p->g > 1.0)
p->g = 1.0;
if (p->b > 1.0)
p->b = 1.0;
if (p->a > 1.0)
p->a = 1.0;
if (p->r < 0.0)
p->r = 0.0;
if (p->g < 0.0)
p->g = 0.0;
if (p->b < 0.0)
p->b = 0.0;
if (p->a < 0.0)
p->a = 0.0;
}
void gck_rgba_set(GckRGB * p, double r, double g, double b, double a)
{
g_assert(p!=NULL);
p->r = r;
p->g = g;
p->b = b;
p->a = a;
}
/* This one is also not needed */
void gck_rgba_gamma(GckRGB * p, double gamma)
{
double ig;
g_assert(p!=NULL);
if (gamma != 0.0)
ig = 1.0 / gamma;
else
(ig = 0.0);
p->r = pow(p->r, ig);
p->g = pow(p->g, ig);
p->b = pow(p->b, ig);
p->a = pow(p->a, ig);
}
/**************************/
/* Colorspace conversions */
/**************************/
/***********************************************/
/* (Red,Green,Blue) <-> (Hue,Saturation,Value) */
/***********************************************/
void gck_rgb_to_hsv(GckRGB * p, double *h, double *s, double *v)
{
double max,min,delta;
g_assert(p!=NULL);
g_assert(h!=NULL);
g_assert(s!=NULL);
g_assert(v!=NULL);
max = gck_rgb_max(p);
min = gck_rgb_min(p);
*v = max;
if (max != 0.0)
{
*s = (max - min) / max;
}
else
*s = 0.0;
if (*s == 0.0)
*h = GCK_HSV_UNDEFINED;
else
{
delta = max - min;
if (p->r == max)
{
*h = (p->g - p->b) / delta;
}
else if (p->g == max)
{
*h = 2.0 + (p->b - p->r) / delta;
}
else if (p->b == max)
{
*h = 4.0 + (p->r - p->g) / delta;
}
*h = *h * 60.0;
if (*h < 0.0)
*h = *h + 360;
}
}
void gck_hsv_to_rgb(double h, double s, double v, GckRGB * p)
{
int i;
double f, w, q, t;
g_assert(p!=NULL);
if (s == 0.0)
{
if (h == GCK_HSV_UNDEFINED)
{
p->r = v;
p->g = v;
p->b = v;
}
}
else
{
if (h == 360.0)
h = 0.0;
h = h / 60.0;
i = (int)h;
f = h - i;
w = v * (1.0 - s);
q = v * (1.0 - (s * f));
t = v * (1.0 - (s * (1.0 - f)));
switch (i)
{
case 0:
p->r = v;
p->g = t;
p->b = w;
break;
case 1:
p->r = q;
p->g = v;
p->b = w;
break;
case 2:
p->r = w;
p->g = v;
p->b = t;
break;
case 3:
p->r = w;
p->g = q;
p->b = v;
break;
case 4:
p->r = t;
p->g = w;
p->b = v;
break;
case 5:
p->r = v;
p->g = w;
p->b = q;
break;
}
}
}
/***************************************************/
/* (Red,Green,Blue) <-> (Hue,Saturation,Lightness) */
/***************************************************/
void gck_rgb_to_hsl(GckRGB * p, double *h, double *s, double *l)
{
double max,min,delta;
g_assert(p!=NULL);
g_assert(h!=NULL);
g_assert(s!=NULL);
g_assert(l!=NULL);
max = gck_rgb_max(p);
min = gck_rgb_min(p);
*l = (max + min) / 2.0;
if (max == min)
{
*s = 0.0;
*h = GCK_HSL_UNDEFINED;
}
else
{
if (*l <= 0.5)
*s = (max - min) / (max + min);
else
*s = (max - min) / (2.0 - max - min);
delta = max - min;
if (p->r == max)
{
*h = (p->g - p->b) / delta;
}
else if (p->g == max)
{
*h = 2.0 + (p->b - p->r) / delta;
}
else if (p->b == max)
{
*h = 4.0 + (p->r - p->g) / delta;
}
*h = *h * 60.0;
if (*h < 0.0)
*h = *h + 360.0;
}
}
double _gck_value(double n1, double n2, double hue)
{
double val;
if (hue > 360.0)
hue = hue - 360.0;
else if (hue < 0.0)
hue = hue + 360.0;
if (hue < 60.0)
val = n1 + (n2 - n1) * hue / 60.0;
else if (hue < 180.0)
val = n2;
else if (hue < 240.0)
val = n1 + (n2 - n1) * (240.0 - hue) / 60.0;
else
val = n1;
return (val);
}
void gck_hsl_to_rgb(double h, double s, double l, GckRGB * p)
{
double m1, m2;
g_assert(p!=NULL);
if (l <= 0.5)
m2 = l * (l + s);
else
m2 = l + s + l * s;
m1 = 2.0 * l - m2;
if (s == 0)
{
if (h == GCK_HSV_UNDEFINED)
p->r = p->g = p->b = 1.0;
}
else
{
p->r = _gck_value(m1, m2, h + 120.0);
p->g = _gck_value(m1, m2, h);
p->b = _gck_value(m1, m2, h - 120.0);
}
}
#define GCK_RETURN_RGB(x, y, z) {rgb->r = x; rgb->g = y; rgb->b = z; return; }
/***********************************************************************************/
/* Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure */
/* red always maps to 6 in this implementation. Therefore UNDEFINED can be */
/* defined as 0 in situations where only unsigned numbers are desired. */
/***********************************************************************************/
void gck_rgb_to_hwb(GckRGB *rgb, gdouble *hue,gdouble *whiteness,gdouble *blackness)
{
/* RGB are each on [0, 1]. W and B are returned on [0, 1] and H is */
/* returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B. */
/* ====================================================================== */
gdouble R = rgb->r, G = rgb->g, B = rgb->b, w, v, b, f;
gint i;
w = gck_rgb_min(rgb);
v = gck_rgb_max(rgb);
b = 1.0 - v;
if (v == w)
{
*hue=GCK_HSV_UNDEFINED;
*whiteness=w;
*blackness=b;
}
else
{
f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
i = (R == w) ? 3.0 : ((G == w) ? 5.0 : 1.0);
*hue=(360.0/6.0)*(i - f /(v - w));
*whiteness=w;
*blackness=b;
}
}
void gck_hwb_to_rgb(gdouble H,gdouble W, gdouble B, GckRGB *rgb)
{
/* H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1]. */
/* RGB are each returned on [0, 1]. */
/* =============================================================== */
gdouble h = H, w = W, b = B, v, n, f;
gint i;
h=6.0*h/360.0;
v = 1.0 - b;
if (h == GCK_HSV_UNDEFINED)
{
rgb->r=v;
rgb->g=v;
rgb->b=v;
}
else
{
i = floor(h);
f = h - i;
if (i & 1) f = 1.0 - f; /* if i is odd */
n = w + f * (v - w); /* linear interpolation between w and v */
switch (i)
{
case 6:
case 0: GCK_RETURN_RGB(v, n, w);
break;
case 1: GCK_RETURN_RGB(n, v, w);
break;
case 2: GCK_RETURN_RGB(w, v, n);
break;
case 3: GCK_RETURN_RGB(w, n, v);
break;
case 4: GCK_RETURN_RGB(n, w, v);
break;
case 5: GCK_RETURN_RGB(v, w, n);
break;
}
}
}
/*********************************************************************/
/* Sumpersampling code (Quartic) */
/* This code is *largely* based on the sources for POV-Ray 3.0. I am */
/* grateful to the POV-Team for such a great program and for making */
/* their sources available. All comments / bug reports / */
/* etc. regarding this code should be addressed to me, not to the */
/* POV-Ray team. Any bugs are my responsibility, not theirs. */
/*********************************************************************/
gulong gck_render_sub_pixel(int max_depth, int depth, _GckSampleType ** block,
int x, int y, int x1, int y1, int x3, int y3, double threshold,
int sub_pixel_size, GckRenderFunction render_func, GckRGB * color)
{
int x2, y2, cnt; /* Coords of center sample */
double dx1, dy1; /* Delta to upper left sample */
double dx3, dy3, weight; /* Delta to lower right sample */
GckRGB c[4],tmpcol;
unsigned long num_samples = 0;
/* Get offsets for corners */
/* ======================= */
dx1 = (double)(x1 - sub_pixel_size / 2) / sub_pixel_size;
dx3 = (double)(x3 - sub_pixel_size / 2) / sub_pixel_size;
dy1 = (double)(y1 - sub_pixel_size / 2) / sub_pixel_size;
dy3 = (double)(y3 - sub_pixel_size / 2) / sub_pixel_size;
/* Render upper left sample */
/* ======================== */
if (!block[y1][x1].ready)
{
num_samples++;
(*render_func) (x + dx1, y + dy1, &c[0]);
block[y1][x1].ready = 1;
block[y1][x1].color = c[0];
}
else
c[0] = block[y1][x1].color;
/* Render upper right sample */
/* ========================= */
if (!block[y1][x3].ready)
{
num_samples++;
(*render_func) (x + dx3, y + dy1, &c[1]);
block[y1][x3].ready = 1;
block[y1][x3].color = c[1];
}
else
c[1] = block[y1][x3].color;
/* Render lower left sample */
/* ======================== */
if (!block[y3][x1].ready)
{
num_samples++;
(*render_func) (x + dx1, y + dy3, &c[2]);
block[y3][x1].ready = 1;
block[y3][x1].color = c[2];
}
else
c[2] = block[y3][x1].color;
/* Render lower right sample */
/* ========================= */
if (!block[y3][x3].ready)
{
num_samples++;
(*render_func) (x + dx3, y + dy3, &c[3]);
block[y3][x3].ready = 1;
block[y3][x3].color = c[3];
}
else
c[3] = block[y3][x3].color;
/* Check for supersampling */
/* ======================= */
if (depth <= max_depth)
{
/* Check whether we have to supersample */
/* ==================================== */
if ((gck_rgba_dist(&c[0], &c[1]) >= threshold) ||
(gck_rgba_dist(&c[0], &c[2]) >= threshold) ||
(gck_rgba_dist(&c[0], &c[3]) >= threshold) ||
(gck_rgba_dist(&c[1], &c[2]) >= threshold) ||
(gck_rgba_dist(&c[1], &c[3]) >= threshold) ||
(gck_rgba_dist(&c[2], &c[3]) >= threshold))
{
/* Calc coordinates of center subsample */
/* ==================================== */
x2 = (x1 + x3) / 2;
y2 = (y1 + y3) / 2;
/* Render sub-blocks */
/* ================= */
num_samples += gck_render_sub_pixel(max_depth, depth + 1, block, x, y, x1, y1, x2, y2,
threshold, sub_pixel_size, render_func, &c[0]);
num_samples += gck_render_sub_pixel(max_depth, depth + 1, block, x, y, x2, y1, x3, y2,
threshold, sub_pixel_size, render_func, &c[1]);
num_samples += gck_render_sub_pixel(max_depth, depth + 1, block, x, y, x1, y2, x2, y3,
threshold, sub_pixel_size, render_func, &c[2]);
num_samples += gck_render_sub_pixel(max_depth, depth + 1, block, x, y, x2, y2, x3, y3,
threshold, sub_pixel_size, render_func, &c[3]);
}
}
if (c[0].a==0.0 || c[1].a==0.0 || c[2].a==0.0 || c[3].a==0.0)
{
tmpcol.r=0.0;
tmpcol.g=0.0;
tmpcol.b=0.0;
weight=2.0;
for (cnt=0;cnt<4;cnt++)
{
if (c[cnt].a!=0.0)
{
tmpcol.r+=c[cnt].r;
tmpcol.g+=c[cnt].g;
tmpcol.b+=c[cnt].b;
weight/=2.0;
}
}
color->r=weight*tmpcol.r;
color->g=weight*tmpcol.g;
color->b=weight*tmpcol.b;
}
else
{
color->r = 0.25 * (c[0].r + c[1].r + c[2].r + c[3].r);
color->g = 0.25 * (c[0].g + c[1].g + c[2].g + c[3].g);
color->b = 0.25 * (c[0].b + c[1].b + c[2].b + c[3].b);
}
color->a = 0.25 * (c[0].a + c[1].a + c[2].a + c[3].a);
return (num_samples);
} /* Render_Sub_Pixel */
gulong gck_adaptive_supersample_area(int x1, int y1, int x2, int y2, int max_depth,
double threshold,
GckRenderFunction render_func,
GckPutPixelFunction put_pixel_func,
GckProgressFunction progress_func)
{
int x, y, width; /* Counters, width of region */
int xt, xtt, yt; /* Temporary counters */
int sub_pixel_size; /* Numbe of samples per pixel (1D) */
size_t row_size; /* Memory needed for one row */
GckRGB color; /* Rendered pixel's color */
_GckSampleType tmp_sample; /* For swapping samples */
_GckSampleType *top_row, *bot_row, *tmp_row; /* Sample rows */
_GckSampleType **block; /* Sample block matrix */
unsigned long num_samples;
/* Initialize color */
/* ================ */
color.r = color.b = color.g = color.a = 0.0;
/* Calculate sub-pixel size */
/* ======================== */
sub_pixel_size = 1 << max_depth;
/* Create row arrays */
/* ================= */
width = x2 - x1 + 1;
row_size = (sub_pixel_size * width + 1) * sizeof(_GckSampleType);
top_row = (_GckSampleType *) g_malloc(row_size);
bot_row = (_GckSampleType *) g_malloc(row_size);
for (x = 0; x < (sub_pixel_size * width + 1); x++)
{
top_row[x].ready = 0;
top_row[x].color.r = 0.0;
top_row[x].color.g = 0.0;
top_row[x].color.b = 0.0;
top_row[x].color.a = 0.0;
bot_row[x].ready = 0;
bot_row[x].color.r = 0.0;
bot_row[x].color.g = 0.0;
bot_row[x].color.b = 0.0;
bot_row[x].color.a = 0.0;
}
/* Allocate block matrix */
/* ===================== */
block = g_malloc((sub_pixel_size + 1) * sizeof(_GckSampleType *)); /* Rows */
for (y = 0; y < (sub_pixel_size + 1); y++)
block[y] = g_malloc((sub_pixel_size + 1) * sizeof(_GckSampleType));
for (y = 0; y < (sub_pixel_size + 1); y++)
for (x = 0; x < (sub_pixel_size + 1); x++)
{
block[y][x].ready = 0;
block[y][x].color.r = 0.0;
block[y][x].color.g = 0.0;
block[y][x].color.b = 0.0;
block[y][x].color.a = 0.0;
}
/* Render region */
/* ============= */
num_samples = 0;
for (y = y1; y <= y2; y++)
{
/* Clear the bottom row */
/* ==================== */
for (xt = 0; xt < (sub_pixel_size * width + 1); xt++)
bot_row[xt].ready = 0;
/* Clear first column */
/* ================== */
for (yt = 0; yt < (sub_pixel_size + 1); yt++)
block[yt][0].ready = 0;
/* Render row */
/* ========== */
for (x = x1; x <= x2; x++)
{
/* Initialize block by clearing all but first row/column */
/* ===================================================== */
for (yt = 1; yt < (sub_pixel_size + 1); yt++)
for (xt = 1; xt < (sub_pixel_size + 1); xt++)
block[yt][xt].ready = 0;
/* Copy samples from top row to block */
/* ================================== */
for (xtt = 0, xt = (x - x1) * sub_pixel_size; xtt < (sub_pixel_size + 1); xtt++, xt++)
block[0][xtt] = top_row[xt];
/* Render pixel on (x, y) */
/* ====================== */
num_samples += gck_render_sub_pixel(max_depth, 1, block, x, y, 0, 0, sub_pixel_size,
sub_pixel_size, threshold, sub_pixel_size, render_func, &color);
(*put_pixel_func) (x, y, &color);
/* Copy block information to rows */
/* ============================== */
top_row[(x - x1 + 1) * sub_pixel_size] = block[0][sub_pixel_size];
for (xtt = 0, xt = (x - x1) * sub_pixel_size; xtt < (sub_pixel_size + 1); xtt++, xt++)
bot_row[xt] = block[sub_pixel_size][xtt];
/* Swap first and last columns */
/* =========================== */
for (yt = 0; yt < (sub_pixel_size + 1); yt++)
{
tmp_sample = block[yt][0];
block[yt][0] = block[yt][sub_pixel_size];
block[yt][sub_pixel_size] = tmp_sample;
}
}
/* Swap rows */
/* ========= */
tmp_row = top_row;
top_row = bot_row;
bot_row = tmp_row;
/* Call progress display function (if any) */
/* ======================================= */
if (progress_func != NULL)
(*progress_func) (y1, y2, y);
} /* for */
/* Free memory */
/* =========== */
for (y = 0; y < (sub_pixel_size + 1); y++)
g_free(block[y]);
g_free(block);
g_free(top_row);
g_free(bot_row);
return (num_samples);
}