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