[ome-users] LZW-compression not working for large tiles

Matthias Baldauf matthias.baldauf at umit.at
Thu Aug 2 15:46:19 BST 2012


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();
  }

}

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openmicroscopy.org.uk/pipermail/ome-users/attachments/20120802/7ad039b3/attachment.html>


More information about the ome-users mailing list