Uploaded image for project: 'Commons Imaging'
  1. Commons Imaging
  2. IMAGING-69

Streamlined TIFF strip reader reduces load time by a factor of 5

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Major
    • Resolution: Fixed
    • None
    • 1.0-alpha1
    • None
    • None

    Description

      Testing reveals that streamlining the DataReaderStrip.java operations for 8 and 24 bit-per-pixel TIFF images reduces the TIFF file load time by a factor of 5.

      For each pixel in images of these types, the interpretStrip() method of DataReaderStrip makes calls to a generic bit extractor using its getSamplesAsBytes() method. Internally, this method simply copies the requisite number of bytes (8 or 24), but it executes a lot of conditional statements to do so. Under most architectures, conditionals tend to take 2 to 3 times as long to execute as simple arithmetic statements, so this approach is expensive (especially since an image may contain millions of pixels). While the implementation is very generic, the majority of TIFF files out there appear to fall into two simple categories. By implementing specialized code for these two cases, the loading time for TIFF images is dramatically reduced.

      The following snippet shows the code I used for testing. It was added right at the beginning of the interpretStrip() method.

      // Oct 2011 changes.
      // The general case decoder is based on the idea of using a
      // generic bit-reader to unpack the number of bytes that are
      // needed. Although it is efficiently implemented, it does
      // require performing at least three conditional branches per sample
      // extracted (and often more). This change attempts to bypass that
      // overhead by implementing specialized blocks of extraction code
      // for commonly used 8 bitsPerPixel and 24 bitsPerPixel cases.
      // In other cases, it will simply fall through to the original code.
      // note that when promoting a byte to an integer, it is necessary
      // to mask it with 0xff because the Java byte type is signed
      // an this implementation requires an unsigned value
      if(x>=width)

      { // this may not be required. it was coded based on the // original implementation. But looking at the TIFF 6.0 spec, // it looks like the rows always evenly fill out the strip, // so there should never be a partial row in a strip and x // should not be anything except zero. x = 0; y++; }

      if(y>=height)

      { // we check it once before starting, so that we don't have // to check it redundantly for each pixel return; }

      if(predictor==-1 && this.bitsPerPixel==8)
      {
      int [] samples = new int[1];
      for(int i=0; i<pixels_per_strip; i++)
      {
      samples[0] = bytes[i]&0x000000ff;
      photometricInterpreter.interpretPixel(bi, samples, x, y);
      x++;
      if(x>=width)

      { x = 0; y++; if(y>=height) return; // any remaining bytes are not needed }
      }
      return;
      }
      else if(predictor==-1 && this.bitsPerPixel==24)
      {
      int [] samples = new int[3];
      int k = 0;
      for(int i=0; i<pixels_per_strip; i++)
      {
      samples[0] = bytes[k++]&0x000000ff;
      samples[1] = bytes[k++]&0x000000ff;
      samples[2] = bytes[k++]&0x000000ff;
      photometricInterpreter.interpretPixel(bi, samples, x, y);
      x++;
      if(x>=width)
      { x = 0; y++; if(y>=height) return; // any remaining bytes are not needed }

      }
      return;
      }

      // original code before Oct 2011 modification
      ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
      BitInputStream bis = new BitInputStream(bais);
      etc.

      Attachments

        1. Sanselan-58-TiffStripReaderSpeed.patch
          3 kB
          Gary Lucas
        2. Tracker_Item_58_22_Apr_2012.patch
          5 kB
          Gary Lucas
        3. ApacheImagingTrackerItem69_May_9_2012.patch
          9 kB
          Gary Lucas
        4. ApacheImagingTrackerItem69_May_30_2012.patch
          10 kB
          Gary Lucas

        Activity

          People

            Unassigned Unassigned
            gwlucas Gary Lucas
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - 1h
                1h
                Remaining:
                Remaining Estimate - 1h
                1h
                Logged:
                Time Spent - Not Specified
                Not Specified