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 3cb7f5d Refactor a RasterFactor static method into an ImageRenderer
helper class.
3cb7f5d is described below
commit 3cb7f5d36dd7084e4f8a006baf697893ee5de03c
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Jan 7 11:23:34 2019 +0100
Refactor a RasterFactor static method into an ImageRenderer helper class.
---
.../coverage/MismatchedCoverageRangeException.java | 63 ++++
.../org/apache/sis/coverage/grid/GridCoverage.java | 56 +++-
.../org/apache/sis/coverage/grid/GridGeometry.java | 1 +
.../grid/IllegalGridGeometryException.java | 4 +
.../apache/sis/coverage/grid/ImageRenderer.java | 351 +++++++++++++++++++++
.../grid/IncompleteGridGeometryException.java | 12 +
.../sis/internal/raster/ColorModelFactory.java | 9 +-
.../apache/sis/internal/raster/RasterFactory.java | 93 ++----
.../org/apache/sis/internal/raster/Resources.java | 25 ++
.../sis/internal/raster/Resources.properties | 5 +
.../sis/internal/raster/Resources_fr.properties | 5 +
ide-project/NetBeans/nbproject/genfiles.properties | 2 +-
ide-project/NetBeans/nbproject/project.xml | 1 +
.../java/org/apache/sis/storage/netcdf/Image.java | 24 +-
14 files changed, 552 insertions(+), 99 deletions(-)
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/MismatchedCoverageRangeException.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/MismatchedCoverageRangeException.java
new file mode 100644
index 0000000..18d182e
--- /dev/null
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/MismatchedCoverageRangeException.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.coverage;
+
+
+/**
+ * Thrown when the number of bands or sample dimensions specified to a method
+ * is not equal to the number expected by a coverage.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ *
+ * @see org.opengis.geometry.MismatchedDimensionException
+ *
+ * @since 1.0
+ * @module
+ */
+public class MismatchedCoverageRangeException extends IllegalArgumentException
{
+ /**
+ * Serial number for inter-operability with different versions.
+ */
+ private static final long serialVersionUID = -8484971745880403661L;
+
+ /**
+ * Creates an exception with no message.
+ */
+ public MismatchedCoverageRangeException() {
+ super();
+ }
+
+ /**
+ * Creates an exception with the specified message.
+ *
+ * @param message the detail message, saved for later retrieval by the
{@link #getMessage()} method.
+ */
+ public MismatchedCoverageRangeException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Creates an exception with the specified message and cause.
+ *
+ * @param message the detail message, saved for later retrieval by the
{@link #getMessage()} method.
+ * @param cause the cause, saved for later retrieval by the {@link
#getCause()} method.
+ */
+ public MismatchedCoverageRangeException(final String message, final
Throwable cause) {
+ super(message, cause);
+ }
+}
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 dea57aa..d921ef2 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
@@ -116,12 +116,27 @@ public abstract class GridCoverage {
}
/**
- * Returns a two-dimensional slice of grid data as a rendered image. The
given {@code slicePoint} argument specifies
+ * Returns a two-dimensional slice of grid data as a rendered image. The
given {@code sliceExtent} argument specifies
* the coordinates of the slice in all dimensions that are not in the
two-dimensional image. For example if this grid
- * coverage has (<var>x</var>, <var>y</var>, <var>z</var>, <var>t</var>)
dimensions and we want to render an image
- * of data in the (<var>x</var>, <var>y</var>) dimensions, then the given
{@code slicePoint} shall contain the
- * (<var>z</var>, <var>t</var>) coordinates of the desired slice. The two
coordinates of the data to be shown
- * (<var>x</var> and <var>y</var> in our example) shall be excluded from
the slice point in one of the following ways:
+ * coverage has
<i>(<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>)</i> dimensions and we
want to render an image
+ * of data in the <i>(<var>x</var>,<var>y</var>)</i> dimensions, then the
given {@code sliceExtent} shall contain the
+ * <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.
+ *
+ * <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>
+ *
+ * <div class="section">Computing a slice extent from a slice point in
"real world" coordinates</div>
+ * 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
+ * should be constructed as a {@link DirectPosition} in one of the
following ways:
*
* <ul>
* <li>The {@code slicePoint} has a CRS with two dimensions less than
this grid coverage CRS.</li>
@@ -129,21 +144,36 @@ public abstract class GridCoverage {
* exclude are set to {@link Double#NaN}.</li>
* </ul>
*
+ * Then:
+ *
+ * <blockquote><code>sliceExtent = {@linkplain
#getGridGeometry()}.{@linkplain GridGeometry#subExtent(DirectPosition)
+ * subExtent}(slicePoint);</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. If the {@code slicePoint}
CRS is {@code null}, it is assumed the
- * same than this grid coverage CRS. If this grid coverage is
two-dimensional or can render only one image for
- * other reason, then the {@code slicePoint} can be null.
+ * a coordinate transformation will be applied as needed.
+ *
+ * <div class="section">Rendered image properties</div>
+ * 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).
*
- * <p>Implementations should return a view as much as possible, without
copying sample values.</p>
+ * <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.
+ * This method does not mandate any behavior regarding tiling (size of
tiles, their numbering system, <i>etc.</i>).
+ * Some implementations may defer data loading until {@linkplain
RenderedImage#getTile(int, int) a tile is requested}.</p>
*
- * @param slicePoint coordinates of the slice in all dimensions other
than the two dimensions to be shown on the image.
- * May be {@code null} if this coverage can render only one image,
for example because its CRS is two-dimensional.
+ * @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 point is
illegal.
+ * @throws PointOutsideCoverageException if the given slice extent
contains illegal coordinates.
* @throws SubspaceNotSpecifiedException if the given argument is not
sufficient for reducing the grid to a two-dimensional slice.
* @throws CannotEvaluateException if this method can not produce the
rendered image for another reason.
*/
- public abstract RenderedImage render(DirectPosition slicePoint) throws
CannotEvaluateException;
+ public abstract RenderedImage render(GridExtent sliceExtent) throws
CannotEvaluateException;
/**
* Returns a string representation of this grid coverage for debugging
purpose.
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index fa361cc..272d191 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -713,6 +713,7 @@ public class GridGeometry implements Serializable {
* @throws IllegalGridGeometryException if an error occurred while
converting the point coordinates to grid coordinates.
*
* @see #slice(DirectPosition)
+ * @see GridCoverage#render(GridExtent)
*/
public GridExtent subExtent(final DirectPosition slicePoint) {
ArgumentChecks.ensureNonNull("slicePoint", slicePoint);
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IllegalGridGeometryException.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IllegalGridGeometryException.java
index fcfb8be..1f2d0ee 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IllegalGridGeometryException.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IllegalGridGeometryException.java
@@ -21,6 +21,10 @@ import org.apache.sis.internal.raster.Resources;
/**
* Thrown when the argument specified to a method or constructor would result
in an invalid {@link GridGeometry}.
+ * This exception may have a {@link
org.opengis.referencing.operation.TransformException} as its cause, in which
+ * case the grid geometry failed to use a given "grid to CRS" transform over
the given grid extent. Such failure
+ * may happen with non-linear transforms, but are less likely in the common
case where the grid geometry uses a
+ * linear (or affine) "grid to CRS" transform.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0
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
new file mode 100644
index 0000000..8f95bc0
--- /dev/null
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
@@ -0,0 +1,351 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.coverage.grid;
+
+import java.util.Arrays;
+import java.nio.Buffer;
+import java.awt.Point;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.awt.image.RasterFormatException;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.apache.sis.coverage.SubspaceNotSpecifiedException;
+import org.apache.sis.coverage.MismatchedCoverageRangeException;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.internal.raster.ColorModelFactory;
+import org.apache.sis.internal.raster.RasterFactory;
+import org.apache.sis.internal.raster.Resources;
+import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.util.NullArgumentException;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.math.Vector;
+
+
+/**
+ * A builder for the rendered image to be returned by {@link
GridCoverage#render(GridExtent)}.
+ * This builder does not copy any sample values. Instead, it wraps existing
data arrays into
+ * {@link java.awt.image.Raster} objects by computing required information
such as
+ * {@linkplain java.awt.image.ComponentSampleModel#getPixelStride() pixel
stride},
+ * {@linkplain java.awt.image.ComponentSampleModel#getScanlineStride()
scanline stride} and
+ * {@linkplain java.awt.image.ComponentSampleModel#getBandOffsets() band
offsets}.
+ * Different {@code setData(…)} methods are provided for allowing to specify
the data arrays
+ * from different objects such as Java2D {@link DataBuffer} or NIO {@link
Buffer}.
+ *
+ * <p>All {@code setData(…)} methods assume that the first valid element in
each array is the value
+ * located at <code>{@linkplain GridCoverage#getGridGeometry()}.{@linkplain
GridGeometry#getExtent()
+ * getExtent()}.{@linkplain GridExtent#getLow(int) getLow()}</code>. This
{@code ImageRenderer} class
+ * computes automatically the offsets from that position to the position of
the first value included
+ * in the {@code sliceExtent} given to the constructor.</p>
+ *
+ * <p>Current implementation constructs only images made of a single tile.
+ * Support for tiled images will be added in a future version.</p>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+public class ImageRenderer {
+ /**
+ * Pixel coordinates of the image upper-left location.
+ * This is often left to zero since {@link BufferedImage} has this
constraint.
+ *
+ * @see #setLocation(int, int)
+ */
+ private int x, y;
+
+ /**
+ * Width (number of pixels in a row) of the image to render.
+ * This is usually set to the grid extent along the first dimension
+ * having a {@linkplain GridExtent#getSize(int) size} greater than 1.
+ *
+ * @see RenderedImage#getWidth()
+ */
+ private final int width;
+
+ /**
+ * Height (number of pixels in a column) of the image to render.
+ * This is usually set to the grid extent along the second dimension
+ * having a {@linkplain GridExtent#getSize(int) size} greater than 1.
+ *
+ * @see RenderedImage#getHeight()
+ */
+ private final int height;
+
+ /**
+ * 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}.
+ *
+ * @see java.awt.image.ComponentSampleModel#pixelStride
+ */
+ private final int pixelStride;
+
+ /**
+ * Number of data elements between a given sample and the corresponding
sample in the same column of the next 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 #height}.
+ *
+ * @see java.awt.image.ComponentSampleModel#scanlineStride
+ */
+ private final int scanlineStride;
+
+ /**
+ * The sample dimensions, to be used for defining the bands.
+ */
+ private final SampleDimension[] bands;
+
+ /**
+ * Bank indices for each band, or {@code null} for 0, 1, 2, 3….
+ * If non-null, this array length must be equal to {@link #bands} array
length.
+ */
+ 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;
+
+ /**
+ * The data to render, or {@code null} if not yet specified.
+ * If non-null, {@link DataBuffer#getNumBanks()} must be equal to {@link
#bands} array length.
+ */
+ private DataBuffer buffer;
+
+ /**
+ * Creates a new image renderer for the given slice extent. The image will
have only one tile.
+ *
+ * @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 ArithmeticException if a stride calculation overflows the 32
bits integer capacity.
+ */
+ public ImageRenderer(final GridCoverage coverage, GridExtent sliceExtent) {
+ ArgumentChecks.ensureNonNull("coverage", coverage);
+ bands = CollectionsExt.toArray(coverage.getSampleDimensions(),
SampleDimension.class);
+ final GridExtent source = coverage.getGridGeometry().getExtent();
+ if (sliceExtent != null) {
+ final int dimension = sliceExtent.getDimension();
+ if (source.getDimension() != dimension) {
+ throw new MismatchedDimensionException(Errors.format(
+ Errors.Keys.MismatchedDimension_3, "target",
source.getDimension(), dimension));
+ }
+ } else {
+ 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));
+ /*
+ * 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.
+ */
+ xo = Math.subtractExact(xo, source.getLow(xd));
+ yo = Math.subtractExact(yo, source.getLow(yd));
+ long pixelStride = 1;
+ for (int i=0; i<xd; i++) {
+ pixelStride = Math.multiplyExact(pixelStride, source.getSize(i));
+ }
+ long scanlineStride = pixelStride;
+ for (int i=xd; i<yd; i++) {
+ scanlineStride = Math.multiplyExact(scanlineStride,
source.getSize(i));
+ }
+ 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)));
+ }
+
+ /**
+ * Returns the number of bands that the image will have. By default, this
is the number of
+ * {@linkplain GridCoverage#getSampleDimensions() sample dimensions} in
the grid coverage.
+ *
+ * @return the number of bands in the rendered image.
+ */
+ public final int getNumBands() {
+ return bands.length;
+ }
+
+ /**
+ * Ensures that the given number is equals to the expected number of bands.
+ */
+ private void ensureExpectedBandCount(final int n) {
+ final int e = getNumBands();
+ if (n != e) {
+ throw new
MismatchedCoverageRangeException(Resources.format(Resources.Keys.UnexpectedNumberOfBands_2,
e, n));
+ }
+ }
+
+ /**
+ * 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).
+ *
+ * @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()
+ */
+ 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);
+ }
+
+ /**
+ * Sets the data as a Java2D buffer. The {@linkplain
DataBuffer#getNumBanks() number of banks}
+ * in the given buffer must be equal to the {@linkplain #getNumBands()
expected number of bands}.
+ * In each bank, the value located at the {@linkplain
DataBuffer#getOffsets() bank offset} is the value
+ * located at <code>{@linkplain
GridCoverage#getGridGeometry()}.{@linkplain GridGeometry#getExtent()
+ * getExtent()}.{@linkplain GridExtent#getLow(int) getLow()}</code>, as
specified in class javadoc.
+ *
+ * @param data the Java2D buffer containing data for all bands.
+ * @throws NullArgumentException if {@code data} is null.
+ * @throws MismatchedCoverageRangeException if the given data buffer does
not have the expected amount of banks.
+ */
+ public void setData(final DataBuffer data) {
+ ArgumentChecks.ensureNonNull("data", data);
+ ensureExpectedBandCount(data.getNumBanks());
+ buffer = data;
+ }
+
+ /**
+ * Sets the data as NIO buffers. The number of buffers must be equal to
the {@linkplain #getNumBands() expected
+ * number of bands}. All buffers must be {@linkplain Buffer#array() backed
by arrays} of the type specified by
+ * the {@code dataType} argument and have the same amount of {@linkplain
Buffer#remaining() remaining elements}.
+ * This method wraps the underlying arrays of a primitive type into a
Java2D buffer; data are not copied.
+ * For each buffer, the grid coverage data (not only the slice data)
starts at {@linkplain Buffer#position()
+ * buffer position} and ends at that position + {@linkplain
Buffer#remaining() remaining}.
+ *
+ * <p>The data type must be specified in order to distinguish between the
signed and unsigned types.
+ * {@link DataBuffer#TYPE_BYTE} and {@link DataBuffer#TYPE_USHORT} are
unsigned, all other supported
+ * types are signed.</p>
+ *
+ * <p><b>Implementation note:</b> the Java2D buffer is set by a call to
{@link #setData(DataBuffer)},
+ * which can be overridden by subclasses if desired.</p>
+ *
+ * @param dataType type of data as one of {@link DataBuffer#TYPE_BYTE},
{@link DataBuffer#TYPE_SHORT TYPE_SHORT}
+ * {@link DataBuffer#TYPE_USHORT TYPE_USHORT}, {@link
DataBuffer#TYPE_INT TYPE_INT},
+ * {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT} or {@link
DataBuffer#TYPE_DOUBLE TYPE_DOUBLE} constants.
+ * @param data the buffers wrapping arrays of primitive type.
+ * @throws NullArgumentException if {@code data} is null or one of {@code
data} element is null.
+ * @throws IllegalArgumentException if {@code dataType} is not a supported
value.
+ * @throws MismatchedCoverageRangeException if the number of specified
buffers is not equal to the number of bands.
+ * @throws UnsupportedOperationException if a buffer is not backed by an
accessible array or is read-only.
+ * @throws ArrayStoreException if a buffer type is incompatible with
{@code dataType}.
+ * @throws RasterFormatException if buffers do not have the same amount of
remaining values.
+ * @throws ArithmeticException if a buffer position overflows the 32 bits
integer capacity.
+ */
+ public void setData(final int dataType, final Buffer... data) {
+ ArgumentChecks.ensureNonNull("data", data);
+ ensureExpectedBandCount(data.length);
+ final DataBuffer banks = RasterFactory.wrap(dataType, data);
+ if (banks == null) {
+ throw new
IllegalArgumentException(Resources.format(Resources.Keys.UnknownDataType_1,
dataType));
+ }
+ setData(banks);
+ }
+
+ /**
+ * Sets the data as vectors. The number of vectors must be equal to the
{@linkplain #getNumBands() expected number of bands}.
+ * All vectors must be backed by arrays (indirectly, through {@linkplain
Vector#buffer() buffers} backed by arrays) and have
+ * the same {@linkplain Vector#size() size}.
+ * This method wraps the underlying arrays of a primitive type into a
Java2D buffer; data are not copied.
+ *
+ * <p><b>Implementation note:</b> the NIO buffers are set by a call to
{@link #setData(int, Buffer...)},
+ * which can be overridden by subclasses if desired.</p>
+ *
+ * @param data the vectors wrapping arrays of primitive type.
+ * @throws NullArgumentException if {@code data} is null or one of {@code
data} element is null.
+ * @throws MismatchedCoverageRangeException if the number of specified
vectors is not equal to the number of bands.
+ * @throws UnsupportedOperationException if a vector is not backed by an
accessible array or is read-only.
+ * @throws RasterFormatException if vectors do not have the same size.
+ * @throws ArithmeticException if a buffer position overflows the 32 bits
integer capacity.
+ */
+ public void setData(final Vector... data) {
+ ArgumentChecks.ensureNonNull("data", data);
+ ensureExpectedBandCount(data.length);
+ final Buffer[] buffers = new Buffer[data.length];
+ int dataType = DataBuffer.TYPE_UNDEFINED;
+ for (int i=0; i<data.length; i++) {
+ final Vector v = data[i];
+ ArgumentChecks.ensureNonNullElement("data", i, v);
+ final int t = RasterFactory.getType(v.getElementType(),
v.isUnsigned());
+ if (dataType != t) {
+ if (i != 0) {
+ throw new
RasterFormatException(Resources.format(Resources.Keys.MismatchedDataType));
+ }
+ dataType = t;
+ }
+ buffers[i] =
v.buffer().orElseThrow(UnsupportedOperationException::new);
+ }
+ setData(dataType, buffers);
+ }
+
+ /**
+ * 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()}.
+ *
+ * @return the raster.
+ * @throws IllegalStateException if no {@code setData(…)} method has been
invoked before this method call.
+ */
+ 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;
+ 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()}.
+ *
+ * @return the image.
+ * @throws IllegalStateException if no {@code setData(…)} method has been
invoked before this method call.
+ */
+ public RenderedImage image() {
+ WritableRaster raster = raster();
+ ColorModel colors = ColorModelFactory.createColorModel(bands,
visibleBand, buffer.getDataType(), ColorModelFactory.GRAYSCALE);
+ return new BufferedImage(colors, raster, false, null);
+ }
+}
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IncompleteGridGeometryException.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IncompleteGridGeometryException.java
index 84f5bbe..dfc4572 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IncompleteGridGeometryException.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/IncompleteGridGeometryException.java
@@ -22,6 +22,18 @@ package org.apache.sis.coverage.grid;
* For example this exception is thrown when {@link
GridGeometry#getEnvelope()} is invoked while
* the grid geometry has been built with a null envelope.
*
+ * <p>The {@link GridGeometry#isDefined(int)} can be used for avoiding this
exception.
+ * For example if a process is going to need both the grid extent and the
"grid to CRS" transform,
+ * than it can verify if those two conditions are met in a single method
call:</p>
+ *
+ * {@preformat java
+ * if (gg.isDefined(GridGeometry.EXTENT | GridGeometry.GRID_TO_CRS) {
+ * GridExtent extent = gg.getGridExtent();
+ * MathTransform gridToCRS = gg.getGridToCRS(PixelInCell.CELL_CENTER);
+ * // Do the process.
+ * }
+ * }
+ *
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 1.0
* @since 1.0
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/ColorModelFactory.java
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/ColorModelFactory.java
index f21386a..281b8b5 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/ColorModelFactory.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/ColorModelFactory.java
@@ -17,7 +17,6 @@
package org.apache.sis.internal.raster;
import java.util.Map;
-import java.util.List;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
@@ -50,7 +49,7 @@ import org.apache.sis.util.collection.WeakValueHashMap;
public final class ColorModelFactory {
/**
* Applies a gray scale to quantitative category and transparent colors to
qualitative categories.
- * This is a possible argument for {@link #createColorModel(List, int,
int, Function)}.
+ * This is a possible argument for {@link
#createColorModel(SampleDimension[], int, int, Function)}.
*/
public static final Function<Category,Color[]> GRAYSCALE =
(category) -> category.isQuantitative() ? new Color[]
{Color.BLACK, Color.WHITE} : null;
@@ -283,16 +282,16 @@ public final class ColorModelFactory {
* @param colors the colors to use for each category. The function
may return {@code null}, which means transparent.
* @return a color model suitable for {@link java.awt.image.RenderedImage}
objects with values in the given ranges.
*/
- public static ColorModel createColorModel(final List<? extends
SampleDimension> bands,
+ public static ColorModel createColorModel(final SampleDimension[] bands,
final int visibleBand, final int type, Function<Category,Color[]>
colors)
{
ArgumentChecks.ensureNonNull("bands", bands);
ArgumentChecks.ensureNonNull("colors", colors);
final Map<NumberRange<?>, Color[]> ranges = new LinkedHashMap<>();
- for (final Category category : bands.get(visibleBand).getCategories())
{
+ for (final Category category : bands[visibleBand].getCategories()) {
ranges.put(category.getSampleRange(), colors.apply(category));
}
- return createColorModel(ranges, visibleBand, bands.size(), type);
+ return createColorModel(ranges, visibleBand, bands.length, type);
}
/**
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/RasterFactory.java
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/RasterFactory.java
index 9619ca6..edfdd23 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/RasterFactory.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/RasterFactory.java
@@ -30,15 +30,13 @@ import java.awt.image.SampleModel;
import java.awt.image.BandedSampleModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.RasterFormatException;
import java.awt.image.WritableRaster;
-import org.opengis.geometry.MismatchedDimensionException;
-import org.apache.sis.coverage.SubspaceNotSpecifiedException;
-import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.Numbers;
import org.apache.sis.util.Static;
import org.apache.sis.util.Workaround;
import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.resources.Errors;
/**
@@ -57,57 +55,6 @@ public final class RasterFactory extends Static {
}
/**
- * Wraps a sub-region of the given data buffer in a raster.
- * The raster width, raster height, pixel stride and scanline stride are
inferred from the grid extents.
- * The sample model type is selected according the number of bands and the
pixel stride.
- *
- * @param buffer buffer that contains the sample values.
- * @param bankIndices bank indices for each band, or {@code null} for
0, 1, 2, 3….
- * @param bandOffsets number of data elements from the first element
of the bank to the first sample of the band, or {@code null} for all 0.
- * @param source extent of the data wrapped by the given buffer.
May have any number of dimensions.
- * @param target extent of the subspace to wrap in a raster.
- * @param startAtZero whether to force the raster to start at (0,0)
instead than the target extent low coordinates.
- * @return a raster built from given properties.
- * @throws ArithmeticException if a stride calculation overflows the 32
bits integer capacity.
- * @throws SubspaceNotSpecifiedException if this method can not infer a
two-dimensional slice from {@code target}.
- */
- public static WritableRaster createRaster(final DataBuffer buffer, final
int[] bankIndices, final int[] bandOffsets,
- final GridExtent source, final GridExtent target, final boolean
startAtZero)
- {
- int dimension = target.getDimension();
- if (source.getDimension() != dimension) {
- throw new MismatchedDimensionException(Errors.format(
- Errors.Keys.MismatchedDimension_3, "target",
source.getDimension(), dimension));
- }
- final int[] dimensions = target.getSubspaceDimensions(2);
- int xd = dimensions[0];
- int yd = dimensions[1];
- final Point location;
- if (startAtZero) {
- location = null;
- } else {
- location = new Point(Math.toIntExact(target.getLow(xd)),
- Math.toIntExact(target.getLow(yd)));
- }
- final int width = Math.toIntExact(target.getSize(xd));
- final int height = Math.toIntExact(target.getSize(yd));
- /*
- * 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.
- */
- long pixelStride = 1;
- for (int i=0; i<xd; i++) {
- pixelStride = Math.multiplyExact(pixelStride, target.getSize(i));
- }
- long scanlineStride = pixelStride;
- for (int i=xd; i<yd; i++) {
- scanlineStride = Math.multiplyExact(scanlineStride,
target.getSize(i));
- }
- return createRaster(buffer, width, height,
- Math.toIntExact(pixelStride), Math.toIntExact(scanlineStride),
bankIndices, bandOffsets, location);
- }
-
- /**
* Wraps the given data buffer in a raster.
* The sample model type is selected according the number of bands and the
pixel stride.
*
@@ -120,6 +67,8 @@ public final class RasterFactory extends Static {
* @param bandOffsets number of data elements from the first element
of the bank to the first sample of the band, or {@code null} for all 0.
* @param location the upper-left corner of the raster, or {@code
null} for (0,0).
* @return a raster built from given properties.
+ * @throws NullPointerException if {@code buffer} is {@code null}.
+ * @throws RasterFormatException if the width or height is less than or
equal to zero, or if there is an integer overflow.
*
* @see WritableRaster#createInterleavedRaster(DataBuffer, int, int, int,
int, int[], Point)
* @see WritableRaster#createBandedRaster(DataBuffer, int, int, int,
int[], int[], Point)
@@ -129,10 +78,10 @@ public final class RasterFactory extends Static {
final int width, final int height, final int pixelStride, final
int scanlineStride,
int[] bankIndices, int[] bandOffsets, final Point location)
{
- ArgumentChecks.ensureStrictlyPositive("width", width);
- ArgumentChecks.ensureStrictlyPositive("height", height);
- ArgumentChecks.ensureStrictlyPositive("pixelStride", pixelStride);
- ArgumentChecks.ensureStrictlyPositive("scanlineStride",
scanlineStride);
+ /*
+ * We do not verify the argument validity. Since this class is
internal, caller should have done verification
+ * itself. Furthermore those arguments are verified by WritableRaster
constructors anyway.
+ */
if (bandOffsets == null) {
bandOffsets = new int[buffer.getNumBanks()];
}
@@ -197,6 +146,25 @@ public final class RasterFactory extends Static {
}
/**
+ * Returns the {@link DataBuffer} constant for the given type. The given
{@code sample} class
+ * should be a primitive type such as {@link Float#TYPE}. Wrappers class
are also accepted.
+ *
+ * @param sample the primitive type or its wrapper class. May be
{@code null}.
+ * @param unsigned whether the type should be considered unsigned.
+ * @return the {@link DataBuffer} type, or {@link
DataBuffer#TYPE_UNDEFINED}.
+ */
+ public static int getType(final Class<?> sample, final boolean unsigned) {
+ switch (Numbers.getEnumConstant(sample)) {
+ case Numbers.BYTE: if (unsigned) return DataBuffer.TYPE_BYTE;
else break;
+ case Numbers.SHORT: return unsigned ? DataBuffer.TYPE_USHORT :
DataBuffer.TYPE_SHORT;
+ case Numbers.INTEGER: if (!unsigned) return DataBuffer.TYPE_INT;
else break;
+ case Numbers.FLOAT: return DataBuffer.TYPE_FLOAT;
+ case Numbers.DOUBLE: return DataBuffer.TYPE_DOUBLE;
+ }
+ return DataBuffer.TYPE_UNDEFINED;
+ }
+
+ /**
* Wraps the backing arrays of given NIO buffers into Java2D buffers.
* This method wraps the underlying array of primitive types; data are not
copied.
* For each buffer, the data starts at {@linkplain Buffer#position()
buffer position}
@@ -208,8 +176,8 @@ public final class RasterFactory extends Static {
* @throws UnsupportedOperationException if a buffer is not backed by an
accessible array.
* @throws ReadOnlyBufferException if a buffer is backed by an array but
is read-only.
* @throws ArrayStoreException if the type of a backing array is not
{@code dataType}.
- * @throws ArithmeticException if the position of a buffer is too high.
- * @throws IllegalArgumentException if buffers do not have the same amount
of remaining values.
+ * @throws ArithmeticException if a buffer position overflows the 32 bits
integer capacity.
+ * @throws RasterFormatException if buffers do not have the same amount of
remaining values.
*/
public static DataBuffer wrap(final int dataType, final Buffer... data) {
final int numBands = data.length;
@@ -227,12 +195,13 @@ public final class RasterFactory extends Static {
int length = 0;
for (int i=0; i<numBands; i++) {
final Buffer buffer = data[i];
+ ArgumentChecks.ensureNonNullElement("data", i, buffer);
arrays [i] = buffer.array();
offsets[i] = Math.addExact(buffer.arrayOffset(),
buffer.position());
final int r = buffer.remaining();
if (i == 0) length = r;
else if (length != r) {
- throw new
IllegalArgumentException(Errors.format(Errors.Keys.MismatchedArrayLengths));
+ throw new
RasterFormatException(Resources.format(Resources.Keys.MismatchedBandSize));
}
}
switch (dataType) {
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
index 2728aab..ffc6eb3 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
@@ -125,6 +125,16 @@ public final class Resources extends IndexedResourceBundle
{
public static final short IterationNotStarted = 4;
/**
+ * The bands have different number of sample values.
+ */
+ public static final short MismatchedBandSize = 28;
+
+ /**
+ * The bands store sample values using different data types.
+ */
+ public static final short MismatchedDataType = 30;
+
+ /**
* The two images have different size or pixel coordinates.
*/
public static final short MismatchedImageLocation = 5;
@@ -176,6 +186,16 @@ public final class Resources extends IndexedResourceBundle
{
public static final short TooManyQualitatives = 17;
/**
+ * Expected {0} bands but got {1}.
+ */
+ public static final short UnexpectedNumberOfBands_2 = 27;
+
+ /**
+ * Raster data type ‘{0}’ is unknown or unsupported.
+ */
+ public static final short UnknownDataType_1 = 29;
+
+ /**
* Coordinate reference system is unspecified.
*/
public static final short UnspecifiedCRS = 9;
@@ -186,6 +206,11 @@ public final class Resources extends IndexedResourceBundle
{
public static final short UnspecifiedGridExtent = 10;
/**
+ * Raster data are unspecified.
+ */
+ public static final short UnspecifiedRasterData = 31;
+
+ /**
* Coordinates transform is unspecified.
*/
public static final short UnspecifiedTransform = 11;
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
index 90419df..157b261 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
@@ -32,6 +32,8 @@ IllegalTransferFunction_1 = Illegal transfer function
for \u201c{0}\u201
IncompatibleTile_2 = The ({0}, {1}) tile has an unexpected
size, number of bands or sample layout.
IterationIsFinished = Iteration is finished.
IterationNotStarted = Iteration did not started.
+MismatchedBandSize = The bands have different number of sample
values.
+MismatchedDataType = The bands store sample values using
different data types.
MismatchedImageLocation = The two images have different size or
pixel coordinates.
MismatchedSampleModel = The two images use different sample models.
MismatchedTileGrid = The two images have different tile grid.
@@ -42,6 +44,9 @@ NotStrictlyOrderedDimensions = The specified dimensions
are not in strictly
OutOfIteratorDomain_2 = The ({0,number}, {1,number}) pixel
coordinate is outside iterator domain.
PointOutsideCoverageDomain_1 = Point ({0}) is outside the coverage domain.
TooManyQualitatives = Too many qualitative categories.
+UnexpectedNumberOfBands_2 = Expected {0} bands but got {1}.
+UnknownDataType_1 = Raster data type \u2018{0}\u2019 is
unknown or unsupported.
UnspecifiedCRS = Coordinate reference system is unspecified.
UnspecifiedGridExtent = Grid extent is unspecified.
+UnspecifiedRasterData = Raster data are unspecified.
UnspecifiedTransform = Coordinates transform is unspecified.
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
index f2a6c2d..ba0f80c 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
@@ -37,6 +37,8 @@ IllegalTransferFunction_1 = Fonction de transfert
ill\u00e9gale pour la
IncompatibleTile_2 = La tuile ({0}, {1}) a une taille, un
nombre de bandes ou une disposition des valeurs inattendu.
IterationIsFinished = L\u2019it\u00e9ration est termin\u00e9e.
IterationNotStarted = L\u2019it\u00e9ration n\u2019a pas
commenc\u00e9e.
+MismatchedBandSize = Les bandes ont un nombre diff\u00e9rent de
valeurs.
+MismatchedDataType = Les bandes stockent leurs valeurs en
utilisant des types de donn\u00e9es diff\u00e9rents.
MismatchedImageLocation = Les deux images ont une taille ou des
coordonn\u00e9es pixels diff\u00e9rentes.
MismatchedSampleModel = Les deux images disposent les pixels
diff\u00e9remment.
MismatchedTileGrid = Les deux images utilisent des grilles de
tuiles diff\u00e9rentes.
@@ -47,6 +49,9 @@ NotStrictlyOrderedDimensions = Les dimensions
sp\u00e9cifi\u00e9es ne sont
OutOfIteratorDomain_2 = La coordonn\u00e9e pixel ({0,number},
{1,number}) est en dehors du domaine de l\u2019it\u00e9rateur.
PointOutsideCoverageDomain_1 = Le point ({0}) est en dehors du domaine de
la couverture de donn\u00e9es.
TooManyQualitatives = Trop de cat\u00e9gories qualitatives.
+UnexpectedNumberOfBands_2 = On attendait {0} bandes mais {1} ont
\u00e9t\u00e9 sp\u00e9cifi\u00e9es.
+UnknownDataType_1 = Le type de donn\u00e9es raster
\u2018{0}\u2019 est inconnu ou non-support\u00e9.
UnspecifiedCRS = Le syst\u00e8me de r\u00e9f\u00e9rence des
coordonn\u00e9es n\u2019a pas \u00e9t\u00e9 sp\u00e9cifi\u00e9.
UnspecifiedGridExtent = L\u2019\u00e9tendue de la grille n\u2019a
pas \u00e9t\u00e9 sp\u00e9cifi\u00e9e.
+UnspecifiedRasterData = Les donn\u00e9es du raster n\u2019ont pas
\u00e9t\u00e9 sp\u00e9cifi\u00e9es.
UnspecifiedTransform = La transformation de coordonn\u00e9es
n\u2019a pas \u00e9t\u00e9 sp\u00e9cifi\u00e9e.
diff --git a/ide-project/NetBeans/nbproject/genfiles.properties
b/ide-project/NetBeans/nbproject/genfiles.properties
index cb85add..ec9b777 100644
--- a/ide-project/NetBeans/nbproject/genfiles.properties
+++ b/ide-project/NetBeans/nbproject/genfiles.properties
@@ -3,6 +3,6 @@
build.xml.data.CRC32=58e6b21c
build.xml.script.CRC32=462eaba0
[email protected]
-nbproject/build-impl.xml.data.CRC32=1a7e4f72
+nbproject/build-impl.xml.data.CRC32=80e7865b
nbproject/build-impl.xml.script.CRC32=a7689f96
nbproject/[email protected]
diff --git a/ide-project/NetBeans/nbproject/project.xml
b/ide-project/NetBeans/nbproject/project.xml
index 2e7964c..3d5b601 100644
--- a/ide-project/NetBeans/nbproject/project.xml
+++ b/ide-project/NetBeans/nbproject/project.xml
@@ -116,6 +116,7 @@
<word>polyline</word>
<word>polylines</word>
<word>recursivity</word>
+ <word>scanline</word>
<word>spliterator</word>
<word>subsampled</word>
<word>subsampling</word>
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/Image.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/Image.java
index ba322ce..845eaf3 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/Image.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/Image.java
@@ -18,17 +18,13 @@ package org.apache.sis.storage.netcdf;
import java.util.List;
import java.awt.image.DataBuffer;
-import java.awt.image.ColorModel;
-import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
-import java.awt.image.WritableRaster;
-import org.opengis.geometry.DirectPosition;
import org.opengis.coverage.CannotEvaluateException;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
-import org.apache.sis.internal.raster.RasterFactory;
-import org.apache.sis.internal.raster.ColorModelFactory;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.ImageRenderer;
/**
@@ -41,11 +37,6 @@ import org.apache.sis.internal.raster.ColorModelFactory;
*/
final class Image extends GridCoverage {
/**
- * Index of the band to show in rendered image.
- */
- private static final int VISIBLE_BAND = 0;
-
- /**
* The sample values.
*/
private final DataBuffer data;
@@ -63,14 +54,11 @@ final class Image extends GridCoverage {
* This returns a view as much as possible; sample values are not copied.
*/
@Override
- public RenderedImage render(final DirectPosition slicePoint) {
- GridGeometry source = getGridGeometry();
- GridGeometry target = source;
- if (slicePoint != null) target = target.slice(slicePoint);
+ public RenderedImage render(final GridExtent target) {
try {
- WritableRaster raster = RasterFactory.createRaster(data, null,
null, source.getExtent(), target.getExtent(), true);
- ColorModel colors =
ColorModelFactory.createColorModel(getSampleDimensions(), VISIBLE_BAND,
data.getDataType(), ColorModelFactory.GRAYSCALE);
- return new BufferedImage(colors, raster, false, null);
+ final ImageRenderer renderer = new ImageRenderer(this, target);
+ renderer.setData(data);
+ return renderer.image();
} catch (ArithmeticException | IllegalArgumentException e) {
throw new CannotEvaluateException(null, e);
}