1

Is it actually possible to write a region (small 100x100px) to an image (250k x 250k px) without reading the whole target image? My region is only 100px in square and I like to store it at a certain location in an huge Jpeg. Thanks for your hints, Durin

Theolodis
  • 4,977
  • 3
  • 34
  • 53
Durin
  • 687
  • 1
  • 8
  • 18
  • given that you would have to forgo lossy compression feature of image codecs if you want this, the next thing to ask is if it's ok for you to simply store the raw pixels on disk? if yes, then you can look into hdf file format. it does have transparent compression mechanism but not as good as jpeg etc. i think it's as best as you can get – Zaw Lin Jun 03 '14 at 10:39
  • @Durin: Are you trying to avoid reading the entire image to save memory, CPU (/time) or both? – Harald K Jun 03 '14 at 12:57
  • @haraldK I'm trying to avoid to read the entire target image. It's to huge to load into memory. I'd like to modify parts of it without reading the whole image first. Currently they are stored in jpeg format. – Durin Jun 03 '14 at 13:59
  • @Durin If only memory (Java heap) is a concern, it's possible to use a [`BufferedImage` backed by a memory mapped file](https://github.com/haraldk/TwelveMonkeys/blob/master/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedImageFactory.java), to do the replacement with a minimal amount of heap. It's slow, but might help get around `OutOfMemoryError` situations. – Harald K Jun 04 '14 at 08:23

2 Answers2

3

This is probably not what you are looking for, but I'm adding the answer, should anyone else need a solution. :-)

The ImageIO API does support writing a region into a file. However, this support is format specific, and as already pointed out by other answers, JPEG (and most other compressed formats) is not such a format.

public void replacePixelsTest(BufferedImage replacement) throws IOException {
    // Should point to an existing image, in a format supported (not tested)
    File target = new File("path/to/file.tif");

    // Find writer, use suffix of existing file
    ImageWriter writer = ImageIO.getImageWritersBySuffix(FileUtils.suffix(target)).next(); 
    ImageWriteParam param = writer.getDefaultWriteParam();

    ImageOutputStream output = ImageIO.createImageOutputStream(target);
    writer.setOutput(output);

    // Test if the writer supports replacing pixels
    if (writer.canReplacePixels(0)) {
        // Set the region we want to replace
        writer.prepareReplacePixels(0, new Rectangle(0, 0, 100, 100));

        // Replacement image is clipped against region prepared above
        writer.replacePixels(replacement, param);

        // We're done updating the image
        writer.endReplacePixels();
    }
    else {
        // If the writer don't support it, we're out of luck...
    }

    output.close(); // You probably want this in a finally block, but it clutters the example...
}
Harald K
  • 26,314
  • 7
  • 65
  • 111
1

For a raw format like BMP you would just need to know where to write to.

But JPEG is a (lossy) compressed format. You would have to keep the data coherent with the compression algorithm. So writing something into the middle of the image would require the algorithm to support this. I don't know JPEG in detail, but I don't think this is a feature of it.

Dawnkeeper
  • 2,844
  • 1
  • 25
  • 41