001: /*
002: * $RCSfile: GIFWritableImageMetadata.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: 2006/03/24 22:30:11 $
043: * $State: Exp $
044: */
045:
046: package com.sun.media.imageioimpl.plugins.gif;
047:
048: import java.io.UnsupportedEncodingException;
049: import java.nio.charset.Charset;
050: import java.util.ArrayList;
051: import java.util.Iterator;
052: import java.util.List;
053: import javax.imageio.ImageTypeSpecifier;
054: import javax.imageio.metadata.IIOInvalidTreeException;
055: import javax.imageio.metadata.IIOMetadata;
056: import javax.imageio.metadata.IIOMetadataNode;
057: import javax.imageio.metadata.IIOMetadataFormat;
058: import javax.imageio.metadata.IIOMetadataFormatImpl;
059: import org.w3c.dom.Node;
060:
061: class GIFWritableImageMetadata extends GIFImageMetadata {
062:
063: // package scope
064: static final String NATIVE_FORMAT_NAME = "javax_imageio_gif_image_1.0";
065:
066: GIFWritableImageMetadata() {
067: super (
068: true,
069: NATIVE_FORMAT_NAME,
070: "com.sun.media.imageioimpl.plugins.gif.GIFImageMetadataFormat",
071: null, null);
072: }
073:
074: public boolean isReadOnly() {
075: return false;
076: }
077:
078: public void reset() {
079: // Fields from Image Descriptor
080: imageLeftPosition = 0;
081: imageTopPosition = 0;
082: imageWidth = 0;
083: imageHeight = 0;
084: interlaceFlag = false;
085: sortFlag = false;
086: localColorTable = null;
087:
088: // Fields from Graphic Control Extension
089: disposalMethod = 0;
090: userInputFlag = false;
091: transparentColorFlag = false;
092: delayTime = 0;
093: transparentColorIndex = 0;
094:
095: // Fields from Plain Text Extension
096: hasPlainTextExtension = false;
097: textGridLeft = 0;
098: textGridTop = 0;
099: textGridWidth = 0;
100: textGridHeight = 0;
101: characterCellWidth = 0;
102: characterCellHeight = 0;
103: textForegroundColor = 0;
104: textBackgroundColor = 0;
105: text = null;
106:
107: // Fields from ApplicationExtension
108: applicationIDs = null;
109: authenticationCodes = null;
110: applicationData = null;
111:
112: // Fields from CommentExtension
113: // List of byte[]
114: comments = null;
115: }
116:
117: private byte[] fromISO8859(String data) {
118: try {
119: return data.getBytes("ISO-8859-1");
120: } catch (UnsupportedEncodingException e) {
121: return (new String("")).getBytes();
122: }
123: }
124:
125: protected void mergeNativeTree(Node root)
126: throws IIOInvalidTreeException {
127: Node node = root;
128: if (!node.getNodeName().equals(nativeMetadataFormatName)) {
129: fatal(node, "Root must be " + nativeMetadataFormatName);
130: }
131:
132: node = node.getFirstChild();
133: while (node != null) {
134: String name = node.getNodeName();
135:
136: if (name.equals("ImageDescriptor")) {
137: imageLeftPosition = getIntAttribute(node,
138: "imageLeftPosition", -1, true, true, 0, 65535);
139:
140: imageTopPosition = getIntAttribute(node,
141: "imageTopPosition", -1, true, true, 0, 65535);
142:
143: imageWidth = getIntAttribute(node, "imageWidth", -1,
144: true, true, 1, 65535);
145:
146: imageHeight = getIntAttribute(node, "imageHeight", -1,
147: true, true, 1, 65535);
148:
149: interlaceFlag = getBooleanAttribute(node,
150: "interlaceFlag", false, true);
151: } else if (name.equals("LocalColorTable")) {
152: int sizeOfLocalColorTable = getIntAttribute(node,
153: "sizeOfLocalColorTable", true, 2, 256);
154: if (sizeOfLocalColorTable != 2
155: && sizeOfLocalColorTable != 4
156: && sizeOfLocalColorTable != 8
157: && sizeOfLocalColorTable != 16
158: && sizeOfLocalColorTable != 32
159: && sizeOfLocalColorTable != 64
160: && sizeOfLocalColorTable != 128
161: && sizeOfLocalColorTable != 256) {
162: fatal(node,
163: "Bad value for LocalColorTable attribute sizeOfLocalColorTable!");
164: }
165:
166: sortFlag = getBooleanAttribute(node, "sortFlag", false,
167: true);
168:
169: localColorTable = getColorTable(node,
170: "ColorTableEntry", true, sizeOfLocalColorTable);
171: } else if (name.equals("GraphicControlExtension")) {
172: String disposalMethodName = getStringAttribute(node,
173: "disposalMethod", null, true,
174: disposalMethodNames);
175: disposalMethod = 0;
176: while (!disposalMethodName
177: .equals(disposalMethodNames[disposalMethod])) {
178: disposalMethod++;
179: }
180:
181: userInputFlag = getBooleanAttribute(node,
182: "userInputFlag", false, true);
183:
184: transparentColorFlag = getBooleanAttribute(node,
185: "transparentColorFlag", false, true);
186:
187: delayTime = getIntAttribute(node, "delayTime", -1,
188: true, true, 0, 65535);
189:
190: transparentColorIndex = getIntAttribute(node,
191: "transparentColorIndex", -1, true, true, 0,
192: 65535);
193: } else if (name.equals("PlainTextExtension")) {
194: hasPlainTextExtension = true;
195:
196: textGridLeft = getIntAttribute(node, "textGridLeft",
197: -1, true, true, 0, 65535);
198:
199: textGridTop = getIntAttribute(node, "textGridTop", -1,
200: true, true, 0, 65535);
201:
202: textGridWidth = getIntAttribute(node, "textGridWidth",
203: -1, true, true, 1, 65535);
204:
205: textGridHeight = getIntAttribute(node,
206: "textGridHeight", -1, true, true, 1, 65535);
207:
208: characterCellWidth = getIntAttribute(node,
209: "characterCellWidth", -1, true, true, 1, 65535);
210:
211: characterCellHeight = getIntAttribute(node,
212: "characterCellHeight", -1, true, true, 1, 65535);
213:
214: textForegroundColor = getIntAttribute(node,
215: "textForegroundColor", -1, true, true, 0, 255);
216:
217: textBackgroundColor = getIntAttribute(node,
218: "textBackgroundColor", -1, true, true, 0, 255);
219:
220: // XXX The "text" attribute of the PlainTextExtension element
221: // is not defined in the GIF image metadata format but it is
222: // present in the GIFImageMetadata class. Consequently it is
223: // used here but not required and with a default of "". See
224: // bug 5082763.
225:
226: String textString = getStringAttribute(node, "text",
227: "", false, null);
228: text = fromISO8859(textString);
229: } else if (name.equals("ApplicationExtensions")) {
230: IIOMetadataNode applicationExtension = (IIOMetadataNode) node
231: .getFirstChild();
232:
233: if (!applicationExtension.getNodeName().equals(
234: "ApplicationExtension")) {
235: fatal(node,
236: "Only a ApplicationExtension may be a child of a ApplicationExtensions!");
237: }
238:
239: String applicationIDString = getStringAttribute(
240: applicationExtension, "applicationID", null,
241: true, null);
242:
243: String authenticationCodeString = getStringAttribute(
244: applicationExtension, "authenticationCode",
245: null, true, null);
246:
247: Object applicationExtensionData = applicationExtension
248: .getUserObject();
249: if (applicationExtensionData == null
250: || !(applicationExtensionData instanceof byte[])) {
251: fatal(applicationExtension,
252: "Bad user object in ApplicationExtension!");
253: }
254:
255: if (applicationIDs == null) {
256: applicationIDs = new ArrayList();
257: authenticationCodes = new ArrayList();
258: applicationData = new ArrayList();
259: }
260:
261: applicationIDs.add(fromISO8859(applicationIDString));
262: authenticationCodes
263: .add(fromISO8859(authenticationCodeString));
264: applicationData.add(applicationExtensionData);
265: } else if (name.equals("CommentExtensions")) {
266: Node commentExtension = node.getFirstChild();
267: if (commentExtension != null) {
268: while (commentExtension != null) {
269: if (!commentExtension.getNodeName().equals(
270: "CommentExtension")) {
271: fatal(node,
272: "Only a CommentExtension may be a child of a CommentExtensions!");
273: }
274:
275: if (comments == null) {
276: comments = new ArrayList();
277: }
278:
279: String comment = getStringAttribute(
280: commentExtension, "value", null, true,
281: null);
282:
283: comments.add(fromISO8859(comment));
284:
285: commentExtension = commentExtension
286: .getNextSibling();
287: }
288: }
289: } else {
290: fatal(node, "Unknown child of root node!");
291: }
292:
293: node = node.getNextSibling();
294: }
295: }
296:
297: protected void mergeStandardTree(Node root)
298: throws IIOInvalidTreeException {
299: Node node = root;
300: if (!node.getNodeName().equals(
301: IIOMetadataFormatImpl.standardMetadataFormatName)) {
302: fatal(node, "Root must be "
303: + IIOMetadataFormatImpl.standardMetadataFormatName);
304: }
305:
306: node = node.getFirstChild();
307: while (node != null) {
308: String name = node.getNodeName();
309:
310: if (name.equals("Chroma")) {
311: Node childNode = node.getFirstChild();
312: while (childNode != null) {
313: String childName = childNode.getNodeName();
314: if (childName.equals("Palette")) {
315: localColorTable = getColorTable(childNode,
316: "PaletteEntry", false, -1);
317: break;
318: }
319: childNode = childNode.getNextSibling();
320: }
321: } else if (name.equals("Compression")) {
322: Node childNode = node.getFirstChild();
323: while (childNode != null) {
324: String childName = childNode.getNodeName();
325: if (childName.equals("NumProgressiveScans")) {
326: int numProgressiveScans = getIntAttribute(
327: childNode, "value", 4, false, true, 1,
328: Integer.MAX_VALUE);
329: if (numProgressiveScans > 1) {
330: interlaceFlag = true;
331: }
332: break;
333: }
334: childNode = childNode.getNextSibling();
335: }
336: } else if (name.equals("Dimension")) {
337: Node childNode = node.getFirstChild();
338: while (childNode != null) {
339: String childName = childNode.getNodeName();
340: if (childName.equals("HorizontalPixelOffset")) {
341: imageLeftPosition = getIntAttribute(childNode,
342: "value", -1, true, true, 0, 65535);
343: } else if (childName.equals("VerticalPixelOffset")) {
344: imageTopPosition = getIntAttribute(childNode,
345: "value", -1, true, true, 0, 65535);
346: }
347: childNode = childNode.getNextSibling();
348: }
349: } else if (name.equals("Text")) {
350: Node childNode = node.getFirstChild();
351: while (childNode != null) {
352: String childName = childNode.getNodeName();
353: if (childName.equals("TextEntry")
354: && getAttribute(childNode, "compression",
355: "none", false).equals("none")
356: && Charset.isSupported(getAttribute(
357: childNode, "encoding",
358: "ISO-8859-1", false))) {
359: String value = getAttribute(childNode, "value");
360: byte[] comment = fromISO8859(value);
361: if (comments == null) {
362: comments = new ArrayList();
363: }
364: comments.add(comment);
365: }
366: childNode = childNode.getNextSibling();
367: }
368: } else if (name.equals("Transparency")) {
369: Node childNode = node.getFirstChild();
370: while (childNode != null) {
371: String childName = childNode.getNodeName();
372: if (childName.equals("TransparentIndex")) {
373: transparentColorIndex = getIntAttribute(
374: childNode, "value", -1, true, true, 0,
375: 255);
376: transparentColorFlag = true;
377: break;
378: }
379: childNode = childNode.getNextSibling();
380: }
381: }
382:
383: node = node.getNextSibling();
384: }
385: }
386:
387: public void setFromTree(String formatName, Node root)
388: throws IIOInvalidTreeException {
389: reset();
390: mergeTree(formatName, root);
391: }
392: }
|