Skip to content

Commit

Permalink
[GEOS-8996] CoverageView setup fails if one of the source bands has a…
Browse files Browse the repository at this point in the history
…n indexed color model
  • Loading branch information
aaime committed Oct 31, 2018
1 parent 12a42fb commit 0d35fb6
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
import it.geosolutions.imageio.utilities.ImageIOUtilities;
import it.geosolutions.jaiext.JAIExt;
import it.geosolutions.jaiext.utilities.ImageLayout2;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.renderable.ParameterBlock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -29,6 +30,7 @@
import javax.media.jai.ImageLayout;
import javax.media.jai.JAI;
import javax.media.jai.RasterFactory;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.ConstantDescriptor;
import org.apache.commons.lang3.ArrayUtils;
import org.geoserver.catalog.CoverageView.CoverageBand;
Expand Down Expand Up @@ -57,6 +59,7 @@
import org.geotools.util.factory.Hints;
import org.geotools.util.logging.Logging;
import org.opengis.coverage.grid.Format;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.filter.FilterFactory2;
import org.opengis.geometry.BoundingBox;
Expand Down Expand Up @@ -430,6 +433,7 @@ public GridCoverage2D read(GeneralParameterValue[] parameters)
}

coverage = retainBands(bandIndices, coverage, localHints);
coverage = prepareForBandMerge(coverage);
coverages.add(coverage);
if (resolutionChooser.visit(coverage)) {
transformationChoice = index;
Expand Down Expand Up @@ -480,6 +484,60 @@ public GridCoverage2D read(GeneralParameterValue[] parameters)
return result;
}

/**
* The BandMerge operation takes indexed images and expands them, however in the context of
* coverage view band merging we don't normally want that, e.g., raster mask bands are
* represented as indexed but we really want to keep them in their binary, single band form. To
* do so, the IndexColorModel is replaced by a ComponentColorModel
*
* @param coverage
* @return
*/
private GridCoverage2D prepareForBandMerge(GridCoverage2D coverage) {
RenderedImage ri = coverage.getRenderedImage();
SampleModel sampleModel = ri.getSampleModel();
if (sampleModel.getNumBands() == 1 && ri.getColorModel() instanceof IndexColorModel) {
// format with same data type as input
final ParameterBlock paramBlk = new ParameterBlock().addSource(ri);
int dataType = sampleModel.getDataType();
paramBlk.add(dataType);
// force the desired color model
ComponentColorModel targetColorModel =
new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY),
false,
false,
Transparency.OPAQUE,
dataType);
ImageLayout layout = new ImageLayout(ri);
layout.setColorModel(targetColorModel);

// that might not be enough, the source sample model might not be compatible
// e.g., MultiPixelPackedSampleModel is not compatible with ComponentColorModel
if (!targetColorModel.isCompatibleSampleModel(sampleModel)) {
SampleModel targetSampleModel =
targetColorModel.createCompatibleSampleModel(
sampleModel.getWidth(), sampleModel.getHeight());
layout.setSampleModel(targetSampleModel);
}

Hints localHints = new Hints(hints);
localHints.put(JAI.KEY_IMAGE_LAYOUT, layout);
RenderedOp formatted = JAI.create("Format", paramBlk, localHints);

return new GridCoverageFactory()
.create(
coverage.getName(),
formatted,
coverage.getGridGeometry(),
coverage.getSampleDimensions(),
new GridCoverage[] {coverage},
coverage.getProperties());
}

return coverage;
}

