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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 641cbee  Specifies the meaning of RenderedImage.getMinX()/getMinY() 
resulting from a call to GridCoverage.render(…). Throw an exception if the 
given extent is out of bounds. Fix ImageRenderer.setSampleStrid(int) method 
contract.
641cbee is described below

commit 641cbeea81ad2db652033728bf4b0cfbb8603427
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Mar 23 18:12:26 2019 +0100

    Specifies the meaning of RenderedImage.getMinX()/getMinY() resulting from a 
call to GridCoverage.render(…).
    Throw an exception if the given extent is out of bounds. Fix 
ImageRenderer.setSampleStrid(int) method contract.
---
 .../sis/coverage/grid/DisjointExtentException.java |   2 +-
 .../org/apache/sis/coverage/grid/GridCoverage.java |  45 ++++---
 .../apache/sis/coverage/grid/GridDerivation.java   |   2 +
 .../org/apache/sis/coverage/grid/GridExtent.java   |   2 +-
 .../apache/sis/coverage/grid/ImageRenderer.java    | 144 +++++++++++++--------
 .../org/apache/sis/internal/netcdf/Raster.java     |  13 +-
 6 files changed, 130 insertions(+), 78 deletions(-)

diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/DisjointExtentException.java
 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/DisjointExtentException.java
