Exemplo n.º 1
0
 public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
   seekToImage(imageIndex);
   TIFFImageMetadata im = new TIFFImageMetadata(imageMetadata.getRootIFD().getTagSetList());
   Node root = imageMetadata.getAsTree(TIFFImageMetadata.nativeMetadataFormatName);
   im.setFromTree(TIFFImageMetadata.nativeMetadataFormatName, root);
   return im;
 }
Exemplo n.º 2
0
  /**
   * Invokes the superclass method and then sets instance variables on the basis of the metadata set
   * on this decompressor.
   */
  public void beginDecoding() {
    super.beginDecoding();

    if (metadata instanceof TIFFImageMetadata) {
      TIFFImageMetadata tmetadata = (TIFFImageMetadata) metadata;
      TIFFField f;

      f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
      this.fillOrder = f == null ? BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT : f.getAsInt(0);

      f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
      this.compression = f == null ? BaselineTIFFTagSet.COMPRESSION_CCITT_RLE : f.getAsInt(0);

      f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_T4_OPTIONS);
      this.t4Options = f == null ? 0 : f.getAsInt(0);
      this.oneD = (t4Options & 0x01);
      // uncompressedMode - haven't dealt with this yet.
      this.uncompressedMode = ((t4Options & 0x02) >> 1);
      this.fillBits = ((t4Options & 0x04) >> 2);
      f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_T6_OPTIONS);
      this.t6Options = f == null ? 0 : f.getAsInt(0);
    } else {
      this.fillOrder = BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT;

      this.compression = BaselineTIFFTagSet.COMPRESSION_CCITT_RLE; // RLE

      this.t4Options = 0; // Irrelevant as applies to T.4 only
      this.oneD = 0; // One-dimensional
      this.uncompressedMode = 0; // Not uncompressed mode
      this.fillBits = 0; // No fill bits
      this.t6Options = 0;
    }
  }
Exemplo n.º 3
0
  private int getPlanarConfiguration() {
    TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
    if (f != null) {
      int planarConfigurationValue = f.getAsInt(0);
      if (planarConfigurationValue == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
        // Some writers (e.g. Kofax standard Multi-Page TIFF
        // Storage Filter v2.01.000; cf. bug 4929147) do not
        // correctly set the value of this field. Attempt to
        // ascertain whether the value is correctly Planar.
        if (getCompression() == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG
            && imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) != null) {
          // JPEG interchange format cannot have
          // PlanarConfiguration value Chunky so reset.
          processWarningOccurred(
              "PlanarConfiguration \"Planar\" value inconsistent with JPEGInterchangeFormat; resetting to \"Chunky\".");
          planarConfigurationValue = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
        } else {
          TIFFField offsetField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
          if (offsetField == null) {
            // Tiles
            offsetField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
            int tw = getTileOrStripWidth();
            int th = getTileOrStripHeight();
            int tAcross = (getWidth() + tw - 1) / tw;
            int tDown = (getHeight() + th - 1) / th;
            int tilesPerImage = tAcross * tDown;
            long[] offsetArray = offsetField.getAsLongs();
            if (offsetArray != null && offsetArray.length == tilesPerImage) {
              // Length of offsets array is
              // TilesPerImage for Chunky and
              // SamplesPerPixel*TilesPerImage for Planar.
              processWarningOccurred(
                  "PlanarConfiguration \"Planar\" value inconsistent with TileOffsets field value count; resetting to \"Chunky\".");
              planarConfigurationValue = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
            }
          } else {
            // Strips
            int rowsPerStrip = getTileOrStripHeight();
            int stripsPerImage = (getHeight() + rowsPerStrip - 1) / rowsPerStrip;
            long[] offsetArray = offsetField.getAsLongs();
            if (offsetArray != null && offsetArray.length == stripsPerImage) {
              // Length of offsets array is
              // StripsPerImage for Chunky and
              // SamplesPerPixel*StripsPerImage for Planar.
              processWarningOccurred(
                  "PlanarConfiguration \"Planar\" value inconsistent with StripOffsets field value count; resetting to \"Chunky\".");
              planarConfigurationValue = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
            }
          }
        }
      }
      return planarConfigurationValue;
    }

    return BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
  }
