| /* |
| * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.imageio.plugins.gif; |
| |
| import java.io.UnsupportedEncodingException; |
| import java.nio.charset.Charset; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import javax.imageio.ImageTypeSpecifier; |
| import javax.imageio.metadata.IIOInvalidTreeException; |
| import javax.imageio.metadata.IIOMetadata; |
| import javax.imageio.metadata.IIOMetadataNode; |
| import javax.imageio.metadata.IIOMetadataFormat; |
| import javax.imageio.metadata.IIOMetadataFormatImpl; |
| import org.w3c.dom.Node; |
| |
| class GIFWritableImageMetadata extends GIFImageMetadata { |
| |
| // package scope |
| static final String |
| NATIVE_FORMAT_NAME = "javax_imageio_gif_image_1.0"; |
| |
| GIFWritableImageMetadata() { |
| super(true, |
| NATIVE_FORMAT_NAME, |
| "com.sun.imageio.plugins.gif.GIFImageMetadataFormat", |
| null, null); |
| } |
| |
| public boolean isReadOnly() { |
| return false; |
| } |
| |
| public void reset() { |
| // Fields from Image Descriptor |
| imageLeftPosition = 0; |
| imageTopPosition = 0; |
| imageWidth = 0; |
| imageHeight = 0; |
| interlaceFlag = false; |
| sortFlag = false; |
| localColorTable = null; |
| |
| // Fields from Graphic Control Extension |
| disposalMethod = 0; |
| userInputFlag = false; |
| transparentColorFlag = false; |
| delayTime = 0; |
| transparentColorIndex = 0; |
| |
| // Fields from Plain Text Extension |
| hasPlainTextExtension = false; |
| textGridLeft = 0; |
| textGridTop = 0; |
| textGridWidth = 0; |
| textGridHeight = 0; |
| characterCellWidth = 0; |
| characterCellHeight = 0; |
| textForegroundColor = 0; |
| textBackgroundColor = 0; |
| text = null; |
| |
| // Fields from ApplicationExtension |
| applicationIDs = null; |
| authenticationCodes = null; |
| applicationData = null; |
| |
| // Fields from CommentExtension |
| // List of byte[] |
| comments = null; |
| } |
| |
| private byte[] fromISO8859(String data) { |
| try { |
| return data.getBytes("ISO-8859-1"); |
| } catch (UnsupportedEncodingException e) { |
| return "".getBytes(); |
| } |
| } |
| |
| protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { |
| Node node = root; |
| if (!node.getNodeName().equals(nativeMetadataFormatName)) { |
| fatal(node, "Root must be " + nativeMetadataFormatName); |
| } |
| |
| node = node.getFirstChild(); |
| while (node != null) { |
| String name = node.getNodeName(); |
| |
| if (name.equals("ImageDescriptor")) { |
| imageLeftPosition = getIntAttribute(node, |
| "imageLeftPosition", |
| -1, true, |
| true, 0, 65535); |
| |
| imageTopPosition = getIntAttribute(node, |
| "imageTopPosition", |
| -1, true, |
| true, 0, 65535); |
| |
| imageWidth = getIntAttribute(node, |
| "imageWidth", |
| -1, true, |
| true, 1, 65535); |
| |
| imageHeight = getIntAttribute(node, |
| "imageHeight", |
| -1, true, |
| true, 1, 65535); |
| |
| interlaceFlag = getBooleanAttribute(node, "interlaceFlag", |
| false, true); |
| } else if (name.equals("LocalColorTable")) { |
| int sizeOfLocalColorTable = |
| getIntAttribute(node, "sizeOfLocalColorTable", |
| true, 2, 256); |
| if (sizeOfLocalColorTable != 2 && |
| sizeOfLocalColorTable != 4 && |
| sizeOfLocalColorTable != 8 && |
| sizeOfLocalColorTable != 16 && |
| sizeOfLocalColorTable != 32 && |
| sizeOfLocalColorTable != 64 && |
| sizeOfLocalColorTable != 128 && |
| sizeOfLocalColorTable != 256) { |
| fatal(node, |
| "Bad value for LocalColorTable attribute sizeOfLocalColorTable!"); |
| } |
| |
| sortFlag = getBooleanAttribute(node, "sortFlag", false, true); |
| |
| localColorTable = getColorTable(node, "ColorTableEntry", |
| true, sizeOfLocalColorTable); |
| } else if (name.equals("GraphicControlExtension")) { |
| String disposalMethodName = |
| getStringAttribute(node, "disposalMethod", null, |
| true, disposalMethodNames); |
| disposalMethod = 0; |
| while(!disposalMethodName.equals(disposalMethodNames[disposalMethod])) { |
| disposalMethod++; |
| } |
| |
| userInputFlag = getBooleanAttribute(node, "userInputFlag", |
| false, true); |
| |
| transparentColorFlag = |
| getBooleanAttribute(node, "transparentColorFlag", |
| false, true); |
| |
| delayTime = getIntAttribute(node, |
| "delayTime", |
| -1, true, |
| true, 0, 65535); |
| |
| transparentColorIndex = |
| getIntAttribute(node, "transparentColorIndex", |
| -1, true, |
| true, 0, 65535); |
| } else if (name.equals("PlainTextExtension")) { |
| hasPlainTextExtension = true; |
| |
| textGridLeft = getIntAttribute(node, |
| "textGridLeft", |
| -1, true, |
| true, 0, 65535); |
| |
| textGridTop = getIntAttribute(node, |
| "textGridTop", |
| -1, true, |
| true, 0, 65535); |
| |
| textGridWidth = getIntAttribute(node, |
| "textGridWidth", |
| -1, true, |
| true, 1, 65535); |
| |
| textGridHeight = getIntAttribute(node, |
| "textGridHeight", |
| -1, true, |
| true, 1, 65535); |
| |
| characterCellWidth = getIntAttribute(node, |
| "characterCellWidth", |
| -1, true, |
| true, 1, 65535); |
| |
| characterCellHeight = getIntAttribute(node, |
| "characterCellHeight", |
| -1, true, |
| true, 1, 65535); |
| |
| textForegroundColor = getIntAttribute(node, |
| "textForegroundColor", |
| -1, true, |
| true, 0, 255); |
| |
| textBackgroundColor = getIntAttribute(node, |
| "textBackgroundColor", |
| -1, true, |
| true, 0, 255); |
| |
| // XXX The "text" attribute of the PlainTextExtension element |
| // is not defined in the GIF image metadata format but it is |
| // present in the GIFImageMetadata class. Consequently it is |
| // used here but not required and with a default of "". See |
| // bug 5082763. |
| |
| String textString = |
| getStringAttribute(node, "text", "", false, null); |
| text = fromISO8859(textString); |
| } else if (name.equals("ApplicationExtensions")) { |
| IIOMetadataNode applicationExtension = |
| (IIOMetadataNode)node.getFirstChild(); |
| |
| if (!applicationExtension.getNodeName().equals("ApplicationExtension")) { |
| fatal(node, |
| "Only a ApplicationExtension may be a child of a ApplicationExtensions!"); |
| } |
| |
| String applicationIDString = |
| getStringAttribute(applicationExtension, "applicationID", |
| null, true, null); |
| |
| String authenticationCodeString = |
| getStringAttribute(applicationExtension, "authenticationCode", |
| null, true, null); |
| |
| Object applicationExtensionData = |
| applicationExtension.getUserObject(); |
| if (applicationExtensionData == null || |
| !(applicationExtensionData instanceof byte[])) { |
| fatal(applicationExtension, |
| "Bad user object in ApplicationExtension!"); |
| } |
| |
| if (applicationIDs == null) { |
| applicationIDs = new ArrayList(); |
| authenticationCodes = new ArrayList(); |
| applicationData = new ArrayList(); |
| } |
| |
| applicationIDs.add(fromISO8859(applicationIDString)); |
| authenticationCodes.add(fromISO8859(authenticationCodeString)); |
| applicationData.add(applicationExtensionData); |
| } else if (name.equals("CommentExtensions")) { |
| Node commentExtension = node.getFirstChild(); |
| if (commentExtension != null) { |
| while(commentExtension != null) { |
| if (!commentExtension.getNodeName().equals("CommentExtension")) { |
| fatal(node, |
| "Only a CommentExtension may be a child of a CommentExtensions!"); |
| } |
| |
| if (comments == null) { |
| comments = new ArrayList(); |
| } |
| |
| String comment = |
| getStringAttribute(commentExtension, "value", null, |
| true, null); |
| |
| comments.add(fromISO8859(comment)); |
| |
| commentExtension = commentExtension.getNextSibling(); |
| } |
| } |
| } else { |
| fatal(node, "Unknown child of root node!"); |
| } |
| |
| node = node.getNextSibling(); |
| } |
| } |
| |
| protected void mergeStandardTree(Node root) |
| throws IIOInvalidTreeException { |
| Node node = root; |
| if (!node.getNodeName() |
| .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) { |
| fatal(node, "Root must be " + |
| IIOMetadataFormatImpl.standardMetadataFormatName); |
| } |
| |
| node = node.getFirstChild(); |
| while (node != null) { |
| String name = node.getNodeName(); |
| |
| if (name.equals("Chroma")) { |
| Node childNode = node.getFirstChild(); |
| while(childNode != null) { |
| String childName = childNode.getNodeName(); |
| if (childName.equals("Palette")) { |
| localColorTable = getColorTable(childNode, |
| "PaletteEntry", |
| false, -1); |
| break; |
| } |
| childNode = childNode.getNextSibling(); |
| } |
| } else if (name.equals("Compression")) { |
| Node childNode = node.getFirstChild(); |
| while(childNode != null) { |
| String childName = childNode.getNodeName(); |
| if (childName.equals("NumProgressiveScans")) { |
| int numProgressiveScans = |
| getIntAttribute(childNode, "value", 4, false, |
| true, 1, Integer.MAX_VALUE); |
| if (numProgressiveScans > 1) { |
| interlaceFlag = true; |
| } |
| break; |
| } |
| childNode = childNode.getNextSibling(); |
| } |
| } else if (name.equals("Dimension")) { |
| Node childNode = node.getFirstChild(); |
| while(childNode != null) { |
| String childName = childNode.getNodeName(); |
| if (childName.equals("HorizontalPixelOffset")) { |
| imageLeftPosition = getIntAttribute(childNode, |
| "value", |
| -1, true, |
| true, 0, 65535); |
| } else if (childName.equals("VerticalPixelOffset")) { |
| imageTopPosition = getIntAttribute(childNode, |
| "value", |
| -1, true, |
| true, 0, 65535); |
| } |
| childNode = childNode.getNextSibling(); |
| } |
| } else if (name.equals("Text")) { |
| Node childNode = node.getFirstChild(); |
| while(childNode != null) { |
| String childName = childNode.getNodeName(); |
| if (childName.equals("TextEntry") && |
| getAttribute(childNode, "compression", |
| "none", false).equals("none") && |
| Charset.isSupported(getAttribute(childNode, |
| "encoding", |
| "ISO-8859-1", |
| false))) { |
| String value = getAttribute(childNode, "value"); |
| byte[] comment = fromISO8859(value); |
| if (comments == null) { |
| comments = new ArrayList(); |
| } |
| comments.add(comment); |
| } |
| childNode = childNode.getNextSibling(); |
| } |
| } else if (name.equals("Transparency")) { |
| Node childNode = node.getFirstChild(); |
| while(childNode != null) { |
| String childName = childNode.getNodeName(); |
| if (childName.equals("TransparentIndex")) { |
| transparentColorIndex = getIntAttribute(childNode, |
| "value", |
| -1, true, |
| true, 0, 255); |
| transparentColorFlag = true; |
| break; |
| } |
| childNode = childNode.getNextSibling(); |
| } |
| } |
| |
| node = node.getNextSibling(); |
| } |
| } |
| |
| public void setFromTree(String formatName, Node root) |
| throws IIOInvalidTreeException |
| { |
| reset(); |
| mergeTree(formatName, root); |
| } |
| } |