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