| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| package org.openoffice.xmerge.util; |
| |
| |
| import java.awt.Color; |
| |
| /** |
| * Utility class mapping RGB colour specifications to the colour indices used |
| * in the Pocket PC. The original converter was written for use with Pocket |
| * Word it was later put into the utils so Pocket excel could use this code |
| * also. For this reason the defualt values are those used by Pocket Word but |
| * a colour table can be passed in through the constructor to map the 16 |
| * values to a colour table. |
| * |
| * These colour indices are based on the Windows VGA 16 colour palette, which |
| * later was used as the basis for the named colours in the HTML 3.2 |
| * specification. |
| * |
| * In Pocket Word's case, the match to the VGA 16 palette is not exact as it |
| * swaps Grey and Silver, with Silver being the darker colour (i.e. having the |
| * lower RGB value). |
| */ |
| |
| public class ColourConverter { |
| |
| /** Colour table index for Black */ |
| private static final short BLACK = 0; |
| |
| /** Colour table index for Silver */ |
| private static final short SILVER = 1; |
| |
| /** Colour table index for Grey */ |
| private static final short GREY = 2; |
| |
| /** Colour table index for White */ |
| private static final short WHITE = 3; |
| |
| /** Colour table index for Red */ |
| private static final short RED = 4; |
| |
| /** Colour table index for Lime */ |
| private static final short LIME = 5; |
| |
| /** Colour table index for Blue */ |
| private static final short BLUE = 6; |
| |
| /** Colour table index for Aqua */ |
| private static final short AQUA = 7; |
| |
| /** Colour table index for Fuchsia */ |
| private static final short FUCHSIA = 8; |
| |
| /** Colour table index for Yellow */ |
| private static final short YELLOW = 9; |
| |
| /** Colour table index for Maroon */ |
| private static final short MAROON = 10; |
| |
| /** Colour table index for Green */ |
| private static final short GREEN = 11; |
| |
| /** Colour table index for Navy */ |
| private static final short NAVY = 12; |
| |
| /** Colour table index for Teal */ |
| private static final short TEAL = 13; |
| |
| /** Colour table index for Purple */ |
| private static final short PURPLE = 14; |
| |
| /** Colour table index for Olive */ |
| public static final short OLIVE = 15; |
| |
| private short tableLookup[] = null; |
| |
| /** |
| * Default constructor used in the case where a lookup table is not |
| * required |
| */ |
| public ColourConverter() { |
| |
| } |
| |
| /** |
| * Constructor that passes in the colour lookup table. This is required in |
| * cases where the 16 colour values are something other than there default |
| * values (e.g. in the case of pocket Excel) |
| * |
| * @param short[] a 16 bit array mapping the 16 colours to there values |
| */ |
| public ColourConverter(short lookup[]) { |
| |
| tableLookup = lookup; |
| } |
| |
| /** |
| * Uses the colour table it it exists to translate default values to |
| * values in the colorTable |
| */ |
| private short colourLookup(short colour) { |
| |
| if(tableLookup!=null) { |
| return tableLookup[colour]; |
| } else { |
| return colour; |
| } |
| } |
| |
| /** |
| * Uses the colour table it it exists to translate default values to |
| * values in the colorTable |
| */ |
| private short indexLookup(short index) { |
| |
| short result = 0; |
| |
| if(tableLookup!=null) { |
| for(short i = 0;i < tableLookup.length;i++) { |
| if(tableLookup[i]==index) |
| result = i; |
| } |
| } else { |
| result = index; |
| } |
| |
| return result; |
| } |
| /** |
| * This method maps a Pocket Word colour index value to an RGB value as |
| * used by OpenOffice. |
| * |
| * @param index The index into Pocket Word's colour table. |
| * |
| * @return A Color object representing the RGB value of the Pocket Word |
| * colour. |
| */ |
| public Color convertToRGB (short colour) { |
| |
| short index = indexLookup(colour); |
| |
| int r = 0; |
| int g = 0; |
| int b = 0; |
| |
| switch (index) { |
| case SILVER: |
| r = g = b = 128; |
| break; |
| |
| case GREY: |
| r = g = b = 192; |
| break; |
| |
| case WHITE: |
| r = g = b = 255; |
| break; |
| |
| case RED: |
| r = 255; |
| break; |
| |
| case LIME: |
| g = 255; |
| break; |
| |
| case BLUE: |
| b = 255; |
| break; |
| |
| case AQUA: |
| g = b = 255; |
| break; |
| |
| case FUCHSIA: |
| r = b = 255; |
| break; |
| |
| case YELLOW: |
| r = g = 255; |
| break; |
| |
| case MAROON: |
| r = 128; |
| break; |
| |
| case GREEN: |
| g = 128; |
| break; |
| |
| case NAVY: |
| b = 128; |
| break; |
| |
| case TEAL: |
| b = g = 128; |
| break; |
| |
| case PURPLE: |
| r = b = 128; |
| break; |
| |
| case OLIVE: |
| r = g = 128; |
| break; |
| |
| case BLACK: |
| default: |
| r = g = b = 0; |
| break; |
| } |
| |
| return new Color(r, g, b); |
| } |
| |
| |
| /** |
| * This method approximates an RGB value (as used by Writer) to one of the |
| * 16 available colours |
| * |
| * Most of the supported colours have their components set to either 0, 128 |
| * or 255. The exception is 'Grey' which is 0xC0C0C0. |
| * |
| * @param colour Color object representing the RGB value of the colour. |
| * |
| * @return Index into the Pocket Word colour table which represents the |
| * closest match to the specified colour. |
| */ |
| public short convertFromRGB (Color colour) { |
| int matchedRGB = 0; |
| short indexColour = 0; |
| int reducedMap[] = new int[] { 0, 0, 128 }; |
| |
| int red = colour.getRed(); |
| int green = colour.getGreen(); |
| int blue = colour.getBlue(); |
| |
| // We need to convert the pale colors to their base color rather than |
| // white so we modify the rgb values if the colour is sufficently |
| // white |
| if(red>0xC0 && green>0xC0 && blue>0xC0) { |
| |
| if(red!=0xFF) |
| red = getClosest(red, reducedMap); |
| if(green!=0xFF) |
| green = getClosest(green, reducedMap); |
| if(blue!=0xFF) |
| blue = getClosest(blue, reducedMap); |
| } |
| |
| /* |
| * Need to derive an RGB value that has been rounded to match the ones |
| * Pocket Word knows about. |
| */ |
| matchedRGB += getClosest(red) << 16; |
| matchedRGB += getClosest(green) << 8; |
| matchedRGB += getClosest(blue); |
| |
| /* |
| * The colour map used by Pocket Word doesn't have any combinations of |
| * values beyond 0 and any other value. A value of 255 in any RGB |
| * code indicates a dominant colour. Other colours are only modifiers |
| * to the principal colour(s). Thus, for this conversion, modifiers |
| * can be dropped. |
| */ |
| if ((matchedRGB & 0xFF0000) == 0xFF0000 || (matchedRGB & 0xFF00) == 0xFF00 |
| || (matchedRGB & 0xFF) == 0xFF) { |
| if ((matchedRGB & 0xFF0000) == 0x800000) { |
| matchedRGB ^= 0x800000; |
| } |
| if ((matchedRGB & 0xFF00) == 0x8000) { |
| matchedRGB ^= 0x8000; |
| } |
| if ((matchedRGB & 0xFF) == 0x80) { |
| matchedRGB ^= 0x80; |
| } |
| } |
| |
| |
| /* |
| * And now for the actual matching ... |
| * |
| * Colours are based on the Windows VGA 16 palette. One difference |
| * though is that Pocket Word seems to switch the RGB codes for Grey |
| * and Silver. In Pocket Word Silver is the darker colour leaving Grey |
| * is closest to White. |
| * |
| * Shades of grey will be converted to either Silver or White, where |
| * Grey may be a more appropraite colour. This is handled specially |
| * only for Silver and White matches. |
| */ |
| switch (matchedRGB) { |
| case 0x000000: |
| indexColour = BLACK; |
| break; |
| |
| case 0x808080: |
| if (!isGrey(colour)) { |
| indexColour = SILVER; |
| } |
| else { |
| indexColour = GREY; |
| } |
| break; |
| |
| case 0xFFFFFF: |
| if (!isGrey(colour)) { |
| indexColour = WHITE; |
| } |
| else { |
| indexColour = GREY; |
| } |
| break; |
| |
| case 0xFF0000: |
| indexColour = RED; |
| break; |
| |
| case 0x00FF00: |
| indexColour = LIME; |
| break; |
| |
| case 0x0000FF: |
| indexColour = BLUE; |
| break; |
| |
| case 0x00FFFF: |
| indexColour = AQUA; |
| break; |
| |
| case 0xFF00FF: |
| indexColour = FUCHSIA; |
| break; |
| |
| case 0xFFFF00: |
| indexColour = YELLOW; |
| break; |
| |
| case 0x800000: |
| indexColour = MAROON; |
| break; |
| |
| case 0x008000: |
| indexColour = GREEN; |
| break; |
| |
| case 0x000080: |
| indexColour = NAVY; |
| break; |
| |
| case 0x008080: |
| indexColour = TEAL; |
| break; |
| |
| case 0x800080: |
| indexColour = PURPLE; |
| break; |
| |
| case 0x808000: |
| indexColour = OLIVE; |
| break; |
| |
| default: // Just in case! |
| indexColour = BLACK; |
| break; |
| } |
| |
| return colourLookup(indexColour); |
| } |
| |
| |
| /* |
| * Default implementation, checks for the closest of value to 0, 128 or 255. |
| */ |
| private int getClosest(int value) { |
| int points[] = new int[] { 0, 128, 255 }; |
| |
| return getClosest(value, points); |
| } |
| |
| |
| /* |
| * Utility method that returns the closest of the three points to the value |
| * supplied. |
| */ |
| private int getClosest(int value, int[] points) { |
| |
| if (value == points[0] || value == points[1] || value == points[2]) { |
| return value; |
| } |
| |
| if (value < points[1]) { |
| int x = value - points[0]; |
| return (Math.round((float)x / (points[1] - points[0])) == 1 ? points[1] : points[0]); |
| } |
| else { |
| int x = value - points[1]; |
| return (Math.round((float)x / (points[2] - points[1])) >= 1 ? points[2] : points[1]); |
| } |
| } |
| |
| |
| /* |
| * Checks to see if the supplied colour can be considered to be grey. |
| */ |
| private boolean isGrey(Color c) { |
| int matchedRGB = 0; |
| int points[] = new int[] { 128, 192, 255 }; |
| |
| matchedRGB += getClosest(c.getRed(), points) << 16; |
| matchedRGB += getClosest(c.getGreen(), points) << 8; |
| matchedRGB += getClosest(c.getBlue(), points); |
| |
| if (matchedRGB == 0xC0C0C0) { |
| return true; |
| } |
| |
| return false; |
| } |
| } |
| |