/**
   * Crops the image representing a full tile set to the required dimension and returns it, but
   * keeps minx and miny being zero.
   *
   * @param fullTilesRaster
   * @param tiledImageGridRange
   * @param cropTo
   * @return
   */
  private RenderedImage cropToRequiredDimension(
      final RenderedImage fullTilesRaster, final GridEnvelope cropTo) {
    GridEnvelope2D crop =
        new GridEnvelope2D(
            cropTo.getLow(0), cropTo.getLow(1), cropTo.getSpan(0), cropTo.getSpan(1));

    GridEnvelope2D origDim =
        new GridEnvelope2D(
            fullTilesRaster.getMinX(),
            fullTilesRaster.getMinY(),
            fullTilesRaster.getWidth(),
            fullTilesRaster.getHeight());
    if (!origDim.contains(crop)) {
      throw new IllegalArgumentException(
          "Original image (" + origDim + ") does not contain desired dimension (" + crop + ")");
    } else if (origDim.equals(crop)) {
      if (LOGGER.isLoggable(Level.FINER)) {
        LOGGER.finer(
            "No need to crop image, full tiled dimension and target one "
                + "do match: original: "
                + fullTilesRaster.getWidth()
                + "x"
                + fullTilesRaster.getHeight()
                + ", target: "
                + crop.getSpan(0)
                + "x"
                + crop.getSpan(1));
      }
      return fullTilesRaster;
    }

    ParameterBlock cropParams = new ParameterBlock();

    cropParams.addSource(fullTilesRaster); // Source
    // cropParams.add(Float.valueOf(cropTo.x - tiledImageGridRange.x)); // x origin for each
    // band
    // cropParams.add(Float.valueOf(cropTo.y - tiledImageGridRange.y)); // y origin for each
    // band
    cropParams.add(Float.valueOf(crop.getLow(0))); // x origin for each band
    cropParams.add(Float.valueOf(crop.getLow(1))); // y origin for each band
    cropParams.add(Float.valueOf(crop.getSpan(0))); // width for each band
    cropParams.add(Float.valueOf(crop.getSpan(1))); // height for each band

    final RenderingHints hints =
        new RenderingHints(JAI.KEY_OPERATION_BOUND, OpImage.OP_NETWORK_BOUND);
    RenderedImage image = JAI.create("Crop", cropParams, hints);

    // assert cropTo.x - tiledImageGridRange.x == image.getMinX();
    // assert cropTo.y - tiledImageGridRange.y == image.getMinY();
    assert crop.getLow(0) == image.getMinX();
    assert crop.getLow(1) == image.getMinY();
    assert crop.getSpan(0) == image.getWidth();
    assert crop.getSpan(1) == image.getHeight();

    // assert cropTo.x == image.getMinX();
    // assert cropTo.y == image.getMinY();
    // assert cropTo.width == image.getWidth();
    // assert cropTo.height == image.getHeight();
    return image;
  }
Example #2
0
  @Override
  public void process() throws Exception {
    RenderedImage source = (RenderedImage) params.get(INPUT_IMG);
    RenderedImage result = source;
    Rectangle area = (Rectangle) params.get(P_AREA);

    if (area == null) {
      LOGGER.warn("Cannot apply \"{}\" because a parameter is null", OP_NAME); // $NON-NLS-1$
    } else {
      area =
          area.intersection(
              new Rectangle(
                  source.getMinX(), source.getMinY(), source.getWidth(), source.getHeight()));
      if (area.width > 1 && area.height > 1) {
        ParameterBlock pb = new ParameterBlock();
        pb.addSource(source);
        pb.add((float) area.x).add((float) area.y);
        pb.add((float) area.width).add((float) area.height);
        result = JAI.create("crop", pb, null); // $NON-NLS-1$

        if (JMVUtils.getNULLtoFalse(params.get(P_SHIFT_TO_ORIGIN))) {
          float diffw = source.getMinX() - result.getMinX();
          float diffh = source.getMinY() - result.getMinY();
          if (diffw != 0.0f || diffh != 0.0f) {
            pb = new ParameterBlock();
            pb.addSource(result);
            pb.add(diffw);
            pb.add(diffh);
            result = JAI.create("translate", pb, null); // $NON-NLS-1$
          }
        }
      }
    }
    params.put(OUTPUT_IMG, result);
  }
  /**
   * Constructs a <code>SubsampleBinaryToGrayOpImage</code> from a <code>RenderedImage</code>
   * source, x and y scale object. The image dimensions are determined by forward-mapping the source
   * bounds, and are passed to the superclass constructor by means of the <code>layout</code>
   * parameter. Other fields of the layout are passed through unchanged. If <code>layout</code> is
   * <code>null</code>, a new <code>ImageLayout</code> will be constructor to hold the bounds
   * information.
   *
   * <p>The float rounding errors, such as 1.2 being internally represented as 1.200001, are dealt
   * with the floatTol, which is set up so that only 1/10 of pixel error will occur at the end of a
   * line, which yields correct results with Math.round() operation. The repeatability is guaranteed
   * with a one-time computed table xvalues and yvalues.
   *
   * @param layout an <code>ImageLayout</code> optionally containing the tile grid layout, <code>
   *     SampleModel</code>, and <code>ColorModel</code>, or <code>null</code>.
   * @param source a <code>RenderedImage</code>. from this <code>OpImage</code>, or <code>null
   *     </code>. If <code>null</code>, no caching will be performed.
   * @param cobbleSources a boolean indicating whether <code>computeRect</code> expects contiguous
   *     sources.
   * @param extender a <code>BorderExtender</code>, or <code>null</code>.
   * @param interp an <code>Interpolation</code> object to use for resampling.
   * @param scaleX scale factor along x axis.
   * @param scaleY scale factor along y axis.
   * @throws IllegalArgumentException if combining the source bounds with the layout parameter
   *     results in negative output width or height.
   */
  public SubsampleBinaryToGrayOpImage(
      RenderedImage source, ImageLayout layout, Map config, float scaleX, float scaleY) {

    super(
        vectorize(source),
        layoutHelper(source, scaleX, scaleY, layout, config),
        configHelper(config),
        true, // cobbleSources,
        null, // extender
        null, // interpolation
        null);

    this.scaleX = scaleX;
    this.scaleY = scaleY;
    int srcMinX = source.getMinX();
    int srcMinY = source.getMinY();
    int srcWidth = source.getWidth();
    int srcHeight = source.getHeight();

    // compute floatTol, invScaleX, blockX, dWidth, dHeight,...
    computeDestInfo(srcWidth, srcHeight);

    if (extender == null) {
      computableBounds = new Rectangle(0, 0, dWidth, dHeight);
    } else {
      // If extender is present we can write the entire destination.
      computableBounds = getBounds();
    }

    // these can be delayed, such as placed in computeRect()
    buildLookupTables();

    // compute the begining bit position of each row and column
    computeXYValues(srcWidth, srcHeight, srcMinX, srcMinY);
  }
 public void appendLoggingGeometries(String geomName, RenderedImage img) {
   if (LOGGER.isLoggable(GEOM_LEVEL)) {
     appendLoggingGeometries(
         geomName,
         new GridEnvelope2D(img.getMinX(), img.getMinY(), img.getWidth(), img.getHeight()));
   }
 }
  // package accessible for SubsampleBinaryToGrayOpImage4x4, etc...
  static ImageLayout layoutHelper(
      RenderedImage source, float scaleX, float scaleY, ImageLayout il, Map config) {

    ImageLayout layout = (il == null) ? new ImageLayout() : (ImageLayout) il.clone();

    // to compute dWidth and dHeight
    // fTol and dWi, dHi must be the same as in computeDestInfo(..)
    // due to static method, a few lines of coding are repeated
    int srcWidth = source.getWidth();
    int srcHeight = source.getHeight();

    float f_dw = scaleX * srcWidth;
    float f_dh = scaleY * srcHeight;
    float fTol = .1F * Math.min(scaleX / (f_dw + 1.0F), scaleY / (f_dh + 1.0F));

    int dWi = (int) (f_dw);
    int dHi = (int) (f_dh);

    // let it be int in the almost int case
    //   espacially in the true int case with float calculation errors
    if (Math.abs(Math.round(f_dw) - f_dw) < fTol) {
      dWi = Math.round(f_dw);
    }

    if (Math.abs(Math.round(f_dh) - f_dh) < fTol) {
      dHi = Math.round(f_dh);
    }

    // Set the top left coordinate of the destination
    layout.setMinX((int) (scaleX * source.getMinX()));
    layout.setMinY((int) (scaleY * source.getMinY()));

    layout.setWidth(dWi);
    layout.setHeight(dHi);

    // sample model
    SampleModel sm = layout.getSampleModel(null);

    if (sm == null
        || sm.getDataType() != DataBuffer.TYPE_BYTE
        || !(sm instanceof PixelInterleavedSampleModel
            || sm instanceof SinglePixelPackedSampleModel && sm.getNumBands() == 1)) {

      // Width and height will be corrected in OpImage.layoutHelper
      sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, 1, 1, 1, 1, new int[] {0});
    }

    layout.setSampleModel(sm);

    ColorModel cm = layout.getColorModel(null);

    if (cm == null || !JDKWorkarounds.areCompatibleDataModels(sm, cm)) {

      layout.setColorModel(ImageUtil.getCompatibleColorModel(sm, config));
    }

    return layout;
  }
