/** * 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()); }
/** * 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 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()); }
/** * 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; }