index 9860c05..dbfb587 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/DisjointExtentException.java
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/DisjointExtentException.java
@@ -21,7 +21,7 @@ import org.apache.sis.internal.raster.Resources;
 
 /**
  * Thrown when operations on a {@link GridGeometry} result in an area which
- * do not intersect anymore the {@link GridExtent} of the {@link GridGeometry}.
+ * does not intersect anymore the {@link GridExtent} of the {@link 
GridGeometry}.
  *
  * @author  Johann Sorel (Geomatys)
  * @version 1.0
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
index cd6998c..5a6b2fb 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
@@ -35,7 +35,6 @@ import org.apache.sis.util.Debug;
 
 // Branch-specific imports
 import org.opengis.coverage.CannotEvaluateException;
-import org.opengis.coverage.PointOutsideCoverageException;
 
 
 /**
@@ -133,16 +132,15 @@ public abstract class GridCoverage {
      * <i>(<var>z</var>,<var>t</var>)</i> coordinates of the desired slice. 
Those coordinates are specified in a grid extent
      * where {@linkplain GridExtent#getLow(int) low coordinate} = {@linkplain 
GridExtent#getHigh(int) high coordinate} in the
      * <var>z</var> and <var>t</var> dimensions. The two dimensions of the 
data to be shown (<var>x</var> and <var>y</var>
-     * in our example) shall be the only dimensions with a {@linkplain 
GridExtent#getSize(int) size} greater than 1 cell.
+     * in our example) shall be the only dimensions having a {@linkplain 
GridExtent#getSize(int) size} greater than 1 cell.
      *
      * <p>If the {@code sliceExtent} argument is {@code null}, then the 
default value is
      * <code>{@linkplain #getGridGeometry()}.{@linkplain 
GridGeometry#getExtent() getExtent()}</code>.
      * This means that {@code gridExtent} is optional for two-dimensional grid 
coverages or grid coverages where all dimensions
      * except two have a size of 1 cell. If the grid extent contains more than 
2 dimensions with a size greater than one cell,
-     * then a {@link SubspaceNotSpecifiedException} is thrown. If some {@code 
sliceExtent} coordinates are outside the extent
-     * of this grid coverage, then a {@link PointOutsideCoverageException} is 
thrown.</p>
+     * then a {@link SubspaceNotSpecifiedException} is thrown.</p>
      *
-     * <div class="section">Computing a slice extent from a slice point in 
"real world" coordinates</div>
+     * <div class="note"><p><b>How to compute a slice extent from a slice 
point in "real world" coordinates</b></p>
      * The {@code sliceExtent} is specified to this method as grid indices. If 
the <var>z</var> and <var>t</var> values
      * are not grid indices but are relative to some Coordinate Reference 
System (CRS) instead, then the slice extent can
      * be computed as below. First, a <cite>slice point</cite> containing the 
<var>z</var> and <var>t</var> coordinates
@@ -158,19 +156,34 @@ public abstract class GridCoverage {
      *
      * <blockquote><code>sliceExtent = {@linkplain #getGridGeometry()}.{@link 
GridGeometry#derive()
      * derive()}.{@linkplain GridDerivation#slice(DirectPosition)
-     * slice}(slicePoint).{@linkplain GridDerivation#build() 
build()};</code></blockquote>
+     * slice}(slicePoint).{@linkplain GridDerivation#getIntersection() 
getIntersection()};</code></blockquote>
      *
      * If the {@code slicePoint} CRS is different than this grid coverage CRS 
(except for the number of dimensions),
-     * a coordinate transformation will be applied as needed.
+     * a coordinate transformation will be applied as needed.</div>
+     *
+     * <div class="section">Characteristics of the returned image</div>
+     * Image dimensions <var>x</var> and <var>y</var> map to the first and 
second dimension respectively of
+     * the two-dimensional {@code sliceExtent} {@linkplain 
GridExtent#getSubspaceDimensions(int) subspace}.
+     * The coordinates given by {@link RenderedImage#getMinX()} and {@link 
RenderedImage#getMinY() getMinY()}
+     * will be the image location <em>relative to</em> the location specified 
in {@code sliceExtent}
+     * {@linkplain GridExtent#getLow(int) low coordinates}.
+     * For example in the case of image {@linkplain RenderedImage#getMinX() 
minimum X coordinate}:
+     *
+     * <ul class="verbose">
+     *   <li>A value of 0 means that the image left border is exactly where 
requested by {@code sliceExtent.getLow(xDimension)}.</li>
+     *   <li>A positive value means that the returned image is shifted to the 
right compared to specified extent.
+     *       This implies that the image has less data than requested on left 
side.
+     *       It may happen if the specified extent is partially outside grid 
coverage extent.</li>
+     *   <li>A negative value means that the returned image is shifted to the 
left compared to specified extent.
+     *       This implies that the image has more data than requested on left 
side. It may happen if the image is tiled,
+     *       the specified {@code sliceExtent} covers many tiles, and 
expanding the specified extent is necessary
+     *       for returning an integer amount of tiles.</li>
+     * </ul>
      *
-     * <div class="section">Rendered image properties</div>
+     * Similar discussion applies to the {@linkplain RenderedImage#getMinY() 
minimum Y coordinate}.
      * The {@linkplain RenderedImage#getWidth() image width} and {@linkplain 
RenderedImage#getHeight() height} will be
-     * the {@code sliceExtent} {@linkplain GridExtent#getSize(int) sizes} in 
the first and second dimension respectively
-     * of the two-dimensional {@code sliceExtent} {@linkplain 
GridExtent#getSubspaceDimensions(int) subspace}.
-     * The image location ({@linkplain RenderedImage#getMinX() x}, {@linkplain 
RenderedImage#getMinY() y}) can be any point;
-     * that location may not be the same as the {@code sliceExtent} 
{@linkplain GridExtent#getLow(int) low} coordinates
-     * since conversion from {@code long} to {@code int} primitive type may 
cause lost of precision, and some implementations
-     * like {@link java.awt.image.BufferedImage} restrict that location to 
(0,0).
+     * the {@code sliceExtent} {@linkplain GridExtent#getSize(int) sizes} if 
this method can honor exactly the request,
+     * or otherwise may be adjusted for the same reasons than <var>x</var> and 
<var>y</var> location discussed above.
      *
      * <p>Implementations should return a view as much as possible, without 
copying sample values.
      * {@code GridCoverage} subclasses can use the {@link ImageRenderer} class 
as a helper tool for that purpose.
@@ -179,9 +192,9 @@ public abstract class GridCoverage {
      *
      * @param  sliceExtent  a subspace of this grid coverage extent where all 
dimensions except two have a size of 1 cell.
      *         May be {@code null} if this grid coverage has only two 
dimensions with a size greater than 1 cell.
-     * @return the grid slice as a rendered image.
-     * @throws PointOutsideCoverageException if the given slice extent 
contains illegal coordinates.
+     * @return the grid slice as a rendered image. Image location is relative 
to {@code sliceExtent}.
      * @throws SubspaceNotSpecifiedException if the given argument is not 
sufficient for reducing the grid to a two-dimensional slice.
+     * @throws DisjointExtentException if the given extent does not intersect 
this grid coverage.
      * @throws CannotEvaluateException if this method can not produce the 
rendered image for another reason.
      */
     public abstract RenderedImage render(GridExtent sliceExtent) throws 