Example #6
0
  /**
   * Performs a translation using the "Resample" operation.
   *
   * @param grid the {@link GridCoverage2D} to apply the translation on.
   * @throws NoninvertibleTransformException If a "grid to CRS" transform is not invertible.
   */
  private void doTranslation(GridCoverage2D grid) throws NoninvertibleTransformException {
    final int transX = -253;
    final int transY = -456;
    final double scaleX = 0.04;
    final double scaleY = -0.04;
    final ParameterBlock block =
        new ParameterBlock()
            .addSource(grid.getRenderedImage())
            .add((float) transX)
            .add((float) transY);
    RenderedImage image = JAI.create("Translate", block);
    assertEquals("Incorrect X translation", transX, image.getMinX());
    assertEquals("Incorrect Y translation", transY, image.getMinY());

    /*
     * Create a grid coverage from the translated image but with the same envelope.
     * Consequently, the 'gridToCoordinateSystem' should be translated by the same
     * amount, with the opposite sign.
     */
    AffineTransform expected = getAffineTransform(grid);
    assertNotNull(expected);
    expected = new AffineTransform(expected); // Get a mutable instance.
    final GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
    grid =
        factory.create(
            "Translated",
            image,
            grid.getEnvelope(),
            grid.getSampleDimensions(),
            new GridCoverage2D[] {grid},
            grid.getProperties());
    expected.translate(-transX, -transY);
    assertTransformEquals(expected, getAffineTransform(grid));

    /*
     * Apply the "Resample" operation with a specific 'gridToCoordinateSystem' transform.
     * The envelope is left unchanged. The "Resample" operation should compute automatically
     * new image bounds.
     */
    final AffineTransform at = AffineTransform.getScaleInstance(scaleX, scaleY);
    final MathTransform tr = ProjectiveTransform.create(at);
    // account for the half pixel correction between the two spaces since we are talking raster here
    // but the resample will talk model!
    final MathTransform correctedTransform =
        PixelTranslation.translate(tr, PixelInCell.CELL_CORNER, PixelInCell.CELL_CENTER);
    final GridGeometry2D geometry = new GridGeometry2D(null, correctedTransform, null);
    final GridCoverage2D newGrid =
        (GridCoverage2D)
            Operations.DEFAULT.resample(grid, grid.getCoordinateReferenceSystem(), geometry, null);
    assertEquals(correctedTransform, getAffineTransform(newGrid));
    image = newGrid.getRenderedImage();
    expected.preConcatenate(at.createInverse());
    final Point point = new Point(transX, transY);
    assertSame(point, expected.transform(point, point)); // Round toward neareast integer
  }
  @Test
  public void testOptimizeAffine() throws Exception {
    BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
    ImageWorker iw = new ImageWorker(bi);

    // apply straight translation
    AffineTransform at = AffineTransform.getTranslateInstance(100, 100);
    iw.affine(at, null, null);
    RenderedImage t1 = iw.getRenderedImage();
    assertEquals(100, t1.getMinX());
    assertEquals(100, t1.getMinY());

    // now go back
    AffineTransform atInverse = AffineTransform.getTranslateInstance(-100, -100);
    iw.affine(atInverse, null, null);
    RenderedImage t2 = iw.getRenderedImage();
    assertEquals(0, t2.getMinX());
    assertEquals(0, t2.getMinY());
    assertSame(bi, t2);
  }
Example #8
0
 /**
  * Makes sure the image starts at 0,0, all images coming from files do but the ones coming from a
  * JAI chain might not
  *
  * @param image
  * @return
  */
 static final RenderedImage realignImage(RenderedImage image) {
   if (image.getMinX() > 0 || image.getMinY() > 0) {
     return new BufferedImage(
         image.getColorModel(),
         ((WritableRaster) image.getData()).createWritableTranslatedChild(0, 0),
         image.getColorModel().isAlphaPremultiplied(),
         null);
   } else {
     return image;
   }
 }
  /** Gets the number of tiles */
  public int getNumTiles() {
    Rectangle sourceRegion = getSourceRegion();
    if (sourceRegion == null) {
      if (imgsrc != null)
        sourceRegion =
            new Rectangle(
                imgsrc.getMinX(), imgsrc.getMinY(), imgsrc.getWidth(), imgsrc.getHeight());
      else sourceRegion = raster.getBounds();
    } else {
      if (imgsrc != null)
        sourceRegion =
            sourceRegion.intersection(
                new Rectangle(
                    imgsrc.getMinX(), imgsrc.getMinY(), imgsrc.getWidth(), imgsrc.getHeight()));
      else sourceRegion = sourceRegion.intersection(raster.getBounds());
    }

    int scaleX = getSourceXSubsampling();
    int scaleY = getSourceYSubsampling();
    int xOffset = getSubsamplingXOffset();
    int yOffset = getSubsamplingYOffset();

    int w = (sourceRegion.width - xOffset + scaleX - 1) / scaleX;
    int h = (sourceRegion.height - yOffset + scaleY - 1) / scaleY;

    minX = (sourceRegion.x + xOffset) / scaleX;
    minY = (sourceRegion.y + yOffset) / scaleY;

    numTiles =
        (int)
            ((Math.floor((minX + w + tileWidth - 1.0) / tileWidth)
                    - Math.floor((double) minX / tileWidth))
                * (Math.floor((minY + h + tileHeight - 1.0) / tileHeight)
                    - Math.floor((double) minY / tileHeight)));
    tileGridXOffset += (minX - tileGridXOffset) / tileWidth * tileWidth;
    tileGridYOffset += (minY - tileGridYOffset) / tileHeight * tileHeight;

    return numTiles;
  }
