/* ==================================================================== | |
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.ddf; | |
import org.apache.poi.util.BitField; | |
import org.apache.poi.util.LittleEndian; | |
/** | |
* An OfficeArtCOLORREF structure entry which also handles color extension opid data | |
*/ | |
public class EscherColorRef { | |
int opid = -1; | |
int colorRef = 0; | |
public enum SysIndexSource { | |
/** Use the fill color of the shape. */ | |
FILL_COLOR(0xF0), | |
/** If the shape contains a line, use the line color of the shape. Otherwise, use the fill color. */ | |
LINE_OR_FILL_COLOR(0xF1), | |
/** Use the line color of the shape. */ | |
LINE_COLOR(0xF2), | |
/** Use the shadow color of the shape. */ | |
SHADOW_COLOR(0xF3), | |
/** Use the current, or last-used, color. */ | |
CURRENT_OR_LAST_COLOR(0xF4), | |
/** Use the fill background color of the shape. */ | |
FILL_BACKGROUND_COLOR(0xF5), | |
/** Use the line background color of the shape. */ | |
LINE_BACKGROUND_COLOR(0xF6), | |
/** If the shape contains a fill, use the fill color of the shape. Otherwise, use the line color. */ | |
FILL_OR_LINE_COLOR(0xF7) | |
; | |
int value; | |
SysIndexSource(int value) { this.value = value; } | |
} | |
/** | |
* The following enum specifies values that indicate special procedural properties that | |
* are used to modify the color components of another color. These values are combined with | |
* those of the {@link SysIndexSource} enum or with a user-specified color. | |
* The first six values are mutually exclusive. | |
*/ | |
public enum SysIndexProcedure { | |
/** | |
* Darken the color by the value that is specified in the blue field. | |
* A blue value of 0xFF specifies that the color is to be left unchanged, | |
* whereas a blue value of 0x00 specifies that the color is to be completely darkened. | |
*/ | |
DARKEN_COLOR(0x01), | |
/** | |
* Lighten the color by the value that is specified in the blue field. | |
* A blue value of 0xFF specifies that the color is to be left unchanged, | |
* whereas a blue value of 0x00 specifies that the color is to be completely lightened. | |
*/ | |
LIGHTEN_COLOR(0x02), | |
/** | |
* Add a gray level RGB value. The blue field contains the gray level to add: | |
* NewColor = SourceColor + gray | |
*/ | |
ADD_GRAY_LEVEL(0x03), | |
/** | |
* Subtract a gray level RGB value. The blue field contains the gray level to subtract: | |
* NewColor = SourceColor - gray | |
*/ | |
SUB_GRAY_LEVEL(0x04), | |
/** | |
* Reverse-subtract a gray level RGB value. The blue field contains the gray level from | |
* which to subtract: | |
* NewColor = gray - SourceColor | |
*/ | |
REVERSE_GRAY_LEVEL(0x05), | |
/** | |
* If the color component being modified is less than the parameter contained in the blue | |
* field, set it to the minimum intensity. If the color component being modified is greater | |
* than or equal to the parameter, set it to the maximum intensity. | |
*/ | |
THRESHOLD(0x06), | |
/** | |
* After making other modifications, invert the color. | |
* This enum value is only for documentation and won't be directly returned. | |
*/ | |
INVERT_AFTER(0x20), | |
/** | |
* After making other modifications, invert the color by toggling just the high bit of each | |
* color channel. | |
* This enum value is only for documentation and won't be directly returned. | |
*/ | |
INVERT_HIGHBIT_AFTER(0x40) | |
; | |
BitField mask; | |
SysIndexProcedure(int mask) { | |
this.mask = new BitField(mask); | |
} | |
} | |
/** | |
* A bit that specifies whether the system color scheme will be used to determine the color. | |
* A value of 0x1 specifies that green and red will be treated as an unsigned 16-bit index | |
* into the system color table. Values less than 0x00F0 map directly to system colors. | |
*/ | |
private static final BitField FLAG_SYS_INDEX = new BitField(0x10000000); | |
/** | |
* A bit that specifies whether the current application-defined color scheme will be used | |
* to determine the color. A value of 0x1 specifies that red will be treated as an index | |
* into the current color scheme table. If this value is 0x1, green and blue MUST be 0x00. | |
*/ | |
private static final BitField FLAG_SCHEME_INDEX = new BitField(0x08000000); | |
/** | |
* A bit that specifies whether the color is a standard RGB color. | |
* 0x0 : The RGB color MAY use halftone dithering to display. | |
* 0x1 : The color MUST be a solid color. | |
*/ | |
private static final BitField FLAG_SYSTEM_RGB = new BitField(0x04000000); | |
/** | |
* A bit that specifies whether the current palette will be used to determine the color. | |
* A value of 0x1 specifies that red, green, and blue contain an RGB value that will be | |
* matched in the current color palette. This color MUST be solid. | |
*/ | |
private static final BitField FLAG_PALETTE_RGB = new BitField(0x02000000); | |
/** | |
* A bit that specifies whether the current palette will be used to determine the color. | |
* A value of 0x1 specifies that green and red will be treated as an unsigned 16-bit index into | |
* the current color palette. This color MAY be dithered. If this value is 0x1, blue MUST be 0x00. | |
*/ | |
private static final BitField FLAG_PALETTE_INDEX = new BitField(0x01000000); | |
/** | |
* An unsigned integer that specifies the intensity of the blue color channel. A value | |
* of 0x00 has the minimum blue intensity. A value of 0xFF has the maximum blue intensity. | |
*/ | |
private static final BitField FLAG_BLUE = new BitField(0x00FF0000); | |
/** | |
* An unsigned integer that specifies the intensity of the green color channel. A value | |
* of 0x00 has the minimum green intensity. A value of 0xFF has the maximum green intensity. | |
*/ | |
private static final BitField FLAG_GREEN = new BitField(0x0000FF00); | |
/** | |
* An unsigned integer that specifies the intensity of the red color channel. A value | |
* of 0x00 has the minimum red intensity. A value of 0xFF has the maximum red intensity. | |
*/ | |
private static final BitField FLAG_RED = new BitField(0x000000FF); | |
public EscherColorRef(int colorRef) { | |
this.colorRef = colorRef; | |
} | |
public EscherColorRef(byte[] source, int start, int len) { | |
assert(len == 4 || len == 6); | |
int offset = start; | |
if (len == 6) { | |
opid = LittleEndian.getUShort(source, offset); | |
offset += 2; | |
} | |
colorRef = LittleEndian.getInt(source, offset); | |
} | |
public boolean hasSysIndexFlag() { | |
return FLAG_SYS_INDEX.isSet(colorRef); | |
} | |
public void setSysIndexFlag(boolean flag) { | |
colorRef = FLAG_SYS_INDEX.setBoolean(colorRef, flag); | |
} | |
public boolean hasSchemeIndexFlag() { | |
return FLAG_SCHEME_INDEX.isSet(colorRef); | |
} | |
public void setSchemeIndexFlag(boolean flag) { | |
colorRef = FLAG_SCHEME_INDEX.setBoolean(colorRef, flag); | |
} | |
public boolean hasSystemRGBFlag() { | |
return FLAG_SYSTEM_RGB.isSet(colorRef); | |
} | |
public void setSystemRGBFlag(boolean flag) { | |
colorRef = FLAG_SYSTEM_RGB.setBoolean(colorRef, flag); | |
} | |
public boolean hasPaletteRGBFlag() { | |
return FLAG_PALETTE_RGB.isSet(colorRef); | |
} | |
public void setPaletteRGBFlag(boolean flag) { | |
colorRef = FLAG_PALETTE_RGB.setBoolean(colorRef, flag); | |
} | |
public boolean hasPaletteIndexFlag() { | |
return FLAG_PALETTE_INDEX.isSet(colorRef); | |
} | |
public void setPaletteIndexFlag(boolean flag) { | |
colorRef = FLAG_PALETTE_INDEX.setBoolean(colorRef, flag); | |
} | |
public int[] getRGB() { | |
int rgb[] = { | |
FLAG_RED.getValue(colorRef), | |
FLAG_GREEN.getValue(colorRef), | |
FLAG_BLUE.getValue(colorRef) | |
}; | |
return rgb; | |
} | |
/** | |
* @return {@link SysIndexSource} if {@link #hasSysIndexFlag()} is {@code true}, otherwise null | |
*/ | |
public SysIndexSource getSysIndexSource() { | |
if (!hasSysIndexFlag()) return null; | |
int val = FLAG_RED.getValue(colorRef); | |
for (SysIndexSource sis : SysIndexSource.values()) { | |
if (sis.value == val) return sis; | |
} | |
return null; | |
} | |
/** | |
* Return the {@link SysIndexProcedure} - for invert flag use {@link #getSysIndexInvert()} | |
* @return {@link SysIndexProcedure} if {@link #hasSysIndexFlag()} is {@code true}, otherwise null | |
*/ | |
public SysIndexProcedure getSysIndexProcedure() { | |
if (!hasSysIndexFlag()) return null; | |
int val = FLAG_GREEN.getValue(colorRef); | |
for (SysIndexProcedure sip : SysIndexProcedure.values()) { | |
if (sip == SysIndexProcedure.INVERT_AFTER || sip == SysIndexProcedure.INVERT_HIGHBIT_AFTER) continue; | |
if (sip.mask.isSet(val)) return sip; | |
} | |
return null; | |
} | |
/** | |
* @return 0 for no invert flag, 1 for {@link SysIndexProcedure#INVERT_AFTER} and | |
* 2 for {@link SysIndexProcedure#INVERT_HIGHBIT_AFTER} | |
*/ | |
public int getSysIndexInvert() { | |
if (!hasSysIndexFlag()) return 0; | |
int val = FLAG_GREEN.getValue(colorRef); | |
if ((SysIndexProcedure.INVERT_AFTER.mask.isSet(val))) return 1; | |
if ((SysIndexProcedure.INVERT_HIGHBIT_AFTER.mask.isSet(val))) return 2; | |
return 0; | |
} | |
/** | |
* @return index of the scheme color or -1 if {@link #hasSchemeIndexFlag()} is {@code false} | |
* | |
* @see org.apache.poi.hslf.record.ColorSchemeAtom#getColor(int) | |
*/ | |
public int getSchemeIndex() { | |
if (!hasSchemeIndexFlag()) return -1; | |
return FLAG_RED.getValue(colorRef); | |
} | |
/** | |
* @return index of current palette (color) or -1 if {@link #hasPaletteIndexFlag()} is {@code false} | |
*/ | |
public int getPaletteIndex() { | |
return (hasPaletteIndexFlag()) ? getIndex() : -1; | |
} | |
/** | |
* @return index of system color table or -1 if {@link #hasSysIndexFlag()} is {@code false} | |
* | |
* @see org.apache.poi.sl.usermodel.PresetColor | |
*/ | |
public int getSysIndex() { | |
return (hasSysIndexFlag()) ? getIndex() : -1; | |
} | |
private int getIndex() { | |
return (FLAG_GREEN.getValue(colorRef) << 8) | FLAG_RED.getValue(colorRef); | |
} | |
} |