2003-01-02 10:09:15 -05:00
|
|
|
/* ====================================================================
|
2006-12-22 14:18:16 -05:00
|
|
|
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
|
2004-04-09 09:05:39 -04:00
|
|
|
|
|
|
|
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.
|
|
|
|
==================================================================== */
|
2004-08-23 04:52:54 -04:00
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
package org.apache.poi.hssf.usermodel;
|
|
|
|
|
2015-09-01 14:49:50 -04:00
|
|
|
import java.util.Locale;
|
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
import org.apache.poi.hssf.record.PaletteRecord;
|
|
|
|
import org.apache.poi.hssf.util.HSSFColor;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a workbook color palette.
|
|
|
|
* Internally, the XLS format refers to colors using an offset into the palette
|
|
|
|
* record. Thus, the first color in the palette has the index 0x8, the second
|
|
|
|
* has the index 0x9, etc. through 0x40
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public final class HSSFPalette {
|
|
|
|
private PaletteRecord _palette;
|
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
protected HSSFPalette(PaletteRecord palette)
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
_palette = palette;
|
2003-01-02 10:09:15 -05:00
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
/**
|
|
|
|
* Retrieves the color at a given index
|
|
|
|
*
|
|
|
|
* @param index the palette index, between 0x8 to 0x40 inclusive
|
|
|
|
* @return the color, or null if the index is not populated
|
|
|
|
*/
|
|
|
|
public HSSFColor getColor(short index)
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
//Handle the special AUTOMATIC case
|
|
|
|
if (index == HSSFColor.AUTOMATIC.index) {
|
|
|
|
return HSSFColor.AUTOMATIC.getInstance();
|
|
|
|
}
|
|
|
|
byte[] b = _palette.getColor(index);
|
2006-07-24 08:18:48 -04:00
|
|
|
if (b != null)
|
|
|
|
{
|
|
|
|
return new CustomColor(index, b);
|
|
|
|
}
|
2003-01-02 10:09:15 -05:00
|
|
|
return null;
|
|
|
|
}
|
2008-09-21 14:56:32 -04:00
|
|
|
/**
|
|
|
|
* Retrieves the color at a given index
|
|
|
|
*
|
|
|
|
* @param index the palette index, between 0x8 to 0x40 inclusive
|
|
|
|
* @return the color, or null if the index is not populated
|
|
|
|
*/
|
|
|
|
public HSSFColor getColor(int index) {
|
|
|
|
return getColor((short)index);
|
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
/**
|
2013-09-09 05:41:31 -04:00
|
|
|
* Finds the first occurrence of a given color
|
2003-01-02 10:09:15 -05:00
|
|
|
*
|
|
|
|
* @param red the RGB red component, between 0 and 255 inclusive
|
|
|
|
* @param green the RGB green component, between 0 and 255 inclusive
|
|
|
|
* @param blue the RGB blue component, between 0 and 255 inclusive
|
|
|
|
* @return the color, or null if the color does not exist in this palette
|
|
|
|
*/
|
|
|
|
public HSSFColor findColor(byte red, byte green, byte blue)
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
byte[] b = _palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
|
|
|
|
for (short i = PaletteRecord.FIRST_COLOR_INDEX; b != null;
|
|
|
|
b = _palette.getColor(++i))
|
2003-01-02 10:09:15 -05:00
|
|
|
{
|
2003-07-27 14:53:53 -04:00
|
|
|
if (b[0] == red && b[1] == green && b[2] == blue)
|
2003-01-02 10:09:15 -05:00
|
|
|
{
|
|
|
|
return new CustomColor(i, b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2004-04-09 07:45:38 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds the closest matching color in the custom palette. The
|
|
|
|
* method for finding the distance between the colors is fairly
|
|
|
|
* primative.
|
|
|
|
*
|
|
|
|
* @param red The red component of the color to match.
|
|
|
|
* @param green The green component of the color to match.
|
|
|
|
* @param blue The blue component of the color to match.
|
|
|
|
* @return The closest color or null if there are no custom
|
|
|
|
* colors currently defined.
|
|
|
|
*/
|
2009-11-25 06:45:37 -05:00
|
|
|
public HSSFColor findSimilarColor(byte red, byte green, byte blue) {
|
|
|
|
return findSimilarColor(unsignedInt(red), unsignedInt(green), unsignedInt(blue));
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Finds the closest matching color in the custom palette. The
|
|
|
|
* method for finding the distance between the colors is fairly
|
|
|
|
* primative.
|
|
|
|
*
|
|
|
|
* @param red The red component of the color to match.
|
|
|
|
* @param green The green component of the color to match.
|
|
|
|
* @param blue The blue component of the color to match.
|
|
|
|
* @return The closest color or null if there are no custom
|
|
|
|
* colors currently defined.
|
|
|
|
*/
|
|
|
|
public HSSFColor findSimilarColor(int red, int green, int blue) {
|
2004-04-09 07:45:38 -04:00
|
|
|
HSSFColor result = null;
|
|
|
|
int minColorDistance = Integer.MAX_VALUE;
|
2009-08-18 01:29:53 -04:00
|
|
|
byte[] b = _palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
|
|
|
|
for (short i = PaletteRecord.FIRST_COLOR_INDEX; b != null;
|
|
|
|
b = _palette.getColor(++i))
|
2004-04-09 07:45:38 -04:00
|
|
|
{
|
2009-11-25 06:45:37 -05:00
|
|
|
int colorDistance = Math.abs(red - unsignedInt(b[0])) +
|
|
|
|
Math.abs(green - unsignedInt(b[1])) +
|
|
|
|
Math.abs(blue - unsignedInt(b[2]));
|
2004-04-09 07:45:38 -04:00
|
|
|
if (colorDistance < minColorDistance)
|
|
|
|
{
|
2008-02-21 06:34:25 -05:00
|
|
|
minColorDistance = colorDistance;
|
2004-04-09 07:45:38 -04:00
|
|
|
result = getColor(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2009-11-25 06:45:37 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Turn a byte of between -127 and 127 into something between
|
|
|
|
* 0 and 255, so distance calculations work as expected.
|
|
|
|
*/
|
|
|
|
private int unsignedInt(byte b) {
|
2015-02-09 17:33:24 -05:00
|
|
|
return 0xFF & b;
|
2009-11-25 06:45:37 -05:00
|
|
|
}
|
2004-04-09 07:45:38 -04:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
/**
|
|
|
|
* Sets the color at the given offset
|
|
|
|
*
|
|
|
|
* @param index the palette index, between 0x8 to 0x40 inclusive
|
|
|
|
* @param red the RGB red component, between 0 and 255 inclusive
|
|
|
|
* @param green the RGB green component, between 0 and 255 inclusive
|
|
|
|
* @param blue the RGB blue component, between 0 and 255 inclusive
|
|
|
|
*/
|
|
|
|
public void setColorAtIndex(short index, byte red, byte green, byte blue)
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
_palette.setColor(index, red, green, blue);
|
2004-08-23 04:52:54 -04:00
|
|
|
}
|
|
|
|
|
2004-04-09 07:45:38 -04:00
|
|
|
/**
|
|
|
|
* Adds a new color into an empty color slot.
|
|
|
|
* @param red The red component
|
|
|
|
* @param green The green component
|
|
|
|
* @param blue The blue component
|
|
|
|
*
|
|
|
|
* @return The new custom color.
|
|
|
|
*
|
|
|
|
* @throws RuntimeException if there are more more free color indexes.
|
|
|
|
*/
|
|
|
|
public HSSFColor addColor( byte red, byte green, byte blue )
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
byte[] b = _palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
|
2004-04-09 07:45:38 -04:00
|
|
|
short i;
|
2009-08-18 01:29:53 -04:00
|
|
|
for (i = PaletteRecord.FIRST_COLOR_INDEX; i < PaletteRecord.STANDARD_PALETTE_SIZE + PaletteRecord.FIRST_COLOR_INDEX; b = _palette.getColor(++i))
|
2004-04-09 07:45:38 -04:00
|
|
|
{
|
|
|
|
if (b == null)
|
|
|
|
{
|
|
|
|
setColorAtIndex( i, red, green, blue );
|
|
|
|
return getColor(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new RuntimeException("Could not find free color index");
|
|
|
|
}
|
|
|
|
|
2009-08-18 01:29:53 -04:00
|
|
|
private static final class CustomColor extends HSSFColor {
|
|
|
|
private short _byteOffset;
|
|
|
|
private byte _red;
|
|
|
|
private byte _green;
|
|
|
|
private byte _blue;
|
|
|
|
|
|
|
|
public CustomColor(short byteOffset, byte[] colors)
|
2003-01-02 10:09:15 -05:00
|
|
|
{
|
|
|
|
this(byteOffset, colors[0], colors[1], colors[2]);
|
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
private CustomColor(short byteOffset, byte red, byte green, byte blue)
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
_byteOffset = byteOffset;
|
|
|
|
_red = red;
|
|
|
|
_green = green;
|
|
|
|
_blue = blue;
|
2003-01-02 10:09:15 -05:00
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2013-09-09 05:41:31 -04:00
|
|
|
@Override
|
2003-01-02 10:09:15 -05:00
|
|
|
public short getIndex()
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
return _byteOffset;
|
2003-01-02 10:09:15 -05:00
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2013-09-09 05:41:31 -04:00
|
|
|
@Override
|
2003-01-02 10:09:15 -05:00
|
|
|
public short[] getTriplet()
|
|
|
|
{
|
|
|
|
return new short[]
|
|
|
|
{
|
2009-08-18 01:29:53 -04:00
|
|
|
(short) (_red & 0xff),
|
|
|
|
(short) (_green & 0xff),
|
|
|
|
(short) (_blue & 0xff)
|
2003-01-02 10:09:15 -05:00
|
|
|
};
|
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2013-09-09 05:41:31 -04:00
|
|
|
@Override
|
2003-01-02 10:09:15 -05:00
|
|
|
public String getHexString()
|
|
|
|
{
|
|
|
|
StringBuffer sb = new StringBuffer();
|
2009-08-18 01:29:53 -04:00
|
|
|
sb.append(getGnumericPart(_red));
|
2003-01-02 10:09:15 -05:00
|
|
|
sb.append(':');
|
2009-08-18 01:29:53 -04:00
|
|
|
sb.append(getGnumericPart(_green));
|
2003-01-02 10:09:15 -05:00
|
|
|
sb.append(':');
|
2009-08-18 01:29:53 -04:00
|
|
|
sb.append(getGnumericPart(_blue));
|
2003-01-02 10:09:15 -05:00
|
|
|
return sb.toString();
|
|
|
|
}
|
2009-08-18 01:29:53 -04:00
|
|
|
|
2003-01-02 10:09:15 -05:00
|
|
|
private String getGnumericPart(byte color)
|
|
|
|
{
|
|
|
|
String s;
|
|
|
|
if (color == 0)
|
|
|
|
{
|
|
|
|
s = "0";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int c = color & 0xff; //as unsigned
|
|
|
|
c = (c << 8) | c; //pad to 16-bit
|
2015-09-01 14:49:50 -04:00
|
|
|
s = Integer.toHexString(c).toUpperCase(Locale.ROOT);
|
2003-01-02 10:09:15 -05:00
|
|
|
while (s.length() < 4)
|
|
|
|
{
|
|
|
|
s = "0" + s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|