public void runTest(Object ctx, int numReps) {
   final Context ictx = (Context) ctx;
   final ImageInputStream iis = ictx.inputStream;
   final int length = ictx.length;
   int pos = 0;
   try {
     iis.mark();
     do {
       if (pos + 4 > length) {
         iis.reset();
         iis.mark();
         pos = 0;
       }
       iis.readUnsignedInt();
       pos += 4;
     } while (--numReps >= 0);
   } catch (IOException e) {
     e.printStackTrace();
   } finally {
     try {
       iis.reset();
     } catch (IOException e) {
     }
   }
 }
 public void runTest(Object ctx, int numReps) {
   final Context ictx = (Context) ctx;
   final ImageInputStream iis = ictx.inputStream;
   final int scanlineStride = ictx.scanlineStride;
   final int length = ictx.length;
   int pos = 0;
   try {
     iis.mark();
     do {
       if (pos + scanlineStride > length) {
         iis.reset();
         iis.mark();
         pos = 0;
       }
       iis.skipBytes(scanlineStride);
       pos += scanlineStride;
     } while (--numReps >= 0);
   } catch (IOException e) {
     e.printStackTrace();
   } finally {
     try {
       iis.reset();
     } catch (IOException e) {
     }
   }
 }
  public boolean canDecodeInput(Object source) throws IOException {
    if (!(source instanceof ImageInputStream)) {
      return false;
    }

    ImageInputStream stream = (ImageInputStream) source;

    stream.mark();
    int type = stream.readByte(); // TypeField
    byte fixHeaderField = stream.readByte();

    int width = ImageUtil.readMultiByteInteger(stream);
    int height = ImageUtil.readMultiByteInteger(stream);

    long remainingBytes = stream.length() - stream.getStreamPosition();
    stream.reset();

    // check WBMP "header"
    if (type != 0 || fixHeaderField != 0) {
      // while WBMP reader does not support ext WBMP headers
      return false;
    }

    // check image dimension
    if (width <= 0 || height <= 0) {
      return false;
    }

    long scanSize = (width / 8) + ((width % 8) == 0 ? 0 : 1);

    return (remainingBytes == scanSize * height);
  }
  public boolean canDecodeInput(Object input) throws IOException {

    // The input source must be an ImageInputStream because the constructor
    // passes STANDARD_INPUT_TYPE (an array consisting of ImageInputStream)
    // as the only type of input source that it will deal with to its
    // superclass.

    if (!(input instanceof ImageInputStream)) return false;

    ImageInputStream stream = (ImageInputStream) input;

    /** Read and validate the input source's header. */
    byte[] header = new byte[8];
    try {
      // The input source's current position must be preserved so that
      // other ImageReaderSpis can determine if they can decode the input
      // source's format, should this input source be unable to handle the
      // decoding. Because the input source is an ImageInputStream, its
      // mark() and reset() methods are called to preserve the current
      // position.

      stream.mark();
      stream.read(header);
      stream.reset();
    } catch (IOException e) {
      return false;
    }

    byte[] controlHeader = new byte[] {(byte) 151, 74, 66, 50, 13, 10, 26, 10};

    return Arrays.equals(controlHeader, header);
  }
  /**
   * Returns the geotiff metadata for this geotiff file.
   *
   * @return the metadata
   */
  public GeoTiffIIOMetadataDecoder getMetadata() {
    GeoTiffIIOMetadataDecoder metadata = null;
    ImageReader reader = null;
    boolean closeMe = true;
    ImageInputStream stream = null;

    try {
      if ((source instanceof InputStream) || (source instanceof ImageInputStream)) {
        closeMe = false;
      }
      if (source instanceof ImageInputStream) {
        stream = (ImageInputStream) source;
      } else {
        inStreamSPI = ImageIOExt.getImageInputStreamSPI(source);
        if (inStreamSPI == null) {
          throw new IllegalArgumentException("No input stream for the provided source");
        }
        stream =
            inStreamSPI.createInputStreamInstance(
                source, ImageIO.getUseCache(), ImageIO.getCacheDirectory());
      }
      if (stream == null) {
        throw new IllegalArgumentException("No input stream for the provided source");
      }
      stream.mark();
      reader = READER_SPI.createReaderInstance();
      reader.setInput(stream);
      final IIOMetadata iioMetadata = reader.getImageMetadata(0);
      metadata = new GeoTiffIIOMetadataDecoder(iioMetadata);
    } catch (IOException e) {
      if (LOGGER.isLoggable(Level.SEVERE)) {
        LOGGER.log(Level.SEVERE, e.getMessage(), e);
      }
    } finally {
      if (reader != null)
        try {
          reader.dispose();
        } catch (Throwable t) {
        }

      if (stream != null) {
        try {
          stream.reset();
        } catch (Throwable t) {
        }
        if (closeMe) {
          try {
            stream.close();
          } catch (Throwable t) {
          }
        }
      }
    }
    return metadata;
  }
Exemple #6
0
 BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException {
   iis.mark();
   iis.seek(streamPos);
   JPEGImageReader thumbReader = new JPEGImageReader(null);
   thumbReader.setInput(iis);
   thumbReader.addIIOReadProgressListener(new ThumbnailReadListener(reader));
   BufferedImage ret = thumbReader.read(0, null);
   thumbReader.dispose();
   iis.reset();
   return ret;
 }
  public boolean canDecodeInput(Object source) throws IOException {
    if (!(source instanceof ImageInputStream)) {
      return false;
    }

    ImageInputStream stream = (ImageInputStream) source;
    byte[] b = new byte[2];
    stream.mark();
    stream.readFully(b);
    stream.reset();

    return (b[0] == 0x42) && (b[1] == 0x4d);
  }
