001: /*
002: * $RCSfile: ChannelDefinitionBox.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:31 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.jpeg2000;
046:
047: import java.awt.image.ColorModel;
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: /** This class is designed to represent a Channel Definition Box of
054: * JPEG JP2 file format. A Channel Definition Box has a length, and
055: * a fixed type of "cdef". Its content defines the type of the image
056: * channels: color channel, alpha channel or premultiplied alpha channel.
057: */
058: public class ChannelDefinitionBox extends Box {
059: /** The cached data elements. */
060: private short num;
061: private short[] channels;
062: private short[] types;
063: private short[] associations;
064:
065: /** Computes the length of this box from the provided
066: * <code>ColorModel</code>.
067: */
068: private static int computeLength(ColorModel colorModel) {
069: int length = colorModel.getComponentSize().length - 1;
070: return 10 + (colorModel.isAlphaPremultiplied() ? length * 18
071: : length * 12);
072: }
073:
074: /** Fills the channel definitions into the arrays based on the number
075: * of components and isPremultiplied.
076: */
077: public static void fillBasedOnBands(int numComps,
078: boolean isPremultiplied, short[] c, short[] t, short[] a) {
079: int num = numComps * (isPremultiplied ? 3 : 2);
080: if (isPremultiplied) {
081: for (int i = numComps * 2; i < num; i++) {
082: c[i] = (short) (i - numComps * 2);
083: t[i] = 2; // 2 -- premultiplied
084: a[i] = (short) (i + 1 - numComps * 2);
085: }
086: }
087:
088: for (int i = 0; i < numComps; i++) {
089: int j = i + numComps;
090: c[i] = (short) i;
091: t[i] = 0; // The original channel
092: a[j] = a[i] = (short) (i + 1);
093:
094: c[j] = (short) numComps;
095: t[j] = 1; // 1 -- transparency
096: }
097: }
098:
099: /** Constructs a <code>ChannelDefinitionBox</code> based on the provided
100: * <code>ColorModel</code>.
101: */
102: public ChannelDefinitionBox(ColorModel colorModel) {
103: super (computeLength(colorModel), 0x63646566, null);
104:
105: // creates the buffers for the channel definitions.
106: short length = (short) (colorModel.getComponentSize().length - 1);
107: num = (short) (length * (colorModel.isAlphaPremultiplied() ? 3
108: : 2));
109: channels = new short[num];
110: types = new short[num];
111: associations = new short[num];
112:
113: // fills the arrays.
114: fillBasedOnBands(length, colorModel.isAlphaPremultiplied(),
115: channels, types, associations);
116: }
117:
118: /** Constructs a <code>ChannelDefinitionBox</code> based on the provided
119: * content in byte array.
120: */
121: public ChannelDefinitionBox(byte[] data) {
122: super (8 + data.length, 0x63646566, data);
123: }
124:
125: /** Constructs a <code>ChannelDefinitionBox</code> based on the provided
126: * channel definitions.
127: */
128: public ChannelDefinitionBox(short[] channel, short[] types,
129: short[] associations) {
130: super (10 + channel.length * 6, 0x63646566, null);
131: this .num = (short) channel.length;
132: this .channels = channel;
133: this .types = types;
134: this .associations = associations;
135: }
136:
137: /** Constructs a <code>ChannelDefinitionBox</code> based on the provided
138: * <code>org.w3c.dom.Node</code>.
139: */
140: public ChannelDefinitionBox(Node node)
141: throws IIOInvalidTreeException {
142: super (node);
143: NodeList children = node.getChildNodes();
144: int index = 0;
145:
146: for (int i = 0; i < children.getLength(); i++) {
147: Node child = children.item(i);
148: String name = child.getNodeName();
149:
150: if ("NumberOfDefinition".equals(name)) {
151: num = Box.getShortElementValue(child);
152: }
153:
154: if ("Definitions".equals(name)) {
155: channels = new short[num];
156: types = new short[num];
157: associations = new short[num];
158:
159: NodeList children1 = child.getChildNodes();
160:
161: for (int j = 0; j < children1.getLength(); j++) {
162: child = children1.item(j);
163: name = child.getNodeName();
164: if ("ChannelNumber".equals(name)) {
165: channels[index] = Box
166: .getShortElementValue(child);
167: }
168:
169: if ("ChannelType".equals(name)) {
170: types[index] = Box.getShortElementValue(child);
171: }
172:
173: if ("Association".equals(name)) {
174: associations[index++] = Box
175: .getShortElementValue(child);
176: }
177: }
178: }
179: }
180: }
181:
182: /** Parse the channel definitions from the content data array. */
183: protected void parse(byte[] data) {
184: num = (short) ((data[0] << 8) | data[1]);
185: channels = new short[num];
186: types = new short[num];
187: associations = new short[num];
188:
189: for (int i = 0, j = 2; i < num; i++) {
190: channels[i] = (short) (((data[j++] & 0xFF) << 8) + (data[j++] & 0xFF));
191: types[i] = (short) (((data[j++] & 0xFF) << 8) + (data[j++] & 0xFF));
192: associations[i] = (short) (((data[j++] & 0xFF) << 8) + (data[j++] & 0xFF));
193: }
194: }
195:
196: /** Returns the defined channels. */
197: public short[] getChannel() {
198: return channels;
199: }
200:
201: /** Returns the channel types. */
202: public short[] getTypes() {
203: return types;
204: }
205:
206: /** Returns the association which associates a color channel to a color
207: * component in the color space of the image.
208: */
209: public short[] getAssociation() {
210: return associations;
211: }
212:
213: /** Creates an <code>IIOMetadataNode</code> from this channel definition
214: * box. The format of this node is defined in the XML dtd and xsd
215: * for the JP2 image file.
216: */
217: public IIOMetadataNode getNativeNode() {
218: IIOMetadataNode node = new IIOMetadataNode(Box
219: .getName(getType()));
220: setDefaultAttributes(node);
221:
222: IIOMetadataNode child = new IIOMetadataNode(
223: "NumberOfDefinition");
224: child.setUserObject(new Short(num));
225: child.setNodeValue("" + num);
226: node.appendChild(child);
227:
228: child = new IIOMetadataNode("Definitions");
229: node.appendChild(child);
230:
231: for (int i = 0; i < num; i++) {
232: IIOMetadataNode child1 = new IIOMetadataNode(
233: "ChannelNumber");
234: child1.setUserObject(new Short(channels[i]));
235: child1.setNodeValue("" + channels[i]);
236: child.appendChild(child1);
237:
238: child1 = new IIOMetadataNode("ChannelType");
239: child1.setUserObject(new Short(types[i]));
240: child1.setNodeValue("" + types[i]);
241: child.appendChild(child1);
242:
243: child1 = new IIOMetadataNode("Association");
244: child1.setUserObject(new Short(associations[i]));
245: child1.setNodeValue("" + associations[i]);
246: child.appendChild(child1);
247: }
248:
249: return node;
250: }
251:
252: protected void compose() {
253: if (data != null)
254: return;
255: int len = num * 6 + 2;
256: data = new byte[len];
257: data[0] = (byte) (num >> 8);
258: data[1] = (byte) (num & 0xFF);
259:
260: for (int i = 0, j = 2; i < num; i++) {
261: data[j++] = (byte) (channels[i] >> 8);
262: data[j++] = (byte) (channels[i] & 0xFF);
263:
264: data[j++] = (byte) (types[i] >> 8);
265: data[j++] = (byte) (types[i] & 0xFF);
266:
267: data[j++] = (byte) (associations[i] >> 8);
268: data[j++] = (byte) (associations[i] & 0xFF);
269: }
270: }
271: }
|