001/* 002 * $RCSfile: J2KMetadataFormat.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.2 $ 042 * $Date: 2005/04/27 18:23:01 $ 043 * $State: Exp $ 044 */ 045package com.github.jaiimageio.jpeg2000.impl; 046 047import java.awt.image.ColorModel; 048import java.awt.image.IndexColorModel; 049import java.lang.reflect.Method; 050import java.util.Enumeration; 051import java.util.Hashtable; 052import java.util.Iterator; 053import java.util.Set; 054 055import javax.imageio.ImageTypeSpecifier; 056import javax.imageio.metadata.IIOMetadataFormatImpl; 057 058public class J2KMetadataFormat extends IIOMetadataFormatImpl { 059 /** The table to link the child to its parent. 060 */ 061 private static Hashtable parents = new Hashtable(); 062 063 static { 064 //children for the root 065 parents.put("JPEG2000SignatureBox", "com_sun_media_imageio_plugins_jpeg2000_image_1.0"); 066 parents.put("JPEG2000FileTypeBox", "com_sun_media_imageio_plugins_jpeg2000_image_1.0"); 067 parents.put("OtherBoxes", "com_sun_media_imageio_plugins_jpeg2000_image_1.0"); 068 069 // children for the boxes other than 070 // JPEG2000SignatureBox/JPEG2000FileTypeBox 071 parents.put("JPEG2000HeaderSuperBox", "OtherBoxes"); 072 parents.put("JPEG2000CodeStreamBox", "OtherBoxes"); 073 074 parents.put("JPEG2000IntellectualPropertyRightsBox", "OtherBoxes"); 075 parents.put("JPEG2000XMLBox", "OtherBoxes"); 076 parents.put("JPEG2000UUIDBox", "OtherBoxes"); 077 parents.put("JPEG2000UUIDInfoBox", "OtherBoxes"); 078 079 // Children of JPEG2000HeaderSuperBox 080 parents.put("JPEG2000HeaderBox", "JPEG2000HeaderSuperBox"); 081 parents.put("OptionalBoxes", "JPEG2000HeaderSuperBox"); 082 083 // Optional boxes in JPEG2000HeaderSuperBox 084 parents.put("JPEG2000BitsPerComponentBox", "OptionalBoxes"); 085 parents.put("JPEG2000ColorSpecificationBox", "OptionalBoxes"); 086 parents.put("JPEG2000PaletteBox", "OptionalBoxes"); 087 parents.put("JPEG2000ComponentMappingBox", "OptionalBoxes"); 088 parents.put("JPEG2000ChannelDefinitionBox", "OptionalBoxes"); 089 parents.put("JPEG2000ResolutionBox", "OptionalBoxes"); 090 091 // Children of JPEG2000ResolutionBox 092 parents.put("JPEG2000CaptureResolutionBox", "JPEG2000ResolutionBox"); 093 parents.put("JPEG2000DefaultDisplayResolutionBox", 094 "JPEG2000ResolutionBox"); 095 096 // Children of JPEG2000UUIDInfoBox 097 parents.put("JPEG2000UUIDListBox", "JPEG2000UUIDInfoBox"); 098 parents.put("JPEG2000DataEntryURLBox", "JPEG2000UUIDInfoBox"); 099 } 100 101 private static J2KMetadataFormat instance; 102 103 public static synchronized J2KMetadataFormat getInstance() { 104 if (instance == null) 105 instance = new J2KMetadataFormat(); 106 return instance; 107 } 108 109 String resourceBaseName = this.getClass().getName() + "Resources"; 110 111 /** Constructs <code>J2KMetadataFormat</code>. Calls the super 112 * class constructor. Sets the resource base name. Adds the elements 113 * into this format object based on the XML schema and DTD. 114 */ 115 J2KMetadataFormat() { 116 super("com_sun_media_imageio_plugins_jpeg2000_image_1.0", CHILD_POLICY_ALL); 117 setResourceBaseName(resourceBaseName); 118 addElements(); 119 } 120 121 /** Adds the elements into this format object based on the XML 122 * schema and DTD. 123 */ 124 private void addElements() { 125 addElement("JPEG2000SignatureBox", 126 getParent("JPEG2000SignatureBox"), 127 CHILD_POLICY_EMPTY); 128 129 addElement("JPEG2000FileTypeBox", 130 getParent("JPEG2000FileTypeBox"), 131 CHILD_POLICY_ALL); 132 addElement("OtherBoxes", 133 getParent("OtherBoxes"), 134 CHILD_POLICY_CHOICE); 135 136 addElement("JPEG2000HeaderSuperBox", 137 getParent("JPEG2000HeaderSuperBox"), 138 CHILD_POLICY_CHOICE); 139 addElement("JPEG2000CodeStreamBox", 140 getParent("JPEG2000CodeStreamBox"), 141 CHILD_POLICY_EMPTY); 142 addElement("JPEG2000IntellectualPropertyRightsBox", 143 getParent("JPEG2000IntellectualPropertyRightsBox"), 144 CHILD_POLICY_ALL); 145 addElement("JPEG2000XMLBox", 146 getParent("JPEG2000XMLBox"), 147 CHILD_POLICY_ALL); 148 addElement("JPEG2000UUIDBox", 149 getParent("JPEG2000UUIDBox"), 150 CHILD_POLICY_ALL); 151 addElement("JPEG2000UUIDInfoBox", 152 getParent("JPEG2000UUIDInfoBox"), 153 CHILD_POLICY_ALL); 154 155 addElement("JPEG2000HeaderBox", 156 "JPEG2000HeaderSuperBox", 157 CHILD_POLICY_ALL); 158 addElement("OptionalBoxes", 159 "JPEG2000HeaderSuperBox", 160 CHILD_POLICY_CHOICE); 161 addElement("JPEG2000BitsPerComponentBox", 162 "OptionalBoxes", 163 CHILD_POLICY_ALL); 164 addElement("JPEG2000ColorSpecificationBox", 165 "OptionalBoxes", 166 CHILD_POLICY_ALL); 167 addElement("JPEG2000PaletteBox", 168 "OptionalBoxes", 169 CHILD_POLICY_ALL); 170 addElement("JPEG2000ComponentMappingBox", 171 "OptionalBoxes", 172 CHILD_POLICY_ALL); 173 addElement("JPEG2000ChannelDefinitionBox", 174 "OptionalBoxes", 175 CHILD_POLICY_ALL); 176 addElement("JPEG2000ResolutionBox", 177 "OptionalBoxes", 178 CHILD_POLICY_ALL); 179 180 addElement("JPEG2000CaptureResolutionBox", 181 "JPEG2000ResolutionBox", 182 CHILD_POLICY_ALL); 183 addElement("JPEG2000DefaultDisplayResolutionBox", 184 "JPEG2000ResolutionBox", 185 CHILD_POLICY_ALL); 186 187 addElement("JPEG2000UUIDListBox", 188 "JPEG2000UUIDInfoBox", 189 CHILD_POLICY_ALL); 190 addElement("JPEG2000DataEntryURLBox", 191 "JPEG2000UUIDInfoBox", 192 CHILD_POLICY_ALL); 193 // Adds the default attributes "Length", "Type" and "ExtraLength" into 194 // the J2K box-related data elements 195 Enumeration keys = parents.keys(); 196 while (keys.hasMoreElements()) { 197 String s = (String)keys.nextElement(); 198 if (s.startsWith("JPEG2000")) { 199 addAttribute(s, "Length", DATATYPE_INTEGER, true, null); 200 addAttribute(s, "Type", DATATYPE_STRING, true, Box.getTypeByName(s)); 201 addAttribute(s, "ExtraLength", DATATYPE_STRING, false, null); 202 203 // If it is a simple node, adds the data elements by using 204 // relection. 205 Class c = Box.getBoxClass(Box.getTypeInt(Box.getTypeByName(s))); 206 207 try { 208 Method m = c.getMethod("getElementNames", (Class[])null); 209 String[] elementNames = (String[])m.invoke(null, 210 (Object[])null); 211 for (int i = 0; i < elementNames.length; i++) 212 addElement(elementNames[i], s, CHILD_POLICY_EMPTY); 213 } catch (Exception e) { 214 // no such method 215 } 216 } 217 } 218 219 addAttribute("JPEG2000SignatureBox", 220 "Signature", 221 DATATYPE_STRING, 222 true, 223 "0D0A870A"); 224 225 addElement("BitDepth", 226 "JPEG2000BitsPerComponentBox", 227 CHILD_POLICY_EMPTY); 228 229 addElement("NumberEntries", 230 "JPEG2000PaletteBox", 231 CHILD_POLICY_EMPTY); 232 233 addElement("NumberColors", 234 "JPEG2000PaletteBox", 235 CHILD_POLICY_EMPTY); 236 237 addElement("BitDepth", 238 "JPEG2000PaletteBox", 239 CHILD_POLICY_EMPTY); 240 241 addElement("LUT", 242 "JPEG2000PaletteBox", 243 1, 1024); 244 245 addElement("LUTRow", 246 "LUT", 247 CHILD_POLICY_EMPTY); 248 249 addElement("Component", 250 "JPEG2000ComponentMappingBox", 251 CHILD_POLICY_EMPTY); 252 253 addElement("ComponentType", 254 "JPEG2000ComponentMappingBox", 255 CHILD_POLICY_EMPTY); 256 257 addElement("ComponentAssociation", 258 "JPEG2000ComponentMappingBox", 259 CHILD_POLICY_EMPTY); 260 261 addElement("NumberOfDefinition", 262 "JPEG2000ChannelDefinitionBox", 263 CHILD_POLICY_EMPTY); 264 265 addElement("Definitions", 266 "JPEG2000ChannelDefinitionBox", 267 0, 9); 268 269 addElement("ChannelNumber", 270 "Definitions", 271 CHILD_POLICY_EMPTY); 272 273 addElement("ChannelType", 274 "Definitions", 275 CHILD_POLICY_EMPTY); 276 addElement("ChannelAssociation", 277 "Definitions", 278 CHILD_POLICY_EMPTY); 279 addElement("CodeStream", 280 "JPEG2000CodeStreamBox", 281 CHILD_POLICY_EMPTY); 282 addElement("Content", 283 "JPEG2000IntellectualPropertyRightsBox", 284 CHILD_POLICY_EMPTY); 285 addElement("Content", 286 "JPEG2000XMLBox", 287 CHILD_POLICY_EMPTY); 288 addElement("UUID", 289 "JPEG2000UUIDBox", 290 CHILD_POLICY_EMPTY); 291 addElement("Data", 292 "JPEG2000UUIDBox", 293 CHILD_POLICY_EMPTY); 294 addElement("NumberUUID", 295 "JPEG2000UUIDListBox", 296 CHILD_POLICY_EMPTY); 297 addElement("UUID", 298 "JPEG2000UUIDListBox", 299 CHILD_POLICY_EMPTY); 300 addElement("Version", 301 "JPEG2000DataEntryURLBox", 302 CHILD_POLICY_EMPTY); 303 addElement("Flags", 304 "JPEG2000DataEntryURLBox", 305 CHILD_POLICY_EMPTY); 306 addElement("URL", 307 "JPEG2000DataEntryURLBox", 308 CHILD_POLICY_EMPTY); 309 } 310 311 public String getParent(String elementName) { 312 return (String)parents.get(elementName); 313 } 314 315 public boolean canNodeAppear(String elementName, 316 ImageTypeSpecifier imageType) { 317 ColorModel cm = imageType.getColorModel(); 318 if (!(cm instanceof IndexColorModel)) 319 if ("JPEG2000PaletteBox".equals(elementName)) 320 return false; 321 if (!cm.hasAlpha()) 322 if ("JPEG2000ChannelDefinitionBox".equals(elementName)) 323 return false; 324 325 if (getParent(elementName) != null) 326 return true; 327 return false; 328 } 329 330 public boolean isLeaf(String name) { 331 Set keys = parents.keySet(); 332 Iterator iterator = keys.iterator(); 333 while(iterator.hasNext()) { 334 if (name.equals(parents.get(iterator.next()))) 335 return false; 336 } 337 338 return true; 339 } 340 341 public boolean singleInstance(String name) { 342 return !(name.equals("JPEG2000IntellectualPropertyRightsBox") || 343 name.equals("JPEG2000XMLBox") || 344 name.equals("JPEG2000UUIDBox") || 345 name.equals("JPEG2000UUIDInfoBox") || 346 name.equals("JPEG2000UUIDListBox") || 347 name.equals("JPEG2000DataEntryURLBox")); 348 } 349}