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
commit 67c5d18936c47de51f842a93bbcb597f8d42918b Author: Martin Desruisseaux <[email protected]> AuthorDate: Thu Dec 19 18:51:17 2019 +0100 Add an `ImageUtilities` class for methods to be needed by `GridCoverage2D`. --- .../sis/internal/coverage/ImageUtilities.java | 154 +++++++++++++++++++++ .../sis/internal/coverage/ImageUtilitiesTest.java | 77 +++++++++++ .../apache/sis/test/suite/FeatureTestSuite.java | 1 + .../org/apache/sis/util/resources/Vocabulary.java | 45 ++++++ .../sis/util/resources/Vocabulary.properties | 9 ++ .../sis/util/resources/Vocabulary_fr.properties | 9 ++ 6 files changed, 295 insertions(+) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/ImageUtilities.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/ImageUtilities.java new file mode 100644 index 0000000..73fa6aa --- /dev/null +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/ImageUtilities.java @@ -0,0 +1,154 @@ +/* + * 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.internal.coverage; + +import java.util.Arrays; +import java.awt.color.ColorSpace; +import java.awt.image.ColorModel; +import java.awt.image.PackedColorModel; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import org.apache.sis.internal.system.Modules; +import org.apache.sis.util.logging.Logging; +import org.apache.sis.util.resources.Vocabulary; + + +/** + * Utility methods related to images and their color model or sample model. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.1 + * @since 1.1 + * @module + */ +public final class ImageUtilities { + /** + * Do not allow instantiation of this class. + */ + private ImageUtilities() { + } + + /** + * Returns names of bands based on inspection of the color model. + * The bands are identified by {@link Vocabulary.Keys} values for + * red, green, blue, cyan, magenta, yellow, black, gray, <i>etc</i>. + * If a band can not be identified, then its corresponding value is 0. + * + * @param image the image for which to get band names (can not be null). + * @return {@link Vocabulary.Keys} identifying the bands. + */ + @SuppressWarnings("fallthrough") + public static short[] bandNames(final RenderedImage image) { + final SampleModel sm = image.getSampleModel(); + final int n; + if (sm != null) { + n = sm.getNumBands(); + } else { + // Should not happen since SampleModel is essential, but we try to be robust. + n = image.getTile(image.getMinTileX(), image.getMinTileY()).getNumBands(); + } + final short[] keys = new short[n]; + final ColorModel cm = image.getColorModel(); + if (cm != null) { + final ColorSpace cs = cm.getColorSpace(); + if (cs != null) { + /* + * Get one of the following sets of color names (ignoring order for now): + * + * - Red, Green, Blue + * - Cyan, Magenta, Yellow, Black + * - Gray + */ + switch (cs.getType()) { + case ColorSpace.TYPE_CMYK: { + if (n >= 4) keys[3] = Vocabulary.Keys.Black; + // Fallthrough + } + case ColorSpace.TYPE_CMY: { + switch (n) { + default: keys[2] = Vocabulary.Keys.Yellow; // Fallthrough everywhere. + case 2: keys[1] = Vocabulary.Keys.Magenta; + case 1: keys[0] = Vocabulary.Keys.Cyan; + case 0: break; + } + break; + } + case ColorSpace.TYPE_RGB: { + switch (n) { + default: keys[2] = Vocabulary.Keys.Blue; // Fallthrough everywhere. + case 2: keys[1] = Vocabulary.Keys.Green; + case 1: keys[0] = Vocabulary.Keys.Red; + case 0: break; + } + break; + } + case ColorSpace.TYPE_GRAY: { + if (n != 0) keys[0] = Vocabulary.Keys.Gray; + break; + } + } + /* + * If the color model has more components than the number of colors, + * then the additional component is an alpha channel. + */ + final int nc = cm.getNumColorComponents(); + if (nc < n && nc < cm.getNumComponents()) { + keys[nc] = Vocabulary.Keys.Transparency; + } + /* + * In current version we do not try to adapt the bands order to the masks. + * A few tests suggest that the following methods provide the same values: + * + * - PackedColorModel.getMasks() + * - SinglePixelPackedSampleModel.getBitMasks() + * + * For a BufferedImage.TYPE_INT_ARGB, both methods give in that order: + * + * masks[0]: 00FF0000 (red) + * masks[1]: 0000FF00 (green) + * masks[2]: 000000FF (blue) + * masks[3]: FF000000 (alpha) — this last element is absent with TYPE_INT_RGB. + * + * For a BufferedImage.TYPE_INT_BGR, both methods give in that order: + * + * masks[0]: 000000FF (red) + * masks[1]: 0000FF00 (green) + * masks[2]: 00FF0000 (blue) + * + * So it looks like that SampleModel already normalizes the color components + * to (Red, Green, Blue) order, at least when the image has been created with + * a standard constructor. However we do not know yet what would be the behavior + * if masks are not the same. For now we just log a warning. + */ + int[] m1 = null; + int[] m2 = null; + if (cm instanceof PackedColorModel) { + m1 = ((PackedColorModel) cm).getMasks(); + } + if (sm instanceof SinglePixelPackedSampleModel) { + m2 = ((SinglePixelPackedSampleModel) sm).getBitMasks(); + } + if (!Arrays.equals(m1, m2)) { + // If this logging happen, we should revisit this method and improve it. + Logging.getLogger(Modules.RASTER).warning("Band names may be in wrong order."); + } + } + } + return keys; + } +} diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/ImageUtilitiesTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/ImageUtilitiesTest.java new file mode 100644 index 0000000..ba21f6c --- /dev/null +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/ImageUtilitiesTest.java @@ -0,0 +1,77 @@ +/* + * 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.internal.coverage; + +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import org.apache.sis.util.resources.Vocabulary; +import org.apache.sis.test.TestCase; +import org.junit.Test; + +import static org.junit.Assert.*; + + +/** + * Tests {@link ImageUtilities}. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.1 + * @since 1.1 + * @module + */ +public final strictfp class ImageUtilitiesTest extends TestCase { + /** + * Tests {@link ImageUtilities#bandNames(RenderedImage)}. + */ + @Test + public void testBandNames() { + RenderedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + assertArrayEquals(new short[] { + Vocabulary.Keys.Red, + Vocabulary.Keys.Green, + Vocabulary.Keys.Blue, + Vocabulary.Keys.Transparency + }, ImageUtilities.bandNames(image)); + /* + * Same as above, but without alpha channel. + */ + image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + assertArrayEquals(new short[] { + Vocabulary.Keys.Red, + Vocabulary.Keys.Green, + Vocabulary.Keys.Blue + }, ImageUtilities.bandNames(image)); + /* + * Same as above but in sample values packed in reverse order. Note that while values + * are packed in BGR order, the sample model is still providing the values in RGB order. + * For that reason, the band order below is the same than in above test. + */ + image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_BGR); + assertArrayEquals(new short[] { + Vocabulary.Keys.Red, + Vocabulary.Keys.Green, + Vocabulary.Keys.Blue + }, ImageUtilities.bandNames(image)); + /* + * One-banded image. + */ + image = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY); + assertArrayEquals(new short[] { + Vocabulary.Keys.Gray + }, ImageUtilities.bandNames(image)); + } +} diff --git a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java index 2a59156..edd4256 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java +++ b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java @@ -85,6 +85,7 @@ import org.junit.runners.Suite; org.apache.sis.coverage.CategoryListTest.class, org.apache.sis.coverage.SampleDimensionTest.class, org.apache.sis.coverage.SampleRangeFormatTest.class, + org.apache.sis.internal.coverage.ImageUtilitiesTest.class, org.apache.sis.internal.coverage.ScaledColorSpaceTest.class, org.apache.sis.internal.coverage.BufferedGridCoverageTest.class, org.apache.sis.internal.coverage.GridCoverage2DTest.class, diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java index 23aeb70..cf576a6 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java +++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java @@ -122,6 +122,16 @@ public final class Vocabulary extends IndexedResourceBundle { public static final short BarometricAltitude = 13; /** + * Black + */ + public static final short Black = 175; + + /** + * Blue + */ + public static final short Blue = 176; + + /** * Cardinality */ public static final short Cardinality = 14; @@ -217,6 +227,11 @@ public final class Vocabulary extends IndexedResourceBundle { public static final short CurrentDirectory = 32; /** + * Cyan + */ + public static final short Cyan = 177; + + /** * Cycle omitted */ public static final short CycleOmitted = 33; @@ -407,6 +422,16 @@ public final class Vocabulary extends IndexedResourceBundle { public static final short GeographicIdentifier = 70; /** + * Gray + */ + public static final short Gray = 178; + + /** + * Green + */ + public static final short Green = 179; + + /** * Grid extent */ public static final short GridExtent = 71; @@ -527,6 +552,11 @@ public final class Vocabulary extends IndexedResourceBundle { public static final short LowerBound = 94; /** + * Magenta + */ + public static final short Magenta = 180; + + /** * Mandatory */ public static final short Mandatory = 95; @@ -692,6 +722,11 @@ public final class Vocabulary extends IndexedResourceBundle { public static final short Read = 127; /** + * Red + */ + public static final short Red = 181; + + /** * Remarks */ public static final short Remarks = 128; @@ -822,6 +857,11 @@ public final class Vocabulary extends IndexedResourceBundle { public static final short TransformationAccuracy = 152; /** + * Transparency + */ + public static final short Transparency = 183; + + /** * Truncated Julian */ public static final short TruncatedJulian = 153; @@ -925,6 +965,11 @@ public final class Vocabulary extends IndexedResourceBundle { * Write */ public static final short Write = 173; + + /** + * Yellow + */ + public static final short Yellow = 182; } /** diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties index 56682fe..89741cf 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties +++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties @@ -27,6 +27,8 @@ AxisChanges = Axis changes Azimuth = Azimuth Band_1 = Band {0} BarometricAltitude = Barometric altitude +Black = Black +Blue = Blue Cardinality = Cardinality CausedBy_1 = Caused by {0} CellCount_1 = {0} cells @@ -47,6 +49,7 @@ Create = Create CurrentDateTime = Current date and time CurrentDirectory = Current directory CycleOmitted = Cycle omitted +Cyan = Cyan DataBase = Database DataDirectory = Data directory DataFormats = Data formats @@ -84,6 +87,8 @@ GeodesicDistance = Geodesic distance GeodeticDataset = Geodetic dataset GeographicExtent = Geographic extent GeographicIdentifier = Geographic identifier +Gray = Gray +Green = Green GridExtent = Grid extent Height = Height Identifier = Identifier @@ -108,6 +113,7 @@ Localization = Localization LocationType = Location type Logging = Logging LowerBound = Lower bound +Magenta = Magenta Mandatory = Mandatory Mapping = Mapping MaximumValue = Maximum value @@ -141,6 +147,7 @@ Plugins = Plug-ins Preprocessing = Preprocessing Quoted_1 = \u201c{0}\u201d Read = Read +Red = Red Remarks = Remarks RemoteConfiguration = Remote configuration RepresentativeValue = Representative value @@ -167,6 +174,7 @@ Time_1 = {0} time Timezone = Timezone Transformation = Transformation TransformationAccuracy = Transformation accuracy +Transparency = Transparency TruncatedJulian = Truncated Julian Type = Type Unknown = Unknown @@ -188,3 +196,4 @@ Warnings = Warnings WestBound = West bound World = World Write = Write +Yellow = Yellow diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties index 0e80ee4..e9e6323 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties +++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties @@ -34,6 +34,8 @@ AxisChanges = Changements d\u2019axes Azimuth = Azimut Band_1 = Bande {0} BarometricAltitude = Altitude barom\u00e9trique +Black = Noir +Blue = Bleu Cardinality = Cardinalit\u00e9 CausedBy_1 = Caus\u00e9e par {0} CellCount_1 = {0} cellules @@ -53,6 +55,7 @@ CoverageDomain = Domaine de la couverture de donn\u00e9es Create = Cr\u00e9ation CurrentDateTime = Date et heure courantes CurrentDirectory = R\u00e9pertoire courant +Cyan = Cyan CycleOmitted = Cycle omit DataBase = Base de donn\u00e9es DataDirectory = R\u00e9pertoire des donn\u00e9es @@ -91,6 +94,8 @@ GeodesicDistance = Distance g\u00e9od\u00e9sique GeodeticDataset = Base de donn\u00e9es g\u00e9od\u00e9sique GeographicExtent = \u00c9tendue g\u00e9ographique GeographicIdentifier = Identifiant g\u00e9ographique +Gray = Gris +Green = Vert GridExtent = \u00c9tendue de la grille Height = Hauteur Identifier = Identifiant @@ -115,6 +120,7 @@ Localization = R\u00e9gionalisation LocationType = Type de location Logging = Journalisation LowerBound = Limite basse +Magenta = Magenta Mandatory = Requis Mapping = Cartographie MaximumValue = Valeur maximale @@ -148,6 +154,7 @@ Plugins = Modules d\u2019extension Preprocessing = Pr\u00e9traitement Quoted_1 = \u00ab\u202f{0}\u202f\u00bb Read = Lecture +Red = Rouge Remarks = Remarques RemoteConfiguration = Configuration distante RepresentativeValue = Valeur repr\u00e9sentative @@ -174,6 +181,7 @@ Time_1 = Heure {0} Timezone = Fuseau horaire Transformation = Transformation TransformationAccuracy = Pr\u00e9cision de la transformation +Transparency = Transparence TruncatedJulian = Julien tronqu\u00e9 Type = Type Unknown = Inconnu @@ -195,3 +203,4 @@ Warnings = Avertissements WestBound = Limite ouest World = Monde Write = \u00c9criture +Yellow = Jaune