private void addAlphaColorModelHint(Hints localHints, int currentBandCount) {
ImageLayout layout = new ImageLayout();
ColorModel alphaModel = getColorModelWithAlpha(currentBandCount);
Expand Down
110 changes: 99 additions & 11 deletions src/main/src/test/java/org/geoserver/catalog/CoverageViewTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
*/
package org.geoserver.catalog;

import static org.geotools.gml2.GML.coverage;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import it.geosolutions.jaiext.JAIExt;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import javax.media.jai.PlanarImage;
import javax.xml.namespace.QName;
import org.geoserver.catalog.CoverageView.CompositionType;
import org.geoserver.catalog.CoverageView.CoverageBand;
Expand All @@ -39,6 +43,7 @@
import org.geotools.feature.visitor.MinVisitor;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.image.util.ImageUtilities;
import org.geotools.parameter.DefaultParameterDescriptor;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.transform.AffineTransform2D;
Expand All @@ -57,9 +62,12 @@ public class CoverageViewTest extends GeoServerSystemTestSupport {

private static final String RGB_IR_VIEW = "RgbIrView";
private static final String S2_REDUCED_VIEW = "s2reduced_view";
private static final String BANDS_FLAGS_VIEW = "BandsFlagsView";
protected static QName WATTEMP = new QName(MockData.SF_URI, "watertemp", MockData.SF_PREFIX);
protected static QName S2REDUCED = new QName(MockData.SF_URI, "s2reduced", MockData.SF_PREFIX);
protected static QName IR_RGB = new QName(MockData.SF_URI, "ir-rgb", MockData.SF_PREFIX);
protected static QName BANDS_FLAGS =
new QName(MockData.SF_URI, "bands-flags", MockData.SF_PREFIX);

@Before
public void cleanupCatalog() {
Expand All @@ -84,6 +92,7 @@ protected void setUpTestData(SystemTestData testData) throws Exception {
testData.setUpRasterLayer(WATTEMP, "watertemp.zip", null, null, TestData.class);
testData.setUpRasterLayer(S2REDUCED, "s2reduced.zip", null, null, TestData.class);
testData.setUpRasterLayer(IR_RGB, "ir-rgb.zip", null, null, TestData.class);
testData.setUpRasterLayer(BANDS_FLAGS, "bands-flags.zip", null, null, TestData.class);

UTM32N = CRS.decode("EPSG:32632", true);
}
Expand All @@ -94,6 +103,11 @@ protected void onSetUp(SystemTestData testData) throws Exception {

// setup the coverage view
final Catalog cat = getCatalog();
configureIROnCatalog(cat);
configureBandsFlagsOnCatalog(cat);
}

private void configureIROnCatalog(Catalog cat) throws Exception {
final CoverageStoreInfo storeInfo = cat.getCoverageStoreByName("ir-rgb");
final CoverageView coverageView = buildRgbIRView();
final CatalogBuilder builder = new CatalogBuilder(cat);
Expand All @@ -109,6 +123,18 @@ protected void onSetUp(SystemTestData testData) throws Exception {
cat.add(coverageInfo);
}

private void configureBandsFlagsOnCatalog(Catalog cat) throws Exception {
final CoverageStoreInfo storeInfo = cat.getCoverageStoreByName("bands-flags");
final CoverageView coverageView = buildBandsFlagsView();
final CatalogBuilder builder = new CatalogBuilder(cat);
builder.setStore(storeInfo);

final CoverageInfo coverageInfo =
coverageView.createCoverageInfo(BANDS_FLAGS_VIEW, storeInfo, builder);
coverageInfo.getParameters().put("USE_JAI_IMAGEREAD", "false");
cat.add(coverageInfo);
}

private CoverageView buildRgbIRView() {
final CoverageBand rBand =
new CoverageBand(
Expand Down Expand Up @@ -143,6 +169,45 @@ private CoverageView buildRgbIRView() {
return coverageView;
}

private CoverageView buildBandsFlagsView() {
String[] sources =
new String[] {
"SWIR",
"VNIR",
"QUALITY_CLASSES",
"QUALITY_CLOUD",
"QUALITY_CLOUDSHADOW",
"QUALITY_HAZE",
"QUALITY_SNOW"
};

List<CoverageBand> bands = new ArrayList<>();
for (String source : sources) {
if (source.startsWith("QUALITY_")) {
CoverageBand band =
new CoverageBand(
Arrays.asList(new InputCoverageBand(source, "0")),
source,
0,
CompositionType.BAND_SELECT);
bands.add(band);
} else {
for (int i = 0; i < 3; i++) {
CoverageBand band =
new CoverageBand(
Arrays.asList(new InputCoverageBand(source, "" + i)),
source + "_" + i,
i,
CompositionType.BAND_SELECT);
bands.add(band);
}
}
}

final CoverageView coverageView = new CoverageView(BANDS_FLAGS_VIEW, bands);
return coverageView;
}

@Test
public void testPreserveCoverageBandNames() throws Exception {
final Catalog cat = getCatalog();
Expand Down Expand Up @@ -193,11 +258,21 @@ public void testCoverageView() throws Exception {
resPool.getGridCoverage(coverageInfo, "waterView", bbox, null);
assertEquals(coverage.getNumSampleDimensions(), 1);

((GridCoverage2D) coverage).dispose(true);
disposeCoverage(coverage);
final GridCoverageReader reader = resPool.getGridCoverageReader(coverageInfo, null);
reader.dispose();
}

private void disposeCoverage(GridCoverage coverage) {
RenderedImage ri = coverage.getRenderedImage();
if (coverage instanceof GridCoverage2D) {
((GridCoverage2D) coverage).dispose(true);
}
if (ri instanceof PlanarImage) {
ImageUtilities.disposePlanarImageChain((PlanarImage) ri);
}
}

/** */
@Test
public void testBands() throws Exception {
Expand Down Expand Up @@ -265,7 +340,7 @@ public void testRGBIrToRGB() throws IOException {
// System.out.println(solidCoverage);
assertBandNames(solidCoverage, "Red", "Green", "Blue");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}

// dynamic tx due to footprint
Expand All @@ -275,7 +350,7 @@ public void testRGBIrToRGB() throws IOException {
// System.out.println(txCoverage);
assertBandNames(txCoverage, "Red", "Green", "Blue", "ALPHA_BAND");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}
}

Expand All @@ -294,7 +369,7 @@ public void testRGBIrToIr() throws IOException {
// System.out.println(solidCoverage);
assertBandNames(solidCoverage, "Infrared");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}

// get IR, dynamic tx due to footprint
Expand All @@ -304,7 +379,7 @@ public void testRGBIrToIr() throws IOException {
// System.out.println(txCoverage);
assertBandNames(txCoverage, "Infrared", "ALPHA_BAND");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}
}

Expand All @@ -323,7 +398,7 @@ public void testRGBIrToIrGB() throws IOException {
// System.out.println(solidCoverage);
assertBandNames(solidCoverage, "Infrared", "Green", "Blue");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}

// get IR, dynamic tx due to footprint
Expand All @@ -333,7 +408,7 @@ public void testRGBIrToIrGB() throws IOException {
// System.out.println(txCoverage);
assertBandNames(txCoverage, "Infrared", "Green", "Blue", "ALPHA_BAND");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}
}

Expand All @@ -352,7 +427,7 @@ public void testRGBIrToRed() throws IOException {
// System.out.println(solidCoverage);
assertBandNames(solidCoverage, "Red");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}

// get IR, dynamic tx due to footprint
Expand All @@ -362,7 +437,7 @@ public void testRGBIrToRed() throws IOException {
// System.out.println(txCoverage);
assertBandNames(txCoverage, "Red", "ALPHA_BAND");
} finally {
((GridCoverage2D) solidCoverage).dispose(true);
disposeCoverage(solidCoverage);
}
}

Expand Down Expand Up @@ -751,4 +826,17 @@ public void testCoverageViewGranuleSourceAggregation() throws Exception {
granules.accepts(visitor, null);
assertEquals("20170410T103021026Z_fullres_CC2.1989_T32TMT_B01.tif", visitor.getMin());
}

@Test
public void testBandsFlagsView() throws Exception {
// creation in the setup would have failed before the fix for
// [GEOT-6168] CoverageView setup fails if one of the source bands has an indexed color
// model

CoverageInfo info = getCatalog().getCoverageByName(BANDS_FLAGS_VIEW);
GridCoverageReader reader = info.getGridCoverageReader(null, null);
GridCoverage2D coverage = (GridCoverage2D) reader.read(null);
assertEquals(11, coverage.getRenderedImage().getSampleModel().getNumBands());
coverage.dispose(true);
}
}
Binary file not shown.

0 comments on commit 0d35fb6

Please sign in to comment.