Exemplo n.º 4
0
  // Returns tile height if image is tiled, else strip height
  private int getTileOrStripHeight() {
    TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_LENGTH);
    if (f != null) {
      return f.getAsInt(0);
    }

    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_ROWS_PER_STRIP);
    // Default for ROWS_PER_STRIP is 2^32 - 1, i.e., infinity
    int h = (f == null) ? -1 : f.getAsInt(0);
    return (h == -1) ? getHeight() : h;
  }
Exemplo n.º 5
0
  private long getTileOrStripOffset(int tileIndex) throws IIOException {
    TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
    if (f == null) {
      f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
    }
    if (f == null) {
      f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
    }

    if (f == null) {
      throw new IIOException("Missing required strip or tile offsets field.");
    }

    return f.getAsLong(tileIndex);
  }
Exemplo n.º 6
0
  // Stream must be positioned at start of IFD for 'currIndex'
  private void readMetadata() throws IIOException {
    if (stream == null) {
      throw new IllegalStateException("Input not set!");
    }

    if (imageMetadata != null) {
      return;
    }
    try {
      // Create an object to store the image metadata
      List tagSets;
      if (imageReadParam instanceof TIFFImageReadParam) {
        tagSets = ((TIFFImageReadParam) imageReadParam).getAllowedTagSets();
      } else {
        tagSets = new ArrayList(1);
        tagSets.add(BaselineTIFFTagSet.getInstance());
      }

      this.imageMetadata = new TIFFImageMetadata(tagSets);
      imageMetadata.initializeFromStream(stream, ignoreMetadata);
    } catch (IIOException iioe) {
      throw iioe;
    } catch (IOException ioe) {
      throw new IIOException("I/O error reading image metadata!", ioe);
    }
  }
Exemplo n.º 7
0
 private int getCompression() {
   TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
   if (f == null) {
     return BaselineTIFFTagSet.COMPRESSION_NONE;
   } else {
     return f.getAsInt(0);
   }
 }
  public TIFFYCbCrColorConverter(TIFFImageMetadata metadata) {
    TIFFImageMetadata tmetadata = (TIFFImageMetadata) metadata;

    TIFFField f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS);
    if (f != null && f.getCount() == 3) {
      this.LumaRed = f.getAsFloat(0);
      this.LumaGreen = f.getAsFloat(1);
      this.LumaBlue = f.getAsFloat(2);
    }

    f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE);
    if (f != null && f.getCount() == 6) {
      this.referenceBlackY = f.getAsFloat(0);
      this.referenceWhiteY = f.getAsFloat(1);
      this.referenceBlackCb = f.getAsFloat(2);
      this.referenceWhiteCb = f.getAsFloat(3);
      this.referenceBlackCr = f.getAsFloat(4);
      this.referenceWhiteCr = f.getAsFloat(5);
    }
  }
Exemplo n.º 9
0
  private long getTileOrStripByteCount(int tileIndex) throws IOException {
    TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS);
    if (f == null) {
      f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS);
    }
    if (f == null) {
      f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
    }

    long tileOrStripByteCount;
    if (f != null) {
      tileOrStripByteCount = f.getAsLong(tileIndex);
    } else {
      processWarningOccurred(
          "TIFF directory contains neither StripByteCounts nor TileByteCounts field: attempting to calculate from strip or tile width and height.");

      // Initialize to number of bytes per strip or tile assuming
      // no compression.
      int bitsPerPixel = bitsPerSample[0];
      for (int i = 1; i < samplesPerPixel; i++) {
        bitsPerPixel += bitsPerSample[i];
      }
      int bytesPerRow = (getTileOrStripWidth() * bitsPerPixel + 7) / 8;
      tileOrStripByteCount = bytesPerRow * getTileOrStripHeight();

      // Clamp to end of stream if possible.
      long streamLength = stream.length();
      if (streamLength != -1) {
        tileOrStripByteCount =
            Math.min(tileOrStripByteCount, streamLength - getTileOrStripOffset(tileIndex));
      } else {
        processWarningOccurred(
            "Stream length is unknown: cannot clamp estimated strip or tile byte count to EOF.");
      }
    }

    return tileOrStripByteCount;
  }
Exemplo n.º 10
0
  public boolean isImageTiled(int imageIndex) throws IOException {
    seekToImage(imageIndex);

    TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
    return f != null;
  }
