Author: desruisseaux Date: Tue Aug 8 11:15:52 2017 New Revision: 1804399 URL: http://svn.apache.org/viewvc?rev=1804399&view=rev Log: Add tests for WritablePixelIterator.
Added: sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java - copied, changed from r1804398, sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java Removed: sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java?rev=1804399&r1=1804398&r2=1804399&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java [UTF-8] Tue Aug 8 11:15:52 2017 @@ -279,6 +279,18 @@ public abstract class PixelIterator { } /** + * Returns {@code true} if this iterator can write pixel values (after cast to {@code WritablePixelIterator}). + * This method should be used instead than {@code instanceof} check because, for some implementations, being + * an instance of {@code WritablePixelIterator} is not a sufficient condition. + * + * @return {@code true} if this iterator can safely be casted to {@link WritablePixelIterator} and used for + * writing pixel values. + */ + public boolean isWritable() { + return false; + } + + /** * Returns the most efficient type ({@code int}, {@code float} or {@code double}) for transferring data between the * underlying rasters and this iterator. The transfer type is not necessarily the storage type used by the rasters. * For example {@code int} values will be used for transferring data even if the underlying rasters store all sample Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java?rev=1804399&r1=1804398&r2=1804399&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java [UTF-8] Tue Aug 8 11:15:52 2017 @@ -32,9 +32,11 @@ import org.apache.sis.util.ArgumentCheck /** * A pixel iterator capable to write sample values. This iterator can edit pixel values in place, * or write values in a different destination image than the source image. Source and destination - * images must use the same sample model, + * images must use the same sample model and the same coordinates (both for pixels and tiles). + * + * <p>Contrarily to {@code PixelIterator}, {@code WritablePixelIterator} needs to be closed after + * iteration in order to release tiles. Example:</p> * - * <p>Usage example:</p> * {@preformat java * try (WritablePixelIterator it = WritablePixelIterator.create(image)) { * double[] samples = null; @@ -46,6 +48,10 @@ import org.apache.sis.util.ArgumentCheck * } * } * + * <div class="section">Casting a {@code PixelIterator}</div> + * To check if a {@code PixelIterator} can be used for writing pixels, a {@code … instanceof WritablePixelIterator} + * check is not sufficient. The {@link PixelIterator#isWritable()} method should be invoked instead. + * * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) * @version 0.8 @@ -213,6 +219,19 @@ public abstract class WritablePixelItera } /** + * Returns {@code true} if this iterator can write pixel values. + * This method should be used instead than {@code instanceof} check because, for some implementations, being an + * instance of {@code WritablePixelIterator} is not a sufficient condition. However this method is guaranteed to + * return {@code true} for any iterator created by {@code WritablePixelIterator.create(…)} methods. + * + * @return {@code true} if this iterator can be used for writing pixel values. + */ + @Override + public boolean isWritable() { + return (destination != null) || (destRaster != null); + } + + /** * Writes a sample value in the specified band of current pixel. * The {@link #next()} method must have returned {@code true}, or the {@link #moveTo(int,int)} method must have * been invoked successfully, before this {@code setSample(int, int)} method is invoked. If above condition is Copied: sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java (from r1804398, sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java) URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java?p2=sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java&p1=sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java&r1=1804398&r2=1804399&rev=1804399&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java [UTF-8] Tue Aug 8 11:15:52 2017 @@ -28,14 +28,16 @@ import java.nio.FloatBuffer; import org.opengis.coverage.grid.SequenceType; import org.apache.sis.test.DependsOnMethod; import org.apache.sis.test.TestCase; +import org.junit.After; import org.junit.Test; import static org.junit.Assert.*; /** - * Base class of {@link PixelIterator} tests. This base class tests the default read-only iterator - * on signed short integer values. Subclasses will test variants, for example the read-write iterator. + * Base class of {@link PixelIterator} tests. This base class tests the default read-write iterator + * on signed short integer values. Subclasses will test variants, for example optimized iterators + * for some specific sample models. * * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) @@ -43,12 +45,12 @@ import static org.junit.Assert.*; * @since 0.8 * @module */ -public strictfp class PixelIteratorTest extends TestCase { +public strictfp class DefaultIteratorTest extends TestCase { /** * The pixel iterator being tested. * This field is initialized by a call to one of the {@code createPixelIterator(…)} methods. */ - private PixelIterator iterator; + private WritablePixelIterator iterator; /** * The raster or image data type as one of the {@link DataBuffer} constants. @@ -104,18 +106,23 @@ public strictfp class PixelIteratorTest private float[] expected; /** + * {@code true} for testing write operations in addition of read operations. + */ + private boolean isWritable; + + /** * Creates a new test case for the given data type. * * @param dataType the raster or image data type as one of the {@link DataBuffer} constants. */ - PixelIteratorTest(final int dataType) { + DefaultIteratorTest(final int dataType) { this.dataType = dataType; } /** * Creates a new test case. */ - public PixelIteratorTest() { + public DefaultIteratorTest() { this(DataBuffer.TYPE_SHORT); } @@ -240,50 +247,62 @@ public strictfp class PixelIteratorTest * Creates a {@code PixelIterator} for a sub-area of given raster. * The iterator shall be assigned to the {@link #iterator} field. * - * <p>The default implementation creates read-only iterators. - * Tests for read-write iterators need to override.</p> + * <p>The default implementation creates {@link DefaultIterator} instances. + * Tests for other kinds of iterator need to override.</p> * * @param raster the data on which to perform iteration. * @param subArea the boundary of the raster sub-area where to perform iteration. */ void createPixelIterator(WritableRaster raster, Rectangle subArea) { - iterator = new DefaultIterator(raster, null, subArea, null); + iterator = new DefaultIterator(raster, isWritable ? raster : null, subArea, null); assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder()); + assertEquals("isWritable", isWritable, iterator.isWritable()); } /** * Creates a {@code PixelIterator} for a sub-area of given image. * The iterator shall be assigned to the {@link #iterator} field. * - * <p>The default implementation creates read-only iterators. - * Tests for read-write iterators need to override.</p> + * <p>The default implementation creates {@link DefaultIterator} instances. + * Tests for other kinds of iterator need to override.</p> * * @param image the data on which to perform iteration. * @param subArea the boundary of the image sub-area where to perform iteration. */ void createPixelIterator(WritableRenderedImage image, Rectangle subArea) { - iterator = new DefaultIterator(image, null, subArea, null); + iterator = new DefaultIterator(image, isWritable ? image : null, subArea, null); + assertEquals("isWritable", isWritable, iterator.isWritable()); } /** * Creates a {@code PixelIterator} for a window in the given image. * The iterator shall be assigned to the {@link #iterator} field. * - * <p>The default implementation creates read-only iterators. - * Tests for read-write iterators need to override.</p> + * <p>The default implementation creates {@link DefaultIterator} instances. + * Tests for other kinds of iterator need to override.</p> * * @param image the data on which to perform iteration. * @param window size of the window to use in {@link PixelIterator#createWindow(TransferType)} method. */ void createWindowIterator(WritableRenderedImage image, Dimension window) { - iterator = new DefaultIterator(image, null, null, window); + iterator = new DefaultIterator(image, isWritable ? image : null, null, window); + assertEquals("isWritable", isWritable, iterator.isWritable()); + } + + /** + * Invoked after every tests for releasing resources. + */ + @After + public void dispose() { + iterator.close(); } /** * Verifies the sample value at current iterator position. + * If the iterator is writable, tests also setting a value. * - * @param i index in {@link #expected} array. - * @param b band number at current iterator position. + * @param i index in {@link #expected} array. + * @param b band number at current iterator position. */ private void verifySample(final int i, final int b) { final float e = expected[i]; @@ -291,13 +310,19 @@ public strictfp class PixelIteratorTest if (Float.floatToRawIntBits(a) != Float.floatToRawIntBits(e)) { fail("Pixel iteration at index " + i + ": expected " + e + " but got " + a); } + if (isWritable) { + final float newValue = a + 20; + iterator.setSample(b, newValue); + assertEquals("Verification after write", newValue, iterator.getSampleFloat(b), 0f); + expected[i] = newValue; + } } /** * Iterates over all values returned by the current {@link #iterator} and compares with expected values. * - * @param verifyIndices whether to verify also iterator {@code getPosition()} return values. - * This is usually {@code true} if an only if the iterator cover the full raster area. + * @param verifyIndices whether to verify also iterator {@code getPosition()} return values. + * This is usually {@code true} if an only if the iterator cover the full raster area. * * @see #verifyIterationAfterMove(int, int) * @see #verifyWindow(Dimension) @@ -1091,4 +1116,37 @@ public strictfp class PixelIteratorTest assertNull("getIterationOrder()", iterator.getIterationOrder()); verifyWindow(window); } + + /** + * Tests write operations in a single raster. + * The destination image is the same than the source image. + */ + @Test + @DependsOnMethod("testOnRasterSubArea") + public void testOnWritableRaster() { + isWritable = true; + testOnRasterSubArea(); + } + + /** + * Tests write operations in a single tile of an image. + * The destination image is the same than the source image. + */ + @Test + @DependsOnMethod({"testOnWritableRaster", "testOnTileSubArea"}) + public void testOnWritableTile() { + isWritable = true; + testOnTileSubArea(); + } + + /** + * Tests write operations in a tiled image. + * The destination image is the same than the source image. + */ + @Test + @DependsOnMethod({"testOnWritableTile", "testOnImageSubArea"}) + public void testOnWritableImage() { + isWritable = true; + testOnImageSubArea(); + } } Modified: sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java?rev=1804399&r1=1804398&r2=1804399&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java [UTF-8] Tue Aug 8 11:15:52 2017 @@ -29,6 +29,8 @@ import java.awt.image.WritableRaster; import java.awt.image.WritableRenderedImage; import java.util.Vector; +import static org.junit.Assert.*; + /** * A rendered image which can contain an arbitrary number of tiles. Tiles are stored in memory. @@ -79,6 +81,16 @@ final class TiledImage implements Writab private final SampleModel sampleModel; /** + * Indices of acquired tiles. Those indices are valid only if {@link #isTileAcquired} is {@code true}. + */ + private int acquiredTileX, acquiredTileY; + + /** + * Whether a tile has been acquired by a call to {@link #getWritableTile(int, int)} and not yet released. + */ + private boolean isTileAcquired; + + /** * Creates a new tiled image. * * @param dataType sample data type as one of the {@link java.awt.image.DataBuffer} constants. @@ -152,23 +164,41 @@ final class TiledImage implements Writab if (ox < 0 || ox >= width || oy < 0 || oy >= height) { throw new IndexOutOfBoundsException(); } - getWritableTile(ox / tileWidth + minTileX, - oy / tileHeight + minTileY).setSample(x, y, b, value); + tile(ox / tileWidth + minTileX, + oy / tileHeight + minTileY).setSample(x, y, b, value); } /** * Returns the tile at the given location in tile coordinates. + * This method verifies that no writable raster have been acquired. Actually this conditions is not part of + * {@link WritableRenderedImage} contract, since a readable and writable rasters can be used in same time. + * But we add this condition because they way {@link PixelIterator} are currently implemented, it would be + * a bug if we ask for a readable tile while we already have a writable one. This condition may change in + * any future Apache SIS version. */ @Override public Raster getTile(final int tileX, final int tileY) { - return getWritableTile(tileX, tileY); + assertFalse("isTileAcquired", isTileAcquired); // See javadoc. + return tile(tileX, tileY); } /** * Returns the tile at the given location tile coordinates. */ @Override - public WritableRaster getWritableTile(int tileX, int tileY) { + public WritableRaster getWritableTile(final int tileX, final int tileY) { + assertFalse("isTileAcquired", isTileAcquired); + isTileAcquired = true; + acquiredTileX = tileX; + acquiredTileY = tileY; + return tile(tileX, tileY); + } + + /** + * Returns the tile at the given index without any verification. It is caller responsibility to verify if this + * method is invoked in a consistent context (for example after a writable raster has been properly acquired). + */ + private WritableRaster tile(int tileX, int tileY) { if ((tileX -= minTileX) < 0 || tileX >= numXTiles || (tileY -= minTileY) < 0 || tileY >= numYTiles) { @@ -185,19 +215,23 @@ final class TiledImage implements Writab } /** - * Ignored since this implementation does not need to be informed - * about when the user is doing with the {@link WritableRaster}. + * Verifies that the given tile has been acquired. */ @Override - public void releaseWritableTile(int tileX, int tileY) { + public void releaseWritableTile(final int tileX, final int tileY) { + assertTrue("isTileAcquired", isTileAcquired); + assertEquals("tileX", acquiredTileX, tileX); + assertEquals("tileY", acquiredTileY, tileY); + isTileAcquired = false; } /** - * Returns {@code false} since we do not keep track of who called {@link #getWritableTile(int,int)}. + * Returns {@code true} if the given tile indices are the one given to the last call to + * {@link #getWritableTile(int, int)} and that tile has not yet been released. */ @Override - public boolean isTileWritable(int tileX, int tileY) { - return false; + public boolean isTileWritable(final int tileX, final int tileY) { + return isTileAcquired && (tileX == acquiredTileX) && (tileY == acquiredTileY); } /** @@ -205,15 +239,15 @@ final class TiledImage implements Writab */ @Override public boolean hasTileWriters() { - return false; + return isTileAcquired; } /** - * Returns {@code null} since we do not keep track of who called {@link #getWritableTile(int,int)}. + * Returns the indices of acquired tile, or {@code null} if none. */ @Override public Point[] getWritableTileIndices() { - return null; + return isTileAcquired ? new Point[] {new Point(acquiredTileX, acquiredTileY)} : null; } /** Modified: sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java?rev=1804399&r1=1804398&r2=1804399&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java [UTF-8] Tue Aug 8 11:15:52 2017 @@ -30,7 +30,7 @@ import org.junit.BeforeClass; * @module */ @Suite.SuiteClasses({ - org.apache.sis.image.PixelIteratorTest.class + org.apache.sis.image.DefaultIteratorTest.class }) public final strictfp class RasterTestSuite extends TestSuite { /**