Changeset 5970


Ignore:
Timestamp:
02/26/10 14:33:23 (10 years ago)
Author:
melissa
Message:

Consolidated a lot of pixel unpacking logic. See #466.

Location:
branches/cleanup/components/bio-formats/src/loci/formats/tiff
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/cleanup/components/bio-formats/src/loci/formats/tiff/PhotoInterp.java

    r5969 r5970  
    5353  CIE_LAB(8, "CIELAB", "RGB"), 
    5454  CFA_ARRAY(32803, "Color Filter Array", "RGB"); 
     55 
     56  /** Default luminance values for YCbCr data. */ 
     57  public static final float LUMA_RED = 0.299f; 
     58  public static final float LUMA_GREEN = 0.587f; 
     59  public static final float LUMA_BLUE = 0.114f; 
    5560 
    5661  /** Code for the IFD type in the actual TIFF file. */ 
  • branches/cleanup/components/bio-formats/src/loci/formats/tiff/TiffParser.java

    r5969 r5970  
    705705  /** 
    706706   * Extracts pixel information from the given byte array according to the 
    707    * bits per sample, photometric interpretation, and the specified byte 
    708    * ordering. 
    709    * No error checking is performed. 
    710    * This method is tailored specifically for planar (separated) images. 
    711    */ 
    712   public static void planarUnpack(byte[] samples, int startIndex, byte[] bytes, 
    713     IFD ifd) throws FormatException 
    714   { 
    715     BitBuffer bb = new BitBuffer(bytes); 
    716  
    717     int numBytes = ifd.getBytesPerSample()[0]; 
    718     int realBytes = numBytes; 
    719     if (numBytes == 3) numBytes++; 
    720  
    721     int bitsPerSample = ifd.getBitsPerSample()[0]; 
    722     boolean littleEndian = ifd.isLittleEndian(); 
    723     PhotoInterp photoInterp = ifd.getPhotometricInterpretation(); 
    724  
    725     for (int j=0; j<bytes.length / realBytes; j++) { 
    726       int value = bb.getBits(bitsPerSample); 
    727       if (littleEndian) value = DataTools.swap(value) >> (32 - bitsPerSample); 
    728  
    729       if (photoInterp == PhotoInterp.WHITE_IS_ZERO) { 
    730         value = (int) (Math.pow(2, bitsPerSample) - 1 - value); 
    731       } 
    732       else if (photoInterp == PhotoInterp.CMYK) { 
    733         value = Integer.MAX_VALUE - value; 
    734       } 
    735  
    736       if (numBytes*(startIndex + j) < samples.length) { 
    737         DataTools.unpackBytes(value, samples, numBytes*(startIndex + j), 
    738           numBytes, littleEndian); 
    739       } 
    740     } 
    741   } 
    742  
    743   /** 
    744    * Extracts pixel information from the given byte array according to the 
    745707   * bits per sample, photometric interpretation and color map IFD directory 
    746708   * entry values, and the specified byte ordering. 
     
    750712    IFD ifd) throws FormatException 
    751713  { 
    752     if (ifd.getPlanarConfiguration() == 2) { 
    753       planarUnpack(samples, startIndex, bytes, ifd); 
    754       return; 
    755     } 
     714    boolean planar = ifd.getPlanarConfiguration() == 2; 
    756715 
    757716    TiffCompression compression = ifd.getCompression(); 
     
    761720    int[] bitsPerSample = ifd.getBitsPerSample(); 
    762721    int nChannels = bitsPerSample.length; 
     722 
     723    int sampleCount = (8 * bytes.length) / (nChannels * bitsPerSample[0]); 
     724    if (photoInterp == PhotoInterp.Y_CB_CR) sampleCount *= 3; 
     725    if (planar) { 
     726      sampleCount *= nChannels; 
     727      nChannels = 1; 
     728    } 
     729 
    763730    int nSamples = samples.length / nChannels; 
    764  
    765     int totalBits = 0; 
    766     for (int i=0; i<nChannels; i++) totalBits += bitsPerSample[i]; 
    767     int sampleCount = 8 * bytes.length / totalBits; 
    768     if (photoInterp == PhotoInterp.Y_CB_CR) sampleCount *= 3; 
    769731 
    770732    LOGGER.debug( 
    771733      "unpacking {} samples (startIndex={}; totalBits={}; numBytes={})", 
    772       new Object[] {sampleCount, startIndex, totalBits, bytes.length}); 
     734      new Object[] {sampleCount, startIndex, nChannels * bitsPerSample[0], 
     735      bytes.length}); 
    773736 
    774737    long imageWidth = ifd.getImageWidth(); 
     
    782745 
    783746    boolean littleEndian = ifd.isLittleEndian(); 
    784  
    785     int[] reference = ifd.getIFDIntArray(IFD.REFERENCE_BLACK_WHITE, false); 
    786     int[] subsampling = ifd.getIFDIntArray(IFD.Y_CB_CR_SUB_SAMPLING, false); 
    787     TiffRational[] coefficients = (TiffRational[]) 
    788       ifd.getIFDValue(IFD.Y_CB_CR_COEFFICIENTS); 
    789747 
    790748    BitBuffer bb = new BitBuffer(bytes); 
     
    805763    } 
    806764 
    807     for (int j=0; j<sampleCount; j++) { 
    808       for (int i=0; i<nChannels; i++) { 
    809         int index = numBytes * (j * nChannels + i); 
    810         int ndx = startIndex + j; 
    811         if (ndx >= nSamples) { 
    812           break; 
    813         } 
    814         int outputIndex = i * nSamples + ndx * numBytes; 
    815  
    816         if (noDiv8) { 
    817           // bits per sample is not a multiple of 8 
    818  
    819           short s = 0; 
    820           if ((i == 0 && photoInterp == PhotoInterp.RGB_PALETTE) || 
    821             (photoInterp != PhotoInterp.CFA_ARRAY && 
    822             photoInterp != PhotoInterp.RGB_PALETTE)) 
    823           { 
    824             s = (short) (bb.getBits(bps0) & 0xffff); 
    825             if ((ndx % imageWidth) == imageWidth - 1 && bps0 < 8) { 
    826               bb.skipBits((imageWidth * bps0 * sampleCount) % 8); 
     765    long maxValue = (long) Math.pow(2, bps0) - 1; 
     766    if (photoInterp == PhotoInterp.CMYK) maxValue = Integer.MAX_VALUE; 
     767 
     768    int skipBits = (int) (8 - ((imageWidth * bps0 * nChannels) % 8)); 
     769    if (skipBits == 8) skipBits = 0; 
     770 
     771    // set up YCbCr-specific values 
     772    float lumaRed = PhotoInterp.LUMA_RED; 
     773    float lumaGreen = PhotoInterp.LUMA_GREEN; 
     774    float lumaBlue = PhotoInterp.LUMA_BLUE; 
     775    int[] reference = ifd.getIFDIntArray(IFD.REFERENCE_BLACK_WHITE, false); 
     776    if (reference == null) { 
     777      reference = new int[] {0, 0, 0, 0, 0, 0}; 
     778    } 
     779    int[] subsampling = ifd.getIFDIntArray(IFD.Y_CB_CR_SUB_SAMPLING, false); 
     780    TiffRational[] coefficients = (TiffRational[]) 
     781      ifd.getIFDValue(IFD.Y_CB_CR_COEFFICIENTS); 
     782    if (coefficients != null) { 
     783      lumaRed = coefficients[0].floatValue(); 
     784      lumaGreen = coefficients[1].floatValue(); 
     785      lumaBlue = coefficients[2].floatValue(); 
     786    } 
     787    int subX = subsampling == null ? 2 : subsampling[0]; 
     788    int subY = subsampling == null ? 2 : subsampling[1]; 
     789    int block = subX * subY; 
     790    int nTiles = (int) (imageWidth / subX); 
     791 
     792    // unpack pixels 
     793    for (int sample=0; sample<sampleCount; sample++) { 
     794      int ndx = startIndex + sample; 
     795      if (ndx >= nSamples) break; 
     796 
     797      for (int channel=0; channel<nChannels; channel++) { 
     798        int index = numBytes * (sample * nChannels + channel); 
     799        int outputIndex = channel * nSamples + ndx * numBytes; 
     800 
     801        // unpack non-YCbCr samples 
     802        if (photoInterp != PhotoInterp.Y_CB_CR) { 
     803          long value = 0; 
     804 
     805          if (noDiv8) { 
     806            // bits per sample is not a multiple of 8 
     807 
     808            if ((channel == 0 && photoInterp == PhotoInterp.RGB_PALETTE) || 
     809              (photoInterp != PhotoInterp.CFA_ARRAY && 
     810              photoInterp != PhotoInterp.RGB_PALETTE)) 
     811            { 
     812              value = bb.getBits(bps0) & 0xffff; 
     813              if (littleEndian) value = DataTools.swap(value) >> (32 - bps0); 
     814              if ((ndx % imageWidth) == imageWidth - 1 && bps0 < 8) { 
     815                bb.skipBits(skipBits); 
     816              } 
    827817            } 
     818          } 
     819          else { 
     820            value = DataTools.bytesToLong(bytes, index, numBytes, littleEndian); 
    828821          } 
    829822 
     
    831824            photoInterp == PhotoInterp.CMYK) 
    832825          { 
    833             // invert colors 
    834             s = (short) (Math.pow(2, bitsPerSample[0]) - 1 - s); 
     826            value = maxValue - value; 
    835827          } 
    836828 
    837829          if (outputIndex + numBytes <= samples.length) { 
    838             DataTools.unpackBytes(s, samples, outputIndex, numBytes, 
     830            DataTools.unpackBytes(value, samples, outputIndex, numBytes, 
    839831              littleEndian); 
    840832          } 
    841833        } 
    842         else if (bps8) { 
    843           // special case handles 8-bit data more quickly 
    844  
    845           if (outputIndex >= samples.length) break; 
    846  
    847           if (photoInterp != PhotoInterp.Y_CB_CR) { 
    848             samples[outputIndex] = (byte) (bytes[index] & 0xff); 
    849           } 
    850  
    851           if (photoInterp == PhotoInterp.WHITE_IS_ZERO) { // invert color value 
    852             samples[outputIndex] = (byte) (255 - samples[outputIndex]); 
    853           } 
    854           else if (photoInterp == PhotoInterp.CMYK) { 
    855             samples[outputIndex] = 
    856               (byte) (Integer.MAX_VALUE - samples[outputIndex]); 
    857           } 
    858           else if (photoInterp == PhotoInterp.Y_CB_CR) { 
    859             if (i == bitsPerSample.length - 1) { 
    860               float lumaRed = 0.299f; 
    861               float lumaGreen = 0.587f; 
    862               float lumaBlue = 0.114f; 
    863               if (coefficients != null) { 
    864                 lumaRed = coefficients[0].floatValue(); 
    865                 lumaGreen = coefficients[1].floatValue(); 
    866                 lumaBlue = coefficients[2].floatValue(); 
    867               } 
    868  
    869               int subX = subsampling == null ? 2 : subsampling[0]; 
    870               int subY = subsampling == null ? 2 : subsampling[1]; 
    871  
    872               int block = subX * subY; 
    873               int lumaIndex = j + (2 * (j / block)); 
    874               int chromaIndex = (j / block) * (block + 2) + block; 
    875  
    876               if (chromaIndex + 1 >= bytes.length) break; 
    877  
    878               int tile = ndx / block; 
    879               int pixel = ndx % block; 
    880               int nTiles = (int) (imageWidth / subX); 
    881               long r = subY * (tile / nTiles) + (pixel / subX); 
    882               long c = subX * (tile % nTiles) + (pixel % subX); 
    883  
    884               int idx = (int) (r * imageWidth + c); 
    885  
    886               if (idx < nSamples) { 
    887                 int y = (bytes[lumaIndex] & 0xff) - reference[0]; 
    888                 int cb = (bytes[chromaIndex] & 0xff) - reference[2]; 
    889                 int cr = (bytes[chromaIndex + 1] & 0xff) - reference[4]; 
    890  
    891                 int red = (int) (cr * (2 - 2 * lumaRed) + y); 
    892                 int blue = (int) (cb * (2 - 2 * lumaBlue) + y); 
    893                 int green = (int) 
    894                   ((y - lumaBlue * blue - lumaRed * red) / lumaGreen); 
    895  
    896                 samples[idx] = (byte) red; 
    897                 samples[nSamples + idx] = (byte) green; 
    898                 samples[2*nSamples + idx] = (byte) blue; 
    899               } 
     834        else { 
     835          // unpack YCbCr samples; these need special handling, as each of 
     836          // the RGB components depends upon two or more of the YCbCr components 
     837          if (channel == nChannels - 1) { 
     838            int lumaIndex = sample + (2 * (sample / block)); 
     839            int chromaIndex = (sample / block) * (block + 2) + block; 
     840 
     841            if (chromaIndex + 1 >= bytes.length) break; 
     842 
     843            int tile = ndx / block; 
     844            int pixel = ndx % block; 
     845            long r = subY * (tile / nTiles) + (pixel / subX); 
     846            long c = subX * (tile % nTiles) + (pixel % subX); 
     847 
     848            int idx = (int) (r * imageWidth + c); 
     849 
     850            if (idx < nSamples) { 
     851              int y = (bytes[lumaIndex] & 0xff) - reference[0]; 
     852              int cb = (bytes[chromaIndex] & 0xff) - reference[2]; 
     853              int cr = (bytes[chromaIndex + 1] & 0xff) - reference[4]; 
     854 
     855              int red = (int) (cr * (2 - 2 * lumaRed) + y); 
     856              int blue = (int) (cb * (2 - 2 * lumaBlue) + y); 
     857              int green = (int) 
     858                ((y - lumaBlue * blue - lumaRed * red) / lumaGreen); 
     859 
     860              samples[idx] = (byte) (red & 0xff); 
     861              samples[nSamples + idx] = (byte) (green & 0xff); 
     862              samples[2*nSamples + idx] = (byte) (blue & 0xff); 
    900863            } 
    901864          } 
    902         } // end if (bps8) 
    903         else { 
    904           int offset = numBytes + index < bytes.length ? 
    905             index : bytes.length - numBytes; 
    906           long v = DataTools.bytesToLong(bytes, offset, numBytes, littleEndian); 
    907  
    908           if (photoInterp == PhotoInterp.WHITE_IS_ZERO) { // invert color value 
    909             long max = (long) Math.pow(2, numBytes * 8) - 1; 
    910             v = max - v; 
    911           } 
    912           else if (photoInterp == PhotoInterp.CMYK) { 
    913             v = Integer.MAX_VALUE - v; 
    914           } 
    915           if (ndx*numBytes >= nSamples) break; 
    916           DataTools.unpackBytes(v, samples, i*nSamples + ndx*numBytes, 
    917             numBytes, littleEndian); 
    918         } // end else 
     865        } 
    919866      } 
    920867    } 
Note: See TracChangeset for help on using the changeset viewer.