jai-imageio-core
  1. jai-imageio-core
  2. JAI_IMAGEIO_CORE-194

ArrayIndexOutOfBoundsException at TIFFFaxCompressor.addEOFB

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.1
    • Fix Version/s: None
    • Component/s: implementation
    • Labels:
      None

      Description

      Writing some black and white images to TIFF using fax compression results in the following exception:

      java.lang.ArrayIndexOutOfBoundsException: 55
      	at com.sun.media.imageioimpl.plugins.tiff.TIFFFaxCompressor.addEOFB(TIFFFaxCompressor.java:481)
      	at com.sun.media.imageioimpl.plugins.tiff.TIFFT6Compressor.encodeT6(TIFFT6Compressor.java:161)
      	at com.sun.media.imageioimpl.plugins.tiff.TIFFT6Compressor.encode(TIFFT6Compressor.java:204)
      	at com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriter.writeTile(TIFFImageWriter.java:1814)
      	at com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriter.write(TIFFImageWriter.java:2686)
      	at com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriter.write(TIFFImageWriter.java:2417)
      	at com.nuix.integration.TestTrash.testPngToTiff(TestTrash.java:88)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
      	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
      	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
      	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
      	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
      	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
      

      Test case:

      @Test
      public void testPngToTiff() throws Exception
      {
          BufferedImage image = ImageIO.read(new File("z:\\Data\\out7.png"));
       
          try (OutputStream fileOutput = new FileOutputStream(new File("z:\\Data\\out1.tiff"));
               ImageOutputStream output = ImageIO.createImageOutputStream(fileOutput))
          {
              ImageWriter writer = new TIFFImageWriterSpi().createWriterInstance();
              writer.setOutput(output);
              ImageWriteParam parameters = writer.getDefaultWriteParam();
              parameters.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
              parameters.setCompressionType("CCITT T.6");
              IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(parameters);
              IIOMetadata imageMetadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), parameters);
              writer.write(streamMetadata, new IIOImage(image, null, imageMetadata), parameters);
              writer.dispose();
          }
      

      Test image is attached.

        Activity

        Hide
        trejkaz added a comment -

        Since I can't find the attach files button, here's the attachment as base 64:

        iVBORw0KGgoAAAANSUhEUgAAAEgAAAAIAQAAAAByzoSGAAAAF0lEQVR42mNYBQMMoTDAQKzYKxhAiAEA+H8mHaP7QSQAAAAASUVORK5CYII=
        
        Show
        trejkaz added a comment - Since I can't find the attach files button, here's the attachment as base 64: iVBORw0KGgoAAAANSUhEUgAAAEgAAAAIAQAAAAByzoSGAAAAF0lEQVR42mNYBQMMoTDAQKzYKxhAiAEA+H8mHaP7QSQAAAAASUVORK5CYII=
        Hide
        trejkaz added a comment - - edited

        Shorter reproduction after seeing what's actually on the stack:

        // passes:
        @Test
        public void testTiffT6Compressor_64() throws Exception {
            byte[] uncompressed = { 85,85,85,85,85,85,85,85 };
            TIFFT6Compressor compressor = new TIFFT6Compressor();
            compressor.setStream(ImageIO.createImageOutputStream(new ByteArrayOutputStream()); //TODO verify results
            compressor.encode(uncompressed, 0, 64, 1, new int[] { 1 }, 8);
        }
        
        // fails:
        @Test
        public void testTiffT6Compressor_72() throws Exception {
            byte[] uncompressed = { 85,85,85,85,85,85,85,85,85 };
            TIFFT6Compressor compressor = new TIFFT6Compressor();
            compressor.setStream(ImageIO.createImageOutputStream(new ByteArrayOutputStream()); //TODO verify results
            compressor.encode(uncompressed, 0, 72, 1, new int[] { 1 }, 9);
        }
        
        Show
        trejkaz added a comment - - edited Shorter reproduction after seeing what's actually on the stack: // passes: @Test public void testTiffT6Compressor_64() throws Exception { byte [] uncompressed = { 85,85,85,85,85,85,85,85 }; TIFFT6Compressor compressor = new TIFFT6Compressor(); compressor.setStream(ImageIO.createImageOutputStream( new ByteArrayOutputStream()); //TODO verify results compressor.encode(uncompressed, 0, 64, 1, new int [] { 1 }, 8); } // fails: @Test public void testTiffT6Compressor_72() throws Exception { byte [] uncompressed = { 85,85,85,85,85,85,85,85,85 }; TIFFT6Compressor compressor = new TIFFT6Compressor(); compressor.setStream(ImageIO.createImageOutputStream( new ByteArrayOutputStream()); //TODO verify results compressor.encode(uncompressed, 0, 72, 1, new int [] { 1 }, 9); }
        Hide
        trejkaz added a comment - - edited

        What I'm seeing in the debugger is a repeating pattern of bytes in the buffer:

        buf[0] = 35
        buf[1] = -94
        buf[2] = 58
        buf[3] = 35
        ...
        

        Stepping through, it looks like the amount of space used is 12 bits for each pair of pixels. The code allocating the buffer has assumed the worst case is 9, so I guess that is the bug.

        Show
        trejkaz added a comment - - edited What I'm seeing in the debugger is a repeating pattern of bytes in the buffer: buf[0] = 35 buf[1] = -94 buf[2] = 58 buf[3] = 35 ... Stepping through, it looks like the amount of space used is 12 bits for each pair of pixels. The code allocating the buffer has assumed the worst case is 9, so I guess that is the bug.
        Hide
        trejkaz added a comment -

        Proposed patch (again, can't find the attachment button):

        Index: src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT4Compressor.java
        ===================================================================
        --- src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT4Compressor.java	(revision 29635)
        +++ src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT4Compressor.java	(revision 29636)
        @@ -249,14 +249,14 @@
         
                 // This initial buffer size is based on an alternating 1-0
                 // pattern generating the most bits when converted to code
        -        // words: 9 bits out for each pair of bits in. So the number
        -        // of bit pairs is determined, multiplied by 9, converted to
        +        // words: 12 bits out for each pair of bits in. So the number
        +        // of bit pairs is determined, multiplied by 12, converted to
                 // bytes, and a ceil() is taken to account for fill bits at the
                 // end of each line.  The "2" addend accounts for the case
                 // of the pattern beginning with black.  The buffer is intended
                 // to hold only a single row.
         
        -        int maxBits = 9*((width + 1)/2) + 2;
        +        int maxBits = 12*((width + 1)/2) + 2;
                 int bufSize = (maxBits + 7)/8;
         
                 // Calculate the maximum row as the G3-1D size plus the EOL,
        Index: src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT6Compressor.java
        ===================================================================
        --- src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT6Compressor.java	(revision 29635)
        +++ src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT6Compressor.java	(revision 29636)
        @@ -196,7 +196,7 @@
                 }
                  
                 // See comment in TIFFT4Compressor
        -        int maxBits = 9*((width + 1)/2) + 2;
        +        int maxBits = 12*((width + 1)/2) + 2;
                 int bufSize = (maxBits + 7)/8;
                 bufSize = height*(bufSize + 2) + 12;
         
        
        Show
        trejkaz added a comment - Proposed patch (again, can't find the attachment button): Index: src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT4Compressor.java =================================================================== --- src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT4Compressor.java (revision 29635) +++ src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT4Compressor.java (revision 29636) @@ -249,14 +249,14 @@ // This initial buffer size is based on an alternating 1-0 // pattern generating the most bits when converted to code - // words: 9 bits out for each pair of bits in. So the number - // of bit pairs is determined, multiplied by 9, converted to + // words: 12 bits out for each pair of bits in. So the number + // of bit pairs is determined, multiplied by 12, converted to // bytes, and a ceil() is taken to account for fill bits at the // end of each line. The "2" addend accounts for the case // of the pattern beginning with black. The buffer is intended // to hold only a single row. - int maxBits = 9*((width + 1)/2) + 2; + int maxBits = 12*((width + 1)/2) + 2; int bufSize = (maxBits + 7)/8; // Calculate the maximum row as the G3-1D size plus the EOL, Index: src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT6Compressor.java =================================================================== --- src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT6Compressor.java (revision 29635) +++ src/share/classes/com/sun/media/imageioimpl/plugins/tiff/TIFFT6Compressor.java (revision 29636) @@ -196,7 +196,7 @@ } // See comment in TIFFT4Compressor - int maxBits = 9*((width + 1)/2) + 2; + int maxBits = 12*((width + 1)/2) + 2; int bufSize = (maxBits + 7)/8; bufSize = height*(bufSize + 2) + 12;

          People

          • Assignee:
            Unassigned
            Reporter:
            trejkaz
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: