Memory leak in java ImageIO.read() - java

I am utilizing ImageIO.read(). The class which is called by the main method of the original App is this:
import java.awt.*;
import javax.swing.*;
import java.io.File;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.JPanel;
class ImageGenerator extends JPanel{
JpegReader jpeg;
public ImageGenerator(Aplicacion a){
jpeg = new JpegReader();
loadImage();
}
private void loadImage(){
String path = "C:\\image.jpg";
image = new BufferedImage(100,100, BufferedImage.TYPE_INT_RGB); //in case error
try{
image = jpeg.readImage(new File(path));
}catch(Exception e){
System.err.println(e.getMessage());
}
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.drawImage(image, 0, 0, 1000, 800, null);
}
}
I am using the above in conjunction with this other class JpegReader, which I actually found on StackOverflow as an answer, but I forgot the name of the author to quote him.
import java.awt.image.BufferedImage;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.awt.color.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.ArrayList;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.byteSources.ByteSourceFile;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.formats.jpeg.JpegImageParser;
import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
public class JpegReader {
public static final int COLOR_TYPE_RGB = 1;
public static final int COLOR_TYPE_CMYK = 2;
public static final int COLOR_TYPE_YCCK = 3;
private int colorType = COLOR_TYPE_RGB;
private boolean hasAdobeMarker = false;
public BufferedImage readImage(File file) throws IOException, ImageReadException {
colorType = COLOR_TYPE_RGB;
hasAdobeMarker = false;
ImageInputStream stream = ImageIO.createImageInputStream(file);
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
while (iter.hasNext()) {
ImageReader reader = iter.next();
reader.setInput(stream);
BufferedImage image;
ICC_Profile profile = null;
try {
image = reader.read(0);
} catch (IIOException e) {
System.out.println("Hello");
colorType = COLOR_TYPE_CMYK;
checkAdobeMarker(file);
profile = Sanselan.getICCProfile(file);
WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
if (colorType == COLOR_TYPE_YCCK)
convertYcckToCmyk(raster);
if (hasAdobeMarker)
convertInvertedColors(raster);
image = convertCmykToRgb(raster, profile);
System.out.println("Hello");
}finally {
try {
System.out.println("facebook");
stream.close();
} catch (IOException ioex) {
//omitted.
}
}
return image;
}
return null;
}
public void checkAdobeMarker(File file) throws IOException, ImageReadException {
JpegImageParser parser = new JpegImageParser();
ByteSource byteSource = new ByteSourceFile(file);
#SuppressWarnings("rawtypes")
ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
if (segments != null && segments.size() >= 1) {
UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
byte[] data = app14Segment.bytes;
if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
{
hasAdobeMarker = true;
int transform = app14Segment.bytes[11] & 0xff;
if (transform == 2)
colorType = COLOR_TYPE_YCCK;
}
}
}
public static void convertYcckToCmyk(WritableRaster raster) {
int height = raster.getHeight();
int width = raster.getWidth();
int stride = width * 4;
int[] pixelRow = new int[stride];
for (int h = 0; h < height; h++) {
raster.getPixels(0, h, width, 1, pixelRow);
for (int x = 0; x < stride; x += 4) {
int y = pixelRow[x];
int cb = pixelRow[x + 1];
int cr = pixelRow[x + 2];
int c = (int) (y + 1.402 * cr - 178.956);
int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
y = (int) (y + 1.772 * cb - 226.316);
if (c < 0) c = 0; else if (c > 255) c = 255;
if (m < 0) m = 0; else if (m > 255) m = 255;
if (y < 0) y = 0; else if (y > 255) y = 255;
pixelRow[x] = 255 - c;
pixelRow[x + 1] = 255 - m;
pixelRow[x + 2] = 255 - y;
}
raster.setPixels(0, h, width, 1, pixelRow);
}
}
public static void convertInvertedColors(WritableRaster raster) {
int height = raster.getHeight();
int width = raster.getWidth();
int stride = width * 4;
int[] pixelRow = new int[stride];
for (int h = 0; h < height; h++) {
raster.getPixels(0, h, width, 1, pixelRow);
for (int x = 0; x < stride; x++)
pixelRow[x] = 255 - pixelRow[x];
raster.setPixels(0, h, width, 1, pixelRow);
}
}
public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
if (cmykProfile == null)
cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));
if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) {
byte[] profileData = cmykProfile.getData();
if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first
cmykProfile = ICC_Profile.getInstance(profileData);
}
}
ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster rgbRaster = rgbImage.getRaster();
ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
cmykToRgb.filter(cmykRaster, rgbRaster);
return rgbImage;
}
static void intToBigEndian(int value, byte[] array, int index) {
array[index] = (byte) (value >> 24);
array[index+1] = (byte) (value >> 16);
array[index+2] = (byte) (value >> 8);
array[index+3] = (byte) (value);
}
}
I am using sanselan-0.97-incubator.jar.
If I run this program 31 times approximately, I will get a java heap space error, so I suspect I have a memory leak.
Please help me find the memory leak or suggest how to fix the issue.
Also let me know if the jar file I'm using is OKAY, or maybe it's outdated. I had some issues locating a sanselan jar file.
Thanks in advance.

I have got the same memory issue with this code (JPEGReader). After a few trials, I found that calling reader.dispose() can solve this issue.
I give the method that I have modified. Hope it is helpful to you.
public BufferedImage readImage(File file) throws IOException, ImageReadException {
colorType = COLOR_TYPE_RGB;
hasAdobeMarker = false;
ImageInputStream stream = ImageIO.createImageInputStream(file);
try{
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
while (iter.hasNext()) {
ImageReader reader = iter.next();
reader.setInput(stream);
BufferedImage image;
ICC_Profile profile = null;
try {
image = reader.read(0);
} catch (IIOException e) {
colorType = COLOR_TYPE_CMYK;
checkAdobeMarker(file);
profile = Sanselan.getICCProfile(file);
WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
if (colorType == COLOR_TYPE_YCCK)
convertYcckToCmyk(raster);
if (hasAdobeMarker)
convertInvertedColors(raster);
image = convertCmykToRgb(raster, profile);
return image;
}
finally {
reader.dispose();
}
}
return null;
}
finally {
if (stream != null){
stream.close();
}
}
}

