You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
16 KiB
403 lines
16 KiB
/*
|
|
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
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);
|
|
}
|
|
}
|