001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hssf.record;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.apache.poi.util.LittleEndian;
024:
025: /**
026: * PaletteRecord - Supports custom palettes.
027: * @author Andrew C. Oliver (acoliver at apache dot org)
028: * @author Brian Sanders (bsanders at risklabs dot com) - custom palette editing
029: * @version 2.0-pre
030: */
031:
032: public class PaletteRecord extends Record {
033: public final static short sid = 0x92;
034: /** The standard size of an XLS palette */
035: public final static byte STANDARD_PALETTE_SIZE = (byte) 56;
036: /** The byte index of the first color */
037: public final static short FIRST_COLOR_INDEX = (short) 0x8;
038:
039: private short field_1_numcolors;
040: private List field_2_colors;
041:
042: public PaletteRecord() {
043: createDefaultPalette();
044: }
045:
046: /**
047: * Constructs a PaletteRecord record and sets its fields appropriately.
048: * @param in the RecordInputstream to read the record from
049: */
050:
051: public PaletteRecord(RecordInputStream in) {
052: super (in);
053: }
054:
055: protected void validateSid(short id) {
056: if (id != sid) {
057: throw new RecordFormatException("NOT An Palette RECORD");
058: }
059: }
060:
061: protected void fillFields(RecordInputStream in) {
062: field_1_numcolors = in.readShort();
063: field_2_colors = new ArrayList(field_1_numcolors);
064: for (int k = 0; k < field_1_numcolors; k++) {
065: field_2_colors.add(new PColor(in.readByte(), in.readByte(),
066: in.readByte()));
067: //Read unused byte.
068: in.readByte();
069: }
070: }
071:
072: public String toString() {
073: StringBuffer buffer = new StringBuffer();
074:
075: buffer.append("[PALETTE]\n");
076: buffer.append(" numcolors = ").append(field_1_numcolors)
077: .append('\n');
078: for (int k = 0; k < field_1_numcolors; k++) {
079: PColor c = (PColor) field_2_colors.get(k);
080: buffer.append("* colornum = ").append(k).append('\n');
081: buffer.append(c.toString());
082: buffer.append("/*colornum = ").append(k).append('\n');
083: }
084: buffer.append("[/PALETTE]\n");
085: return buffer.toString();
086: }
087:
088: public int serialize(int offset, byte[] data) {
089: LittleEndian.putShort(data, 0 + offset, sid);
090: LittleEndian.putShort(data, 2 + offset,
091: (short) (getRecordSize() - 4));
092: LittleEndian.putShort(data, 4 + offset, field_1_numcolors);
093: for (int k = 0; k < field_1_numcolors; k++) {
094: PColor c = (PColor) field_2_colors.get(k);
095: c.serialize(data, (6 + offset + (k * 4)));
096: }
097:
098: return getRecordSize();
099: }
100:
101: public int getRecordSize() {
102: return 4 + 2 + (field_1_numcolors * 4);
103: }
104:
105: public short getSid() {
106: return sid;
107: }
108:
109: /**
110: * Returns the color value at a given index
111: *
112: * @return the RGB triplet for the color, or null if the specified index
113: * does not exist
114: */
115: public byte[] getColor(short byteIndex) {
116: int i = byteIndex - FIRST_COLOR_INDEX;
117: if (i < 0 || i >= field_2_colors.size()) {
118: return null;
119: }
120: PColor color = (PColor) field_2_colors.get(i);
121: return new byte[] { color.red, color.green, color.blue };
122: }
123:
124: /**
125: * Sets the color value at a given index
126: *
127: * If the given index is greater than the current last color index,
128: * then black is inserted at every index required to make the palette continuous.
129: *
130: * @param byteIndex the index to set; if this index is less than 0x8 or greater than
131: * 0x40, then no modification is made
132: */
133: public void setColor(short byteIndex, byte red, byte green,
134: byte blue) {
135: int i = byteIndex - FIRST_COLOR_INDEX;
136: if (i < 0 || i >= STANDARD_PALETTE_SIZE) {
137: return;
138: }
139: while (field_2_colors.size() <= i) {
140: field_2_colors
141: .add(new PColor((byte) 0, (byte) 0, (byte) 0));
142: }
143: PColor custColor = new PColor(red, green, blue);
144: field_2_colors.set(i, custColor);
145: }
146:
147: /**
148: * Creates the default palette as PaletteRecord binary data
149: *
150: * @see org.apache.poi.hssf.model.Workbook#createPalette
151: */
152: private void createDefaultPalette() {
153: field_1_numcolors = STANDARD_PALETTE_SIZE;
154: field_2_colors = new ArrayList(field_1_numcolors);
155: byte[] palette = new byte[] {
156: (byte) 0,
157: (byte) 0,
158: (byte) 0,
159: (byte) 0, //color 0...
160: (byte) 255, (byte) 255, (byte) 255, (byte) 0,
161: (byte) 255, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
162: (byte) 255, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
163: (byte) 255, (byte) 0, (byte) 255, (byte) 255, (byte) 0,
164: (byte) 0, (byte) 255, (byte) 0, (byte) 255, (byte) 0,
165: (byte) 0, (byte) 255, (byte) 255, (byte) 0, (byte) 128,
166: (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 128,
167: (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 128,
168: (byte) 0, (byte) 128, (byte) 128, (byte) 0, (byte) 0,
169: (byte) 128, (byte) 0, (byte) 128, (byte) 0, (byte) 0,
170: (byte) 128, (byte) 128, (byte) 0, (byte) 192,
171: (byte) 192, (byte) 192, (byte) 0, (byte) 128,
172: (byte) 128, (byte) 128, (byte) 0, (byte) 153,
173: (byte) 153, (byte) 255, (byte) 0, (byte) 153,
174: (byte) 51, (byte) 102, (byte) 0, (byte) 255,
175: (byte) 255, (byte) 204, (byte) 0, (byte) 204,
176: (byte) 255, (byte) 255, (byte) 0, (byte) 102, (byte) 0,
177: (byte) 102, (byte) 0, (byte) 255, (byte) 128,
178: (byte) 128, (byte) 0, (byte) 0, (byte) 102, (byte) 204,
179: (byte) 0, (byte) 204, (byte) 204, (byte) 255, (byte) 0,
180: (byte) 0, (byte) 0, (byte) 128, (byte) 0, (byte) 255,
181: (byte) 0, (byte) 255, (byte) 0, (byte) 255, (byte) 255,
182: (byte) 0, (byte) 0, (byte) 0, (byte) 255, (byte) 255,
183: (byte) 0, (byte) 128, (byte) 0, (byte) 128, (byte) 0,
184: (byte) 128, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
185: (byte) 128, (byte) 128, (byte) 0, (byte) 0, (byte) 0,
186: (byte) 255, (byte) 0, (byte) 0, (byte) 204, (byte) 255,
187: (byte) 0, (byte) 204, (byte) 255, (byte) 255, (byte) 0,
188: (byte) 204, (byte) 255, (byte) 204, (byte) 0,
189: (byte) 255, (byte) 255, (byte) 153, (byte) 0,
190: (byte) 153, (byte) 204, (byte) 255, (byte) 0,
191: (byte) 255, (byte) 153, (byte) 204, (byte) 0,
192: (byte) 204, (byte) 153, (byte) 255, (byte) 0,
193: (byte) 255, (byte) 204, (byte) 153, (byte) 0,
194: (byte) 51, (byte) 102, (byte) 255, (byte) 0, (byte) 51,
195: (byte) 204, (byte) 204, (byte) 0, (byte) 153,
196: (byte) 204, (byte) 0, (byte) 0, (byte) 255, (byte) 204,
197: (byte) 0, (byte) 0, (byte) 255, (byte) 153, (byte) 0,
198: (byte) 0, (byte) 255, (byte) 102, (byte) 0, (byte) 0,
199: (byte) 102, (byte) 102, (byte) 153, (byte) 0,
200: (byte) 150, (byte) 150, (byte) 150, (byte) 0, (byte) 0,
201: (byte) 51, (byte) 102, (byte) 0, (byte) 51, (byte) 153,
202: (byte) 102, (byte) 0, (byte) 0, (byte) 51, (byte) 0,
203: (byte) 0, (byte) 51, (byte) 51, (byte) 0, (byte) 0,
204: (byte) 153, (byte) 51, (byte) 0, (byte) 0, (byte) 153,
205: (byte) 51, (byte) 102, (byte) 0, (byte) 51, (byte) 51,
206: (byte) 153, (byte) 0, (byte) 51, (byte) 51, (byte) 51,
207: (byte) 0 };
208:
209: for (int k = 0; k < field_1_numcolors; k++) {
210: field_2_colors.add(new PColor(palette[k * 4],
211: palette[k * 4 + 1], palette[k * 4 + 2]));
212: }
213:
214: }
215: }
216:
217: /**
218: * PColor - element in the list of colors - consider it a "struct"
219: */
220: class PColor {
221: public byte red;
222: public byte green;
223: public byte blue;
224:
225: public PColor(byte red, byte green, byte blue) {
226: this .red = red;
227: this .green = green;
228: this .blue = blue;
229: }
230:
231: public void serialize(byte[] data, int offset) {
232: data[offset + 0] = red;
233: data[offset + 1] = green;
234: data[offset + 2] = blue;
235: data[offset + 3] = 0;
236: }
237:
238: public String toString() {
239: StringBuffer buffer = new StringBuffer();
240: buffer.append(" red = ").append(red & 0xff).append(
241: '\n');
242: buffer.append(" green = ").append(green & 0xff)
243: .append('\n');
244: buffer.append(" blue = ").append(blue & 0xff).append(
245: '\n');
246: return buffer.toString();
247: }
248: }
|