Skip to content

Commit 2f2c7bf

Browse files
committed
Issue geosolutions-it#328: GDAL reading reduced bands
1 parent 5141a3b commit 2f2c7bf

File tree

4 files changed

+167
-9
lines changed

4 files changed

+167
-9
lines changed

library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALCommonIIOImageMetadata.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,12 @@
4343
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.FieldDefn;
4444
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.FieldType;
4545
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.GDALRasterAttributeTable;
46-
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Histograms;
47-
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Histograms.HistItem;
4846
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Metadata;
4947
import it.geosolutions.imageio.pam.PAMDataset.PAMRasterBand.Row;
5048
import org.gdal.gdal.Band;
5149
import org.gdal.gdal.ColorTable;
5250
import org.gdal.gdal.Dataset;
5351
import org.gdal.gdal.Driver;
54-
import org.gdal.gdal.InfoOptions;
5552
import org.gdal.gdal.RasterAttributeTable;
5653
import org.gdal.gdal.gdal;
5754
import org.gdal.gdalconst.gdalconst;

library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALImageReader.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -850,30 +850,38 @@ public BufferedImage read(final int imageIndex,final ImageReadParam param)throw
850850
final int width = item.getWidth();
851851
final int height = item.getHeight();
852852
final SampleModel itemSampleModel = item.getSampleModel();
853-
int itemNBands = itemSampleModel.getNumBands();
854-
int nDestBands;
855-
856853
BufferedImage bi = null;
857854
final ImageReadParam imageReadParam;
858855
if (param == null)
859856
imageReadParam = getDefaultReadParam();
860857
else
861858
imageReadParam = param;
862859

