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