Exemplo n.º 11
0
  public Iterator getImageTypes(int imageIndex) throws IIOException {
    List l; // List of ImageTypeSpecifiers

    Integer imageIndexInteger = new Integer(imageIndex);
    if (imageTypeMap.containsKey(imageIndexInteger)) {
      // Return the cached ITS List.
      l = (List) imageTypeMap.get(imageIndexInteger);
    } else {
      // Create a new ITS List.
      l = new ArrayList(1);

      // Create the ITS and cache if for later use so that this method
      // always returns an Iterator containing the same ITS objects.
      seekToImage(imageIndex);
      ImageTypeSpecifier itsRaw =
          TIFFDecompressor.getRawImageTypeSpecifier(
              photometricInterpretation,
              compression,
              samplesPerPixel,
              bitsPerSample,
              sampleFormat,
              extraSamples,
              colorMap);

      // Check for an ICCProfile field.
      TIFFField iccProfileField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE);

      // If an ICCProfile field is present change the ImageTypeSpecifier
      // to use it if the data layout is component type.
      if (iccProfileField != null && itsRaw.getColorModel() instanceof ComponentColorModel) {
        // Create a ColorSpace from the profile.
        byte[] iccProfileValue = iccProfileField.getAsBytes();
        ICC_Profile iccProfile = ICC_Profile.getInstance(iccProfileValue);
        ICC_ColorSpace iccColorSpace = new ICC_ColorSpace(iccProfile);

        // Get the raw sample and color information.
        ColorModel cmRaw = itsRaw.getColorModel();
        ColorSpace csRaw = cmRaw.getColorSpace();
        SampleModel smRaw = itsRaw.getSampleModel();

        // Get the number of samples per pixel and the number
        // of color components.
        int numBands = smRaw.getNumBands();
        int numComponents = iccColorSpace.getNumComponents();

        // Replace the ColorModel with the ICC ColorModel if the
        // numbers of samples and color components are amenable.
        if (numBands == numComponents || numBands == numComponents + 1) {
          // Set alpha flags.
          boolean hasAlpha = numComponents != numBands;
          boolean isAlphaPre = hasAlpha && cmRaw.isAlphaPremultiplied();

          // Create a ColorModel of the same class and with
          // the same transfer type.
          ColorModel iccColorModel =
              new ComponentColorModel(
                  iccColorSpace,
                  cmRaw.getComponentSize(),
                  hasAlpha,
                  isAlphaPre,
                  cmRaw.getTransparency(),
                  cmRaw.getTransferType());

          // Prepend the ICC profile-based ITS to the List. The
          // ColorModel and SampleModel are guaranteed to be
          // compatible as the old and new ColorModels are both
          // ComponentColorModels with the same transfer type
          // and the same number of components.
          l.add(new ImageTypeSpecifier(iccColorModel, smRaw));

          // Append the raw ITS to the List if and only if its
          // ColorSpace has the same type and number of components
          // as the ICC ColorSpace.
          if (csRaw.getType() == iccColorSpace.getType()
              && csRaw.getNumComponents() == iccColorSpace.getNumComponents()) {
            l.add(itsRaw);
          }
        } else { // ICCProfile not compatible with SampleModel.
          // Append the raw ITS to the List.
          l.add(itsRaw);
        }
      } else { // No ICCProfile field or raw ColorModel not component.
        // Append the raw ITS to the List.
        l.add(itsRaw);
      }

      // Cache the ITS List.
      imageTypeMap.put(imageIndexInteger, l);
    }

    return l.iterator();
  }