Example #10
0
 public ImageHeader(RenderedImage image, String tileFormat) {
   this(
       new ImageLayout(
           image.getMinX(),
           image.getMinY(),
           image.getWidth(),
           image.getHeight(),
           image.getTileGridXOffset(),
           image.getTileGridYOffset(),
           image.getTileWidth(),
           image.getTileHeight(),
           image.getSampleModel(),
           image.getColorModel()),
       tileFormat);
 }
  private byte[] getROIData(ROI roi, Rectangle rectIMG) {
    byte[] dataROI;
    PlanarImage roiIMG = roi.getAsImage();
    Rectangle rectROI = roiIMG.getBounds();
    // Forcing to component colormodel in order to avoid packed bits
    ImageWorker w = new ImageWorker();
    w.setImage(roiIMG);
    w.forceComponentColorModel();
    RenderedImage img = w.getRenderedImage();
    //
    BufferedImage test =
        new BufferedImage(rectIMG.width, rectIMG.height, BufferedImage.TYPE_BYTE_GRAY);
    ImageLayout2 layout = new ImageLayout2(test);
    layout.setMinX(img.getMinX());
    layout.setMinY(img.getMinY());
    layout.setWidth(img.getWidth());
    layout.setHeight(img.getHeight());
    // Lookup
    byte[] lut = new byte[256];
    lut[255] = 1;
    lut[1] = 1;
    LookupTableJAI table = new LookupTableJAI(lut);
    RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
    RenderedOp transformed = LookupDescriptor.create(img, table, hints);

    Graphics2D gc2d = null;
    // Translation parameters in order to position the ROI data correctly in the Raster Space
    int trX = -rectIMG.x + rectROI.x - rectIMG.x;
    int trY = -rectIMG.y + rectROI.y - rectIMG.y;
    try {
      gc2d = test.createGraphics();
      gc2d.drawRenderedImage(transformed, AffineTransform.getTranslateInstance(trX, trY));
    } finally {
      gc2d.dispose();
    }
    Rectangle testRect = new Rectangle(rectIMG.width, rectIMG.height);
    DataBufferByte dbRoi = (DataBufferByte) test.getData(testRect).getDataBuffer();
    dataROI = dbRoi.getData();
    // BufferedImage is stored in memory so the planarImage chain before can be disposed
    ImageUtilities.disposePlanarImageChain(transformed);
    // Flush of the BufferedImage
    test.flush();

    return dataROI;
  }
  /**
   * Returns a contiguous <code>Raster</code> of data over the specified <code>Rectangle</code>. If
   * the region is a sub-region of a single tile, then a child of that tile will be returned. If the
   * region overlaps more than one tile and has 8 bits per sample, then a pixel interleaved Raster
   * having band offsets 0,1,... will be returned. Otherwise the Raster returned by <code>
   * im.copyData(null)</code> will be returned.
   */
  private static final Raster getContiguousData(RenderedImage im, Rectangle region) {
    if (im == null) {
      throw new IllegalArgumentException("im == null");
    } else if (region == null) {
      throw new IllegalArgumentException("region == null");
    }

    Raster raster;
    if (im.getNumXTiles() == 1 && im.getNumYTiles() == 1) {
      // Image is not tiled so just get a reference to the tile.
      raster = im.getTile(im.getMinTileX(), im.getMinTileY());

      // Ensure result has requested coverage.
      Rectangle bounds = raster.getBounds();
      if (!bounds.equals(region)) {
        raster =
            raster.createChild(
                region.x, region.y, region.width, region.height, region.x, region.y, null);
      }
    } else {
      // Image is tiled.

      // Create an interleaved raster for copying for 8-bit case.
      // This ensures that for RGB data the band offsets are {0,1,2}.
      SampleModel sampleModel = im.getSampleModel();
      WritableRaster target =
          sampleModel.getSampleSize(0) == 8
              ? Raster.createInterleavedRaster(
                  DataBuffer.TYPE_BYTE,
                  im.getWidth(),
                  im.getHeight(),
                  sampleModel.getNumBands(),
                  new Point(im.getMinX(), im.getMinY()))
              : null;

      // Copy the data.
      raster = im.copyData(target);
    }

    return raster;
  }
Example #13
0
  private BufferedImage cropScaleGrayscale(Rectangle visibleRect, RenderedImage image) {
    int minX = image.getMinX();
    int minY = image.getMinY();
    int width = image.getWidth();
    int height = image.getHeight();

    Rectangle bounds = new Rectangle(minX, minY, width, height);

    visibleRect = bounds.intersection(visibleRect);

    if (bounds.contains(visibleRect)) {
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(image);
      pb.add((float) visibleRect.x);
      pb.add((float) visibleRect.y);
      pb.add((float) visibleRect.width);
      pb.add((float) visibleRect.height);
      image = JAI.create("Crop", pb, JAIContext.noCacheHint);
    }
    Dimension previewSize = getSize();

    if ((visibleRect.width > previewSize.width) || (visibleRect.height > previewSize.height)) {
      float scale =
          Math.min(
              previewSize.width / (float) visibleRect.width,
              previewSize.height / (float) visibleRect.height);

      image = ConvolveDescriptor.create(image, Functions.getGaussKernel(.25 / scale), null);
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(image);
      pb.add(scale);
      pb.add(scale);
      image = JAI.create("Scale", pb, JAIContext.noCacheHint);
    }
    image = Functions.toColorSpace(image, JAIContext.systemColorSpace, null);

    if (image.getSampleModel().getDataType() == DataBuffer.TYPE_USHORT) {
      image = Functions.fromUShortToByte(image, null);
    }
    return Functions.toFastBufferedImage(image);
  }
