Omnimaga
General Discussion => Technology and Development => Computer Programming => Topic started by: Scipi on August 02, 2012, 07:37:58 pm
-
I'm trying to add gif support to a certain secret project. Due to the way I'm handling drawing to the screen, I need to convert the gif image data into an array of pixels as well as get the data for how many frames, time between frames, etc. I was wondering if anyone here knows the gif file format and could help me.
Here is the current way I load pixels:
private void loadTiles(String name) {
for (int i = 0; i < tileNames.length; i++) {
try {
BufferedImage image = ImageIO.read(TileSet.class.getResource("/tiles/" + name + "/" + tileNames[i] + ".gif"));
Render result = new Render(xPix, yPix);//Render contains the pixel data in result.pixels
System.out.println(result.width);
image.getRGB(0, 0, xPix, yPix, result.pixels, 0, xPix);
tileRender[i] = result;
} catch (Exception e) {
System.err.println("File: \"" + "tiles/" + name + "/" + tileNames[i] + ".gif" + "\" does not exist");
throw new RuntimeException(e);
}
}
}
It seems I could use image.getRGB(), but how would I do so?
Thanks!
-
you may start here:
http://www.martinreddy.net/gfx/2d/GIF87a.txt
-
Thanks, though is there a way to get the data using BufferedImage? I'd rather use something like that to easily handle everything instead of having to dig out everything directly. I know how I could get all the data into an array, but how do I get the number of frames for each? Or is there a better way to get animation?
-
Okay, here's an example I made that shows loading a gif and displaying it as an animation. You should be able to look at this and adapt it for what you need. If you need help, just ask, or if you want me to try and adapt it for you, I could try, you'll just need to provide a little more info on the code structure of the project =P
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import org.w3c.dom.*;
public class GIFTEST {
public static void main(String[] args) throws IOException {
File input = new File("cat.gif");
ImageInputStream stream = ImageIO.createImageInputStream(input);
Iterator readers = ImageIO.getImageReaders(stream);
if (!readers.hasNext()) throw new RuntimeException("No image reader found");
ImageReader reader = (ImageReader)readers.next();
reader.setInput(stream);
int num = reader.getNumImages(true);
GifFrame[] frames = new GifFrame[num];
for (int i = 0; i < num; i++) {
frames[i] = new GifFrame();
BufferedImage image = reader.read(i);
frames[i].i = image;
IIOMetadata meta = reader.getImageMetadata(i);
NodeList nodes = meta.getAsTree(meta.getNativeMetadataFormatName()).getChildNodes();
for (int x = 0; x < nodes.getLength(); x++) {
Node n = nodes.item(x);
if (n.getLocalName().equals("GraphicControlExtension")) {
NamedNodeMap atts = n.getAttributes();
frames[i].time = Integer.parseInt(atts.getNamedItem("delayTime").getNodeValue());
frames[i].dispose = atts.getNamedItem("disposalMethod").getNodeValue();
frames[i].wait = Boolean.parseBoolean(atts.getNamedItem("userInputFlag").getNodeValue());
}
}
}
stream.close();
Frame f = new Frame("GIF Test");
GifAnimator ga = new GifAnimator(frames);
ga.setSize(400, 400);
f.add(ga);
f.pack();
f.setVisible(true);
ga.start();
}
}
class GifFrame {
public Image i;
public int time;
public String dispose;
public boolean wait;
}
class GifAnimator extends Canvas {
private GifFrame[] frames;
private Thread animator;
private boolean run = false;
private int f = 0;
public GifAnimator(GifFrame[] frames) {
this.frames = frames;
}
public void start() {
run = true;
animator = new Thread() {
@Override
public void run() {
while (run) {
for (int i = 0; i < frames.length; i++) {
f = i;
repaint();
try {sleep(frames[i].time * 10);} catch (Exception e) {}
}
}
}
};
animator.start();
}
public void stop() {
run = false;
}
@Override
public void paint(Graphics g) {
g.drawImage(frames[f].i, 0, 0, null);
}
@Override
public void update(Graphics g) {
paint(g);
}
}
-
Okay, here's an example I made that shows loading a gif and displaying it as an animation. You should be able to look at this and adapt it for what you need. If you need help, just ask, or if you want me to try and adapt it for you, I could try, you'll just need to provide a little more info on the code structure of the project =P
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import org.w3c.dom.*;
public class GIFTEST {
public static void main(String[] args) throws IOException {
File input = new File("cat.gif");
ImageInputStream stream = ImageIO.createImageInputStream(input);
Iterator readers = ImageIO.getImageReaders(stream);
if (!readers.hasNext()) throw new RuntimeException("No image reader found");
ImageReader reader = (ImageReader)readers.next();
reader.setInput(stream);
int num = reader.getNumImages(true);
GifFrame[] frames = new GifFrame[num];
for (int i = 0; i < num; i++) {
frames[i] = new GifFrame();
BufferedImage image = reader.read(i);
frames[i].i = image;
IIOMetadata meta = reader.getImageMetadata(i);
NodeList nodes = meta.getAsTree(meta.getNativeMetadataFormatName()).getChildNodes();
for (int x = 0; x < nodes.getLength(); x++) {
Node n = nodes.item(x);
if (n.getLocalName().equals("GraphicControlExtension")) {
NamedNodeMap atts = n.getAttributes();
frames[i].time = Integer.parseInt(atts.getNamedItem("delayTime").getNodeValue());
frames[i].dispose = atts.getNamedItem("disposalMethod").getNodeValue();
frames[i].wait = Boolean.parseBoolean(atts.getNamedItem("userInputFlag").getNodeValue());
}
}
}
stream.close();
Frame f = new Frame("GIF Test");
GifAnimator ga = new GifAnimator(frames);
ga.setSize(400, 400);
f.add(ga);
f.pack();
f.setVisible(true);
ga.start();
}
}
class GifFrame {
public Image i;
public int time;
public String dispose;
public boolean wait;
}
class GifAnimator extends Canvas {
private GifFrame[] frames;
private Thread animator;
private boolean run = false;
private int f = 0;
public GifAnimator(GifFrame[] frames) {
this.frames = frames;
}
public void start() {
run = true;
animator = new Thread() {
@Override
public void run() {
while (run) {
for (int i = 0; i < frames.length; i++) {
f = i;
repaint();
try {sleep(frames[i].time * 10);} catch (Exception e) {}
}
}
}
};
animator.start();
}
public void stop() {
run = false;
}
@Override
public void paint(Graphics g) {
g.drawImage(frames[f].i, 0, 0, null);
}
@Override
public void update(Graphics g) {
paint(g);
}
}
This is perfect, I know exactly how to modify it, I just need to take each frame for each BufferedImage and get the pixel data array with getRGB, get the animation times, and number of frames like you did, and use those to display each frame for however long it needs to be.
Beyond that I'll just need to modify my code to support each drawable entity to have an array of arrays of ints to hold each frame.
I'll modify it to my code tonight, thanks!
Btw, I've been looking all over Google for the solution to this issue and found nothing. Where did you learn the stuff for gif rendering and animation?
-
http://www.daniweb.com/software-development/java/threads/177666/imageobserver-and-animated-gifs#post811177 Is where I found the code I used in the first part to actually load the frame data, then I saw a mention of metadata somewhere, so I googled that and came up with http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/metadata/package-summary.html and therefore http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/metadata/doc-files/gif_metadata.html which I used to write the metadata extractor, then I just added a simple animator to use all the read data.