Exemplo n.º 12
0
  /**
   * Initializes these instance variables from the image metadata:
   *
   * <pre>
   * compression
   * width
   * height
   * samplesPerPixel
   * numBands
   * colorMap
   * photometricInterpretation
   * sampleFormat
   * bitsPerSample
   * extraSamples
   * tileOrStripWidth
   * tileOrStripHeight
   * </pre>
   */
  private void initializeFromMetadata() {
    TIFFField f;

    // Compression
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
    if (f == null) {
      processWarningOccurred("Compression field is missing; assuming no compression");
      compression = BaselineTIFFTagSet.COMPRESSION_NONE;
    } else {
      compression = f.getAsInt(0);
    }

    // Whether key dimensional information is absent.
    boolean isMissingDimension = false;

    // ImageWidth -> width
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
    if (f != null) {
      this.width = f.getAsInt(0);
    } else {
      processWarningOccurred("ImageWidth field is missing.");
      isMissingDimension = true;
    }

    // ImageLength -> height
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH);
    if (f != null) {
      this.height = f.getAsInt(0);
    } else {
      processWarningOccurred("ImageLength field is missing.");
      isMissingDimension = true;
    }

    // SamplesPerPixel
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
    if (f != null) {
      samplesPerPixel = f.getAsInt(0);
    } else {
      samplesPerPixel = 1;
      isMissingDimension = true;
    }

    // If any dimension is missing and there is a JPEG stream available
    // get the information from it.
    int defaultBitDepth = 1;
    if (isMissingDimension
        && (f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT))
            != null) {
      Iterator iter = ImageIO.getImageReadersByFormatName("JPEG");
      if (iter != null && iter.hasNext()) {
        ImageReader jreader = (ImageReader) iter.next();
        try {
          stream.mark();
          stream.seek(f.getAsLong(0));
          jreader.setInput(stream);
          if (imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH) == null) {
            this.width = jreader.getWidth(0);
          }
          if (imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH) == null) {
            this.height = jreader.getHeight(0);
          }
          ImageTypeSpecifier imageType = jreader.getRawImageType(0);
          if (imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL) == null) {
            this.samplesPerPixel = imageType.getSampleModel().getNumBands();
          }
          stream.reset();
          defaultBitDepth = imageType.getColorModel().getComponentSize(0);
        } catch (IOException e) {
          // Ignore it and proceed: an error will occur later.
        }
        jreader.dispose();
      }
    }

    if (samplesPerPixel < 1) {
      processWarningOccurred("Samples per pixel < 1!");
    }

    // SamplesPerPixel -> numBands
    numBands = samplesPerPixel;

    // ColorMap
    this.colorMap = null;
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP);
    if (f != null) {
      // Grab color map
      colorMap = f.getAsChars();
    }

    // PhotometricInterpretation
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
    if (f == null) {
      if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE
          || compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_4
          || compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_6) {
        processWarningOccurred(
            "PhotometricInterpretation field is missing; " + "assuming WhiteIsZero");
        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
      } else if (this.colorMap != null) {
        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
      } else if (samplesPerPixel == 3 || samplesPerPixel == 4) {
        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB;
      } else {
        processWarningOccurred(
            "PhotometricInterpretation field is missing; " + "assuming BlackIsZero");
        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
      }
    } else {
      photometricInterpretation = f.getAsInt(0);
    }

    // SampleFormat
    boolean replicateFirst = false;
    int first = -1;

    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
    sampleFormat = new int[samplesPerPixel];
    replicateFirst = false;
    if (f == null) {
      replicateFirst = true;
      first = BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED;
    } else if (f.getCount() != samplesPerPixel) {
      replicateFirst = true;
      first = f.getAsInt(0);
    }

    for (int i = 0; i < samplesPerPixel; i++) {
      sampleFormat[i] = replicateFirst ? first : f.getAsInt(i);
      if (sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER
          && sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER
          && sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT
          && sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED) {
        processWarningOccurred("Illegal value for SAMPLE_FORMAT, assuming SAMPLE_FORMAT_UNDEFINED");
        sampleFormat[i] = BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED;
      }
    }

    // BitsPerSample
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
    this.bitsPerSample = new int[samplesPerPixel];
    replicateFirst = false;
    if (f == null) {
      replicateFirst = true;
      first = defaultBitDepth;
    } else if (f.getCount() != samplesPerPixel) {
      replicateFirst = true;
      first = f.getAsInt(0);
    }

    for (int i = 0; i < samplesPerPixel; i++) {
      // Replicate initial value if not enough values provided
      bitsPerSample[i] = replicateFirst ? first : f.getAsInt(i);

      if (DEBUG) {
        System.out.println("bitsPerSample[" + i + "] = " + bitsPerSample[i]);
      }
    }

    // ExtraSamples
    this.extraSamples = null;
    f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
    if (f != null) {
      extraSamples = f.getAsInts();
    }

    //         System.out.println("colorMap = " + colorMap);
    //         if (colorMap != null) {
    //             for (int i = 0; i < colorMap.length; i++) {
    //              System.out.println("colorMap[" + i + "] = " + (int)(colorMap[i]));
    //             }
    //         }

  }