Related

Floyd-SteinBerg dithering program bug. java

Hey im trying to create a program which uses Floyd-Steinberg's dithering algorithm to produce a dithered version of a image.
the code for my program is below.
but I believe I am getting an error with with the rounding in the "calculateErr" multiplication with the diviser.
the image I am using to test is this cat one: Cat Image
and for some reason it ends up looking like this Dithered cat image
any solutions to what I am doing wrong would be greatly appreciated.
import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Dithering extends Canvas {
public BufferedImage ditheredIMG = new BufferedImage(481,480,
BufferedImage.TYPE_BYTE_GRAY);
public void paint(Graphics g) {
BufferedImage i = null;
try {
i = displayImage(g);
} catch (IOException e) {
throw new RuntimeException(e);
}
getPixels(g, i);
g.drawImage(ditheredIMG,480,0,this);
}
public static void main(String[] args) {
Dithering d = new Dithering();
JFrame f =new JFrame();
f.add(d);
f.setSize( 960,481);
f.setVisible(true);
}
public BufferedImage displayImage(Graphics g) throws IOException {
final File file = new File("Cat.jpg");
final BufferedImage i = ImageIO.read(file);
g.drawImage(i, 0,0,this);
return i;
}
public void getPixels(Graphics g, BufferedImage i) {
for (int y = 1; y < i.getHeight()-1; y++){
for (int x = 1; x < i.getWidth()-1; x++) {
int pixelValue = i.getRGB(x, y);
int red = (pixelValue & 0x00ff0000) >> 16;
int green = (pixelValue & 0x0000ff00) >> 8;
int blue = pixelValue & 0x000000ff;
int newRed = quantisePixel(red);
int newGreen = quantisePixel(green);
int newBlue = quantisePixel(blue);
int newPixel = (newRed << 16) | (newGreen << 8) | newBlue;
ditheredIMG.setRGB(x+1,y, (int) (calculateErr(pixelValue, newPixel) * (7/16.0)));
ditheredIMG.setRGB(x-1,y+1, (int) (calculateErr(pixelValue, newPixel) * (3/16.0)));
ditheredIMG.setRGB(x,y+1, (int) (calculateErr(pixelValue, newPixel) * (5/16.0)));
ditheredIMG.setRGB(x+1,y+1, (int) (calculateErr(pixelValue, newPixel)* (1/16.0)));
}
}
}
public int calculateErr(int oldVal, int newVal){
return oldVal-newVal;
}
public static int quantisePixel(int val){
if(val > 127){
return 255;
} else{
return 0;
}
}
}
hey so here is the updated version but I am unsure if its working correctly if anyone can tell me if it is or is not that would be greatly appreciated. I've changed it so now its supposed to be updating the surrounding pixels correctly but from my eyes it looks to be the exact same as without updating the neighbours.
import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import static java.lang.Math.abs;
public class Dithering extends Canvas {
public BufferedImage ditheredIMG = new BufferedImage(481,480,
BufferedImage.TYPE_BYTE_GRAY);
public void paint(Graphics g) {
BufferedImage i = null;
try {
i = displayImage(g);
} catch (IOException e) {
throw new RuntimeException(e);
}
getPixels(g, i);
g.drawImage(ditheredIMG,480,0,this);
}
public static void main(String[] args) {
Dithering d = new Dithering();
JFrame f =new JFrame();
f.add(d);
f.setSize( 960,481);
f.setVisible(true);
}
public BufferedImage displayImage(Graphics g) throws IOException {
final File file = new File("Cat.jpg");
final BufferedImage i = ImageIO.read(file);
g.drawImage(i, 0,0,this);
return i;
}
public void getPixels(Graphics g, BufferedImage i) {
for (int y = 1; y < i.getHeight()-1; y++){
for (int x = 1; x < i.getWidth()-1; x++) {
int pixelValue = i.getRGB(x, y);
int red = (pixelValue & 0x00ff0000) >> 16;
int green = (pixelValue & 0x0000ff00) >> 8;
int blue = pixelValue & 0x000000ff;
int newRed = quantisePixel(red);
int newGreen = quantisePixel(green);
int newBlue = quantisePixel(blue);
int newPixel = (newRed << 16) | (newGreen << 8) | newBlue;
ditheredIMG.setRGB(x,y,newPixel);
int newPixelValue = i.getRGB(x+1,y);
ditheredIMG.setRGB(x+1,y, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (7/16.0)));
newPixelValue = i.getRGB(x-1,y+1);
ditheredIMG.setRGB(x-1,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (3/16.0)));
newPixelValue = i.getRGB(x,y+1);
ditheredIMG.setRGB(x,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (5/16.0)));
newPixelValue = i.getRGB(x+1,y+1);
ditheredIMG.setRGB(x+1,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel)* (1/16.0)));
}
}
}
public int calculateErr(int oldVal, int newVal){
return oldVal-newVal;
}
public static int quantisePixel(int val){
if(val > 127){
return 255;
} else{
return 0;
}
}
}

How to check if a character is a modifier in java

