/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2010, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.display2d; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.storage.DataStoreException; import org.geotoolkit.storage.coverage.PyramidCoverageBuilder; import org.geotoolkit.coverage.grid.GridCoverage2D; import org.geotoolkit.coverage.grid.GridCoverageBuilder; import org.geotoolkit.coverage.io.CoverageIO; import org.geotoolkit.coverage.io.CoverageStoreException; import org.geotoolkit.coverage.io.GridCoverageReader; import org.geotoolkit.coverage.memory.MPCoverageStore; import org.geotoolkit.display.PortrayalException; import org.geotoolkit.display2d.service.CanvasDef; import org.geotoolkit.display2d.service.DefaultPortrayalService; import org.geotoolkit.display2d.service.SceneDef; import org.geotoolkit.display2d.service.ViewDef; import org.geotoolkit.factory.Hints; import org.geotoolkit.util.NamesExt; import org.geotoolkit.image.interpolation.InterpolationCase; import org.geotoolkit.image.iterator.PixelIterator; import org.geotoolkit.image.iterator.PixelIteratorFactory; import org.geotoolkit.lang.Setup; import org.geotoolkit.map.CoverageMapLayer; import org.geotoolkit.map.MapBuilder; import org.geotoolkit.map.MapContext; import org.geotoolkit.referencing.crs.PredefinedCRS; import org.apache.sis.referencing.CommonCRS; import org.geotoolkit.image.io.large.ImageCacheConfiguration; import org.geotoolkit.style.DefaultStyleFactory; import org.geotoolkit.style.MutableStyleFactory; import org.geotoolkit.style.StyleConstants; import org.junit.Test; import org.opengis.referencing.crs.CoordinateReferenceSystem; import static org.junit.Assert.assertTrue; import org.opengis.util.GenericName; import org.opengis.geometry.Envelope; import org.opengis.referencing.operation.TransformException; import org.opengis.util.FactoryException; /** * Test between output image from renderer and images from some differents storing source. * * @author Remi Marechal (Geomatys). */ public class CoverageImageTest extends org.geotoolkit.test.TestBase { public static final MutableStyleFactory SF = new DefaultStyleFactory(); private static final double EPSILON = 1E-9; final CanvasDef cdef = new CanvasDef(); final ViewDef vdef = new ViewDef(); final SceneDef sdef = new SceneDef(); final Dimension outputImgDim = new Dimension(); int proportionalityCoefficient; Envelope resEnv; Hints hints; int srcWidth; int srcHeight; /** * Create an appropriate test image. * * @param width output image width. * @param height output image height. * @return an appropriate test image. */ private BufferedImage createImage(int width, int height) { final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); g2d.setColor(Color.red); g2d.fillRect(0, 0, width, height); return img; } /** * Create and return a {@link GridCoverage2D} from image, {@link CoordinateReferenceSystem} * and double table values which represent geographic envelope in {@link CoordinateReferenceSystem} units. * * @param image coverage image. * @param crs coverage {@link CoordinateReferenceSystem} * @param ordinates coverage envelope ordinate values.(xmin, ymin, ... xmax, ymax ...) * @return {@link GridCoverage2D} from image, {@link CoordinateReferenceSystem} * and double table values which represent geographic envelope in {@link CoordinateReferenceSystem} units. */ private GridCoverage2D createCoverage(RenderedImage image, CoordinateReferenceSystem crs, double...ordinates) { final GridCoverageBuilder gcb = new GridCoverageBuilder(); gcb.setCoordinateReferenceSystem(crs); gcb.setRenderedImage(image); gcb.setEnvelope(ordinates); return gcb.getGridCoverage2D(); } /** * Compare {@link RenderedImage} from expected {@link RenderedImage} and a proportionality coefficient. * * @param sourceImage tested Image. * @param resultImage expected image. * @param proportionalityCoefficient resample coefficient. */ private void checkImage(RenderedImage sourceImage, BufferedImage resultImage, int proportionalityCoefficient) { final int numband = sourceImage.getSampleModel().getNumBands(); final int srcMinX = sourceImage.getMinX(); final int srcMinY = sourceImage.getMinY(); assertTrue(numband == resultImage.getSampleModel().getNumBands()); final PixelIterator srcPix = PixelIteratorFactory.createRowMajorIterator(sourceImage); final PixelIterator destPix = PixelIteratorFactory.createRowMajorIterator(resultImage); assertTrue(Math.abs(resultImage.getWidth() - sourceImage.getWidth() * proportionalityCoefficient) <= EPSILON); assertTrue(Math.abs(resultImage.getHeight() - sourceImage.getHeight() * proportionalityCoefficient) <= EPSILON); int b = 0; while (srcPix.next()) { final double srcValue = srcPix.getSampleDouble(); final int srcX = srcPix.getX() - srcMinX; final int srcY = srcPix.getY() - srcMinY; final int destX = proportionalityCoefficient * srcX; final int destY = proportionalityCoefficient * srcY; for(int dy = destY; dy < destY + proportionalityCoefficient; dy++) { for(int dx = destX; dx < destX + proportionalityCoefficient; dx++) { destPix.moveTo(dx, dy, b); assertTrue(Math.abs(srcValue-destPix.getSampleDouble()) <= EPSILON); } } if (++b == numband) b = 0; } } /** * Compute and compare result image from {@link MapContext} build with {@link CoverageMapLayer}, * and sourceImage. * * @param sourceImage expected image will be tested. * @param cml {@link CoverageMapLayer} use to build {@link MapContext}. * @throws PortrayalException */ private void testImageLayer(RenderedImage sourceImage, CoverageMapLayer cml) throws PortrayalException{ //create a mapcontext final MapContext context = MapBuilder.createContext(); context.layers().add(cml); outputImgDim.setSize(proportionalityCoefficient * srcWidth, proportionalityCoefficient * srcHeight); hints = new Hints(GO2Hints.KEY_COLOR_MODEL, sourceImage.getColorModel(), RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); cdef.setDimension(outputImgDim); sdef.setContext(context); sdef.setHints(hints); vdef.setEnvelope(resEnv); final BufferedImage imgResult = DefaultPortrayalService.portray(cdef, sdef, vdef); checkImage(sourceImage, imgResult, proportionalityCoefficient); } /** * <p>Test between output image from renderer and source image within pyramidal model.<br/> * Note : PyramidalModel use for this test is a "MemoryCoverageStore" which store all raster in memory.</p> * * @throws PortrayalException * @throws DataStoreException * @throws TransformException * @throws FactoryException */ @Test public void pyramidtest() throws PortrayalException, DataStoreException, TransformException, FactoryException, IOException { ImageIO.scanForPlugins(); Setup.initialize(null); ImageCacheConfiguration.setCacheSwapEnable(false); final File input = new File("src/test/resources/org/geotoolkit/display2d/clouds.jpg"); final GridCoverageReader reader = CoverageIO.createSimpleReader(input); final MPCoverageStore mpCovStore = new MPCoverageStore(); final PyramidCoverageBuilder pcb = new PyramidCoverageBuilder(new Dimension(25, 25), InterpolationCase.NEIGHBOR, 2); final double[] fillValue = new double[3]; final GeneralEnvelope env = new GeneralEnvelope(CommonCRS.WGS84.normalizedGeographic()); env.setEnvelope(-180, -90, 180, 90); final double[] scales = new double[]{1.40625, 2.8125}; final Map<Envelope, double[]> map = new HashMap<>(); map.put(env, scales); final GenericName name = NamesExt.create("memory_store_test"); pcb.create(reader, mpCovStore, name, map, fillValue); final GridCoverage2D gridcov = (GridCoverage2D) reader.read(0, null); final RenderedImage img = gridcov.getRenderedImage(); srcWidth = img.getWidth(); srcHeight = img.getHeight(); //Envelope result resEnv = gridcov.getEnvelope(); proportionalityCoefficient = 2; final CoverageMapLayer cl = MapBuilder.createCoverageLayer(mpCovStore.getCoverageReference(name)); testImageLayer(img, cl); proportionalityCoefficient = 1; testImageLayer(img, cl); } /** * Test between output image from renderer and source image within {@link GridCoverage2D}. * * @throws PortrayalException */ @Test public void coverage2DTest() throws PortrayalException { final BufferedImage img = createImage(180, 90); final CoordinateReferenceSystem crs = PredefinedCRS.CARTESIAN_2D; final double[] envelope = new double[]{-180, -90, 180, 90}; final GridCoverage2D gc2D = createCoverage(img, crs, envelope); final CoverageMapLayer cl = MapBuilder.createCoverageLayer(gc2D, SF.style(StyleConstants.DEFAULT_RASTER_SYMBOLIZER), "raster"); //Envelope result GeneralEnvelope resuEnv = new GeneralEnvelope(crs); resuEnv.setEnvelope(envelope); resEnv = resuEnv; proportionalityCoefficient = 2; srcWidth = 180; srcHeight = 90; testImageLayer(img, cl); } /** * Test between output image from renderer and source image within {@link GridCoverageReader}. * * @throws PortrayalException * @throws CoverageStoreException * @throws IOException */ @Test public void coverageReaderTest() throws PortrayalException, CoverageStoreException, IOException { ImageIO.scanForPlugins(); Setup.initialize(null); final File input = new File("src/test/resources/org/geotoolkit/display2d/clouds.jpg"); final GridCoverageReader reader = CoverageIO.createSimpleReader(input); final BufferedImage img = ImageIO.read(input); final GridCoverage2D gridcov = (GridCoverage2D) reader.read(0, null); proportionalityCoefficient = 2; final CoverageMapLayer cl = MapBuilder.createCoverageLayer(input); //Envelope result resEnv = gridcov.getEnvelope(); srcWidth = img.getWidth(); srcHeight = img.getHeight(); testImageLayer(img, cl); } }