Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak in java ImageIO.read()

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.

like image 829
ThePrince Avatar asked Oct 07 '13 20:10

ThePrince


People also ask

What is ImageIO read?

Imageio is a Python library that provides an easy interface to read and write a wide range of image data, including animated images, volumetric data, and scientific formats. It is cross-platform, runs on Python 3.5+, and is easy to install.

What is ImageIO in Java?

ImageIO. A class containing static convenience methods for locating ImageReader s and ImageWriter s, and performing simple encoding and decoding. ImageReader. An abstract superclass for parsing and decoding of images.

What kind of exception does the ImageIO class cause?

imageio. ImageIO. write and that failure is causing a null pointer exception.

What does ImageIO write do?

The ImageIO. write method calls the code that implements PNG writing a “PNG writer plug-in”. The term plug-in is used since Image I/O is extensible and can support a wide range of formats. But the following standard image format plugins : JPEG, PNG, GIF, BMP and WBMP are always be present.


1 Answers

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();
        }
    }
}
like image 50
Jibeex Avatar answered Oct 05 '22 23:10

Jibeex