Example #14
0
 public static void dumpImageInfo(RenderedImage image) {
   final SampleModel sampleModel = image.getSampleModel();
   final ColorModel colorModel = image.getColorModel();
   System.out.println("image: " + image);
   System.out.println("  minX            = " + image.getMinX());
   System.out.println("  minY            = " + image.getMinY());
   System.out.println("  width           = " + image.getWidth());
   System.out.println("  height          = " + image.getHeight());
   System.out.println(
       "  colorModel      = " + (colorModel != null ? colorModel.getClass() : "null"));
   System.out.println(
       "  colorSpace      = " + (colorModel != null ? colorModel.getColorSpace() : "null"));
   System.out.println("  sampleModel     = " + sampleModel.getClass());
   System.out.println("  numBands        = " + sampleModel.getNumBands());
   System.out.println("  dataType        = " + sampleModel.getDataType());
   System.out.println("  transferType    = " + sampleModel.getTransferType());
   System.out.println("  tileGridXOffset = " + image.getTileGridXOffset());
   System.out.println("  tileGridYOffset = " + image.getTileGridYOffset());
   System.out.println("  minTileX        = " + image.getMinTileX());
   System.out.println("  minTileY        = " + image.getMinTileY());
   System.out.println("  tileWidth       = " + image.getTileWidth());
   System.out.println("  tileHeight      = " + image.getTileHeight());
 }
  /**
   * Checking if NoData and ROI are defined correctly
   *
   * @param indexed
   * @param image
   * @param roi
   * @param nodata
   * @param destNoData
   */
  private void checkNoDataROI(
      RenderedImage indexed, RenderedImage image, ROI roi, Range nodata, int destNoData) {
    // Ensure the dimensions are the same
    assertEquals(indexed.getMinX(), image.getMinX());
    assertEquals(indexed.getMinY(), image.getMinY());
    assertEquals(indexed.getWidth(), image.getWidth());
    assertEquals(indexed.getHeight(), image.getHeight());

    boolean roiExists = roi != null;
    boolean nodataExists = nodata != null;
    // Simply ensure no exception is thrown
    if (!nodataExists && !roiExists) {
      PlanarImage.wrapRenderedImage(indexed).getTiles();
      return;
    }

    if (nodataExists) {
      nodata = RangeFactory.convertToDoubleRange(nodata);
    }
    RandomIter roiIter = null;
    Rectangle roiBounds = null;
    if (roiExists) {
      PlanarImage roiIMG = roi.getAsImage();
      roiIter = RandomIterFactory.create(roiIMG, null, true, true);
      roiBounds = roi.getBounds();
    }

    // Else check ROI and NoData
    RandomIter sourceIter = RandomIterFactory.create(image, null, true, true);
    RandomIter destIter = RandomIterFactory.create(indexed, null, true, true);
    // Start the iteration (we iterate only the first band)
    int w = image.getWidth();
    int h = image.getHeight();
    int minX = image.getMinX();
    int minY = image.getMinY();
    int maxX = minX + w;
    int maxY = minY + h;
    int limx = minX - image.getTileGridXOffset();
    int limy = minY - image.getTileGridYOffset();
    Rectangle translated = new Rectangle(limx, limy, w, h);

    for (int y = minY; y < maxY; y++) {
      for (int x = minX; x < maxX; x++) {

        double src = sourceIter.getSampleDouble(x, y, 0);
        double dest = destIter.getSampleDouble(x, y, 0);

        boolean valid = true;

        // ROI Check
        if (roiExists
            && !(roiBounds.contains(x, y) && roiIter.getSample(x, y, 0) > 0)
            && translated.contains(x, y)) {
          valid = false;
        }

        // NoData Check
        if (nodataExists && nodata.contains(src)) {
          valid = false;
        }
        if (!valid) {
          assertEquals(destNoData, dest, TOLERANCE);
        }
      }
    }
  }
  /**
   * Quick method for populating the {@link CUDABean} instance provided.
   *
   * @param bean
   * @param reference
   * @param coverage
   * @param geo
   * @param transform
   * @throws IOException
   * @throws MismatchedDimensionException
   * @throws TransformException
   */
  private void populateBean(
      CUDABean bean,
      boolean reference,
      GridCoverage2D coverage,
      Geometry geo,
      MathTransform transform,
      int buffer)
      throws IOException, MismatchedDimensionException, TransformException {

    RenderedImage image = coverage.getRenderedImage();

    // 0) Check if a buffer must be applied
    Geometry originalGeo = (Geometry) geo.clone();
    if (buffer > 0) {
      try {
        if (!"EPSG:4326"
            .equals(CRS.lookupIdentifier(coverage.getCoordinateReferenceSystem(), false))) {
          geo = geo.buffer(buffer);
        } else {
          geo = geo.buffer(buffer / 111.128);
        }
      } catch (FactoryException e) {
        geo = geo.buffer(buffer);
      }
    }

    // 1) Crop the two coverages with the selected Geometry
    GridCoverage2D crop = CROP.execute(coverage, geo, null);
    transform =
        ProjectiveTransform.create(
                (AffineTransform) crop.getGridGeometry().getGridToCRS(PixelInCell.CELL_CORNER))
            .inverse();

    // 2) Extract the BufferedImage from each image
    image = crop.getRenderedImage();

    Rectangle rectIMG =
        new Rectangle(image.getMinX(), image.getMinY(), image.getWidth(), image.getHeight());
    ImageWorker w = new ImageWorker(image);
    BufferedImage buf = w.getBufferedImage();
    if (image instanceof RenderedOp) {
      ((RenderedOp) image).dispose();
    }

    // 3) Generate an array of data from each image
    Raster data = buf.getData();
    final DataBufferByte db = (DataBufferByte) data.getDataBuffer();
    byte[] byteData = db.getData();

    if (reference) {
      // 4) Transform the Geometry to Raster space
      Geometry rs = JTS.transform(geo, transform);
      Geometry rsFilter = JTS.transform(geo.difference(originalGeo), transform);
      ROI roiGeo = new ROIGeometry(rs);
      ROI roiFilter = new ROIGeometry(rsFilter);

      // 5) Extract an array of data from the transformed ROI
      byte[] roiData = getROIData((buffer > 0 ? roiFilter : roiGeo), rectIMG);
      bean.setRoi(roiData);
      bean.setRoiObj(roiGeo);

      // 6) Setting the Coverage data array
      bean.setReferenceImage(byteData);

      // 7) Setting the Image dimensions
      bean.setHeight(rectIMG.height);
      bean.setWidth(rectIMG.width);
      bean.setMinX(rectIMG.x);
      bean.setMinY(rectIMG.y);
    } else {
      // 6) Setting the Coverage data array
      bean.setCurrentImage(byteData);
    }

    // 7) Store the Reference Covergae containing the geospatial info
    bean.setReferenceCoverage(coverage);
  }
  /**
   * Returns the specified property.
   *
   * @param name Property name.
   * @param opNode Operation node.
   */
  public Object getProperty(String name, Object opNode) {
    validate(name, opNode);

    if (opNode instanceof RenderedOp && name.equalsIgnoreCase("roi")) {
      RenderedOp op = (RenderedOp) opNode;

      ParameterBlock pb = op.getParameterBlock();

      // Retrieve the rendered source image and its ROI.
      RenderedImage src = pb.getRenderedSource(0);
      Object property = src.getProperty("ROI");
      if (property == null
          || property.equals(java.awt.Image.UndefinedProperty)
          || !(property instanceof ROI)) {
        return java.awt.Image.UndefinedProperty;
      }

      // Return undefined also if source ROI is empty.
      ROI srcROI = (ROI) property;
      if (srcROI.getBounds().isEmpty()) {
        return java.awt.Image.UndefinedProperty;
      }

      // Retrieve the Interpolation object.
      Interpolation interp = (Interpolation) pb.getObjectParameter(1);

      // Determine the effective source bounds.
      Rectangle srcBounds = null;
      PlanarImage dst = op.getRendering();
      if (dst instanceof GeometricOpImage && ((GeometricOpImage) dst).getBorderExtender() == null) {
        srcBounds =
            new Rectangle(
                src.getMinX() + interp.getLeftPadding(),
                src.getMinY() + interp.getTopPadding(),
                src.getWidth() - interp.getWidth() + 1,
                src.getHeight() - interp.getHeight() + 1);
      } else {
        srcBounds = new Rectangle(src.getMinX(), src.getMinY(), src.getWidth(), src.getHeight());
      }

      // If necessary, clip the ROI to the effective source bounds.
      if (!srcBounds.contains(srcROI.getBounds())) {
        srcROI = srcROI.intersect(new ROIShape(srcBounds));
      }

      // Retrieve the Warp object.
      Warp warp = (Warp) pb.getObjectParameter(0);

      // Setting constant image to be warped as a ROI
      Rectangle dstBounds = op.getBounds();

      // Setting layout of the constant image
      ImageLayout2 layout = new ImageLayout2();
      int minx = (int) srcBounds.getMinX();
      int miny = (int) srcBounds.getMinY();
      int w = (int) srcBounds.getWidth();
      int h = (int) srcBounds.getHeight();
      layout.setMinX(minx);
      layout.setMinY(miny);
      layout.setWidth(w);
      layout.setHeight(h);
      RenderingHints hints = op.getRenderingHints();
      hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));

      final PlanarImage constantImage =
          ConstantDescriptor.create(new Float(w), new Float(h), new Byte[] {(byte) 255}, hints);

      PlanarImage roiImage = null;

      // Make sure to specify tileCache, tileScheduler, tileRecyclier, by cloning hints.
      RenderingHints warpingHints = op.getRenderingHints();
      warpingHints.remove(JAI.KEY_IMAGE_LAYOUT);

      // Creating warped roi by the same way (Warp, Interpolation, source ROI) we warped the
      // input image.
      final ParameterBlock paramBlk = new ParameterBlock();
      paramBlk.addSource(constantImage);
      paramBlk.add(warp);
      paramBlk.add(interp);
      paramBlk.add(null);
      paramBlk.add(srcROI);

      // force in the image layout, this way we get exactly the same
      // as the affine we're eliminating
      Hints localHints = new Hints(op.getRenderingHints());
      localHints.remove(JAI.KEY_IMAGE_LAYOUT);
      ImageLayout il = new ImageLayout();
      il.setMinX(dstBounds.x);
      il.setMinY(dstBounds.y);
      il.setWidth(dstBounds.width);
      il.setHeight(dstBounds.height);
      localHints.put(JAI.KEY_IMAGE_LAYOUT, il);
      roiImage = JAI.create("Warp", paramBlk, localHints);
      ROI dstROI = new ROI(roiImage, 1);

      // If necessary, clip the warped ROI to the destination bounds.
      if (!dstBounds.contains(dstROI.getBounds())) {
        dstROI = dstROI.intersect(new ROIShape(dstBounds));
      }

      // Return the warped and possibly clipped ROI.
      return dstROI;
    }

    return java.awt.Image.UndefinedProperty;
  }
  /**
   * For each raster: crop->scale->translate->add to mosaic
   *
   * @param queries
   * @param mosaicGeometry
   * @return
   * @throws IOException
   */
  private RenderedImage createMosaic(
      final List<RasterQueryInfo> queries,
      final GridEnvelope mosaicGeometry,
      final LoggingHelper log)
      throws IOException {

    List<RenderedImage> transformed = new ArrayList<RenderedImage>(queries.size());

    /*
     * Do we need to expand to RGB color space and then create a new colormapped image with the
     * whole mosaic?
     */
    boolean expandCM = queries.size() > 1 && rasterInfo.isColorMapped();
    if (expandCM) {
      LOGGER.fine(
          "Creating mosaic out of "
              + queries.size()
              + " colormapped rasters. The mosaic tiles will be expanded to "
              + "\nRGB space and the resulting mosaic reduced to a new IndexColorModel");
    }

    for (RasterQueryInfo query : queries) {
      RenderedImage image = query.getResultImage();
      log.log(image, query.getRasterId(), "01_original");
      if (expandCM) {
        if (LOGGER.isLoggable(Level.FINER)) {
          LOGGER.finer(
              "Creating color expanded version of tile for raster #" + query.getRasterId());
        }

        /*
         * reformat the image as a 4 band rgba backed by byte data
         */
        image = FormatDescriptor.create(image, Integer.valueOf(DataBuffer.TYPE_BYTE), null);

        log.log(image, query.getRasterId(), "04_1_colorExpanded");
      }

      image = cropToRequiredDimension(image, query.getResultGridRange());
      log.log(image, query.getRasterId(), "02_crop");

      // Raster data = image.getData();
      // image = new BufferedImage(image.getColorModel(), (WritableRaster) data, false, null);
      if (queries.size() == 1) {
        return image;
      }
      final GridEnvelope mosaicLocation = query.getMosaicLocation();
      // scale
      Float scaleX = Float.valueOf(((float) mosaicLocation.getSpan(0) / image.getWidth()));
      Float scaleY = Float.valueOf(((float) mosaicLocation.getSpan(1) / image.getHeight()));
      Float translateX = Float.valueOf(0);
      Float translateY = Float.valueOf(0);

      if (!(Float.valueOf(1.0F).equals(scaleX) && Float.valueOf(1.0F).equals(scaleY))) {
        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image);
        pb.add(scaleX);
        pb.add(scaleY);
        pb.add(translateX);
        pb.add(translateY);
        pb.add(new InterpolationNearest());

        image = JAI.create("scale", pb);
        log.log(image, query.getRasterId(), "03_scale");

        int width = image.getWidth();
        int height = image.getHeight();

        assert mosaicLocation.getSpan(0) == width;
        assert mosaicLocation.getSpan(1) == height;
      }

      if (image.getMinX() != mosaicLocation.getLow(0)
          || image.getMinY() != mosaicLocation.getLow(1)) {
        // translate
        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image);
        pb.add(Float.valueOf(mosaicLocation.getLow(0) - image.getMinX()));
        pb.add(Float.valueOf(mosaicLocation.getLow(1) - image.getMinY()));
        pb.add(null);

        image = JAI.create("translate", pb);
        log.log(image, query.getRasterId(), "04_translate");

        assert image.getMinX() == mosaicLocation.getLow(0)
            : image.getMinX() + " != " + mosaicLocation.getLow(0);
        assert image.getMinY() == mosaicLocation.getLow(1)
            : image.getMinY() + " != " + mosaicLocation.getLow(1);
        assert image.getWidth() == mosaicLocation.getSpan(0)
            : image.getWidth() + " != " + mosaicLocation.getSpan(0);
        assert image.getHeight() == mosaicLocation.getSpan(1)
            : image.getHeight() + " != " + mosaicLocation.getSpan(1);
      }

      transformed.add(image);
    }

    final RenderedImage mosaic;
    if (queries.size() == 1) {
      /*
       * This is besides a very slight perf improvement needed because the JAI mosaic
       * operation truncates floating point raster values to 0 and 1. REVISIT: If there's no
       * workaround for that we should prevent raster catalogs made of floating point rasters
       * and throw an exception as we could not really support that.
       */
      mosaic = transformed.get(0);
    } else {
      /*
       * adapted from RasterLayerResponse.java in the imagemosaic module
       */
      ParameterBlockJAI mosaicParams = new ParameterBlockJAI("Mosaic");
      mosaicParams.setParameter("mosaicType", MosaicDescriptor.MOSAIC_TYPE_OVERLAY);

      // set background values to raster's no-data
      double[] backgroundValues;
      if (expandCM) {
        backgroundValues = new double[] {0, 0, 0, 0};
      } else {
        final int numBands = rasterInfo.getNumBands();
        backgroundValues = new double[numBands];
        final int rasterIndex = 0;
        Number noDataValue;
        for (int bn = 0; bn < numBands; bn++) {
          noDataValue = rasterInfo.getNoDataValue(rasterIndex, bn);
          backgroundValues[bn] = noDataValue.doubleValue();
        }
      }
      mosaicParams.setParameter("backgroundValues", backgroundValues);

      final ImageLayout layout =
          new ImageLayout(
              mosaicGeometry.getLow(0),
              mosaicGeometry.getLow(1),
              mosaicGeometry.getSpan(0),
              mosaicGeometry.getSpan(1));
      final int tileWidth = rasterInfo.getTileDimension(0).width;
      final int tileHeight = rasterInfo.getTileDimension(0).height;
      layout.setTileWidth(tileWidth);
      layout.setTileHeight(tileHeight);

      final RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);

      for (RenderedImage img : transformed) {
        mosaicParams.addSource(img);
        log.appendLoggingGeometries(LoggingHelper.MOSAIC_RESULT, img);
      }
      log.log(LoggingHelper.MOSAIC_RESULT);

      LOGGER.fine("Creating mosaic out of " + queries.size() + " raster tiles");
      mosaic = JAI.create("Mosaic", mosaicParams, hints);

      log.log(mosaic, 0L, "05_mosaic_result");
    }
    return mosaic;
  }
