[ome-users] LZW-compression not working for large tiles
Melissa Linkert
melissa at glencoesoftware.com
Thu Aug 2 18:03:44 BST 2012
Hi Matthias,
Thank you very much for reporting this.
> I have developed a small Java-tool which converts a JPEG-image, stored in a NDPI-file, to an OME-TIFF. It also works for images with an edge length larger than 65536 pixels. Therefore, I read the image using tiles.
I would be very interested in knowing how you are reading the images
from the NDPI file. Are you using a particular library for reading the
JPEG data?
> With large JPEG-files the automatically calculated tile size can reach 3968x3968 pixels (or maybe even more). I use the writer-methods provided by Bio-Formats to save the image as a tiled OME-TIFF. The problem: When using the provided LZW-compression, a NegativeArraySizeException exception is thrown by the LZWCodec-class when the tile size reaches a certain level. I think the reason for this exception is an integer-overflow in the LZWCodec-class, when calculating the size of the output buffer in the following line (at the beginning of the compress-method):
You're absolutely right - the size of that buffer is being calculated
incorrectly. I have put in a fix here:
https://github.com/melissalinkert/bioformats/commit/0966339a3a5ba930f43735bb540069d046d6d616
which seems to work correctly with your test case and various other tests
that I have done here. Note that new builds are not yet available, but you
can try it out by building from this branch:
https://github.com/melissalinkert/bioformats/tree/sprint1.2-bug-fixes
Regards,
-Melissa
On Thu, Aug 02, 2012 at 04:46:19PM +0200, Matthias Baldauf wrote:
> Hello,
>
> I have developed a small Java-tool which converts a JPEG-image, stored in a NDPI-file, to an OME-TIFF. It also works for images with an edge length larger than 65536 pixels. Therefore, I read the image using tiles. With large JPEG-files the automatically calculated tile size can reach 3968x3968 pixels (or maybe even more). I use the writer-methods provided by Bio-Formats to save the image as a tiled OME-TIFF. The problem: When using the provided LZW-compression, a NegativeArraySizeException exception is thrown by the LZWCodec-class when the tile size reaches a certain level. I think the reason for this exception is an integer-overflow in the LZWCodec-class, when calculating the size of the output buffer in the following line (at the beginning of the compress-method):
>
> byte[] output = new byte[(input.length * 141) / 100 + 3];
>
> Thrown exception:
> Exception in thread "main" java.lang.NegativeArraySizeException
> at loci.formats.codec.LZWCodec.compress(LZWCodec.java:117)
> at loci.formats.tiff.TiffCompression.compress(TiffCompression.java:328)
> at loci.formats.tiff.TiffSaver.writeImage(TiffSaver.java:371)
> at loci.formats.tiff.TiffSaver.writeImage(TiffSaver.java:265)
> at loci.formats.out.TiffWriter.saveBytes(TiffWriter.java:191)
> at loci.formats.out.OMETiffWriter.saveBytes(OMETiffWriter.java:197)
> at LZWTest.main(LZWTest.java:63)
>
> I am using the latest trunk build of Bio-Formats.
>
> Below, I added an example-code (LZWTest.java) to reproduce this exception.
> Example settings:
> Tile size: 2250 x 2250 pixels, 3 components, 8bit per component (= works)
> Tile size: 2300 x 2300 pixels, 3 components, 8bit per component (= NegativeArraySizeException)
>
> Thanks in advance for having a look at it!
>
> Regards,
> Matthias
>
>
> ------------------------------------------------
> LZWTest.java
> ------------------------------------------------
> import loci.common.services.ServiceFactory;
> import loci.formats.FormatTools;
> import loci.formats.MetadataTools;
> import loci.formats.meta.IMetadata;
> import loci.formats.out.OMETiffWriter;
> import loci.formats.out.TiffWriter;
> import loci.formats.services.OMEXMLService;
> import loci.formats.tiff.IFD;
> import loci.formats.tiff.TiffCompression;
>
> public class LZWTest {
>
> static final int PIXEL_TYPE = FormatTools.UINT8;
> static final int COMPONENTS = 3;
> static final int w = 2300;
> static final int h = 2300;
>
> public static void main(String[] args) throws Exception {
> if (args.length < 1) {
> System.out.println("Please specify an output file name.");
> System.exit(1);
> }
> String id = args[0];
>
> // create blank image
> System.out.println("Creating random image...");
> byte[] img = new byte[w * h * COMPONENTS * FormatTools.getBytesPerPixel(PIXEL_TYPE)];
> System.out.println("Image Size in Bytes: " + img.length);
>
> /*
> * Wrong calculated size of output buffer because of integer overflow
> * Taken from LZWCodec.java - compress-method
> */
> System.out.println("Wrong LZW Buffer Size: " + (img.length * 141) / 100 + 3);
>
> // This would be the right size for the output buffer
> System.out.println("Right LZW Buffer Size: " + img.length * 1.41 + 3);
>
> // fill image with random data
> for (int i=0; i<img.length; i++) img[i] = (byte) (256 * Math.random());
>
> // create metadata object with minimum required metadata fields
> System.out.println("Populating metadata...");
> ServiceFactory factory = new ServiceFactory();
> OMEXMLService service = factory.getInstance(OMEXMLService.class);
> IMetadata meta = service.createOMEXMLMetadata();
> MetadataTools.populateMetadata(meta, 0, null, false, "XYZCT", FormatTools.getPixelTypeString(PIXEL_TYPE), w, h, 1, COMPONENTS, 1, COMPONENTS);
>
> // Set up the writer for OME-TIFF
> TiffWriter writer = new OMETiffWriter();
> writer.setMetadataRetrieve(meta);
> writer.setInterleaved(Boolean.TRUE);
> writer.setBigTiff(false);
> writer.setId(id);
>
> // Set up IFD for creating a tiled OME-TIFF
> IFD ifd = new IFD();
> ifd.put(IFD.TILE_WIDTH, w);
> ifd.put(IFD.TILE_LENGTH, h);
> ifd.put(IFD.COMPRESSION, TiffCompression.LZW.getCode());
>
> // Save tile
> writer.saveBytes(0, img, ifd, 0, 0, w, h);
>
> writer.close();
> }
>
> }
>
> _______________________________________________
> ome-users mailing list
> ome-users at lists.openmicroscopy.org.uk
> http://lists.openmicroscopy.org.uk/mailman/listinfo/ome-users
More information about the ome-users
mailing list