001: /*
002: * $RCSfile: PaletteBox.java,v $
003: *
004: *
005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * - Redistribution of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * - Redistribution in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * Neither the name of Sun Microsystems, Inc. or the names of
020: * contributors may be used to endorse or promote products derived
021: * from this software without specific prior written permission.
022: *
023: * This software is provided "AS IS," without a warranty of any
024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
035: * POSSIBILITY OF SUCH DAMAGES.
036: *
037: * You acknowledge that this software is not designed or intended for
038: * use in the design, construction, operation or maintenance of any
039: * nuclear facility.
040: *
041: * $Revision: 1.1 $
042: * $Date: 2005/02/11 05:01:36 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.jpeg2000;
046:
047: import java.awt.image.IndexColorModel;
048: import javax.imageio.metadata.IIOInvalidTreeException;
049: import javax.imageio.metadata.IIOMetadataNode;
050: import org.w3c.dom.Node;
051: import org.w3c.dom.NodeList;
052:
053: import com.sun.media.imageioimpl.common.ImageUtil;
054:
055: /** This class is designed to represent a palette box for JPEG 2000 JP2 file
056: * format. A palette box has a length, and a fixed type of "pclr".
057: *
058: * Its content contains the number of palette entry, the number of color
059: * components, the bit depths of the output components, the LUT.
060: *
061: * Currently, only 8-bit color index is supported.
062: */
063: public class PaletteBox extends Box {
064: /** The value of the data elements.
065: */
066: private int numEntries;
067: private int numComps;
068: private byte[] bitDepth;
069: private byte[][] lut;
070:
071: /** Compute the length of this box. */
072: private static int computeLength(IndexColorModel icm) {
073: int size = icm.getMapSize();
074: int[] comp = icm.getComponentSize();
075: return 11 + comp.length + size * comp.length;
076: }
077:
078: /** Gets the size of the components or the bit depth for all the color
079: * coomponents.
080: */
081: private static byte[] getCompSize(IndexColorModel icm) {
082: int[] comp = icm.getComponentSize();
083: int size = comp.length;
084: byte[] buf = new byte[size];
085: for (int i = 0; i < size; i++)
086: buf[i] = (byte) (comp[i] - 1);
087: return buf;
088: }
089:
090: /** Gets the LUT from the <code>IndexColorModel</code> as an two-dimensional
091: * byte array.
092: */
093: private static byte[][] getLUT(IndexColorModel icm) {
094: int[] comp = icm.getComponentSize();
095: int size = icm.getMapSize();
096: byte[][] lut = new byte[comp.length][size];
097: icm.getReds(lut[0]);
098: icm.getGreens(lut[1]);
099: icm.getBlues(lut[2]);
100: if (comp.length == 4)
101: icm.getAlphas(lut[3]);
102: return lut;
103: }
104:
105: /** Constructs a <code>PlatteBox</code> from an
106: * <code>IndexColorModel</code>.
107: */
108: public PaletteBox(IndexColorModel icm) {
109: this (computeLength(icm), getCompSize(icm), getLUT(icm));
110: }
111:
112: /** Constructs a <code>PlatteBox</code> from an
113: * <code>org.w3c.dom.Node</code>.
114: */
115: public PaletteBox(Node node) throws IIOInvalidTreeException {
116: super (node);
117: byte[][] tlut = null;
118: int index = 0;
119:
120: NodeList children = node.getChildNodes();
121: for (int i = 0; i < children.getLength(); i++) {
122: Node child = children.item(i);
123: String name = child.getNodeName();
124:
125: if ("NumberEntries".equals(name)) {
126: numEntries = Box.getIntElementValue(child);
127: }
128:
129: if ("NumberColors".equals(name)) {
130: numComps = Box.getIntElementValue(child);
131: }
132:
133: if ("BitDepth".equals(name)) {
134: bitDepth = Box.getByteArrayElementValue(child);
135: }
136:
137: if ("LUT".equals(name)) {
138: tlut = new byte[numEntries][];
139:
140: NodeList children1 = child.getChildNodes();
141:
142: for (int j = 0; j < children1.getLength(); j++) {
143: Node child1 = children1.item(j);
144: name = child1.getNodeName();
145: if ("LUTRow".equals(name)) {
146: tlut[index++] = Box
147: .getByteArrayElementValue(child1);
148: }
149: }
150: }
151: }
152:
153: //XXX: currently only 8-bit LUT is supported so no decode is needed
154: // For more refer to read palette box section.
155: lut = new byte[numComps][numEntries];
156:
157: for (int i = 0; i < numComps; i++)
158: for (int j = 0; j < numEntries; j++)
159: lut[i][j] = tlut[j][i];
160:
161: }
162:
163: /** Constructs a <code>PlatteBox</code> from the provided length, bit
164: * depths of the color components and the LUT.
165: */
166: public PaletteBox(int length, byte[] comp, byte[][] lut) {
167: super (length, 0x70636C72, null);
168: this .bitDepth = comp;
169: this .lut = lut;
170: this .numEntries = lut[0].length;
171: this .numComps = lut.length;
172: }
173:
174: /** Constructs a <code>PlatteBox</code> from the provided byte array.
175: */
176: public PaletteBox(byte[] data) {
177: super (8 + data.length, 0x70636C72, data);
178: }
179:
180: /** Return the number of palette entries. */
181: public int getNumEntries() {
182: return numEntries;
183: }
184:
185: /** Return the number of color components. */
186: public int getNumComp() {
187: return numComps;
188: }
189:
190: /** Return the bit depths for all the color components. */
191: public byte[] getBitDepths() {
192: return bitDepth;
193: }
194:
195: /** Return the LUT. */
196: public byte[][] getLUT() {
197: return lut;
198: }
199:
200: /** creates an <code>IIOMetadataNode</code> from this palette box.
201: * The format of this node is defined in the XML dtd and xsd
202: * for the JP2 image file.
203: */
204: public IIOMetadataNode getNativeNode() {
205: IIOMetadataNode node = new IIOMetadataNode(Box
206: .getName(getType()));
207: setDefaultAttributes(node);
208:
209: IIOMetadataNode child = new IIOMetadataNode("NumberEntries");
210: child.setUserObject(new Integer(numEntries));
211: child.setNodeValue("" + numEntries);
212: node.appendChild(child);
213:
214: child = new IIOMetadataNode("NumberColors");
215: child.setUserObject(new Integer(numComps));
216: child.setNodeValue("" + numComps);
217: node.appendChild(child);
218:
219: child = new IIOMetadataNode("BitDepth");
220: child.setUserObject(bitDepth);
221: child.setNodeValue(ImageUtil.convertObjectToString(bitDepth));
222: node.appendChild(child);
223:
224: child = new IIOMetadataNode("LUT");
225: for (int i = 0; i < numEntries; i++) {
226: IIOMetadataNode child1 = new IIOMetadataNode("LUTRow");
227: byte[] row = new byte[numComps];
228: for (int j = 0; j < numComps; j++)
229: row[j] = lut[j][i];
230:
231: child1.setUserObject(row);
232: child1.setNodeValue(ImageUtil.convertObjectToString(row));
233: child.appendChild(child1);
234: }
235: node.appendChild(child);
236:
237: return node;
238: }
239:
240: protected void parse(byte[] data) {
241: if (data == null)
242: return;
243: numEntries = (short) (((data[0] & 0xFF) << 8) | (data[1] & 0xFF));
244:
245: numComps = data[2];
246: bitDepth = new byte[numComps];
247: System.arraycopy(data, 3, bitDepth, 0, numComps);
248:
249: lut = new byte[numComps][numEntries];
250: for (int i = 0, k = 3 + numComps; i < numEntries; i++)
251: for (int j = 0; j < numComps; j++)
252: lut[j][i] = data[k++];
253: }
254:
255: protected void compose() {
256: if (data != null)
257: return;
258: data = new byte[3 + numComps + numEntries * numComps];
259: data[0] = (byte) (numEntries >> 8);
260: data[1] = (byte) (numEntries & 0xFF);
261:
262: data[2] = (byte) numComps;
263: System.arraycopy(bitDepth, 0, data, 3, numComps);
264:
265: for (int i = 0, k = 3 + numComps; i < numEntries; i++)
266: for (int j = 0; j < numComps; j++)
267: data[k++] = lut[j][i];
268: }
269: }
|