860+
int itemNBands = itemSampleModel.getNumBands();
861+
int[] srcBands = GDALUtilities.extractBands(imageReadParam);
862+
int[] destBands = imageReadParam.getDestinationBands();
863+
int nDestBands;
864+
863865
// //
864866
//
865867
// First, check for a specified ImageTypeSpecifier
866868
//
867869
// //
868870
ImageTypeSpecifier imageType = imageReadParam.getDestinationType();
869871
SampleModel destSampleModel = null;
872+
873+
// Set number of destination bands
870874
if (imageType != null) {
871875
destSampleModel = imageType.getSampleModel();
872876
nDestBands = destSampleModel.getNumBands();
873877
} else {
874878
bi = imageReadParam.getDestination();
875879
if (bi != null)
876880
nDestBands = bi.getSampleModel().getNumBands();
881+
else if (destBands != null)
882+
nDestBands = destBands.length;
883+
else if (srcBands != null)
884+
nDestBands = srcBands.length;
877885
else
878886
nDestBands = itemNBands;
879887
}
@@ -884,8 +892,7 @@ public BufferedImage read(final int imageIndex,final ImageReadParam param)throw
884892
//
885893
// //
886894
checkReadParamBandSettings(imageReadParam, itemNBands, nDestBands);
887-
int[] srcBands = imageReadParam.getSourceBands();
888-
// int[] destBands = imageReadParam.getDestinationBands();
895+
889896
//
890897
// //
891898
//
@@ -939,7 +946,7 @@ public BufferedImage read(final int imageIndex,final ImageReadParam param)throw
939946
// //
940947
ColorModel cm;
941948
if (imageType == null) {
942-
cm = item.getColorModel();
949+
cm = GDALUtilities.extractColorModel(item.getColorModel(), item.getSampleModel(), nDestBands);
943950
bi = new BufferedImage(cm, (WritableRaster) readDatasetRaster(
944951
item, srcRegion, destRegion, srcBands,null), false, null);
945952
} else {

library/gdalframework/src/main/java/it/geosolutions/imageio/gdalframework/GDALUtilities.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.logging.Level;
3535
import java.util.logging.Logger;
3636

37+
import javax.imageio.ImageReadParam;
3738
import javax.imageio.ImageReader;
3839
import javax.imageio.metadata.IIOMetadataFormat;
3940
import javax.imageio.metadata.IIOMetadataFormatImpl;
@@ -46,6 +47,8 @@
4647
import javax.media.jai.JAI;
4748
import javax.media.jai.RasterFactory;
4849

50+
import com.sun.media.imageioimpl.common.BogusColorSpace;
51+
import it.geosolutions.imageio.imageioimpl.EnhancedImageReadParam;
4952
import org.gdal.gdal.Dataset;
5053
import org.gdal.gdal.Driver;
5154
import org.gdal.gdal.gdal;
@@ -764,6 +767,99 @@ public static ColorModel buildColorModel(final SampleModel sampleModel) {
764767
return colorModel;
765768
}
766769

770+
/**
771+
* Extracts the bands from the provided {@link ImageReadParam},
772+
* with EnhancedImageReadParam.getBands() taking precedence
773+
* over ImageReadParam.getSourceBands() and overriding it.
774+
*
775+
* @param imageReadParam
776+
* @return
777+
*/
778+
public static int[] extractBands(ImageReadParam imageReadParam) {
779+
int[] srcBands = imageReadParam.getSourceBands();
780+
if (imageReadParam instanceof EnhancedImageReadParam) {
781+
// Let's check if the EnhancedImageReadParam has been set and it contains
782+
// a bands array. In that case, this will take precedence over the srcBands
783+
final EnhancedImageReadParam eparam = (EnhancedImageReadParam) imageReadParam;
784+
if (eparam.getBands() != null) {
785+
srcBands = eparam.getBands();
786+
imageReadParam.setSourceBands(srcBands);
787+
}
788+
}
789+
return srcBands;
790+
}
791+
792+
/**
793+
* Extracts a {@link ColorModel} given a source ColorModel, a
794+
* provided {@link SampleModel} and a number of destination bands.
795+
* If the number of bands in the provided {@link SampleModel} matches
796+
* the destination number of bands, the source color model is returned.
797+
*
798+
* @param cm
799+
* the original ColorModel.
800+
* @param sm
801+
* the SampleModel to be used as reference.
802+
* @param destNumBands
803+
* the number of bands to be used for extracting the ColorModel.
804+
* @return a new ColorModel based on the provided parameters.
805+
*/
806+
public static ColorModel extractColorModel(ColorModel cm, SampleModel sm, int destNumBands) {
807+
int dataType = sm.getDataType();
808+
809+
if (sm.getNumBands() != destNumBands) {
810+
boolean hasAlpha = (destNumBands == 2 || destNumBands == 4) && cm.hasAlpha();
811+
int transparency = hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
812+
813+
// Choose color space based on band count
814+
ColorSpace cs;
815+
if (destNumBands == 1 || destNumBands == 2) {
816+
cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
817+
} else if (destNumBands == 3 || destNumBands == 4) {
818+
cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
819+
} else {
820+
cs = new BogusColorSpace(destNumBands);
821+
}
822+
823+
// Validate compatibility for float/double types
824+
if (isSupportedColorModel(cs, hasAlpha, dataType)) {
825+
cm = buildColorModel(cs, hasAlpha, transparency, dataType);
826+
} else {
827+
// Fall back to generic model if the requested one is invalid
828+
cm = buildColorModel(new BogusColorSpace(destNumBands), false, Transparency.OPAQUE, dataType);
829+
}
830+
}
831+
832+
return cm;
833+
}
834+
835+
private static ColorModel buildColorModel(ColorSpace cs, boolean hasAlpha, int transparency, int dataType) {
836+
return new ComponentColorModel(cs, hasAlpha, false, transparency, dataType);
837+
}
838+
839+
/**
840+
* Check if the combination is valid for ComponentColorModel.
841+
*/
842+
private static boolean isSupportedColorModel(ColorSpace cs, boolean hasAlpha, int dataType) {
843+
int numComponents = cs.getNumComponents() + (hasAlpha ? 1 : 0);
844+
boolean isFloatLike = dataType == DataBuffer.TYPE_FLOAT || dataType == DataBuffer.TYPE_DOUBLE;
845+
846+
// Disallow RGB for float/double data types
847+
// TODO: RGB are supported using FloatDoubleColorModel with normalized pixels in range [0,1]
848+
// Skip that case for now
849+
if (isFloatLike && cs == ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
850+
return false;
851+
}
852+
853+
// Allow GRAY with float/double
854+
if (isFloatLike && cs == ColorSpace.getInstance(ColorSpace.CS_GRAY) && numComponents <= 2) {
855+
return true;
856+
}
857+
858+
// Allow all other types
859+
return !isFloatLike;
860+
}
861+
862+
767863
//
768864
// Provides to retrieve projections from the provided {@lik RenderedImage}
769865
// and return the String containing properly formatted text.

plugin/gdal/gdalvrt/src/test/java/it/geosolutions/imageio/plugins/vrt/ErdasImgVrtTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,24 @@
1717
package it.geosolutions.imageio.plugins.vrt;
1818

1919
import it.geosolutions.imageio.gdalframework.AbstractGDALTest;
20+
import it.geosolutions.imageio.gdalframework.GDALUtilities;
2021
import it.geosolutions.imageio.gdalframework.Viewer;
2122
import it.geosolutions.imageio.utilities.ImageIOUtilities;
2223
import it.geosolutions.resources.TestData;
2324
import org.junit.Assert;
2425
import org.junit.Test;
2526

27+
import javax.imageio.ImageReadParam;
28+
import javax.media.jai.ImageLayout;
2629
import javax.media.jai.JAI;
2730
import javax.media.jai.ParameterBlockJAI;
2831
import javax.media.jai.RenderedOp;
32+
import java.awt.*;
33+
import java.awt.color.ColorSpace;
34+
import java.awt.image.ColorModel;
35+
import java.awt.image.ComponentSampleModel;
36+
import java.awt.image.DataBuffer;
37+
import java.awt.image.SampleModel;
2938
import java.io.File;
3039
import java.io.FileNotFoundException;
3140
import java.io.IOException;
@@ -69,4 +78,53 @@ public void jaiOperations() throws FileNotFoundException, IOException {
6978
ImageIOUtilities.disposeImage(image);
7079
}
7180

81+
@Test
82+
public void bandSelection() throws FileNotFoundException, IOException {
83+
if (!isGDALAvailable) {
84+
return;
85+
}
86+
File file = TestData.file(this, fileName);
87+
88+
// ////////////////////////////////////////////////////////////////
89+
// preparing to read
90+
// ////////////////////////////////////////////////////////////////
91+
final ParameterBlockJAI pbjImageRead;
92+
pbjImageRead = new ParameterBlockJAI("ImageRead");
93+
pbjImageRead.setParameter("Input", file);
94+
ImageReadParam param = new ImageReadParam();
95+
param.setSourceBands(new int[] { 2 });
96+
97+
SampleModel originalSampleModel = new ComponentSampleModel(
98+
DataBuffer.TYPE_FLOAT, 256, 256, 3, 256 * 3, new int[] {0,1,2});
99+
SampleModel sm = new ComponentSampleModel(
100+
DataBuffer.TYPE_FLOAT, 256, 256, 1, 256, new int[] {0});
101+
102+
ColorModel cm = GDALUtilities.extractColorModel(null, originalSampleModel, 1);
103+
104+
ImageLayout layout = new ImageLayout().setTileHeight(256).setTileWidth(256);
105+
layout.setColorModel(cm);
106+
layout.setSampleModel(sm);
107+
RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
108+
109+
// get a RenderedImage
110+
RenderedOp image = JAI.create("ImageRead", pbjImageRead, hints);
111+
112+
sm = image.getSampleModel();
113+
cm = image.getColorModel();
114+
ColorSpace colorSpace = cm.getColorSpace();
115+
// Original image is RGB: 400x200 pixels, 3 bands
116+
// Let's verify we only get one band image with
117+
// the databuffer only containing one band pixels
118+
Assert.assertEquals(1, sm.getNumBands());
119+
Assert.assertEquals(1, cm.getNumComponents());
120+
Assert.assertEquals(ColorSpace.TYPE_GRAY, colorSpace.getType());
121+
Assert.assertEquals(400*200*1, image.getData().getDataBuffer().getSize());
122+
123+
if (TestData.isInteractiveTest())
124+
Viewer.visualizeAllInformation(image, "Read");
125+
else
126+
Assert.assertNotNull(image.getTiles());
127+
ImageIOUtilities.disposeImage(image);
128+
}
129+
72130
}

0 commit comments

Comments
 (0)