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.openxml4j.opc.PackageRelationship;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFColor;
|
import org.apache.poi.xssf.usermodel.XSSFColor;
|
||||||
import org.apache.xmlbeans.XmlException;
|
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.CTColorScheme;
|
||||||
import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument;
|
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
|
* Class that represents theme of XLSX document. The theme includes specific
|
||||||
* colors and fonts.
|
* colors and fonts.
|
||||||
*
|
|
||||||
* @author Petr Udalau(Petr.Udalau at exigenservices.com) - theme colors
|
|
||||||
*/
|
*/
|
||||||
public class ThemesTable extends POIXMLDocumentPart {
|
public class ThemesTable extends POIXMLDocumentPart {
|
||||||
private ThemeDocument theme;
|
private ThemeDocument theme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a ThemesTable.
|
||||||
|
* @param part A PackagePart.
|
||||||
|
* @param rel A PackageRelationship.
|
||||||
|
*/
|
||||||
public ThemesTable(PackagePart part, PackageRelationship rel) throws IOException {
|
public ThemesTable(PackagePart part, PackageRelationship rel) throws IOException {
|
||||||
super(part, rel);
|
super(part, rel);
|
||||||
|
|
||||||
@ -47,35 +49,53 @@ public class ThemesTable extends POIXMLDocumentPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a ThemesTable from an existing ThemeDocument.
|
||||||
|
* @param theme A ThemeDocument.
|
||||||
|
*/
|
||||||
public ThemesTable(ThemeDocument theme) {
|
public ThemesTable(ThemeDocument theme) {
|
||||||
this.theme = 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) {
|
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();
|
CTColorScheme colorScheme = theme.getTheme().getThemeElements().getClrScheme();
|
||||||
CTColor ctColor = null;
|
CTColor ctColor;
|
||||||
int cnt = 0;
|
switch (idx) {
|
||||||
for (XmlObject obj : colorScheme.selectPath("./*")) {
|
case 0: ctColor = colorScheme.getLt1(); break;
|
||||||
if (obj instanceof org.openxmlformats.schemas.drawingml.x2006.main.CTColor) {
|
case 1: ctColor = colorScheme.getDk1(); break;
|
||||||
if (cnt == idx) {
|
case 2: ctColor = colorScheme.getLt2(); break;
|
||||||
ctColor = (org.openxmlformats.schemas.drawingml.x2006.main.CTColor) obj;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] rgb = null;
|
byte[] rgb = null;
|
||||||
if (ctColor.getSrgbClr() != null) {
|
if (ctColor.isSetSrgbClr()) {
|
||||||
// Colour is a regular one
|
// Color is a regular one
|
||||||
rgb = ctColor.getSrgbClr().getVal();
|
rgb = ctColor.getSrgbClr().getVal();
|
||||||
} else if (ctColor.getSysClr() != null) {
|
} else if (ctColor.isSetSysClr()) {
|
||||||
// Colour is a tint of white or black
|
// Color is a tint of white or black
|
||||||
rgb = ctColor.getSysClr().getLastClr();
|
rgb = ctColor.getSysClr().getLastClr();
|
||||||
}
|
} else {
|
||||||
|
|
||||||
return new XSSFColor(rgb);
|
|
||||||
}
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
||||||
|
@ -80,27 +80,6 @@ public class XSSFColor implements Color {
|
|||||||
ctColor.setIndexed(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard Red Green Blue ctColor value (RGB).
|
* Standard Red Green Blue ctColor value (RGB).
|
||||||
* If there was an A (Alpha) value, it will be stripped.
|
* If there was an A (Alpha) value, it will be stripped.
|
||||||
@ -158,9 +137,7 @@ public class XSSFColor implements Color {
|
|||||||
|
|
||||||
// Grab the colour
|
// Grab the colour
|
||||||
rgb = ctColor.getRgb();
|
rgb = ctColor.getRgb();
|
||||||
|
return rgb;
|
||||||
// Correct it as needed, and return
|
|
||||||
return correctRGB(rgb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,8 +197,7 @@ public class XSSFColor implements Color {
|
|||||||
* Standard Alpha Red Green Blue ctColor value (ARGB).
|
* Standard Alpha Red Green Blue ctColor value (ARGB).
|
||||||
*/
|
*/
|
||||||
public void setRgb(byte[] rgb) {
|
public void setRgb(byte[] rgb) {
|
||||||
// Correct it and save
|
ctColor.setRgb(rgb);
|
||||||
ctColor.setRgb(correctRGB(rgb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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]);
|
assertEquals(-1, rgb3.getARgb()[3]);
|
||||||
|
|
||||||
// Tint doesn't have the alpha
|
// 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(3, rgb3.getRgbWithTint().length);
|
||||||
assertEquals(0, rgb3.getRgbWithTint()[0]);
|
assertEquals(-91, rgb3.getRgbWithTint()[0]);
|
||||||
assertEquals(0, rgb3.getRgbWithTint()[1]);
|
assertEquals(-91, rgb3.getRgbWithTint()[1]);
|
||||||
assertEquals(0, rgb3.getRgbWithTint()[2]);
|
assertEquals(-91, rgb3.getRgbWithTint()[2]);
|
||||||
|
|
||||||
// Set the colour to black, will get translated internally
|
// Set the color to black (no theme).
|
||||||
// (Excel stores 3 colour white and black wrong!)
|
rgb3.setRgb(new byte[] {0, 0, 0});
|
||||||
rgb3.setRgb(new byte[] {-1,-1,-1});
|
assertEquals("FF000000", rgb3.getARGBHex());
|
||||||
assertEquals("FFFFFFFF", rgb3.getARGBHex());
|
|
||||||
assertEquals(0, rgb3.getCTColor().getRgb()[0]);
|
assertEquals(0, rgb3.getCTColor().getRgb()[0]);
|
||||||
assertEquals(0, rgb3.getCTColor().getRgb()[1]);
|
assertEquals(0, rgb3.getCTColor().getRgb()[1]);
|
||||||
assertEquals(0, rgb3.getCTColor().getRgb()[2]);
|
assertEquals(0, rgb3.getCTColor().getRgb()[2]);
|
||||||
|
@ -75,11 +75,16 @@ public class TestXSSFCellFill extends TestCase {
|
|||||||
XSSFColor foregroundColor = cellWithThemeColor.getCellStyle().getFillForegroundXSSFColor();
|
XSSFColor foregroundColor = cellWithThemeColor.getCellStyle().getFillForegroundXSSFColor();
|
||||||
byte[] rgb = foregroundColor.getRgb();
|
byte[] rgb = foregroundColor.getRgb();
|
||||||
byte[] rgbWithTint = foregroundColor.getRgbWithTint();
|
byte[] rgbWithTint = foregroundColor.getRgbWithTint();
|
||||||
assertEquals(rgb[0],-18);
|
// Dk2
|
||||||
assertEquals(rgb[1],-20);
|
assertEquals(rgb[0],31);
|
||||||
assertEquals(rgb[2],-31);
|
assertEquals(rgb[1],73);
|
||||||
assertEquals(rgbWithTint[0],-12);
|
assertEquals(rgb[2],125);
|
||||||
assertEquals(rgbWithTint[1],-13);
|
// Dk2, lighter 40% (tint is about 0.39998)
|
||||||
assertEquals(rgbWithTint[2],-20);
|
// 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