Hi guys,
You may have noticed that I'm working on a program to convert an animated GIF to a bootanimation.zip.
I have almost everything working, but I realized something today: My converted PNGs don't work!
I can take an animated GIF and convert it into PNGs via a command line tool, and put them in a zip, and everything works. When I do the same with my tool it creates an almost identical image (slight differences in resize algorithm), but when I package them into a bootanimation.zip and put it on my phone it just shows a black screen on boot.
Here is an example of a working boot animation I made (created with command line utilities):
http://dl.dropbox.com/u/68531860/bootanimation.zip
and here is the same animation NOT working (created with my Java program):
http://dl.dropbox.com/u/68531860/bootanimationJ.zip
Here is my code:
Please help me figure out what the difference is between my working and non working PNGs!
You may have noticed that I'm working on a program to convert an animated GIF to a bootanimation.zip.
I have almost everything working, but I realized something today: My converted PNGs don't work!
I can take an animated GIF and convert it into PNGs via a command line tool, and put them in a zip, and everything works. When I do the same with my tool it creates an almost identical image (slight differences in resize algorithm), but when I package them into a bootanimation.zip and put it on my phone it just shows a black screen on boot.
Here is an example of a working boot animation I made (created with command line utilities):
http://dl.dropbox.com/u/68531860/bootanimation.zip
and here is the same animation NOT working (created with my Java program):
http://dl.dropbox.com/u/68531860/bootanimationJ.zip
Here is my code:
Code:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.*;
public class test {
static BufferedImage background; // background (for optimized GIFs)
public static void main(String[] args) throws Exception {
Object input = new File("img.gif"); // or Object input = new FileInputStream("animated.gif");
ImageInputStream stream = ImageIO.createImageInputStream(input);
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (!readers.hasNext())
throw new RuntimeException("no image reader found");
ImageReader reader = (ImageReader) readers.next();
reader.setInput(stream);
int n = reader.getNumImages(true);
System.out.println("numImages = " + n);
for (int i = 0; i < n; i++) {
// get metadata (in order to detect framerate and top/left positioning for each frame)
IIOImage frame = reader.readAll(i,null);
IIOMetadata meta = frame.getMetadata();
IIOMetadataNode imgRootNode = (IIOMetadataNode) meta.getAsTree("javax_imageio_gif_image_1.0");
// get framerate for animation
if (i == 0) {
IIOMetadataNode gce = (IIOMetadataNode) imgRootNode.getElementsByTagName("GraphicControlExtension").item(0);
int delay = Integer.parseInt(gce.getAttribute("delayTime"));
System.out.println("DELAY: " + delay);
}
IIOMetadataNode imgDescr = (IIOMetadataNode) imgRootNode.getElementsByTagName("ImageDescriptor").item(0);
int offsetX = Integer.parseInt(imgDescr.getAttribute("imageLeftPosition")); // find offsets for each
int offsetY = Integer.parseInt(imgDescr.getAttribute("imageTopPosition")); // frame in the animated GIF
BufferedImage overlay = reader.read(i);
if (i == 0) { background = reader.read(i); }
// combine current and previous frame to create complete frame (in case of optimized GIFs)
BufferedImage combined = new BufferedImage(background.getWidth(), background.getHeight(), BufferedImage.TYPE_INT_ARGB);
// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(background, 0, 0, null);
g.drawImage(overlay, offsetX, offsetY, null);
// create new directory for images
if (i == 0) {
new File("bootanimation/").mkdirs();
}
// resize frame to fit screen
int resizeWidth;
int resizeHeight;
if (background.getWidth() > background.getHeight()) {
resizeWidth = 480;
resizeHeight = 320;
}
else {
resizeWidth = 320;
resizeHeight = 480;
}
// Create new (blank) image of required (scaled) size
BufferedImage scaledImage = new BufferedImage(resizeWidth, resizeHeight, BufferedImage.TYPE_INT_ARGB);
// Paint scaled version of image to new image
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(combined, 0, 0, resizeWidth, resizeHeight, null);
graphics2D.dispose();
// rotate the image if it's wider than it is tall
if (scaledImage.getWidth() > scaledImage.getHeight()) {
ImageIO.write(rotate270(scaledImage), "PNG", new File("bootanimation/img" + String.format("%04d", i) + ".png"));
}
else {
ImageIO.write(scaledImage, "PNG", new File("bootanimation/img" + String.format("%04d", i) + ".png"));
}
background = combined; // save our most recently created frame as the background for the next frame (in case of optimized GIFs)
}
stream.close();
}
public static BufferedImage rotate270(BufferedImage img) {
int width = img.getWidth();
int height = img.getHeight();
BufferedImage newImage = new BufferedImage(height, width, img.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
newImage.setRGB(j, width - 1 - i, img.getRGB(i, j));
return newImage;
}
}
Please help me figure out what the difference is between my working and non working PNGs!