Work around size limit of exported image formats (PNG/JPG/PPM)

Issue #383 open
Robert Leach created an issue

USE CASE: WHAT DO YOU WANT TO DO?

Export large matrices at higher resolution.

STEPS TO REPRODUCE AN ISSUE (OR TRIGGER A NEW FEATURE)

  1. Open a very large matrix file
  2. Export a PNG of the entire matrix

CURRENT BEHAVIOR

There are 2 types of impediments to exporting large matrices: one is a memory limitation and the other is a limitation imposed by the use of the BufferedImage class for handling the export.

A large will produce an out of memory error either because the process simply didn't have enough memory or because the number of points in the image is larger than the limit imposed by the BufferedImage class (which is defined as Integer.MAX_VALUE). This is stored in ExportHandler as a static class variable called "MAX_IMAGE_SIZE".

Various options which will produce images that are too large (based on this limit) are grayed out if they will exceed this limit. A matrix that will end up generating an image that is too large, given certain options such as aspect ratio or region, is prevented from being exported in PNG/JPG/PPM formats using the following methods: getOversizedRegions, getOversizedAspects, and isOversized. Tooltips that say "Too big for PNG/JPG/PPM export" are added to the grayed out options.

The minimum number of "points" needed per tile to center a tree leaf/branch on said tile and separate the branches from one another is 3 and that is set in ExportHandler as minTileDim, tileHeight, and tileWidth. The number which must be less than Integer.MAX_VALUE is the width times the height (times the points of each tile dimension) - assuming there are no trees. This, a 6k x 6k matrix is composed of this number of points:

6000 * 3 * 6000 * 3 = 324,000,000

Integer.MAX_VALUE = 2,147,483,647

If we want to include enough space for labels with a font size of around 12, tile dimensions would have to be 13 x 13 pixels, and that works out to be:

6000 * 13 * 6000 * 13 = 6,084,000,000

which is larger than Integer.MAX_VALUE.

The error resulting from the size exceeding Integer.MAX_VALUE is different from the memory exceeded error, the former of which is avoided by graying out options.

Both limitations however must be overcome.

EXPECTED BEHAVIOR

The ability to export 6k x 6k matrixes at a high enough resolution to support 12 point font labels (i.e. tile dimensions of 13x13).

DEVELOPERS ONLY SECTION

SUGGESTED CHANGE (Pseudocode optional)

A package called PNGJ exists for exporting a PNG of any size/resolution by stitching together pieces of the image. I think this only works for PNG exports, so either we could use it and get rid of JPG & PPM formats, or we could find a package like it that supports more formats.

FILES AFFECTED (where the changes will be implemented) - developers only

unknown

LEVEL OF EFFORT - developers only

medium

COMMENTS

Just for documentation purposes, this is where I found out about PNGJ, and it talks a little about the root cause of the problem:

http://stackoverflow.com/questions/9089675/creating-huge-bufferedimage

Comments (15)

  1. mohammed faizaan

    Hi @hepcat72 , just a small question on this. Do you know how much memory does it cost to load a 7MegaByte PNG file in a java bufferedImage object? I know that I can write a sample program for this. But if you happen to know then it'll be great.

  2. Robert Leach reporter

    I do not know. The limit I ran into had to do with bufferedImage using Integer.MAX_VALUE or some such thing. I have notes on it somewhere.

  3. Robert Leach reporter

    I have been testing the memory and size limitations a bit since I ran into them while testing your recent PR. It's notable to reference issue #62. I'd done some testing of memory usage for clustering, but it seems as though we can also hit a memory limit during export.

    As I mentioned in the edit of this issue, there are 2 limitations on the size of the exported image: memory and a built-in limitation that an image can have at most Integer.MAX_VALUE "points".

    1. Case 1: 6kx6k, PDF exported with a tile aspect set to "as seen on screen". This used to work on my computer, though it took a long time. However, the master branch currently produces a "damaged" file. No out of memory error is reported. The file size is 5.44Gb - although it should be larger than the 1:1 export of the same region, so I suspect there was a memory issue that somehow did not generate an exception (or report it). The jar file for pull request #126 generates an out of memory error for this scenario: outofmemory-jarerror-masternoerror.png
    2. Case 2: 6kx6k, PDF exported with a tile aspect set to "1:1". The jar file for pull request #126 generates a good PDF but the master version currently generates a bad PDF file, which Adobe Reader complains is "damaged".

    I find this whole issue confusingly inconsistent. I know that when I initially implemented the export feature, the options presented in the export interface reliably worked on my computer, which they no longer do. But regardless, systems with less memory run into out of memory issues and my system no longer reliably produces good images (using the current master). The jar file for pull request #126 at least reports an out of memory error in 1 case and generates a good image in the other.

    I just thought I'd report the results of my testing and comment on my hunches. I don't envy the task of working on this issue.

  4. mohammed faizaan

    I experimented with PNGJ library. There is a limitation to what can be done with the library. Some drawbacks with the PNGJ library are:

    1. There is no graphics object
    2. There is only one method to write into PNG (PngWriter.writeRows()), that writes row-wise (single row at a time). That means you can only write rows and not columns. Ofcourse, we can modify to make it work for column. In our export, We have methods to draw lines (for trees) such graphics.drawPolyLine, graphics.drawLine(), we have methods to fill rectangles such as graphics.fillRectangle(), graphics.drawRectangle(). These methods need to be modified to make them work with PngWriter.writeRows() which is a huge task.

    On a summarized note, We can not use the library easily to resolve this issue. A better solution would be to cut the image into smaller pieces and merge them (which again is a good amount of work).

  5. Robert Leach reporter

    So this issue is going to be much more of an issue once I'm done with the inclusion of labels in the exported image. Text in a PNG greatly increases the resolution requirements. Right now, the tile dimensions are 3x3 pixels. To get a decently rendered font, you have to at least triple that, if not quadruple. And the 6kx6k requirement goal will definitely not be able to be exported. I'd like to be able to make the minimum tile dimension 13 or 15 (odd so that the tree branch is centered well). Just for the matrix, that would be way too big.

    I understand that PNGJ appears insufficient, but we're going to need something in place for the next release. Have you found any alternatives?

  6. Log in to comment