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}