Results 1 to 5 of 5
  1. #1
    BLuFeNiX is offline Member
    Join Date
    Dec 2011
    Rep Power

    Default ImageIO.write creates malformed PNG

    Hi everyone,

    I'm making a program to convert animated GIFs into a boot animation for android phones.

    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 and put it on my phone it just shows a black screen on boot. The phone can't read them for some reason.

    Here is an example of a working boot animation I made (created with command line utilities):

    and here is the same animation NOT working (created with my Java program):

    Here is my code:
    Java Code:
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.image.BufferedImage;
    import java.util.Iterator;
    import javax.imageio.*;
    import javax.imageio.metadata.IIOMetadata;
    import javax.imageio.metadata.IIOMetadataNode;
    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);
    		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 =;
    			if (i == 0) { background =; }
    			// 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.drawImage(combined, 0, 0, resizeWidth, resizeHeight, null);
    			// 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)
    	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;
    I compared the working and non-working PNGs metadata, and it's all identical except for lines 3-6 (which is present only in the WORKING image's metadata):
    Java Code:
        <IHDR width="320" height="480" bitDepth="8" colorType="RGB" compressionMethod="deflate" filterMethod="adaptive" interlaceMethod="none"/>
        <pHYs pixelsPerUnitXAxis="72" pixelsPerUnitYAxis="72" unitSpecifier="unknown"/>
            <UnknownChunk type="vpAg"/>
            <ColorSpaceType name="RGB"/>
            <NumChannels value="3"/>
            <BlackIsZero value="true"/>
            <CompressionTypeName value="deflate"/>
            <Lossless value="true"/>
            <NumProgressiveScans value="1"/>
            <PlanarConfiguration value="PixelInterleaved"/>
            <SampleFormat value="UnsignedIntegral"/>
            <BitsPerSample value="8 8 8"/>
            <PixelAspectRatio value="1.0"/>
            <ImageOrientation value="Normal"/>
            <Alpha value="none"/>
    Is there some other way to write out a PNG? Please help me figure out what the difference is between my working and non working PNGs! Thanks!

  2. #2
    Bushman is offline Member
    Join Date
    Apr 2012
    Spainish TOwn
    Rep Power

    Default Re: ImageIO.write creates malformed PNG

    1.Open app.
    2.Toggle ctrl+print screen.

  3. #3
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Madgaon, Goa, India
    Rep Power

    Default Re: ImageIO.write creates malformed PNG

    Moved from Advanced Java

    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  4. #4
    BLuFeNiX is offline Member
    Join Date
    Dec 2011
    Rep Power

    Default Re: ImageIO.write creates malformed PNG

    Quote Originally Posted by Bushman View Post
    1.Open app.
    2.Toggle ctrl+print screen.
    I'm not sure what you mean. You want me to take a screenshot of something?

  5. #5
    BLuFeNiX is offline Member
    Join Date
    Dec 2011
    Rep Power

    Default Re: ImageIO.write creates malformed PNG

    Quote Originally Posted by DarrylBurke View Post
    Moved from Advanced Java

    Thanks, I'll look more carefully at the subforum choices next time.

Similar Threads

  1. MalFormed DataBase Schema
    By Glorfindel Arnatuile in forum JDBC
    Replies: 2
    Last Post: 02-29-2012, 04:50 AM
  2. Creates multiple log files
    By bikashlama in forum New To Java
    Replies: 3
    Last Post: 12-27-2011, 07:09 AM
  3. Choking on malformed args?
    By blackbird in forum Networking
    Replies: 14
    Last Post: 07-19-2011, 10:14 PM
  4. When the compiler creates the variable?
    By hitesh_public in forum New To Java
    Replies: 14
    Last Post: 08-17-2010, 11:21 AM
  5. PDFBox certificate malformed
    By wanderer2019 in forum Advanced Java
    Replies: 0
    Last Post: 06-09-2010, 11:29 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts