001: /*
002: * $RCSfile: GIFImageMetadata.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: 2006/03/24 22:30:09 $
043: * $State: Exp $
044: */
045:
046: package com.sun.media.imageioimpl.plugins.gif;
047:
048: import java.io.UnsupportedEncodingException;
049: import java.util.ArrayList;
050: import java.util.Iterator;
051: import java.util.List;
052: import javax.imageio.ImageTypeSpecifier;
053: import javax.imageio.metadata.IIOInvalidTreeException;
054: import javax.imageio.metadata.IIOMetadata;
055: import javax.imageio.metadata.IIOMetadataNode;
056: import javax.imageio.metadata.IIOMetadataFormat;
057: import javax.imageio.metadata.IIOMetadataFormatImpl;
058: import org.w3c.dom.Node;
059:
060: /**
061: * @version 0.5
062: */
063: public class GIFImageMetadata extends GIFMetadata {
064:
065: // package scope
066: static final String nativeMetadataFormatName = "javax_imageio_gif_image_1.0";
067:
068: static final String[] disposalMethodNames = { "none",
069: "doNotDispose", "restoreToBackgroundColor",
070: "restoreToPrevious", "undefinedDisposalMethod4",
071: "undefinedDisposalMethod5", "undefinedDisposalMethod6",
072: "undefinedDisposalMethod7" };
073:
074: // Fields from Image Descriptor
075: public int imageLeftPosition;
076: public int imageTopPosition;
077: public int imageWidth;
078: public int imageHeight;
079: public boolean interlaceFlag = false;
080: public boolean sortFlag = false;
081: public byte[] localColorTable = null;
082:
083: // Fields from Graphic Control Extension
084: public int disposalMethod = 0;
085: public boolean userInputFlag = false;
086: public boolean transparentColorFlag = false;
087: public int delayTime = 0;
088: public int transparentColorIndex = 0;
089:
090: // Fields from Plain Text Extension
091: public boolean hasPlainTextExtension = false;
092: public int textGridLeft;
093: public int textGridTop;
094: public int textGridWidth;
095: public int textGridHeight;
096: public int characterCellWidth;
097: public int characterCellHeight;
098: public int textForegroundColor;
099: public int textBackgroundColor;
100: public byte[] text;
101:
102: // Fields from ApplicationExtension
103: // List of byte[]
104: public List applicationIDs = null; // new ArrayList();
105:
106: // List of byte[]
107: public List authenticationCodes = null; // new ArrayList();
108:
109: // List of byte[]
110: public List applicationData = null; // new ArrayList();
111:
112: // Fields from CommentExtension
113: // List of byte[]
114: public List comments = null; // new ArrayList();
115:
116: protected GIFImageMetadata(boolean standardMetadataFormatSupported,
117: String nativeMetadataFormatName,
118: String nativeMetadataFormatClassName,
119: String[] extraMetadataFormatNames,
120: String[] extraMetadataFormatClassNames) {
121: super (standardMetadataFormatSupported,
122: nativeMetadataFormatName,
123: nativeMetadataFormatClassName,
124: extraMetadataFormatNames, extraMetadataFormatClassNames);
125: }
126:
127: public GIFImageMetadata() {
128: this (
129: true,
130: nativeMetadataFormatName,
131: "com.sun.media.imageioimpl.plugins.gif.GIFImageMetadataFormat",
132: null, null);
133: }
134:
135: public boolean isReadOnly() {
136: return true;
137: }
138:
139: public Node getAsTree(String formatName) {
140: if (formatName.equals(nativeMetadataFormatName)) {
141: return getNativeTree();
142: } else if (formatName
143: .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
144: return getStandardTree();
145: } else {
146: throw new IllegalArgumentException(
147: "Not a recognized format!");
148: }
149: }
150:
151: private String toISO8859(byte[] data) {
152: try {
153: return new String(data, "ISO-8859-1");
154: } catch (UnsupportedEncodingException e) {
155: return "";
156: }
157: }
158:
159: private Node getNativeTree() {
160: IIOMetadataNode node; // scratch node
161: IIOMetadataNode root = new IIOMetadataNode(
162: nativeMetadataFormatName);
163:
164: // Image descriptor
165: node = new IIOMetadataNode("ImageDescriptor");
166: node.setAttribute("imageLeftPosition", Integer
167: .toString(imageLeftPosition));
168: node.setAttribute("imageTopPosition", Integer
169: .toString(imageTopPosition));
170: node.setAttribute("imageWidth", Integer.toString(imageWidth));
171: node.setAttribute("imageHeight", Integer.toString(imageHeight));
172: node.setAttribute("interlaceFlag", interlaceFlag ? "true"
173: : "false");
174: root.appendChild(node);
175:
176: // Local color table
177: if (localColorTable != null) {
178: node = new IIOMetadataNode("LocalColorTable");
179: int numEntries = localColorTable.length / 3;
180: node.setAttribute("sizeOfLocalColorTable", Integer
181: .toString(numEntries));
182: node.setAttribute("sortFlag", sortFlag ? "TRUE" : "FALSE");
183:
184: for (int i = 0; i < numEntries; i++) {
185: IIOMetadataNode entry = new IIOMetadataNode(
186: "ColorTableEntry");
187: entry.setAttribute("index", Integer.toString(i));
188: int r = localColorTable[3 * i] & 0xff;
189: int g = localColorTable[3 * i + 1] & 0xff;
190: int b = localColorTable[3 * i + 2] & 0xff;
191: entry.setAttribute("red", Integer.toString(r));
192: entry.setAttribute("green", Integer.toString(g));
193: entry.setAttribute("blue", Integer.toString(b));
194: node.appendChild(entry);
195: }
196: root.appendChild(node);
197: }
198:
199: // Graphic control extension
200: node = new IIOMetadataNode("GraphicControlExtension");
201: node.setAttribute("disposalMethod",
202: disposalMethodNames[disposalMethod]);
203: node.setAttribute("userInputFlag", userInputFlag ? "true"
204: : "false");
205: node.setAttribute("transparentColorFlag",
206: transparentColorFlag ? "true" : "false");
207: node.setAttribute("delayTime", Integer.toString(delayTime));
208: node.setAttribute("transparentColorIndex", Integer
209: .toString(transparentColorIndex));
210: root.appendChild(node);
211:
212: if (hasPlainTextExtension) {
213: node = new IIOMetadataNode("PlainTextExtension");
214: node.setAttribute("textGridLeft", Integer
215: .toString(textGridLeft));
216: node.setAttribute("textGridTop", Integer
217: .toString(textGridTop));
218: node.setAttribute("textGridWidth", Integer
219: .toString(textGridWidth));
220: node.setAttribute("textGridHeight", Integer
221: .toString(textGridHeight));
222: node.setAttribute("characterCellWidth", Integer
223: .toString(characterCellWidth));
224: node.setAttribute("characterCellHeight", Integer
225: .toString(characterCellHeight));
226: node.setAttribute("textForegroundColor", Integer
227: .toString(textForegroundColor));
228: node.setAttribute("textBackgroundColor", Integer
229: .toString(textBackgroundColor));
230: node.setAttribute("text", toISO8859(text));
231:
232: root.appendChild(node);
233: }
234:
235: // Application extensions
236: int numAppExtensions = applicationIDs == null ? 0
237: : applicationIDs.size();
238: if (numAppExtensions > 0) {
239: node = new IIOMetadataNode("ApplicationExtensions");
240: for (int i = 0; i < numAppExtensions; i++) {
241: IIOMetadataNode appExtNode = new IIOMetadataNode(
242: "ApplicationExtension");
243: byte[] applicationID = (byte[]) applicationIDs.get(i);
244: appExtNode.setAttribute("applicationID",
245: toISO8859(applicationID));
246: byte[] authenticationCode = (byte[]) authenticationCodes
247: .get(i);
248: appExtNode.setAttribute("authenticationCode",
249: toISO8859(authenticationCode));
250: byte[] appData = (byte[]) applicationData.get(i);
251: appExtNode.setUserObject((byte[]) appData.clone());
252: node.appendChild(appExtNode);
253: }
254:
255: root.appendChild(node);
256: }
257:
258: // Comment extensions
259: int numComments = comments == null ? 0 : comments.size();
260: if (numComments > 0) {
261: node = new IIOMetadataNode("CommentExtensions");
262: for (int i = 0; i < numComments; i++) {
263: IIOMetadataNode commentNode = new IIOMetadataNode(
264: "CommentExtension");
265: byte[] comment = (byte[]) comments.get(i);
266: commentNode.setAttribute("value", toISO8859(comment));
267: node.appendChild(commentNode);
268: }
269:
270: root.appendChild(node);
271: }
272:
273: return root;
274: }
275:
276: public IIOMetadataNode getStandardChromaNode() {
277: IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma");
278: IIOMetadataNode node = null; // scratch node
279:
280: node = new IIOMetadataNode("ColorSpaceType");
281: node.setAttribute("name", "RGB");
282: chroma_node.appendChild(node);
283:
284: node = new IIOMetadataNode("NumChannels");
285: node.setAttribute("value", transparentColorFlag ? "4" : "3");
286: chroma_node.appendChild(node);
287:
288: // Gamma not in format
289:
290: node = new IIOMetadataNode("BlackIsZero");
291: node.setAttribute("value", "TRUE");
292: chroma_node.appendChild(node);
293:
294: if (localColorTable != null) {
295: node = new IIOMetadataNode("Palette");
296: int numEntries = localColorTable.length / 3;
297: for (int i = 0; i < numEntries; i++) {
298: IIOMetadataNode entry = new IIOMetadataNode(
299: "PaletteEntry");
300: entry.setAttribute("index", Integer.toString(i));
301: entry.setAttribute("red", Integer
302: .toString(localColorTable[3 * i] & 0xff));
303: entry.setAttribute("green", Integer
304: .toString(localColorTable[3 * i + 1] & 0xff));
305: entry.setAttribute("blue", Integer
306: .toString(localColorTable[3 * i + 2] & 0xff));
307: node.appendChild(entry);
308: }
309: chroma_node.appendChild(node);
310: }
311:
312: // BackgroundIndex not in image
313: // BackgroundColor not in format
314:
315: return chroma_node;
316: }
317:
318: public IIOMetadataNode getStandardCompressionNode() {
319: IIOMetadataNode compression_node = new IIOMetadataNode(
320: "Compression");
321: IIOMetadataNode node = null; // scratch node
322:
323: node = new IIOMetadataNode("CompressionTypeName");
324: node.setAttribute("value", "lzw");
325: compression_node.appendChild(node);
326:
327: node = new IIOMetadataNode("Lossless");
328: node.setAttribute("value", "TRUE");
329: compression_node.appendChild(node);
330:
331: node = new IIOMetadataNode("NumProgressiveScans");
332: node.setAttribute("value", interlaceFlag ? "4" : "1");
333: compression_node.appendChild(node);
334:
335: // BitRate not in format
336:
337: return compression_node;
338: }
339:
340: public IIOMetadataNode getStandardDataNode() {
341: IIOMetadataNode data_node = new IIOMetadataNode("Data");
342: IIOMetadataNode node = null; // scratch node
343:
344: // PlanarConfiguration not in format
345:
346: node = new IIOMetadataNode("SampleFormat");
347: node.setAttribute("value", "Index");
348: data_node.appendChild(node);
349:
350: // BitsPerSample not in image
351: // SignificantBitsPerSample not in format
352: // SampleMSB not in format
353:
354: return data_node;
355: }
356:
357: public IIOMetadataNode getStandardDimensionNode() {
358: IIOMetadataNode dimension_node = new IIOMetadataNode(
359: "Dimension");
360: IIOMetadataNode node = null; // scratch node
361:
362: // PixelAspectRatio not in image
363:
364: node = new IIOMetadataNode("ImageOrientation");
365: node.setAttribute("value", "Normal");
366: dimension_node.appendChild(node);
367:
368: // HorizontalPixelSize not in format
369: // VerticalPixelSize not in format
370: // HorizontalPhysicalPixelSpacing not in format
371: // VerticalPhysicalPixelSpacing not in format
372: // HorizontalPosition not in format
373: // VerticalPosition not in format
374:
375: node = new IIOMetadataNode("HorizontalPixelOffset");
376: node.setAttribute("value", Integer.toString(imageLeftPosition));
377: dimension_node.appendChild(node);
378:
379: node = new IIOMetadataNode("VerticalPixelOffset");
380: node.setAttribute("value", Integer.toString(imageTopPosition));
381: dimension_node.appendChild(node);
382:
383: // HorizontalScreenSize not in image
384: // VerticalScreenSize not in image
385:
386: return dimension_node;
387: }
388:
389: // Document not in image
390:
391: public IIOMetadataNode getStandardTextNode() {
392: if (comments == null) {
393: return null;
394: }
395: Iterator commentIter = comments.iterator();
396: if (!commentIter.hasNext()) {
397: return null;
398: }
399:
400: IIOMetadataNode text_node = new IIOMetadataNode("Text");
401: IIOMetadataNode node = null; // scratch node
402:
403: while (commentIter.hasNext()) {
404: byte[] comment = (byte[]) commentIter.next();
405: String s = null;
406: try {
407: s = new String(comment, "ISO-8859-1");
408: } catch (UnsupportedEncodingException e) {
409: throw new RuntimeException(
410: "Encoding ISO-8859-1 unknown!");
411: }
412:
413: node = new IIOMetadataNode("TextEntry");
414: node.setAttribute("value", s);
415: node.setAttribute("encoding", "ISO-8859-1");
416: node.setAttribute("compression", "none");
417: text_node.appendChild(node);
418: }
419:
420: return text_node;
421: }
422:
423: public IIOMetadataNode getStandardTransparencyNode() {
424: if (!transparentColorFlag) {
425: return null;
426: }
427:
428: IIOMetadataNode transparency_node = new IIOMetadataNode(
429: "Transparency");
430: IIOMetadataNode node = null; // scratch node
431:
432: // Alpha not in format
433:
434: node = new IIOMetadataNode("TransparentIndex");
435: node.setAttribute("value", Integer
436: .toString(transparentColorIndex));
437: transparency_node.appendChild(node);
438:
439: // TransparentColor not in format
440: // TileTransparencies not in format
441: // TileOpacities not in format
442:
443: return transparency_node;
444: }
445:
446: public void setFromTree(String formatName, Node root)
447: throws IIOInvalidTreeException {
448: throw new IllegalStateException("Metadata is read-only!");
449: }
450:
451: protected void mergeNativeTree(Node root)
452: throws IIOInvalidTreeException {
453: throw new IllegalStateException("Metadata is read-only!");
454: }
455:
456: protected void mergeStandardTree(Node root)
457: throws IIOInvalidTreeException {
458: throw new IllegalStateException("Metadata is read-only!");
459: }
460:
461: public void reset() {
462: throw new IllegalStateException("Metadata is read-only!");
463: }
464: }
|