diff --git a/library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALCommonIIOImageMetadata.java b/library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALCommonIIOImageMetadata.java index a462015b2..b990cb691 100644 --- a/library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALCommonIIOImageMetadata.java +++ b/library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALCommonIIOImageMetadata.java @@ -39,15 +39,27 @@ import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; +import it.geosolutions.imageio.pam.PAMDataset; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.FieldDefn; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.FieldType; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.GDALRasterAttributeTable; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Histograms; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Histograms.HistItem; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Metadata; +import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Row; import org.gdal.gdal.Band; import org.gdal.gdal.ColorTable; import org.gdal.gdal.Dataset; import org.gdal.gdal.Driver; +import org.gdal.gdal.InfoOptions; +import org.gdal.gdal.RasterAttributeTable; import org.gdal.gdal.gdal; import org.gdal.gdalconst.gdalconst; import org.gdal.gdalconst.gdalconstConstants; import org.w3c.dom.Node; +import static it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.FieldUsage.fromValue; + /** * Class needed to store all available information of a GDAL Dataset with the * add of additional information. For convenience and future re-use this class @@ -68,6 +80,7 @@ public class GDALCommonIIOImageMetadata extends CoreCommonImageMetadata { * domain, the ImageStructure domain, as well as any xml prefixed domain) */ Map> gdalDomainMetadataMap; + private PAMDataset pamDataSet; /** * GDALCommonIIOImageMetadata constructor. Firstly, it @@ -248,6 +261,79 @@ private void setGeoreferencingInfo(final Dataset dataset) { setProjection(dataset.GetProjection()); setGcpProjection(dataset.GetGCPProjection()); setGcpNumber(dataset.GetGCPCount()); + setPamDataset(dataset); + } + public PAMDataset getPamDataset() { + return pamDataSet; + } + + /** + * Creates a PAMDataset object form internal metadata, rather than from an auxiliary xml file. + * @param dataset + */ + private void setPamDataset(Dataset dataset) { + PAMDataset pd = new PAMDataset(); + + int bandCount = dataset.getRasterCount(); + for (int b = 1; b <= bandCount; b++) { + Band band = dataset.GetRasterBand(b); + PAMDataset.PAMRasterBand pdBand = new PAMDataset.PAMRasterBand(); + pdBand.setBand(b); + double min[] = new double[1]; + double max[] = new double[1]; + double mean[] = new double[1]; + double stddev[] = new double[1]; + // grab stats if available, but don't force creation + if (band.GetStatistics(false, false, min, max, mean, stddev) != gdalconstConstants.CE_None) { + Metadata metadata = new Metadata(); + List mdis = metadata.getMDI(); + mdis.add(createMDI("STATISTICS_MINIMUM", min[0])); + mdis.add(createMDI("STATISTICS_MAXIMUM", max[0])); + mdis.add(createMDI("STATISTICS_MEAN", mean[0])); + mdis.add(createMDI("STATISTICS_STDDEV", stddev[0])); + pdBand.setMetadata(metadata); + } + setupRasterAttributeTable(band, pdBand); + band.delete(); + pd.getPAMRasterBand().add(pdBand); + } + this.pamDataSet = pd; + } + + private static void setupRasterAttributeTable(Band band, PAMDataset.PAMRasterBand pdBand) { + RasterAttributeTable rat = band.GetDefaultRAT(); + if (rat != null) { + GDALRasterAttributeTable pdRAT = new GDALRasterAttributeTable(); + List fields = pdRAT.getFieldDefn(); + int columns = rat.GetColumnCount(); + for (int i = 0; i < columns; i++) { + FieldDefn field = new FieldDefn(); + field.setIndex(i); + field.setName(rat.GetNameOfCol(i)); + field.setType(FieldType.fromValue(rat.GetTypeOfCol(i))); + field.setUsage(fromValue(rat.GetUsageOfCol(i))); + fields.add(field); + } + List pdRows = pdRAT.getRow(); + int rows = rat.GetRowCount(); + for (int r = 0; r < rows; r++) { + Row row = new Row(); + List values = row.getF(); + for (int c = 0; c < columns; c++) { + values.add(rat.GetValueAsString(r, c)); + } + pdRows.add(row); + } + pdBand.setGdalRasterAttributeTable(pdRAT); + rat.delete(); + } + } + + private Metadata.MDI createMDI(String key, Object value) { + Metadata.MDI mdi = new Metadata.MDI(); + mdi.setKey(key); + mdi.setValue(String.valueOf(value)); + return mdi; } /** diff --git a/plugin/gdal/gdalvrt/src/test/java/it/geosolutions/imageio/plugins/vrt/RasterAttributeTableTest.java b/plugin/gdal/gdalvrt/src/test/java/it/geosolutions/imageio/plugins/vrt/RasterAttributeTableTest.java new file mode 100644 index 000000000..0be4be681 --- /dev/null +++ b/plugin/gdal/gdalvrt/src/test/java/it/geosolutions/imageio/plugins/vrt/RasterAttributeTableTest.java @@ -0,0 +1,115 @@ +/* + * ImageI/O-Ext - OpenSource Java Image translation Library + * http://www.geo-solutions.it/ + * https://github.com/geosolutions-it/imageio-ext + * (C) 2023, GeoSolutions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package it.geosolutions.imageio.plugins.vrt; + +import it.geosolutions.imageio.gdalframework.AbstractGDALTest; +import it.geosolutions.imageio.gdalframework.GDALCommonIIOImageMetadata; +import it.geosolutions.imageio.gdalframework.Viewer; +import it.geosolutions.imageio.pam.PAMDataset; +import it.geosolutions.imageio.utilities.ImageIOUtilities; +import it.geosolutions.resources.TestData; +import org.junit.Assert; +import org.junit.Test; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.media.jai.JAI; +import javax.media.jai.ParameterBlockJAI; +import javax.media.jai.RenderedOp; +import java.awt.Rectangle; +import java.awt.image.RenderedImage; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Test reading RasterAttributeTable embedded inside VRT file + */ +public class RasterAttributeTableTest extends AbstractGDALTest { + public RasterAttributeTableTest() { + super(); + } + + + @Test + public void readImageIO() throws FileNotFoundException, IOException { + if (!isGDALAvailable) { + return; + } + final File file = TestData.file(this, "095b_dem_90m.asc.vrt"); + + + final Iterator it = ImageIO.getImageReaders(file); + assertTrue(it.hasNext()); + final ImageReader reader = (ImageReader) it.next(); + assertTrue(reader instanceof VRTImageReader); + reader.setInput(file); + + IIOMetadata genericMeta = reader.getImageMetadata(0); + assertTrue(genericMeta instanceof GDALCommonIIOImageMetadata); + + GDALCommonIIOImageMetadata gdalMeta = (GDALCommonIIOImageMetadata) genericMeta; + + PAMDataset pam = gdalMeta.getPamDataset(); + assertNotNull(pam); + + PAMDataset.PAMRasterBand band = pam.getPAMRasterBand().get(0); + PAMDataset.PAMRasterBand.GDALRasterAttributeTable rat = band.getGdalRasterAttributeTable(); + assertNotNull(rat); + + // Check each field + List fields = rat.getFieldDefn(); + assertEquals(3, fields.size()); + assertField(fields.get(0), "con_min", PAMDataset.PAMRasterBand.FieldType.Real, + PAMDataset.PAMRasterBand.FieldUsage.Min); + assertField(fields.get(1), "con_max", PAMDataset.PAMRasterBand.FieldType.Real, + PAMDataset.PAMRasterBand.FieldUsage.Max); + assertField(fields.get(2), "test", PAMDataset.PAMRasterBand.FieldType.String, + PAMDataset.PAMRasterBand.FieldUsage.Generic); + + // Check rows + List rows = rat.getRow(); + assertEquals(8, rows.size()); + + // one sample row + PAMDataset.PAMRasterBand.Row row = rows.get(1); + List fieldValues = row.getF(); + assertEquals("1.4", fieldValues.get(0)); + assertEquals("1.6", fieldValues.get(1)); + assertEquals("white", fieldValues.get(2)); + + reader.dispose(); + } + + + private void assertField(PAMDataset.PAMRasterBand.FieldDefn fieldDefn, String name, + PAMDataset.PAMRasterBand.FieldType type, + PAMDataset.PAMRasterBand.FieldUsage usage) { + assertEquals(name, fieldDefn.getName()); + assertEquals(type, fieldDefn.getType()); + assertEquals(usage, fieldDefn.getUsage()); + } +} + diff --git a/plugin/gdal/gdalvrt/src/test/resources/it/geosolutions/imageio/plugins/vrt/test-data/095b_dem_90m.asc.vrt b/plugin/gdal/gdalvrt/src/test/resources/it/geosolutions/imageio/plugins/vrt/test-data/095b_dem_90m.asc.vrt index 9cf68e120..f21fc50bc 100644 --- a/plugin/gdal/gdalvrt/src/test/resources/it/geosolutions/imageio/plugins/vrt/test-data/095b_dem_90m.asc.vrt +++ b/plugin/gdal/gdalvrt/src/test/resources/it/geosolutions/imageio/plugins/vrt/test-data/095b_dem_90m.asc.vrt @@ -11,5 +11,62 @@ + + + con_min + 1 + 3 + + + con_max + 1 + 4 + + + test + 2 + 0 + + + 1.000000023841858 + 1.200000023841858 + green + + + 1.4 + 1.6 + white + + + 2.4 + 2.6 + gold + + + 5.099999809265137 + 5.299999809265136 + blue + + + 7.200000190734864 + 7.400000190734863 + red + + + 9.000000381469727 + 9.200000381469726 + orange + + + 11.00000038146973 + 11.20000038146973 + black + + + 12.09999980926514 + 12.29999980926514 + purple + +