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
This commit is contained in:
parent
67fcf46d4c
commit
0cbbbfe5d5
@ -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,34 +49,52 @@ 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();
|
||||
}
|
||||
|
||||
return new XSSFColor(rgb);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
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 null;
|
||||
|
||||
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 new XSSFColor(rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,14 +26,14 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor;
|
||||
*/
|
||||
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).
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,43 +163,42 @@ public class XSSFColor implements Color {
|
||||
* Return the ARGB value in hex format, eg FF00FF00.
|
||||
* 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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 <clrScheme> collection, referencing a particular <sysClr> or
|
||||
@ -230,15 +206,15 @@ public class XSSFColor implements Color {
|
||||
*/
|
||||
public int getTheme() {
|
||||
return (int)ctColor.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Index into the <clrScheme> collection, referencing a particular <sysClr> or
|
||||
* <srgbClr> 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,8 +258,8 @@ 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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -93,15 +93,17 @@ public final class TestXSSFColor extends TestCase {
|
||||
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]);
|
||||
assertEquals(-91, rgb3.getRgbWithTint()[0]);
|
||||
assertEquals(-91, rgb3.getRgbWithTint()[1]);
|
||||
assertEquals(-91, 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());
|
||||
// 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]);
|
||||
|
@ -32,33 +32,33 @@ 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 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 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 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);
|
||||
}
|
||||
}
|
||||
|
BIN
test-data/spreadsheet/Themes.xlsx
Normal file
BIN
test-data/spreadsheet/Themes.xlsx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user