Exemplo n.º 13
0
 // Returns tile width if image is tiled, else image width
 private int getTileOrStripWidth() {
   TIFFField f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
   return (f == null) ? getWidth() : f.getAsInt(0);
 }
Exemplo n.º 14
0
  public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
    prepareRead(imageIndex, param);
    this.theImage = getDestination(param, getImageTypes(imageIndex), width, height);

    srcXSubsampling = imageReadParam.getSourceXSubsampling();
    srcYSubsampling = imageReadParam.getSourceYSubsampling();

    Point p = imageReadParam.getDestinationOffset();
    dstXOffset = p.x;
    dstYOffset = p.y;

    // This could probably be made more efficient...
    Rectangle srcRegion = new Rectangle(0, 0, 0, 0);
    Rectangle destRegion = new Rectangle(0, 0, 0, 0);

    computeRegions(imageReadParam, width, height, theImage, srcRegion, destRegion);

    // Initial source pixel, taking source region and source
    // subsamplimg offsets into account
    sourceXOffset = srcRegion.x;
    sourceYOffset = srcRegion.y;

    pixelsToRead = destRegion.width * destRegion.height;
    pixelsRead = 0;

    processImageStarted(imageIndex);
    processImageProgress(0.0f);

    tilesAcross = (width + tileOrStripWidth - 1) / tileOrStripWidth;
    tilesDown = (height + tileOrStripHeight - 1) / tileOrStripHeight;

    int compression = getCompression();

    // Attempt to get decompressor and color converted from the read param

    TIFFColorConverter colorConverter = null;
    if (imageReadParam instanceof TIFFImageReadParam) {
      TIFFImageReadParam tparam = (TIFFImageReadParam) imageReadParam;
      this.decompressor = tparam.getTIFFDecompressor();
      colorConverter = tparam.getColorConverter();
    }

    // If we didn't find one, use a standard decompressor
    if (this.decompressor == null) {
      if (compression == BaselineTIFFTagSet.COMPRESSION_NONE) {
        // Get the fillOrder field.
        TIFFField fillOrderField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);

        // Set the decompressor based on the fill order.
        if (fillOrderField != null && fillOrderField.getAsInt(0) == 2) {
          this.decompressor = new TIFFLSBDecompressor();
        } else {
          this.decompressor = new TIFFNullDecompressor();
        }
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_6) {
        this.decompressor = new TIFFFaxDecompressor();
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_4) {
        this.decompressor = new TIFFFaxDecompressor();
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE) {
        this.decompressor = new TIFFFaxDecompressor();
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_PACKBITS) {
        if (DEBUG) {
          System.out.println("Using TIFFPackBitsDecompressor");
        }
        this.decompressor = new TIFFPackBitsDecompressor();
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_LZW) {
        if (DEBUG) {
          System.out.println("Using TIFFLZWDecompressor");
        }
        TIFFField predictorField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR);
        int predictor =
            ((predictorField == null)
                ? BaselineTIFFTagSet.PREDICTOR_NONE
                : predictorField.getAsInt(0));
        this.decompressor = new TIFFLZWDecompressor(predictor);
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_JPEG) {
        this.decompressor = new TIFFJPEGDecompressor();
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_ZLIB
          || compression == BaselineTIFFTagSet.COMPRESSION_DEFLATE) {
        TIFFField predictorField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR);
        int predictor =
            ((predictorField == null)
                ? BaselineTIFFTagSet.PREDICTOR_NONE
                : predictorField.getAsInt(0));
        this.decompressor = new TIFFDeflateDecompressor(predictor);
      } else if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
        TIFFField JPEGProcField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_PROC);
        if (JPEGProcField == null) {
          processWarningOccurred(
              "JPEGProc field missing; assuming baseline sequential JPEG process.");
        } else if (JPEGProcField.getAsInt(0) != BaselineTIFFTagSet.JPEG_PROC_BASELINE) {
          throw new IIOException(
              "Old-style JPEG supported for baseline sequential JPEG process only!");
        }
        this.decompressor = new TIFFOldJPEGDecompressor();
        // throw new IIOException("Old-style JPEG not supported!");
      } else {
        throw new IIOException("Unsupported compression type (tag number = " + compression + ")!");
      }

      if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR
          && compression != BaselineTIFFTagSet.COMPRESSION_JPEG
          && compression != BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
        boolean convertYCbCrToRGB =
            theImage.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_RGB;
        TIFFDecompressor wrappedDecompressor =
            this.decompressor instanceof TIFFNullDecompressor ? null : this.decompressor;
        this.decompressor = new TIFFYCbCrDecompressor(wrappedDecompressor, convertYCbCrToRGB);
      }
    }

    if (DEBUG) {
      System.out.println("\nDecompressor class = " + decompressor.getClass().getName() + "\n");
    }

    if (colorConverter == null) {
      if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB
          && theImage.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_RGB) {
        colorConverter = new TIFFCIELabColorConverter();
      } else if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR
          && !(this.decompressor instanceof TIFFYCbCrDecompressor)
          && compression != BaselineTIFFTagSet.COMPRESSION_JPEG
          && compression != BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
        colorConverter = new TIFFYCbCrColorConverter(imageMetadata);
      }
    }

    decompressor.setReader(this);
    decompressor.setMetadata(imageMetadata);
    decompressor.setImage(theImage);

    decompressor.setPhotometricInterpretation(photometricInterpretation);
    decompressor.setCompression(compression);
    decompressor.setSamplesPerPixel(samplesPerPixel);
    decompressor.setBitsPerSample(bitsPerSample);
    decompressor.setSampleFormat(sampleFormat);
    decompressor.setExtraSamples(extraSamples);
    decompressor.setColorMap(colorMap);

    decompressor.setColorConverter(colorConverter);

    decompressor.setSourceXOffset(sourceXOffset);
    decompressor.setSourceYOffset(sourceYOffset);
    decompressor.setSubsampleX(srcXSubsampling);
    decompressor.setSubsampleY(srcYSubsampling);

    decompressor.setDstXOffset(dstXOffset);
    decompressor.setDstYOffset(dstYOffset);

    decompressor.setSourceBands(sourceBands);
    decompressor.setDestinationBands(destinationBands);

    // Compute bounds on the tile indices for this source region.
    int minTileX = TIFFImageWriter.XToTileX(srcRegion.x, 0, tileOrStripWidth);
    int minTileY = TIFFImageWriter.YToTileY(srcRegion.y, 0, tileOrStripHeight);
    int maxTileX = TIFFImageWriter.XToTileX(srcRegion.x + srcRegion.width - 1, 0, tileOrStripWidth);
    int maxTileY =
        TIFFImageWriter.YToTileY(srcRegion.y + srcRegion.height - 1, 0, tileOrStripHeight);

    boolean isAbortRequested = false;
    if (planarConfiguration == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {

      decompressor.setPlanar(true);

      int[] sb = new int[1];
      int[] db = new int[1];
      for (int tj = minTileY; tj <= maxTileY; tj++) {
        for (int ti = minTileX; ti <= maxTileX; ti++) {
          for (int band = 0; band < numBands; band++) {
            sb[0] = sourceBands[band];
            decompressor.setSourceBands(sb);
            db[0] = destinationBands[band];
            decompressor.setDestinationBands(db);
            // XXX decompressor.beginDecoding();

            // The method abortRequested() is synchronized
            // so check it only once per loop just before
            // doing any actual decoding.
            if (abortRequested()) {
              isAbortRequested = true;
              break;
            }

            decodeTile(ti, tj, band);
          }

          if (isAbortRequested) break;

          reportProgress();
        }

        if (isAbortRequested) break;
      }
    } else {
      // XXX decompressor.beginDecoding();

      for (int tj = minTileY; tj <= maxTileY; tj++) {
        for (int ti = minTileX; ti <= maxTileX; ti++) {
          // The method abortRequested() is synchronized
          // so check it only once per loop just before
          // doing any actual decoding.
          if (abortRequested()) {
            isAbortRequested = true;
            break;
          }

          decodeTile(ti, tj, -1);

          reportProgress();
        }

        if (isAbortRequested) break;
      }
    }

    if (isAbortRequested) {
      processReadAborted();
    } else {
      processImageComplete();
    }

    return theImage;
  }