I am trying to make an image to text program that converts a 0-255 value to a character that matches it (visually). The important thing here is having all characters the same width so in a text editor the text is square...
basically I want all characters from 32-4000 that have the same width as 'X' so I can use 'Q' but not '|' (this font is mono tho so there is no difference)
I am using the Unifont font.
What I have currently works, but I want to supply a general range of unicode characters that are all the same size (so it looks good in text at the end)
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Color fntC = new Color(255, 255, 255);
Graphics2D g = img.createGraphics();
g.setFont(f);
FontMetrics fm = g.getFontMetrics();
for (int i = 32; i <= 4000/*126*/; i++) { //33 126
if (fm.charWidth((char)i) == fm.charWidth('X') && Character.isLetter(i))
dictionary.add(new letter((char) i, getValue((char) i)));
}
This code works pretty well, but I still get characters like 'ȷ' that has a smaller width in the text editor but is treated as the same width as 'X' according to font metrics (I'm using Courier new since that's the default of Notepad++)
MOAR CODE:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MainImageToText {
public static void main(String[] args) {
CharDictionary cd = new CharDictionary(new Font("Unifont", 1, 20));
JFileChooser chooser = new JFileChooser();
/*FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG Images", "png");
chooser.setFileFilter(filter);*/
chooser.setCurrentDirectory(new File(System.getProperty("user.home"), "Desktop"));
int returnVal = chooser.showOpenDialog(null);
File f = chooser.getSelectedFile();
if (returnVal == JFileChooser.APPROVE_OPTION) {
System.out.println("\nYou chose to open this file: " + f);
File output = new File(f.getParentFile(), "$output.txt");
saveTextFile(output, ImageToText(f, cd));
}
}
static String ImageToText(File f, CharDictionary cd) {
BufferedImage img = null;
String text = "";
try {
img = ImageIO.read(f);
} catch (IOException e) {
e.printStackTrace();
}
int w = img.getWidth();
int h = img.getHeight();
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color col = new Color(img.getRGB(x, y));
int red = col.getRed();
int green = col.getGreen();
int blue = col.getBlue();
int finalAverage = (red + green + blue) / 3;
text += cd.getDictionaryLetter(finalAverage);
System.out.println(x + ", " + y);
}
text += "\n";
}
cd.debugPrintDictionary();
// System.out.println(text);
return text;
}
static void saveTextFile(File f, String s) {
File desktop = new File(System.getProperty("user.home"), "Desktop");
File outputfile = new File(desktop.toString() + "\\" + "file.txt");
try {
System.out.println("creating file...");
PrintWriter out = new PrintWriter(outputfile, "UTF-8");
out.write(s);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Saved to: " + f);
}
}
class letter {
public String c;
public int val;
letter(String ch, int dub) {
c = ch;
val = dub;
}
public char getChar() {
Random rand = new Random();
return c.charAt(rand.nextInt(c.length()));
}
public void addChar(char ch) {
c += ch;
}
public void addChar(String ch) {
c += ch;
}
}
class LetterComparator implements Comparator<letter> {
#Override
public int compare(letter a, letter b) {
return (a.val - b.val); // *100 for more precision
}
}
class CharDictionary {
private Font f;
private List<letter> dictionary = new ArrayList<letter>();
CharDictionary(Font font) {
f = font;
createDictionary();
}
public void createDictionary() {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Color fntC = new Color(255, 255, 255);
Graphics2D g = img.createGraphics();
g.setFont(f);
FontMetrics fm = g.getFontMetrics();
dictionary.add(new letter(" ", getValue(' ')));
for (int i = 32; i <= 65000; i++) { //33 126
if (fm.charWidth(i) == fm.charWidth('X') && !Character.isWhitespace(i))
dictionary.add(new letter((char) i + "", getValue((char) i)));
}
sort();
compact();
}
public void sort() {
Collections.sort(dictionary, new LetterComparator());
}
public void compact() {
int val;
for (int i = dictionary.size()-1; i > 0 ; i--) {
val = dictionary.get(i).val;
if (val == dictionary.get(i-1).val) {
dictionary.get(i-1).addChar(dictionary.get(i).c);
dictionary.remove(i);
}
}
}
public void debugPrintDictionary() {
for (int i = 0; i < dictionary.size(); i++) {
System.out.println("Char: " + dictionary.get(i).c + " Value: " + dictionary.get(i).val);
}
}
/*public int getIndexofVal(int n) {
return null;
}*/
public char getDictionaryLetter(int val) {
for (int i = 0; i < dictionary.size(); i++) {
int charvalue = dictionary.get(i).val;
if (charvalue >= 255-val) {//inverted here
return dictionary.get(i).getChar();
}
}
return dictionary.get(dictionary.size() - 1).getChar(); /// PROBLEM HERE
}
public int getValue(char c) {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Color fntC = new Color(255, 255, 255);
Graphics2D g = img.createGraphics();
g.setFont(f);
FontMetrics fm = g.getFontMetrics();
int width = fm.charWidth(c);
int height = fm.getAscent()+ fm.getDescent(); // too big
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g = img.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(fntC);
g.setFont(f);
// g.fill
g.drawString(c + "", 0, fm.getAscent());
int w = img.getWidth();
int h = img.getHeight();
double finalAverage = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color col = new Color(img.getRGB(x, y));
int red = col.getRed();
int green = col.getGreen();
int blue = col.getBlue();
finalAverage += (red + green + blue) / 3;
}
}
finalAverage /= w * h;
/*try {
File desktop = new File(System.getProperty("user.home"), "Desktop");
File outputfile = new File(desktop.toString() + "\\letters\\" + (int) c + ".png");
ImageIO.write(img, "png", outputfile);
} catch (IOException e) {
}*/
return (int)finalAverage;
}
}

Program doesn't work - NullPointerException

