Exemplo n.º 1
0
  private Raster readSubsampledRaster(WritableRaster raster) throws IOException {
    if (raster == null)
      raster =
          Raster.createWritableRaster(
              sampleModel.createCompatibleSampleModel(
                  destinationRegion.x + destinationRegion.width,
                  destinationRegion.y + destinationRegion.height),
              new Point(destinationRegion.x, destinationRegion.y));

    int pixbuf[] = null; // line buffer for pixel data
    boolean prog = false; // Flag for progressive data
    Point nT = ictransf.getNumTiles(null);
    int numBands = sourceBands.length;

    Rectangle destRect = raster.getBounds().intersection(destinationRegion);

    int offx = destinationRegion.x;
    int offy = destinationRegion.y;

    int sourceSX = (destRect.x - offx) * scaleX + sourceOrigin.x;
    int sourceSY = (destRect.y - offy) * scaleY + sourceOrigin.y;
    int sourceEX = (destRect.width - 1) * scaleX + sourceSX;
    int sourceEY = (destRect.height - 1) * scaleY + sourceSY;

    int startXTile = (sourceSX - tileXOffset) / tileWidth;
    int startYTile = (sourceSY - tileYOffset) / tileHeight;
    int endXTile = (sourceEX - tileXOffset) / tileWidth;
    int endYTile = (sourceEY - tileYOffset) / tileHeight;

    startXTile = clip(startXTile, 0, nT.x - 1);
    startYTile = clip(startYTile, 0, nT.y - 1);
    endXTile = clip(endXTile, 0, nT.x - 1);
    endYTile = clip(endYTile, 0, nT.y - 1);

    int totalXTiles = endXTile - startXTile + 1;
    int totalYTiles = endYTile - startYTile + 1;
    int totalTiles = totalXTiles * totalYTiles;

    // Start the data delivery to the cached consumers tile by tile
    for (int y = startYTile; y <= endYTile; y++) {
      if (reader.getAbortRequest()) break;

      // Loop on horizontal tiles
      for (int x = startXTile; x <= endXTile; x++) {
        if (reader.getAbortRequest()) break;

        float initialFraction = (x - startXTile + (y - startYTile) * totalXTiles) / totalTiles;

        ictransf.setTile(x * tileStepX, y * tileStepY);

        int sx = hd.getCompSubsX(0);
        int cTileWidth = (ictransf.getTileWidth() + sx - 1) / sx;
        int sy = hd.getCompSubsY(0);
        int cTileHeight = (ictransf.getTileHeight() + sy - 1) / sy;

        // Offsets within the tile.
        int tx = 0;
        int ty = 0;

        // The region for this tile
        int startX = tileXOffset + x * tileWidth;
        int startY = tileYOffset + y * tileHeight;

        // sourceSX is guaranteed to be >= startX
        if (sourceSX > startX) {
          if (startX >= hd.getImgULX()) {
            tx = sourceSX - startX; // Intra-tile offset.
            cTileWidth -= tx; // Reduce effective width.
          }
          startX = sourceSX; // Absolute position.
        }

        // sourceSY is guaranteed to be >= startY
        if (sourceSY > startY) {
          if (startY >= hd.getImgULY()) {
            ty = sourceSY - startY; // Intra-tile offset.
            cTileHeight -= ty; // Reduce effective width.
          }
          startY = sourceSY; // Absolute position.
        }

        // Decrement dimensions if end position is within tile.
        if (sourceEX < startX + cTileWidth - 1) {
          cTileWidth += sourceEX - startX - cTileWidth + 1;
        }
        if (sourceEY < startY + cTileHeight - 1) {
          cTileHeight += sourceEY - startY - cTileHeight + 1;
        }

        // The start X in the destination
        int x1 = (startX + scaleX - 1 - sourceOrigin.x) / scaleX;
        int x2 = (startX + scaleX - 1 + cTileWidth - sourceOrigin.x) / scaleX;
        int lineLength = x2 - x1;
        if (pixbuf == null || pixbuf.length < lineLength)
          pixbuf = new int[lineLength]; // line buffer for pixel data
        x2 = (x2 - 1) * scaleX + sourceOrigin.x - startX;

        int y1 = (startY + scaleY - 1 - sourceOrigin.y) / scaleY;

        x1 += offx;
        y1 += offy;

        // check to see if we have YCbCr data
        boolean ycbcr = false;

        for (int i = 0; i < numBands; i++) {
          DataBlkInt db = dataBlocks[i];
          db.ulx = tx;
          db.uly = ty + cTileHeight - 1;
          db.w = cTileWidth;
          db.h = 1;

          try {
            ictransf.getInternCompData(db, channelMap[sourceBands[i]]);
          } catch (ArrayIndexOutOfBoundsException e) {
            ycbcr = true;
            break;
          }
        }

        // Deliver in lines to reduce memory usage
        for (int l = ty, m = y1; l < ty + cTileHeight; l += scaleY, m++) {
          if (reader.getAbortRequest()) break;

          if (ycbcr) {
            DataBlkInt lum = dataBlocks[0];
            DataBlkInt cb = dataBlocks[1];
            DataBlkInt cr = dataBlocks[2];

            lum.ulx = tx;
            lum.uly = l;
            lum.w = cTileWidth;
            lum.h = 1;
            ictransf.getInternCompData(lum, channelMap[sourceBands[0]]);
            prog = prog || lum.progressive;

            cb.ulx = tx;
            cb.uly = l;
            cb.w = cTileWidth / 2;
            cb.h = 1;
            ictransf.getInternCompData(cb, channelMap[sourceBands[1]]);
            prog = prog || cb.progressive;

            cr.ulx = tx;
            cr.uly = l;
            cr.w = cTileWidth / 2;
            cr.h = 1;
            ictransf.getInternCompData(cr, channelMap[sourceBands[2]]);
            prog = prog || cr.progressive;

            int[] lumdata = lum.data;
            int[] cbdata = cb.data;
            int[] crdata = cr.data;

            int k1 = lum.offset + x2;

            int fracBit = fracBits[0];
            int lS = levelShift[0];
            int min = minValues[0];
            int max = maxValues[0];

            int[][] pix = new int[3][lineLength];

            for (int j = lineLength - 1; j >= 0; j--, k1 -= scaleX) {
              int red = (lumdata[k1] >> fracBit) + lS;
              red = (red < min) ? min : ((red > max) ? max : red);

              int cIndex = k1 / 2;

              int chrom1 = cbdata[cIndex];
              int chrom2 = crdata[cIndex];
              int lumval = red;

              red = (int) (chrom2 * 1.542 + lumval);
              int blue = (int) (lumval + 1.772 * chrom1 - 0.886);
              int green = (int) (lumval - 0.34413 * chrom1 - 0.71414 * chrom2 - 0.1228785);

              if (red > 255) red = 255;
              if (green > 255) green = 255;
              if (blue > 255) blue = 255;

              if (red < 0) red = 0;
              if (green < 0) green = 0;
              if (blue < 0) blue = 0;

              pix[0][j] = red;
              pix[1][j] = green;
              pix[2][j] = blue;
            }

            raster.setSamples(x1, m, lineLength, 1, destinationBands[0], pix[0]);
            raster.setSamples(x1, m, lineLength, 1, destinationBands[1], pix[1]);
            raster.setSamples(x1, m, lineLength, 1, destinationBands[2], pix[2]);

            continue;
          }

          // Request line data
          for (int i = 0; i < numBands; i++) {
            DataBlkInt db = dataBlocks[i];
            db.ulx = tx;
            db.uly = l;
            db.w = ycbcr && i > 0 ? cTileWidth / 2 : cTileWidth;
            db.h = 1;
            ictransf.getInternCompData(db, channelMap[sourceBands[i]]);
            prog = prog || db.progressive;

            int[] data = db.data;
            int k1 = db.offset + x2;

            int fracBit = fracBits[i];
            int lS = levelShift[i];
            int min = minValues[i];
            int max = maxValues[i];

            if (ImageUtil.isBinary(sampleModel)) {
              // Force min max to 0 and 1.
              min = 0;
              max = 1;
              if (bytebuf == null || bytebuf.length < cTileWidth * numBands)
                bytebuf = new byte[cTileWidth * numBands];
              for (int j = lineLength - 1; j >= 0; j--, k1 -= scaleX) {
                int tmp = (data[k1] >> fracBit) + lS;
                bytebuf[j] = (byte) ((tmp < min) ? min : ((tmp > max) ? max : tmp));
              }

              ImageUtil.setUnpackedBinaryData(bytebuf, raster, new Rectangle(x1, m, lineLength, 1));
            } else {
              for (int j = lineLength - 1; j >= 0; j--, k1 -= scaleX) {
                int tmp = (data[k1] >> fracBit) + lS;
                pixbuf[j] = (tmp < min) ? min : ((tmp > max) ? max : tmp);
              }

              // Send the line data to the BufferedImage
              raster.setSamples(x1, m, lineLength, 1, destinationBands[i], pixbuf);
            }
          }

          if (destImage != null)
            reader.processImageUpdateWrapper(
                destImage, x1, m, cTileWidth, 1, 1, 1, destinationBands);

          float fraction = initialFraction + (l - ty + 1.0F) / cTileHeight / totalTiles;
          reader.processImageProgressWrapper(100.0f * fraction);
        }
      } // End loop on horizontal tiles
    } // End loop on vertical tiles

    return raster;
  }
Exemplo n.º 2
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);
    }
  }