From d788ff06b4005225d59e4ebd4355544f81a19e20 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 20 Jul 2015 00:46:50 +0000 Subject: [PATCH] Move some of the XSSF Color logic to a base class, so that the HSSF Extended Color wrapper can use it git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1691864 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/usermodel/ExtendedColor.java | 237 ++++++++++++++++++ .../apache/poi/xssf/usermodel/XSSFColor.java | 129 +++++----- 2 files changed, 294 insertions(+), 72 deletions(-) create mode 100644 src/java/org/apache/poi/ss/usermodel/ExtendedColor.java diff --git a/src/java/org/apache/poi/ss/usermodel/ExtendedColor.java b/src/java/org/apache/poi/ss/usermodel/ExtendedColor.java new file mode 100644 index 0000000000..30f296fd11 --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/ExtendedColor.java @@ -0,0 +1,237 @@ +/* ==================================================================== + 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.ss.usermodel; + +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.Color; + +/** + * Represents a XSSF-style color (based on either a + * {@link org.apache.poi.xssf.usermodel.XSSFColor} or a + * {@link org.apache.poi.hssf.record.common.ExtendedColor} + */ +public abstract class ExtendedColor implements Color { + protected void setColor(java.awt.Color clr) { + setRGB(new byte[]{(byte)clr.getRed(), (byte)clr.getGreen(), (byte)clr.getBlue()}); + } + + /** + * A boolean value indicating the color is automatic + */ + public abstract boolean isAuto(); + + /** + * A boolean value indicating the color is indexed + */ + public abstract boolean isIndexed(); + + /** + * A boolean value indicating the color is RGB / ARGB + */ + public abstract boolean isRGB(); + + /** + * A boolean value indicating the color is from a Theme + */ + public abstract boolean isThemed(); + + /** + * Indexed Color value, if {@link #isIndexed()} is true + */ + public abstract short getIndex(); + + /** + * Index of Theme color, if {@link #isThemed()} is true + */ + public abstract int getTheme(); + + /** + * Standard Red Green Blue ctColor value (RGB). + * If there was an A (Alpha) value, it will be stripped. + */ + public abstract byte[] getRGB(); + /** + * Standard Alpha Red Green Blue ctColor value (ARGB). + */ + public abstract byte[] getARGB(); + + /** + * RGB or ARGB or null + */ + protected abstract byte[] getStoredRBG(); + + /** + * Sets the Red Green Blue or Alpha Red Green Blue + */ + public abstract void setRGB(byte[] rgb); + + protected byte[] getRGBOrARGB() { + byte[] rgb = null; + + if (isIndexed() && getIndex() > 0) { + int indexNum = getIndex(); + HSSFColor indexed = HSSFColor.getIndexHash().get(indexNum); + if (indexed != null) { + rgb = new byte[3]; + rgb[0] = (byte) indexed.getTriplet()[0]; + rgb[1] = (byte) indexed.getTriplet()[1]; + rgb[2] = (byte) indexed.getTriplet()[2]; + return rgb; + } + } + + // Grab the colour + rgb = getStoredRBG(); + return rgb; + } + + /** + * Standard Red Green Blue ctColor value (RGB) with applied tint. + * Alpha values are ignored. + */ + public byte[] getRGBWithTint() { + byte[] rgb = getStoredRBG(); + if (rgb != null) { + if(rgb.length == 4) { + byte[] tmp = new byte[3]; + System.arraycopy(rgb, 1, tmp, 0, 3); + rgb = tmp; + } + for (int i = 0; i < rgb.length; i++){ + rgb[i] = applyTint(rgb[i] & 0xFF, getTint()); + } + } + return rgb; + } + + /** + * 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 = c & 0xff; + 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; + } + } + + /** + * Specifies the tint value applied to the ctColor. + * + *

+ * If tint is supplied, then it is applied to the RGB value of the ctColor to determine the final + * ctColor applied. + *

+ *

+ * The tint value is stored as a double from -1.0 .. 1.0, where -1.0 means 100% darken and + * 1.0 means 100% lighten. Also, 0.0 means no change. + *

+ *

+ * In loading the RGB value, it is converted to HLS where HLS values are (0..HLSMAX), where + * HLSMAX is currently 255. + *

+ * Here are some examples of how to apply tint to ctColor: + *
+ *
+     * If (tint < 0)
+     * Lum' = Lum * (1.0 + tint)
+     *
+     * For example: Lum = 200; tint = -0.5; Darken 50%
+     * Lum' = 200 * (0.5) => 100
+     * For example: Lum = 200; tint = -1.0; Darken 100% (make black)
+     * Lum' = 200 * (1.0-1.0) => 0
+     * If (tint > 0)
+     * Lum' = Lum * (1.0-tint) + (HLSMAX - HLSMAX * (1.0-tint))
+     * For example: Lum = 100; tint = 0.75; Lighten 75%
+     *
+     * Lum' = 100 * (1-.75) + (HLSMAX - HLSMAX*(1-.75))
+     * = 100 * .25 + (255 - 255 * .25)
+     * = 25 + (255 - 63) = 25 + 192 = 217
+     * For example: Lum = 100; tint = 1.0; Lighten 100% (make white)
+     * Lum' = 100 * (1-1) + (HLSMAX - HLSMAX*(1-1))
+     * = 100 * 0 + (255 - 255 * 0)
+     * = 0 + (255 - 0) = 255
+     * 
+ *
+ * + * @return the tint value + */ + public abstract double getTint(); + + /** + * Specifies the tint value applied to the ctColor. + * + *

+ * If tint is supplied, then it is applied to the RGB value of the ctColor to determine the final + * ctColor applied. + *

+ *

+ * The tint value is stored as a double from -1.0 .. 1.0, where -1.0 means 100% darken and + * 1.0 means 100% lighten. Also, 0.0 means no change. + *

+ *

+ * In loading the RGB value, it is converted to HLS where HLS values are (0..HLSMAX), where + * HLSMAX is currently 255. + *

+ * Here are some examples of how to apply tint to ctColor: + *
+ *
+     * If (tint < 0)
+     * Lum' = Lum * (1.0 + tint)
+     *
+     * For example: Lum = 200; tint = -0.5; Darken 50%
+     * Lum' = 200 * (0.5) => 100
+     * For example: Lum = 200; tint = -1.0; Darken 100% (make black)
+     * Lum' = 200 * (1.0-1.0) => 0
+     * If (tint > 0)
+     * Lum' = Lum * (1.0-tint) + (HLSMAX - HLSMAX * (1.0-tint))
+     * For example: Lum = 100; tint = 0.75; Lighten 75%
+     *
+     * Lum' = 100 * (1-.75) + (HLSMAX - HLSMAX*(1-.75))
+     * = 100 * .25 + (255 - 255 * .25)
+     * = 25 + (255 - 63) = 25 + 192 = 217
+     * For example: Lum = 100; tint = 1.0; Lighten 100% (make white)
+     * Lum' = 100 * (1-1) + (HLSMAX - HLSMAX*(1-1))
+     * = 100 * 0 + (255 - 255 * 0)
+     * = 0 + (255 - 0) = 255
+     * 
+ *
+ * + * @param tint the tint value + */ + public abstract void setTint(double tint); +} 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 19fd5a5b48..f443212de9 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java @@ -16,16 +16,15 @@ ==================================================================== */ package org.apache.poi.xssf.usermodel; -import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.Color; +import org.apache.poi.ss.usermodel.ExtendedColor; import org.apache.poi.util.Internal; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; /** * Represents a color in SpreadsheetML */ -public class XSSFColor implements Color { - +public class XSSFColor extends ExtendedColor { private CTColor ctColor; /** @@ -44,7 +43,7 @@ public class XSSFColor implements Color { public XSSFColor(java.awt.Color clr) { this(); - ctColor.setRgb(new byte[]{(byte)clr.getRed(), (byte)clr.getGreen(), (byte)clr.getBlue()}); + setColor(clr); } public XSSFColor(byte[] rgb) { @@ -55,10 +54,10 @@ public class XSSFColor implements Color { /** * A boolean value indicating the ctColor is automatic and system ctColor dependent. */ + @Override public boolean isAuto() { return ctColor.getAuto(); } - /** * A boolean value indicating the ctColor is automatic and system ctColor dependent. */ @@ -66,12 +65,42 @@ public class XSSFColor implements Color { ctColor.setAuto(auto); } + /** + * A boolean value indicating the ctColor is Indexed + */ + @Override + public boolean isIndexed() { + return ctColor.isSetIndexed(); + } + + /** + * A boolean value indicating the ctColor is RGB or ARGB based + */ + @Override + public boolean isRGB() { + return ctColor.isSetRgb(); + } + + /** + * A boolean value indicating the ctColor is Theme based + */ + @Override + public boolean isThemed() { + return ctColor.isSetTheme(); + } + /** * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. */ - public short getIndexed() { + public short getIndex() { return (short)ctColor.getIndexed(); } + /** + * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. + */ + public short getIndexed() { + return getIndex(); + } /** * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. @@ -84,7 +113,7 @@ public class XSSFColor implements Color { * Standard Red Green Blue ctColor value (RGB). * If there was an A (Alpha) value, it will be stripped. */ - public byte[] getRgb() { + public byte[] getRGB() { byte[] rgb = getRGBOrARGB(); if(rgb == null) return null; @@ -97,11 +126,17 @@ public class XSSFColor implements Color { return rgb; } } + /** + * @deprecated use {@link #getRGB()} + */ + public byte[] getRgb() { + return getRGB(); + } /** * Standard Alpha Red Green Blue ctColor value (ARGB). */ - public byte[] getARgb() { + public byte[] getARGB() { byte[] rgb = getRGBOrARGB(); if(rgb == null) return null; @@ -115,85 +150,35 @@ public class XSSFColor implements Color { return rgb; } } + /** + * @deprecated Use {@link #getARGB()} + */ + public byte[] getARgb() { + return getARGB(); + } - private byte[] getRGBOrARGB() { - byte[] rgb = null; - - if (ctColor.isSetIndexed() && ctColor.getIndexed() > 0) { - HSSFColor indexed = HSSFColor.getIndexHash().get((int) ctColor.getIndexed()); - if (indexed != null) { - rgb = new byte[3]; - rgb[0] = (byte) indexed.getTriplet()[0]; - rgb[1] = (byte) indexed.getTriplet()[1]; - rgb[2] = (byte) indexed.getTriplet()[2]; - return rgb; - } - } - - if (!ctColor.isSetRgb()) { - // No colour is available, sorry - return null; - } - - // Grab the colour - rgb = ctColor.getRgb(); - return rgb; - } + protected byte[] getStoredRBG() { + return ctColor.getRgb(); + } /** * Standard Red Green Blue ctColor value (RGB) with applied tint. * Alpha values are ignored. */ public byte[] getRgbWithTint() { - byte[] rgb = ctColor.getRgb(); - if (rgb != null) { - if(rgb.length == 4) { - byte[] tmp = new byte[3]; - System.arraycopy(rgb, 1, tmp, 0, 3); - rgb = tmp; - } - for (int i = 0; i < rgb.length; i++){ - rgb[i] = applyTint(rgb[i] & 0xFF, ctColor.getTint()); - } - } - return rgb; + return getRGBWithTint(); } /** - * Return the ARGB value in hex format, eg FF00FF00. - * Works for both regular and indexed colours. + * Standard Alpha Red Green Blue ctColor value (ARGB). */ - public String getARGBHex() { - StringBuffer sb = new StringBuffer(); - byte[] rgb = getARgb(); - if(rgb == null) { - return null; - } - for(byte c : rgb) { - int i = c & 0xff; - 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 void setRgb(byte[] rgb) { + setRGB(rgb); } - /** * Standard Alpha Red Green Blue ctColor value (ARGB). */ - public void setRgb(byte[] rgb) { + public void setRGB(byte[] rgb) { ctColor.setRgb(rgb); } -- 2.39.5