Example #19
0
  public void encode(RenderedImage im) throws IOException {
    // Get the SampleModel.
    SampleModel sm = im.getSampleModel();

    // Check the data type, band count, and sample size.
    int dataType = sm.getTransferType();
    if (dataType == DataBuffer.TYPE_FLOAT || dataType == DataBuffer.TYPE_DOUBLE) {
      throw new IllegalArgumentException(JaiI18N.getString("WBMPImageEncoder0"));
    } else if (sm.getNumBands() != 1) {
      throw new IllegalArgumentException(JaiI18N.getString("WBMPImageEncoder1"));
    } else if (sm.getSampleSize(0) != 1) {
      throw new IllegalArgumentException(JaiI18N.getString("WBMPImageEncoder2"));
    }

    // Save image dimensions.
    int width = im.getWidth();
    int height = im.getHeight();

    // Write WBMP header.
    output.write(0); // TypeField
    output.write(0); // FixHeaderField
    output.write(intToMultiByte(width)); // width
    output.write(intToMultiByte(height)); // height

    Raster tile = null;

    // If the data are not formatted nominally then reformat.
    if (sm.getDataType() != DataBuffer.TYPE_BYTE
        || !(sm instanceof MultiPixelPackedSampleModel)
        || ((MultiPixelPackedSampleModel) sm).getDataBitOffset() != 0) {
      MultiPixelPackedSampleModel mppsm =
          new MultiPixelPackedSampleModel(
              DataBuffer.TYPE_BYTE, width, height, 1, (width + 7) / 8, 0);
      WritableRaster raster =
          Raster.createWritableRaster(mppsm, new Point(im.getMinX(), im.getMinY()));
      raster.setRect(im.getData());
      tile = raster;
    } else if (im.getNumXTiles() == 1 && im.getNumYTiles() == 1) {
      tile = im.getTile(im.getMinTileX(), im.getMinTileY());
    } else {
      tile = im.getData();
    }

    // Check whether the image is white-is-zero.
    boolean isWhiteZero = false;
    if (im.getColorModel() instanceof IndexColorModel) {
      IndexColorModel icm = (IndexColorModel) im.getColorModel();
      isWhiteZero =
          (icm.getRed(0) + icm.getGreen(0) + icm.getBlue(0))
              > (icm.getRed(1) + icm.getGreen(1) + icm.getBlue(1));
    }

    // Get the line stride, bytes per row, and data array.
    int lineStride = ((MultiPixelPackedSampleModel) sm).getScanlineStride();
    int bytesPerRow = (width + 7) / 8;
    byte[] bdata = ((DataBufferByte) tile.getDataBuffer()).getData();

    // Write the data.
    if (!isWhiteZero && lineStride == bytesPerRow) {
      // Write the entire image.
      output.write(bdata, 0, height * bytesPerRow);
    } else {
      // Write the image row-by-row.
      int offset = 0;
      if (!isWhiteZero) {
        // Black-is-zero
        for (int row = 0; row < height; row++) {
          output.write(bdata, offset, bytesPerRow);
          offset += lineStride;
        }
      } else {
        // White-is-zero: need to invert data.
        byte[] inverted = new byte[bytesPerRow];
        for (int row = 0; row < height; row++) {
          for (int col = 0; col < bytesPerRow; col++) {
            inverted[col] = (byte) (~(bdata[col + offset]));
          }
          output.write(inverted, 0, bytesPerRow);
          offset += lineStride;
        }
      }
    }
  }
