/* * This file is part of MoleculeViewer. * * MoleculeViewer is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MoleculeViewer 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with MoleculeViewer. If not, see <http://www.gnu.org/licenses/>. */ package astex; /** * Manipulate packed colors. */ import java.util.*; import java.awt.*; public class Color32 { /** Alpha bits. */ private static final int Alpha = 0xFF000000; /** Red bits. */ private static final int Red = 0xFF0000; /** Green bits. */ private static final int Green = 0xFF00; /** Blue bits. */ private static final int Blue = 0xFF; public static int getComponent(int c, int comp){ if(comp == 0) return getRed(c); if(comp == 1) return getGreen(c); if(comp == 2) return getBlue(c); return 0; } /** Returns the red component. */ public static int getRed(int c){ return (c & Red) >> 16; } /** Returns the green component. */ public static int getGreen(int c){ return (c & Green) >> 8; } /** Returns the blue component. */ public static int getBlue(int c){ return c & Blue; } public static int getIntensity(int c){ int r = getRed(c); int g = getGreen(c); int b = getBlue(c); int intensity = (int)((r+g+b)/3.0); return intensity; } public static int getMaximumIntensity(int c){ int r = getRed(c); int g = getGreen(c); int b = getBlue(c); int max = r; if(g > max){ max = g; } if(b > max){ max = b; } return max; } public static int getGrayScale(int c){ int r = getRed(c); int g = getGreen(c); int b = getBlue(c); int luma = (int)(r*0.3 + g*0.59+ b*0.11); if(luma > 255) luma = 255; return pack(luma, luma, luma); } /** Clamp components to 0,255 and return rgb color. */ public static int getClampColor(int r, int g, int b){ return Alpha|(clamp(r)<<16)|(clamp(g)<<8)|clamp(b); } /** Clamp number to range specified. */ public static int clamp(int num) { if(num < 0) return 0; if(num > 255) return 255; return num; } public static int scale(int c, int factor) { if (factor == 255) return c; if (factor == 0) return 0; int r = (c>>16)&0xff; int g = (c>>8)&0xff; int b = c&0xff; r = (r * factor)>>8; g = (g * factor)>>8; b = (b * factor)>>8; return (r<<16)|(g<<8)|b; } public static int add(int color1, int color2) { int r = (color1 & Red) + (color2 & Red); int g = (color1 & Green) + (color2 & Green); int b = (color1 & Blue) + (color2 & Blue); if (r > Red ) r = Red; if (g > Green) g = Green; if (b > Blue ) b = Blue; return (r|g|b); } public static int multiply(int c1, int c2) { int c1r = (c1 >> 16) & 0xff; int c1g = (c1 >> 8) & 0xff; int c1b = (c1 >> 0) & 0xff; int c2r = (c2 >> 16) & 0xff; int c2g = (c2 >> 8) & 0xff; int c2b = (c2 >> 0) & 0xff; // the mutliply means we need to scale down by 256 // equivalent to right shift 8 bits c2r = (c1r * c2r) >> 8; c2g = (c1g * c2g) >> 8; c2b = (c1b * c2b) >> 8; return (c2r << 16) | (c2g << 8) | (c2b); } /** multiply by intensity between 0 and 255 and specularise. */ public static int intensitySpecularise(int c1, int intensity, int specular) { c1 = scale(c1, intensity); return add(c1, specular); } // blend alpha's worth of c1 and 255-alpha's worth of c2 // I'm sure there are faster ways of doing this... public static int blend(int c1, int c2, int alpha) { if (alpha==0) return c2; if (alpha==255) return c1; int c1r = (c1 >> 16) & 0xff; int c1g = (c1 >> 8) & 0xff; int c1b = (c1 >> 0) & 0xff; int c2r = (c2 >> 16) & 0xff; int c2g = (c2 >> 8) & 0xff; int c2b = (c2 >> 0) & 0xff; int r = (alpha*(c1r) + (255-alpha)*(c2r))>>8; int g = (alpha*(c1g) + (255-alpha)*(c2g))>>8; int b = (alpha*(c1b) + (255-alpha)*(c2b))>>8; return Alpha|(r<<16)|(g<<8)|b; } /** Interpolate two colors. (frac*c1 + (1.-frac)*c2)*/ public static int blend(int c1, int c2, double frac){ return blend(c1, c2, (int)(255 * frac)); } /** Convert hsv format colour to rgb. */ public static void hsv2rgb (double hsv[], double rgb[]){ int HueQuadrant; double HueLocal, Diff, m, n, k; HueLocal = hsv[0]; while (HueLocal >= 360.0) HueLocal -= 360.0; HueLocal /= 60.0; HueQuadrant = (int)HueLocal; Diff = HueLocal - HueQuadrant; m = hsv[2] * (1.0 - hsv[1]); n = hsv[2] * (1.0 - hsv[1] * Diff); k = hsv[2] * (1.0 - hsv[1] * (1.0 - Diff)); switch(HueQuadrant){ case 0: rgb[0] = hsv[2]; rgb[1] = k; rgb[2] = m; break; case 1: rgb[0] = n; rgb[1] = hsv[2]; rgb[2] = m; break; case 2: rgb[0] = m; rgb[1] = hsv[2]; rgb[2] = k; break; case 3: rgb[0] = m; rgb[1] = n; rgb[2] = hsv[2]; break; case 4: rgb[0] = k; rgb[1] = m; rgb[2] = hsv[2]; break; case 5: rgb[0] = hsv[2]; rgb[1] = m; rgb[2] = n; break; } // clamp to range 0.0-1.0 // not sure if this is actually necesarry. for(int i = 0; i < 3; i++){ if(rgb[i] < 0.0) rgb[i] = 0.0; else if(rgb[i] > 1.0) rgb[i] = 1.0; } } /** Pack r,g,b triple into a single int. */ public static int pack(int r, int g, int b) { return Alpha | r << 16 | g << 8 | b; } /** Convert rgb to hsv. */ public static void rgb2hsv (double rgb[], double hsv[]){ double x, Rtemp, Gtemp, Btemp; hsv[2] = Math.max(rgb[0], Math.max(rgb[1], rgb[2])); x = Math.min(rgb[0], Math.min(rgb[1], rgb[2])); hsv[1] = (hsv[2] - x) / hsv[2]; Rtemp = (hsv[2] - rgb[0]) * 60 / (hsv[2] - x); Gtemp = (hsv[2] - rgb[1]) * 60 / (hsv[2] - x); Btemp = (hsv[2] - rgb[2]) * 60 / (hsv[2] - x); if(rgb[0] == hsv[2]){ if (rgb[1] == x) hsv[0] = 300 + Btemp; else hsv[0] = 60 - Gtemp; }else if(rgb[1] == hsv[2]){ if (rgb[2] == x) hsv[0] = 60 + Rtemp; else hsv[0] = 180 - Btemp; }else{ if (rgb[0] == x) hsv[0] = 180 + Gtemp; else hsv[0] = 300 - Rtemp; } } /** Working space for rgb conversions. */ private static double rgbtmp[] = new double[3]; /** Convert hsv to packed int color. */ public static int hsv2packed(double hsv[]){ int r, g, b; hsv2rgb(hsv, rgbtmp); r = (int)(rgbtmp[0] * 255.0); g = (int)(rgbtmp[1] * 255.0); b = (int)(rgbtmp[2] * 255.0); int c = pack(r, g, b); //print("rgb=", c); return c; } /** Convert a packed rgb number to hsv. */ public static void packed2hsv(int rgb, double hsv[]){ int r = getRed(rgb); int g = getGreen(rgb); int b = getBlue(rgb); rgbtmp[0] = r / 255.0; rgbtmp[1] = g / 255.0; rgbtmp[2] = b / 255.0; rgb2hsv(rgbtmp, hsv); } /** Print a colour representation. */ public static void print(String s, int c){ print(s, getRed(c), getGreen(c), getBlue(c)); } /** Print a colour representation. */ public static void print(String s, int r, int g, int b){ FILE.out.print(s); FILE.out.print(" [%03d", r); FILE.out.print(",%03d", g); FILE.out.print(",%03d]\n", b); } public static String format(int c){ return "'0x" + String.format("%02x", getRed(c)) + String.format("%02x", getGreen(c)) + String.format("%02x'", getBlue(c)); } public static String formatNoQuotes(int c){ return "0x" + String.format("%02x", getRed(c)) + String.format("%02x", getGreen(c)) + String.format("%02x", getBlue(c)); } /* Some internal colors. */ public static final int snow = pack(255, 250, 250); public static final int gainsboro = pack(220, 220, 220); public static final int linen = pack(250, 240, 230); public static final int bisque = pack(255, 228, 196); public static final int moccasin = pack(255, 228, 181); public static final int cornsilk = pack(255, 248, 220); public static final int ivory = pack(255, 255, 240); public static final int seashell = pack(255, 245, 238); public static final int honeydew = pack(240, 255, 240); public static final int azure = pack(240, 255, 255); public static final int lavender = pack(230, 230, 250); public static final int white = pack(255, 255, 255); public static final int black = pack( 0, 0, 0); public static final int navy = pack( 0, 0, 128); public static final int blue = pack( 0, 0, 255); public static final int turquoise = pack( 64, 224, 208); public static final int cyan = pack( 0, 255, 255); public static final int aquamarine = pack(127, 255, 212); public static final int green = pack( 0, 255, 0); public static final int chartreuse = pack(127, 255, 0); public static final int khaki = pack(240, 230, 140); public static final int yellow = pack(255, 255, 0); public static final int gold = pack(255, 215, 0); public static final int goldenrod = pack(218, 165, 32); public static final int sienna = pack(160, 82, 45); public static final int peru = pack(205, 133, 63); public static final int burlywood = pack(222, 184, 135); public static final int beige = pack(245, 245, 220); public static final int wheat = pack(245, 222, 179); public static final int tan = pack(210, 180, 140); public static final int chocolate = pack(210, 105, 30); public static final int firebrick = pack(178, 34, 34); public static final int brown = pack(165, 42, 42); public static final int salmon = pack(250, 128, 114); public static final int orange = pack(255, 165, 0); public static final int coral = pack(255, 127, 80); public static final int tomato = pack(255, 99, 71); public static final int red = pack(255, 0, 0); public static final int pink = pack(255, 192, 203); public static final int maroon = pack(176, 48, 96); public static final int magenta = pack(255, 0, 255); public static final int violet = pack(238, 130, 238); public static final int plum = pack(221, 160, 221); public static final int orchid = pack(218, 112, 214); public static final int purple = pack(160, 32, 240); public static final int thistle = pack(216, 191, 216); public static final int grey = pack(190, 190, 190); public static final int gray = grey; public static final int rwb0 = pack( 255, 0, 0 ); // rwb0 public static final int rwb1 = pack( 255, 115, 115 ); // rwb1 public static final int rwb2 = pack( 255, 170, 170 ); // rwb2 public static final int rwb3 = pack( 255, 215, 215 ); // rwb3 public static final int rwb4 = pack( 215, 215, 255 ); // rwb4 public static final int rwb5 = pack( 170, 170, 255 ); // rwb5 public static final int rwb6 = pack( 115, 115, 255 ); // rwb6 public static final int rwb7 = pack( 0, 0, 255 ); // rwb7 public static final int undefinedColor = white; /** Hashtable for storing color name -> rgb values. */ private static HashMap<String,Integer> colorHash; /** Valid digits for a hex format number. */ private static String hexDigits = "0123456789abcdefABCDEFx"; /** Return packed color value from string name. */ public static int getColorFromName(String colorName){ int len = colorName.length(); int color = undefinedColor; if(colorName.indexOf(',') != -1){ String components[] = FILE.split(colorName, ","); if(components.length == 3){ int r = FILE.readInteger(components[0]); int g = FILE.readInteger(components[1]); int b = FILE.readInteger(components[2]); color = Color32.getClampColor(r, g, b); }else{ Log.error("color should be \"r,g,b\" not: " + colorName); } return color; } boolean allHex = true; for(int i = 0; i < len; i++){ char c = colorName.charAt(i); if(hexDigits.indexOf(c) == -1){ allHex = false; break; } } if(allHex){ int start = -1; int group_mult = 256; int char_mult = 16; if(len == 8 && colorName.charAt(0) == '0' && colorName.charAt(1) == 'x'){ start = 2; group_mult = 16; char_mult = 1; }else if(len == 6){ start = 0; group_mult = 16; char_mult = 1; }else if(len == 7){ start = 1; }else if(len == 4){ start = 1; group_mult = 16; char_mult = 1; }else if(len == 3){ start = 0; } if(start == -1){ System.out.println("illegal color format: " + colorName); return undefinedColor; } int total = 0; for(int i = start; i < len; i++){ int c = colorName.charAt(i); if(c >= '0' && c <= '9'){ total = group_mult * total + (c - '0') * char_mult; }else if(c >= 'a' && c <= 'f'){ total = group_mult * total + (c - 'a' + 10) * char_mult; }else if(c >= 'A' && c <= 'F'){ total = group_mult * total + (c - 'A' + 10) * char_mult; }else{ System.out.println("getColorIndex: illegal char: " + (char)c); } } color = total; }else{ ensureColorHashDefined(); colorName = colorName.toLowerCase(); Integer colorValue = colorHash.get(colorName); if(colorValue != null){ color = colorValue.intValue(); }else{ System.out.println("couldn't find color " + colorName); color = undefinedColor; } } return color; } /** Return AWT color of this. */ public static Color getAWTColor(int color){ Color awtColor = new Color(getRed(color), getGreen(color), getBlue(color)); return awtColor; } /** Make sure the color hash is defined and initialised. */ private static void ensureColorHashDefined(){ if(colorHash == null){ colorHash = new HashMap<String,Integer>(500); FILE f = FILE.open("color.properties"); while(f.nextLine()){ if(f.getChar(0) != '#'){ int fc = f.getFieldCount(); if(fc != 4){ System.out.println("color.properties: invalid color definition"); System.out.println(f.getCurrentLineAsString()); }else{ String name = f.getField(0); name = name.toLowerCase(); Integer colorValue = Integer.valueOf(pack(f.getInteger(1), f.getInteger(2), f.getInteger(3))); colorHash.put(name, colorValue); } }else{ System.out.println(f.getCurrentLineAsString()); } } f.close(); } } }