/* * 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((byte[]) 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); } }