Example #20
0
  /**
   * Writes any extension blocks, the Image Descriptor, the image data, and optionally the header
   * (Signature and Logical Screen Descriptor) and trailer (Block Terminator).
   *
   * @param writeHeader Whether to write the header.
   * @param writeTrailer Whether to write the trailer.
   * @param sm The stream metadata or <code>null</code> if <code>writeHeader</code> is <code>false
   *     </code>.
   * @param iioimage The image and image metadata.
   * @param p The write parameters.
   * @throws IllegalArgumentException if the number of bands is not 1.
   * @throws IllegalArgumentException if the number of bits per sample is greater than 8.
   * @throws IllegalArgumentException if the color component size is greater than 8.
   * @throws IllegalArgumentException if <code>writeHeader</code> is <code>true</code> and <code>sm
   *     </code> is <code>null</code>.
   * @throws IllegalArgumentException if <code>writeHeader</code> is <code>false</code> and a
   *     sequence is not being written.
   */
  private void write(
      boolean writeHeader,
      boolean writeTrailer,
      IIOMetadata sm,
      IIOImage iioimage,
      ImageWriteParam p)
      throws IOException {
    clearAbortRequest();

    RenderedImage image = iioimage.getRenderedImage();

    // Check for ability to encode image.
    if (needToCreateIndex(image)) {
      image = PaletteBuilder.createIndexedImage(image);
      iioimage.setRenderedImage(image);
    }

    ColorModel colorModel = image.getColorModel();
    SampleModel sampleModel = image.getSampleModel();

    // Determine source region and destination dimensions.
    Rectangle sourceBounds =
        new Rectangle(image.getMinX(), image.getMinY(), image.getWidth(), image.getHeight());
    Dimension destSize = new Dimension();
    computeRegions(sourceBounds, destSize, p);

    // Convert any provided image metadata.
    GIFWritableImageMetadata imageMetadata = null;
    if (iioimage.getMetadata() != null) {
      imageMetadata = new GIFWritableImageMetadata();
      convertMetadata(IMAGE_METADATA_NAME, iioimage.getMetadata(), imageMetadata);
      // Converted rgb image can use palette different from global.
      // In order to avoid color artefacts we want to be sure we use
      // appropriate palette. For this we initialize local color table
      // from current color and sample models.
      // At this point we can guarantee that local color table can be
      // build because image was already converted to indexed or
      // gray-scale representations
      if (imageMetadata.localColorTable == null) {
        imageMetadata.localColorTable = createColorTable(colorModel, sampleModel);

        // in case of indexed image we should take care of
        // transparent pixels
        if (colorModel instanceof IndexColorModel) {
          IndexColorModel icm = (IndexColorModel) colorModel;
          int index = icm.getTransparentPixel();
          imageMetadata.transparentColorFlag = (index != -1);
          if (imageMetadata.transparentColorFlag) {
            imageMetadata.transparentColorIndex = index;
          }
          /* NB: transparentColorFlag might have not beed reset for
             greyscale images but explicitly reseting it here
             is potentially not right thing to do until we have way
             to find whether current value was explicitly set by
             the user.
          */
        }
      }
    }

    // Global color table values.
    byte[] globalColorTable = null;

    // Write the header (Signature+Logical Screen Descriptor+
    // Global Color Table).
    if (writeHeader) {
      if (sm == null) {
        throw new IllegalArgumentException("Cannot write null header!");
      }

      GIFWritableStreamMetadata streamMetadata = (GIFWritableStreamMetadata) sm;

      // Set the version if not set.
      if (streamMetadata.version == null) {
        streamMetadata.version = "89a";
      }

      // Set the Logical Screen Desriptor if not set.
      if (streamMetadata.logicalScreenWidth == GIFMetadata.UNDEFINED_INTEGER_VALUE) {
        streamMetadata.logicalScreenWidth = destSize.width;
      }

      if (streamMetadata.logicalScreenHeight == GIFMetadata.UNDEFINED_INTEGER_VALUE) {
        streamMetadata.logicalScreenHeight = destSize.height;
      }

      if (streamMetadata.colorResolution == GIFMetadata.UNDEFINED_INTEGER_VALUE) {
        streamMetadata.colorResolution =
            colorModel != null ? colorModel.getComponentSize()[0] : sampleModel.getSampleSize()[0];
      }

      // Set the Global Color Table if not set, i.e., if not
      // provided in the stream metadata.
      if (streamMetadata.globalColorTable == null) {
        if (isWritingSequence && imageMetadata != null && imageMetadata.localColorTable != null) {
          // Writing a sequence and a local color table was
          // provided in the metadata of the first image: use it.
          streamMetadata.globalColorTable = imageMetadata.localColorTable;
        } else if (imageMetadata == null || imageMetadata.localColorTable == null) {
          // Create a color table.
          streamMetadata.globalColorTable = createColorTable(colorModel, sampleModel);
        }
      }

      // Set the Global Color Table. At this point it should be
      // A) the global color table provided in stream metadata, if any;
      // B) the local color table of the image metadata, if any, if
      //    writing a sequence;
      // C) a table created on the basis of the first image ColorModel
      //    and SampleModel if no local color table is available; or
      // D) null if none of the foregoing conditions obtain (which
      //    should only be if a sequence is not being written and
      //    a local color table is provided in image metadata).
      globalColorTable = streamMetadata.globalColorTable;

      // Write the header.
      int bitsPerPixel;
      if (globalColorTable != null) {
        bitsPerPixel = getNumBits(globalColorTable.length / 3);
      } else if (imageMetadata != null && imageMetadata.localColorTable != null) {
        bitsPerPixel = getNumBits(imageMetadata.localColorTable.length / 3);
      } else {
        bitsPerPixel = sampleModel.getSampleSize(0);
      }
      writeHeader(streamMetadata, bitsPerPixel);
    } else if (isWritingSequence) {
      globalColorTable = theStreamMetadata.globalColorTable;
    } else {
      throw new IllegalArgumentException("Must write header for single image!");
    }

    // Write extension blocks, Image Descriptor, and image data.
    writeImage(
        iioimage.getRenderedImage(), imageMetadata, p, globalColorTable, sourceBounds, destSize);

    // Write the trailer.
    if (writeTrailer) {
      writeTrailer();
    }
  }
    @Override
    public RenderedImage postProcessMosaic(
        RenderedImage mosaic, ROI overallROI, RenderingHints hints) {

      // force the current image in RGB or Gray
      final ImageWorker imageWorker = new ImageWorker(mosaic);
      hints = prepareHints(hints);
      imageWorker.setRenderingHints(hints);

      // make sure the mosaic image is either gray of RGB
      if (!imageWorker.isColorSpaceGRAYScale()) {
        if (!imageWorker.isColorSpaceRGB()) {
          imageWorker.forceColorSpaceRGB();
        }
      }
      imageWorker.forceComponentColorModel(); // todo optimize with paletted imagery

      // do we already have a alpha band in the input image?
      if (imageWorker.getRenderedImage().getColorModel().hasAlpha()) {
        // if so we reuse it applying the ROI on top of it
        RenderedImage alpha = imageWorker.retainLastBand().getRenderedImage();
        RenderedImage maskedAlpha =
            new ImageWorker(hints)
                .mosaic(
                    new RenderedImage[] {alpha},
                    MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
                    null,
                    new ROI[] {overallROI},
                    null,
                    null)
                .getRenderedImage();

        imageWorker.retainBands(mosaic.getColorModel().getNumColorComponents());
        imageWorker.addBand(maskedAlpha, false, true, null);
      } else {

        // turn the roi into a single band image and add it to the mosaic as transparency
        final ImageWorker roiImageWorker = new ImageWorker(overallROI.getAsImage());
        roiImageWorker.setRenderingHints(hints);

        PlanarImage alpha =
            roiImageWorker.forceComponentColorModel().retainFirstBand().getPlanarImage();
        if (!alpha.getBounds().equals(imageWorker.getPlanarImage().getBounds())) {
          // build final layout and use it for giving the alpha band a simil size and tiling
          // to the one of the image
          final ImageLayout layout =
              new ImageLayout(
                  mosaic.getMinX(), mosaic.getMinY(), mosaic.getWidth(), mosaic.getHeight());

          //
          final SampleModel sampleModel = mosaic.getSampleModel();
          layout.setTileHeight(sampleModel.getWidth()).setTileWidth(sampleModel.getHeight());
          hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));

          // correct bounds of the current image
          alpha =
              new ImageWorker(hints)
                  .mosaic(
                      new RenderedImage[] {alpha},
                      MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
                      null,
                      new ROI[] {overallROI},
                      null,
                      null)
                  .getRenderedOperation();
        }
        imageWorker.addBand(alpha, false, true, null);
      }

      RenderedImage result = imageWorker.getRenderedImage();
      return result;
    }
