You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2025/01/22 10:22:37 UTC
(sis) 03/05: Move `ReshapedImage` to an internal package for reuse by other modules, and add a constructor for creating a translated image. It will be needed for work on aggregation in later commit.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit cd3eb5eaf8377414343ef631a09db3c3a1531987
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jan 22 11:07:46 2025 +0100
Move `ReshapedImage` to an internal package for reuse by other modules, and add a constructor for creating a translated image.
It will be needed for work on aggregation in later commit.
---
.../sis/coverage/grid/BufferedGridCoverage.java | 4 +-
.../apache/sis/coverage/grid/GridCoverage2D.java | 23 +++++-----
.../grid => image/privy}/ReshapedImage.java | 51 +++++++++++++++++-----
.../coverage/grid/ResampledGridCoverageTest.java | 1 +
.../grid => image/privy}/ReshapedImageTest.java | 12 ++---
5 files changed, 60 insertions(+), 31 deletions(-)
diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
index 098515b9c8..e4105667ea 100644
--- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
+++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
@@ -166,7 +166,7 @@ public class BufferedGridCoverage extends GridCoverage {
final long expectedSize = getSampleCount(extent, numBands);
final long bufferSize = Math.multiplyFull(data.getSize(), numBanks);
if (bufferSize < expectedSize) {
- final StringBuilder b = new StringBuilder();
+ final var b = new StringBuilder();
for (int i=0; i < extent.getDimension(); i++) {
if (i != 0) b.append(" × ");
b.append(extent.getSize(i));
@@ -254,7 +254,7 @@ public class BufferedGridCoverage extends GridCoverage {
}
try {
return cachedRenderings.computeIfAbsent(sliceExtent, (slice) -> {
- ImageRenderer renderer = new ImageRenderer(this, slice);
+ var renderer = new ImageRenderer(this, slice);
renderer.setData(data);
return renderer.createImage();
});
diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
index 90753bb89a..e3bd525acd 100644
--- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
+++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
@@ -45,6 +45,7 @@ import org.opengis.referencing.operation.MathTransform1D;
import org.apache.sis.image.DataType;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.image.privy.ImageUtilities;
+import org.apache.sis.image.privy.ReshapedImage;
import org.apache.sis.feature.internal.Resources;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Debug;
@@ -90,7 +91,7 @@ import org.opengis.coverage.PointOutsideCoverageException;
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
* @author Alexis Manin (Geomatys)
- * @version 1.4
+ * @version 1.5
* @since 1.1
*/
public class GridCoverage2D extends GridCoverage {
@@ -274,7 +275,7 @@ public class GridCoverage2D extends GridCoverage {
*/
private static RenderedImage unwrapIfSameSize(RenderedImage data) {
if (data instanceof ReshapedImage) {
- final RenderedImage source = ((ReshapedImage) data).source;
+ final var source = ((ReshapedImage) data).source;
if (source.getWidth() == data.getWidth() && source.getHeight() == data.getHeight()) {
data = source;
}
@@ -347,8 +348,8 @@ public class GridCoverage2D extends GridCoverage {
* @param crs coordinate reference system, or {@code null} if none.
*/
private static GridExtent createExtent(final int dimension, final Rectangle bounds, final CoordinateReferenceSystem crs) {
- final long[] low = new long[dimension];
- final long[] high = new long[dimension];
+ final var low = new long[dimension];
+ final var high = new long[dimension];
low [0] = bounds.x;
low [1] = bounds.y;
high[0] = bounds.width + low[0] - 1; // Inclusive.
@@ -588,11 +589,11 @@ public class GridCoverage2D extends GridCoverage {
/*
* Convert the coordinates from this grid coverage coordinate system to the image coordinate system.
* The coverage coordinates may require 64 bits integers, but after translation the (x,y) coordinates
- * should be in 32 bits integers range. Do not cast to 32 bits now however; this will be done later.
+ * should be in 32 bits integers range. Do not cast to 32 bits now however, this will be done later.
*/
final long xmin = addExact(sliceExtent.getLow (xDimension), gridToImageX);
final long ymin = addExact(sliceExtent.getLow (yDimension), gridToImageY);
- final long xmax = addExact(sliceExtent.getHigh(xDimension), gridToImageX);
+ final long xmax = addExact(sliceExtent.getHigh(xDimension), gridToImageX); // Inclusive
final long ymax = addExact(sliceExtent.getHigh(yDimension), gridToImageY);
/*
* BufferedImage.getSubimage() returns a new image with upper-left coordinate at (0,0),
@@ -600,7 +601,7 @@ public class GridCoverage2D extends GridCoverage {
* upper-left point is inside the image.
*/
if (data instanceof BufferedImage) {
- BufferedImage result = (BufferedImage) data;
+ var result = (BufferedImage) data;
/*
* BufferedImage origin should be (0, 0). But for consistency with image API,
* we consider it as variable.
@@ -645,7 +646,7 @@ public class GridCoverage2D extends GridCoverage {
* with Raster.createChild(…), but that would force us to invoke RenderedImage.getTile(…) which
* may force data loading earlier than desired.
*/
- final ReshapedImage result = new ReshapedImage(data, xmin, ymin, xmax, ymax);
+ final var result = new ReshapedImage(data, xmin, ymin, xmax, ymax);
return result.isIdentity() ? data : result;
} catch (ArithmeticException e) {
throw new CannotEvaluateException(e.getMessage(), e);
@@ -665,9 +666,9 @@ public class GridCoverage2D extends GridCoverage {
void appendDataLayout(final TreeTable.Node root, final Vocabulary vocabulary, final TableColumn<CharSequence> column) {
final TreeTable.Node branch = root.newChild();
branch.setValue(column, vocabulary.getString(Vocabulary.Keys.ImageLayout));
- final NumberFormat nf = NumberFormat.getIntegerInstance(vocabulary.getLocale());
- final FieldPosition pos = new FieldPosition(0);
- final StringBuffer buffer = new StringBuffer();
+ final var nf = NumberFormat.getIntegerInstance(vocabulary.getLocale());
+ final var pos = new FieldPosition(0);
+ final var buffer = new StringBuffer();
write: for (int item=0; ; item++) try {
switch (item) {
case 0: {
diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/ReshapedImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ReshapedImage.java
similarity index 87%
rename from endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/ReshapedImage.java
rename to endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ReshapedImage.java
index 2091cd364a..f131176aae 100644
--- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/ReshapedImage.java
+++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ReshapedImage.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sis.coverage.grid;
+package org.apache.sis.image.privy;
import java.util.Vector;
import java.util.Objects;
@@ -35,18 +35,18 @@ import org.apache.sis.image.PlanarImage;
/**
* A view over another image with the origin relocated to a new position.
- * Only the pixel coordinates are changed; the tile indices stay the same.
+ * Only the pixel coordinates are changed, the tile indices stay the same.
* However, the image view may expose less tiles than the wrapped image.
* This wrapper does not change image size otherwise than by an integer number of tiles.
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
*/
-final class ReshapedImage extends PlanarImage {
+public final class ReshapedImage extends PlanarImage {
/**
* The image to translate.
*/
- final RenderedImage source;
+ public final RenderedImage source;
/**
* Value to add for converting a column index from the coordinate system of the wrapped image
@@ -79,6 +79,33 @@ final class ReshapedImage extends PlanarImage {
*/
private final int minTileX, minTileY;
+ /**
+ * Creates an image with the data of the given image translated by the given amount.
+ * The number of tiles and their indexes are unchanged.
+ *
+ * @param source the image to translate.
+ * @param tx the translation to apply on <var>x</var> coordinates.
+ * @param ty the translation to apply on <var>y</var> coordinates.
+ * @throws ArithmeticException if image indices would overflow 32-bits integer capacity.
+ */
+ public ReshapedImage(RenderedImage source, long tx, long ty) {
+ while (source instanceof ReshapedImage) {
+ final var r = (ReshapedImage) source;
+ tx = addExact(r.offsetX, tx);
+ ty = addExact(r.offsetY, ty);
+ source = r.source;
+ }
+ this.source = source;
+ offsetX = toIntExact(tx);
+ offsetY = toIntExact(ty);
+ minX = toIntExact(tx + source.getMinX());
+ minY = toIntExact(ty + source.getMinY());
+ width = source.getWidth();
+ height = source.getHeight();
+ minTileX = source.getMinTileX();
+ minTileY = source.getMinTileY();
+ }
+
/**
* Creates a new image with the same data as the given image but located at different coordinates.
* In addition, this constructor can reduce the number of tiles.
@@ -88,9 +115,9 @@ final class ReshapedImage extends PlanarImage {
* @param ymin minimal <var>y</var> coordinate of the requested region, inclusive.
* @param xmax maximal <var>x</var> coordinate of the requested region, inclusive.
* @param ymax maximal <var>y</var> coordinate of the requested region, inclusive.
- * @throws ArithmeticException if image indices would overflow 32 bits integer capacity.
+ * @throws ArithmeticException if image indices would overflow 32-bits integer capacity.
*/
- ReshapedImage(final RenderedImage source, final long xmin, final long ymin, final long xmax, final long ymax) {
+ public ReshapedImage(final RenderedImage source, final long xmin, final long ymin, final long xmax, final long ymax) {
this.source = source;
/*
* Compute indices of all tiles to retain in this image. All local fields are `long` in order to force
@@ -106,14 +133,14 @@ final class ReshapedImage extends PlanarImage {
final long th = source.getTileHeight();
final long xo = source.getTileGridXOffset();
final long yo = source.getTileGridYOffset();
- final long minTX = floorDiv(max(lowerX, xmin) - xo, tw); // Indices of the first tile to retain.
- final long minTY = floorDiv(max(lowerY, ymin) - yo, th);
- final long maxTX = floorDiv(min(upperX, xmax) - xo, tw); // Indices of the last tile to retain (inclusive).
- final long maxTY = floorDiv(min(upperY, ymax) - yo, th);
+ final long minTX = floorDiv(max(xmin, lowerX) - xo, tw); // Indices of the first tile to retain.
+ final long minTY = floorDiv(max(ymin, lowerY) - yo, th);
+ final long maxTX = floorDiv(min(xmax, upperX-1) - xo, tw); // Indices of the last tile to retain (inclusive).
+ final long maxTY = floorDiv(min(ymax, upperY-1) - yo, th);
/*
* Coordinates in source image of the first pixel to show in this relocated image.
* They are the coordinates of the upper-left corner of the first tile to retain,
- * clamped to image bounds if needed. This is not yet coordinates of this image.
+ * clamped to image bounds if needed. This is not yet the coordinates of this image.
*/
final long sx = max(lowerX, minTX * tw + xo);
final long sy = max(lowerY, minTY * th + yo);
@@ -137,7 +164,7 @@ final class ReshapedImage extends PlanarImage {
/**
* Returns {@code true} if this image does not move and does not subset the wrapped image.
*/
- final boolean isIdentity() {
+ public boolean isIdentity() {
// The use of >= is a paranoiac check, but the > case should never happen actually.
return offsetX == 0 && offsetY == 0 && width >= source.getWidth() && height >= source.getHeight();
}
diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
index 7fbf205b5f..f0530b7ddb 100644
--- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
+++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
@@ -37,6 +37,7 @@ import org.apache.sis.geometry.DirectPosition2D;
import org.apache.sis.geometry.ImmutableEnvelope;
import org.apache.sis.image.Interpolation;
import org.apache.sis.image.privy.TiledImage;
+import org.apache.sis.image.privy.ReshapedImage;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.referencing.privy.Formulas;
import org.apache.sis.referencing.privy.AffineTransform2D;
diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ReshapedImageTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ReshapedImageTest.java
similarity index 94%
rename from endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ReshapedImageTest.java
rename to endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ReshapedImageTest.java
index 6bc4c17ba0..c2aa208379 100644
--- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ReshapedImageTest.java
+++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ReshapedImageTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sis.coverage.grid;
+package org.apache.sis.image.privy;
import java.util.Random;
import java.awt.image.DataBuffer;
@@ -145,7 +145,7 @@ public final class ReshapedImageTest extends TestCase {
*/
@Test
public void testMultiTiles() {
- final Random random = TestUtilities.createRandomNumberGenerator(219970242558564L);
+ final Random random = TestUtilities.createRandomNumberGenerator();
final int dataMinX, dataMinY;
dataMinX = random.nextInt(20) - 10;
dataMinY = random.nextInt(20) - 10;
@@ -155,9 +155,9 @@ public final class ReshapedImageTest extends TestCase {
numYTiles = 4;
width = numXTiles * TILE_WIDTH;
height = numYTiles * TILE_HEIGHT;
- final TiledImageMock data = new TiledImageMock(DataBuffer.TYPE_USHORT, 1, dataMinX, dataMinY,
- width, height, TILE_WIDTH, TILE_HEIGHT, minTileX, minTileY,
- random.nextBoolean()); // Banded or interleaved sample model
+ final var data = new TiledImageMock(DataBuffer.TYPE_USHORT, 1, dataMinX, dataMinY,
+ width, height, TILE_WIDTH, TILE_HEIGHT, minTileX, minTileY,
+ random.nextBoolean()); // Banded or interleaved sample model
data.validate();
data.initializeAllTiles(0);
/*
@@ -165,7 +165,7 @@ public final class ReshapedImageTest extends TestCase {
*/
tileXOffset = (minX = 7) - minTileX * TILE_WIDTH;
tileYOffset = (minY = 13) - minTileY * TILE_HEIGHT;
- ReshapedImage image = new ReshapedImage(data, dataMinX - 7, dataMinY - 13, 100, 100);
+ var image = new ReshapedImage(data, dataMinX - 7, dataMinY - 13, 100, 100);
verifyLayout(image);
assertValuesEqual(image.getData(), 0, new int[][] {
{ 100, 101, 102 , 200, 201, 202 , 300, 301, 302 , 400, 401, 402 , 500, 501, 502},