CannotEvaluateException;
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
index 1521e52..c3eea61 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
@@ -803,6 +803,8 @@ public class GridDerivation {
      * Builds a grid geometry with the configuration specified by the other 
methods in this {@code GridDerivation} class.
      *
      * @return the modified grid geometry. May be the {@link #base} grid 
geometry if no change apply.
+     *
+     * @see #getIntersection()
      */
     public GridGeometry build() {
         /*
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index 04af16a..4ebbe97 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -734,7 +734,7 @@ public class GridExtent implements Serializable {
      * @param  index       index of the dimension as stored in this grid 
extent.
      * @param  indexShown  index to write in the message. Often the same as 
{@code index}.
      */
-    private Object getAxisIdentification(final int index, final int 
indexShown) {
+    final Object getAxisIdentification(final int index, final int indexShown) {
         if (types != null) {
             final DimensionNameType type = types[index];
             if (type != null) {
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
index 7263498..b46fdd3 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
@@ -19,8 +19,10 @@ package org.apache.sis.coverage.grid;
 import java.util.Arrays;
 import java.nio.Buffer;
 import java.awt.Point;
+import java.awt.Rectangle;
 import java.awt.image.ColorModel;
 import java.awt.image.DataBuffer;
+import java.awt.image.SampleModel;
 import java.awt.image.BufferedImage;
 import java.awt.image.RenderedImage;
 import java.awt.image.WritableRaster;
@@ -86,12 +88,24 @@ import org.apache.sis.math.Vector;
  */
 public class ImageRenderer {
     /**
-     * Pixel coordinates of the image upper-left location.
-     * This is often left to zero since {@link BufferedImage} has this 
constraint.
+     * Location of the first image pixel relative to the grid coverage extent. 
The (0,0) offset means that the first pixel
+     * in the {@code sliceExtent} (specified at construction time) is the 
first pixel in the whole {@link GridCoverage}.
      *
-     * @see #setLocation(int, int)
+     * <div class="note"><b>Note:</b> if those offsets exceed 32 bits integer 
capacity, then it may not be possible to build
+     * an image for given {@code sliceExtent} from a single {@link 
DataBuffer}, because accessing sample values would exceed
+     * the* capacity of index in Java arrays. In those cases the image needs 
to be tiled.</div>
      */
-    private int x, y;
+    private final long offsetX, offsetY;
+
+    /**
+     * Pixel coordinates of the image upper-left corner, as an offset relative 
to the {@code sliceExtent}.
+     * This is initially zero (unless {@code sliceExtent} is partially outside 
the grid coverage extent),
+     * but a different value may be used if the given data are tiled.
+     *
+     * @see RenderedImage#getMinX()
+     * @see RenderedImage#getMinY()
+     */
+    private final int imageX, imageY;
 
     /**
      * Width (number of pixels in a row) of the image to render.
@@ -112,6 +126,15 @@ public class ImageRenderer {
     private final int height;
 
     /**
+     * Number of data elements between two samples in the data {@link 
#buffer}. This value is implicitly 1 in Java2D since
+     * {@link java.awt.image} supports <cite>pixel stride</cite> and 
<cite>scanline stride</cite> in {@link SampleModel},
+     * but does not support stride at the {@link DataBuffer} level. This is 
theoretically not needed since "sample stride"
+     * can be represented as {@link #pixelStride}. We allow this concept for 
the convenience of this builder, but at the
+     * end this value is incorporated into the pixel stride.
+     */
+    private int sampleStride;
+
+    /**
      * Number of data elements between two samples for the same band on the 
same line.
      * This is set to the product of {@linkplain GridExtent#getSize(int) grid 
sizes} of enclosing
      * {@code GridCoverage} in all dimensions before the dimension of image 
{@linkplain #width}.
@@ -141,12 +164,6 @@ public class ImageRenderer {
     private int[] bankIndices;
 
     /**
-     * Number of data elements from the first element of the bank to the first 
sample of the band, or {@code null} for all 0.
-     * If non-null, this array length must be equal to {@link #bands} array 
length.
-     */
-    private final int[] bandOffsets;
-
-    /**
      * The band to be made visible (usually 0). All other bands, if any will 
be ignored.
      */
     private int visibleBand;
@@ -158,11 +175,12 @@ public class ImageRenderer {
     private DataBuffer buffer;
 
     /**
-     * Creates a new image renderer for the given slice extent. The image will 
have only one tile.
+     * Creates a new image renderer for the given slice extent.
      *
      * @param  coverage     the grid coverage for which to build an image.
      * @param  sliceExtent  the grid geometry from which to create an image, 
or {@code null} for the {@code coverage} extent.
      * @throws SubspaceNotSpecifiedException if this method can not infer a 
two-dimensional slice from {@code sliceExtent}.
+     * @throws DisjointExtentException if the given extent does not intersect 
this grid coverage.
      * @throws ArithmeticException if a stride calculation overflows the 32 
bits integer capacity.
      */
     public ImageRenderer(final GridCoverage coverage, GridExtent sliceExtent) {
@@ -179,19 +197,33 @@ public class ImageRenderer {
             sliceExtent = source;
         }
         final int[] dimensions = sliceExtent.getSubspaceDimensions(2);
-        int  xd = dimensions[0];
-        int  yd = dimensions[1];
-        long xo = sliceExtent.getLow(xd);
-        long yo = sliceExtent.getLow(yd);
-        width  = Math.toIntExact(sliceExtent.getSize(xd));
-        height = Math.toIntExact(sliceExtent.getSize(yd));
+        final int  xd   = dimensions[0];
+        final int  yd   = dimensions[1];
+        final long xcov = source.getLow(xd);
+        final long ycov = source.getLow(yd);
+        final long xreq = sliceExtent.getLow(xd);
+        final long yreq = sliceExtent.getLow(yd);
+        final long xmin = Math.max(xreq, xcov);
+        final long ymin = Math.max(yreq, ycov);
+        final long xmax = Math.min(sliceExtent.getHigh(xd), 
source.getHigh(xd));
+        final long ymax = Math.min(sliceExtent.getHigh(yd), 
source.getHigh(yd));
+        if (xmax <= xmin || ymax <= ymin) {
+            final int d = (xmax <= xmin) ? xd : yd;
+            throw new DisjointExtentException(source.getAxisIdentification(d, 
d),
+                    source.getLow(d), source.getHigh(d), 
sliceExtent.getLow(d), sliceExtent.getHigh(d));
+        }
+        width   = Math.incrementExact(Math.toIntExact(xmax - xmin));
+        height  = Math.incrementExact(Math.toIntExact(ymax - ymin));
+        imageX  = Math.toIntExact(Math.subtractExact(xreq, xmin));
+        imageY  = Math.toIntExact(Math.subtractExact(yreq, ymin));
+        offsetX = Math.subtractExact(xmin, xcov);
+        offsetY = Math.subtractExact(ymin, ycov);
         /*
-         * After this point, xd and yd should be indices relative to source 
extent.
-         * For now we keep them unchanged on the assumption that the two grid 
extents have the same dimensions.
+         * At this point, the RenderedImage properties have been computed on 
the assumption
+         * that the returned image will be a single tile. Now compute 
SampleModel properties.
          */
-        xo = Math.subtractExact(xo, source.getLow(xd));
-        yo = Math.subtractExact(yo, source.getLow(yd));
-        long pixelStride = 1;
+        this.sampleStride = 1;
+        long pixelStride  = 1;
         for (int i=0; i<xd; i++) {
             pixelStride = Math.multiplyExact(pixelStride, source.getSize(i));
         }
@@ -201,8 +233,6 @@ public class ImageRenderer {
         }
         this.pixelStride    = Math.toIntExact(pixelStride);
         this.scanlineStride = Math.toIntExact(scanlineStride);
-        this.bandOffsets    = new int[getNumBands()];
-        Arrays.fill(bandOffsets, Math.toIntExact(xo + Math.multiplyExact(yo, 
scanlineStride)));
     }
 
     /**
@@ -226,30 +256,12 @@ public class ImageRenderer {
     }
 
     /**
-     * Sets the pixel coordinates of the upper-left corner of the rendered 
image to create.
-     * If this method is not invoked, then the default value is (0,0).
-     * That default value is often suitable since {@link BufferedImage} 
constraints that corner to (0,0).
+     * Returns the location of the image upper-left corner together with the 
image size.
      *
-     * @param  x  the minimum <var>x</var> coordinate (inclusive) of the 
rendered image.
-     * @param  y  the minimum <var>y</var> coordinate (inclusive) of the 
rendered image.
-     *
-     * @see RenderedImage#getMinX()
-     * @see RenderedImage#getMinY()
+     * @return the rendered image location and size (never null).
      */
-    public void setLocation(final int x, final int y) {
-        this.x = x;
-        this.y = y;
-    }
-
-    /**
-     * Returns the location of the image upper-left corner.
-     * This is the last value set by a call to {@link #setLocation(int, int)}.
-     * The default value is (0,0).
-     *
-     * @return the image location (never null).
-     */
-    public final Point getLocation() {
-        return new Point(x,y);
+    public final Rectangle getBounds() {
+        return new Rectangle(imageX, imageY, width, height);
     }
 
     /**
@@ -343,41 +355,59 @@ public class ImageRenderer {
     }
 
     /**
-     * Applies a subsampling between pixels. Invoking this method multiplies 
the <cite>pixel stride</cite>
-     * by the given amount. This method is cumulative: invoking it many times 
is equivalent to invoking it
-     * once with the product of all argument values.
+     * Specifies the number of data elements between two samples in the 
vectors specified by {@code setData(…)} methods.
+     * The default value is 1. A value of 2 (for example) instructs {@code 
ImageRenderer} to use the first value of the
+     * given data vectors, skip a value, use the next value, <i>etc.</i> In 
other words, this method applies a subsampling
+     * on the vectors specified to {@link #setData(Vector...)} or {@link 
#setData(int, Buffer...)}.
+     *
+     * @param  stride  the number of data elements between each sample values 
in the data vectors.
+     * @throws ArithmeticException if the given stride is too large.
      *
-     * @param  subsampling   the subsampling between pixels in each row.
+     * @see java.awt.image.ComponentSampleModel#pixelStride
+     * @see java.awt.image.ComponentSampleModel#scanlineStride
      */
-    public void subsampleX(final int subsampling) {
-        ArgumentChecks.ensureStrictlyPositive("subsampling", subsampling);
-        scanlineStride = Math.multiplyExact(scanlineStride, subsampling);
-        pixelStride *= subsampling;       // If above operation did not fail, 
then this operation can not fail.
+    public void setSampleStride(final int stride) {
+        if (stride != sampleStride) {
+            ArgumentChecks.ensureStrictlyPositive("stride", stride);
+            // Division by 'dataStride' is for cancelling effect of previous 
calls.
+            scanlineStride = Math.multiplyExact(scanlineStride / sampleStride, 
stride);
+            // If above operation did not fail, then following operation can 
not fail.
+            pixelStride = (pixelStride / sampleStride) * stride;
+            sampleStride = stride;
+        }
     }
 
     /**
      * Creates a raster with the data specified by the last call to a {@code 
setData(…)} method.
-     * The raster upper-left corner is located at the position given by {@link 
#getLocation()}.
+     * The raster upper-left corner is located at the position given by {@link 
#getBounds()}.
      *
      * @return the raster.
      * @throws IllegalStateException if no {@code setData(…)} method has been 
invoked before this method call.
      * @throws RasterFormatException if a call to a {@link WritableRaster} 
factory method failed.
+     * @throws ArithmeticException if a property of the raster to construct 
exceeds the capacity of 32 bits integers.
      */
     public WritableRaster raster() {
         if (buffer == null) {
             throw new 
IllegalStateException(Resources.format(Resources.Keys.UnspecifiedRasterData));
         }
-        final Point location = ((x | y) != 0) ? new Point(x,y) : null;
+        // Number of data elements from the first element of the bank to the 
first sample of the band.
+        final int[] bandOffsets = new int[getNumBands()];
+        Arrays.fill(bandOffsets, Math.toIntExact(Math.addExact(
+                Math.multiplyExact(offsetX, pixelStride),
+                Math.multiplyExact(offsetY, scanlineStride))));
+
+        final Point location = new Point(imageX, imageY);
         return RasterFactory.createRaster(buffer, width, height, pixelStride, 
scanlineStride, bankIndices, bandOffsets, location);
     }
 
     /**
      * Creates an image with the data specified by the last call to a {@code 
setData(…)} method.
-     * The image upper-left corner is located at the position given by {@link 
#getLocation()}.
+     * The image upper-left corner is located at the position given by {@link 
#getBounds()}.
      *
      * @return the image.
      * @throws IllegalStateException if no {@code setData(…)} method has been 
invoked before this method call.
      * @throws RasterFormatException if a call to a {@link WritableRaster} 
factory method failed.
+     * @throws ArithmeticException if a property of the image to construct 
exceeds the capacity of 32 bits integers.
      */
     public RenderedImage image() {
         WritableRaster raster = raster();
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
index cf29b44..7f5b979 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
@@ -29,7 +29,9 @@ import org.apache.sis.coverage.grid.ImageRenderer;
 
 
 /**
- * Data loaded from a {@link RasterResource}.
+ * Data loaded from a {@link RasterResource} and potentially shown as {@link 
RenderedImage}.
+ * The rendered image is usually mono-banded, but may be multi-banded in some 
special cases
+ * handled by {@link RasterResource#read(GridGeometry, int...)}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @version 1.0
@@ -38,7 +40,12 @@ import org.apache.sis.coverage.grid.ImageRenderer;
  */
 final class Raster extends GridCoverage {
     /**
-     * The sample values.
+     * The sample values, potentially multi-banded. If there is more than one 
band to put in the rendered image,
+     * then each band is a {@linkplain DataBuffer#getNumBanks() separated 
bank} in the buffer, even if two banks
+     * are actually wrapping the same arrays with different offsets.
+     *
+     * <div class="note">The later case is better represented by {@link 
java.awt.image.PixelInterleavedSampleModel},
+     * but it is {@link ImageRenderer} responsibility to perform this 
substitution as an optimization.</div>
      */
     private final DataBuffer data;
 
@@ -73,7 +80,7 @@ final class Raster extends GridCoverage {
         try {
             final ImageRenderer renderer = new ImageRenderer(this, target);
             renderer.setData(data);
-            renderer.subsampleX(pixelStride);
+            renderer.setSampleStride(pixelStride);
             return renderer.image();
         } catch (IllegalArgumentException | ArithmeticException | 
RasterFormatException e) {
             throw new 
CannotEvaluateException(Resources.format(Resources.Keys.CanNotRender_2, label, 
e), e);

Reply via email to