Example #22
0
  private void testType(RenderedImage src, boolean nodataUsed, boolean roiUsed) {
    // Optional No Data Range used
    Range noData;
    // Source image data type
    int dataType = src.getSampleModel().getDataType();
    // If no Data are present, the No Data Range associated is used
    if (nodataUsed) {

      switch (dataType) {
        case DataBuffer.TYPE_BYTE:
          noData = noDataByte;
          break;
        case DataBuffer.TYPE_USHORT:
          noData = noDataUShort;
          break;
        case DataBuffer.TYPE_SHORT:
          noData = noDataShort;
          break;
        case DataBuffer.TYPE_INT:
          noData = noDataInt;
          break;
        case DataBuffer.TYPE_FLOAT:
          noData = noDataFloat;
          break;
        case DataBuffer.TYPE_DOUBLE:
          noData = noDataDouble;
          break;
        default:
          throw new IllegalArgumentException("Wrong data type");
      }
    } else {
      noData = null;
    }

    ROI roi;

    if (roiUsed) {
      roi = roiObject;
    } else {
      roi = null;
    }

    // BandCombined result
    RenderedOp combined =
        BandCombineDescriptor.create(src, matrix, roi, noData, destinationNoData, null);

    int tileWidth = combined.getTileWidth();
    int tileHeight = combined.getTileHeight();
    int minTileX = combined.getMinTileX();
    int minTileY = combined.getMinTileY();
    int numXTiles = combined.getNumXTiles();
    int numYTiles = combined.getNumYTiles();
    int maxTileX = minTileX + numXTiles;
    int maxTileY = minTileY + numYTiles;
    // Ensure same size
    assertEquals(combined.getWidth(), src.getWidth());
    assertEquals(combined.getHeight(), src.getHeight());
    assertEquals(combined.getMinX(), src.getMinX());
    assertEquals(combined.getMinY(), src.getMinY());
    assertEquals(minTileX, src.getMinTileX());
    assertEquals(minTileY, src.getMinTileY());
    assertEquals(numXTiles, src.getNumXTiles());
    assertEquals(numYTiles, src.getNumYTiles());
    assertEquals(tileWidth, src.getTileWidth());
    assertEquals(tileHeight, src.getTileHeight());

    int srcBands = src.getSampleModel().getNumBands();
    int dstBands = combined.getNumBands();

    // Ensure a correct band size
    assertEquals(dstBands, matrix.length);

    // Check on all the pixels if they have been calculate correctly
    for (int tileX = minTileX; tileX < maxTileX; tileX++) {
      for (int tileY = minTileY; tileY < maxTileY; tileY++) {
        Raster tile = combined.getTile(tileX, tileY);
        Raster srcTile = src.getTile(tileX, tileY);

        int minX = tile.getMinX();
        int minY = tile.getMinY();
        int maxX = minX + tileWidth - 1;
        int maxY = minY + tileHeight - 1;

        for (int x = minX; x <= maxX; x++) {
          for (int y = minY; y <= maxY; y++) {

            boolean isValidRoi = !roiUsed || (roiUsed && roiObject.contains(x, y));

            if (isValidRoi) {
              for (int b = 0; b < dstBands; b++) {
                // Getting the result
                double result = tile.getSampleDouble(x, y, b);

                // Calculating the expected result from sources
                boolean valid = false;
                double calculated = 0;

                for (int i = 0; i < srcBands; i++) {
                  double sample = srcTile.getSampleDouble(x, y, i);
                  boolean isValidData =
                      !nodataUsed || (nodataUsed && !noDataDouble.contains(sample));
                  valid |= isValidData;
                  if (isValidData) {
                    switch (dataType) {
                      case DataBuffer.TYPE_BYTE:
                        calculated += ((int) sample & 0xFF) * matrix[b][i];
                        break;
                      case DataBuffer.TYPE_USHORT:
                        calculated += ((int) sample & 0xFFFF) * matrix[b][i];
                        break;
                      case DataBuffer.TYPE_SHORT:
                      case DataBuffer.TYPE_INT:
                      case DataBuffer.TYPE_FLOAT:
                      case DataBuffer.TYPE_DOUBLE:
                        calculated += sample * matrix[b][i];
                        break;
                      default:
                        break;
                    }
                  }
                }

                if (valid) {
                  calculated += matrix[b][srcBands];
                  switch (dataType) {
                    case DataBuffer.TYPE_BYTE:
                      calculated = ImageUtil.clampRoundByte(calculated);
                      result = ImageUtil.clampRoundByte(result);
                      break;
                    case DataBuffer.TYPE_USHORT:
                      calculated = ImageUtil.clampRoundUShort(calculated);
                      result = ImageUtil.clampRoundUShort(result);
                      break;
                    case DataBuffer.TYPE_SHORT:
                      calculated = ImageUtil.clampRoundShort(calculated);
                      result = ImageUtil.clampRoundShort(result);
                      break;
                    case DataBuffer.TYPE_INT:
                      calculated = ImageUtil.clampRoundInt(calculated);
                      result = ImageUtil.clampRoundInt(result);
                      break;
                    case DataBuffer.TYPE_FLOAT:
                      calculated = (float) calculated;
                      calculated = (float) result;
                      break;
                    case DataBuffer.TYPE_DOUBLE:
                      break;
                    default:
                      break;
                  }
                  assertEquals(result, calculated, TOLERANCE);
                } else {
                  assertEquals(result, destNoData, TOLERANCE);
                }
              }
            } else {
              for (int b = 0; b < dstBands; b++) {
                assertEquals(tile.getSampleDouble(x, y, b), destNoData, TOLERANCE);
              }
            }
          }
        }
      }
    }

    // Disposal of the output image
    combined.dispose();
  }