/** * Test Read exploiting JAI-ImageIO tools capabilities and GDAL warp. * * @throws FileNotFoundException * @throws IOException */ @Test public void readWithWarp() throws FileNotFoundException, IOException { if (!isGDALAvailable) { return; } final ParameterBlockJAI pbjImageRead; String fileName = "utmByte.tif"; final File file = TestData.file(this, fileName); SpatialReference destinationReference = new SpatialReference(); destinationReference.SetProjCS("UTM 17 (WGS84) in northern hemisphere."); destinationReference.SetWellKnownGeogCS("WGS84"); destinationReference.SetUTM(17, 1); GDALImageReadParam readParam = new GDALImageReadParam(); readParam.setDestinationWkt(destinationReference.ExportToWkt()); readParam.setResampleAlgorithm(ResampleAlgorithm.CUBIC); pbjImageRead = new ParameterBlockJAI("ImageRead"); pbjImageRead.setParameter("Input", new FileImageInputStreamExtImpl(file)); pbjImageRead.setParameter("Reader", new GeoTiffImageReaderSpi().createReaderInstance()); pbjImageRead.setParameter("ReadParam", readParam); RenderedOp image = JAI.create("ImageRead", pbjImageRead); if (TestData.isInteractiveTest()) Viewer.visualizeAllInformation(image, "", true); else Assert.assertNotNull(image.getTiles()); }
public static RenderedOp create( RenderedImage source0, ROIShape roi, Byte[] bandValues, RenderingHints hints) { ParameterBlockJAI pb = new ParameterBlockJAI("Shutter", RenderedRegistryMode.MODE_NAME); // $NON-NLS-1$ pb.setSource("source0", source0); // $NON-NLS-1$ pb.setParameter("roi", roi); // $NON-NLS-1$ pb.setParameter("color", bandValues); // $NON-NLS-1$ return JAI.create("Shutter", pb, hints); // $NON-NLS-1$ }
/** * Reads a standard JFIF (PNG) file. * * <p>Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints * </code> and invokes {@link JAI#create(String,ParameterBlock,RenderingHints)}. * * @see JAI * @see ParameterBlockJAI * @see RenderedOp * @param stream The SeekableStream to read from. * @param param The PNGDecodeParam to use. May be <code>null</code>. * @param hints The <code>RenderingHints</code> to use. May be <code>null</code>. * @return The <code>RenderedOp</code> destination. * @throws IllegalArgumentException if <code>stream</code> is <code>null</code>. */ public static RenderedOp create( SeekableStream stream, PNGDecodeParam param, RenderingHints hints) { ParameterBlockJAI pb = new ParameterBlockJAI("PNG", RenderedRegistryMode.MODE_NAME); pb.setParameter("stream", stream); pb.setParameter("param", param); return JAI.create("PNG", pb, hints); }
@Test public void rectanglePolyAcrossTiles() throws Exception { final int margin = 3; final int Ntiles = 3; int minx = margin; int miny = minx; int maxx = TILE_WIDTH * Ntiles - 2 * margin; int maxy = maxx; String wkt = String.format( "POLYGON((%d %d, %d %d, %d %d, %d %d, %d %d))", minx, miny, minx, maxy, maxx, maxy, maxx, miny, minx, miny); Polygon poly = (Polygon) reader.read(wkt); ParameterBlockJAI pb = new ParameterBlockJAI("VectorBinarize"); pb.setParameter("width", Ntiles * TILE_WIDTH); pb.setParameter("height", Ntiles * TILE_WIDTH); pb.setParameter("geometry", poly); RenderedOp dest = JAI.create("VectorBinarize", pb); CoordinateSequence2D testPointCS = new CoordinateSequence2D(1); Point testPoint = gf.createPoint(testPointCS); for (int ytile = 0; ytile < Ntiles; ytile++) { for (int xtile = 0; xtile < Ntiles; xtile++) { Raster tile = dest.getTile(xtile, ytile); for (int y = tile.getMinY(), iy = 0; iy < tile.getHeight(); y++, iy++) { testPointCS.setY(0, y + 0.5); for (int x = tile.getMinX(), ix = 0; ix < tile.getWidth(); x++, ix++) { testPointCS.setX(0, x + 0.5); testPoint.geometryChanged(); int expected = poly.intersects(testPoint) ? 1 : 0; assertEquals( "Failed test at position " + x + ", " + y + ", " + "expected " + expected + " but got " + tile.getSample(x, y, 0), expected, tile.getSample(x, y, 0)); } } } } }
/** * Test Read exploiting JAI-ImageIO tools capabilities * * @throws FileNotFoundException * @throws IOException */ @Test public void read() throws FileNotFoundException, IOException { if (!isGDALAvailable) { return; } final ParameterBlockJAI pbjImageRead; String fileName = "utmByte.tif"; final File file = TestData.file(this, fileName); pbjImageRead = new ParameterBlockJAI("ImageRead"); pbjImageRead.setParameter("Input", new FileImageInputStreamExtImpl(file)); pbjImageRead.setParameter("Reader", new GeoTiffImageReaderSpi().createReaderInstance()); RenderedOp image = JAI.create("ImageRead", pbjImageRead); if (TestData.isInteractiveTest()) Viewer.visualizeAllInformation(image, "", true); else Assert.assertNotNull(image.getTiles()); }
protected void handleJAIEXTParams(ParameterBlockJAI parameters, ParameterValueGroup parameters2) { if (JAIExt.isJAIExtOperation("algebric")) { parameters.set(Operator.LOG, 0); Collection<GridCoverage2D> sources = (Collection<GridCoverage2D>) parameters2.parameter("sources").getValue(); for (GridCoverage2D source : sources) { handleROINoDataInternal(parameters, source, "algebric", 1, 2); } } }
@Test public void testFourColor() { // build a transparent image BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_4BYTE_ABGR); Graphics g = image.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, 10, 10); g.setColor(Color.RED); g.fillRect(10, 0, 10, 10); g.setColor(Color.BLUE); g.fillRect(20, 0, 10, 10); g.setColor(Color.GREEN); g.fillRect(30, 0, 10, 10); g.dispose(); // // create a palette out of it // CustomPaletteBuilder builder = new CustomPaletteBuilder(image, 255, 1, 1, 1); builder.buildPalette(); RenderedImage indexed = builder.getIndexedImage(); assertTrue(indexed.getColorModel() instanceof IndexColorModel); IndexColorModel icm = (IndexColorModel) indexed.getColorModel(); // make sure we have 4 colors + transparent one assertEquals(5, icm.getMapSize()); // // now use the JAI op // assertNotNull( (OperationDescriptor) JAI.getDefaultInstance() .getOperationRegistry() .getDescriptor(OperationDescriptor.class, "org.geotools.ColorReduction")); ParameterBlockJAI pbj = new ParameterBlockJAI("org.geotools.ColorReduction"); // I will tile the image in 4 tiles and force parallelism here JAI.getDefaultInstance().getTileScheduler().setParallelism(4); pbj.addSource( new ImageWorker(image) .setRenderingHint( JAI.KEY_IMAGE_LAYOUT, new ImageLayout(image) .setTileGridXOffset(0) .setTileGridYOffset(0) .setTileHeight(64) .setTileWidth(64)) .tile() .getRenderedImage()); pbj.setParameter("numColors", 255); pbj.setParameter("alphaThreshold", 1); pbj.setParameter("subsampleX", 1); pbj.setParameter("subsampleY", 1); indexed = JAI.create("org.geotools.ColorReduction", pbj); PlanarImage.wrapRenderedImage(indexed).getTiles(); assertTrue(indexed.getColorModel() instanceof IndexColorModel); // check that we get the same results assertEquals(indexed.getColorModel(), icm); icm = (IndexColorModel) indexed.getColorModel(); // make sure we have 4 colors + transparent one assertEquals(5, icm.getMapSize()); assertEquals(5, icm.getMapSize()); // // now use the inversion of color // assertNotNull( (OperationDescriptor) JAI.getDefaultInstance() .getOperationRegistry() .getDescriptor(OperationDescriptor.class, "org.geotools.ColorInversion")); pbj = new ParameterBlockJAI("org.geotools.ColorInversion"); pbj.addSource( new ImageWorker(image) .setRenderingHint( JAI.KEY_IMAGE_LAYOUT, new ImageLayout(image) .setTileGridXOffset(0) .setTileGridYOffset(0) .setTileHeight(64) .setTileWidth(64)) .tile() .getRenderedImage()); pbj.setParameter("quantizationColors", InverseColorMapRasterOp.DEFAULT_QUANTIZATION_COLORS); pbj.setParameter("alphaThreshold", 1); pbj.setParameter("IndexColorModel", icm); indexed = JAI.create("org.geotools.ColorInversion", pbj); PlanarImage.wrapRenderedImage(indexed).getTiles(); assertTrue(indexed.getColorModel() instanceof IndexColorModel); // check that we get the same results assertEquals(indexed.getColorModel(), icm); icm = (IndexColorModel) indexed.getColorModel(); // make sure we have 4 colors + transparent one assertEquals(5, icm.getMapSize()); assertEquals(5, icm.getMapSize()); }
/** * Test Read on a Paletted Image * * @throws FileNotFoundException * @throws IOException */ @Test public void palette() throws FileNotFoundException, IOException { if (!isGDALAvailable) { return; } final File outputFile = TestData.temp(this, "writetest.tif", false); outputFile.deleteOnExit(); final File inputFile = TestData.file(this, "paletted.tif"); ImageReader reader = new GeoTiffImageReaderSpi().createReaderInstance(); reader.setInput(inputFile); final IIOMetadata metadata = reader.getImageMetadata(0); final ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead"); pbjImageRead.setParameter("Input", inputFile); pbjImageRead.setParameter("reader", reader); final ImageLayout l = new ImageLayout(); l.setTileGridXOffset(0).setTileGridYOffset(0).setTileHeight(256).setTileWidth(256); RenderedOp image = JAI.create("ImageRead", pbjImageRead, new RenderingHints(JAI.KEY_IMAGE_LAYOUT, l)); if (TestData.isInteractiveTest()) Viewer.visualizeAllInformation(image, "Paletted image read"); // //////////////////////////////////////////////////////////////// // preparing to write // //////////////////////////////////////////////////////////////// final ParameterBlockJAI pbjImageWrite = new ParameterBlockJAI("ImageWrite"); ImageWriter writer = new GeoTiffImageWriterSpi().createWriterInstance(); pbjImageWrite.setParameter("Output", outputFile); pbjImageWrite.setParameter("writer", writer); pbjImageWrite.setParameter("ImageMetadata", metadata); pbjImageWrite.setParameter("Transcode", false); pbjImageWrite.addSource(image); final RenderedOp op = JAI.create("ImageWrite", pbjImageWrite); final ImageWriter writer2 = (ImageWriter) op.getProperty(ImageWriteDescriptor.PROPERTY_NAME_IMAGE_WRITER); writer2.dispose(); // //////////////////////////////////////////////////////////////// // preparing to read again // //////////////////////////////////////////////////////////////// final ParameterBlockJAI pbjImageReRead = new ParameterBlockJAI("ImageRead"); pbjImageReRead.setParameter("Input", outputFile); pbjImageReRead.setParameter("Reader", new GeoTiffImageReaderSpi().createReaderInstance()); final RenderedOp image2 = JAI.create("ImageRead", pbjImageReRead); if (TestData.isInteractiveTest()) Viewer.visualizeAllInformation(image2, "Paletted image read back after writing"); else Assert.assertNotNull(image2.getTiles()); ImageIOUtilities.disposeImage(image2); ImageIOUtilities.disposeImage(image); }
/** * Test Writing capabilities. * * @throws FileNotFoundException * @throws IOException */ @Test public void write() throws IOException, FileNotFoundException { if (!isGDALAvailable) { return; } final File outputFile = TestData.temp(this, "writetest.tif", false); outputFile.deleteOnExit(); final File inputFile = TestData.file(this, "utmByte.tif"); ImageReadParam rparam = new ImageReadParam(); rparam.setSourceRegion(new Rectangle(1, 1, 300, 500)); rparam.setSourceSubsampling(1, 2, 0, 0); ImageReader reader = new GeoTiffImageReaderSpi().createReaderInstance(); reader.setInput(inputFile); final IIOMetadata metadata = reader.getImageMetadata(0); final ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead"); pbjImageRead.setParameter("Input", inputFile); pbjImageRead.setParameter("reader", reader); pbjImageRead.setParameter("readParam", rparam); final ImageLayout l = new ImageLayout(); l.setTileGridXOffset(0).setTileGridYOffset(0).setTileHeight(256).setTileWidth(256); RenderedOp image = JAI.create("ImageRead", pbjImageRead, new RenderingHints(JAI.KEY_IMAGE_LAYOUT, l)); if (TestData.isInteractiveTest()) Viewer.visualizeAllInformation(image, "geotiff"); // //////////////////////////////////////////////////////////////// // preparing to write // //////////////////////////////////////////////////////////////// final ParameterBlockJAI pbjImageWrite = new ParameterBlockJAI("ImageWrite"); ImageWriter writer = new GeoTiffImageWriterSpi().createWriterInstance(); pbjImageWrite.setParameter("Output", outputFile); pbjImageWrite.setParameter("writer", writer); pbjImageWrite.setParameter("ImageMetadata", metadata); pbjImageWrite.setParameter("Transcode", false); ImageWriteParam param = new ImageWriteParam(Locale.getDefault()); param.setSourceRegion(new Rectangle(10, 10, 100, 100)); param.setSourceSubsampling(2, 1, 0, 0); pbjImageWrite.setParameter("writeParam", param); pbjImageWrite.addSource(image); final RenderedOp op = JAI.create("ImageWrite", pbjImageWrite); final ImageWriter writer2 = (ImageWriter) op.getProperty(ImageWriteDescriptor.PROPERTY_NAME_IMAGE_WRITER); writer2.dispose(); // //////////////////////////////////////////////////////////////// // preparing to read again // //////////////////////////////////////////////////////////////// final ParameterBlockJAI pbjImageReRead = new ParameterBlockJAI("ImageRead"); pbjImageReRead.setParameter("Input", outputFile); pbjImageReRead.setParameter("Reader", new GeoTiffImageReaderSpi().createReaderInstance()); final RenderedOp image2 = JAI.create("ImageRead", pbjImageReRead); if (TestData.isInteractiveTest()) Viewer.visualizeAllInformation(image2, "geotif2"); else Assert.assertNotNull(image2.getTiles()); }
/** * Executes the raster to vector process. * * @param coverage the input grid coverage * @param band the coverage band to process; defaults to 0 if {@code null} * @param insideEdges whether boundaries between raster regions with data values (ie. not NODATA) * should be returned; defaults to {@code true} if {@code null} * @param roi optional polygonal {@code Geometry} to define a sub-area within which vectorizing * will be done * @param noDataValues optional list of values to treat as NODATA; regions with these values will * not be represented in the returned features; if {@code null}, 0 is used as the single * NODATA value; ignored if {@code classificationRanges} is provided * @param classificationRanges optional list of {@code Range} objects to pre-classify the input * coverage prior to vectorizing; values not included in the list will be treated as NODATA; * values in the first {@code Range} are classified to 1, those in the second {@code Range} to * 2 etc. * @param progressListener an optional listener * @return a feature collection where each feature has a {@code Polygon} ("the_geom") and an * attribute "value" with value of the corresponding region in either {@code coverage} or the * classified coverage (when {@code classificationRanges} is used) * @throws ProcessException */ @DescribeResult(name = "result", description = "The polygon feature collection") public SimpleFeatureCollection execute( @DescribeParameter(name = "data", description = "The raster to be used as the source") GridCoverage2D coverage, @DescribeParameter( name = "band", description = "(Integer, default=0) the source image band to process", min = 0) Integer band, @DescribeParameter( name = "insideEdges", description = "(Boolean, default=true) whether to vectorize boundaries between adjacent regions with non-outside values", min = 0) Boolean insideEdges, @DescribeParameter( name = "roi", description = "The geometry used to delineate the area of interest in model space", min = 0) Geometry roi, @DescribeParameter( name = "nodata", description = "Collection<Number>, default={0}) values to treat as NODATA", collectionType = Number.class, min = 0) Collection<Number> noDataValues, @DescribeParameter( name = "ranges", description = "The list of ranges to be applied. \n" + "Each range is expressed as 'OPEN START ; END CLOSE'\n" + "where 'OPEN:=(|[, CLOSE=)|]',\n " + "START is the low value, or nothing to imply -INF,\n" + "CLOSE is the biggest value, or nothing to imply +INF", collectionType = Range.class, min = 0) List<Range> classificationRanges, ProgressListener progressListener) throws ProcessException { // // initial checks // if (coverage == null) { throw new ProcessException("Invalid input, source grid coverage should be not null"); } if (band == null) { band = 0; } else if (band < 0 || band >= coverage.getNumSampleDimensions()) { throw new ProcessException("Invalid input, invalid band number:" + band); } // do we have classification ranges? boolean hasClassificationRanges = classificationRanges != null && classificationRanges.size() > 0; // apply the classification by setting 0 as the default value and using 1, ..., numClasses for // the other classes. // we use 0 also as the noData for the resulting coverage. if (hasClassificationRanges) { final RangeLookupProcess lookup = new RangeLookupProcess(); coverage = lookup.execute(coverage, band, classificationRanges, progressListener); } // Use noDataValues to set the "outsideValues" parameter of the Vectorize // operation unless classificationRanges are in use, in which case the // noDataValues arg is ignored. List<Number> outsideValues = new ArrayList<Number>(); if (noDataValues != null && !hasClassificationRanges) { outsideValues.addAll(noDataValues); } else { outsideValues.add(0); } // // GRID TO WORLD preparation // final AffineTransform mt2D = (AffineTransform) coverage.getGridGeometry().getGridToCRS2D(PixelOrientation.UPPER_LEFT); // get the rendered image final RenderedImage raster = coverage.getRenderedImage(); // perform jai operation ParameterBlockJAI pb = new ParameterBlockJAI("Vectorize"); pb.setSource("source0", raster); if (roi != null) { pb.setParameter("roi", CoverageUtilities.prepareROI(roi, mt2D)); } pb.setParameter("band", band); pb.setParameter("outsideValues", outsideValues); if (insideEdges != null) { pb.setParameter("insideEdges", insideEdges); } // pb.setParameter("removeCollinear", false); final RenderedOp dest = JAI.create("Vectorize", pb); @SuppressWarnings("unchecked") final Collection<Polygon> prop = (Collection<Polygon>) dest.getProperty(VectorizeDescriptor.VECTOR_PROPERTY_NAME); // wrap as a feature collection and return final SimpleFeatureType featureType = CoverageUtilities.createFeatureType(coverage, Polygon.class); final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType); int i = 0; final ListFeatureCollection featureCollection = new ListFeatureCollection(featureType); final AffineTransformation jtsTransformation = new AffineTransformation( mt2D.getScaleX(), mt2D.getShearX(), mt2D.getTranslateX(), mt2D.getShearY(), mt2D.getScaleY(), mt2D.getTranslateY()); for (Polygon polygon : prop) { // get value Double value = (Double) polygon.getUserData(); polygon.setUserData(null); // filter coordinates in place polygon.apply(jtsTransformation); // create feature and add to list builder.set("the_geom", polygon); builder.set("value", value); featureCollection.add(builder.buildFeature(String.valueOf(i++))); } // return value return featureCollection; }
@DescribeResult(name = "result", description = "The contours feature collection") public SimpleFeatureCollection execute( @DescribeParameter(name = "data", description = "The raster to be used as the source") GridCoverage2D gc2d, @DescribeParameter( name = "band", description = "The source image band to process", min = 0, max = 1) Integer band, @DescribeParameter(name = "levels", description = "Values for which to generate contours") double[] levels, @DescribeParameter( name = "interval", description = "Interval between contour values (ignored if levels arg is supplied)", min = 0) Double interval, @DescribeParameter( name = "simplify", description = "Values for which to generate contours", min = 0) Boolean simplify, @DescribeParameter( name = "smooth", description = "Values for which to generate contours", min = 0) Boolean smooth, @DescribeParameter( name = "roi", description = "The geometry used to delineate the area of interest in model space", min = 0) Geometry roi, ProgressListener progressListener) throws ProcessException { // // initial checks // if (gc2d == null) { throw new ProcessException("Invalid input, source grid coverage should be not null"); } if (band != null && (band < 0 || band >= gc2d.getNumSampleDimensions())) { throw new ProcessException("Invalid input, invalid band number:" + band); } boolean hasValues = !(levels == null || levels.length == 0); if (!hasValues && interval == null) { throw new ProcessException("One between interval and values must be valid"); } // switch to geophisics if necessary gc2d = gc2d.view(ViewType.GEOPHYSICS); // // GRID TO WORLD preparation // final AffineTransform mt2D = (AffineTransform) gc2d.getGridGeometry().getGridToCRS2D(PixelOrientation.CENTER); // get the list of nodata, if any List<Object> noDataList = new ArrayList<Object>(); for (GridSampleDimension sd : gc2d.getSampleDimensions()) { // grab all the explicit nodata final double[] sdNoData = sd.getNoDataValues(); if (sdNoData != null) { for (double nodata : sdNoData) { noDataList.add(nodata); } } // handle also readers setting up nodata in a category with a specific name if (sd.getCategories() != null) { for (Category cat : sd.getCategories()) { if (cat.getName().equals(NO_DATA)) { final NumberRange<? extends Number> catRange = cat.getRange(); if (catRange.getMinimum() == catRange.getMaximum()) { noDataList.add(catRange.getMinimum()); } else { Range<Double> noData = new Range<Double>( catRange.getMinimum(), catRange.isMinIncluded(), catRange.getMaximum(), catRange.isMaxIncluded()); noDataList.add(noData); } } } } } // get the rendered image final RenderedImage raster = gc2d.getRenderedImage(); // perform jai operation ParameterBlockJAI pb = new ParameterBlockJAI("Contour"); pb.setSource("source0", raster); if (roi != null) { pb.setParameter("roi", CoverageUtilities.prepareROI(roi, mt2D)); } if (band != null) { pb.setParameter("band", band); } if (interval != null) { pb.setParameter("interval", interval); } else { final ArrayList<Double> elements = new ArrayList<Double>(levels.length); for (double level : levels) elements.add(level); pb.setParameter("levels", elements); } if (simplify != null) { pb.setParameter("simplify", simplify); } if (smooth != null) { pb.setParameter("smooth", smooth); } if (noDataList != null) { pb.setParameter("nodata", noDataList); } final RenderedOp dest = JAI.create("Contour", pb); @SuppressWarnings("unchecked") final Collection<LineString> prop = (Collection<LineString>) dest.getProperty(ContourDescriptor.CONTOUR_PROPERTY_NAME); // wrap as a feature collection and return final SimpleFeatureType schema = CoverageUtilities.createFeatureType(gc2d, LineString.class); final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema); int i = 0; final ListFeatureCollection featureCollection = new ListFeatureCollection(schema); final AffineTransformation jtsTransformation = new AffineTransformation( mt2D.getScaleX(), mt2D.getShearX(), mt2D.getTranslateX(), mt2D.getShearY(), mt2D.getScaleY(), mt2D.getTranslateY()); for (LineString line : prop) { // get value Double value = (Double) line.getUserData(); line.setUserData(null); // filter coordinates in place line.apply(jtsTransformation); // create feature and add to list builder.set("the_geom", line); builder.set("value", value); featureCollection.add(builder.buildFeature(String.valueOf(i++))); } // return value return featureCollection; }
/** * 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; }