Yes, it’s possible… I dont have time to explain much, but i’ll do that later…
private ArrayList<Node> findNodesWithName(Node n, String s) {
NodeList l = n.getChildNodes();
ArrayList<Node> nodes = new ArrayList<Node>();
for(int i=0; i<l.getLength(); i++) {
if(l.item(i).getNodeName().equals(s)) {
nodes.add(l.item(i));
}
}
NamedNodeMap attributes = n.getAttributes();
if(attributes != null) {
Node nn = attributes.getNamedItem(s);
if(nn != null) {
nodes.add(nn);
}
}
return nodes;
}
private Node findNodeWithName(Node n, String s) {
NodeList l = n.getChildNodes();
ArrayList<Node> nodes = new ArrayList<Node>();
for(int i=0; i<l.getLength(); i++) {
if(l.item(i).getNodeName().equals(s)) {
return l.item(i);
}
}
return null;
}
private ArrayList<Node> findNodesWithPath(Node n, String path) {
if(n == null || path == null || path.length() == 0)
return null;
String[] nodeNames = path.split("\\.");
if(nodeNames.length == 0)
return null;
Node currentNode = n;
for(int i=0;i<nodeNames.length-1;i++) {
currentNode = findNodeWithName(currentNode, nodeNames[i]);
if(currentNode == null) {
return null;
}
}
return findNodesWithName(currentNode, nodeNames[nodeNames.length-1]);
}
private String findValueWithPath(Node n, String path) {
ArrayList<Node> nodes = findNodesWithPath(n, path);
if(nodes.size() > 0)
return nodes.get(0).getNodeValue();
return null;
}
private static final String NODEPATH_WIDTH = "LogicalScreenDescriptor.logicalScreenWidth";
private static final String NODEPATH_HEIGHT = "LogicalScreenDescriptor.logicalScreenHeight";
private static final String NODEPATH_BACKGROUNDCOLORINDEX = "GlobalColorTable.backgroundColorIndex";
private static final String NODEPATH_COLORENTRY = "GlobalColorTable.ColorTableEntry";
private static final String NODEPATH_DELAYTIME = "GraphicControlExtension.delayTime";
private static final String NODEPATH_IMAGELEFTPOS = "ImageDescriptor.imageLeftPosition";
private static final String NODEPATH_IMAGETOPPOS = "ImageDescriptor.imageTopPosition";
private static final String NODEPATH_DISPOSALMETHOD = "GraphicControlExtension.disposalMethod";
private static final String NODEPATH_ISTRANSPARENT = "GraphicControlExtension.transparentColorFlag";
private static final String NODEPATH_TRANSPARENTCOLORINDEX = "GraphicControlExtension.transparentColorIndex";
private static final String DISPOSALMETHOD_RESTOREPREVIOUS = "restoreToPrevious";
private static final String DISPOSALMETHOD_CLEARTOBACKGROUNDCOLOR = "restoreToBackgroundColor";
private static final String NODENAME_INDEX = "index";
private static final String NODENAME_RED = "red";
private static final String NODENAME_GREEN = "green";
private static final String NODENAME_BLUE = "blue";
private static final String EXTENSION_GIF = "gif";
private static final String ERROR_INPUTSTREAMISNULL = "InputStream must not be null";
private static final String ERROR_NOCOMPATIBLEREADERFOUND = "No GIF compatible imagereader found";
private static final String ERROR_IMAGEINPUTSTREAMNOTACCEPTED = "Provided stream is not a GIF image";
private static final int IMAGETYPE = BufferedImage.TYPE_4BYTE_ABGR;
private ImageReader getImageReader(String format) {
Iterator<ImageReader> readerIterator = ImageIO.getImageReadersBySuffix(format);
if(!readerIterator.hasNext())
return null;
return readerIterator.next();
}
private void initialize(InputStream stream, boolean calcTexture) throws IOException {
// ensure we have a stream
if(stream == null)
throw new IOException(ERROR_INPUTSTREAMISNULL);
// ensure we have a reader which can read gifs
ImageReader reader = getImageReader(EXTENSION_GIF);
if(reader == null)
throw new IOException(ERROR_NOCOMPATIBLEREADERFOUND);
// ensure we can create an ImageInputStream from the given Inputstream
ImageInputStream imageInputStream = ImageIO.createImageInputStream(stream);
// (IOException will be thrown if there was an error)
try {
reader.setInput(imageInputStream);
} catch(IllegalArgumentException e) {
throw new IOException(ERROR_IMAGEINPUTSTREAMNOTACCEPTED + e.toString());
}
// read all images in the gif stream,
// giving a null argument because we dont want give
// any special parameters to the gifreader
Iterator<IIOImage> images = reader.readAll(null);
// get the metadata for the entire stream
IIOMetadata streamMetaData = reader.getStreamMetadata();
Node streamRoot = streamMetaData.getAsTree(streamMetaData.getNativeMetadataFormatName());
// process the metadata, find the dimensions for this animation
// and the backgroundcolor
int imageWidth = Integer.parseInt(findValueWithPath(streamRoot, NODEPATH_WIDTH));
int imageHeight = Integer.parseInt(findValueWithPath(streamRoot, NODEPATH_HEIGHT));
int backgroundColorIndex = Integer.parseInt(findValueWithPath(streamRoot, NODEPATH_BACKGROUNDCOLORINDEX));
// set the default backgroundcolor to black
Color backgroundColor = Color.black;
// Get the color palette as given by the gif file
// and search for the background color
// when found, set the backgroundColor to that value
ArrayList<Node> colors = findNodesWithPath(streamRoot, NODEPATH_COLORENTRY);
for(Node n : colors) {
int index = Integer.parseInt(n.getAttributes().getNamedItem(NODENAME_INDEX).getNodeValue());
if(index == backgroundColorIndex) {
int r = Integer.parseInt(n.getAttributes().getNamedItem(NODENAME_RED).getNodeValue());
int g = Integer.parseInt(n.getAttributes().getNamedItem(NODENAME_GREEN).getNodeValue());
int b = Integer.parseInt(n.getAttributes().getNamedItem(NODENAME_BLUE).getNodeValue());
backgroundColor = new Color(r,g,b);
break;
}
}
// Initialize the default image
BufferedImage resultImage = new BufferedImage(imageWidth, imageHeight, IMAGETYPE);
BufferedImage previousImage;
// for each frame in the gif animation
while(images.hasNext()) {
// create a copy for the disposal method "restoreToPrevious"
previousImage = new BufferedImage(imageWidth, imageHeight, IMAGETYPE);
previousImage.setData(resultImage.copyData(null));
// fetch the frame
IIOImage im = images.next();
// get the metadata for this frame
IIOMetadata metaData = im.getMetadata();
Node root = metaData.getAsTree(metaData.getNativeMetadataFormatName());
// we need to determine the "delay" factor,
// the amount of time between this frame and the next
int delay = 0;
String delayString = findValueWithPath(root, NODEPATH_DELAYTIME);
if(delayString != null) {
// values returned are in (1/100), multiply by 10 to convert to millis (1/1000)
// for ease of use with Thread.sleep() and System.currentTimeMillis()
delay = Integer.parseInt(delayString) * 10;
}
// Gif animations return a renderedImage
RenderedImage i = im.getRenderedImage();
// determine where to draw on current frame,
// in the case of a progressive gif animation
int imageLeft= Integer.parseInt(findValueWithPath(root, NODEPATH_IMAGELEFTPOS));
int imageTop = Integer.parseInt(findValueWithPath(root, NODEPATH_IMAGETOPPOS));
// paint the result on the renderedImage
resultImage.createGraphics().drawRenderedImage(i, AffineTransform.getTranslateInstance(imageLeft, imageTop));
// Now we have a new frame, create a bufferedImage to hold this frame
BufferedImage newIm = new BufferedImage(imageWidth, imageHeight, IMAGETYPE);
// and copy the framedata to it
newIm.setData(resultImage.copyData(null));
// and store it somewhere
this.addFrame(newIm, delay, calcTexture);
// now we have to take a look at how to dispose of the current frame
String disposalMethod = findValueWithPath(root, NODEPATH_DISPOSALMETHOD);
// we either restore it to the previous image
if(disposalMethod.equals(DISPOSALMETHOD_RESTOREPREVIOUS)) {
resultImage.setData(previousImage.copyData(null));
// or to the background color
} else if(disposalMethod.equals(DISPOSALMETHOD_CLEARTOBACKGROUNDCOLOR)) {
Graphics2D g = resultImage.createGraphics();
// Set the graphics2D to overwrite mode,
// otherwise painting with transparent colors
// wont be very effective
g.setPaintMode();
// determine if we have a transparent gif
// and wheter the backgroundcolor is the
// transparent color
boolean hasTransparancy = Boolean.parseBoolean(findValueWithPath(root, NODEPATH_ISTRANSPARENT));
int transParantColorIndex = Integer.parseInt(findValueWithPath(root, NODEPATH_TRANSPARENTCOLORINDEX));
if(hasTransparancy && backgroundColorIndex == transParantColorIndex) {
// since the original color isn't transparent
// we must create a new color which is
g.setColor(
new Color(
backgroundColor.getRed(),
backgroundColor.getGreen(),
backgroundColor.getBlue(),
0.0f
)
);
} else {
// use the opaque backgroundColor
g.setColor(backgroundColor);
}
// clear the image
g.fillRect(0,0, imageWidth, imageHeight);
}
// ok.. next frame
}