Exemple #8
0
    BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException {
      iis.mark();
      iis.seek(streamPos);
      DataBufferByte buffer = new DataBufferByte(getLength());
      readByteBuffer(iis, buffer.getData(), reader, 1.0F, 0.0F);
      iis.reset();

      WritableRaster raster =
          Raster.createInterleavedRaster(
              buffer, thumbWidth, thumbHeight, thumbWidth * 3, 3, new int[] {0, 1, 2}, null);
      ColorModel cm =
          new ComponentColorModel(
              JPEG.JCS.sRGB, false, false, ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
      return new BufferedImage(cm, raster, false, null);
    }
Exemple #9
0
    BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException {
      iis.mark();
      iis.seek(streamPos);
      // read the palette
      byte[] palette = new byte[PALETTE_SIZE];
      float palettePart = ((float) PALETTE_SIZE) / getLength();
      readByteBuffer(iis, palette, reader, palettePart, 0.0F);
      DataBufferByte buffer = new DataBufferByte(thumbWidth * thumbHeight);
      readByteBuffer(iis, buffer.getData(), reader, 1.0F - palettePart, palettePart);
      iis.read();
      iis.reset();

      IndexColorModel cm = new IndexColorModel(8, 256, palette, 0, false);
      SampleModel sm = cm.createCompatibleSampleModel(thumbWidth, thumbHeight);
      WritableRaster raster = Raster.createWritableRaster(sm, buffer, null);
      return new BufferedImage(cm, raster, false, null);
    }
  public boolean canDecodeInput(Object input) throws IOException {
    if (!(input instanceof ImageInputStream)) {
      return false;
    }

    ImageInputStream stream = (ImageInputStream) input;
    byte[] b = new byte[4];
    stream.mark();
    stream.readFully(b);
    stream.reset();

    return ((b[0] == (byte) 0x49
            && b[1] == (byte) 0x49
            && b[2] == (byte) 0x2a
            && b[3] == (byte) 0x00)
        || (b[0] == (byte) 0x4d
            && b[1] == (byte) 0x4d
            && b[2] == (byte) 0x00
            && b[3] == (byte) 0x2a));
  }
  private void init(
      final BoundingBox granuleBBOX,
      final URL granuleUrl,
      final ImageReaderSpi suggestedSPI,
      final Geometry inclusionGeometry,
      final boolean heterogeneousGranules,
      final boolean handleArtifactsFiltering) {
    this.granuleBBOX = ReferencedEnvelope.reference(granuleBBOX);
    this.granuleUrl = granuleUrl;
    this.inclusionGeometry = inclusionGeometry;
    this.handleArtifactsFiltering = handleArtifactsFiltering;
    filterMe = handleArtifactsFiltering && inclusionGeometry != null;

    // create the base grid to world transformation
    ImageInputStream inStream = null;
    ImageReader reader = null;
    try {
      //
      // get info about the raster we have to read
      //

      // get a stream
      if (cachedStreamSPI == null) {
        cachedStreamSPI = ImageIOExt.getImageInputStreamSPI(granuleUrl, true);
        if (cachedStreamSPI == null) {
          final File file = DataUtilities.urlToFile(granuleUrl);
          if (file != null) {
            if (LOGGER.isLoggable(Level.WARNING)) {
              LOGGER.log(Level.WARNING, Utils.getFileInfo(file));
            }
          }
          throw new IllegalArgumentException(
              "Unable to get an input stream for the provided granule " + granuleUrl.toString());
        }
      }
      assert cachedStreamSPI != null : "no cachedStreamSPI available!";
      inStream =
          cachedStreamSPI.createInputStreamInstance(
              granuleUrl, ImageIO.getUseCache(), ImageIO.getCacheDirectory());
      if (inStream == null) {
        final File file = DataUtilities.urlToFile(granuleUrl);
        if (file != null) {
          if (LOGGER.isLoggable(Level.WARNING)) {
            LOGGER.log(Level.WARNING, Utils.getFileInfo(file));
          }
        }
        throw new IllegalArgumentException(
            "Unable to get an input stream for the provided file " + granuleUrl.toString());
      }

      // get a reader and try to cache the suggested SPI first
      if (cachedReaderSPI == null) {
        inStream.mark();
        if (suggestedSPI != null && suggestedSPI.canDecodeInput(inStream)) {
          cachedReaderSPI = suggestedSPI;
          inStream.reset();
        } else {
          inStream.mark();
          reader = ImageIOExt.getImageioReader(inStream);
          if (reader != null) cachedReaderSPI = reader.getOriginatingProvider();
          inStream.reset();
        }
      }
      reader = cachedReaderSPI.createReaderInstance();
      if (reader == null)
        throw new IllegalArgumentException(
            "Unable to get an ImageReader for the provided file " + granuleUrl.toString());
      reader.setInput(inStream);
      // get selected level and base level dimensions
      final Rectangle originalDimension = Utils.getDimension(0, reader);

      // build the g2W for this tile, in principle we should get it
      // somehow from the tile itself or from the index, but at the moment
      // we do not have such info, hence we assume that it is a simple
      // scale and translate
      final GridToEnvelopeMapper geMapper =
          new GridToEnvelopeMapper(new GridEnvelope2D(originalDimension), granuleBBOX);
      geMapper.setPixelAnchor(
          PixelInCell
              .CELL_CENTER); // this is the default behavior but it is nice to write it down anyway
      this.baseGridToWorld = geMapper.createAffineTransform();

      try {
        if (inclusionGeometry != null) {
          geMapper.setPixelAnchor(PixelInCell.CELL_CORNER);
          Geometry mapped = JTS.transform(inclusionGeometry, geMapper.createTransform().inverse());
          this.granuleROIShape = new ROIGeometry(mapped);
        }

      } catch (TransformException e1) {
        throw new IllegalArgumentException(e1);
      }

      // add the base level
      this.granuleLevels.put(
          Integer.valueOf(0),
          new GranuleOverviewLevelDescriptor(
              1, 1, originalDimension.width, originalDimension.height));

      ////////////////////// Setting overviewController ///////////////////////
      if (heterogeneousGranules) {
        // //
        //
        // Right now we are setting up overviewsController by assuming that
        // overviews are internal images as happens in TIFF images
        // We can improve this by leveraging on coverageReaders
        //
        // //

        // Getting the first level descriptor
        final GranuleOverviewLevelDescriptor baseOverviewLevelDescriptor = granuleLevels.get(0);

        // Variables initialization
        final int numberOfOvervies = reader.getNumImages(true) - 1;
        final AffineTransform2D baseG2W = baseOverviewLevelDescriptor.getGridToWorldTransform();
        final int width = baseOverviewLevelDescriptor.getWidth();
        final int height = baseOverviewLevelDescriptor.getHeight();
        final double resX = AffineTransform2D.getScaleX0(baseG2W);
        final double resY = AffineTransform2D.getScaleY0(baseG2W);
        final double[] highestRes = new double[] {resX, resY};
        final double[][] overviewsResolution = new double[numberOfOvervies][2];

        // Populating overviews and initializing overviewsController
        for (int i = 0; i < numberOfOvervies; i++) {
          overviewsResolution[i][0] = (highestRes[0] * width) / reader.getWidth(i + 1);
          overviewsResolution[i][1] = (highestRes[1] * height) / reader.getWidth(i + 1);
        }
        overviewsController =
            new OverviewsController(highestRes, numberOfOvervies, overviewsResolution);
      }
      //////////////////////////////////////////////////////////////////////////

    } catch (IllegalStateException e) {
      throw new IllegalArgumentException(e);

    } catch (IOException e) {
      throw new IllegalArgumentException(e);
    } finally {
      // close/dispose stream and readers
      try {
        if (inStream != null) {
          inStream.close();
        }
      } catch (Throwable e) {
        throw new IllegalArgumentException(e);
      } finally {
        if (reader != null) {
          reader.dispose();
        }
      }
    }
  }
Exemple #12
0
  private void initializeRead(int imageIndex, J2KImageReadParamJava param, J2KMetadata metadata) {
    try {
      iis.mark();
      in = new IISRandomAccessIO(iis);

      // **** File Format ****
      // If the codestream is wrapped in the jp2 fileformat, Read the
      // file format wrapper
      ff = new FileFormatReader(in, metadata);
      ff.readFileFormat();
      in.seek(ff.getFirstCodeStreamPos());

      hi = new HeaderInfo();
      try {
        hd = new HeaderDecoder(in, j2krparam, hi);
      } catch (EOFException e) {
        throw new RuntimeException(I18N.getString("J2KReadState2"));
      } catch (IOException ioe) {
        throw new RuntimeException(ioe);
      }

      this.width = hd.getImgWidth();
      this.height = hd.getImgHeight();

      Rectangle sourceRegion = param.getSourceRegion();
      sourceOrigin = new Point();
      sourceRegion = new Rectangle(hd.getImgULX(), hd.getImgULY(), this.width, this.height);

      // if the subsample rate for components are not consistent
      boolean compConsistent = true;
      stepX = hd.getCompSubsX(0);
      stepY = hd.getCompSubsY(0);
      for (int i = 1; i < nComp; i++) {
        if (stepX != hd.getCompSubsX(i) || stepY != hd.getCompSubsY(i))
          throw new RuntimeException(I18N.getString("J2KReadState12"));
      }

      // Get minimum number of resolution levels available across
      // all tile-components.
      int minResLevels = hd.getDecoderSpecs().dls.getMin();

      // Set current resolution level.
      this.resolution = param != null ? param.getResolution() : minResLevels;
      if (resolution < 0 || resolution > minResLevels) {
        resolution = minResLevels;
      }

      // Convert source region to lower resolution level.
      if (resolution != minResLevels || stepX != 1 || stepY != 1) {
        sourceRegion =
            J2KImageReader.getReducedRect(sourceRegion, minResLevels, resolution, stepX, stepY);
      }

      destinationRegion = (Rectangle) sourceRegion.clone();

      J2KImageReader.computeRegionsWrapper(
          param,
          false,
          this.width,
          this.height,
          param.getDestination(),
          sourceRegion,
          destinationRegion);

      sourceOrigin = new Point(sourceRegion.x, sourceRegion.y);
      scaleX = param.getSourceXSubsampling();
      scaleY = param.getSourceYSubsampling();
      xOffset = param.getSubsamplingXOffset();
      yOffset = param.getSubsamplingYOffset();

      this.width = destinationRegion.width;
      this.height = destinationRegion.height;

      Point tileOffset = hd.getTilingOrigin(null);

      this.tileWidth = hd.getNomTileWidth();
      this.tileHeight = hd.getNomTileHeight();

      // Convert tile 0 to lower resolution level.
      if (resolution != minResLevels || stepX != 1 || stepY != 1) {
        Rectangle tileRect = new Rectangle(tileOffset);
        tileRect.width = tileWidth;
        tileRect.height = tileHeight;
        tileRect = J2KImageReader.getReducedRect(tileRect, minResLevels, resolution, stepX, stepY);
        tileOffset = tileRect.getLocation();
        tileWidth = tileRect.width;
        tileHeight = tileRect.height;
      }

      tileXOffset = tileOffset.x;
      tileYOffset = tileOffset.y;

      // Set the tile step sizes. These values are used because it
      // is possible that tiles will be empty. In particular at lower
      // resolution levels when subsampling is used this may be the
      // case. This method of calculation will work at least for
      // Profile-0 images.
      if (tileWidth * (1 << (minResLevels - resolution)) * stepX > hd.getNomTileWidth()) {
        tileStepX =
            (tileWidth * (1 << (minResLevels - resolution)) * stepX + hd.getNomTileWidth() - 1)
                / hd.getNomTileWidth();
      } else {
        tileStepX = 1;
      }

      if (tileHeight * (1 << (minResLevels - resolution)) * stepY > hd.getNomTileHeight()) {
        tileStepY =
            (tileHeight * (1 << (minResLevels - resolution)) * stepY + hd.getNomTileHeight() - 1)
                / hd.getNomTileHeight();
      } else {
        tileStepY = 1;
      }

      if (!destinationRegion.equals(sourceRegion)) noTransform = false;

      // **** Header decoder ****
      // Instantiate header decoder and read main header
      decSpec = hd.getDecoderSpecs();

      // **** Instantiate decoding chain ****
      // Get demixed bitdepths
      nComp = hd.getNumComps();

      int[] depth = new int[nComp];
      for (int i = 0; i < nComp; i++) depth[i] = hd.getOriginalBitDepth(i);

      // Get channel mapping
      ChannelDefinitionBox cdb = null;
      if (metadata != null)
        cdb = (ChannelDefinitionBox) metadata.getElement("JPEG2000ChannelDefinitionBox");

      channelMap = new int[nComp];
      if (cdb != null && metadata.getElement("JPEG2000PaletteBox") == null) {
        short[] assoc = cdb.getAssociation();
        short[] types = cdb.getTypes();
        short[] channels = cdb.getChannel();

        for (int i = 0; i < types.length; i++)
          if (types[i] == 0) channelMap[channels[i]] = assoc[i] - 1;
          else if (types[i] == 1 || types[i] == 2) channelMap[channels[i]] = channels[i];
      } else {
        for (int i = 0; i < nComp; i++) channelMap[i] = i;
      }

      // **** Bitstream reader ****
      try {
        boolean logJJ2000Messages = Boolean.getBoolean("jj2000.j2k.decoder.log");
        breader =
            BitstreamReaderAgent.createInstance(in, hd, j2krparam, decSpec, logJJ2000Messages, hi);
      } catch (IOException e) {
        throw new RuntimeException(
            I18N.getString("J2KReadState3")
                + " "
                + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : ""));
      } catch (IllegalArgumentException e) {
        throw new RuntimeException(
            I18N.getString("J2KReadState4")
                + " "
                + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : ""));
      }

      // **** Entropy decoder ****
      try {
        entdec = hd.createEntropyDecoder(breader, j2krparam);
      } catch (IllegalArgumentException e) {
        throw new RuntimeException(
            I18N.getString("J2KReadState5")
                + " "
                + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : ""));
      }

      // **** ROI de-scaler ****
      try {
        roids = hd.createROIDeScaler(entdec, j2krparam, decSpec);
      } catch (IllegalArgumentException e) {
        throw new RuntimeException(
            I18N.getString("J2KReadState6")
                + " "
                + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : ""));
      }

      // **** Dequantizer ****
      try {
        deq = hd.createDequantizer(roids, depth, decSpec);
      } catch (IllegalArgumentException e) {
        throw new RuntimeException(
            I18N.getString("J2KReadState7")
                + " "
                + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : ""));
      }

      // **** Inverse wavelet transform ***
      try {
        // full page inverse wavelet transform
        invWT = InverseWT.createInstance(deq, decSpec);
      } catch (IllegalArgumentException e) {
        throw new RuntimeException(
            I18N.getString("J2KReadState8")
                + " "
                + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : ""));
      }

      int res = breader.getImgRes();
      int mrl = decSpec.dls.getMin();
      invWT.setImgResLevel(res);

      // **** Data converter **** (after inverse transform module)
      converter = new ImgDataConverter(invWT, 0);

      // **** Inverse component transformation ****
      ictransf = new InvCompTransf(converter, decSpec, depth);

      // If the destination band is set used it
      sourceBands = j2krparam.getSourceBands();

      if (sourceBands == null) {
        sourceBands = new int[nComp];
        for (int i = 0; i < nComp; i++) sourceBands[i] = i;
      }

      nComp = sourceBands.length;

      destinationBands = j2krparam.getDestinationBands();
      if (destinationBands == null) {
        destinationBands = new int[nComp];
        for (int i = 0; i < nComp; i++) destinationBands[i] = i;
      }

      J2KImageReader.checkReadParamBandSettingsWrapper(
          param, hd.getNumComps(), destinationBands.length);

      levelShift = new int[nComp];
      minValues = new int[nComp];
      maxValues = new int[nComp];
      fracBits = new int[nComp];
      dataBlocks = new DataBlkInt[nComp];

      depth = new int[nComp];
      bandOffsets = new int[nComp];
      maxDepth = 0;
      isSigned = false;
      for (int i = 0; i < nComp; i++) {
        depth[i] = hd.getOriginalBitDepth(sourceBands[i]);
        if (depth[i] > maxDepth) maxDepth = depth[i];
        dataBlocks[i] = new DataBlkInt();

        // XXX: may need to change if ChannelDefinition is used to
        // define the color channels, such as BGR order
        bandOffsets[i] = i;
        if (hd.isOriginalSigned(sourceBands[i])) isSigned = true;
        else {
          levelShift[i] = 1 << (ictransf.getNomRangeBits(sourceBands[i]) - 1);
        }

        // Get the number of bits in the image, and decide what the max
        // value should be, depending on whether it is signed or not
        int nomRangeBits = ictransf.getNomRangeBits(sourceBands[i]);
        maxValues[i] = (1 << (isSigned == true ? (nomRangeBits - 1) : nomRangeBits)) - 1;
        minValues[i] = isSigned ? -(maxValues[i] + 1) : 0;

        fracBits[i] = ictransf.getFixedPoint(sourceBands[i]);
      }

      iis.reset();
    } catch (IllegalArgumentException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (Error e) {
      if (e.getMessage() != null) throw new RuntimeException(e.getMessage(), e);
      else {
        throw new RuntimeException(I18N.getString("J2KReadState9"), e);
      }
    } catch (RuntimeException e) {
      if (e.getMessage() != null)
        throw new RuntimeException(I18N.getString("J2KReadState10") + " " + e.getMessage(), e);
      else {
        throw new RuntimeException(I18N.getString("J2KReadState10"), e);
      }
    } catch (Throwable e) {
      throw new RuntimeException(I18N.getString("J2KReadState10"), e);
    }
  }
  /**
   * 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]));
    //             }
    //         }

  }
  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();
  }
 public synchronized void mark(int readlimit) {
   src.mark();
 }
  private void readHeader() throws IOException {
    if (gotHeader) {
      iis.seek(128);
      return;
    }

    metadata = new PCXMetadata();

    manufacturer = iis.readByte(); // manufacturer
    if (manufacturer != MANUFACTURER) throw new IllegalStateException("image is not a PCX file");
    metadata.version = iis.readByte(); // version
    encoding = iis.readByte(); // encoding
    if (encoding != ENCODING)
      throw new IllegalStateException("image is not a PCX file, invalid encoding " + encoding);

    metadata.bitsPerPixel = iis.readByte();

    metadata.xmin = iis.readShort();
    metadata.ymin = iis.readShort();
    xmax = iis.readShort();
    ymax = iis.readShort();

    metadata.hdpi = iis.readShort();
    metadata.vdpi = iis.readShort();

    iis.readFully(smallPalette);

    iis.readByte(); // reserved

    colorPlanes = iis.readByte();
    bytesPerLine = iis.readShort();
    paletteType = iis.readShort();

    metadata.hsize = iis.readShort();
    metadata.vsize = iis.readShort();

    iis.skipBytes(54); // skip filler

    width = xmax - metadata.xmin + 1;
    height = ymax - metadata.ymin + 1;

    if (colorPlanes == 1) {
      if (paletteType == PALETTE_GRAYSCALE) {
        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
        int[] nBits = {8};
        colorModel =
            new ComponentColorModel(
                cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        sampleModel =
            new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 1, width, new int[] {0});
      } else {
        if (metadata.bitsPerPixel == 8) {
          // read palette from end of file, then reset back to image data
          iis.mark();

          if (iis.length() == -1) {
            // read until eof, and work backwards
            while (iis.read() != -1) ;
            iis.seek(iis.getStreamPosition() - 256 * 3 - 1);
          } else {
            iis.seek(iis.length() - 256 * 3 - 1);
          }

          int palletteMagic = iis.read();
          if (palletteMagic != 12)
            processWarningOccurred(
                "Expected palette magic number 12; instead read "
                    + palletteMagic
                    + " from this image.");

          iis.readFully(largePalette);
          iis.reset();

          colorModel = new IndexColorModel(metadata.bitsPerPixel, 256, largePalette, 0, false);
          sampleModel = colorModel.createCompatibleSampleModel(width, height);
        } else {
          int msize = metadata.bitsPerPixel == 1 ? 2 : 16;
          colorModel = new IndexColorModel(metadata.bitsPerPixel, msize, smallPalette, 0, false);
          sampleModel = colorModel.createCompatibleSampleModel(width, height);
        }
      }
    } else {
      ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
      int[] nBits = {8, 8, 8};
      colorModel =
          new ComponentColorModel(
              cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
      sampleModel =
          new ComponentSampleModel(
              DataBuffer.TYPE_BYTE,
              width,
              height,
              1,
              width * colorPlanes,
              new int[] {0, width, width * 2});
    }

    originalSampleModel = sampleModel;
    originalColorModel = colorModel;

    gotHeader = true;
  }
Exemple #17
0
  public void initialize(
      ImageInputStream stream, boolean ignoreUnknownFields, final boolean isBTIFF)
      throws IOException {
    removeTIFFFields();

    List tagSetList = getTagSetList();

    final long numEntries;
    if (isBTIFF) numEntries = stream.readLong();
    else numEntries = stream.readUnsignedShort();

    for (int i = 0; i < numEntries; i++) {
      // Read tag number, value type, and value count.
      int tag = stream.readUnsignedShort();
      int type = stream.readUnsignedShort();
      int count;
      if (isBTIFF) {
        long count_ = stream.readLong();
        count = (int) count_;
        if (count != count_)
          throw new IllegalArgumentException("unable to use long number of values");
      } else count = (int) stream.readUnsignedInt();

      // Get the associated TIFFTag.
      TIFFTag tiffTag = getTag(tag, tagSetList);

      // Ignore unknown fields.
      if (ignoreUnknownFields && tiffTag == null) {
        // Skip the value/offset so as to leave the stream
        // position at the start of the next IFD entry.

        if (isBTIFF) stream.skipBytes(8);
        else stream.skipBytes(4);

        // XXX Warning message ...

        // Continue with the next IFD entry.
        continue;
      }

      long nextTagOffset;

      if (isBTIFF) {
        nextTagOffset = stream.getStreamPosition() + 8;
        int sizeOfType = TIFFTag.getSizeOfType(type);
        if (count * sizeOfType > 8) {
          long value = stream.readLong();
          stream.seek(value);
        }
      } else {
        nextTagOffset = stream.getStreamPosition() + 4;
        int sizeOfType = TIFFTag.getSizeOfType(type);
        if (count * sizeOfType > 4) {
          long value = stream.readUnsignedInt();
          stream.seek(value);
        }
      }

      if (tag == BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS
          || tag == BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS
          || tag == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) {
        this.stripOrTileByteCountsPosition = stream.getStreamPosition();
        if (LAZY_LOADING) {
          type = type == TIFFTag.TIFF_LONG ? TIFFTag.TIFF_LAZY_LONG : TIFFTag.TIFF_LAZY_LONG8;
        }
      } else if (tag == BaselineTIFFTagSet.TAG_STRIP_OFFSETS
          || tag == BaselineTIFFTagSet.TAG_TILE_OFFSETS
          || tag == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) {
        this.stripOrTileOffsetsPosition = stream.getStreamPosition();
        if (LAZY_LOADING) {
          type = type == TIFFTag.TIFF_LONG ? TIFFTag.TIFF_LAZY_LONG : TIFFTag.TIFF_LAZY_LONG8;
        }
      }

      Object obj = null;

      try {
        switch (type) {
          case TIFFTag.TIFF_BYTE:
          case TIFFTag.TIFF_SBYTE:
          case TIFFTag.TIFF_UNDEFINED:
          case TIFFTag.TIFF_ASCII:
            byte[] bvalues = new byte[count];
            stream.readFully(bvalues, 0, count);

            if (type == TIFFTag.TIFF_ASCII) {
              // Can be multiple strings
              final List<String> v = new ArrayList<String>();
              boolean inString = false;
              int prevIndex = 0;
              for (int index = 0; index <= count; index++) {
                if (index < count && bvalues[index] != 0) {
                  if (!inString) {
                    // start of string
                    prevIndex = index;
                    inString = true;
                  }
                } else { // null or special case at end of string
                  if (inString) {
                    // end of string
                    final String s = new String(bvalues, prevIndex, index - prevIndex);
                    v.add(s);
                    inString = false;
                  }
                }
              }

              count = v.size();
              String[] strings;
              if (count != 0) {
                strings = new String[count];
                for (int c = 0; c < count; c++) {
                  strings[c] = v.get(c);
                }
              } else {
                // This case has been observed when the value of
                // 'count' recorded in the field is non-zero but
                // the value portion contains all nulls.
                count = 1;
                strings = new String[] {""};
              }

              obj = strings;
            } else {
              obj = bvalues;
            }
            break;

          case TIFFTag.TIFF_SHORT:
            char[] cvalues = new char[count];
            for (int j = 0; j < count; j++) {
              cvalues[j] = (char) (stream.readUnsignedShort());
            }
            obj = cvalues;
            break;

          case TIFFTag.TIFF_LONG:
          case TIFFTag.TIFF_IFD_POINTER:
            long[] lvalues = new long[count];
            for (int j = 0; j < count; j++) {
              lvalues[j] = stream.readUnsignedInt();
            }
            obj = lvalues;
            break;

          case TIFFTag.TIFF_RATIONAL:
            long[][] llvalues = new long[count][2];
            for (int j = 0; j < count; j++) {
              llvalues[j][0] = stream.readUnsignedInt();
              llvalues[j][1] = stream.readUnsignedInt();
            }
            obj = llvalues;
            break;

          case TIFFTag.TIFF_SSHORT:
            short[] svalues = new short[count];
            for (int j = 0; j < count; j++) {
              svalues[j] = stream.readShort();
            }
            obj = svalues;
            break;

          case TIFFTag.TIFF_SLONG:
            int[] ivalues = new int[count];
            for (int j = 0; j < count; j++) {
              ivalues[j] = stream.readInt();
            }
            obj = ivalues;
            break;

          case TIFFTag.TIFF_SRATIONAL:
            int[][] iivalues = new int[count][2];
            for (int j = 0; j < count; j++) {
              iivalues[j][0] = stream.readInt();
              iivalues[j][1] = stream.readInt();
            }
            obj = iivalues;
            break;

          case TIFFTag.TIFF_FLOAT:
            float[] fvalues = new float[count];
            for (int j = 0; j < count; j++) {
              fvalues[j] = stream.readFloat();
            }
            obj = fvalues;
            break;

          case TIFFTag.TIFF_DOUBLE:
            double[] dvalues = new double[count];
            for (int j = 0; j < count; j++) {
              dvalues[j] = stream.readDouble();
            }
            obj = dvalues;
            break;

          case TIFFTag.TIFF_LONG8:
          case TIFFTag.TIFF_SLONG8:
          case TIFFTag.TIFF_IFD8:
            long[] lBvalues = new long[count];
            for (int j = 0; j < count; j++) {
              lBvalues[j] = stream.readLong();
            }
            obj = lBvalues;
            break;

          case TIFFTag.TIFF_LAZY_LONG8:
          case TIFFTag.TIFF_LAZY_LONG:
            obj = new TIFFLazyData(stream, type, count);
            break;
          default:
            // XXX Warning
            break;
        }
      } catch (EOFException eofe) {
        // The TIFF 6.0 fields have tag numbers less than or equal
        // to 532 (ReferenceBlackWhite) or equal to 33432 (Copyright).
        // If there is an error reading a baseline tag, then re-throw
        // the exception and fail; otherwise continue with the next
        // field.
        if (BaselineTIFFTagSet.getInstance().getTag(tag) == null) {
          throw eofe;
        }
      }

      if (tiffTag == null) {
        // XXX Warning: unknown tag
      } else if (!tiffTag.isDataTypeOK(type)) {
        // XXX Warning: bad data type
      } else if (tiffTag.isIFDPointer() && obj != null) {
        stream.mark();
        stream.seek(((long[]) obj)[0]);

        List tagSets = new ArrayList(1);
        tagSets.add(tiffTag.getTagSet());
        TIFFIFD subIFD = new TIFFIFD(tagSets);

        // XXX Use same ignore policy for sub-IFD fields?
        subIFD.initialize(stream, ignoreUnknownFields);
        obj = subIFD;
        stream.reset();
      }

      if (tiffTag == null) {
        tiffTag = new TIFFTag(null, tag, 1 << type, null);
      }

      // Add the field if its contents have been initialized which
      // will not be the case if an EOF was ignored above.
      if (obj != null) {
        TIFFField f = new TIFFField(tiffTag, type, count, obj);
        addTIFFField(f);
      }

      stream.seek(nextTagOffset);
    }

    this.lastPosition = stream.getStreamPosition();
  }
Exemple #18
0
  @Override
  protected boolean canConnect(URL url, Map<String, Serializable> params) {

    if (url == null) {
      return false;
    }
    ImageInputStream inputStream = null;
    Object source = null;
    try {
      // /////////////////////////////////////////////////////////////
      //
      // URL management
      // In case the URL points to a file we need to get to the file
      // directly and avoid caching. In case it points to http or ftp
      // or it is an open stream we have very small to do and we need
      // to enable caching.
      //
      // /////////////////////////////////////////////////////////////
      if (url.getProtocol().equalsIgnoreCase("file")) {
        File file = new File(URLDecoder.decode(url.getFile(), "UTF-8"));

        if (file.exists()) {
          if (!file.canRead() || !file.isFile()) {
            if (LOGGER.isLoggable(Level.FINE))
              LOGGER.fine("File cannot be read or it is a directory");
            return false;
          }

          if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Provided URL is a file");
          // setting source
          source = file;

        } else {
          if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("File doesn't exist");
          return false;
        }

      } else {
        if (url.getProtocol().toLowerCase().startsWith("http")
            || url.getProtocol().equalsIgnoreCase("dods")) {
          URIImageInputStream uriInStream = new URIImageInputStreamImpl(url.toURI());
          source = uriInStream;
          if (!spi.canDecodeInput(source)) {
            if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Unable to decode the inputStream");
            return false;
          }
          return true;
        } else if (url.getProtocol().equalsIgnoreCase("ftp")) {
          source = url.openStream();
        } else {
          if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Unsupported protocol");
          return false;
        }
      }

      // get a stream
      inputStream =
          (ImageInputStream)
              ((source instanceof ImageInputStream)
                  ? source
                  : (source instanceof File)
                      ? new FileImageInputStreamExtImpl((File) source)
                      : ImageIO.createImageInputStream(source));
      if (inputStream == null) {
        if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Unable to get an ImageInputStream");
        return false;
      }

      inputStream.mark();

      if (!spi.canDecodeInput(inputStream)) {
        if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Unable to decode the inputStream");
        return false;
      }

      return true;
    } catch (Throwable e) {
      if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
      return false;
    } finally {

      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (Exception e) {

        }
      }
      if (source != null && (source instanceof InputStream)) {
        try {
          ((InputStream) source).close();
        } catch (Exception e) {
          if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
        }
      }
    }
  }
  @Override
  protected boolean canConnect(URL url, Map<String, Serializable> params) {
    if (url == null) {
      return false;
    }
    ImageInputStream inputStream = null;
    Object source = null;
    try {
      // /////////////////////////////////////////////////////////////
      //
      // URL management
      // In case the URL points to a file we need to get to the file
      // directly and avoid caching. In case it points to http or ftp
      // or it is an open stream we have very small to do and we need
      // to enable caching.
      //
      // /////////////////////////////////////////////////////////////
      if (url.getProtocol().equalsIgnoreCase("file")) {
        File file = urlToFile(url);
        if (file.exists() && file.canRead() && file.isFile()) {
          // setting source
          source = file;
        } else {
          return false;
        }
      } else if (url.getProtocol().equalsIgnoreCase("http")
          || url.getProtocol().equalsIgnoreCase("ftp")) {
        source = url.openStream();
      } else {
        return false;
      }

      // get a stream
      inputStream =
          (ImageInputStream)
              ((source instanceof ImageInputStream)
                  ? source
                  : ImageIO.createImageInputStream(source));
      if (inputStream == null) {
        if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Unable to get an ImageInputStream");
        return false;
      }
      // get a reader and check if it is a geotiff
      inputStream.mark();

      // tiff
      if (!readerSpi.canDecodeInput(inputStream)) {
        return false;
      }
      return true;
    } catch (Throwable e) {
      if (LOGGER.isLoggable(Level.FINE)) {
        LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
      }
      return false;
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (Exception e) {
          if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
        }
      }
      if (source != null && (source instanceof InputStream)) {
        try {
          ((InputStream) source).close();
        } catch (Exception e) {
          if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public Image loadImage(final ImageInfo info, final Map hints, final ImageSessionContext session)
      throws ImageException, IOException {
    if (!MimeConstants.MIME_JPEG.equals(info.getMimeType())) {
      throw new IllegalArgumentException(
          "ImageInfo must be from a image with MIME type: " + MimeConstants.MIME_JPEG);
    }

    ColorSpace colorSpace = null;
    boolean appeFound = false;
    int sofType = 0;
    ByteArrayOutputStream iccStream = null;

    final Source src = session.needSource(info.getOriginalURI());
    final ImageInputStream in = ImageUtil.needImageInputStream(src);
    final JPEGFile jpeg = new JPEGFile(in);
    in.mark();
    try {
      outer:
      while (true) {
        int reclen;
        final int segID = jpeg.readMarkerSegment();
        if (log.isTraceEnabled()) {
          log.trace("Seg Marker: " + Integer.toHexString(segID));
        }
        switch (segID) {
          case EOI:
            log.trace("EOI found. Stopping.");
            break outer;
          case SOS:
            log.trace("SOS found. Stopping early."); // TODO Not sure if
            // this is safe
            break outer;
          case SOI:
          case NULL:
            break;
          case SOF0: // baseline
          case SOF1: // extended sequential DCT
          case SOF2: // progressive (since PDF 1.3)
          case SOFA: // progressive (since PDF 1.3)
            sofType = segID;
            if (log.isTraceEnabled()) {
              log.trace("SOF: " + Integer.toHexString(sofType));
            }
            in.mark();
            try {
              reclen = jpeg.readSegmentLength();
              in.skipBytes(1); // data precision
              in.skipBytes(2); // height
              in.skipBytes(2); // width
              final int numComponents = in.readUnsignedByte();
              if (numComponents == 1) {
                colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
              } else if (numComponents == 3) {
                colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
              } else if (numComponents == 4) {
                colorSpace = ColorSpaces.getDeviceCMYKColorSpace();
              } else {
                throw new ImageException(
                    "Unsupported ColorSpace for image "
                        + info
                        + ". The number of components supported are 1, 3 and 4.");
              }
            } finally {
              in.reset();
            }
            in.skipBytes(reclen);
            break;
          case APP2: // ICC (see ICC1V42.pdf)
            in.mark();
            try {
              reclen = jpeg.readSegmentLength();
              // Check for ICC profile
              final byte[] iccString = new byte[11];
              in.readFully(iccString);
              in.skipBytes(1); // string terminator (null byte)

              if ("ICC_PROFILE".equals(new String(iccString, "US-ASCII"))) {
                in.skipBytes(2); // chunk sequence number and total
                // number of chunks
                final int payloadSize = reclen - 2 - 12 - 2;
                if (ignoreColorProfile(hints)) {
                  log.debug("Ignoring ICC profile data in JPEG");
                  in.skipBytes(payloadSize);
                } else {
                  final byte[] buf = new byte[payloadSize];
                  in.readFully(buf);
                  if (iccStream == null) {
                    if (log.isDebugEnabled()) {
                      log.debug("JPEG has an ICC profile");
                      final DataInputStream din =
                          new DataInputStream(new ByteArrayInputStream(buf));
                      log.debug("Declared ICC profile size: " + din.readInt());
                    }
                    // ICC profiles can be split into several
                    // chunks
                    // so collect in a byte array output stream
                    iccStream = new ByteArrayOutputStream();
                  }
                  iccStream.write(buf);
                }
              }
            } finally {
              in.reset();
            }
            in.skipBytes(reclen);
            break;
          case APPE: // Adobe-specific (see 5116.DCT_Filter.pdf)
            in.mark();
            try {
              reclen = jpeg.readSegmentLength();
              // Check for Adobe header
              final byte[] adobeHeader = new byte[5];
              in.readFully(adobeHeader);

              if ("Adobe".equals(new String(adobeHeader, "US-ASCII"))) {
                // The reason for reading the APPE marker is that
                // Adobe Photoshop
                // generates CMYK JPEGs with inverted values. The
                // correct thing
                // to do would be to interpret the values in the
                // marker, but for now
                // only assume that if APPE marker is present and
                // colorspace is CMYK,
                // the image is inverted.
                appeFound = true;
              }
            } finally {
              in.reset();
            }
            in.skipBytes(reclen);
            break;
          default:
            jpeg.skipCurrentMarkerSegment();
        }
      }
    } finally {
      in.reset();
    }

    final ICC_Profile iccProfile = buildICCProfile(info, colorSpace, iccStream);
    if (iccProfile == null && colorSpace == null) {
      throw new ImageException("ColorSpace could not be identified for JPEG image " + info);
    }

    boolean invertImage = false;
    if (appeFound && colorSpace.getType() == ColorSpace.TYPE_CMYK) {
      if (log.isDebugEnabled()) {
        log.debug(
            "JPEG has an Adobe APPE marker. Note: CMYK Image will be inverted. ("
                + info.getOriginalURI()
                + ")");
      }
      invertImage = true;
    }

    final ImageRawJPEG rawImage =
        new ImageRawJPEG(
            info, ImageUtil.needInputStream(src), sofType, colorSpace, iccProfile, invertImage);
    return rawImage;
  }