123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- /*
- * ====================================================================
- * 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.xslf.usermodel;
-
- import java.awt.Color;
-
- import javax.xml.namespace.QName;
-
- import org.apache.poi.sl.draw.DrawPaint;
- import org.apache.poi.sl.usermodel.AbstractColorStyle;
- import org.apache.poi.sl.usermodel.ColorStyle;
- import org.apache.poi.sl.usermodel.PresetColor;
- import org.apache.poi.util.Beta;
- import org.apache.poi.util.Internal;
- import org.apache.poi.util.POILogFactory;
- import org.apache.poi.util.POILogger;
- import org.apache.xmlbeans.XmlCursor;
- import org.apache.xmlbeans.XmlObject;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTFontReference;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveFixedPercentage;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTScRgbColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTSystemColor;
-
- /**
- * Encapsulates logic to read color definitions from DrawingML and convert them to java.awt.Color
- */
- @Beta
- @Internal
- public class XSLFColor {
- private static final POILogger LOGGER = POILogFactory.getLogger(XSLFColor.class);
- private static final QName VAL_ATTR = new QName("val");
-
- private XmlObject _xmlObject;
- private Color _color;
- private CTSchemeColor _phClr;
- private XSLFSheet _sheet;
-
- @SuppressWarnings("WeakerAccess")
- public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr, XSLFSheet sheet) {
- _xmlObject = obj;
- _phClr = phClr;
- _sheet = sheet;
- _color = toColor(obj, theme);
- }
-
- @Internal
- public XmlObject getXmlObject() {
- return _xmlObject;
- }
-
- /**
- *
- * @return the displayed color as a Java Color.
- * If not color information was found in the supplied xml object then a null is returned.
- */
- public Color getColor() {
- return DrawPaint.applyColorTransform(getColorStyle());
- }
-
-
- @SuppressWarnings("WeakerAccess")
- public ColorStyle getColorStyle() {
- return new XSLFColorStyle(_xmlObject, _color, _phClr);
- }
-
- private Color toColor(CTHslColor hsl) {
- return DrawPaint.HSL2RGB(
- hsl.getHue2() / 60000d,
- hsl.getSat2() / 1000d,
- hsl.getLum2() / 1000d,
- 1d);
- }
-
- private Color toColor(CTPresetColor prst) {
- String colorName = prst.getVal().toString();
- PresetColor pc = PresetColor.valueOfOoxmlId(colorName);
- return (pc != null) ? pc.color : null;
- }
-
- private Color toColor(CTSchemeColor schemeColor, XSLFTheme theme) {
- String colorRef = schemeColor.getVal().toString();
- if(_phClr != null) {
- // context color overrides the theme
- colorRef = _phClr.getVal().toString();
- }
- // find referenced CTColor in the theme and convert it to java.awt.Color via a recursive call
- CTColor ctColor = theme == null ? null : theme.getCTColor(_sheet.mapSchemeColor(colorRef));
- return (ctColor != null) ? toColor(ctColor, null) : null;
- }
-
- private Color toColor(CTScRgbColor scrgb) {
- // percental [0..100000] scRGB color space needs to be gamma corrected for AWT/sRGB colorspace
- return DrawPaint.SCRGB2RGB(scrgb.getR()/100_000d,scrgb.getG()/100_000d,scrgb.getB()/100_000d);
- }
-
- private Color toColor(CTSRgbColor srgb) {
- // color in sRGB color space, i.e. same as AWT Color
- byte[] val = srgb.getVal();
- return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
- }
-
- private Color toColor(CTSystemColor sys) {
- if (sys.isSetLastClr()) {
- byte[] val = sys.getLastClr();
- return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
- } else {
- String colorName = sys.getVal().toString();
- PresetColor pc = PresetColor.valueOfOoxmlId(colorName);
- return (pc != null && pc.color != null) ? pc.color : Color.black;
- }
- }
-
- private Color toColor(XmlObject obj, XSLFTheme theme) {
- if (obj == null) {
- return _phClr == null ? null : toColor(_phClr, theme);
- }
-
- final XmlCursor cur = obj.newCursor();
- Color color = null;
- try {
- XmlObject ch;
- for (int idx=0; color == null && (ch = nextObject(obj, cur, idx)) != null; idx++) {
- if (ch instanceof CTHslColor) {
- color = toColor((CTHslColor)ch);
- } else if (ch instanceof CTPresetColor) {
- color = toColor((CTPresetColor)ch);
- } else if (ch instanceof CTSchemeColor) {
- color = toColor((CTSchemeColor)ch, theme);
- } else if (ch instanceof CTScRgbColor) {
- color = toColor((CTScRgbColor)ch);
- } else if (ch instanceof CTSRgbColor) {
- color = toColor((CTSRgbColor)ch);
- } else if (ch instanceof CTSystemColor) {
- color = toColor((CTSystemColor)ch);
- } else if (!(ch instanceof CTFontReference) && idx > 0) {
- throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass());
- }
- }
- } finally {
- cur.dispose();
- }
- return color;
- }
-
- private static XmlObject nextObject(XmlObject obj, XmlCursor cur, int idx) {
- switch (idx) {
- case 0:
- return obj;
- case 1:
- return cur.toFirstChild() ? cur.getObject() : null;
- default:
- return cur.toNextSibling() ? cur.getObject() : null;
- }
- }
-
- /**
- * Sets the solid color
- *
- * @param color solid color
- */
- @Internal
- protected void setColor(Color color) {
- if (!(_xmlObject instanceof CTSolidColorFillProperties)) {
- LOGGER.log(POILogger.ERROR, "XSLFColor.setColor currently only supports CTSolidColorFillProperties");
- return;
- }
- CTSolidColorFillProperties fill = (CTSolidColorFillProperties)_xmlObject;
- if (fill.isSetSrgbClr()) {
- fill.unsetSrgbClr();
- }
-
- if (fill.isSetScrgbClr()) {
- fill.unsetScrgbClr();
- }
-
- if (fill.isSetHslClr()) {
- fill.unsetHslClr();
- }
-
- if (fill.isSetPrstClr()) {
- fill.unsetPrstClr();
- }
-
- if (fill.isSetSchemeClr()) {
- fill.unsetSchemeClr();
- }
-
- if (fill.isSetSysClr()) {
- fill.unsetSysClr();
- }
-
- float[] rgbaf = color.getRGBComponents(null);
- boolean addAlpha = (rgbaf.length == 4 && rgbaf[3] < 1f);
- CTPositiveFixedPercentage alphaPct;
-
- // see office open xml part 4 - 5.1.2.2.30 and 5.1.2.2.32
- if (isInt(rgbaf[0]) && isInt(rgbaf[1]) && isInt(rgbaf[2])) {
- // sRGB has a gamma of 2.2
- CTSRgbColor rgb = fill.addNewSrgbClr();
-
- byte[] rgbBytes = {(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()};
- rgb.setVal(rgbBytes);
- alphaPct = (addAlpha) ? rgb.addNewAlpha() : null;
- } else {
- CTScRgbColor rgb = fill.addNewScrgbClr();
- double[] scRGB = DrawPaint.RGB2SCRGB(color);
- rgb.setR((int)Math.rint(scRGB[0]*100_000d));
- rgb.setG((int)Math.rint(scRGB[1]*100_000d));
- rgb.setB((int)Math.rint(scRGB[2]*100_000d));
- alphaPct = (addAlpha) ? rgb.addNewAlpha() : null;
- }
-
- // alpha (%)
- if (alphaPct != null) {
- alphaPct.setVal((int)Math.rint(rgbaf[3]*100_000));
- }
- }
-
- /**
- * @return true, if this is an integer color value
- */
- private static boolean isInt(float f) {
- return Math.abs((f*255d) - Math.rint(f*255d)) < 0.00001;
- }
-
- private static int getRawValue(CTSchemeColor phClr, XmlObject xmlObject, String elem) {
- for (XmlObject obj : new XmlObject[]{xmlObject,phClr}) {
- if (obj == null) {
- continue;
- }
- XmlCursor cur = obj.newCursor();
- try {
- if (!(
- cur.toChild(XSLFRelation.NS_DRAWINGML, elem) ||
- (cur.toFirstChild() && cur.toChild(XSLFRelation.NS_DRAWINGML, elem))
- )) {
- continue;
- }
- String str = cur.getAttributeText(VAL_ATTR);
- if (str != null && !"".equals(str)) {
- return Integer.parseInt(str);
- }
- } finally {
- cur.dispose();
- }
- }
- return -1;
- }
-
- /**
- * Read a perecentage value from the supplied xml bean.
- * Example:
- * <a:tint val="45000"/>
- *
- * the returned value is 45
- *
- * @return the percentage value in the range [0 .. 100]
- */
- private int getPercentageValue(String elem){
- int val = getRawValue(_phClr, _xmlObject, elem);
- return (val == -1) ? val : (val / 1000);
- }
-
- /**
- * the opacity as expressed by a percentage value
- *
- * @return opacity in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getAlpha(){
- return getPercentageValue("alpha");
- }
-
- /**
- * the opacity as expressed by a percentage relative to the input color
- *
- * @return opacity in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getAlphaMod(){
- return getPercentageValue("alphaMod");
- }
-
- /**
- * the opacity as expressed by a percentage offset increase or decrease relative to
- * the input color. Increases will never increase the opacity beyond 100%, decreases will
- * never decrease the opacity below 0%.
- *
- * @return opacity shift in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getAlphaOff(){
- return getPercentageValue("alphaOff");
- }
-
-
- @SuppressWarnings("unused")
- int getHue(){
- int val = getRawValue(_phClr, _xmlObject, "hue");
- return (val == -1) ? val : (val / 60000);
- }
-
- @SuppressWarnings("unused")
- int getHueMod(){
- return getPercentageValue("hueMod");
- }
-
- @SuppressWarnings("unused")
- int getHueOff(){
- return getPercentageValue("hueOff");
- }
-
- /**
- * specifies the input color with the specified luminance,
- * but with its hue and saturation unchanged.
- *
- * @return luminance in percents in the range [0..100]
- * or -1 if the value is not set
- */
- @SuppressWarnings("unused")
- int getLum(){
- return getPercentageValue("lum");
- }
-
- /**
- * the luminance as expressed by a percentage relative to the input color
- *
- * @return luminance in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getLumMod(){
- return getPercentageValue("lumMod");
- }
-
- /**
- * the luminance shift as expressed by a percentage relative to the input color
- *
- * @return luminance shift in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getLumOff(){
- return getPercentageValue("lumOff");
- }
-
- /**
- * specifies the input color with the specified saturation,
- * but with its hue and luminance unchanged.
- *
- * @return saturation in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getSat(){
- return getPercentageValue("sat");
- }
-
- /**
- * the saturation as expressed by a percentage relative to the input color
- *
- * @return saturation in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getSatMod(){
- return getPercentageValue("satMod");
- }
-
- /**
- * the saturation shift as expressed by a percentage relative to the input color
- *
- * @return saturation shift in percents in the range [0..100]
- * or -1 if the value is not set
- */
- int getSatOff(){
- return getPercentageValue("satOff");
- }
-
- /**
- * specifies the input color with the specific red component, but with the blue and green color
- * components unchanged
- *
- * @return the value of the red component specified as a
- * percentage with 0% indicating minimal blue and 100% indicating maximum
- * or -1 if the value is not set
- */
- int getRed(){
- return getPercentageValue("red");
- }
-
- @SuppressWarnings("unused")
- int getRedMod(){
- return getPercentageValue("redMod");
- }
-
- @SuppressWarnings("unused")
- int getRedOff(){
- return getPercentageValue("redOff");
- }
-
- /**
- * specifies the input color with the specific green component, but with the red and blue color
- * components unchanged
- *
- * @return the value of the green component specified as a
- * percentage with 0% indicating minimal blue and 100% indicating maximum
- * or -1 if the value is not set
- */
- int getGreen(){
- return getPercentageValue("green");
- }
-
- @SuppressWarnings("unused")
- int getGreenMod(){
- return getPercentageValue("greenMod");
- }
-
- @SuppressWarnings("unused")
- int getGreenOff(){
- return getPercentageValue("greenOff");
- }
-
- /**
- * specifies the input color with the specific blue component, but with the red and green color
- * components unchanged
- *
- * @return the value of the blue component specified as a
- * percentage with 0% indicating minimal blue and 100% indicating maximum
- * or -1 if the value is not set
- */
- int getBlue(){
- return getPercentageValue("blue");
- }
-
- @SuppressWarnings("unused")
- int getBlueMod(){
- return getPercentageValue("blueMod");
- }
-
- @SuppressWarnings("unused")
- int getBlueOff(){
- return getPercentageValue("blueOff");
- }
-
- /**
- * specifies a darker version of its input color.
- * A 10% shade is 10% of the input color combined with 90% black.
- *
- * @return the value of the shade specified as a
- * percentage with 0% indicating minimal shade and 100% indicating maximum
- * or -1 if the value is not set
- */
- @SuppressWarnings("WeakerAccess")
- public int getShade(){
- return getPercentageValue("shade");
- }
-
- /**
- * specifies a lighter version of its input color.
- * A 10% tint is 10% of the input color combined with 90% white.
- *
- * @return the value of the tint specified as a
- * percentage with 0% indicating minimal tint and 100% indicating maximum
- * or -1 if the value is not set
- */
- public int getTint(){
- return getPercentageValue("tint");
- }
-
- private static class XSLFColorStyle extends AbstractColorStyle {
- private XmlObject xmlObject;
- private Color color;
- private CTSchemeColor phClr;
-
- XSLFColorStyle(XmlObject xmlObject, Color color, CTSchemeColor phClr) {
- this.xmlObject = xmlObject;
- this.color = color;
- this.phClr = phClr;
- }
-
- @Override
- public Color getColor() {
- return color;
- }
-
- @Override
- public int getAlpha() {
- return getRawValue(phClr, xmlObject, "alpha");
- }
-
- @Override
- public int getHueOff() {
- return getRawValue(phClr, xmlObject, "hueOff");
- }
-
- @Override
- public int getHueMod() {
- return getRawValue(phClr, xmlObject, "hueMod");
- }
-
- @Override
- public int getSatOff() {
- return getRawValue(phClr, xmlObject, "satOff");
- }
-
- @Override
- public int getSatMod() {
- return getRawValue(phClr, xmlObject, "satMod");
- }
-
- @Override
- public int getLumOff() {
- return getRawValue(phClr, xmlObject, "lumOff");
- }
-
- @Override
- public int getLumMod() {
- return getRawValue(phClr, xmlObject, "lumMod");
- }
-
- @Override
- public int getShade() {
- return getRawValue(phClr, xmlObject, "shade");
- }
-
- @Override
- public int getTint() {
- return getRawValue(phClr, xmlObject, "tint");
- }
- }
- }
|