I am using eclipse to export my project as a runnable jar file, when I try to run it nothing happens, when I run it using cmd I get this error.
C:\Users\Enes\Desktop>cmd.exe
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\Enes\Desktop>java -jar Game.Jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoa
der.java:58)
Caused by: java.lang.NullPointerException
at scrolls.Resources.createArray(Resources.java:111)
at scrolls.Player.<init>(Player.java:31)
at scrolls.Draw.<init>(Draw.java:27)
at scrolls.Frame.main(Frame.java:18)
... 5 more
C:\Users\Enes\Desktop>
When I run it using eclipse it runs fine with no errors or warnings.
This is my Resource file which seems to be causing the problem at line 111
package scrolls;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.imgscalr.Scalr;
public class Resources
{
Map map;
static BufferedImage[] textures = new BufferedImage[8];
static BufferedImage[] mapTextures = new BufferedImage[9];
static BufferedImage texture;
static BufferedImage[] waterAnimated = new BufferedImage[64];
static BufferedImage water;
static BufferedImage icon;
public static Font f, fs;
static int imageCounter = 0;
public Resources()
{
map = new Map();
textures();
createArray(texture, textures, 32, 1, 8);
createArray(water, waterAnimated, 32, 64, 1);
getFont();
buildMapTextures(textures, mapTextures);
}
public static void counter()
{
imageCounter++;
if (imageCounter >= 500)
imageCounter = 0;
//System.out.println(imageCounter / 8);
}
private void buildMapTextures(BufferedImage[] textures, BufferedImage[] mapTextures)
{
for (int i = 0; i <= 7; i++)
{
mapTextures[i] = resize(textures[i], 3, 3);
}
mapTextures[8] = resize(waterAnimated[2], 3, 3);
}
private BufferedImage resize(BufferedImage image, int newW, int newH)
{
BufferedImage thumbnail = Scalr.resize(image, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, newW, newH, Scalr.OP_ANTIALIAS);
return thumbnail;
}
public static BufferedImage waterAnimation()
{
return waterAnimated[imageCounter / 8];
}
private void textures()
{
try
{
texture = ImageIO.read(new File("src/resources/textures.png"));
} catch (IOException e)
{
}
try
{
water = ImageIO.read(new File("src/resources/water.png"));
} catch (IOException e)
{
}
try
{
icon = ImageIO.read(new File("src/resources/icon.png"));
} catch (IOException e)
{
}
}
static BufferedImage player()
{
BufferedImage player = null;
try
{
player = ImageIO.read(new File("src/resources/player.png"));
} catch (IOException e)
{
}
return player;
}
static void createArray(BufferedImage image, BufferedImage[] images, int size, int rows, int cols)
{
BufferedImage temp = image;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
images[(i * cols) + j] = temp.getSubimage(j * size, i * size, size, size); // line 111
}
}
}
public static void readLevel(String filename, int[][] level, int part)
{
try
{
File f = new File("src/resources/levels/" + part + "/" + filename + ".txt");
FileReader fr = new FileReader(f);
BufferedReader in = new BufferedReader(fr);
StringBuilder sb = new StringBuilder();
byte b = 0;
while ((b = (byte) in.read()) != -1)
{
sb.append("" + ((char) b));
}
String str = sb.toString();
String[] lines = str.split("(\n|\r)+");
for (int i = 0; i < lines.length; i++)
{
for (int j = 0; j < lines[i].length(); j++)
{
level[i][j] = Integer.parseInt("" + lines[i].charAt(j));
}
}
in.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
private static void getFont()
{
try
{
f = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream("src/resources/Jet Set.ttf"));
fs = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream("src/resources/Jet Set.ttf"));
} catch (Exception e)
{
System.out.println(e);
}
f = f.deriveFont(22f);
fs = fs.deriveFont(13f);
}
}
Player code
package scrolls;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Transparency;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
public class Player
{
static int x, y, dx, dy;
BufferedImage[] sprites = new BufferedImage[8];
int rotation = 0;
int imageCounter = 0;
public static boolean moving = false;
static int playerEnergy = 150000;
static int playerLvl = 1;
static int playerExp = 3;
static int expNeeded = (((playerLvl + 1) * playerLvl) * 2);
static int playerHealth = 100;
static int playerMana = 100;
static int mapRow = 6;
static int mapColumn = 8;
static int playerRow, playerColumn;
public Player()
{
y = 40;
x = 700;
Resources.createArray(Resources.player(), sprites, 66, 1, 8);
}
private void changeImage()
{
imageCounter++;
if (imageCounter >= 80)
imageCounter = 0;
}
public void move()
{
y = y + dy;
x = x + dx;
changeImage();
playerPosition();
}
static void mapPosition()
{
if (y < 0)
playerRow = 0;
else
playerRow = (y / 32) + 1;
if (x < 0)
playerColumn = 0;
else
playerColumn = (x / 32) + 1;
}
private void playerPosition()
{
if (x >= 817 - 59)
{
x = -24;
mapColumn++;
}
if (x <= -25)
{
x = 817 - 59;
mapColumn--;
}
if (y <= -25)
{
y = 599 - 152 - 41;
mapRow--;
}
if (y >= 599 - 152 - 40)
{
y = -24;
mapRow++;
}
}
public static int playerExp()
{
return playerExp;
}
public static int getNextExp()
{
return expNeeded;
}
public static int playerLvl()
{
if (playerExp >= expNeeded)
{
playerLvl++;
}
return playerLvl;
}
public static int playerHealth()
{
return playerHealth;
}
public static int playerMana()
{
return playerMana;
}
public static int playerEnergy()
{
if ((dx != 0) || (dy != 0))
playerEnergy--;
if ((dx != 0) && (dy != 0))
playerEnergy--;
return playerEnergy;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public static BufferedImage rotate(BufferedImage image, double angle)
{
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
int w = image.getWidth(), h = image.getHeight();
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
Graphics2D g = result.createGraphics();
g.translate((neww - w) / 2, (newh - h) / 2);
g.rotate(angle, w / 2, h / 2);
g.drawRenderedImage(image, null);
g.dispose();
return result;
}
public BufferedImage getPlayerImage()
{
roatePlayer();
int image = animatePlayer();
double angle = Math.toRadians(rotation);
if (dy != 0 || dx != 0)
{
return rotate(sprites[image], angle);
}
return rotate(sprites[0], angle);
}
private int animatePlayer()
{
return imageCounter / 10;
}
private void roatePlayer()
{
if (dy > 0)
rotation = 0;
if (dy < 0)
rotation = 180;
if (dx > 0)
rotation = -90;
if (dx < 0)
rotation = 90;
if (dy > 0 && dx > 0)
rotation = -45;
if (dy > 0 && dx < 0)
rotation = 45;
if (dy < 0 && dx < 0)
rotation = 135;
if (dy < 0 && dx > 0)
rotation = -135;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_A)
{
dx = -1;
rotation = -90;
}
if (key == KeyEvent.VK_S)
{
dy = 1;
rotation = 0;
}
if (key == KeyEvent.VK_D)
{
dx = 1;
rotation = 90;
}
if (key == KeyEvent.VK_W)
{
dy = -1;
rotation = 180;
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_A)
dx = 0;
if (key == KeyEvent.VK_S)
dy = 0;
if (key == KeyEvent.VK_D)
dx = 0;
if (key == KeyEvent.VK_W)
dy = 0;
}
}
I strongly suspect that you're loading some resources (sounds, images) either by assuming that they're present as files, or you're using appropriate getResource / getResourceAsStream calls, but your resources aren't present in the jar file. We can't really tell without seeing any of your code or what's in your jar file, but you should check where you're loading the resource, and why you expect the resource to be found.
Oh, and you may have a casing issue too - when it's loading resources from the Windows file system, asking for FOO.PNG will work even if the file is called foo.png; the same is not true when loading resources from a jar file.
Of course, you should look at Resources.java line 111 and Player.java line 31 to help pin down exactly what's going wrong (e.g. which resource is failing).
EDIT: Okay, now that we've got the code, it's exactly as I first suggested. This line of code in Resource.player():
player = ImageIO.read(new File("src/resources/player.png"));
... is loading player.png expecting it to be a file on the local file system. You want something like:
player = ImageIO.read(Resource.class.getResource("/src/resources/player.png"));
It's odd to have a src folder in your jar file, by the way. If you've actually just got the image in a reources directory, you'd want:
player = ImageIO.read(Resource.class.getResource("/resources/player.png"));

