commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Gary Lucas (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (IMAGING-69) Streamlined TIFF strip reader reduces load time by a factor of 5
Date Thu, 31 May 2012 12:26:23 GMT

     [ https://issues.apache.org/jira/browse/IMAGING-69?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Gary Lucas updated IMAGING-69:
------------------------------

    Attachment: ApacheImagingTrackerItem69_May_30_2012.patch

Damjan Jovanovic asked some questions regarding byte-order issues which led to this patch.
 In a TIFF file, a pixel is represented by a set of "samples". For example, in a RGB model,
the samples are the red, green, and blue values. The speed enhancements I proposed only worked
when the samples were exactly one byte in size (which is usually the case, but there can be
exceptions).  So I've added logic to check for that condition.

Once again, this patch supercedes my earlier submissions.
                
> Streamlined TIFF strip reader reduces load time by a factor of 5
> ----------------------------------------------------------------
>
>                 Key: IMAGING-69
>                 URL: https://issues.apache.org/jira/browse/IMAGING-69
>             Project: Apache Commons Imaging
>          Issue Type: Improvement
>            Reporter: Gary Lucas
>         Attachments: ApacheImagingTrackerItem69_May_30_2012.patch, ApacheImagingTrackerItem69_May_9_2012.patch,
Sanselan-58-TiffStripReaderSpeed.patch, Tracker_Item_58_22_Apr_2012.patch
>
>   Original Estimate: 1h
>  Remaining Estimate: 1h
>
> 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.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Mime
View raw message