2

I've to make a parallel image processing script in java, the idea is to divide the images into tiles of any size, process them, and reassemble the final image.

For now i've created a function:

public static BufferedImage readImg (String path, int startx, int starty, int w, int h)

that returns the region of an image as BufferedImage, then i'll process it and i want to place that region in the correct position of the final image.

So i've tried to make a function writeImg that uses replacePixels method to write just in the correct position without loading the whole image into memory:

public static void writeImg (String path, int startx, int starty, BufferedImage image){
    File output = new File(path);
    ImageOutputStream ios = null;
    try {
        ios = ImageIO.createImageOutputStream(output);
    } catch (IOException e){
        e.printStackTrace();
    }
    Iterator iter = ImageIO.getImageWritersByFormatName("JPEG");
    ImageWriter writer = (ImageWriter)iter.next();
    writer.setOutput(ios);

    try{
        if(writer.canReplacePixels(0)){
            System.out.println("True");
        }else{
            System.out.println("False");
        }
    }catch (IOException e) {
        e.printStackTrace();
    }

    ImageWriteParam param = writer.getDefaultWriteParam();
    Point destinationOffset = new Point(startx,starty);
    param.setDestinationOffset(destinationOffset);
    try {
        writer.replacePixels(image, param);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

The problem is that canReplacePixels is always set as false, and i've no idea what should i use to do that.

The images can be very big so it's impossible to load the whole image in memory as it will cause a OutOfMemory exception.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Alex88
  • 21
  • 1

1 Answers1

3

As long as you are fine with an 24 bit PNG file as output I have a working solution for you (under GPL license):

The class PngXxlWriter allows to write PNG files "line by line". That means that you can write an image of 10000x10000 (width * height) pixels in lines of e.g. 256 pixels (10000 * 256).

Usually this reduces the memory usage down to a level which is practically.

All required classes can be found here:

PngXxlWriter is the main class. By calling its method writeTileLine you can add a new line to the output image.

https://sourceforge.net/p/mobac/code/HEAD/tree/trunk/MOBAC/src/main/java/mobac/utilities/imageio/

Robert
  • 39,162
  • 17
  • 99
  • 152
  • Wow fast answer, well that would be fine, just another thing, any idea why replacePixels won't work with a jpeg image? Any other way for doing that in other languages or other way? It remains the problem if the line is still big enough to don't fit in memory of vjm. – Alex88 Mar 04 '11 at 16:34
  • Also, you need to supply it lines in order, that's improbable that parallel threads will finish in order. – Alex88 Mar 04 '11 at 16:46
  • My guess is that replace pixels doesn't work due to JPEG being lossy compression. Have you tried doing this with PNG? Or any other image format? – troutinator Mar 04 '11 at 18:24
  • @Alex88: doing it on JPEG pictures would be a huge headaches, if possible at all, due to how JPEGs are encoded. Regarding supplying the lines in order, then simply spawn at max *n* threads (anyway having *n* much bigger than the number of cores is non-sense) as to not consume too much memory and when one "square" is processed, put in in a PriorityQueue. Only dequeue when you've got the correct element available. Rinse and repeat. – SyntaxT3rr0r Mar 04 '11 at 18:33
  • @SyntaxT3rr0r no i'll do that on a cluster of machines with the map reduce framework, not on a single pc. – Alex88 Mar 04 '11 at 23:44