Getting error while creating BufferedImage

CODE 1
/*
Java code for making the image grayscale, then binarizing it.
*/
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.Object;
import java.lang.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class lineremoval {
private static BufferedImage binarizedImage;
public static void main(String[] args) throws IOException {
File orignal_name = new File("photot.png");
binarizedImage = ImageIO.read(orignal_name);
ExtractBeltsBasedonCoveredHeight();
BufferedImage bmp = new BufferedImage(binarizedImage.getWidth(), binarizedImage.getHeight(),binarizedImage.getType());
for(int i=0; i<binarizedImage.getWidth(); i++) {
for(int j=0; j<binarizedImage.getHeight(); j++) {
int red;
red = new Color(binarizedImage.getRGB(i,j)).getRed();
int alpha = new Color(binarizedImage.getRGB(i,j)).getAlpha();
int newPixel;
newPixel = colorToRGB(alpha, red,red,red);
bmp.setRGB(i, j, newPixel);
}
}
writeImage(bmp,0);
}
public static int FindBottomOfLine(BufferedImage bitmap, int topOfLine)
{
int x=0;
boolean no_black_pixel;
no_black_pixel = false;
int to_match;
while (no_black_pixel == false)
{
topOfLine++;
int white=new Color(bitmap.getRGB(0,0)).getRed();
no_black_pixel = true;
for (x = 0; x < bitmap.getWidth() && topOfLine < bitmap.getHeight(); x++)
{
to_match = new Color(bitmap.getRGB(x,topOfLine)).getRed();
if (to_match!=white)
no_black_pixel = false;
}
}
return topOfLine - 1;
}
public static int ExtractBeltsBasedonCoveredHeight()
{
int y = 0;
int x = 0;
boolean line_present = true;
ArrayList<Integer> line_top = new ArrayList<Integer>(1000);
ArrayList<Integer> line_bottom = new ArrayList<Integer>(1000);
while (line_present)
{
x = 0;
y = FindNextLine(binarizedImage, y, x);
if (y == -1)
break;
if (y >= binarizedImage.getHeight())
{
line_present = false;
}
if (line_present)
{
line_top.add(y);
y = FindBottomOfLine(binarizedImage, y) + 1;
line_bottom.add(y);
}
}
return 1;
}
private static void writeImage(BufferedImage bmp,int number) throws IOException {
String strI = Integer.toString(number);
File file = new File("output"+strI+".png");
try {
ImageIO.write(bmp, "png", file);
}catch(IOException e) {
System.out.println("Not worked");
}
finally {
System.out.println("Works fine");
}
}
private static int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red; newPixel = newPixel << 8;
newPixel += green; newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
public static int FindNextLine(BufferedImage bitmap, int y,int x)
{
if (y >= bitmap.getHeight())
return -1;
int white=new Color(bitmap.getRGB(0,0)).getRed();
int to_match = new Color(bitmap.getRGB(x,y)).getRed();
while (to_match==white)
{
x++;
if (x == bitmap.getWidth())
{
x = 0;
y++;
}
if (y >= bitmap.getHeight())
{
break;
}
to_match = new Color(bitmap.getRGB(x,y)).getRed();
}
return y < bitmap.getHeight() ? y : -1;
}
}
CODE 2
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.Object;
import java.lang.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class lineremoval {
private static BufferedImage binarizedImage;
public static void main(String[] args) throws IOException {
File orignal_name = new File("photot.png");
binarizedImage = ImageIO.read(orignal_name);
ExtractBeltsBasedonCoveredHeight();
}
public static int FindBottomOfLine(BufferedImage bitmap, int topOfLine)
{
int x=0;
boolean no_black_pixel;
no_black_pixel = false;
int to_match;
while (no_black_pixel == false)
{
topOfLine++;
int white=new Color(bitmap.getRGB(0,0)).getRed();
no_black_pixel = true;
for (x = 0; x < bitmap.getWidth() && topOfLine < bitmap.getHeight(); x++)
{
to_match = new Color(bitmap.getRGB(x,topOfLine)).getRed();
if (to_match!=white)
no_black_pixel = false;
}
}
return topOfLine - 1;
}
public static int ExtractBeltsBasedonCoveredHeight()
{
int y = 0;
int x = 0;
boolean line_present = true;
ArrayList<Integer> line_top = new ArrayList<Integer>(1000);
ArrayList<Integer> line_bottom = new ArrayList<Integer>(1000);
while (line_present)
{
x = 0;
y = FindNextLine(binarizedImage, y, x);
if (y == -1)
break;
if (y >= binarizedImage.getHeight())
{
line_present = false;
}
if (line_present)
{
line_top.add(y);
y = FindBottomOfLine(binarizedImage, y) + 1;
line_bottom.add(y);
}
}
BufferedImage bmp = new BufferedImage(binarizedImage.getWidth(), binarizedImage.getHeight(),binarizedImage.getType());
for(int i=0; i<binarizedImage.getWidth(); i++) {
for(int j=0; j<binarizedImage.getHeight(); j++) {
int red;
red = new Color(binarizedImage.getRGB(i,j)).getRed();
int alpha = new Color(binarizedImage.getRGB(i,j)).getAlpha();
int newPixel;
newPixel = colorToRGB(alpha, red,red,red);
bmp.setRGB(i, j, newPixel);
}
}
writeImage(bmp,0);
return 1;
}
private static void writeImage(BufferedImage bmp,int number) throws IOException {
String strI = Integer.toString(number);
File file = new File("output"+strI+".png");
try {
ImageIO.write(bmp, "png", file);
}catch(IOException e) {
System.out.println("Not worked");
}
finally {
System.out.println("Works fine");
}
}
private static int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red; newPixel = newPixel << 8;
newPixel += green; newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
public static int FindNextLine(BufferedImage bitmap, int y,int x)
{
if (y >= bitmap.getHeight())
return -1;
int white=new Color(bitmap.getRGB(0,0)).getRed();
int to_match = new Color(bitmap.getRGB(x,y)).getRed();
while (to_match==white)
{
x++;
if (x == bitmap.getWidth())
{
x = 0;
y++;
}
if (y >= bitmap.getHeight())
{
break;
}
to_match = new Color(bitmap.getRGB(x,y)).getRed();
}
return y < bitmap.getHeight() ? y : -1;
}
}
I want to get x images from a bitmap Images containing x lines of paragraph.
each Image should contain one line from the paragraph.For this I have used function("ExtractBeltsBasedonCoveredHeight") to get two lists. In these lists ith element denotes the starting row no and end row no of ith line in paragraph (in list list_top and list_bottom).
After getting these values I am not able create Images from function ExtractBeltsBasedonCoveredHeight .
My code1 creates Images but code2 gives error both code are same the only difference is in code2 I have called writeImage from function "ExtractBeltsBasedonCoveredHeight" and in code1 I have called writeImage from main function
ERROR MESSAGE
lineremoval.java:86: error: unreported exception IOException; must be caught or declared to be thrown
writeImage(bmp,0);
^
1 error
The message is (as usual) telling you exactly what is wrong and how to fix it. You're calling code that has the potential to call an IOException, and when you do this you must either throw the exception or catch it in a try/catch block. Your best bet is to check out the exceptions tutorial to learn how to do both of these.

