From 8ed6940008f010b3d6db0cebf611c7476956fa1a Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Fri, 29 Aug 2014 22:14:55 +0000 Subject: [PATCH] Bug 51222 - XSSFColor.getARGBHex() returns wrong color for Excel 2007 xlsx file git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1621393 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/xssf/model/ThemesTable.java | 74 +++++--- .../apache/poi/xssf/usermodel/XSSFColor.java | 162 ++++++++---------- .../poi/xssf/model/TestThemesTable.java | 78 +++++++++ .../poi/xssf/usermodel/TestXSSFColor.java | 62 +++---- .../extensions/TestXSSFCellFill.java | 73 ++++---- test-data/spreadsheet/Themes.xlsx | Bin 0 -> 9506 bytes 6 files changed, 265 insertions(+), 184 deletions(-) create mode 100644 src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java create mode 100644 test-data/spreadsheet/Themes.xlsx diff --git a/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java b/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java index 3bd00f4a2f..0e8f906339 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java @@ -23,20 +23,22 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.xssf.usermodel.XSSFColor; import org.apache.xmlbeans.XmlException; -import org.apache.xmlbeans.XmlObject; +import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; import org.openxmlformats.schemas.drawingml.x2006.main.CTColorScheme; import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument; -import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; /** * Class that represents theme of XLSX document. The theme includes specific * colors and fonts. - * - * @author Petr Udalau(Petr.Udalau at exigenservices.com) - theme colors */ public class ThemesTable extends POIXMLDocumentPart { private ThemeDocument theme; + /** + * Construct a ThemesTable. + * @param part A PackagePart. + * @param rel A PackageRelationship. + */ public ThemesTable(PackagePart part, PackageRelationship rel) throws IOException { super(part, rel); @@ -47,38 +49,56 @@ public class ThemesTable extends POIXMLDocumentPart { } } + /** + * Construct a ThemesTable from an existing ThemeDocument. + * @param theme A ThemeDocument. + */ public ThemesTable(ThemeDocument theme) { this.theme = theme; } + /** + * Convert a theme "index" into a color. + * @param idx A theme "index" + * @return The mapped XSSFColor, or null if not mapped. + */ public XSSFColor getThemeColor(int idx) { + // Theme color references are NOT positional indices into the color scheme, + // i.e. these keys are NOT the same as the order in which theme colors appear + // in theme1.xml. They are keys to a mapped color. CTColorScheme colorScheme = theme.getTheme().getThemeElements().getClrScheme(); - CTColor ctColor = null; - int cnt = 0; - for (XmlObject obj : colorScheme.selectPath("./*")) { - if (obj instanceof org.openxmlformats.schemas.drawingml.x2006.main.CTColor) { - if (cnt == idx) { - ctColor = (org.openxmlformats.schemas.drawingml.x2006.main.CTColor) obj; - - byte[] rgb = null; - if (ctColor.getSrgbClr() != null) { - // Colour is a regular one - rgb = ctColor.getSrgbClr().getVal(); - } else if (ctColor.getSysClr() != null) { - // Colour is a tint of white or black - rgb = ctColor.getSysClr().getLastClr(); - } + CTColor ctColor; + switch (idx) { + case 0: ctColor = colorScheme.getLt1(); break; + case 1: ctColor = colorScheme.getDk1(); break; + case 2: ctColor = colorScheme.getLt2(); break; + case 3: ctColor = colorScheme.getDk2(); break; + case 4: ctColor = colorScheme.getAccent1(); break; + case 5: ctColor = colorScheme.getAccent2(); break; + case 6: ctColor = colorScheme.getAccent3(); break; + case 7: ctColor = colorScheme.getAccent4(); break; + case 8: ctColor = colorScheme.getAccent5(); break; + case 9: ctColor = colorScheme.getAccent6(); break; + case 10: ctColor = colorScheme.getHlink(); break; + case 11: ctColor = colorScheme.getFolHlink(); break; + default: return null; + } - return new XSSFColor(rgb); - } - cnt++; - } + byte[] rgb = null; + if (ctColor.isSetSrgbClr()) { + // Color is a regular one + rgb = ctColor.getSrgbClr().getVal(); + } else if (ctColor.isSetSysClr()) { + // Color is a tint of white or black + rgb = ctColor.getSysClr().getLastClr(); + } else { + return null; } - return null; + return new XSSFColor(rgb); } /** - * If the colour is based on a theme, then inherit + * If the colour is based on a theme, then inherit * information (currently just colours) from it as * required. */ @@ -91,13 +111,13 @@ public class ThemesTable extends POIXMLDocumentPart { // No theme set, nothing to do return; } - + // Get the theme colour XSSFColor themeColor = getThemeColor(color.getTheme()); // Set the raw colour, not the adjusted one // Do a raw set, no adjusting at the XSSFColor layer either color.getCTColor().setRgb(themeColor.getCTColor().getRgb()); - + // All done } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java index b15eaa55ba..3082e53878 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java @@ -25,16 +25,16 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; * Represents a color in SpreadsheetML */ public class XSSFColor implements Color { - - private CTColor ctColor; + + private CTColor ctColor; /** * Create an instance of XSSFColor from the supplied XML bean */ public XSSFColor(CTColor color) { - this.ctColor = color; - } - + this.ctColor = color; + } + /** * Create an new instance of XSSFColor */ @@ -56,50 +56,29 @@ public class XSSFColor implements Color { * A boolean value indicating the ctColor is automatic and system ctColor dependent. */ public boolean isAuto() { - return ctColor.getAuto(); - } - + return ctColor.getAuto(); + } + /** * A boolean value indicating the ctColor is automatic and system ctColor dependent. */ - public void setAuto(boolean auto) { - ctColor.setAuto(auto); - } + public void setAuto(boolean auto) { + ctColor.setAuto(auto); + } /** * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. */ public short getIndexed() { - return (short)ctColor.getIndexed(); - } - + return (short)ctColor.getIndexed(); + } + /** * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. */ - public void setIndexed(int indexed) { - ctColor.setIndexed(indexed); - } - - /** - * For RGB colours, but not ARGB (we think...) - * Excel gets black and white the wrong way around, so switch them - */ - private byte[] correctRGB(byte[] rgb) { - if(rgb.length == 4) { - // Excel doesn't appear to get these wrong - // Nothing to change - return rgb; - } else { - // Excel gets black and white the wrong way around, so switch them - if (rgb[0] == 0 && rgb[1] == 0 && rgb[2] == 0) { - rgb = new byte[] {-1, -1, -1}; - } - else if (rgb[0] == -1 && rgb[1] == -1 && rgb[2] == -1) { - rgb = new byte[] {0, 0, 0}; - } - return rgb; - } - } + public void setIndexed(int indexed) { + ctColor.setIndexed(indexed); + } /** * Standard Red Green Blue ctColor value (RGB). @@ -108,7 +87,7 @@ public class XSSFColor implements Color { public byte[] getRgb() { byte[] rgb = getRGBOrARGB(); if(rgb == null) return null; - + if(rgb.length == 4) { // Need to trim off the alpha byte[] tmp = new byte[3]; @@ -125,7 +104,7 @@ public class XSSFColor implements Color { public byte[] getARgb() { byte[] rgb = getRGBOrARGB(); if(rgb == null) return null; - + if(rgb.length == 3) { // Pad with the default Alpha byte[] tmp = new byte[4]; @@ -136,7 +115,7 @@ public class XSSFColor implements Color { return rgb; } } - + private byte[] getRGBOrARGB() { byte[] rgb = null; @@ -150,7 +129,7 @@ public class XSSFColor implements Color { return rgb; } } - + if (!ctColor.isSetRgb()) { // No colour is available, sorry return null; @@ -158,9 +137,7 @@ public class XSSFColor implements Color { // Grab the colour rgb = ctColor.getRgb(); - - // Correct it as needed, and return - return correctRGB(rgb); + return rgb; } /** @@ -181,64 +158,63 @@ public class XSSFColor implements Color { } return rgb; } - + /** * Return the ARGB value in hex format, eg FF00FF00. - * Works for both regular and indexed colours. + * Works for both regular and indexed colours. */ - public String getARGBHex() { - StringBuffer sb = new StringBuffer(); - byte[] rgb = getARgb(); - if(rgb == null) { - return null; - } - for(byte c : rgb) { - int i = (int)c; - if(i < 0) { - i += 256; - } - String cs = Integer.toHexString(i); - if(cs.length() == 1) { - sb.append('0'); - } - sb.append(cs); - } - return sb.toString().toUpperCase(); - } - - private static byte applyTint(int lum, double tint){ - if(tint > 0){ - return (byte)(lum * (1.0-tint) + (255 - 255 * (1.0-tint))); - } else if (tint < 0){ - return (byte)(lum*(1+tint)); - } else { - return (byte)lum; - } - } + public String getARGBHex() { + StringBuffer sb = new StringBuffer(); + byte[] rgb = getARgb(); + if(rgb == null) { + return null; + } + for(byte c : rgb) { + int i = (int)c; + if(i < 0) { + i += 256; + } + String cs = Integer.toHexString(i); + if(cs.length() == 1) { + sb.append('0'); + } + sb.append(cs); + } + return sb.toString().toUpperCase(); + } + + private static byte applyTint(int lum, double tint){ + if(tint > 0){ + return (byte)(lum * (1.0-tint) + (255 - 255 * (1.0-tint))); + } else if (tint < 0){ + return (byte)(lum*(1+tint)); + } else { + return (byte)lum; + } + } /** * Standard Alpha Red Green Blue ctColor value (ARGB). */ - public void setRgb(byte[] rgb) { - // Correct it and save - ctColor.setRgb(correctRGB(rgb)); - } - + public void setRgb(byte[] rgb) { + ctColor.setRgb(rgb); + } + /** * Index into the collection, referencing a particular or * value expressed in the Theme part. */ public int getTheme() { return (int)ctColor.getTheme(); - } - + } + /** * Index into the collection, referencing a particular or * value expressed in the Theme part. */ - public void setTheme(int theme) { - ctColor.setTheme(theme); - } + public void setTheme(int theme) { + ctColor.setTheme(theme); + } /** * Specifies the tint value applied to the ctColor. @@ -282,9 +258,9 @@ public class XSSFColor implements Color { * @return the tint value */ public double getTint() { - return ctColor.getTint(); - } - + return ctColor.getTint(); + } + /** * Specifies the tint value applied to the ctColor. * @@ -326,9 +302,9 @@ public class XSSFColor implements Color { * * @param tint the tint value */ - public void setTint(double tint) { - ctColor.setTint(tint); - } + public void setTint(double tint) { + ctColor.setTint(tint); + } /** * Returns the underlying XML bean @@ -339,7 +315,7 @@ public class XSSFColor implements Color { public CTColor getCTColor(){ return ctColor; } - + public int hashCode(){ return ctColor.toString().hashCode(); } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java new file mode 100644 index 0000000000..40ab5b46e5 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java @@ -0,0 +1,78 @@ +/* ==================================================================== + 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.apache.poi.xssf.model; + +import static org.junit.Assert.assertEquals; + +import java.io.FileOutputStream; + +import org.apache.commons.codec.binary.Hex; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.XSSFTestDataSamples; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Test; + +public class TestThemesTable { + private String testFile = "Themes.xlsx"; + + @Test + public void testThemesTableColors() throws Exception { + XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook(testFile); + String rgbExpected[] = { + "ffffff", // Lt1 + "000000", // Dk1 + "eeece1", // Lt2 + "1f497d", // DK2 + "4f81bd", // Accent1 + "c0504d", // Accent2 + "9bbb59", // Accent3 + "8064a2", // Accent4 + "4bacc6", // Accent5 + "f79646", // Accent6 + "0000ff", // Hlink + "800080" // FolHlink + }; + boolean createFile = false; + int i=0; + for (Row row : workbook.getSheetAt(0)) { + XSSFFont font = ((XSSFRow)row).getCell(0).getCellStyle().getFont(); + XSSFColor color = font.getXSSFColor(); + assertEquals("Failed color theme "+i, rgbExpected[i], Hex.encodeHexString(color.getRgb())); + long themeIdx = font.getCTFont().getColorArray(0).getTheme(); + assertEquals("Failed color theme "+i, i, themeIdx); + if (createFile) { + XSSFCellStyle cs = (XSSFCellStyle)row.getSheet().getWorkbook().createCellStyle(); + cs.setFillForegroundColor(color); + cs.setFillPattern(CellStyle.SOLID_FOREGROUND); + row.createCell(1).setCellStyle(cs); + } + i++; + } + + if (createFile) { + FileOutputStream fos = new FileOutputStream("foobaa.xlsx"); + workbook.write(fos); + fos.close(); + } + } +} \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java index b2aa11447b..6f31cc49f4 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java @@ -24,49 +24,49 @@ import org.apache.poi.xssf.XSSFTestDataSamples; public final class TestXSSFColor extends TestCase { public void testIndexedColour() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("48779.xlsx"); - + // Check the CTColor is as expected XSSFColor indexed = wb.getCellStyleAt((short)1).getFillBackgroundXSSFColor(); assertEquals(true, indexed.getCTColor().isSetIndexed()); assertEquals(64, indexed.getCTColor().getIndexed()); assertEquals(false, indexed.getCTColor().isSetRgb()); assertEquals(null, indexed.getCTColor().getRgb()); - + // Now check the XSSFColor // Note - 64 is a special "auto" one with no rgb equiv assertEquals(64, indexed.getIndexed()); assertEquals(null, indexed.getRgb()); assertEquals(null, indexed.getRgbWithTint()); assertEquals(null, indexed.getARGBHex()); - + // Now move to one with indexed rgb values indexed.setIndexed(59); assertEquals(true, indexed.getCTColor().isSetIndexed()); assertEquals(59, indexed.getCTColor().getIndexed()); assertEquals(false, indexed.getCTColor().isSetRgb()); assertEquals(null, indexed.getCTColor().getRgb()); - + assertEquals(59, indexed.getIndexed()); assertEquals("FF333300", indexed.getARGBHex()); - + assertEquals(3, indexed.getRgb().length); assertEquals(0x33, indexed.getRgb()[0]); assertEquals(0x33, indexed.getRgb()[1]); assertEquals(0x00, indexed.getRgb()[2]); - + assertEquals(4, indexed.getARgb().length); assertEquals(-1, indexed.getARgb()[0]); assertEquals(0x33, indexed.getARgb()[1]); assertEquals(0x33, indexed.getARgb()[2]); assertEquals(0x00, indexed.getARgb()[3]); - + // You don't get tinted indexed colours, sorry... assertEquals(null, indexed.getRgbWithTint()); } - + public void testRGBColour() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("50299.xlsx"); - + // Check the CTColor is as expected XSSFColor rgb3 = wb.getCellStyleAt((short)25).getFillForegroundXSSFColor(); assertEquals(false, rgb3.getCTColor().isSetIndexed()); @@ -75,37 +75,39 @@ public final class TestXSSFColor extends TestCase { assertEquals(-0.34999, rgb3.getCTColor().getTint(), 0.00001); assertEquals(true, rgb3.getCTColor().isSetRgb()); assertEquals(3, rgb3.getCTColor().getRgb().length); - + // Now check the XSSFColor assertEquals(0, rgb3.getIndexed()); assertEquals(-0.34999, rgb3.getTint(), 0.00001); - + assertEquals("FFFFFFFF", rgb3.getARGBHex()); assertEquals(3, rgb3.getRgb().length); assertEquals(-1, rgb3.getRgb()[0]); assertEquals(-1, rgb3.getRgb()[1]); assertEquals(-1, rgb3.getRgb()[2]); - + assertEquals(4, rgb3.getARgb().length); assertEquals(-1, rgb3.getARgb()[0]); assertEquals(-1, rgb3.getARgb()[1]); assertEquals(-1, rgb3.getARgb()[2]); assertEquals(-1, rgb3.getARgb()[3]); - + // Tint doesn't have the alpha + // tint = -0.34999 + // 255 * (1 + tint) = 165 truncated + // or (byte) -91 (which is 165 - 256) assertEquals(3, rgb3.getRgbWithTint().length); - assertEquals(0, rgb3.getRgbWithTint()[0]); - assertEquals(0, rgb3.getRgbWithTint()[1]); - assertEquals(0, rgb3.getRgbWithTint()[2]); - - // Set the colour to black, will get translated internally - // (Excel stores 3 colour white and black wrong!) - rgb3.setRgb(new byte[] {-1,-1,-1}); - assertEquals("FFFFFFFF", rgb3.getARGBHex()); + assertEquals(-91, rgb3.getRgbWithTint()[0]); + assertEquals(-91, rgb3.getRgbWithTint()[1]); + assertEquals(-91, rgb3.getRgbWithTint()[2]); + + // Set the color to black (no theme). + rgb3.setRgb(new byte[] {0, 0, 0}); + assertEquals("FF000000", rgb3.getARGBHex()); assertEquals(0, rgb3.getCTColor().getRgb()[0]); assertEquals(0, rgb3.getCTColor().getRgb()[1]); assertEquals(0, rgb3.getCTColor().getRgb()[2]); - + // Set another, is fine rgb3.setRgb(new byte[] {16,17,18}); assertEquals("FF101112", rgb3.getARGBHex()); @@ -113,45 +115,45 @@ public final class TestXSSFColor extends TestCase { assertEquals(0x11, rgb3.getCTColor().getRgb()[1]); assertEquals(0x12, rgb3.getCTColor().getRgb()[2]); } - + public void testARGBColour() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("48779.xlsx"); - + // Check the CTColor is as expected XSSFColor rgb4 = wb.getCellStyleAt((short)1).getFillForegroundXSSFColor(); assertEquals(false, rgb4.getCTColor().isSetIndexed()); assertEquals(0, rgb4.getCTColor().getIndexed()); assertEquals(true, rgb4.getCTColor().isSetRgb()); assertEquals(4, rgb4.getCTColor().getRgb().length); - + // Now check the XSSFColor assertEquals(0, rgb4.getIndexed()); assertEquals(0.0, rgb4.getTint()); - + assertEquals("FFFF0000", rgb4.getARGBHex()); assertEquals(3, rgb4.getRgb().length); assertEquals(-1, rgb4.getRgb()[0]); assertEquals(0, rgb4.getRgb()[1]); assertEquals(0, rgb4.getRgb()[2]); - + assertEquals(4, rgb4.getARgb().length); assertEquals(-1, rgb4.getARgb()[0]); assertEquals(-1, rgb4.getARgb()[1]); assertEquals(0, rgb4.getARgb()[2]); assertEquals(0, rgb4.getARgb()[3]); - + // Tint doesn't have the alpha assertEquals(3, rgb4.getRgbWithTint().length); assertEquals(-1, rgb4.getRgbWithTint()[0]); assertEquals(0, rgb4.getRgbWithTint()[1]); assertEquals(0, rgb4.getRgbWithTint()[2]); - + // Turn on tinting, and check it behaves // TODO These values are suspected to be wrong... rgb4.setTint(0.4); assertEquals(0.4, rgb4.getTint()); - + assertEquals(3, rgb4.getRgbWithTint().length); assertEquals(-1, rgb4.getRgbWithTint()[0]); assertEquals(102, rgb4.getRgbWithTint()[1]); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java index 2ad4f5645d..b268410bfa 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java @@ -31,34 +31,34 @@ import junit.framework.TestCase; public class TestXSSFCellFill extends TestCase { - - public void testGetFillBackgroundColor() { - CTFill ctFill = CTFill.Factory.newInstance(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); - CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); - CTColor bgColor = ctPatternFill.addNewBgColor(); - assertNotNull(cellFill.getFillBackgroundColor()); - bgColor.setIndexed(2); - assertEquals(2, cellFill.getFillBackgroundColor().getIndexed()); - } - - public void testGetFillForegroundColor() { - CTFill ctFill = CTFill.Factory.newInstance(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); - CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); - CTColor fgColor = ctPatternFill.addNewFgColor(); - assertNotNull(cellFill.getFillForegroundColor()); - fgColor.setIndexed(8); - assertEquals(8, cellFill.getFillForegroundColor().getIndexed()); - } - - public void testGetSetPatternType() { - CTFill ctFill = CTFill.Factory.newInstance(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); - CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); - ctPatternFill.setPatternType(STPatternType.SOLID); - //assertEquals(FillPatternType.SOLID_FOREGROUND.ordinal(), cellFill.getPatternType().ordinal()); - } + + public void testGetFillBackgroundColor() { + CTFill ctFill = CTFill.Factory.newInstance(); + XSSFCellFill cellFill = new XSSFCellFill(ctFill); + CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); + CTColor bgColor = ctPatternFill.addNewBgColor(); + assertNotNull(cellFill.getFillBackgroundColor()); + bgColor.setIndexed(2); + assertEquals(2, cellFill.getFillBackgroundColor().getIndexed()); + } + + public void testGetFillForegroundColor() { + CTFill ctFill = CTFill.Factory.newInstance(); + XSSFCellFill cellFill = new XSSFCellFill(ctFill); + CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); + CTColor fgColor = ctPatternFill.addNewFgColor(); + assertNotNull(cellFill.getFillForegroundColor()); + fgColor.setIndexed(8); + assertEquals(8, cellFill.getFillForegroundColor().getIndexed()); + } + + public void testGetSetPatternType() { + CTFill ctFill = CTFill.Factory.newInstance(); + XSSFCellFill cellFill = new XSSFCellFill(ctFill); + CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); + ctPatternFill.setPatternType(STPatternType.SOLID); + //assertEquals(FillPatternType.SOLID_FOREGROUND.ordinal(), cellFill.getPatternType().ordinal()); + } public void testGetNotModifies() { CTFill ctFill = CTFill.Factory.newInstance(); @@ -75,11 +75,16 @@ public class TestXSSFCellFill extends TestCase { XSSFColor foregroundColor = cellWithThemeColor.getCellStyle().getFillForegroundXSSFColor(); byte[] rgb = foregroundColor.getRgb(); byte[] rgbWithTint = foregroundColor.getRgbWithTint(); - assertEquals(rgb[0],-18); - assertEquals(rgb[1],-20); - assertEquals(rgb[2],-31); - assertEquals(rgbWithTint[0],-12); - assertEquals(rgbWithTint[1],-13); - assertEquals(rgbWithTint[2],-20); + // Dk2 + assertEquals(rgb[0],31); + assertEquals(rgb[1],73); + assertEquals(rgb[2],125); + // Dk2, lighter 40% (tint is about 0.39998) + // 31 * (1.0 - 0.39998) + (255 - 255 * (1.0 - 0.39998)) = 120.59552 => 120 (byte) + // 73 * (1.0 - 0.39998) + (255 - 255 * (1.0 - 0.39998)) = 145.79636 => -111 (byte) + // 125 * (1.0 - 0.39998) + (255 - 255 * (1.0 - 0.39998)) = 176.99740 => -80 (byte) + assertEquals(rgbWithTint[0],120); + assertEquals(rgbWithTint[1],-111); + assertEquals(rgbWithTint[2],-80); } } diff --git a/test-data/spreadsheet/Themes.xlsx b/test-data/spreadsheet/Themes.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..188f1bdbc28f4ecc80bfbe9cdcb368b140d056ec GIT binary patch literal 9506 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 b_w>i?tt