Changeset 4895


Ignore:
Timestamp:
03/09/09 14:58:08 (11 years ago)
Author:
melissa
Message:

Added methods to TiffTools that return an individual tile or strip and cleaned up some of the image retrieval logic. Closes #348.

Location:
trunk/components
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/components/bio-formats/src/loci/formats/TiffTools.java

    r4806 r4895  
    325325      Hashtable ifd = getIFD(in, ifdNum, offset, bigTiff); 
    326326      if (ifd == null || ifd.size() <= 1) break; 
    327       // if width or length entries are not present, the IFD is invalid 
    328       if (ifd.get(new Integer(IMAGE_WIDTH)) != null && 
    329         ifd.get(new Integer(IMAGE_LENGTH)) != null) 
    330       { 
    331         v.add(ifd); 
    332       } 
     327      v.add(ifd); 
    333328      offset = bigTiff ? in.readLong() : (long) (in.readInt() & 0xffffffffL); 
    334329      if (offset <= 0 || offset >= in.length()) break; 
     
    454449 
    455450    // read in directory entries for this IFD 
    456     if (DEBUG) { 
    457       debug("getIFDs: seeking IFD #" + ifdNum + " at " + offset); 
    458     } 
     451    debug("getIFDs: seeking IFD #" + ifdNum + " at " + offset); 
    459452    in.seek(offset); 
    460453    long numEntries = bigTiff ? in.readLong() : in.readShort() & 0xffff; 
    461     if (DEBUG) debug("getIFDs: " + numEntries + " directory entries to read"); 
     454    debug("getIFDs: " + numEntries + " directory entries to read"); 
    462455    if (numEntries == 0 || numEntries == 1) return ifd; 
    463456 
     
    473466      int count = bigTiff ? (int) (in.readLong() & 0xffffffff) : in.readInt(); 
    474467 
    475       if (DEBUG) { 
    476         debug("getIFDs: read " + getIFDTagName(tag) + 
    477           " (type=" + getIFDTypeName(type) + "; count=" + count + ")"); 
    478       } 
     468      debug("getIFDs: read " + getIFDTagName(tag) + 
     469        " (type=" + getIFDTypeName(type) + "; count=" + count + ")"); 
    479470      if (count < 0) return null; // invalid data 
    480471      Object value = null; 
     
    891882  } 
    892883 
     884  /** Returns the width of an image tile. */ 
     885  public static long getTileWidth(Hashtable ifd) throws FormatException { 
     886    long tileWidth = getIFDLongValue(ifd, TILE_WIDTH, false, 0); 
     887    return tileWidth == 0 ? getImageWidth(ifd) : tileWidth; 
     888  } 
     889 
     890  /** Returns the length of an image tile. */ 
     891  public static long getTileLength(Hashtable ifd) throws FormatException { 
     892    long tileLength = getIFDLongValue(ifd, TILE_LENGTH, false, 0); 
     893    return tileLength == 0 ? getRowsPerStrip(ifd)[0] : tileLength; 
     894  } 
     895 
     896  /** Returns the number of image tiles per row. */ 
     897  public static long getTilesPerRow(Hashtable ifd) throws FormatException { 
     898    long tileWidth = getTileWidth(ifd); 
     899    long imageWidth = getImageWidth(ifd); 
     900    long nTiles = imageWidth / tileWidth; 
     901    if (nTiles * tileWidth < imageWidth) nTiles++; 
     902    return nTiles; 
     903  } 
     904 
     905  /** Returns the number of image tiles per column. */ 
     906  public static long getTilesPerColumn(Hashtable ifd) throws FormatException { 
     907    long tileLength = getTileLength(ifd); 
     908    long imageLength = getImageLength(ifd); 
     909    long nTiles = imageLength / tileLength; 
     910    if (nTiles * tileLength < imageLength) nTiles++; 
     911    return nTiles; 
     912  } 
     913 
    893914  // -- Image reading methods -- 
     915 
     916  public static byte[] getTile(Hashtable ifd, RandomAccessStream in, 
     917    int row, int col) 
     918    throws FormatException, IOException 
     919  { 
     920    int samplesPerPixel = getSamplesPerPixel(ifd); 
     921    if (getPlanarConfiguration(ifd) == 2) samplesPerPixel = 1; 
     922    int bpp = getBytesPerSample(ifd)[0]; 
     923    int width = (int) getTileWidth(ifd); 
     924    int height = (int) getTileLength(ifd); 
     925    byte[] buf = new byte[width * height * samplesPerPixel * bpp]; 
     926 
     927    return getTile(ifd, in, buf, row, col); 
     928  } 
     929 
     930  public static byte[] getTile(Hashtable ifd, RandomAccessStream in, 
     931    byte[] buf, int row, int col) 
     932    throws FormatException, IOException 
     933  { 
     934    byte[] jpegTable = 
     935      (byte[]) TiffTools.getIFDValue(ifd, JPEG_TABLES, false, null); 
     936 
     937    CodecOptions options = new CodecOptions(); 
     938    options.interleaved = true; 
     939    options.littleEndian = isLittleEndian(ifd); 
     940 
     941    long tileWidth = getTileWidth(ifd); 
     942    long tileLength = getTileLength(ifd); 
     943    int samplesPerPixel = getSamplesPerPixel(ifd); 
     944    int planarConfig = getPlanarConfiguration(ifd); 
     945    int compression = getCompression(ifd); 
     946 
     947    long numTileCols = getTilesPerRow(ifd); 
     948 
     949    int pixel = getBytesPerSample(ifd)[0]; 
     950    int effectiveChannels = planarConfig == 2 ? 1 : samplesPerPixel; 
     951 
     952    long[] stripOffsets = getStripOffsets(ifd); 
     953    long[] stripByteCounts = getStripByteCounts(ifd); 
     954 
     955    int tileNumber = (int) (row * numTileCols + col); 
     956    byte[] tile = new byte[(int) stripByteCounts[tileNumber]]; 
     957    in.seek(stripOffsets[tileNumber] & 0xffffffffL); 
     958    in.read(tile); 
     959 
     960    int size = (int) (tileWidth * tileLength * pixel * effectiveChannels); 
     961    options.maxBytes = size; 
     962 
     963    if (jpegTable != null) { 
     964      byte[] q = new byte[jpegTable.length + tile.length - 4]; 
     965      System.arraycopy(jpegTable, 0, q, 0, jpegTable.length - 2); 
     966      System.arraycopy(tile, 2, q, jpegTable.length - 2, tile.length - 2); 
     967      tile = uncompress(q, compression, options); 
     968    } 
     969    else tile = uncompress(tile, compression, options); 
     970 
     971    undifference(tile, ifd); 
     972    unpackBytes(buf, 0, tile, ifd); 
     973 
     974    return buf; 
     975  } 
    894976 
    895977  /** Reads the image defined in the given IFD from the specified file. */ 
     
    898980  { 
    899981    int samplesPerPixel = getSamplesPerPixel(ifd); 
    900     int bpp = getBitsPerSample(ifd)[0]; 
    901     while ((bpp % 8) != 0) bpp++; 
    902     bpp /= 8; 
     982    int bpp = getBytesPerSample(ifd)[0]; 
    903983    long width = getImageWidth(ifd); 
    904984    long length = getImageLength(ifd); 
     
    9271007    throws FormatException, IOException 
    9281008  { 
    929     if (DEBUG) debug("parsing IFD entries"); 
     1009    debug("parsing IFD entries"); 
    9301010 
    9311011    // get internal non-IFD entries 
     
    9341014 
    9351015    // get relevant IFD entries 
    936     long imageWidth = getImageWidth(ifd); 
    937     long imageLength = getImageLength(ifd); 
    938     int[] bitsPerSample = getBitsPerSample(ifd); 
    9391016    int samplesPerPixel = getSamplesPerPixel(ifd); 
    940     int compression = getCompression(ifd); 
    941     int photoInterp = getPhotometricInterpretation(ifd); 
    942     long[] stripOffsets = getStripOffsets(ifd); 
    943     long[] stripByteCounts = getStripByteCounts(ifd); 
    944     long[] rowsPerStripArray = getRowsPerStrip(ifd); 
    945  
    946     boolean fakeByteCounts = stripByteCounts == null; 
    947     boolean fakeRPS = rowsPerStripArray == null; 
    948     boolean isTiled = stripOffsets == null || 
    949       ifd.get(new Integer(TILE_WIDTH)) != null; 
    950  
    951     long[] maxes = getIFDLongArray(ifd, MAX_SAMPLE_VALUE, false); 
    952     long maxValue = maxes == null ? 0 : maxes[0]; 
    953  
    954     if (isTiled) { 
    955       if (stripOffsets == null) { 
    956         stripOffsets = getIFDLongArray(ifd, TILE_OFFSETS, true); 
    957       } 
    958       if (stripByteCounts == null) { 
    959         stripByteCounts = getIFDLongArray(ifd, TILE_BYTE_COUNTS, true); 
    960       } 
    961       rowsPerStripArray = new long[] {imageLength}; 
    962     } 
    963     else if (fakeByteCounts) { 
    964       // technically speaking, this shouldn't happen (since TIFF writers are 
    965       // required to write the StripByteCounts tag), but we'll support it 
    966       // anyway 
    967  
    968       // don't rely on RowsPerStrip, since it's likely that if the file doesn't 
    969       // have the StripByteCounts tag, it also won't have the RowsPerStrip tag 
    970       stripByteCounts = new long[stripOffsets.length]; 
    971       if (stripByteCounts.length == 1) { 
    972         stripByteCounts[0] = imageWidth * imageLength * (bitsPerSample[0] / 8); 
    973       } 
    974       else { 
    975         stripByteCounts[0] = stripOffsets[0]; 
    976         for (int i=1; i<stripByteCounts.length; i++) { 
    977           stripByteCounts[i] = stripOffsets[i] - stripByteCounts[i-1]; 
    978         } 
    979       } 
    980     } 
    981  
    982     boolean lastBitsZero = bitsPerSample[bitsPerSample.length - 1] == 0; 
    983  
    984     if (fakeRPS && !isTiled) { 
    985       // create a false rowsPerStripArray if one is not present 
    986       // it's sort of a cheap hack, but here's how it's done: 
    987       // RowsPerStrip = stripByteCounts / (imageLength * bitsPerSample) 
    988       // since stripByteCounts and bitsPerSample are arrays, we have to 
    989       // iterate through each item 
    990  
    991       rowsPerStripArray = new long[bitsPerSample.length]; 
    992  
    993       long temp = stripByteCounts[0]; 
    994       stripByteCounts = new long[bitsPerSample.length]; 
    995       Arrays.fill(stripByteCounts, temp); 
    996       temp = bitsPerSample[0]; 
    997       if (temp == 0) temp = 8; 
    998       bitsPerSample = new int[bitsPerSample.length]; 
    999       Arrays.fill(bitsPerSample, (int) temp); 
    1000       temp = stripOffsets[0]; 
    1001  
    1002       // we have two files that reverse the endianness for BitsPerSample, 
    1003       // StripOffsets, and StripByteCounts 
    1004  
    1005       if (bitsPerSample[0] > 64) { 
    1006         bitsPerSample[0] = DataTools.swap(bitsPerSample[0]); 
    1007         stripOffsets[0] = DataTools.swap(stripOffsets[0]); 
    1008         stripByteCounts[0] = DataTools.swap(stripByteCounts[0]); 
    1009       } 
    1010  
    1011       if (rowsPerStripArray.length == 1 && stripByteCounts[0] != 
    1012         (imageWidth * imageLength * (bitsPerSample[0] / 8)) && 
    1013         compression == UNCOMPRESSED) 
    1014       { 
    1015         stripByteCounts = new long[] { 
    1016           imageWidth * imageLength * (bitsPerSample[0] / 8)}; 
    1017         stripOffsets = new long[] {stripOffsets[0]}; 
    1018       } 
    1019  
    1020       for (int i=0; i<bitsPerSample.length; i++) { 
    1021         // case 1: we're still within bitsPerSample array bounds 
    1022         if (i < bitsPerSample.length) { 
    1023           if (i == samplesPerPixel) { 
    1024             bitsPerSample[i] = 0; 
    1025             lastBitsZero = true; 
    1026           } 
    1027  
    1028           // remember that the universe collapses when we divide by 0 
    1029           if (bitsPerSample[i] != 0) { 
    1030             rowsPerStripArray[i] = (long) stripByteCounts[i] / 
    1031               (imageWidth * (bitsPerSample[i] / 8)); 
    1032           } 
    1033           else if (bitsPerSample[i] == 0 && i > 0) { 
    1034             rowsPerStripArray[i] = (long) stripByteCounts[i] / 
    1035               (imageWidth * (bitsPerSample[i - 1] / 8)); 
    1036             bitsPerSample[i] = bitsPerSample[i - 1]; 
    1037           } 
    1038           else { 
    1039             throw new FormatException("BitsPerSample is 0"); 
    1040           } 
    1041         } 
    1042         // case 2: we're outside bitsPerSample array bounds 
    1043         else if (i >= bitsPerSample.length) { 
    1044           rowsPerStripArray[i] = (long) stripByteCounts[i] / 
    1045             (imageWidth * (bitsPerSample[bitsPerSample.length - 1] / 8)); 
    1046         } 
    1047       } 
    1048  
    1049       if (compression != UNCOMPRESSED) { 
    1050         for (int i=0; i<stripByteCounts.length; i++) { 
    1051           stripByteCounts[i] *= 2; 
    1052         } 
    1053       } 
    1054     } 
    1055  
    1056     if (lastBitsZero) { 
    1057       bitsPerSample[bitsPerSample.length - 1] = 0; 
    1058     } 
    1059  
    1060     TiffRational xResolution = getIFDRationalValue(ifd, X_RESOLUTION, false); 
    1061     TiffRational yResolution = getIFDRationalValue(ifd, Y_RESOLUTION, false); 
    1062     int planarConfig = getIFDIntValue(ifd, PLANAR_CONFIGURATION, false, 1); 
    1063     int resolutionUnit = getIFDIntValue(ifd, RESOLUTION_UNIT, false, 2); 
    1064     if (xResolution == null || yResolution == null) resolutionUnit = 0; 
    1065     int[] colorMap = getIFDIntArray(ifd, COLOR_MAP, false); 
    1066     int predictor = getIFDIntValue(ifd, PREDICTOR, false, 1); 
    1067  
    1068     if (DEBUG) { 
    1069       StringBuffer sb = new StringBuffer(); 
    1070       sb.append("IFD directory entry values:"); 
    1071       sb.append("\n\tLittleEndian="); 
    1072       sb.append(littleEndian); 
    1073       sb.append("\n\tImageWidth="); 
    1074       sb.append(imageWidth); 
    1075       sb.append("\n\tImageLength="); 
    1076       sb.append(imageLength); 
    1077       sb.append("\n\tBitsPerSample="); 
    1078       sb.append(bitsPerSample[0]); 
    1079       for (int i=1; i<bitsPerSample.length; i++) { 
    1080         sb.append(","); 
    1081         sb.append(bitsPerSample[i]); 
    1082       } 
    1083       sb.append("\n\tSamplesPerPixel="); 
    1084       sb.append(samplesPerPixel); 
    1085       sb.append("\n\tCompression="); 
    1086       sb.append(compression); 
    1087       sb.append("\n\tPhotometricInterpretation="); 
    1088       sb.append(photoInterp); 
    1089       sb.append("\n\tStripOffsets="); 
    1090       sb.append(stripOffsets[0]); 
    1091       for (int i=1; i<stripOffsets.length; i++) { 
    1092         sb.append(","); 
    1093         sb.append(stripOffsets[i]); 
    1094       } 
    1095       sb.append("\n\tRowsPerStrip="); 
    1096       sb.append(rowsPerStripArray[0]); 
    1097       for (int i=1; i<rowsPerStripArray.length; i++) { 
    1098         sb.append(","); 
    1099         sb.append(rowsPerStripArray[i]); 
    1100       } 
    1101       sb.append("\n\tStripByteCounts="); 
    1102       sb.append(stripByteCounts[0]); 
    1103       for (int i=1; i<stripByteCounts.length; i++) { 
    1104         sb.append(","); 
    1105         sb.append(stripByteCounts[i]); 
    1106       } 
    1107       sb.append("\n\tXResolution="); 
    1108       sb.append(xResolution); 
    1109       sb.append("\n\tYResolution="); 
    1110       sb.append(yResolution); 
    1111       sb.append("\n\tPlanarConfiguration="); 
    1112       sb.append(planarConfig); 
    1113       sb.append("\n\tResolutionUnit="); 
    1114       sb.append(resolutionUnit); 
    1115       sb.append("\n\tColorMap="); 
    1116       if (colorMap == null) sb.append("null"); 
    1117       else { 
    1118         sb.append(colorMap[0]); 
    1119         for (int i=1; i<colorMap.length; i++) { 
    1120           sb.append(","); 
    1121           sb.append(colorMap[i]); 
    1122         } 
    1123       } 
    1124       sb.append("\n\tPredictor="); 
    1125       sb.append(predictor); 
    1126       debug(sb.toString()); 
    1127     } 
    1128  
    1129     for (int i=0; i<samplesPerPixel; i++) { 
    1130       if (bitsPerSample[i] < 1) { 
    1131         throw new FormatException("Illegal BitsPerSample (" + 
    1132           bitsPerSample[i] + ")"); 
    1133       } 
    1134       // don't support odd numbers of bits (except for 1) 
    1135       else if (bitsPerSample[i] % 2 != 0 && bitsPerSample[i] != 1) { 
    1136         throw new FormatException("Sorry, unsupported BitsPerSample (" + 
    1137           bitsPerSample[i] + ")"); 
    1138       } 
    1139     } 
    1140  
    1141     if (bitsPerSample.length < samplesPerPixel) { 
    1142       throw new FormatException("BitsPerSample length (" + 
    1143         bitsPerSample.length + ") does not match SamplesPerPixel (" + 
    1144         samplesPerPixel + ")"); 
    1145     } 
    1146     else if (photoInterp == TRANSPARENCY_MASK) { 
    1147       throw new FormatException( 
    1148         "Sorry, Transparency Mask PhotometricInterpretation is not supported"); 
    1149     } 
    1150     else if (photoInterp == CIE_LAB) { 
    1151       throw new FormatException( 
    1152         "Sorry, CIELAB PhotometricInterpretation is not supported"); 
    1153     } 
    1154     else if (photoInterp != WHITE_IS_ZERO && 
    1155       photoInterp != BLACK_IS_ZERO && photoInterp != RGB && 
    1156       photoInterp != RGB_PALETTE && photoInterp != CMYK && 
    1157       photoInterp != Y_CB_CR && photoInterp != CFA_ARRAY) 
    1158     { 
    1159       throw new FormatException("Unknown PhotometricInterpretation (" + 
    1160         photoInterp + ")"); 
    1161     } 
    1162  
    1163     // rowsPerStrip should never be more than the total number of rows 
    1164     for (int i=0; i<rowsPerStripArray.length; i++) { 
    1165       rowsPerStripArray[i] = (long) Math.min(rowsPerStripArray[i], imageLength); 
    1166     } 
    1167  
    1168     long rowsPerStrip = rowsPerStripArray[0]; 
    1169     for (int i=1; i<rowsPerStripArray.length; i++) { 
    1170       if (rowsPerStrip != rowsPerStripArray[i]) { 
    1171         throw new FormatException( 
    1172           "Sorry, non-uniform RowsPerStrip is not supported"); 
    1173       } 
    1174     } 
    1175  
    1176     if (compression == GROUP_3_FAX) Arrays.fill(bitsPerSample, 8); 
    1177     else if (compression == JPEG) photoInterp = RGB; 
    1178  
    1179     long numStrips = (imageLength + rowsPerStrip - 1) / rowsPerStrip; 
    1180  
    1181     if (isTiled || fakeRPS) numStrips = stripOffsets.length; 
    1182     if (planarConfig == 2) numStrips *= samplesPerPixel; 
    1183  
    1184     if (stripOffsets.length < numStrips && !fakeRPS) { 
    1185       throw new FormatException("StripOffsets length (" + 
    1186         stripOffsets.length + ") does not match expected " + 
    1187         "number of strips (" + numStrips + ")"); 
    1188     } 
    1189     else if (fakeRPS) numStrips = stripOffsets.length; 
    1190  
    1191     if (stripByteCounts.length < numStrips) { 
    1192       throw new FormatException("StripByteCounts length (" + 
    1193         stripByteCounts.length + ") does not match expected " + 
    1194         "number of strips (" + numStrips + ")"); 
    1195     } 
    1196  
    1197     if (width > Integer.MAX_VALUE || height > Integer.MAX_VALUE || 
    1198       width * height > Integer.MAX_VALUE) 
    1199     { 
     1017    long tileWidth = getTileWidth(ifd); 
     1018    long tileLength = getTileLength(ifd); 
     1019    long numTileRows = getTilesPerColumn(ifd); 
     1020    long numTileCols = getTilesPerRow(ifd); 
     1021 
     1022    int planarConfig = getPlanarConfiguration(ifd); 
     1023 
     1024    printIFD(ifd); 
     1025 
     1026    if (width * height > Integer.MAX_VALUE) { 
    12001027      throw new FormatException("Sorry, ImageWidth x ImageLength > " + 
    12011028        Integer.MAX_VALUE + " is not supported (" + 
     
    12041031    int numSamples = (int) (width * height); 
    12051032 
    1206     if (planarConfig != 1 && planarConfig != 2) { 
    1207       throw new FormatException( 
    1208         "Unknown PlanarConfiguration (" + planarConfig + ")"); 
    1209     } 
    1210  
    12111033    // read in image strips 
    1212     if (DEBUG) { 
    1213       debug("reading image data (samplesPerPixel=" + 
    1214         samplesPerPixel + "; numSamples=" + numSamples + ")"); 
    1215     } 
    1216  
    1217     if (photoInterp == CFA_ARRAY) { 
    1218       if (colorMap == null) { 
    1219         colorMap = getIFDIntArray(ifd, TiffTools.COLOR_MAP, false); 
    1220         if (colorMap == null) { 
    1221           colorMap = new int[4]; 
    1222           if (littleEndian) { 
    1223             colorMap[0] = 2; 
    1224             colorMap[1] = 0; 
    1225             colorMap[2] = 2; 
    1226             colorMap[3] = 0; 
     1034    debug("reading image data (samplesPerPixel=" + 
     1035      samplesPerPixel + "; numSamples=" + numSamples + ")"); 
     1036 
     1037    int pixel = getBytesPerSample(ifd)[0]; 
     1038    int effectiveChannels = planarConfig == 2 ? 1 : samplesPerPixel; 
     1039    long nrows = numTileRows; 
     1040    if (planarConfig == 2) numTileRows *= samplesPerPixel; 
     1041 
     1042    Rectangle imageBounds = new Rectangle(x, y, (int) width, 
     1043      (int) (height * (samplesPerPixel / effectiveChannels))); 
     1044 
     1045    int endX = (int) width + x; 
     1046    int endY = (int) height + y; 
     1047 
     1048    for (int row=0; row<numTileRows; row++) { 
     1049      for (int col=0; col<numTileCols; col++) { 
     1050        Rectangle tileBounds = new Rectangle(col * (int) tileWidth, 
     1051          (int) (row * tileLength), (int) tileWidth, 
     1052          (int) tileLength); 
     1053 
     1054        if (!imageBounds.intersects(tileBounds)) continue; 
     1055 
     1056        if (planarConfig == 2) { 
     1057          tileBounds.y = (int) ((row % nrows) * tileLength); 
     1058        } 
     1059 
     1060        byte[] tile = getTile(ifd, in, row, col); 
     1061 
     1062        // adjust tile bounds, if necessary 
     1063 
     1064        int tileX = (int) Math.max(tileBounds.x, x); 
     1065        int tileY = (int) Math.max(tileBounds.y, y); 
     1066        int realX = tileX % (int) tileWidth; 
     1067        int realY = tileY % (int) tileLength; 
     1068 
     1069        int twidth = (int) Math.min(endX - tileX, tileWidth - realX); 
     1070        int theight = (int) Math.min(endY - tileY, tileLength - realY); 
     1071 
     1072        // copy appropriate portion of the tile to the output buffer 
     1073 
     1074        int rowLen = pixel * (int) tileWidth; 
     1075        int copy = pixel * twidth; 
     1076        int tileSize = (int) (tileWidth * tileLength * pixel); 
     1077        int planeSize = (int) (width * height * pixel); 
     1078        int outputRowLen = (int) (pixel * width); 
     1079 
     1080        realX *= pixel; 
     1081        realY *= rowLen; 
     1082 
     1083        for (int q=0; q<effectiveChannels; q++) { 
     1084          int src = (int) (q * tileSize) + realX + realY; 
     1085          int dest = (int) (q * planeSize) + pixel * (tileX - x) + 
     1086            outputRowLen * (tileY - y); 
     1087          if (planarConfig == 2) dest += (planeSize * (row / nrows)); 
     1088          for (int tileRow=0; tileRow<theight; tileRow++) { 
     1089            System.arraycopy(tile, src, buf, dest, copy); 
     1090            src += rowLen; 
     1091            dest += outputRowLen; 
    12271092          } 
    1228           else { 
    1229             colorMap[0] = 0; 
    1230             colorMap[1] = 2; 
    1231             colorMap[2] = 0; 
    1232             colorMap[3] = 2; 
    1233           } 
    1234         } 
    1235       } 
    1236       int[] tempMap = new int[colorMap.length + 2]; 
    1237       System.arraycopy(colorMap, 0, tempMap, 0, colorMap.length); 
    1238       tempMap[tempMap.length - 2] = (int) imageWidth; 
    1239       tempMap[tempMap.length - 1] = (int) imageLength; 
    1240       colorMap = tempMap; 
    1241     } 
    1242     else if (photoInterp == Y_CB_CR) { 
    1243       colorMap = new int[5 + samplesPerPixel * 2]; 
    1244       int[] ref = getIFDIntArray(ifd, REFERENCE_BLACK_WHITE, false); 
    1245       if (ref != null) System.arraycopy(ref, 0, colorMap, 0, ref.length); 
    1246       else { 
    1247         colorMap[0] = colorMap[2] = colorMap[4] = 0; 
    1248         colorMap[1] = colorMap[3] = colorMap[5] = 255; 
    1249       } 
    1250       ref = getIFDIntArray(ifd, Y_CB_CR_SUB_SAMPLING, false); 
    1251       if (ref == null) ref = new int[] {2, 2}; 
    1252       System.arraycopy(ref, 0, colorMap, samplesPerPixel * 2, ref.length); 
    1253       TiffRational[] coeffs = 
    1254         (TiffRational[]) getIFDValue(ifd, Y_CB_CR_COEFFICIENTS); 
    1255       if (coeffs != null) { 
    1256         for (int i=0; i<coeffs.length; i++) { 
    1257           colorMap[colorMap.length - coeffs.length + i] = (int) (10000 * 
    1258             ((float) coeffs[i].getNumerator() / coeffs[i].getDenominator())); 
    1259         } 
    1260       } 
    1261       else { 
    1262         colorMap[colorMap.length - 3] = 2990; 
    1263         colorMap[colorMap.length - 2] = 5870; 
    1264         colorMap[colorMap.length - 1] = 1140; 
    1265       } 
    1266     } 
    1267  
    1268     if (stripOffsets.length > 1 && (stripOffsets[stripOffsets.length - 1] == 
    1269       stripOffsets[stripOffsets.length - 2])) 
    1270     { 
    1271       long[] tmp = stripOffsets; 
    1272       stripOffsets = new long[tmp.length - 1]; 
    1273       System.arraycopy(tmp, 0, stripOffsets, 0, stripOffsets.length); 
    1274       numStrips--; 
    1275     } 
    1276  
    1277     byte[] jpegTable = null; 
    1278     if (compression == JPEG) { 
    1279       jpegTable = (byte[]) TiffTools.getIFDValue(ifd, JPEG_TABLES); 
    1280     } 
    1281  
    1282     CodecOptions options = new CodecOptions(); 
    1283     options.interleaved = true; 
    1284     options.littleEndian = littleEndian; 
    1285  
    1286     if (isTiled) { 
    1287       long tileWidth = getIFDLongValue(ifd, TILE_WIDTH, true, 0); 
    1288       long tileLength = getIFDLongValue(ifd, TILE_LENGTH, true, 0); 
    1289  
    1290       int numTileRows = (int) (imageLength / tileLength); 
    1291       if (numTileRows * tileLength < imageLength) numTileRows++; 
    1292  
    1293       int numTileCols = (int) (imageWidth / tileWidth); 
    1294       if (numTileCols * tileWidth < imageWidth) numTileCols++; 
    1295  
    1296       Rectangle imageBounds = new Rectangle(x, y, (int) width, (int) height); 
    1297       int endX = (int) width + x; 
    1298       int endY = (int) height + y; 
    1299       int pixel = (int) bitsPerSample[0] / 8; 
    1300       int channels = 1; 
    1301       if (planarConfig != 2) channels = samplesPerPixel; 
    1302       else pixel *= samplesPerPixel; 
    1303  
    1304       for (int row=0; row<numTileRows; row++) { 
    1305         for (int col=0; col<numTileCols; col++) { 
    1306           Rectangle tileBounds = new Rectangle(col * (int) tileWidth, 
    1307             row * (int) tileLength, (int) tileWidth, (int) tileLength); 
    1308  
    1309           if (!imageBounds.intersects(tileBounds)) continue; 
    1310  
    1311           int tileNumber = row * numTileCols + col; 
    1312           byte[] tile = new byte[(int) stripByteCounts[tileNumber]]; 
    1313  
    1314           in.seek(stripOffsets[tileNumber] & 0xffffffffL); 
    1315           in.read(tile); 
    1316  
    1317           int size = (int) (tileWidth * tileLength * pixel * channels); 
    1318           options.maxBytes = size; 
    1319           if (jpegTable != null) { 
    1320             byte[] q = new byte[jpegTable.length + tile.length - 4]; 
    1321             System.arraycopy(jpegTable, 0, q, 0, jpegTable.length - 2); 
    1322             System.arraycopy(tile, 2, q, jpegTable.length - 2, tile.length - 2); 
    1323             tile = uncompress(q, compression, options); 
    1324           } 
    1325           else tile = uncompress(tile, compression, options); 
    1326  
    1327           undifference(tile, bitsPerSample, tileWidth, planarConfig, predictor, 
    1328             littleEndian); 
    1329           byte[] t = new byte[size]; 
    1330           unpackBytes(t, 0, tile, bitsPerSample, photoInterp, colorMap, 
    1331             littleEndian, maxValue, planarConfig, 0, 1, tileWidth); 
    1332  
    1333           // adjust tile bounds, if necessary 
    1334  
    1335           int tileX = (int) Math.max(tileBounds.x, x); 
    1336           int tileY = (int) Math.max(tileBounds.y, y); 
    1337  
    1338           int realX = tileX % (int) tileWidth; 
    1339           int realY = tileY % (int) tileLength; 
    1340  
    1341           int twidth = (int) Math.min(endX - tileX, tileWidth - realX); 
    1342           int theight = (int) Math.min(endY - tileY, tileLength - realY); 
    1343  
    1344           // copy appropriate portion of the tile to the output buffer 
    1345  
    1346           int rowLen = pixel * (int) tileWidth; 
    1347           int copy = pixel * twidth; 
    1348           int tileSize = (int) (tileWidth * tileLength * pixel); 
    1349           int planeSize = (int) (width * height * pixel); 
    1350           for (int q=0; q<channels; q++) { 
    1351             for (int tileRow=0; tileRow<theight; tileRow++) { 
    1352               int src = q * tileSize + (realY + tileRow) * rowLen + 
    1353                 realX * pixel; 
    1354               int dest = (int) (q * planeSize + 
    1355                 (tileY - y + tileRow) * width * pixel + (tileX - x) * pixel); 
    1356               System.arraycopy(t, src, buf, dest, copy); 
    1357             } 
    1358           } 
    1359         } 
    1360       } 
    1361     } 
    1362     else { 
    1363       int offset = 0; 
    1364  
    1365       if (rowsPerStrip <= 0 || numStrips <= 0) { 
    1366         numStrips = 1; 
    1367         rowsPerStrip = (int) imageLength; 
    1368       } 
    1369  
    1370       for (int strip=0, row=0; strip<numStrips; row+=rowsPerStrip, strip++) { 
    1371         if (((row % imageLength) + rowsPerStrip < y) || 
    1372           ((row % imageLength) >= y + height)) 
    1373         { 
    1374           continue; 
    1375         } 
    1376  
    1377         try { 
    1378           int size = (int) imageWidth * (bitsPerSample[0] / 8); 
    1379           if (planarConfig != 2) size *= samplesPerPixel; 
    1380           int nRows = (int) rowsPerStrip; 
    1381           if ((row % imageLength) < y) nRows -= (y - (row % imageLength)); 
    1382           if ((row % imageLength) + rowsPerStrip > y + height) { 
    1383             nRows -= ((row % imageLength) + rowsPerStrip - height - y); 
    1384           } 
    1385           size *= rowsPerStrip; 
    1386  
    1387           if (DEBUG) debug("reading image strip #" + strip); 
    1388           if (stripOffsets[strip] < 0) { 
    1389             stripOffsets[strip] = (long) (stripOffsets[strip] & 0xffffffffL); 
    1390           } 
    1391           in.seek(stripOffsets[strip]); 
    1392  
    1393           if (stripByteCounts[strip] > Integer.MAX_VALUE) { 
    1394             throw new FormatException("Sorry, StripByteCounts > " + 
    1395               Integer.MAX_VALUE + " is not supported"); 
    1396           } 
    1397           byte[] bytes = new byte[(int) stripByteCounts[strip]]; 
    1398           in.read(bytes); 
    1399           options.maxBytes = size; 
    1400           if (jpegTable != null) { 
    1401             byte[] q = new byte[jpegTable.length + bytes.length - 4]; 
    1402             System.arraycopy(jpegTable, 0, q, 0, jpegTable.length - 2); 
    1403             System.arraycopy(bytes, 2, q, jpegTable.length - 2, 
    1404               bytes.length - 2); 
    1405             bytes = uncompress(q, compression, options); 
    1406           } 
    1407           else bytes = uncompress(bytes, compression, options); 
    1408  
    1409           undifference(bytes, bitsPerSample, 
    1410             imageWidth, planarConfig, predictor, littleEndian); 
    1411  
    1412           if (x != 0 || width != imageWidth || y != 0 || 
    1413             height != imageLength) 
    1414           { 
    1415             byte[] tmp = bytes; 
    1416             int extra = (int) bitsPerSample[0] / 8; 
    1417             if (planarConfig != 2) extra *= samplesPerPixel; 
    1418             int rowLen = (int) width * extra; 
    1419             int srcRowLen = (int) imageWidth * extra; 
    1420             bytes = new byte[(int) (nRows * extra * width)]; 
    1421  
    1422             int startRow = (row % imageLength) < y ? 
    1423               (int) (y - (row % imageLength)) : 0; 
    1424             int endRow = (int) ((row % imageLength) + rowsPerStrip > 
    1425               y + height ?  y + height - (row % imageLength) : rowsPerStrip); 
    1426             for (int n=startRow; n<endRow; n++) { 
    1427               int srcOffset = n * srcRowLen + x * extra; 
    1428               System.arraycopy(tmp, srcOffset, bytes, 
    1429                 (n - startRow) * rowLen, rowLen); 
    1430             } 
    1431             nRows = endRow - startRow; 
    1432           } 
    1433  
    1434           unpackBytes(buf, offset, bytes, bitsPerSample, 
    1435             photoInterp, colorMap, littleEndian, maxValue, planarConfig, 
    1436             strip, (int) numStrips, width); 
    1437           int div = bitsPerSample[0] / 8; 
    1438           if (div == 0) div = 1; 
    1439           if (bitsPerSample[0] % 8 != 0) div++; 
    1440           if (planarConfig != 2) div *= samplesPerPixel; 
    1441           offset += bytes.length / div; 
    1442         } 
    1443         catch (Exception e) { 
    1444           // CTR TODO - eliminate catch-all exception handling 
    1445           if (strip == 0) { 
    1446             if (e instanceof FormatException) throw (FormatException) e; 
    1447             else throw new FormatException(e); 
    1448           } 
    1449           byte[] bytes = new byte[numSamples]; 
    1450           undifference(bytes, bitsPerSample, imageWidth, planarConfig, 
    1451             predictor, littleEndian); 
    1452           offset = (int) (imageWidth * row); 
    1453           unpackBytes(buf, offset, bytes, bitsPerSample, photoInterp, 
    1454             colorMap, littleEndian, maxValue, planarConfig, 
    1455             strip, (int) numStrips, imageWidth); 
    14561093        } 
    14571094      } 
     
    14691106   */ 
    14701107  public static void planarUnpack(byte[] samples, int startIndex, 
    1471     byte[] bytes, int[] bitsPerSample, int photoInterp, boolean littleEndian, 
    1472     int strip, int numStrips) throws FormatException 
    1473   { 
    1474     int numChannels = bitsPerSample.length; 
    1475     int numSamples = samples.length / numChannels; 
    1476     if (bitsPerSample[bitsPerSample.length - 1] == 0) numChannels--; 
    1477  
    1478     // determine which channel the strip belongs to 
    1479  
    1480     if (numStrips < numChannels) numStrips = numChannels; 
    1481     int channelNum = strip / (numStrips / numChannels); 
    1482  
     1108    byte[] bytes, Hashtable ifd) 
     1109    throws FormatException 
     1110  { 
    14831111    BitBuffer bb = new BitBuffer(bytes); 
    14841112 
    1485     int index = 0; 
    1486     int counter = 0; 
    1487     int numBytes = bitsPerSample[0] / 8; 
    1488     if (bitsPerSample[0] % 8 != 0) numBytes++; 
     1113    int numBytes = getBytesPerSample(ifd)[0]; 
    14891114    int realBytes = numBytes; 
    14901115    if (numBytes == 3) numBytes++; 
    14911116 
     1117    int bitsPerSample = getBitsPerSample(ifd)[0]; 
     1118    boolean littleEndian = isLittleEndian(ifd); 
     1119    int photoInterp = getPhotometricInterpretation(ifd); 
     1120 
    14921121    for (int j=0; j<bytes.length / realBytes; j++) { 
    1493       int value = bb.getBits(bitsPerSample[0]); 
     1122      int value = bb.getBits(bitsPerSample); 
    14941123 
    14951124      if (photoInterp == WHITE_IS_ZERO) { 
    1496         value = (int) (Math.pow(2, bitsPerSample[0]) - 1 - value); 
     1125        value = (int) (Math.pow(2, bitsPerSample) - 1 - value); 
    14971126      } 
    14981127      else if (photoInterp == CMYK) { 
     
    15141143   */ 
    15151144  public static void unpackBytes(byte[] samples, int startIndex, 
    1516     byte[] bytes, int[] bitsPerSample, int photoInterp, int[] colorMap, 
    1517     boolean littleEndian, long maxValue, int planar, int strip, int numStrips, 
    1518     long imageWidth) throws FormatException 
    1519   { 
    1520     if (planar == 2) { 
    1521       planarUnpack(samples, startIndex, bytes, bitsPerSample, photoInterp, 
    1522         littleEndian, strip, numStrips); 
     1145    byte[] bytes, Hashtable ifd) 
     1146    throws FormatException 
     1147  { 
     1148    if (getPlanarConfiguration(ifd) == 2) { 
     1149      planarUnpack(samples, startIndex, bytes, ifd); 
    15231150      return; 
    15241151    } 
    15251152 
    1526     int nSamples = samples.length / bitsPerSample.length; 
     1153    int photoInterp = getPhotometricInterpretation(ifd); 
     1154    int[] bitsPerSample = getBitsPerSample(ifd); 
    15271155    int nChannels = bitsPerSample.length; 
     1156    int nSamples = samples.length / nChannels; 
    15281157 
    15291158    int totalBits = 0; 
    1530     for (int i=0; i<bitsPerSample.length; i++) totalBits += bitsPerSample[i]; 
     1159    for (int i=0; i<nChannels; i++) totalBits += bitsPerSample[i]; 
    15311160    int sampleCount = 8 * bytes.length / totalBits; 
    15321161    if (photoInterp == Y_CB_CR) sampleCount *= 3; 
    15331162 
    1534     if (DEBUG) { 
    1535       debug("unpacking " + sampleCount + " samples (startIndex=" + startIndex + 
    1536         "; totalBits=" + totalBits + "; numBytes=" + bytes.length + ")"); 
    1537     } 
     1163    debug("unpacking " + sampleCount + " samples (startIndex=" + startIndex + 
     1164      "; totalBits=" + totalBits + "; numBytes=" + bytes.length + ")"); 
     1165 
     1166    long imageWidth = getImageWidth(ifd); 
    15381167 
    15391168    int bps0 = bitsPerSample[0]; 
    1540     int numBytes = bps0 / 8; 
     1169    int numBytes = getBytesPerSample(ifd)[0]; 
     1170 
    15411171    boolean noDiv8 = bps0 % 8 != 0; 
    15421172    boolean bps8 = bps0 == 8; 
    1543     boolean bps16 = bps0 == 16; 
    1544  
    1545     if (photoInterp == CFA_ARRAY) { 
    1546       imageWidth = colorMap[colorMap.length - 2]; 
    1547     } 
    1548  
    1549     int row = 0, col = 0; 
    1550  
    1551     if (imageWidth != 0) row = startIndex / (int) imageWidth; 
    1552  
    1553     int cw = 0; 
    1554     int ch = 0; 
    1555  
    1556     if (photoInterp == CFA_ARRAY) { 
    1557       byte[] c = new byte[2]; 
    1558       c[0] = (byte) colorMap[0]; 
    1559       c[1] = (byte) colorMap[1]; 
    1560  
    1561       cw = DataTools.bytesToInt(c, littleEndian); 
    1562       c[0] = (byte) colorMap[2]; 
    1563       c[1] = (byte) colorMap[3]; 
    1564       ch = DataTools.bytesToInt(c, littleEndian); 
    1565  
    1566       int[] tmp = colorMap; 
    1567       colorMap = new int[tmp.length - 6]; 
    1568       System.arraycopy(tmp, 6, colorMap, 0, colorMap.length); 
    1569     } 
    1570  
    1571     int index = 0; 
     1173 
     1174    int row = startIndex / (int) imageWidth; 
     1175    int col = 0; 
     1176 
     1177    int cw = 0, ch = 0; 
     1178 
     1179    boolean littleEndian = isLittleEndian(ifd); 
     1180 
     1181    int[] reference = getIFDIntArray(ifd, REFERENCE_BLACK_WHITE, false); 
     1182    int[] subsampling = getIFDIntArray(ifd, Y_CB_CR_SUB_SAMPLING, false); 
     1183    TiffRational[] coefficients = 
     1184      (TiffRational[]) getIFDValue(ifd, Y_CB_CR_COEFFICIENTS); 
     1185 
    15721186    int count = 0; 
    15731187 
    15741188    BitBuffer bb = new BitBuffer(bytes); 
    1575  
    1576     byte[] copyByteArray = new byte[numBytes]; 
    15771189 
    15781190    for (int j=0; j<sampleCount; j++) { 
    15791191      for (int i=0; i<nChannels; i++) { 
     1192        int index = numBytes * (j * nChannels + i); 
    15801193        int ndx = startIndex + j; 
    1581         if (i * nSamples + ndx >= (i + 1) * nSamples) { 
     1194        if (ndx >= nSamples) { 
    15821195          break; 
    15831196        } 
     1197        int outputIndex = i * nSamples + ndx * numBytes; 
    15841198 
    15851199        if (noDiv8) { 
     
    16011215          } 
    16021216 
    1603           if (i*nSamples + (ndx + 1)*(numBytes + 1) <= samples.length) { 
    1604             DataTools.unpackBytes(s, samples, 
    1605               i*nSamples + ndx*(numBytes + 1), numBytes + 1, littleEndian); 
     1217          if (outputIndex + numBytes + 1 <= samples.length) { 
     1218            DataTools.unpackBytes(s, samples, outputIndex, 
     1219              numBytes + 1, littleEndian); 
    16061220          } 
    16071221        } 
     
    16091223          // special case handles 8-bit data more quickly 
    16101224 
    1611           if (i*nSamples + ndx >= samples.length) break; 
     1225          if (outputIndex >= samples.length) break; 
    16121226 
    16131227          if (photoInterp != Y_CB_CR) { 
    1614             samples[i*nSamples + ndx] = (byte) (bytes[index++] & 0xff); 
     1228            samples[outputIndex] = (byte) (bytes[index] & 0xff); 
    16151229          } 
    16161230 
    16171231          if (photoInterp == WHITE_IS_ZERO) { // invert color value 
    1618             samples[i*nSamples + ndx] = 
    1619               (byte) (255 - samples[i*nSamples + ndx]); 
     1232            samples[outputIndex] = (byte) (255 - samples[outputIndex]); 
    16201233          } 
    16211234          else if (photoInterp == CMYK) { 
    1622             samples[i*nSamples + ndx] = 
    1623               (byte) (Integer.MAX_VALUE - samples[i*nSamples + ndx]); 
     1235            samples[outputIndex] = 
     1236              (byte) (Integer.MAX_VALUE - samples[outputIndex]); 
    16241237          } 
    16251238          else if (photoInterp == Y_CB_CR) { 
    16261239            if (i == bitsPerSample.length - 1) { 
    1627               float lumaRed = (float) colorMap[colorMap.length - 3]; 
    1628               float lumaGreen = (float) colorMap[colorMap.length - 2]; 
    1629               float lumaBlue = (float) colorMap[colorMap.length - 1]; 
    1630               lumaRed /= 10000; 
    1631               lumaGreen /= 10000; 
    1632               lumaBlue /= 10000; 
    1633  
    1634               int subX = colorMap[colorMap.length - 5]; 
    1635               int subY = colorMap[colorMap.length - 4]; 
     1240              float lumaRed = 0.299f; 
     1241              float lumaGreen = 0.587f; 
     1242              float lumaBlue = 0.114f; 
     1243              if (coefficients != null) { 
     1244                lumaRed = coefficients[0].floatValue(); 
     1245                lumaGreen = coefficients[1].floatValue(); 
     1246                lumaBlue = coefficients[2].floatValue(); 
     1247              } 
     1248 
     1249              int subX = subsampling == null ? 2 : subsampling[0]; 
     1250              int subY = subsampling == null ? 2 : subsampling[1]; 
    16361251 
    16371252              int block = subX * subY; 
     
    16431258              int tile = ndx / block; 
    16441259              int pixel = ndx % block; 
    1645               long r = subY * (tile / (imageWidth / subX)) + (pixel / subX); 
    1646               long c = subX * (tile % (imageWidth / subX)) + (pixel % subX); 
     1260              int nTiles = (int) (imageWidth / subX); 
     1261              long r = subY * (tile / nTiles) + (pixel / subX); 
     1262              long c = subX * (tile % nTiles) + (pixel % subX); 
    16471263 
    16481264              int idx = (int) (r * imageWidth + c); 
    16491265 
    16501266              if (idx < nSamples) { 
    1651                 int y = (bytes[lumaIndex] & 0xff) - colorMap[0]; 
    1652                 int cb = (bytes[chromaIndex] & 0xff) - colorMap[2]; 
    1653                 int cr = (bytes[chromaIndex + 1] & 0xff) - colorMap[4]; 
     1267                int y = (bytes[lumaIndex] & 0xff) - reference[0]; 
     1268                int cb = (bytes[chromaIndex] & 0xff) - reference[2]; 
     1269                int cr = (bytes[chromaIndex + 1] & 0xff) - reference[4]; 
    16541270 
    16551271                int red = (int) (cr * (2 - 2 * lumaRed) + y); 
     
    16651281          } 
    16661282        }  // End if (bps8) 
    1667         else if (bps16) { 
    1668           int nioIndex = 
    1669             numBytes + index < bytes.length ? index : bytes.length - numBytes; 
    1670           short v = DataTools.bytesToShort(bytes, nioIndex, 2, littleEndian); 
    1671           index += numBytes; 
     1283        else { 
     1284          int offset = numBytes + index < bytes.length ? 
     1285            index : bytes.length - numBytes; 
     1286          long v = DataTools.bytesToLong(bytes, offset, numBytes, littleEndian); 
    16721287 
    16731288          if (photoInterp == WHITE_IS_ZERO) { // invert color value 
    16741289            long max = (long) Math.pow(2, numBytes * 8) - 1; 
    1675             v = (short) (max - v); 
    1676           } 
    1677           else if (photoInterp == CMYK) { 
    1678             v = (short) (Integer.MAX_VALUE - v); 
    1679           } 
    1680           if (ndx*2 >= nSamples) break; 
    1681           DataTools.unpackShort(v, samples, i*nSamples + ndx*2, littleEndian); 
    1682         }  // End if (bps16) 
    1683         else { 
    1684           if (numBytes + index < bytes.length) { 
    1685             System.arraycopy(bytes, index, copyByteArray, 0, numBytes); 
    1686           } 
    1687           else { 
    1688             System.arraycopy(bytes, bytes.length - numBytes, copyByteArray, 
    1689               0, numBytes); 
    1690           } 
    1691           index += numBytes; 
    1692           long v = DataTools.bytesToLong(copyByteArray, littleEndian); 
    1693  
    1694           if (photoInterp == WHITE_IS_ZERO) { // invert color value 
    1695             long max = 1; 
    1696             for (int q=0; q<numBytes; q++) max *= 8; 
    16971290            v = max - v; 
    16981291          } 
     
    17101303  // -- Decompression methods -- 
    17111304 
     1305  /** Returns true if the given decompression scheme is supported. */ 
     1306  public static boolean isSupportedDecompression(int decompression) { 
     1307    return decompression == UNCOMPRESSED || decompression == LZW || 
     1308      decompression == JPEG || decompression == ALT_JPEG || 
     1309      decompression == JPEG_2000 || decompression == PACK_BITS || 
     1310      decompression == PROPRIETARY_DEFLATE || decompression == DEFLATE || 
     1311      decompression == NIKON || decompression == LURAWAVE; 
     1312  } 
     1313 
    17121314  /** Decodes a strip of data compressed with the given compression scheme. */ 
    17131315  public static byte[] uncompress(byte[] input, int compression, 
     
    17161318  { 
    17171319    if (compression < 0) compression += 65536; 
     1320 
     1321    if (!isSupportedDecompression(compression)) { 
     1322      String compressionName = getCodecName(compression); 
     1323      String message = null; 
     1324      if (compressionName != null) { 
     1325        message = 
     1326          "Sorry, " + compressionName + " compression mode is not supported"; 
     1327      } 
     1328      else message = "Unknown Compression type (" + compression + ")"; 
     1329      throw new FormatException(message); 
     1330    } 
     1331 
     1332    Codec codec = null; 
     1333 
    17181334    if (compression == UNCOMPRESSED) return input; 
    1719     else if (compression == CCITT_1D) { 
    1720       throw new FormatException( 
    1721         "Sorry, CCITT Group 3 1-Dimensional Modified Huffman " + 
    1722         "run length encoding compression mode is not supported"); 
    1723     } 
    1724     else if (compression == GROUP_3_FAX) { 
    1725       //return new T4FaxCodec().decompress(input); 
    1726       throw new FormatException("Sorry, CCITT T.4 bi-level encoding " + 
    1727         "(Group 3 Fax) compression mode is not supported"); 
    1728     } 
    1729     else if (compression == GROUP_4_FAX) { 
    1730       throw new FormatException("Sorry, CCITT T.6 bi-level encoding " + 
    1731         "(Group 4 Fax) compression mode is not supported"); 
    1732     } 
    1733     else if (compression == LZW) { 
    1734       return new LZWCodec().decompress(input, options); 
    1735     } 
     1335    else if (compression == LZW) codec = new LZWCodec(); 
    17361336    else if (compression == JPEG || compression == ALT_JPEG) { 
    1737       return new JPEGCodec().decompress(input, options); 
    1738     } 
    1739     else if (compression == JPEG_2000) { 
    1740       return new JPEG2000Codec().decompress(input, options); 
    1741     } 
    1742     else if (compression == PACK_BITS) { 
    1743       return new PackbitsCodec().decompress(input, options); 
    1744     } 
     1337      codec = new JPEGCodec(); 
     1338    } 
     1339    else if (compression == JPEG_2000) codec = new JPEG2000Codec(); 
     1340    else if (compression == PACK_BITS) codec = new PackbitsCodec(); 
    17451341    else if (compression == PROPRIETARY_DEFLATE || compression == DEFLATE) { 
    1746       return new ZlibCodec().decompress(input, options); 
    1747     } 
    1748     else if (compression == THUNDERSCAN) { 
    1749       throw new FormatException("Sorry, " + 
    1750         "Thunderscan compression mode is not supported"); 
    1751     } 
    1752     else if (compression == NIKON) { 
    1753       return new NikonCodec().decompress(input, options); 
    1754     } 
    1755     else if (compression == LURAWAVE) { 
    1756       return new LuraWaveCodec().decompress(input, options); 
    1757     } 
    1758     else { 
    1759       throw new FormatException( 
    1760         "Unknown Compression type (" + compression + ")"); 
    1761     } 
     1342      codec = new ZlibCodec(); 
     1343    } 
     1344    else if (compression == NIKON) codec = new NikonCodec(); 
     1345    else if (compression == LURAWAVE) codec = new LuraWaveCodec(); 
     1346    if (codec != null) return codec.decompress(input, options); 
     1347    throw new FormatException("Unhandled compression (" + compression + ")"); 
    17621348  } 
    17631349 
    17641350  /** Undoes in-place differencing according to the given predictor value. */ 
    1765   public static void undifference(byte[] input, int[] bitsPerSample, 
    1766     long width, int planarConfig, int predictor, boolean little) 
     1351  public static void undifference(byte[] input, Hashtable ifd) 
    17671352    throws FormatException 
    17681353  { 
     1354    int predictor = getIFDIntValue(ifd, PREDICTOR, false, 1); 
    17691355    if (predictor == 2) { 
    1770       if (DEBUG) debug("reversing horizontal differencing"); 
     1356      debug("reversing horizontal differencing"); 
     1357      int[] bitsPerSample = getBitsPerSample(ifd); 
    17711358      int len = bitsPerSample.length; 
     1359      long width = getImageWidth(ifd); 
     1360      boolean little = isLittleEndian(ifd); 
     1361      int planarConfig = getPlanarConfiguration(ifd); 
     1362 
    17721363      if (planarConfig == 2 || bitsPerSample[len - 1] == 0) len = 1; 
    17731364      if (bitsPerSample[0] <= 8) { 
     
    20541645    int ifd, int tag, Object value) throws FormatException, IOException 
    20551646  { 
    2056     if (DEBUG) { 
    2057       debug("overwriteIFDValue (ifd=" + ifd + "; tag=" + tag + "; value=" + 
    2058         value + ")"); 
    2059     } 
     1647    debug("overwriteIFDValue (ifd=" + ifd + "; tag=" + tag + "; value=" + 
     1648      value + ")"); 
    20601649    byte[] header = new byte[4]; 
    20611650    raf.seek(0); 
     
    21221711        } 
    21231712        boolean terminate = false; 
    2124         if (DEBUG) { 
    2125           debug("overwriteIFDValue:\n\told: (tag=" + oldTag + "; type=" + 
    2126             oldType + "; count=" + oldCount + "; offset=" + oldOffset + 
    2127             ");\n\tnew: (tag=" + newTag + "; type=" + newType + "; count=" + 
    2128             newCount + "; offset=" + newOffset + ")"); 
    2129         } 
     1713        debug("overwriteIFDValue:\n\told: (tag=" + oldTag + "; type=" + 
     1714          oldType + "; count=" + oldCount + "; offset=" + oldOffset + 
     1715          ");\n\tnew: (tag=" + newTag + "; type=" + newType + "; count=" + 
     1716          newCount + "; offset=" + newOffset + ")"); 
    21301717 
    21311718        // determine the best way to overwrite the old entry 
     
    21331720          // new entry is inline; if old entry wasn't, old data is orphaned 
    21341721          // do not override new offset value since data is inline 
    2135           if (DEBUG) debug("overwriteIFDValue: new entry is inline"); 
     1722          debug("overwriteIFDValue: new entry is inline"); 
    21361723        } 
    21371724        else if (oldOffset + 
     
    21411728          newOffset = oldOffset; 
    21421729          terminate = true; 
    2143           if (DEBUG) debug("overwriteIFDValue: old entry is at EOF"); 
     1730          debug("overwriteIFDValue: old entry is at EOF"); 
    21441731        } 
    21451732        else if (newCount <= oldCount) { 
    21461733          // new entry is as small or smaller than old entry; overwrite it 
    21471734          newOffset = oldOffset; 
    2148           if (DEBUG) debug("overwriteIFDValue: new entry is <= old entry"); 
     1735          debug("overwriteIFDValue: new entry is <= old entry"); 
    21491736        } 
    21501737        else { 
    21511738          // old entry was elsewhere; append to EOF, orphaning old entry 
    21521739          newOffset = raf.length(); 
    2153           if (DEBUG) debug("overwriteIFDValue: old entry will be orphaned"); 
     1740          debug("overwriteIFDValue: old entry will be orphaned"); 
    21541741        } 
    21551742 
     
    22011788  { 
    22021789    if (img == null) throw new FormatException("Image is null"); 
    2203     if (DEBUG) debug("writeImage (offset=" + offset + "; last=" + last + ")"); 
     1790    debug("writeImage (offset=" + offset + "; last=" + last + ")"); 
    22041791 
    22051792    boolean little = isLittleEndian(ifd); 
     
    22831870 
    22841871    // compress strips according to given differencing and compression schemes 
    2285     int planarConfig = getIFDIntValue(ifd, PLANAR_CONFIGURATION, false, 1); 
     1872    int planarConfig = getPlanarConfiguration(ifd); 
    22861873    int predictor = getIFDIntValue(ifd, PREDICTOR, false, 1); 
    22871874 
     
    23071894    if (ifd.containsKey(new Integer(BIG_TIFF))) keyCount--; 
    23081895 
    2309     int ifdBytes = (bigTiff ? 16 : 6) + (bigTiff ? 20 : 12) * keyCount; 
     1896    int bytesPerEntry = bigTiff ? BIG_TIFF_BYTES_PER_ENTRY : BYTES_PER_ENTRY; 
     1897    int ifdBytes = (bigTiff ? 16 : 6) + bytesPerEntry * keyCount; 
     1898 
    23101899    long pixelBytes = 0; 
    23111900    for (int i=0; i<stripsPerImage; i++) { 
     
    23361925      if (((Integer) key).intValue() == BIG_TIFF) continue; 
    23371926      Object value = ifd.get(key); 
    2338       if (DEBUG) { 
    2339         String sk = getIFDTagName(((Integer) key).intValue()); 
    2340         String sv = value instanceof int[] ? 
    2341           ("int[" + ((int[]) value).length + "]") : value.toString(); 
    2342         debug("writeImage: writing " + sk + " (value=" + sv + ")"); 
    2343       } 
     1927      String sk = getIFDTagName(((Integer) key).intValue()); 
     1928      String sv = value instanceof int[] ? 
     1929        ("int[" + ((int[]) value).length + "]") : value.toString(); 
     1930      debug("writeImage: writing " + sk + " (value=" + sv + ")"); 
    23441931      writeIFDValue(ifdOut, extraBuf, extraOut, offset, 
    23451932        ((Integer) key).intValue(), value, bigTiff, little); 
     
    23681955  } 
    23691956 
     1957  // -- Tag retrieval methods -- 
     1958 
     1959  public static boolean isTiled(Hashtable ifd) throws FormatException { 
     1960    Object offsets = ifd.get(new Integer(STRIP_OFFSETS)); 
     1961    Object tileWidth = ifd.get(new Integer(TILE_WIDTH)); 
     1962    return offsets == null || tileWidth != null; 
     1963  } 
     1964 
    23701965  /** 
    23711966   * Retrieves the image's width (TIFF tag ImageWidth) from a given TIFF IFD. 
     
    23751970   */ 
    23761971  public static long getImageWidth(Hashtable ifd) throws FormatException { 
    2377     return getIFDLongValue(ifd, IMAGE_WIDTH, true, 0); 
     1972    long width = getIFDLongValue(ifd, IMAGE_WIDTH, true, 0); 
     1973    if (width > Integer.MAX_VALUE) { 
     1974      throw new FormatException("Sorry, ImageWidth > " + Integer.MAX_VALUE + 
     1975        " is not supported."); 
     1976    } 
     1977    return width; 
    23781978  } 
    23791979 
     
    23851985   */ 
    23861986  public static long getImageLength(Hashtable ifd) throws FormatException { 
    2387     return getIFDLongValue(ifd, IMAGE_LENGTH, true, 0); 
     1987    long length = getIFDLongValue(ifd, IMAGE_LENGTH, true, 0); 
     1988    if (length > Integer.MAX_VALUE) { 
     1989      throw new FormatException("Sorry, ImageLength > " + Integer.MAX_VALUE + 
     1990        " is not supported."); 
     1991    } 
     1992    return length; 
    23881993  } 
    23891994 
     
    24002005    int[] bitsPerSample = getIFDIntArray(ifd, BITS_PER_SAMPLE, false); 
    24012006    if (bitsPerSample == null) bitsPerSample = new int[] {1}; 
     2007 
     2008    int samplesPerPixel = getSamplesPerPixel(ifd); 
     2009    if (bitsPerSample.length < samplesPerPixel) { 
     2010      throw new FormatException("BitsPerSample length (" + 
     2011        bitsPerSample.length + ") does not match SamplesPerPixel (" + 
     2012        samplesPerPixel + ")"); 
     2013    } 
     2014    int nSamples = (int) Math.min(bitsPerSample.length, samplesPerPixel); 
     2015    for (int i=0; i<nSamples; i++) { 
     2016      if (bitsPerSample[i] < 1) { 
     2017        throw new FormatException("Illegal BitsPerSample (" + 
     2018          bitsPerSample[i] + ")"); 
     2019      } 
     2020    } 
     2021 
    24022022    return bitsPerSample; 
     2023  } 
     2024 
     2025  /** 
     2026   * Retrieves the image's bytes per sample (derived from tag BitsPerSample) 
     2027   * from a given TIFF IFD. 
     2028   * @param ifd a TIFF IFD hashtable. 
     2029   * @return the image's bytes per sample.  The length of the array is equal to 
     2030   *   the number of samples per pixel. 
     2031   * @throws FormatException if there is a problem parsing the IFD metadata. 
     2032   * @see #getSamplesPerPixel(Hashtable) 
     2033   * @see #getBitsPerSample(Hashtable) 
     2034   */ 
     2035  public static int[] getBytesPerSample(Hashtable ifd) throws FormatException { 
     2036    int[] bitsPerSample = getBitsPerSample(ifd); 
     2037    int[] bps = new int[bitsPerSample.length]; 
     2038    for (int i=0; i<bitsPerSample.length; i++) { 
     2039      bps[i] = bitsPerSample[i]; 
     2040      while ((bps[i] % 8) != 0) bps[i]++; 
     2041      bps[i] /= 8; 
     2042      if (bps[i] == 0) bps[i] = 1; 
     2043    } 
     2044    return bps; 
    24032045  } 
    24042046 
     
    24562098    throws FormatException 
    24572099  { 
    2458     return getIFDIntValue(ifd, PHOTOMETRIC_INTERPRETATION, true, 0); 
     2100    int photoInterp = getIFDIntValue(ifd, PHOTOMETRIC_INTERPRETATION, true, 0); 
     2101    if (photoInterp == TRANSPARENCY_MASK) { 
     2102      throw new FormatException( 
     2103        "Sorry, Transparency Mask PhotometricInterpretation is not supported"); 
     2104    } 
     2105    else if (photoInterp == CIE_LAB) { 
     2106      throw new FormatException( 
     2107        "Sorry, CIELAB PhotometricInterpretation is not supported"); 
     2108    } 
     2109    else if (photoInterp != WHITE_IS_ZERO && 
     2110      photoInterp != BLACK_IS_ZERO && photoInterp != RGB && 
     2111      photoInterp != RGB_PALETTE && photoInterp != CMYK && 
     2112      photoInterp != Y_CB_CR && photoInterp != CFA_ARRAY) 
     2113    { 
     2114      throw new FormatException("Unknown PhotometricInterpretation (" + 
     2115        photoInterp + ")"); 
     2116    } 
     2117    return photoInterp; 
     2118  } 
     2119 
     2120  /** 
     2121   * Retrieves the image's planar configuration (TIFF tag PlanarConfiguration) 
     2122   * from a given TIFF IFD. 
     2123   * @param ifd a TIFF IFD hashtable. 
     2124   * @return the image's planar configuration.  As of TIFF 6.0 this is one of: 
     2125   * <ul> 
     2126   *  <li>Chunky (1)</li> 
     2127   *  <li>Planar (2)</li> 
     2128   * </ul> 
     2129   * 
     2130   * @throws FormatException if there is a problem parsing the IFD metadata. 
     2131   */ 
     2132  public static int getPlanarConfiguration(Hashtable ifd) throws FormatException 
     2133  { 
     2134    int planarConfig = getIFDIntValue(ifd, PLANAR_CONFIGURATION, false, 1); 
     2135    if (planarConfig != 1 && planarConfig != 2) { 
     2136      throw new FormatException("Sorry, PlanarConfiguration (" + planarConfig + 
     2137        ") not supported."); 
     2138    } 
     2139    return planarConfig; 
    24592140  } 
    24602141 
     
    24632144   * given TIFF IFD. 
    24642145   * @param ifd a TIFF IFD hashtable. 
    2465    * @return the strip offsets for the image. The lenght of the array is equal 
     2146   * @return the strip offsets for the image. The length of the array is equal 
    24662147   *   to the number of strips per image. <i>StripsPerImage = 
    24672148   *   floor ((ImageLength + RowsPerStrip - 1) / RowsPerStrip)</i>. 
     
    24712152   */ 
    24722153  public static long[] getStripOffsets(Hashtable ifd) throws FormatException { 
    2473     return getIFDLongArray(ifd, STRIP_OFFSETS, false); 
     2154    int tag = isTiled(ifd) ? TILE_OFFSETS : STRIP_OFFSETS; 
     2155    long[] offsets = getIFDLongArray(ifd, tag, false); 
     2156    if (isTiled(ifd)) return offsets; 
     2157    long rowsPerStrip = getRowsPerStrip(ifd)[0]; 
     2158    long numStrips = (getImageLength(ifd) + rowsPerStrip - 1) / rowsPerStrip; 
     2159    if (getPlanarConfiguration(ifd) == 2) numStrips *= getSamplesPerPixel(ifd); 
     2160    if (offsets.length < numStrips) { 
     2161      throw new FormatException("StripOffsets length (" + offsets.length + 
     2162        ") does not match expected " + "number of strips (" + numStrips + ")"); 
     2163    } 
     2164    return offsets; 
    24742165  } 
    24752166 
     
    24862177  public static long[] getStripByteCounts(Hashtable ifd) throws FormatException 
    24872178  { 
    2488     return getIFDLongArray(ifd, STRIP_BYTE_COUNTS, false); 
     2179    int tag = isTiled(ifd) ? TILE_BYTE_COUNTS : STRIP_BYTE_COUNTS; 
     2180    long[] byteCounts = getIFDLongArray(ifd, tag, false); 
     2181    if (byteCounts == null) { 
     2182      // technically speaking, this shouldn't happen (since TIFF writers are 
     2183      // required to write the StripByteCounts tag), but we'll support it 
     2184      // anyway 
     2185 
     2186      // don't rely on RowsPerStrip, since it's likely that if the file doesn't 
     2187      // have the StripByteCounts tag, it also won't have the RowsPerStrip tag 
     2188      long[] offsets = getStripOffsets(ifd); 
     2189      int bytesPerSample = getBytesPerSample(ifd)[0]; 
     2190      long imageWidth = getImageWidth(ifd); 
     2191      long imageLength = getImageLength(ifd); 
     2192      byteCounts = new long[offsets.length]; 
     2193      int samples = getSamplesPerPixel(ifd); 
     2194      long imageSize = imageWidth * imageLength * bytesPerSample * 
     2195        (getPlanarConfiguration(ifd) == 2 ? 1 : samples); 
     2196      long count = imageSize / byteCounts.length; 
     2197      Arrays.fill(byteCounts, count); 
     2198    } 
     2199 
     2200    long[] counts = new long[byteCounts.length]; 
     2201 
     2202    if (getCompression(ifd) != UNCOMPRESSED) { 
     2203      for (int i=0; i<byteCounts.length; i++) { 
     2204        counts[i] = byteCounts[i] * 2; 
     2205      } 
     2206    } 
     2207    else System.arraycopy(byteCounts, 0, counts, 0, counts.length); 
     2208 
     2209    if (isTiled(ifd)) return counts; 
     2210 
     2211    long rowsPerStrip = getRowsPerStrip(ifd)[0]; 
     2212    long numStrips = (getImageLength(ifd) + rowsPerStrip - 1) / rowsPerStrip; 
     2213    if (getPlanarConfiguration(ifd) == 2) numStrips *= getSamplesPerPixel(ifd); 
     2214 
     2215    if (counts.length < numStrips) { 
     2216      throw new FormatException("StripByteCounts length (" + counts.length + 
     2217        ") does not match expected " + "number of strips (" + numStrips + ")"); 
     2218    } 
     2219 
     2220    return counts; 
    24892221  } 
    24902222 
     
    24972229   */ 
    24982230  public static long[] getRowsPerStrip(Hashtable ifd) throws FormatException { 
    2499     return getIFDLongArray(ifd, ROWS_PER_STRIP, false); 
     2231    if (isTiled(ifd)) { 
     2232      return new long[] {getImageLength(ifd)}; 
     2233    } 
     2234    long[] rowsPerStrip = getIFDLongArray(ifd, ROWS_PER_STRIP, false); 
     2235    if (rowsPerStrip == null) { 
     2236      // create a fake RowsPerStrip entry if one is not present 
     2237      return new long[] {getImageLength(ifd)}; 
     2238    } 
     2239 
     2240    // rowsPerStrip should never be more than the total number of rows 
     2241    long imageLength = getImageLength(ifd); 
     2242    for (int i=0; i<rowsPerStrip.length; i++) { 
     2243      rowsPerStrip[i] = (long) Math.min(rowsPerStrip[i], imageLength); 
     2244    } 
     2245 
     2246    long rows = rowsPerStrip[0]; 
     2247    for (int i=1; i<rowsPerStrip.length; i++) { 
     2248      if (rows != rowsPerStrip[i]) { 
     2249        throw new FormatException( 
     2250          "Sorry, non-uniform RowsPerStrip is not supported"); 
     2251      } 
     2252    } 
     2253 
     2254    return rowsPerStrip; 
    25002255  } 
    25012256 
    25022257  // -- Compression methods -- 
    25032258 
     2259  /** Returns true if the given compression scheme is supported. */ 
     2260  public static boolean isSupportedCompression(int compression) { 
     2261    return compression == UNCOMPRESSED || compression == LZW || 
     2262      compression == JPEG || compression == JPEG_2000; 
     2263  } 
     2264 
    25042265  /** Encodes a strip of data with the given compression scheme. */ 
    2505     public static byte[] compress(byte[] input, Hashtable ifd) 
     2266  public static byte[] compress(byte[] input, Hashtable ifd) 
    25062267    throws FormatException, IOException 
    25072268  { 
    25082269    int compression = getIFDIntValue(ifd, COMPRESSION, false, UNCOMPRESSED); 
     2270 
     2271    if (!isSupportedCompression(compression)) { 
     2272      String compressionName = getCodecName(compression); 
     2273      if (compressionName != null) { 
     2274        throw new FormatException("Sorry, " + compressionName + 
     2275          " compression mode is not supported"); 
     2276      } 
     2277      else { 
     2278        throw new FormatException( 
     2279          "Unknown Compression type (" + compression + ")"); 
     2280      } 
     2281    } 
    25092282 
    25102283    CodecOptions options = new CodecOptions(); 
     
    25172290 
    25182291    if (compression == UNCOMPRESSED) return input; 
     2292    else if (compression == LZW) { 
     2293      return new LZWCodec().compress(input, options); 
     2294    } 
    25192295    else if (compression == JPEG) { 
    25202296      return new JPEGCodec().compress(input, options); 
     
    25232299      return new JPEG2000Codec().compress(input, options); 
    25242300    } 
    2525     else { 
    2526       return compress(input, compression); 
    2527     } 
    2528   } 
    2529  
    2530   /** Encodes a strip of data with the given compression scheme. */ 
    2531   public static byte[] compress(byte[] input, int compression) 
    2532     throws FormatException, IOException 
    2533   { 
    2534     if (compression == UNCOMPRESSED) return input; 
    2535     else if (compression == CCITT_1D) { 
    2536       throw new FormatException( 
    2537         "Sorry, CCITT Group 3 1-Dimensional Modified Huffman " + 
    2538         "run length encoding compression mode is not supported"); 
    2539     } 
    2540     else if (compression == GROUP_3_FAX) { 
    2541       throw new FormatException("Sorry, CCITT T.4 bi-level encoding " + 
    2542         "(Group 3 Fax) compression mode is not supported"); 
    2543     } 
    2544     else if (compression == GROUP_4_FAX) { 
    2545       throw new FormatException("Sorry, CCITT T.6 bi-level encoding " + 
    2546         "(Group 4 Fax) compression mode is not supported"); 
    2547     } 
    2548     else if (compression == LZW) { 
    2549       LZWCodec c = new LZWCodec(); 
    2550       return c.compress(input, null); 
    2551       // return Compression.lzwCompress(input); 
    2552     } 
    2553  
    2554     else if (compression == JPEG) { 
    2555       throw new FormatException( 
    2556         "Sorry, JPEG compression mode is not supported"); 
    2557     } 
    2558     else if (compression == PACK_BITS) { 
    2559       throw new FormatException( 
    2560         "Sorry, PackBits compression mode is not supported"); 
    2561     } 
    2562     else { 
    2563       throw new FormatException( 
    2564         "Unknown Compression type (" + compression + ")"); 
    2565     } 
     2301    throw new FormatException("Unhandled compression (" + compression + ")"); 
    25662302  } 
    25672303 
     
    25712307  { 
    25722308    if (predictor == 2) { 
    2573       if (DEBUG) debug("performing horizontal differencing"); 
     2309      debug("performing horizontal differencing"); 
    25742310      for (int b=input.length-1; b>=0; b--) { 
    25752311        if (b / bitsPerSample.length % width == 0) continue; 
     
    25862322  /** Prints a debugging message with current time. */ 
    25872323  public static void debug(String message) { 
    2588     LogTools.println(System.currentTimeMillis() + ": " + message); 
     2324    if (DEBUG) { 
     2325      LogTools.println(System.currentTimeMillis() + ": " + message); 
     2326    } 
     2327  } 
     2328 
     2329  /** Prints the contents of an IFD. */ 
     2330  public static void printIFD(Hashtable ifd) { 
     2331    StringBuffer sb = new StringBuffer(); 
     2332    sb.append("IFD directory entry values:"); 
     2333 
     2334    Integer[] tags = (Integer[]) ifd.keySet().toArray(new Integer[0]); 
     2335    for (int entry=0; entry<tags.length; entry++) { 
     2336      sb.append("\n\t"); 
     2337      sb.append(getIFDTagName(tags[entry].intValue())); 
     2338      sb.append("="); 
     2339      Object value = ifd.get(tags[entry]); 
     2340      if ((value instanceof Boolean) || (value instanceof Number) || 
     2341        (value instanceof String)) 
     2342      { 
     2343        sb.append(value); 
     2344      } 
     2345      else { 
     2346        // this is an array of primitive types, Strings, or TiffRationals 
     2347        ReflectedUniverse r = new ReflectedUniverse(); 
     2348        r.setVar("value", value); 
     2349        try { 
     2350          int nElements = ((Integer) r.exec("value.length")).intValue(); 
     2351          for (int i=0; i<nElements; i++) { 
     2352            r.setVar("index", i); 
     2353            sb.append(r.exec("value[index]")); 
     2354            if (i < nElements - 1) sb.append(","); 
     2355          } 
     2356        } 
     2357        catch (ReflectException re) { } 
     2358      } 
     2359    } 
     2360    debug(sb.toString()); 
     2361  } 
     2362 
     2363  /** Returns the name of the given codec. */ 
     2364  public static String getCodecName(int codec) { 
     2365    switch (codec) { 
     2366      case UNCOMPRESSED: return "Uncompressed"; 
     2367      case CCITT_1D: return "CCITT Group 3 1-Dimensional Modified Huffman"; 
     2368      case GROUP_3_FAX: return "CCITT T.4 bi-level encoding (Group 3 Fax)"; 
     2369      case GROUP_4_FAX: return "CCITT T.6 bi-level encoding (Group 4 Fax)"; 
     2370      case LZW: return "LZW"; 
     2371      case JPEG: 
     2372      case ALT_JPEG: 
     2373        return "JPEG"; 
     2374      case PACK_BITS: return "PackBits"; 
     2375      case DEFLATE: 
     2376      case PROPRIETARY_DEFLATE: 
     2377        return "Deflate (Zlib)"; 
     2378      case THUNDERSCAN: return "Thunderscan"; 
     2379      case JPEG_2000: return "JPEG-2000"; 
     2380      case NIKON: return "Nikon"; 
     2381      case LURAWAVE: return "LuraWave"; 
     2382    } 
     2383    return null; 
    25892384  } 
    25902385 
  • trunk/components/common/src/loci/common/DataTools.java

    r4804 r4895  
    161161    throws IOException 
    162162  { 
    163     byte[] b =  s.getBytes("UTF-8"); 
     163    byte[] b = s.getBytes("UTF-8"); 
    164164    out.write(b); 
    165165  } 
     
    176176    throws IOException 
    177177  { 
    178     if (little) { 
    179       out.write((int) (v & 0xff)); 
    180       out.write((int) ((v >>> 8) & 0xff)); 
    181       out.write((int) ((v >>> 16) & 0xff)); 
    182       out.write((int) ((v >>> 24) & 0xff)); 
    183       out.write((int) ((v >>> 32) & 0xff)); 
    184       out.write((int) ((v >>> 40) & 0xff)); 
    185       out.write((int) ((v >>> 48) & 0xff)); 
    186       out.write((int) ((v >>> 56) & 0xff)); 
    187     } 
    188     else { 
    189       out.write((int) ((v >>> 56) & 0xff)); 
    190       out.write((int) ((v >>> 48) & 0xff)); 
    191       out.write((int) ((v >>> 40) & 0xff)); 
    192       out.write((int) ((v >>> 32) & 0xff)); 
    193       out.write((int) ((v >>> 24) & 0xff)); 
    194       out.write((int) ((v >>> 16) & 0xff)); 
    195       out.write((int) ((v >>> 8) & 0xff)); 
    196       out.write((int) (v & 0xff)); 
     178    for (int i=0; i<8; i++) { 
     179      int shift = little ? i * 8 : 64 - (i + 1) * 8; 
     180      out.write((int) ((v >>> shift) & 0xff)); 
    197181    } 
    198182  } 
     
    209193    throws IOException 
    210194  { 
    211     if (little) { 
    212       out.write(v & 0xFF); 
    213       out.write((v >>> 8) & 0xFF); 
    214       out.write((v >>> 16) & 0xFF); 
    215       out.write((v >>> 24) & 0xFF); 
    216     } 
    217     else { 
    218       out.write((v >>> 24) & 0xFF); 
    219       out.write((v >>> 16) & 0xFF); 
    220       out.write((v >>> 8) & 0xFF); 
    221       out.write(v & 0xFF); 
     195    for (int i=0; i<4; i++) { 
     196      int shift = little ? i * 8 : 32 - (i + 1) * 8; 
     197      out.write((int) ((v >>> shift) & 0xff)); 
    222198    } 
    223199  } 
     
    227203    throws IOException 
    228204  { 
    229     if (little) { 
    230       out.write(v & 0xFF); 
    231       out.write((v >>> 8) & 0xFF); 
    232     } 
    233     else { 
    234       out.write((v >>> 8) & 0xFF); 
    235       out.write(v & 0xFF); 
     205    for (int i=0; i<2; i++) { 
     206      int shift = little ? i * 8 : 16 - (i + 1) * 8; 
     207      out.write((int) ((v >>> shift) & 0xff)); 
    236208    } 
    237209  } 
Note: See TracChangeset for help on using the changeset viewer.