Convert each animated GIF frame to a separate BufferedImage

I want to be able to take an animated GIF as input, count the frames (and perhaps other metadata), and convert each to a BufferedImage.
How can I do this?
If you want all the frames to be the same size (for optimized GIFs) try something like this:
try {
String[] imageatt = new String[]{
"imageLeftPosition",
"imageTopPosition",
"imageWidth",
"imageHeight"
};
ImageReader reader = (ImageReader)ImageIO.getImageReadersByFormatName("gif").next();
ImageInputStream ciis = ImageIO.createImageInputStream(new File("house2.gif"));
reader.setInput(ciis, false);
int noi = reader.getNumImages(true);
BufferedImage master = null;
for (int i = 0; i < noi; i++) {
BufferedImage image = reader.read(i);
IIOMetadata metadata = reader.getImageMetadata(i);
Node tree = metadata.getAsTree("javax_imageio_gif_image_1.0");
NodeList children = tree.getChildNodes();
for (int j = 0; j < children.getLength(); j++) {
Node nodeItem = children.item(j);
if(nodeItem.getNodeName().equals("ImageDescriptor")){
Map<String, Integer> imageAttr = new HashMap<String, Integer>();
for (int k = 0; k < imageatt.length; k++) {
NamedNodeMap attr = nodeItem.getAttributes();
Node attnode = attr.getNamedItem(imageatt[k]);
imageAttr.put(imageatt[k], Integer.valueOf(attnode.getNodeValue()));
}
if(i==0){
master = new BufferedImage(imageAttr.get("imageWidth"), imageAttr.get("imageHeight"), BufferedImage.TYPE_INT_ARGB);
}
master.getGraphics().drawImage(image, imageAttr.get("imageLeftPosition"), imageAttr.get("imageTopPosition"), null);
}
}
ImageIO.write(master, "GIF", new File( i + ".gif"));
}
} catch (IOException e) {
e.printStackTrace();
}
None of the answers here are correct and suitable for animation. There are many problems in each solution so I wrote something that actually works with all gif files. For instance, this takes into account the actual width and height of the image instead of taking the width and height of the first frame assuming it will fill the entire canvas, no, unfortunately it's not that simple. Second, this doesn't leave any transparent pickles. Third, this takes into account disposal Methods. Fourth, this gives you delays between frames (* 10 if you want to use it in Thread.sleep()).
private ImageFrame[] readGif(InputStream stream) throws IOException{
ArrayList<ImageFrame> frames = new ArrayList<ImageFrame>(2);
ImageReader reader = (ImageReader) ImageIO.getImageReadersByFormatName("gif").next();
reader.setInput(ImageIO.createImageInputStream(stream));
int lastx = 0;
int lasty = 0;
int width = -1;
int height = -1;
IIOMetadata metadata = reader.getStreamMetadata();
Color backgroundColor = null;
if(metadata != null) {
IIOMetadataNode globalRoot = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
NodeList globalColorTable = globalRoot.getElementsByTagName("GlobalColorTable");
NodeList globalScreeDescriptor = globalRoot.getElementsByTagName("LogicalScreenDescriptor");
if (globalScreeDescriptor != null && globalScreeDescriptor.getLength() > 0){
IIOMetadataNode screenDescriptor = (IIOMetadataNode) globalScreeDescriptor.item(0);
if (screenDescriptor != null){
width = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenWidth"));
height = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenHeight"));
}
}
if (globalColorTable != null && globalColorTable.getLength() > 0){
IIOMetadataNode colorTable = (IIOMetadataNode) globalColorTable.item(0);
if (colorTable != null) {
String bgIndex = colorTable.getAttribute("backgroundColorIndex");
IIOMetadataNode colorEntry = (IIOMetadataNode) colorTable.getFirstChild();
while (colorEntry != null) {
if (colorEntry.getAttribute("index").equals(bgIndex)) {
int red = Integer.parseInt(colorEntry.getAttribute("red"));
int green = Integer.parseInt(colorEntry.getAttribute("green"));
int blue = Integer.parseInt(colorEntry.getAttribute("blue"));
backgroundColor = new Color(red, green, blue);
break;
}
colorEntry = (IIOMetadataNode) colorEntry.getNextSibling();
}
}
}
}
BufferedImage master = null;
boolean hasBackround = false;
for (int frameIndex = 0;; frameIndex++) {
BufferedImage image;
try{
image = reader.read(frameIndex);
}catch (IndexOutOfBoundsException io){
break;
}
if (width == -1 || height == -1){
width = image.getWidth();
height = image.getHeight();
}
IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(frameIndex).getAsTree("javax_imageio_gif_image_1.0");
IIOMetadataNode gce = (IIOMetadataNode) root.getElementsByTagName("GraphicControlExtension").item(0);
NodeList children = root.getChildNodes();
int delay = Integer.valueOf(gce.getAttribute("delayTime"));
String disposal = gce.getAttribute("disposalMethod");
if (master == null){
master = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
master.createGraphics().setColor(backgroundColor);
master.createGraphics().fillRect(0, 0, master.getWidth(), master.getHeight());
hasBackround = image.getWidth() == width && image.getHeight() == height;
master.createGraphics().drawImage(image, 0, 0, null);
}else{
int x = 0;
int y = 0;
for (int nodeIndex = 0; nodeIndex < children.getLength(); nodeIndex++){
Node nodeItem = children.item(nodeIndex);
if (nodeItem.getNodeName().equals("ImageDescriptor")){
NamedNodeMap map = nodeItem.getAttributes();
x = Integer.valueOf(map.getNamedItem("imageLeftPosition").getNodeValue());
y = Integer.valueOf(map.getNamedItem("imageTopPosition").getNodeValue());
}
}
if (disposal.equals("restoreToPrevious")){
BufferedImage from = null;
for (int i = frameIndex - 1; i >= 0; i--){
if (!frames.get(i).getDisposal().equals("restoreToPrevious") || frameIndex == 0){
from = frames.get(i).getImage();
break;
}
}
{
ColorModel model = from.getColorModel();
boolean alpha = from.isAlphaPremultiplied();
WritableRaster raster = from.copyData(null);
master = new BufferedImage(model, raster, alpha, null);
}
}else if (disposal.equals("restoreToBackgroundColor") && backgroundColor != null){
if (!hasBackround || frameIndex > 1){
master.createGraphics().fillRect(lastx, lasty, frames.get(frameIndex - 1).getWidth(), frames.get(frameIndex - 1).getHeight());
}
}
master.createGraphics().drawImage(image, x, y, null);
lastx = x;
lasty = y;
}
{
BufferedImage copy;
{
ColorModel model = master.getColorModel();
boolean alpha = master.isAlphaPremultiplied();
WritableRaster raster = master.copyData(null);
copy = new BufferedImage(model, raster, alpha, null);
}
frames.add(new ImageFrame(copy, delay, disposal, image.getWidth(), image.getHeight()));
}
master.flush();
}
reader.dispose();
return frames.toArray(new ImageFrame[frames.size()]);
}
And the ImageFrame class:
import java.awt.image.BufferedImage;
public class ImageFrame {
private final int delay;
private final BufferedImage image;
private final String disposal;
private final int width, height;
public ImageFrame (BufferedImage image, int delay, String disposal, int width, int height){
this.image = image;
this.delay = delay;
this.disposal = disposal;
this.width = width;
this.height = height;
}
public ImageFrame (BufferedImage image){
this.image = image;
this.delay = -1;
this.disposal = null;
this.width = -1;
this.height = -1;
}
public BufferedImage getImage() {
return image;
}
public int getDelay() {
return delay;
}
public String getDisposal() {
return disposal;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
Right, I have never done anything even slightly like this before, but a bit of Googling and fiddling in Java got me this:
public ArrayList<BufferedImage> getFrames(File gif) throws IOException{
ArrayList<BufferedImage> frames = new ArrayList<BufferedImage>();
ImageReader ir = new GIFImageReader(new GIFImageReaderSpi());
ir.setInput(ImageIO.createImageInputStream(gif));
for(int i = 0; i < ir.getNumImages(true); i++)
frames.add(ir.getRawImageType(i).createBufferedImage(ir.getWidth(i), ir.getHeight(i)));
return frames;
}
Edit: see Ansel Zandegran's modification to my answer.
To split an animated GIF into separate BufferedImage frames:
try {
ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
File input = new File("input.gif");
ImageInputStream stream = ImageIO.createImageInputStream(input);
reader.setInput(stream);
int count = reader.getNumImages(true);
for (int index = 0; index < count; index++) {
BufferedImage frame = reader.read(index);
// Here you go
}
} catch (IOException ex) {
// An I/O problem has occurred
}
Alex's answer covers most cases, but it does have a couple of problems. It doesn't handle transparency correctly (at least according to common convention) and it is applying the current frame's disposal method to the previous frame which is incorrect. Here's a version that does handle those cases correctly:
private ImageFrame[] readGIF(ImageReader reader) throws IOException {
ArrayList<ImageFrame> frames = new ArrayList<ImageFrame>(2);
int width = -1;
int height = -1;
IIOMetadata metadata = reader.getStreamMetadata();
if (metadata != null) {
IIOMetadataNode globalRoot = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
NodeList globalScreenDescriptor = globalRoot.getElementsByTagName("LogicalScreenDescriptor");
if (globalScreenDescriptor != null && globalScreenDescriptor.getLength() > 0) {
IIOMetadataNode screenDescriptor = (IIOMetadataNode) globalScreenDescriptor.item(0);
if (screenDescriptor != null) {
width = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenWidth"));
height = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenHeight"));
}
}
}
BufferedImage master = null;
Graphics2D masterGraphics = null;
for (int frameIndex = 0;; frameIndex++) {
BufferedImage image;
try {
image = reader.read(frameIndex);
} catch (IndexOutOfBoundsException io) {
break;
}
if (width == -1 || height == -1) {
width = image.getWidth();
height = image.getHeight();
}
IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(frameIndex).getAsTree("javax_imageio_gif_image_1.0");
IIOMetadataNode gce = (IIOMetadataNode) root.getElementsByTagName("GraphicControlExtension").item(0);
int delay = Integer.valueOf(gce.getAttribute("delayTime"));
String disposal = gce.getAttribute("disposalMethod");
int x = 0;
int y = 0;
if (master == null) {
master = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
masterGraphics = master.createGraphics();
masterGraphics.setBackground(new Color(0, 0, 0, 0));
} else {
NodeList children = root.getChildNodes();
for (int nodeIndex = 0; nodeIndex < children.getLength(); nodeIndex++) {
Node nodeItem = children.item(nodeIndex);
if (nodeItem.getNodeName().equals("ImageDescriptor")) {
NamedNodeMap map = nodeItem.getAttributes();
x = Integer.valueOf(map.getNamedItem("imageLeftPosition").getNodeValue());
y = Integer.valueOf(map.getNamedItem("imageTopPosition").getNodeValue());
}
}
}
masterGraphics.drawImage(image, x, y, null);
BufferedImage copy = new BufferedImage(master.getColorModel(), master.copyData(null), master.isAlphaPremultiplied(), null);
frames.add(new ImageFrame(copy, delay, disposal));
if (disposal.equals("restoreToPrevious")) {
BufferedImage from = null;
for (int i = frameIndex - 1; i >= 0; i--) {
if (!frames.get(i).getDisposal().equals("restoreToPrevious") || frameIndex == 0) {
from = frames.get(i).getImage();
break;
}
}
master = new BufferedImage(from.getColorModel(), from.copyData(null), from.isAlphaPremultiplied(), null);
masterGraphics = master.createGraphics();
masterGraphics.setBackground(new Color(0, 0, 0, 0));
} else if (disposal.equals("restoreToBackgroundColor")) {
masterGraphics.clearRect(x, y, image.getWidth(), image.getHeight());
}
}
reader.dispose();
return frames.toArray(new ImageFrame[frames.size()]);
}
private class ImageFrame {
private final int delay;
private final BufferedImage image;
private final String disposal;
public ImageFrame(BufferedImage image, int delay, String disposal) {
this.image = image;
this.delay = delay;
this.disposal = disposal;
}
public BufferedImage getImage() {
return image;
}
public int getDelay() {
return delay;
}
public String getDisposal() {
return disposal;
}
}
There is a good description of how GIF animations work in this ImageMagick tutorial.
I wrote a GIF image decoder on my own and released it under the Apache License 2.0 on GitHub. You can download it here: https://github.com/DhyanB/Open-Imaging. Example usage:
void example(final byte[] data) throws Exception {
final GifImage gif = GifDecoder .read(data);
final int width = gif.getWidth();
final int height = gif.getHeight();
final int background = gif.getBackgroundColor();
final int frameCount = gif.getFrameCount();
for (int i = 0; i < frameCount; i++) {
final BufferedImage img = gif.getFrame(i);
final int delay = gif.getDelay(i);
ImageIO.write(img, "png", new File(OUTPATH + "frame_" + i + ".png"));
}
}
The decoder supports GIF87a, GIF89a, animation, transparency and interlacing. Frames will have the width and height of the image itself and be placed on the correct position on the canvas. It respects frame transparency and disposal methods. Checkout the project description for more details such as the handling of background colors.
Additionally, the decoder doesn't suffer from this ImageIO bug: ArrayIndexOutOfBoundsException: 4096 while reading gif file.
I'd be happy to get some feedback. I've been testing with a representive set of images, however, some real field testing would be good.
Using c24w's solution, replace:
frames.add(ir.getRawImageType(i).createBufferedImage(ir.getWidth(i), ir.getHeight(i)));
With:
frames.add(ir.read(i));

Categories