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}