Esempio n. 1
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();
  }
Esempio n. 2
0
  private void decodeTile(int ti, int tj, int band) throws IOException {
    if (DEBUG) {
      System.out.println("decodeTile(" + ti + "," + tj + "," + band + ")");
    }

    // Compute the region covered by the strip or tile
    Rectangle tileRect =
        new Rectangle(
            ti * tileOrStripWidth, tj * tileOrStripHeight, tileOrStripWidth, tileOrStripHeight);

    // Clip against the image bounds if the image is not tiled. If it
    // is tiled, the tile may legally extend beyond the image bounds.
    if (!isImageTiled(currIndex)) {
      tileRect = tileRect.intersection(new Rectangle(0, 0, width, height));
    }

    // Return if the intersection is empty.
    if (tileRect.width <= 0 || tileRect.height <= 0) {
      return;
    }

    int srcMinX = tileRect.x;
    int srcMinY = tileRect.y;
    int srcWidth = tileRect.width;
    int srcHeight = tileRect.height;

    // Determine dest region that can be derived from the
    // source region

    dstMinX = iceil(srcMinX - sourceXOffset, srcXSubsampling);
    int dstMaxX = ifloor(srcMinX + srcWidth - 1 - sourceXOffset, srcXSubsampling);

    dstMinY = iceil(srcMinY - sourceYOffset, srcYSubsampling);
    int dstMaxY = ifloor(srcMinY + srcHeight - 1 - sourceYOffset, srcYSubsampling);

    dstWidth = dstMaxX - dstMinX + 1;
    dstHeight = dstMaxY - dstMinY + 1;

    dstMinX += dstXOffset;
    dstMinY += dstYOffset;

    // Clip against image bounds

    Rectangle dstRect =
        new Rectangle(
            dstMinX, dstMinY,
            dstWidth, dstHeight);
    dstRect = dstRect.intersection(theImage.getRaster().getBounds());

    dstMinX = dstRect.x;
    dstMinY = dstRect.y;
    dstWidth = dstRect.width;
    dstHeight = dstRect.height;

    if (dstWidth <= 0 || dstHeight <= 0) {
      return;
    }

    // Backwards map dest region to source to determine
    // active source region

    int activeSrcMinX = (dstMinX - dstXOffset) * srcXSubsampling + sourceXOffset;
    int sxmax = (dstMinX + dstWidth - 1 - dstXOffset) * srcXSubsampling + sourceXOffset;
    int activeSrcWidth = sxmax - activeSrcMinX + 1;

    int activeSrcMinY = (dstMinY - dstYOffset) * srcYSubsampling + sourceYOffset;
    int symax = (dstMinY + dstHeight - 1 - dstYOffset) * srcYSubsampling + sourceYOffset;
    int activeSrcHeight = symax - activeSrcMinY + 1;

    decompressor.setSrcMinX(srcMinX);
    decompressor.setSrcMinY(srcMinY);
    decompressor.setSrcWidth(srcWidth);
    decompressor.setSrcHeight(srcHeight);

    decompressor.setDstMinX(dstMinX);
    decompressor.setDstMinY(dstMinY);
    decompressor.setDstWidth(dstWidth);
    decompressor.setDstHeight(dstHeight);

    decompressor.setActiveSrcMinX(activeSrcMinX);
    decompressor.setActiveSrcMinY(activeSrcMinY);
    decompressor.setActiveSrcWidth(activeSrcWidth);
    decompressor.setActiveSrcHeight(activeSrcHeight);

    int tileIndex = tj * tilesAcross + ti;

    if (planarConfiguration == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
      tileIndex += band * tilesAcross * tilesDown;
    }

    long offset = getTileOrStripOffset(tileIndex);
    long byteCount = getTileOrStripByteCount(tileIndex);

    //
    // Attempt to handle truncated streams, i.e., where reading the
    // compressed strip or tile would result in an EOFException. The
    // number of bytes to read is clamped to the number available
    // from the stream starting at the indicated position in the hope
    // that the decompressor will handle it.
    //
    long streamLength = stream.length();
    if (streamLength > 0 && offset + byteCount > streamLength) {
      processWarningOccurred("Attempting to process truncated stream.");
      if (Math.max(byteCount = streamLength - offset, 0) == 0) {
        processWarningOccurred("No bytes in strip/tile: skipping.");
        return;
      }
    }

    decompressor.setStream(stream);
    decompressor.setOffset(offset);
    decompressor.setByteCount((int) byteCount);

    decompressor.beginDecoding();

    stream.mark();
    decompressor.decode();
    stream.reset();
  }
Esempio n. 3
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;
  }