Changeset 5958


Ignore:
Timestamp:
02/25/10 15:07:22 (10 years ago)
Author:
melissa
Message:
  • Altered IFD retrieval methods in TiffParser to be a little more intuitive, and updated readers accordingly. See #466.
  • Ported parts of r5880 to cleanup, so that TIFF detection works again.
Location:
branches/cleanup/components/bio-formats/src/loci/formats
Files:
3 added
11 edited

Legend:

Unmodified
Added
Removed
  • branches/cleanup/components/bio-formats/src/loci/formats/gui/AWTImageTools.java

    r5852 r5958  
    5151import java.awt.image.PixelInterleavedSampleModel; 
    5252import java.awt.image.Raster; 
     53import java.awt.image.RenderedImage; 
    5354import java.awt.image.SampleModel; 
    5455import java.awt.image.SinglePixelPackedSampleModel; 
    5556import java.awt.image.WritableRaster; 
    5657import java.io.IOException; 
     58import java.util.Hashtable; 
    5759 
    5860import loci.common.DataTools; 
     
    642644 
    643645    SampleModel model; 
    644     if (c > 2 && type == DataBuffer.TYPE_INT && buffer.getNumBanks() == 1) { 
     646    if (c > 2 && type == DataBuffer.TYPE_INT && buffer.getNumBanks() == 1 && 
     647      !(buffer instanceof UnsignedIntBuffer)) 
     648    { 
    645649      int[] bitMasks = new int[c]; 
    646650      for (int i=0; i<c; i++) { 
     
    684688      } 
    685689    } 
    686     else if (c > 2 && type == DataBuffer.TYPE_INT && buffer.getNumBanks() == 1) 
     690    else if (c > 2 && type == DataBuffer.TYPE_INT && buffer.getNumBanks() == 1 
     691      && !(buffer instanceof UnsignedIntBuffer)) 
    687692    { 
    688693      if (c == 3) { 
     
    10821087  //} 
    10831088 
     1089  /** 
     1090   * Converts a java.awt.image.RenderedImage into a 
     1091   * java.awt.image.BufferedImage. 
     1092   * 
     1093   * This code was adapted from 
     1094   * <a href="http://www.jguru.com/faq/view.jsp?EID=114602">a jGuru post</a>. 
     1095   */ 
     1096  public static BufferedImage convertRenderedImage(RenderedImage img) { 
     1097    if (img instanceof BufferedImage) return (BufferedImage) img; 
     1098    ColorModel cm = img.getColorModel(); 
     1099    int width = img.getWidth(); 
     1100    int height = img.getHeight(); 
     1101    WritableRaster raster = cm.createCompatibleWritableRaster(width, height); 
     1102    boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); 
     1103    Hashtable properties = new Hashtable(); 
     1104    String[] keys = img.getPropertyNames(); 
     1105    if (keys != null) { 
     1106      for (int i=0; i<keys.length; i++) { 
     1107        properties.put(keys[i], img.getProperty(keys[i])); 
     1108      } 
     1109    } 
     1110    BufferedImage result = new BufferedImage(cm, 
     1111      raster, isAlphaPremultiplied, properties); 
     1112    img.copyData(raster); 
     1113    return result; 
     1114  } 
     1115 
    10841116  /** Get the bytes from an image, merging the channels as necessary. */ 
    10851117  public static byte[] getBytes(BufferedImage img, boolean separated) { 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/BaseTiffReader.java

    r5957 r5958  
    3232import loci.formats.meta.MetadataStore; 
    3333import loci.formats.tiff.IFD; 
     34import loci.formats.tiff.IFDList; 
    3435import loci.formats.tiff.PhotoInterp; 
    3536import loci.formats.tiff.TiffCompression; 
     
    5758  }; 
    5859 
    59   /** EXIF tags. */ 
    60   private static final int EXIF_VERSION = 36864; 
    61   private static final int FLASH_PIX_VERSION = 40960; 
    62   private static final int COLOR_SPACE = 40961; 
    63   private static final int COMPONENTS_CONFIGURATION = 37121; 
    64   private static final int COMPRESSED_BITS_PER_PIXEL = 37122; 
    65   private static final int PIXEL_X_DIMENSION = 40962; 
    66   private static final int PIXEL_Y_DIMENSION = 40963; 
    67   private static final int MAKER_NOTE = 37500; 
    68   private static final int USER_COMMENT = 37510; 
    69   private static final int RELATED_SOUND_FILE = 40964; 
    70   private static final int DATE_TIME_ORIGINAL = 36867; 
    71   private static final int DATE_TIME_DIGITIZED = 36868; 
    72   private static final int SUB_SEC_TIME = 37520; 
    73   private static final int SUB_SEC_TIME_ORIGINAL = 37521; 
    74   private static final int SUB_SEC_TIME_DIGITIZED = 37522; 
    75   private static final int EXPOSURE_TIME = 33434; 
    76   private static final int F_NUMBER = 33437; 
    77   private static final int EXPOSURE_PROGRAM = 34850; 
    78   private static final int SPECTRAL_SENSITIVITY = 34852; 
    79   private static final int ISO_SPEED_RATINGS = 34855; 
    80   private static final int OECF = 34856; 
    81   private static final int SHUTTER_SPEED_VALUE = 37377; 
    82   private static final int APERTURE_VALUE = 37378; 
    83   private static final int BRIGHTNESS_VALUE = 37379; 
    84   private static final int EXPOSURE_BIAS_VALUE = 37380; 
    85   private static final int MAX_APERTURE_VALUE = 37381; 
    86   private static final int SUBJECT_DISTANCE = 37382; 
    87   private static final int METERING_MODE = 37383; 
    88   private static final int LIGHT_SOURCE = 37384; 
    89   private static final int FLASH = 37385; 
    90   private static final int FOCAL_LENGTH = 37386; 
    91   private static final int FLASH_ENERGY = 41483; 
    92   private static final int SPATIAL_FREQUENCY_RESPONSE = 41484; 
    93   private static final int FOCAL_PLANE_X_RESOLUTION = 41486; 
    94   private static final int FOCAL_PLANE_Y_RESOLUTION = 41487; 
    95   private static final int FOCAL_PLANE_RESOLUTION_UNIT = 41488; 
    96   private static final int SUBJECT_LOCATION = 41492; 
    97   private static final int EXPOSURE_INDEX = 41493; 
    98   private static final int SENSING_METHOD = 41495; 
    99   private static final int FILE_SOURCE = 41728; 
    100   private static final int SCENE_TYPE = 41729; 
    101   private static final int CFA_PATTERN = 41730; 
    102  
    10360  // -- Constructors -- 
    10461 
     
    13491    // retrieve EXIF values, if available 
    13592 
    136     long exifOffset = firstIFD.getIFDLongValue(IFD.EXIF, false, 0); 
    137     if (exifOffset != 0) { 
    138       IFD exif = tiffParser.getIFD(1, exifOffset); 
    139       if (exif != null) { 
    140         for (Integer key : exif.keySet()) { 
    141           int k = key.intValue(); 
    142           addGlobalMeta(getExifTagName(k), exif.get(key)); 
    143         } 
     93    IFDList exifIFDs = tiffParser.getExifIFDs(); 
     94    if (exifIFDs.size() > 0) { 
     95      IFD exif = exifIFDs.get(0); 
     96      for (Integer key : exif.keySet()) { 
     97        int k = key.intValue(); 
     98        addGlobalMeta(getExifTagName(k), exif.get(key)); 
    14499      } 
    145100    } 
     
    564519 
    565520  public static String getExifTagName(int tag) { 
    566     switch (tag) { 
    567       case EXIF_VERSION: 
    568         return "EXIF Version"; 
    569       case FLASH_PIX_VERSION: 
    570         return "FlashPix Version"; 
    571       case COLOR_SPACE: 
    572         return "Color Space"; 
    573       case COMPONENTS_CONFIGURATION: 
    574         return "Components Configuration"; 
    575       case COMPRESSED_BITS_PER_PIXEL: 
    576         return "Compressed Bits Per Pixel"; 
    577       case PIXEL_X_DIMENSION: 
    578         return "Image width"; 
    579       case PIXEL_Y_DIMENSION: 
    580         return "Image height"; 
    581       case MAKER_NOTE: 
    582         return "Maker Note"; 
    583       case USER_COMMENT: 
    584         return "User comment"; 
    585       case RELATED_SOUND_FILE: 
    586         return "Related sound file"; 
    587       case DATE_TIME_ORIGINAL: 
    588         return "Original date/time"; 
    589       case DATE_TIME_DIGITIZED: 
    590         return "Date/time digitized"; 
    591       case SUB_SEC_TIME: 
    592         return "Date/time subseconds"; 
    593       case SUB_SEC_TIME_ORIGINAL: 
    594         return "Original date/time subseconds"; 
    595       case SUB_SEC_TIME_DIGITIZED: 
    596         return "Digitized date/time subseconds"; 
    597       case EXPOSURE_TIME: 
    598         return "Exposure time"; 
    599       case F_NUMBER: 
    600         return "F Number"; 
    601       case EXPOSURE_PROGRAM: 
    602         return "Exposure program"; 
    603       case SPECTRAL_SENSITIVITY: 
    604         return "Spectral sensitivity"; 
    605       case ISO_SPEED_RATINGS: 
    606         return "ISO speed ratings"; 
    607       case OECF: 
    608         return "Optoelectric conversion factor"; 
    609       case SHUTTER_SPEED_VALUE: 
    610         return "Shutter speed"; 
    611       case APERTURE_VALUE: 
    612         return "Aperture value"; 
    613       case BRIGHTNESS_VALUE: 
    614         return "Brightness value"; 
    615       case EXPOSURE_BIAS_VALUE: 
    616         return "Exposure Bias value"; 
    617       case MAX_APERTURE_VALUE: 
    618         return "Max aperture value"; 
    619       case SUBJECT_DISTANCE: 
    620         return "Subject distance"; 
    621       case METERING_MODE: 
    622         return "Metering mode"; 
    623       case LIGHT_SOURCE: 
    624         return "Light source"; 
    625       case FLASH: 
    626         return "Flash"; 
    627       case FOCAL_LENGTH: 
    628         return "Focal length"; 
    629       case FLASH_ENERGY: 
    630         return "Flash energy"; 
    631       case SPATIAL_FREQUENCY_RESPONSE: 
    632         return "Spatial frequency response"; 
    633       case FOCAL_PLANE_X_RESOLUTION: 
    634         return "Focal plane X resolution"; 
    635       case FOCAL_PLANE_Y_RESOLUTION: 
    636         return "Focal plane Y resolution"; 
    637       case FOCAL_PLANE_RESOLUTION_UNIT: 
    638         return "Focal plane resolution unit"; 
    639       case SUBJECT_LOCATION: 
    640         return "Subject location"; 
    641       case EXPOSURE_INDEX: 
    642         return "Exposure index"; 
    643       case SENSING_METHOD: 
    644         return "Sensing method"; 
    645       case FILE_SOURCE: 
    646         return "File source"; 
    647       case SCENE_TYPE: 
    648         return "Scene type"; 
    649       case CFA_PATTERN: 
    650         return "CFA Pattern"; 
    651     } 
    652     return null; 
     521    return IFD.getIFDTagName(tag); 
    653522  } 
    654523 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/FlexReader.java

    r5856 r5958  
    989989              factors = new double[nRows][nCols][]; 
    990990            } 
    991             ifds[row][col] = tp.getIFDs(false, false); 
     991            tp.setDoCaching(false); 
     992            ifds[row][col] = tp.getIFDs(); 
    992993            ifds[row][col].set(0, firstIFD); 
    993994            parseFlexFile(currentWell, row, col, firstFile, store); 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/ImaconReader.java

    r5852 r5958  
    9292    super.initStandardMetadata(); 
    9393 
    94     ifds = tiffParser.getIFDs(false); 
     94    ifds = tiffParser.getIFDs(); 
    9595 
    9696    core = new CoreMetadata[ifds.size()]; 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/MRWReader.java

    r5848 r5958  
    223223              ifd.get(keys[q])); 
    224224          } 
    225  
    226           long exifOffset = 
    227             ifd.getIFDLongValue(IFD.EXIF, false, 0); 
    228           if (exifOffset != 0 && exifOffset < ras.length()) { 
    229             IFD exif = tp.getIFD(1, exifOffset); 
    230  
    231             Integer[] k = (Integer[]) exif.keySet().toArray(new Integer[0]); 
    232             for (int q=0; q<k.length; q++) { 
    233               addGlobalMeta(BaseTiffReader.getExifTagName(k[q].intValue()), 
    234                 exif.get(k[q])); 
    235             } 
     225        } 
     226 
     227        IFDList exifIFDs = tp.getExifIFDs(); 
     228        for (IFD exif : exifIFDs) { 
     229          for (Integer key : exif.keySet()) { 
     230            addGlobalMeta(IFD.getIFDTagName(key.intValue()), exif.get(key)); 
    236231          } 
    237232        } 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/MinimalTiffReader.java

    r5852 r5958  
    6464  /** Constructs a new MinimalTiffReader. */ 
    6565  public MinimalTiffReader() { 
    66     super("Minimal TIFF", new String[] {"tif", "tiff"}); 
    67     domains = new String[] {FormatTools.GRAPHICS_DOMAIN}; 
     66    this("Minimal TIFF", new String[] {"tif", "tiff"}); 
    6867  } 
    6968 
    7069  /** Constructs a new MinimalTiffReader. */ 
    71   public MinimalTiffReader(String name, String suffix) { super(name, suffix); } 
     70  public MinimalTiffReader(String name, String suffix) { 
     71    this(name, new String[] {suffix}); 
     72  } 
    7273 
    7374  /** Constructs a new MinimalTiffReader. */ 
    7475  public MinimalTiffReader(String name, String[] suffixes) { 
    7576    super(name, suffixes); 
     77    domains = new String[] {FormatTools.GRAPHICS_DOMAIN}; 
     78    suffixNecessary = false; 
    7679  } 
    7780 
     
    299302    LOGGER.info("Reading IFDs"); 
    300303 
    301     ifds = tiffParser.getIFDs(); 
     304    ifds = tiffParser.getNonThumbnailIFDs(); 
    302305    if (ifds == null || ifds.size() == 0) { 
    303306      throw new FormatException("No IFDs found"); 
    304307    } 
    305308 
    306     // separate thumbnail IFDs from regular IFDs 
    307  
    308     IFDList v = new IFDList(); 
    309     IFDList thumbs = new IFDList(); 
    310     for (int i=0; i<ifds.size(); i++) { 
    311       IFD ifd = ifds.get(i); 
    312       boolean thumbnail = ifd.getIFDIntValue(IFD.NEW_SUBFILE_TYPE) == 1 && 
    313         (ifds.size() > 1 || ifd.getIFDValue(IFD.IMAGE_WIDTH) == null); 
    314       if (thumbnail) thumbs.add(ifd); 
    315       else v.add(ifd); 
    316     } 
    317  
    318     ifds = v; 
    319     thumbnailIFDs = thumbs; 
     309    thumbnailIFDs = tiffParser.getThumbnailIFDs(); 
    320310 
    321311    LOGGER.info("Populating metadata"); 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/NikonReader.java

    r5852 r5958  
    5858 
    5959  // Tags that give a good indication of whether this is an NEF file. 
    60   private static final int EXIF_IFD_POINTER = 34665; 
    6160  private static final int TIFF_EPS_STANDARD = 37398; 
    62  
    63   // EXIF IFD tags. 
    64   private static final int CFA_REPEAT_DIM = 33421; 
    65   private static final int EXPOSURE_TIME = 33434; 
    66   private static final int APERTURE = 33437; 
    67   private static final int EXPOSURE_PROGRAM = 34850; 
    68   private static final int DATE_TIME_DIGITIZED = 36867; 
    69   private static final int DATE_TIME_ORIGINAL = 36868; 
    70   private static final int EXPOSURE_BIAS_VALUE = 37380; 
    71   private static final int MAX_APERTURE_VALUE = 37381; 
    72   private static final int METERING_MODE = 37383; 
    73   private static final int LIGHT_SOURCE = 37384; 
    74   private static final int FLASH = 37385; 
    75   private static final int FOCAL_LENGTH = 37386; 
    76   private static final int SENSING_METHOD = 37399; 
    77   private static final int MAKER_NOTE = 37500; 
    78   private static final int USER_COMMENT = 37510; 
    79   private static final int SUBSEC_TIME = 37520; 
    80   private static final int SUBSEC_TIME_ORIGINAL = 37521; 
    81   private static final int SUBSEC_TIME_DIGITIZED = 37522; 
    82   private static final int COLOR_SPACE = 40961; 
    83   private static final int FILE_SOURCE = 41728; 
    84   private static final int SCENE_TYPE = 41729; 
    85   private static final int CFA_PATTERN = 41730; 
    86   private static final int CUSTOM_RENDERED = 41985; 
    87   private static final int EXPOSURE_MODE = 41986; 
    88   private static final int WHITE_BALANCE = 41987; 
    89   private static final int DIGITAL_ZOOM_RATIO = 41988; 
    90   private static final int FOCAL_LENGTH_35MM_FILM = 41989; 
    91   private static final int SCENE_CAPTURE_TYPE = 41990; 
    92   private static final int GAIN_CONTROL = 41991; 
    93   private static final int CONTRAST = 41992; 
    94   private static final int SATURATION = 41993; 
    95   private static final int SHARPNESS = 41994; 
    96   private static final int SUBJECT_DISTANCE_RANGE = 41996; 
    9761 
    9862  // Maker Note tags. 
     
    11882  private static final int CAPTURE_EDITOR_DATA = 3585; 
    11983 
    120   // Custom IFD tags 
    121   private static final int SUB_IFD = 330; 
    122  
    12384  // -- Fields -- 
    12485 
     
    297258    // in the 'real' IFD 
    298259 
    299     original = ifds.get(0); 
    300     long[] subIFDOffsets = original.getIFDLongArray(SUB_IFD, false); 
    301  
    302     if (subIFDOffsets != null) { 
    303       IFDList tmpIFDs = new IFDList(); 
    304  
    305       for (int i=0; i<subIFDOffsets.length; i++) { 
    306         IFD ifd = tiffParser.getIFD(i, subIFDOffsets[i]); 
    307         if (ifd.getIFDIntValue(IFD.NEW_SUBFILE_TYPE) == 0) { 
    308           tmpIFDs.add(ifd); 
    309         } 
    310       } 
    311  
    312       ifds = tmpIFDs; 
    313  
    314       core[0].imageCount = ifds.size(); 
    315  
    316       IFD firstIFD = ifds.get(0); 
    317       int photo = firstIFD.getPhotometricInterpretation(); 
    318       int samples = firstIFD.getSamplesPerPixel(); 
    319       core[0].rgb = samples > 1 || photo == PhotoInterp.RGB || 
    320         photo == PhotoInterp.CFA_ARRAY; 
    321       if (photo == PhotoInterp.CFA_ARRAY) samples = 3; 
    322  
    323       core[0].sizeX = (int) firstIFD.getImageWidth(); 
    324       core[0].sizeY = (int) firstIFD.getImageLength(); 
    325       core[0].sizeZ = 1; 
    326       core[0].sizeC = isRGB() ? samples : 1; 
    327       core[0].sizeT = ifds.size(); 
    328       core[0].pixelType = firstIFD.getPixelType(); 
    329       core[0].indexed = false; 
    330     } 
     260    core[0].imageCount = ifds.size(); 
     261 
     262    IFD firstIFD = ifds.get(0); 
     263    int photo = firstIFD.getPhotometricInterpretation(); 
     264    int samples = firstIFD.getSamplesPerPixel(); 
     265    core[0].rgb = samples > 1 || photo == PhotoInterp.RGB || 
     266      photo == PhotoInterp.CFA_ARRAY; 
     267    if (photo == PhotoInterp.CFA_ARRAY) samples = 3; 
     268 
     269    core[0].sizeX = (int) firstIFD.getImageWidth(); 
     270    core[0].sizeY = (int) firstIFD.getImageLength(); 
     271    core[0].sizeZ = 1; 
     272    core[0].sizeC = isRGB() ? samples : 1; 
     273    core[0].sizeT = ifds.size(); 
     274    core[0].pixelType = firstIFD.getPixelType(); 
     275    core[0].indexed = false; 
    331276 
    332277    // now look for the EXIF IFD pointer 
    333278 
    334     int exif = original.getIFDIntValue(EXIF_IFD_POINTER); 
    335     if (exif != -1) { 
    336       IFD exifIFD = tiffParser.getIFD(0, exif); 
     279    IFDList exifIFDs = tiffParser.getExifIFDs(); 
     280    if (exifIFDs.size() > 0) { 
     281      IFD exifIFD = exifIFDs.get(0); 
    337282 
    338283      // put all the EXIF data in the metadata hashtable 
    339284 
    340       if (exifIFD != null) { 
    341         for (Integer key : exifIFD.keySet()) { 
    342           int tag = key.intValue(); 
    343           if (tag == CFA_PATTERN) { 
    344             byte[] cfa = (byte[]) exifIFD.get(key); 
    345             int[] colorMap = new int[cfa.length]; 
    346             for (int i=0; i<cfa.length; i++) colorMap[i] = (int) cfa[i]; 
    347             addGlobalMeta(getTagName(tag), colorMap); 
    348             cfaPattern = colorMap; 
    349           } 
    350           else { 
    351             addGlobalMeta(getTagName(tag), exifIFD.get(key)); 
    352             if (getTagName(tag).equals("Offset to maker note")) { 
    353               byte[] b = (byte[]) exifIFD.get(key); 
    354               int extra = new String(b, 0, 10).startsWith("Nikon") ? 10 : 0; 
    355               byte[] buf = new byte[b.length]; 
    356               System.arraycopy(b, extra, buf, 0, buf.length - extra); 
    357               RandomAccessInputStream makerNote = 
    358                 new RandomAccessInputStream(buf); 
    359               TiffParser tp = new TiffParser(makerNote); 
    360               IFD note = null; 
    361               try { 
    362                 note = tp.getFirstIFD(); 
    363               } 
    364               catch (Exception e) { 
    365                 LOGGER.debug("Failed to parse first IFD", e); 
    366               } 
    367               if (note != null) { 
    368                 for (Integer nextKey : note.keySet()) { 
    369                   int nextTag = nextKey.intValue(); 
    370                   addGlobalMeta(getTagName(nextTag), note.get(nextKey)); 
    371                   if (nextTag == 150) { 
    372                     b = (byte[]) note.get(nextKey); 
    373                     RandomAccessInputStream s = new RandomAccessInputStream(b); 
    374                     byte check1 = s.readByte(); 
    375                     byte check2 = s.readByte(); 
    376  
    377                     lossyCompression = check1 != 0x46; 
    378  
    379                     vPredictor = new int[4]; 
    380                     for (int q=0; q<vPredictor.length; q++) { 
    381                       vPredictor[q] = s.readShort(); 
     285      for (Integer key : exifIFD.keySet()) { 
     286        int tag = key.intValue(); 
     287        String name = IFD.getIFDTagName(tag); 
     288        if (tag == IFD.CFA_PATTERN) { 
     289          byte[] cfa = (byte[]) exifIFD.get(key); 
     290          int[] colorMap = new int[cfa.length]; 
     291          for (int i=0; i<cfa.length; i++) colorMap[i] = (int) cfa[i]; 
     292          addGlobalMeta(name, colorMap); 
     293          cfaPattern = colorMap; 
     294        } 
     295        else { 
     296          addGlobalMeta(name, exifIFD.get(key)); 
     297          if (name.equals("Offset to maker note")) { 
     298            byte[] b = (byte[]) exifIFD.get(key); 
     299            int extra = new String(b, 0, 10).startsWith("Nikon") ? 10 : 0; 
     300            byte[] buf = new byte[b.length]; 
     301            System.arraycopy(b, extra, buf, 0, buf.length - extra); 
     302            RandomAccessInputStream makerNote = 
     303              new RandomAccessInputStream(buf); 
     304            TiffParser tp = new TiffParser(makerNote); 
     305            IFD note = null; 
     306            try { 
     307              note = tp.getFirstIFD(); 
     308            } 
     309            catch (Exception e) { 
     310              LOGGER.debug("Failed to parse first IFD", e); 
     311            } 
     312            if (note != null) { 
     313              for (Integer nextKey : note.keySet()) { 
     314                int nextTag = nextKey.intValue(); 
     315                addGlobalMeta(name, note.get(nextKey)); 
     316                if (nextTag == 150) { 
     317                  b = (byte[]) note.get(nextKey); 
     318                  RandomAccessInputStream s = new RandomAccessInputStream(b); 
     319                  byte check1 = s.readByte(); 
     320                  byte check2 = s.readByte(); 
     321 
     322                  lossyCompression = check1 != 0x46; 
     323 
     324                  vPredictor = new int[4]; 
     325                  for (int q=0; q<vPredictor.length; q++) { 
     326                    vPredictor[q] = s.readShort(); 
     327                  } 
     328 
     329                  curve = new int[16385]; 
     330 
     331                  int bps = ifds.get(0).getBitsPerSample()[0]; 
     332                  int max = 1 << bps & 0x7fff; 
     333                  int step = 0; 
     334                  int csize = s.readShort(); 
     335                  if (csize > 1) { 
     336                    step = max / (csize - 1); 
     337                  } 
     338 
     339                  if (check1 == 0x44 && check2 == 0x20 && step > 0) { 
     340                    for (int i=0; i<csize; i++) { 
     341                      curve[i * step] = s.readShort(); 
    382342                    } 
    383  
    384                     curve = new int[16385]; 
    385  
    386                     int bps = ifds.get(0).getBitsPerSample()[0]; 
    387                     int max = 1 << bps & 0x7fff; 
    388                     int step = 0; 
    389                     int csize = s.readShort(); 
    390                     if (csize > 1) { 
    391                       step = max / (csize - 1); 
     343                    for (int i=0; i<max; i++) { 
     344                      int n = i % step; 
     345                      curve[i] = (curve[i - n] * (step - n) + 
     346                        curve[i - n + step] * n) / step; 
    392347                    } 
    393  
    394                     if (check1 == 0x44 && check2 == 0x20 && step > 0) { 
    395                       for (int i=0; i<csize; i++) { 
    396                         curve[i * step] = s.readShort(); 
     348                    s.seek(562); 
     349                    split = s.readShort(); 
     350                  } 
     351                  else { 
     352                    int maxValue = (int) Math.pow(2, bps) - 1; 
     353                    Arrays.fill(curve, maxValue); 
     354                    int nElements = 
     355                      (int) (s.length() - s.getFilePointer()) / 2; 
     356                    if (nElements < 100) { 
     357                      for (int i=0; i<curve.length; i++) { 
     358                        curve[i] = (short) i; 
    397359                      } 
    398                       for (int i=0; i<max; i++) { 
    399                         int n = i % step; 
    400                         curve[i] = (curve[i - n] * (step - n) + 
    401                           curve[i - n + step] * n) / step; 
    402                       } 
    403                       s.seek(562); 
    404                       split = s.readShort(); 
    405360                    } 
    406361                    else { 
    407                       int maxValue = (int) Math.pow(2, bps) - 1; 
    408                       Arrays.fill(curve, maxValue); 
    409                       int nElements = 
    410                         (int) (s.length() - s.getFilePointer()) / 2; 
    411                       if (nElements < 100) { 
    412                         for (int i=0; i<curve.length; i++) { 
    413                           curve[i] = (short) i; 
    414                         } 
    415                       } 
    416                       else { 
    417                         for (int q=0; q<nElements; q++) { 
    418                           curve[q] = s.readShort(); 
    419                         } 
     362                      for (int q=0; q<nElements; q++) { 
     363                        curve[q] = s.readShort(); 
    420364                      } 
    421365                    } 
    422                     s.close(); 
    423366                  } 
    424                   else if (nextTag == WHITE_BALANCE_RGB_COEFFS) { 
    425                     whiteBalance = (TiffRational[]) note.get(nextKey); 
    426                   } 
     367                  s.close(); 
     368                } 
     369                else if (nextTag == WHITE_BALANCE_RGB_COEFFS) { 
     370                  whiteBalance = (TiffRational[]) note.get(nextKey); 
    427371                } 
    428372              } 
    429               makerNote.close(); 
    430373            } 
     374            makerNote.close(); 
    431375          } 
    432376        } 
     
    460404  } 
    461405 
    462   /** Gets the name of the IFD tag encoded by the given number. */ 
    463   private String getTagName(int tag) { 
    464     switch (tag) { 
    465       case CFA_REPEAT_DIM: 
    466         return "CFA Repeat Dimensions"; 
    467       case EXPOSURE_TIME: 
    468         return "Exposure Time"; 
    469       case APERTURE: 
    470         return "Aperture"; 
    471       case EXPOSURE_PROGRAM: 
    472         return "Exposure Program"; 
    473       case DATE_TIME_DIGITIZED: 
    474         return "Date/Time Digitized"; 
    475       case DATE_TIME_ORIGINAL: 
    476         return "Date/Time Original"; 
    477       case EXPOSURE_BIAS_VALUE: 
    478         return "Exposure Bias Value"; 
    479       case MAX_APERTURE_VALUE: 
    480         return "Max Aperture Value"; 
    481       case METERING_MODE: 
    482         return "Metering Mode"; 
    483       case LIGHT_SOURCE: 
    484         return "Light Source"; 
    485       case FLASH: 
    486         return "Flash Enabled?"; 
    487       case FOCAL_LENGTH: 
    488         return "Focal length of lens"; 
    489       case SENSING_METHOD: 
    490         return "Sensing Method"; 
    491       case MAKER_NOTE: 
    492         return "Offset to maker note"; 
    493       case USER_COMMENT: 
    494         return "User comment"; 
    495       case SUBSEC_TIME: 
    496         return "Subsec. Sampling for Date/Time field"; 
    497       case SUBSEC_TIME_ORIGINAL: 
    498         return "Subsec. Sampling for original date"; 
    499       case SUBSEC_TIME_DIGITIZED: 
    500         return "Subsec. Sampling for digitized date"; 
    501       case COLOR_SPACE: 
    502         return "Color space"; 
    503       case FILE_SOURCE: 
    504         return "File source"; 
    505       case SCENE_TYPE: 
    506         return "Scene type"; 
    507       case CFA_PATTERN: 
    508         return "CFA pattern"; 
    509       case CUSTOM_RENDERED: 
    510         return "Custom Rendered?"; 
    511       case EXPOSURE_MODE: 
    512         return "Exposure mode"; 
    513       case WHITE_BALANCE: 
    514         return "White Balance"; 
    515       case DIGITAL_ZOOM_RATIO: 
    516         return "Digital Zoom Ratio"; 
    517       case FOCAL_LENGTH_35MM_FILM: 
    518         return "Focal Length of 35mm lens"; 
    519       case SCENE_CAPTURE_TYPE: 
    520         return "Scene Capture Type"; 
    521       case GAIN_CONTROL: 
    522         return "Gain Control"; 
    523       case CONTRAST: 
    524         return "Contrast"; 
    525       case SATURATION: 
    526         return "Saturation"; 
    527       case SHARPNESS: 
    528         return "Sharpness"; 
    529       case SUBJECT_DISTANCE_RANGE: 
    530         return "Subject Distance Range"; 
    531       case FIRMWARE_VERSION: 
    532         return "Firmware version"; 
    533       case ISO: 
    534         return "ISO"; 
    535       case QUALITY: 
    536         return "Quality"; 
    537       case MAKER_WHITE_BALANCE: 
    538         return "White Balance (Maker)"; 
    539       case SHARPENING: 
    540         return "Sharpening"; 
    541       case FOCUS_MODE: 
    542         return "Focus Mode"; 
    543       case FLASH_SETTING: 
    544         return "Flash Setting"; 
    545       case FLASH_MODE: 
    546         return "Flash Mode"; 
    547       case WHITE_BALANCE_FINE: 
    548         return "White Balance Fine"; 
    549       case WHITE_BALANCE_RGB_COEFFS: 
    550         return "White Balance (RGB coefficients)"; 
    551       case FLASH_COMPENSATION: 
    552         return "Flash compensation"; 
    553       case TONE_COMPENSATION: 
    554         return "Tone compensation"; 
    555       case LENS_TYPE: 
    556         return "Lens type"; 
    557       case LENS: 
    558         return "Lens"; 
    559       case FLASH_USED: 
    560         return "Flash used?"; 
    561       case CURVE: 
    562         return "Curve"; 
    563       case COLOR_MODE: 
    564         return "Color mode"; 
    565       case LIGHT_TYPE: 
    566         return "Light type"; 
    567       case HUE: 
    568         return "Hue"; 
    569       case CAPTURE_EDITOR_DATA: 
    570         return "Capture Editor Data"; 
    571     } 
    572     return "" + tag; 
    573   } 
    574  
    575406} 
  • branches/cleanup/components/bio-formats/src/loci/formats/in/ZeissLSMReader.java

    r5956 r5958  
    364364      s.order(isLittleEndian()); 
    365365      s.seek(0); 
    366       ifdsList.set(i, new TiffParser(s).getIFDs(true)); 
     366      ifdsList.set(i, new TiffParser(s).getNonThumbnailIFDs()); 
    367367      s.close(); 
    368368    } 
  • branches/cleanup/components/bio-formats/src/loci/formats/out/TiffWriter.java

    r5957 r5958  
    141141 
    142142        for (long ifdNum=0; ifdNum<ifdMax; ifdNum++) { 
    143           tiffParser.getIFD(ifdNum, offset); 
     143          tiffParser.getIFD(offset); 
    144144          offset = tmp.readInt(); 
    145145          if (offset <= 0 || offset >= tmp.length()) break; 
  • branches/cleanup/components/bio-formats/src/loci/formats/tiff/IFD.java

    r5957 r5958  
    151151  public static final int TILE_OFFSETS = 324; 
    152152  public static final int TILE_BYTE_COUNTS = 325; 
     153  public static final int SUB_IFD = 330; 
    153154  public static final int INK_SET = 332; 
    154155  public static final int INK_NAMES = 333; 
     
    178179  public static final int EXIF = 34665; 
    179180 
     181  /** EXIF tags. */ 
     182  public static final int EXPOSURE_TIME = 33434; 
     183  public static final int F_NUMBER = 33437; 
     184  public static final int EXPOSURE_PROGRAM = 34850; 
     185  public static final int SPECTRAL_SENSITIVITY = 34852; 
     186  public static final int ISO_SPEED_RATINGS = 34855; 
     187  public static final int OECF = 34856; 
     188  public static final int EXIF_VERSION = 36864; 
     189  public static final int DATE_TIME_ORIGINAL = 36867; 
     190  public static final int DATE_TIME_DIGITIZED = 36868; 
     191  public static final int COMPONENTS_CONFIGURATION = 37121; 
     192  public static final int COMPRESSED_BITS_PER_PIXEL = 37122; 
     193  public static final int SHUTTER_SPEED_VALUE = 37377; 
     194  public static final int APERTURE_VALUE = 37378; 
     195  public static final int BRIGHTNESS_VALUE = 37379; 
     196  public static final int EXPOSURE_BIAS_VALUE = 37380; 
     197  public static final int MAX_APERTURE_VALUE = 37381; 
     198  public static final int SUBJECT_DISTANCE = 37382; 
     199  public static final int METERING_MODE = 37383; 
     200  public static final int LIGHT_SOURCE = 37384; 
     201  public static final int FLASH = 37385; 
     202  public static final int FOCAL_LENGTH = 37386; 
     203  public static final int MAKER_NOTE = 37500; 
     204  public static final int USER_COMMENT = 37510; 
     205  public static final int SUB_SEC_TIME = 37520; 
     206  public static final int SUB_SEC_TIME_ORIGINAL = 37521; 
     207  public static final int SUB_SEC_TIME_DIGITIZED = 37522; 
     208  public static final int FLASH_PIX_VERSION = 40960; 
     209  public static final int COLOR_SPACE = 40961; 
     210  public static final int PIXEL_X_DIMENSION = 40962; 
     211  public static final int PIXEL_Y_DIMENSION = 40963; 
     212  public static final int RELATED_SOUND_FILE = 40964; 
     213  public static final int FLASH_ENERGY = 41483; 
     214  public static final int SPATIAL_FREQUENCY_RESPONSE = 41484; 
     215  public static final int FOCAL_PLANE_X_RESOLUTION = 41486; 
     216  public static final int FOCAL_PLANE_Y_RESOLUTION = 41487; 
     217  public static final int FOCAL_PLANE_RESOLUTION_UNIT = 41488; 
     218  public static final int SUBJECT_LOCATION = 41492; 
     219  public static final int EXPOSURE_INDEX = 41493; 
     220  public static final int SENSING_METHOD = 41495; 
     221  public static final int FILE_SOURCE = 41728; 
     222  public static final int SCENE_TYPE = 41729; 
     223  public static final int CFA_PATTERN = 41730; 
     224  public static final int CUSTOM_RENDERED = 41985; 
     225  public static final int EXPOSURE_MODE = 41986; 
     226  public static final int WHITE_BALANCE = 41987; 
     227  public static final int DIGITAL_ZOOM_RATIO = 41988; 
     228  public static final int FOCAL_LENGTH_35MM_FILM = 41989; 
     229  public static final int SCENE_CAPTURE_TYPE = 41990; 
     230  public static final int GAIN_CONTROL = 41991; 
     231  public static final int CONTRAST = 41992; 
     232  public static final int SATURATION = 41993; 
     233  public static final int SHARPNESS = 41994; 
     234  public static final int SUBJECT_DISTANCE_RANGE = 41996; 
     235 
    180236  // -- Constructors -- 
    181237 
  • branches/cleanup/components/bio-formats/src/loci/formats/tiff/TiffParser.java

    r5957 r5958  
    6868  private boolean bigTiff; 
    6969 
     70  private boolean doCaching; 
     71 
    7072  // -- Constructors -- 
    7173 
    7274  /** Constructs a new TIFF parser from the given file name. */ 
    7375  public TiffParser(String filename) throws IOException { 
    74     this.in = new RandomAccessInputStream(filename); 
     76    this(new RandomAccessInputStream(filename)); 
    7577  } 
    7678 
     
    7880  public TiffParser(RandomAccessInputStream in) { 
    7981    this.in = in; 
     82    doCaching = true; 
    8083  } 
    8184 
    8285  // -- TiffParser methods -- 
     86 
     87  /** Sets whether or not IFD entries should be cached. */ 
     88  public void setDoCaching(boolean doCaching) { 
     89    this.doCaching = doCaching; 
     90  } 
    8391 
    8492  /** Gets the stream from which TIFF data is being parsed. */ 
     
    137145  // -- TiffParser methods - IFD parsing -- 
    138146 
    139   /** 
    140    * Gets all IFDs within the TIFF file, or null 
    141    * if the input source is not a valid TIFF file. 
    142    */ 
     147  /** Returns all IFDs in the file.  */ 
    143148  public IFDList getIFDs() throws IOException { 
    144     return getIFDs(false); 
    145   } 
    146  
    147   /** 
    148    * Gets all IFDs within the TIFF file, or null 
    149    * if the input source is not a valid TIFF file. 
    150    * If 'skipThumbnails' is set to true, thumbnail IFDs will not be returned. 
    151    */ 
    152   public IFDList getIFDs(boolean skipThumbnails) throws IOException { 
    153     return getIFDs(skipThumbnails, true); 
    154   } 
    155  
    156   /** 
    157    * Gets all IFDs within the TIFF file, or null 
    158    * if the input source is not a valid TIFF file. 
    159    * If 'skipThumbnails' is set to true, thumbnail IFDs will not be returned. 
    160    * If 'fillInEntries' is set to true, IFD entry values that are stored at 
    161    * an arbitrary offset will be read. 
    162    */ 
    163   public IFDList getIFDs(boolean skipThumbnails, boolean fillInEntries) 
    164     throws IOException 
    165   { 
    166     // check TIFF header 
    167     Boolean result = checkHeader(); 
    168     if (result == null) return null; 
    169  
    170     long offset = getFirstOffset(); 
    171  
    172     // compute maximum possible number of IFDs, for loop safety 
    173     // each IFD must have at least one directory entry, which means that 
    174     // each IFD must be at least 2 + 12 + 4 = 18 bytes in length 
    175     long ifdMax = (in.length() - 8) / (bigTiff ? 22 : 18); 
    176  
    177     // read in IFDs 
     149    long[] offsets = getIFDOffsets(); 
    178150    IFDList ifds = new IFDList(); 
    179     for (long ifdNum=0; ifdNum<ifdMax; ifdNum++) { 
    180       IFD ifd = getIFD(ifdNum, offset, fillInEntries); 
    181       if (ifd == null || ifd.size() <= 2) break; 
    182       Number subfile = (Number) ifd.getIFDValue(IFD.NEW_SUBFILE_TYPE); 
     151 
     152    for (long offset : offsets) { 
     153      IFD ifd = getIFD(offset); 
     154      if (ifd == null) continue; 
     155      ifds.add(ifd); 
     156      long[] subOffsets = null; 
     157      try { 
     158        subOffsets = ifd.getIFDLongArray(IFD.SUB_IFD, false); 
     159      } 
     160      catch (FormatException e) { } 
     161      if (subOffsets != null) { 
     162        for (long subOffset : subOffsets) { 
     163          IFD sub = getIFD(subOffset); 
     164          if (sub != null) { 
     165            ifds.add(sub); 
     166          } 
     167        } 
     168      } 
     169    } 
     170 
     171    return ifds; 
     172  } 
     173 
     174  /** Returns thumbnail IFDs. */ 
     175  public IFDList getThumbnailIFDs() throws IOException { 
     176    IFDList ifds = getIFDs(); 
     177    for (int i=0; i<ifds.size(); i++) { 
     178      Number subfile = (Number) ifds.get(i).getIFDValue(IFD.NEW_SUBFILE_TYPE); 
    183179      int subfileType = subfile == null ? 0 : subfile.intValue(); 
    184       if (!skipThumbnails || subfileType == 0) { 
    185         ifds.add(ifd); 
    186       } 
    187       else ifd = null; 
    188       offset = getNextOffset(offset); 
    189       if (offset <= 0 || offset >= in.length()) { 
    190         if (offset != 0) { 
    191           LOGGER.debug("getIFDs: invalid IFD offset: {}", offset); 
     180      if (subfileType == 0) { 
     181        ifds.remove(i--); 
     182      } 
     183    } 
     184    return ifds; 
     185  } 
     186 
     187  /** Returns non-thumbnail IFDs. */ 
     188  public IFDList getNonThumbnailIFDs() throws IOException { 
     189    IFDList ifds = getIFDs(); 
     190    for (int i=0; i<ifds.size(); i++) { 
     191      Number subfile = (Number) ifds.get(i).getIFDValue(IFD.NEW_SUBFILE_TYPE); 
     192      int subfileType = subfile == null ? 0 : subfile.intValue(); 
     193      if (subfileType != 0) { 
     194        ifds.remove(i--); 
     195      } 
     196    } 
     197    return ifds; 
     198  } 
     199 
     200  /** Returns EXIF IFDs. */ 
     201  public IFDList getExifIFDs() throws FormatException, IOException { 
     202    IFDList ifds = getIFDs(); 
     203    IFDList exif = new IFDList(); 
     204    for (IFD ifd : ifds) { 
     205      long offset = ifd.getIFDLongValue(IFD.EXIF, false, 0); 
     206      if (offset != 0) { 
     207        IFD exifIFD = getIFD(offset); 
     208        if (exifIFD != null) { 
     209          exif.add(exifIFD); 
    192210        } 
    193         break; 
    194       } 
    195     } 
    196  
    197     return ifds; 
     211      } 
     212    } 
     213    return exif; 
    198214  } 
    199215 
     
    209225    Vector<Long> offsets = new Vector<Long>(); 
    210226    long offset = getFirstOffset(); 
    211     while (true) { 
     227    while (offset > 0 && offset < in.length()) { 
    212228      in.seek(offset); 
    213229      offsets.add(offset); 
     
    215231      in.skipBytes(nEntries * bytesPerEntry); 
    216232      offset = getNextOffset(offset); 
    217       if (offset <= 0 || offset >= in.length()) break; 
    218233    } 
    219234 
     
    236251 
    237252    long offset = getFirstOffset(); 
    238  
    239     IFD ifd = getIFD(0, offset); 
    240     return ifd; 
     253    return getIFD(offset); 
    241254  } 
    242255 
     
    265278    for (int i = 0; i < numEntries; i++) { 
    266279      in.seek(offset + // The beginning of the IFD 
    267         2 + // The width of the initial numEntries field 
     280        (bigTiff ? 8 : 2) + // The width of the initial numEntries field 
    268281        (bigTiff ? TiffConstants.BIG_TIFF_BYTES_PER_ENTRY : 
    269282        TiffConstants.BYTES_PER_ENTRY) * i); 
    270283 
    271       int entryTag = in.readShort() & 0xffff; 
    272  
    273       // Skip this tag unless it matches the one we want 
    274       if (entryTag != tag) continue; 
    275  
    276       // Parse the entry's "Type" 
    277       int entryType = in.readShort() & 0xffff; 
    278  
    279       // Parse the entry's "ValueCount" 
    280       int valueCount = 
    281         bigTiff ? (int) (in.readLong() & 0xffffffff) : in.readInt(); 
    282       if (valueCount < 0) { 
    283         throw new RuntimeException("Count of '" + valueCount + "' unexpected."); 
    284       } 
    285  
    286       // Parse the entry's "ValueOffset" 
    287       long valueOffset = getNextOffset(0); 
    288  
    289       return new TiffIFDEntry(entryTag, entryType, valueCount, valueOffset); 
     284      TiffIFDEntry entry = readTiffIFDEntry(); 
     285      if (entry.getTag() == tag) { 
     286        return entry; 
     287      } 
    290288    } 
    291289    throw new IllegalArgumentException("Unknown tag: " + tag); 
     
    301299  } 
    302300 
    303   /** Gets the IFD stored at the given offset. */ 
    304   public IFD getIFD(long ifdNum, long offset) throws IOException { 
    305     return getIFD(ifdNum, offset, true); 
    306   } 
    307  
    308   /** 
    309    * Gets the IFD stored at the given offset. 
    310    * If 'fillInEntries' is set to true, IFD entry values that are stored at 
    311    * an arbitrary offset will be read. 
    312    */ 
    313   public IFD getIFD(long ifdNum, long offset, boolean fillInEntries) 
    314     throws IOException 
    315   { 
     301  /** Gets the IFD stored at the given offset.  */ 
     302  public IFD getIFD(long offset) throws IOException { 
    316303    IFD ifd = new IFD(); 
    317304 
     
    321308 
    322309    // read in directory entries for this IFD 
    323     LOGGER.debug("getIFDs: seeking IFD #{} at {}", ifdNum, offset); 
     310    LOGGER.debug("getIFDs: seeking IFD at {}", offset); 
    324311    in.seek(offset); 
    325312    long numEntries = bigTiff ? in.readLong() : in.readShort() & 0xffff; 
     
    334321    for (int i=0; i<numEntries; i++) { 
    335322      in.seek(offset + baseOffset + bytesPerEntry * i); 
    336       int tag = in.readShort() & 0xffff; 
    337       int type = in.readShort() & 0xffff; 
    338       // BigTIFF case is a slight hack because the count could be 
    339       // greater than Integer.MAX_VALUE 
    340       int count = bigTiff ? (int) (in.readLong() & 0xffffffff) : in.readInt(); 
    341       int bpe = IFD.getIFDTypeLength(type); 
    342  
    343       LOGGER.debug("getIFDs: read {} (type={}; count={})", 
    344         new Object[] {IFD.getIFDTagName(tag), IFD.getIFDTypeName(type), count}); 
     323 
     324      TiffIFDEntry entry = readTiffIFDEntry(); 
     325      int count = entry.getValueCount(); 
     326      int tag = entry.getTag(); 
     327      long pointer = entry.getValueOffset(); 
     328      int bpe = IFD.getIFDTypeLength(entry.getType()); 
     329 
    345330      if (count < 0 || bpe <= 0) { 
    346331        // invalid data 
     
    349334      } 
    350335      Object value = null; 
    351  
    352       long pointer = in.getFilePointer(); 
    353  
    354       if (count > threshhold / bpe) { 
    355         pointer = getNextOffset(0); 
    356       } 
    357336 
    358337      long inputLen = in.length(); 
     
    365344      if (count < 0 || count > in.length()) break; 
    366345 
    367       TiffIFDEntry entry = new TiffIFDEntry(tag, type, count, pointer); 
    368  
    369       if (pointer != in.getFilePointer() && !fillInEntries) { 
     346      if (pointer != in.getFilePointer() && !doCaching) { 
    370347        value = entry; 
    371348      } 
     
    378355 
    379356    in.seek(offset + baseOffset + bytesPerEntry * numEntries); 
    380  
    381     if (!(ifd.get(IFD.IMAGE_WIDTH) instanceof Number) || 
    382       !(ifd.get(IFD.IMAGE_LENGTH) instanceof Number)) 
    383     { 
    384       return null; 
    385     } 
    386357 
    387358    return ifd; 
     
    968939    return offset; 
    969940  } 
     941 
     942  TiffIFDEntry readTiffIFDEntry() throws IOException { 
     943    int entryTag = in.readShort() & 0xffff; 
     944 
     945    // Parse the entry's "Type" 
     946    int entryType = in.readShort() & 0xffff; 
     947 
     948    // Parse the entry's "ValueCount" 
     949    int valueCount = 
     950      bigTiff ? (int) (in.readLong() & 0xffffffff) : in.readInt(); 
     951    if (valueCount < 0) { 
     952      throw new RuntimeException("Count of '" + valueCount + "' unexpected."); 
     953    } 
     954 
     955    int nValueBytes = valueCount * IFD.getIFDTypeLength(entryType); 
     956    int threshhold = bigTiff ? 8 : 4; 
     957    long offset = nValueBytes > threshhold ? 
     958      getNextOffset(0) : in.getFilePointer(); 
     959 
     960    return new TiffIFDEntry(entryTag, entryType, valueCount, offset); 
     961  } 
     962 
    970963} 
Note: See TracChangeset for help on using the changeset viewer.