Program: 33374
Project: 33374
Buggy source:
private BufferedImage decodeStrippedTiff(IFD ifd) throws Exception {
  TiffField<?> field=ifd.getField(TiffTag.COMPRESSION.getValue());
  short[] data=(short[])field.getData();
  TiffFieldEnum.Compression compression=TiffFieldEnum.Compression.fromValue(data[0] & 0xffff);
  System.out.println("String_Node_Str" + compression.getDescription());
  TiffField<?> f_stripOffsets=ifd.getField(TiffTag.STRIP_OFFSETS.getValue());
  TiffField<?> f_stripByteCounts=ifd.getField(TiffTag.STRIP_BYTE_COUNTS.getValue());
  int[] stripOffsets=f_stripOffsets.getDataAsLong();
  int[] stripByteCounts=f_stripByteCounts.getDataAsLong();
  int imageWidth=ifd.getField(TiffTag.IMAGE_WIDTH.getValue()).getDataAsLong()[0];
  int imageHeight=ifd.getField(TiffTag.IMAGE_LENGTH.getValue()).getDataAsLong()[0];
  System.out.println("String_Node_Str" + imageWidth);
  System.out.println("String_Node_Str" + imageHeight);
  TiffField<?> f_rowsPerStrip=ifd.getField(TiffTag.ROWS_PER_STRIP.getValue());
  int rowsPerStrip=imageHeight;
  if (f_rowsPerStrip != null)   rowsPerStrip=f_rowsPerStrip.getDataAsLong()[0];
  System.out.println("String_Node_Str" + rowsPerStrip);
  TiffField<?> f_photoMetric=ifd.getField(TiffTag.PHOTOMETRIC_INTERPRETATION.getValue());
  int photoMetric=f_photoMetric.getDataAsLong()[0];
  TiffFieldEnum.PhotoMetric e_photoMetric=TiffFieldEnum.PhotoMetric.fromValue(photoMetric);
  System.out.println("String_Node_Str" + e_photoMetric);
  TiffField<?> f_bitsPerSample=ifd.getField(TiffTag.BITS_PER_SAMPLE.getValue());
  int bitsPerSample=f_bitsPerSample.getDataAsLong()[0];
  System.out.println("String_Node_Str" + bitsPerSample);
  TiffField<?> f_samplesPerPixel=ifd.getField(TiffTag.SAMPLES_PER_PIXEL.getValue());
  int samplesPerPixel=f_samplesPerPixel.getDataAsLong()[0];
  System.out.println("String_Node_Str" + samplesPerPixel);
  TiffField<?> f_predictor=ifd.getField(TiffTag.PREDICTOR.getValue());
  int predictor=0;
  if (f_predictor != null) {
    predictor=f_predictor.getDataAsLong()[0];
    System.out.println("String_Node_Str" + predictor);
  }
  TiffField<?> f_planaryConfiguration=ifd.getField(TiffTag.PLANAR_CONFIGURATTION.getValue());
  int planaryConfiguration=1;
  if (f_planaryConfiguration != null)   planaryConfiguration=f_planaryConfiguration.getDataAsLong()[0];
  TiffFieldEnum.PlanarConfiguration e_planaryConfiguration=TiffFieldEnum.PlanarConfiguration.fromValue(planaryConfiguration);
  System.out.println("String_Node_Str" + e_planaryConfiguration);
  int offset=0;
  ImageDecoder decoder=null;
  byte[] pixels=null;
  int[] stripBytes=TIFFTweaker.getUncompressedStripByteCounts(ifd,stripOffsets.length);
switch (e_photoMetric) {
case PALETTE_COLOR:
    short[] colorMap=(short[])ifd.getField(TiffTag.COLORMAP.getValue()).getData();
  rgbColorPalette=new int[colorMap.length / 3];
int numOfColors=(1 << bitsPerSample);
int numOfColors2=(numOfColors << 1);
for (int i=0, index=0; i < colorMap.length / 3; i++) {
rgbColorPalette[index++]=0xff000000 | ((colorMap[i] & 0xff00) << 8) | ((colorMap[i + numOfColors] & 0xff00))| ((colorMap[i + numOfColors2] & 0xff00) >> 8);
}
int bytesPerScanLine=(imageWidth * bitsPerSample + 7) / 8;
pixels=new byte[bytesPerScanLine * imageHeight];
switch (compression) {
case LZW:
decoder=new LZWTreeDecoder(8,true);
break;
case DEFLATE:
case DEFLATE_ADOBE:
decoder=new DeflateDecoder();
break;
default :
}
if (decoder != null) {
for (int i=0; i < stripByteCounts.length; i++) {
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
decoder.setInput(temp);
int numOfBytes=decoder.decode(pixels,offset,stripBytes[i]);
offset+=numOfBytes;
}
}
DataBuffer db=new DataBufferByte(pixels,pixels.length);
WritableRaster raster=null;
if (bitsPerSample != 8) {
raster=Raster.createPackedRaster(db,imageWidth,imageHeight,bitsPerSample,null);
}
 else {
int[] off={0};
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth,1,off,null);
}
ColorModel cm=new IndexColorModel(bitsPerSample,rgbColorPalette.length,rgbColorPalette,0,false,-1,DataBuffer.TYPE_BYTE);
return new BufferedImage(cm,raster,false,null);
case SEPARATED:
bytesPerScanLine=(imageWidth * samplesPerPixel * bitsPerSample + 7) / 8;
pixels=new byte[imageHeight * bytesPerScanLine];
switch (compression) {
case NONE:
bytesPerScanLine=imageWidth * samplesPerPixel * bitsPerSample / 8;
pixels=new byte[imageWidth * bytesPerScanLine];
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
randIS.seek(stripOffsets[i]);
randIS.readFully(pixels,offset,bytes2Read);
offset+=bytes2Read;
}
break;
case LZW:
decoder=new LZWTreeDecoder(8,true);
break;
case DEFLATE:
case DEFLATE_ADOBE:
decoder=new DeflateDecoder();
break;
default :
break;
}
if (decoder != null) {
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
decoder.setInput(temp);
int numOfBytes=decoder.decode(pixels,offset,bytes2Read);
offset+=numOfBytes;
}
}
if (predictor == 2 && planaryConfiguration == 1) pixels=applyDePredictor(samplesPerPixel,pixels,imageWidth,imageHeight);
db=new DataBufferByte(pixels,pixels.length);
int[] bandoff={0,1,2,3};
boolean transparent=false;
int numOfBands=samplesPerPixel;
int trans=Transparency.OPAQUE;
int[] nBits={8,8,8,8};
if (samplesPerPixel >= 5) {
bandoff=new int[]{0,1,2,3,4};
nBits=new int[]{8,8,8,8,8};
trans=Transparency.TRANSLUCENT;
transparent=true;
}
TiffField<?> f_colorProfile=ifd.getField(TiffTag.ICC_PROFILE.getValue());
ICC_Profile profile=null;
if (f_colorProfile != null) profile=ICC_Profile.getInstance((byte[])f_colorProfile.getData());
ColorSpace colorSpace=CMYKColorSpace.getInstance();
if (profile != null) colorSpace=new ICC_ColorSpace(profile);
if (bitsPerSample == 16) {
short[] spixels=ArrayUtils.byteArrayToShortArray(pixels,true);
db=new DataBufferUShort(spixels,spixels.length);
int[] off={0,1,2,3};
nBits=new int[]{16,16,16,16};
trans=Transparency.OPAQUE;
numOfBands=samplesPerPixel;
if (samplesPerPixel == 5) {
off=new int[]{0,1,2,3,4};
nBits=new int[]{16,16,16,16,16};
trans=Transparency.TRANSLUCENT;
}
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,off,null);
cm=new ComponentColorModel(CMYKColorSpace.getInstance(),nBits,transparent,false,trans,DataBuffer.TYPE_USHORT);
}
 else {
if (planaryConfiguration == 2) {
int bytesPerLine=(samplesPerPixel * bitsPerSample * imageWidth + 7) / 8;
raster=Raster.createBandedRaster(db,imageWidth,imageHeight,bytesPerLine * samplesPerPixel,new int[]{0,0,0},new int[]{0,bytesPerLine,bytesPerLine * 2},null);
if (profile != null) {
raster=IMGUtils.CMYK2RGB(raster,profile,transparent);
cm=new ComponentColorModel(colorSpace,nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
 else cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
 else {
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,bandoff,null);
if (profile != null) {
raster=IMGUtils.CMYK2RGB(raster,profile,transparent);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
 else {
cm=new ComponentColorModel(colorSpace,nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
}
}
return new BufferedImage(cm,raster,false,null);
case YCbCr:
int[] samplingFactor={2,2};
TiffField<?> f_YCbCrSubSampling=ifd.getField(TiffTag.YCbCr_SUB_SAMPLING.getValue());
if (f_YCbCrSubSampling != null) samplingFactor=f_YCbCrSubSampling.getDataAsLong();
float referenceBlackY=0.0f;
float referenceWhiteY=255.0f;
float referenceBlackCb=128.0f;
float referenceWhiteCb=255.0f;
float referenceBlackCr=128.0f;
float referenceWhiteCr=255.0f;
float codingRangeY=255.0f;
float codingRangeCbCr=127.0f;
TiffField<?> f_referenceBlackWhite=ifd.getField(TiffTag.REFERENCE_BLACK_WHITE.getValue());
if (f_referenceBlackWhite != null) {
int[] referenceBlackWhite=f_referenceBlackWhite.getDataAsLong();
referenceBlackY=1.0f * referenceBlackWhite[0] / referenceBlackWhite[1];
referenceWhiteY=1.0f * referenceBlackWhite[2] / referenceBlackWhite[3];
referenceBlackCb=1.0f * referenceBlackWhite[4] / referenceBlackWhite[5];
referenceWhiteCb=1.0f * referenceBlackWhite[6] / referenceBlackWhite[7];
referenceBlackCr=1.0f * referenceBlackWhite[8] / referenceBlackWhite[9];
referenceWhiteCr=1.0f * referenceBlackWhite[10] / referenceBlackWhite[11];
}
float lumaRed=0.299f;
float lumaGreen=0.587f;
float lumaBlue=0.114f;
TiffField<?> f_YCbCrCoefficients=ifd.getField(TiffTag.YCbCr_COEFFICIENTS.getValue());
if (f_YCbCrCoefficients != null) {
int[] lumas=f_YCbCrCoefficients.getDataAsLong();
lumaRed=1.0f * lumas[0] / lumas[1];
lumaGreen=1.0f * lumas[2] / lumas[3];
lumaBlue=1.0f * lumas[4] / lumas[5];
}
int bytesPerUnitY=samplingFactor[0] * samplingFactor[1];
int bytesPerUnitCb=1;
int bytesPerUnitCr=1;
int bytesPerDataUnit=bytesPerUnitY + bytesPerUnitCb + bytesPerUnitCr;
int dataUnitsPerWidth=imageWidth / samplingFactor[0];
int offsetX=0;
int offsetY=0;
int bytesY=imageWidth * imageHeight;
pixels=new byte[bytesY * 3 + rowsPerStrip * imageWidth * samplesPerPixel];
switch (compression) {
case NONE:
if (planaryConfiguration == 1) {
byte[] temp=null;
for (int i=0; i < stripByteCounts.length; i++) {
randIS.seek(stripOffsets[i]);
int len=stripByteCounts[i];
temp=new byte[len];
randIS.readFully(temp);
offset=0;
offsetX=0;
int numOfDataUnit=len / bytesPerDataUnit;
for (int j=1; j <= numOfDataUnit; j++) {
int offsetCb=offset + bytesPerUnitY;
int Cb=temp[offsetCb] & 0xff;
int Cr=temp[offsetCb + 1] & 0xff;
for (int k=0; k < samplingFactor[1]; k++) {
for (int l=0; l < samplingFactor[0]; l++, offsetX++) {
int Y=temp[offset++] & 0xff;
float fY=(Y - referenceBlackY) * codingRangeY / (referenceWhiteY - referenceBlackY);
float fCb=(Cb - referenceBlackCb) * codingRangeCbCr / (referenceWhiteCb - referenceBlackCb);
float fCr=(Cr - referenceBlackCr) * codingRangeCbCr / (referenceWhiteCr - referenceBlackCr);
float R=(fCr * (2 - 2 * lumaRed) + fY);
float B=(fCb * (2 - 2 * lumaBlue) + fY);
float G=((fY - lumaBlue * B - lumaRed * R) / lumaGreen);
if (R < 0) R=0;
if (R > 255) R=255;
if (G < 0) G=0;
if (G > 255) G=255;
if (B < 0) B=0;
if (B > 255) B=255;
int yPos=offsetX + offsetY * imageWidth;
int redPos=3 * yPos;
pixels[redPos]=(byte)R;
pixels[redPos + 1]=(byte)G;
pixels[redPos + 2]=(byte)B;
}
offsetX-=samplingFactor[0];
offsetY+=1;
}
offsetY-=samplingFactor[1];
offset+=2;
offsetX+=samplingFactor[0];
if (j % dataUnitsPerWidth == 0) {
offsetY+=samplingFactor[1];
offsetX=0;
}
}
}
}
 else {
}
break;
case LZW:
if (planaryConfiguration == 1) {
byte[] temp=null;
byte[] temp2=null;
for (int i=0; i < stripByteCounts.length; i++) {
randIS.seek(stripOffsets[i]);
int len=stripByteCounts[i];
temp=new byte[len];
randIS.readFully(temp);
temp2=new byte[stripBytes[i]];
decoder=new LZWTreeDecoder(8,true);
decoder.setInput(temp);
int numOfBytes=decoder.decode(temp2,0,temp2.length);
offset=0;
offsetX=0;
int numOfDataUnit=numOfBytes / bytesPerDataUnit;
for (int j=1; j <= numOfDataUnit; j++) {
int offsetCb=offset + bytesPerUnitY;
int Cb=temp2[offsetCb] & 0xff;
int Cr=temp2[offsetCb + 1] & 0xff;
for (int k=0; k < samplingFactor[1]; k++) {
for (int l=0; l < samplingFactor[0]; l++, offsetX++) {
int Y=temp2[offset++] & 0xff;
float fY=(Y - referenceBlackY) * codingRangeY / (referenceWhiteY - referenceBlackY);
float fCb=(Cb - referenceBlackCb) * codingRangeCbCr / (referenceWhiteCb - referenceBlackCb);
float fCr=(Cr - referenceBlackCr) * codingRangeCbCr / (referenceWhiteCr - referenceBlackCr);
float R=(fCr * (2 - 2 * lumaRed) + fY);
float B=(fCb * (2 - 2 * lumaBlue) + fY);
float G=((fY - lumaBlue * B - lumaRed * R) / lumaGreen);
if (R < 0) R=0;
if (R > 255) R=255;
if (G < 0) G=0;
if (G > 255) G=255;
if (B < 0) B=0;
if (B > 255) B=255;
int yPos=offsetX + offsetY * imageWidth;
int redPos=3 * yPos;
pixels[redPos]=(byte)R;
pixels[redPos + 1]=(byte)G;
pixels[redPos + 2]=(byte)B;
}
offsetX-=samplingFactor[0];
offsetY+=1;
}
offsetY-=samplingFactor[1];
offset+=2;
offsetX+=samplingFactor[0];
if (j % dataUnitsPerWidth == 0) {
offsetY+=samplingFactor[1];
offsetX=0;
}
}
}
}
 else {
}
break;
default :
}
db=new DataBufferByte(pixels,pixels.length);
bandoff=new int[]{0,1,2};
transparent=false;
numOfBands=samplesPerPixel;
trans=Transparency.OPAQUE;
nBits=new int[]{8,8,8};
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,bandoff,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
return new BufferedImage(cm,raster,false,null);
case RGB:
bytesPerScanLine=samplesPerPixel * ((imageWidth * bitsPerSample + 7) / 8);
int totalBytes2Read=imageHeight * bytesPerScanLine;
if (planaryConfiguration == 2) bytesPerScanLine=(imageWidth * bitsPerSample + 7) / 8;
pixels=new byte[totalBytes2Read];
switch (compression) {
case NONE:
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
randIS.seek(stripOffsets[i]);
randIS.readFully(pixels,offset,bytes2Read);
offset+=bytes2Read;
}
break;
case PACKBITS:
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
byte[] temp2=new byte[bytes2Read];
Packbits.unpackbits(temp,temp2);
System.arraycopy(temp2,0,pixels,offset,bytes2Read);
offset+=bytes2Read;
}
break;
case LZW:
decoder=new LZWTreeDecoder(8,true);
break;
case DEFLATE:
case DEFLATE_ADOBE:
decoder=new DeflateDecoder();
break;
default :
}
int[] count=new int[samplesPerPixel];
if (planaryConfiguration == 2) {
int inc=stripBytes.length / samplesPerPixel;
int startOff=0;
int endOff=inc;
for (int k=0; k < samplesPerPixel; k++) {
for (int j=startOff; j < endOff; j++) count[k]+=stripBytes[j];
startOff+=inc;
endOff=startOff + inc;
}
}
if (decoder != null) {
pixels=new byte[stripOffsets.length * stripBytes[0]];
for (int i=0; i < stripByteCounts.length; i++) {
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
decoder.setInput(temp);
int numOfBytes=decoder.decode(pixels,offset,stripBytes[i]);
offset+=numOfBytes;
}
}
if (predictor == 2) {
if (planaryConfiguration == 1) pixels=applyDePredictor(samplesPerPixel,pixels,imageWidth,imageHeight);
 else {
int dataOffset=0;
for (int k=0; k < samplesPerPixel; k++) {
applyDePredictor2(pixels,dataOffset,imageWidth,imageHeight);
dataOffset+=count[k];
}
}
}
if (bitsPerSample == 16) {
short[] spixels=ArrayUtils.byteArrayToShortArray(pixels,true);
db=new DataBufferUShort(spixels,spixels.length);
int[] off={0,1,2};
numOfBands=3;
trans=Transparency.OPAQUE;
nBits=new int[]{16,16,16};
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,off,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,false,false,trans,DataBuffer.TYPE_USHORT);
}
 else {
db=new DataBufferByte(pixels,pixels.length);
bandoff=new int[]{0,1,2};
transparent=false;
numOfBands=samplesPerPixel;
trans=Transparency.OPAQUE;
nBits=new int[]{8,8,8};
if (samplesPerPixel == 4) {
bandoff=new int[]{0,1,2,3};
nBits=new int[]{8,8,8,8};
trans=Transparency.TRANSLUCENT;
transparent=true;
}
if (planaryConfiguration == 2) {
bandoff=new int[]{0,count[0],count[0] + count[1]};
int[] bandIndices=new int[]{0,0,0};
if (samplesPerPixel == 4) {
bandoff=new int[]{0,count[0],count[0] + count[1],count[0] + count[1] + count[2]};
bandIndices=new int[]{0,0,0,0};
}
raster=Raster.createBandedRaster(db,imageWidth,imageHeight,bytesPerScanLine,bandIndices,bandoff,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
 else {
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,bandoff,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
}
return new BufferedImage(cm,raster,false,null);
default :
break;
}
return null;
}

Fixed version (ground truth):
private BufferedImage decodeStrippedTiff(IFD ifd) throws Exception {
  TiffField<?> field=ifd.getField(TiffTag.COMPRESSION.getValue());
  short[] data=(short[])field.getData();
  TiffFieldEnum.Compression compression=TiffFieldEnum.Compression.fromValue(data[0] & 0xffff);
  System.out.println("String_Node_Str" + compression.getDescription());
  TiffField<?> f_stripOffsets=ifd.getField(TiffTag.STRIP_OFFSETS.getValue());
  TiffField<?> f_stripByteCounts=ifd.getField(TiffTag.STRIP_BYTE_COUNTS.getValue());
  int[] stripOffsets=f_stripOffsets.getDataAsLong();
  int[] stripByteCounts=f_stripByteCounts.getDataAsLong();
  int imageWidth=ifd.getField(TiffTag.IMAGE_WIDTH.getValue()).getDataAsLong()[0];
  int imageHeight=ifd.getField(TiffTag.IMAGE_LENGTH.getValue()).getDataAsLong()[0];
  System.out.println("String_Node_Str" + imageWidth);
  System.out.println("String_Node_Str" + imageHeight);
  TiffField<?> f_rowsPerStrip=ifd.getField(TiffTag.ROWS_PER_STRIP.getValue());
  int rowsPerStrip=imageHeight;
  if (f_rowsPerStrip != null)   rowsPerStrip=f_rowsPerStrip.getDataAsLong()[0];
  System.out.println("String_Node_Str" + rowsPerStrip);
  TiffField<?> f_photoMetric=ifd.getField(TiffTag.PHOTOMETRIC_INTERPRETATION.getValue());
  int photoMetric=f_photoMetric.getDataAsLong()[0];
  TiffFieldEnum.PhotoMetric e_photoMetric=TiffFieldEnum.PhotoMetric.fromValue(photoMetric);
  System.out.println("String_Node_Str" + e_photoMetric);
  TiffField<?> f_bitsPerSample=ifd.getField(TiffTag.BITS_PER_SAMPLE.getValue());
  int bitsPerSample=f_bitsPerSample.getDataAsLong()[0];
  System.out.println("String_Node_Str" + bitsPerSample);
  TiffField<?> f_samplesPerPixel=ifd.getField(TiffTag.SAMPLES_PER_PIXEL.getValue());
  int samplesPerPixel=f_samplesPerPixel.getDataAsLong()[0];
  System.out.println("String_Node_Str" + samplesPerPixel);
  TiffField<?> f_predictor=ifd.getField(TiffTag.PREDICTOR.getValue());
  int predictor=0;
  if (f_predictor != null) {
    predictor=f_predictor.getDataAsLong()[0];
    System.out.println("String_Node_Str" + predictor);
  }
  TiffField<?> f_planaryConfiguration=ifd.getField(TiffTag.PLANAR_CONFIGURATTION.getValue());
  int planaryConfiguration=1;
  if (f_planaryConfiguration != null)   planaryConfiguration=f_planaryConfiguration.getDataAsLong()[0];
  TiffFieldEnum.PlanarConfiguration e_planaryConfiguration=TiffFieldEnum.PlanarConfiguration.fromValue(planaryConfiguration);
  System.out.println("String_Node_Str" + e_planaryConfiguration);
  int offset=0;
  ImageDecoder decoder=null;
  byte[] pixels=null;
  int[] stripBytes=TIFFTweaker.getUncompressedStripByteCounts(ifd,stripOffsets.length);
  int[] count=new int[samplesPerPixel];
  if (planaryConfiguration == 2) {
    int inc=stripBytes.length / samplesPerPixel;
    int startOff=0;
    int endOff=inc;
    for (int k=0; k < samplesPerPixel; k++) {
      for (int j=startOff; j < endOff; j++)       count[k]+=stripBytes[j];
      startOff+=inc;
      endOff=startOff + inc;
    }
  }
switch (e_photoMetric) {
case PALETTE_COLOR:
    short[] colorMap=(short[])ifd.getField(TiffTag.COLORMAP.getValue()).getData();
  rgbColorPalette=new int[colorMap.length / 3];
int numOfColors=(1 << bitsPerSample);
int numOfColors2=(numOfColors << 1);
for (int i=0, index=0; i < colorMap.length / 3; i++) {
rgbColorPalette[index++]=0xff000000 | ((colorMap[i] & 0xff00) << 8) | ((colorMap[i + numOfColors] & 0xff00))| ((colorMap[i + numOfColors2] & 0xff00) >> 8);
}
int bytesPerScanLine=(imageWidth * bitsPerSample + 7) / 8;
pixels=new byte[bytesPerScanLine * imageHeight];
switch (compression) {
case LZW:
decoder=new LZWTreeDecoder(8,true);
break;
case DEFLATE:
case DEFLATE_ADOBE:
decoder=new DeflateDecoder();
break;
default :
}
if (decoder != null) {
for (int i=0; i < stripByteCounts.length; i++) {
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
decoder.setInput(temp);
int numOfBytes=decoder.decode(pixels,offset,stripBytes[i]);
offset+=numOfBytes;
}
}
DataBuffer db=new DataBufferByte(pixels,pixels.length);
WritableRaster raster=null;
if (bitsPerSample != 8) {
raster=Raster.createPackedRaster(db,imageWidth,imageHeight,bitsPerSample,null);
}
 else {
int[] off={0};
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth,1,off,null);
}
ColorModel cm=new IndexColorModel(bitsPerSample,rgbColorPalette.length,rgbColorPalette,0,false,-1,DataBuffer.TYPE_BYTE);
return new BufferedImage(cm,raster,false,null);
case SEPARATED:
bytesPerScanLine=samplesPerPixel * ((imageWidth * bitsPerSample + 7) / 8);
if (planaryConfiguration == 2) bytesPerScanLine=(imageWidth * bitsPerSample + 7) / 8;
pixels=new byte[imageHeight * bytesPerScanLine];
switch (compression) {
case NONE:
bytesPerScanLine=imageWidth * samplesPerPixel * bitsPerSample / 8;
pixels=new byte[imageWidth * bytesPerScanLine];
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
randIS.seek(stripOffsets[i]);
randIS.readFully(pixels,offset,bytes2Read);
offset+=bytes2Read;
}
break;
case LZW:
decoder=new LZWTreeDecoder(8,true);
break;
case DEFLATE:
case DEFLATE_ADOBE:
decoder=new DeflateDecoder();
break;
default :
break;
}
if (decoder != null) {
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
decoder.setInput(temp);
int numOfBytes=decoder.decode(pixels,offset,bytes2Read);
offset+=numOfBytes;
}
}
if (predictor == 2 && planaryConfiguration == 1) pixels=applyDePredictor(samplesPerPixel,pixels,imageWidth,imageHeight);
db=new DataBufferByte(pixels,pixels.length);
TiffField<?> f_colorProfile=ifd.getField(TiffTag.ICC_PROFILE.getValue());
ICC_Profile profile=null;
if (f_colorProfile != null) profile=ICC_Profile.getInstance((byte[])f_colorProfile.getData());
ColorSpace colorSpace=CMYKColorSpace.getInstance();
if (profile != null) colorSpace=new ICC_ColorSpace(profile);
int[] bandoff={0,1,2,3};
boolean transparent=false;
int numOfBands=samplesPerPixel;
int trans=Transparency.OPAQUE;
int[] nBits={8,8,8,8};
if (samplesPerPixel >= 5) {
bandoff=new int[]{0,1,2,3,4};
nBits=new int[]{8,8,8,8,8};
trans=Transparency.TRANSLUCENT;
transparent=true;
}
if (bitsPerSample == 16) {
short[] spixels=ArrayUtils.byteArrayToShortArray(pixels,true);
db=new DataBufferUShort(spixels,spixels.length);
int[] off={0,1,2,3};
nBits=new int[]{16,16,16,16};
trans=Transparency.OPAQUE;
numOfBands=samplesPerPixel;
if (samplesPerPixel >= 5) {
off=new int[]{0,1,2,3,4};
nBits=new int[]{16,16,16,16,16};
trans=Transparency.TRANSLUCENT;
}
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,off,null);
cm=new ComponentColorModel(CMYKColorSpace.getInstance(),nBits,transparent,false,trans,DataBuffer.TYPE_USHORT);
}
 else {
cm=new ComponentColorModel(colorSpace,nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
if (planaryConfiguration == 2) {
bandoff=new int[]{0,count[0],count[0] + count[1],count[0] + count[1] + count[2]};
int[] bandIndices=new int[]{0,0,0,0};
if (samplesPerPixel >= 5) {
bandoff=new int[]{0,count[0],count[0] + count[1],count[0] + count[1] + count[2],count[0] + count[1] + count[2]+ count[3]};
bandIndices=new int[]{0,0,0,0,0};
}
raster=Raster.createBandedRaster(db,imageWidth,imageHeight,bytesPerScanLine,bandIndices,bandoff,null);
if (profile != null) {
raster=IMGUtils.CMYK2RGB(raster,cm);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
}
 else {
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,bandoff,null);
if (profile != null) {
raster=IMGUtils.CMYK2RGB(raster,cm);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
}
}
return new BufferedImage(cm,raster,false,null);
case YCbCr:
int[] samplingFactor={2,2};
TiffField<?> f_YCbCrSubSampling=ifd.getField(TiffTag.YCbCr_SUB_SAMPLING.getValue());
if (f_YCbCrSubSampling != null) samplingFactor=f_YCbCrSubSampling.getDataAsLong();
float referenceBlackY=0.0f;
float referenceWhiteY=255.0f;
float referenceBlackCb=128.0f;
float referenceWhiteCb=255.0f;
float referenceBlackCr=128.0f;
float referenceWhiteCr=255.0f;
float codingRangeY=255.0f;
float codingRangeCbCr=127.0f;
TiffField<?> f_referenceBlackWhite=ifd.getField(TiffTag.REFERENCE_BLACK_WHITE.getValue());
if (f_referenceBlackWhite != null) {
int[] referenceBlackWhite=f_referenceBlackWhite.getDataAsLong();
referenceBlackY=1.0f * referenceBlackWhite[0] / referenceBlackWhite[1];
referenceWhiteY=1.0f * referenceBlackWhite[2] / referenceBlackWhite[3];
referenceBlackCb=1.0f * referenceBlackWhite[4] / referenceBlackWhite[5];
referenceWhiteCb=1.0f * referenceBlackWhite[6] / referenceBlackWhite[7];
referenceBlackCr=1.0f * referenceBlackWhite[8] / referenceBlackWhite[9];
referenceWhiteCr=1.0f * referenceBlackWhite[10] / referenceBlackWhite[11];
}
float lumaRed=0.299f;
float lumaGreen=0.587f;
float lumaBlue=0.114f;
TiffField<?> f_YCbCrCoefficients=ifd.getField(TiffTag.YCbCr_COEFFICIENTS.getValue());
if (f_YCbCrCoefficients != null) {
int[] lumas=f_YCbCrCoefficients.getDataAsLong();
lumaRed=1.0f * lumas[0] / lumas[1];
lumaGreen=1.0f * lumas[2] / lumas[3];
lumaBlue=1.0f * lumas[4] / lumas[5];
}
int bytesPerUnitY=samplingFactor[0] * samplingFactor[1];
int bytesPerUnitCb=1;
int bytesPerUnitCr=1;
int bytesPerDataUnit=bytesPerUnitY + bytesPerUnitCb + bytesPerUnitCr;
int dataUnitsPerWidth=imageWidth / samplingFactor[0];
int offsetX=0;
int offsetY=0;
int bytesY=imageWidth * imageHeight;
pixels=new byte[bytesY * 3 + rowsPerStrip * imageWidth * samplesPerPixel];
switch (compression) {
case NONE:
if (planaryConfiguration == 1) {
byte[] temp=null;
for (int i=0; i < stripByteCounts.length; i++) {
randIS.seek(stripOffsets[i]);
int len=stripByteCounts[i];
temp=new byte[len];
randIS.readFully(temp);
offset=0;
offsetX=0;
int numOfDataUnit=len / bytesPerDataUnit;
for (int j=1; j <= numOfDataUnit; j++) {
int offsetCb=offset + bytesPerUnitY;
int Cb=temp[offsetCb] & 0xff;
int Cr=temp[offsetCb + 1] & 0xff;
for (int k=0; k < samplingFactor[1]; k++) {
for (int l=0; l < samplingFactor[0]; l++, offsetX++) {
int Y=temp[offset++] & 0xff;
float fY=(Y - referenceBlackY) * codingRangeY / (referenceWhiteY - referenceBlackY);
float fCb=(Cb - referenceBlackCb) * codingRangeCbCr / (referenceWhiteCb - referenceBlackCb);
float fCr=(Cr - referenceBlackCr) * codingRangeCbCr / (referenceWhiteCr - referenceBlackCr);
float R=(fCr * (2 - 2 * lumaRed) + fY);
float B=(fCb * (2 - 2 * lumaBlue) + fY);
float G=((fY - lumaBlue * B - lumaRed * R) / lumaGreen);
if (R < 0) R=0;
if (R > 255) R=255;
if (G < 0) G=0;
if (G > 255) G=255;
if (B < 0) B=0;
if (B > 255) B=255;
int yPos=offsetX + offsetY * imageWidth;
int redPos=3 * yPos;
pixels[redPos]=(byte)R;
pixels[redPos + 1]=(byte)G;
pixels[redPos + 2]=(byte)B;
}
offsetX-=samplingFactor[0];
offsetY+=1;
}
offsetY-=samplingFactor[1];
offset+=2;
offsetX+=samplingFactor[0];
if (j % dataUnitsPerWidth == 0) {
offsetY+=samplingFactor[1];
offsetX=0;
}
}
}
}
 else {
}
break;
case LZW:
if (planaryConfiguration == 1) {
byte[] temp=null;
byte[] temp2=null;
for (int i=0; i < stripByteCounts.length; i++) {
randIS.seek(stripOffsets[i]);
int len=stripByteCounts[i];
temp=new byte[len];
randIS.readFully(temp);
temp2=new byte[stripBytes[i]];
decoder=new LZWTreeDecoder(8,true);
decoder.setInput(temp);
int numOfBytes=decoder.decode(temp2,0,temp2.length);
offset=0;
offsetX=0;
int numOfDataUnit=numOfBytes / bytesPerDataUnit;
for (int j=1; j <= numOfDataUnit; j++) {
int offsetCb=offset + bytesPerUnitY;
int Cb=temp2[offsetCb] & 0xff;
int Cr=temp2[offsetCb + 1] & 0xff;
for (int k=0; k < samplingFactor[1]; k++) {
for (int l=0; l < samplingFactor[0]; l++, offsetX++) {
int Y=temp2[offset++] & 0xff;
float fY=(Y - referenceBlackY) * codingRangeY / (referenceWhiteY - referenceBlackY);
float fCb=(Cb - referenceBlackCb) * codingRangeCbCr / (referenceWhiteCb - referenceBlackCb);
float fCr=(Cr - referenceBlackCr) * codingRangeCbCr / (referenceWhiteCr - referenceBlackCr);
float R=(fCr * (2 - 2 * lumaRed) + fY);
float B=(fCb * (2 - 2 * lumaBlue) + fY);
float G=((fY - lumaBlue * B - lumaRed * R) / lumaGreen);
if (R < 0) R=0;
if (R > 255) R=255;
if (G < 0) G=0;
if (G > 255) G=255;
if (B < 0) B=0;
if (B > 255) B=255;
int yPos=offsetX + offsetY * imageWidth;
int redPos=3 * yPos;
pixels[redPos]=(byte)R;
pixels[redPos + 1]=(byte)G;
pixels[redPos + 2]=(byte)B;
}
offsetX-=samplingFactor[0];
offsetY+=1;
}
offsetY-=samplingFactor[1];
offset+=2;
offsetX+=samplingFactor[0];
if (j % dataUnitsPerWidth == 0) {
offsetY+=samplingFactor[1];
offsetX=0;
}
}
}
}
 else {
}
break;
default :
}
db=new DataBufferByte(pixels,pixels.length);
bandoff=new int[]{0,1,2};
transparent=false;
numOfBands=samplesPerPixel;
trans=Transparency.OPAQUE;
nBits=new int[]{8,8,8};
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,bandoff,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
return new BufferedImage(cm,raster,false,null);
case RGB:
bytesPerScanLine=samplesPerPixel * ((imageWidth * bitsPerSample + 7) / 8);
int totalBytes2Read=imageHeight * bytesPerScanLine;
if (planaryConfiguration == 2) bytesPerScanLine=(imageWidth * bitsPerSample + 7) / 8;
pixels=new byte[totalBytes2Read];
switch (compression) {
case NONE:
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
randIS.seek(stripOffsets[i]);
randIS.readFully(pixels,offset,bytes2Read);
offset+=bytes2Read;
}
break;
case PACKBITS:
for (int i=0; i < stripByteCounts.length; i++) {
int bytes2Read=stripBytes[i];
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
byte[] temp2=new byte[bytes2Read];
Packbits.unpackbits(temp,temp2);
System.arraycopy(temp2,0,pixels,offset,bytes2Read);
offset+=bytes2Read;
}
break;
case LZW:
decoder=new LZWTreeDecoder(8,true);
break;
case DEFLATE:
case DEFLATE_ADOBE:
decoder=new DeflateDecoder();
break;
default :
}
if (decoder != null) {
pixels=new byte[stripOffsets.length * stripBytes[0]];
for (int i=0; i < stripByteCounts.length; i++) {
byte[] temp=new byte[stripByteCounts[i]];
randIS.seek(stripOffsets[i]);
randIS.readFully(temp);
decoder.setInput(temp);
int numOfBytes=decoder.decode(pixels,offset,stripBytes[i]);
offset+=numOfBytes;
}
}
if (predictor == 2) {
if (planaryConfiguration == 1) pixels=applyDePredictor(samplesPerPixel,pixels,imageWidth,imageHeight);
 else {
int dataOffset=0;
for (int k=0; k < samplesPerPixel; k++) {
applyDePredictor2(pixels,dataOffset,imageWidth,imageHeight);
dataOffset+=count[k];
}
}
}
if (bitsPerSample == 16) {
short[] spixels=ArrayUtils.byteArrayToShortArray(pixels,true);
db=new DataBufferUShort(spixels,spixels.length);
int[] off={0,1,2};
numOfBands=3;
trans=Transparency.OPAQUE;
nBits=new int[]{16,16,16};
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,off,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,false,false,trans,DataBuffer.TYPE_USHORT);
}
 else {
db=new DataBufferByte(pixels,pixels.length);
bandoff=new int[]{0,1,2};
transparent=false;
numOfBands=samplesPerPixel;
trans=Transparency.OPAQUE;
nBits=new int[]{8,8,8};
if (samplesPerPixel == 4) {
bandoff=new int[]{0,1,2,3};
nBits=new int[]{8,8,8,8};
trans=Transparency.TRANSLUCENT;
transparent=true;
}
if (planaryConfiguration == 2) {
bandoff=new int[]{0,count[0],count[0] + count[1]};
int[] bandIndices=new int[]{0,0,0};
if (samplesPerPixel == 4) {
bandoff=new int[]{0,count[0],count[0] + count[1],count[0] + count[1] + count[2]};
bandIndices=new int[]{0,0,0,0};
}
raster=Raster.createBandedRaster(db,imageWidth,imageHeight,bytesPerScanLine,bandIndices,bandoff,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
 else {
raster=Raster.createInterleavedRaster(db,imageWidth,imageHeight,imageWidth * numOfBands,numOfBands,bandoff,null);
cm=new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),nBits,transparent,false,trans,DataBuffer.TYPE_BYTE);
}
}
return new BufferedImage(cm,raster,false,null);
default :
break;
}
return null;
}