From 1f65eb415b3156e93316e5d6a95789236740a584 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Thu, 2 Jan 2003 15:09:15 +0000 Subject: [PATCH] added new files for custom palette patch git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352979 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hssf/usermodel/HSSFPalette.java | 193 ++++++++++++++++++ .../poi/hssf/record/TestPaletteRecord.java | 96 +++++++++ .../poi/hssf/usermodel/TestHSSFPalette.java | 187 +++++++++++++++++ 3 files changed, 476 insertions(+) create mode 100644 src/java/org/apache/poi/hssf/usermodel/HSSFPalette.java create mode 100644 src/testcases/org/apache/poi/hssf/record/TestPaletteRecord.java create mode 100644 src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPalette.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPalette.java new file mode 100644 index 000000000..ffafe90a2 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPalette.java @@ -0,0 +1,193 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.poi.hssf.usermodel; + +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 + * + * @author Brian Sanders (bsanders at risklabs dot com) + */ +public class HSSFPalette +{ + private PaletteRecord palette; + + protected HSSFPalette(PaletteRecord palette) + { + this.palette = palette; + } + + /** + * 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) + { + byte[] b = palette.getColor(index); + if (b != null) + { + return new CustomColor(index, b); + } + return null; + } + + /** + * Finds the first occurance of a given color + * + * @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) + { + byte[] b = palette.getColor(PaletteRecord.FIRST_COLOR_INDEX); + for (short i = (short) PaletteRecord.FIRST_COLOR_INDEX; b != null; + b = palette.getColor(++i)) + { + if (b[0] == red && b[1] == blue && b[2] == green) + { + return new CustomColor(i, b); + } + } + return null; + } + + /** + * 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) + { + palette.setColor(index, red, green, blue); + } + + private static class CustomColor extends HSSFColor + { + private short byteOffset; + private byte red; + private byte green; + private byte blue; + + private CustomColor(short byteOffset, byte[] colors) + { + this(byteOffset, colors[0], colors[1], colors[2]); + } + + private CustomColor(short byteOffset, byte red, byte green, byte blue) + { + this.byteOffset = byteOffset; + this.red = red; + this.green = green; + this.blue = blue; + } + + public short getIndex() + { + return byteOffset; + } + + public short[] getTriplet() + { + return new short[] + { + (short) (red & 0xff), + (short) (green & 0xff), + (short) (blue & 0xff) + }; + } + + public String getHexString() + { + StringBuffer sb = new StringBuffer(); + sb.append(getGnumericPart(red)); + sb.append(':'); + sb.append(getGnumericPart(green)); + sb.append(':'); + sb.append(getGnumericPart(blue)); + return sb.toString(); + } + + 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 + s = Integer.toHexString(c).toUpperCase(); + while (s.length() < 4) + { + s = "0" + s; + } + } + return s; + } + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/TestPaletteRecord.java b/src/testcases/org/apache/poi/hssf/record/TestPaletteRecord.java new file mode 100644 index 000000000..488a9d198 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/TestPaletteRecord.java @@ -0,0 +1,96 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.poi.hssf.record; + +import java.util.Iterator; +import java.util.Map; +import junit.framework.TestCase; +import org.apache.poi.hssf.util.HSSFColor; + +/** + * Verifies that custom palette editing works correctly + * + * @author Brian Sanders (bsanders at risklabs dot com) + */ +public class TestPaletteRecord extends TestCase +{ + public TestPaletteRecord(String name) + { + super(name); + } + + /** + * Tests that the default palette matches the constants of HSSFColor + */ + public void testDefaultPalette() + { + PaletteRecord palette = new PaletteRecord(PaletteRecord.sid); + + //make sure all the HSSFColor constants match + Map colors = HSSFColor.getIndexHash(); + Iterator indexes = colors.keySet().iterator(); + while (indexes.hasNext()) + { + Integer index = (Integer) indexes.next(); + HSSFColor c = (HSSFColor) colors.get(index); + short[] rgbTriplet = c.getTriplet(); + byte[] paletteTriplet = palette.getColor(index.shortValue()); + String msg = "Expected HSSFColor constant to match PaletteRecord at index 0x" + + Integer.toHexString(c.getIndex()); + assertEquals(msg, rgbTriplet[0], paletteTriplet[0] & 0xff); + assertEquals(msg, rgbTriplet[1], paletteTriplet[1] & 0xff); + assertEquals(msg, rgbTriplet[2], paletteTriplet[2] & 0xff); + } + } +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java new file mode 100644 index 000000000..1baec5833 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java @@ -0,0 +1,187 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.poi.hssf.usermodel; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import junit.framework.TestCase; +import org.apache.poi.hssf.record.PaletteRecord; +import org.apache.poi.hssf.util.HSSFColor; + +/** + * @author Brian Sanders (bsanders at risklabs dot com) + */ +public class TestHSSFPalette extends TestCase +{ + private PaletteRecord palette; + private HSSFPalette hssfPalette; + + public TestHSSFPalette(String name) + { + super(name); + } + + public void setUp() + { + palette = new PaletteRecord(PaletteRecord.sid); + hssfPalette = new HSSFPalette(palette); + } + + /** + * Verifies that a custom palette can be created, saved, and reloaded + */ + public void testCustomPalette() throws IOException + { + //reading sample xls + String dir = System.getProperty("HSSF.testdata.path"); + File sample = new File(dir + "/Simple.xls"); + assertTrue("Simple.xls exists and is readable", sample.canRead()); + FileInputStream fis = new FileInputStream(sample); + HSSFWorkbook book = new HSSFWorkbook(fis); + fis.close(); + + //creating custom palette + HSSFPalette palette = book.getCustomPalette(); + palette.setColorAtIndex((short) 0x12, (byte) 101, (byte) 230, (byte) 100); + palette.setColorAtIndex((short) 0x3b, (byte) 0, (byte) 255, (byte) 52); + + //writing to disk; reading in and verifying palette + File temp = File.createTempFile("testCustomPalette", ".xls"); + FileOutputStream fos = new FileOutputStream(temp); + book.write(fos); + fos.close(); + + fis = new FileInputStream(temp); + book = new HSSFWorkbook(fis); + fis.close(); + temp.delete(); + + palette = book.getCustomPalette(); + HSSFColor color = palette.getColor(HSSFColor.CORAL.index); //unmodified + assertNotNull("Unexpected null in custom palette (unmodified index)", color); + short[] expectedRGB = HSSFColor.CORAL.triplet; + short[] actualRGB = color.getTriplet(); + String msg = "Expected palette position to remain unmodified"; + assertEquals(msg, expectedRGB[0], actualRGB[0]); + assertEquals(msg, expectedRGB[1], actualRGB[1]); + assertEquals(msg, expectedRGB[2], actualRGB[2]); + + color = palette.getColor((short) 0x12); + assertNotNull("Unexpected null in custom palette (modified)", color); + actualRGB = color.getTriplet(); + msg = "Expected palette modification to be preserved across save"; + assertEquals(msg, (short) 101, actualRGB[0]); + assertEquals(msg, (short) 230, actualRGB[1]); + assertEquals(msg, (short) 100, actualRGB[2]); + } + + /** + * Verifies that the generated gnumeric-format string values match the + * hardcoded values in the HSSFColor default color palette + */ + public void testGnumericStrings() + { + compareToDefaults(new ColorComparator() { + public void compare(HSSFColor expected, HSSFColor palette) + { + assertEquals(expected.getHexString(), palette.getHexString()); + } + }); + } + + /** + * Verifies that the palette handles invalid palette indexes + */ + public void testBadIndexes() + { + //too small + hssfPalette.setColorAtIndex((short) 2, (byte) 255, (byte) 255, (byte) 255); + //too large + hssfPalette.setColorAtIndex((short) 0x45, (byte) 255, (byte) 255, (byte) 255); + + //should still match defaults; + compareToDefaults(new ColorComparator() { + public void compare(HSSFColor expected, HSSFColor palette) + { + short[] s1 = expected.getTriplet(); + short[] s2 = palette.getTriplet(); + assertEquals(s1[0], s2[0]); + assertEquals(s1[1], s2[1]); + assertEquals(s1[2], s2[2]); + } + }); + } + + private void compareToDefaults(ColorComparator c) + { + Map colors = HSSFColor.getIndexHash(); + Iterator it = colors.keySet().iterator(); + while (it.hasNext()) + { + Number index = (Number) it.next(); + HSSFColor expectedColor = (HSSFColor) colors.get(index); + HSSFColor paletteColor = hssfPalette.getColor(index.shortValue()); + c.compare(expectedColor, paletteColor); + } + } + + private static interface ColorComparator + { + void compare(HSSFColor expected, HSSFColor palette); + } +}