package org.geotools.coverage.grid.imageio.geotiff.metadata; import it.geosolutions.imageio.plugins.tiff.GeoTIFFTagSet; import java.awt.geom.AffineTransform; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.metadata.IIOMetadataNode; import org.geotools.coverage.grid.io.imageio.geotiff.GeoTiffConstants; import org.geotools.coverage.grid.io.imageio.geotiff.PixelScale; import org.geotools.coverage.grid.io.imageio.geotiff.TiePoint; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * * @source $URL$ */ public class GeoTiffMetadataUtilities { /** {@link Logger}. */ private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(GeoTiffMetadataUtilities.class); static PixelScale calculateModelPixelScales(Node rootNode) { final double[] pixScales = getTiffDoubles(getTiffField(rootNode, GeoTIFFTagSet.TAG_MODEL_PIXEL_SCALE)); if (pixScales == null||pixScales.length<=0) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,"Unable to find the model pixel scale tag"); return null; } PixelScale retVal = new PixelScale(); for (int i = 0; i < pixScales.length; i++) switch (i) { case 0: retVal.setScaleX(pixScales[i]); break; case 1: retVal.setScaleY(pixScales[i]); break; case 2: retVal.setScaleZ(pixScales[i]); break; } return retVal; } static TiePoint[] calculateTiePoints(Node rootNode) { IIOMetadataNode node = getTiffField(rootNode, GeoTIFFTagSet.TAG_MODEL_TIE_POINT); if (node == null) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,"Unable to find the model tie points tag"); } final double tiePoints[] = getTiffDoubles(node); if (tiePoints == null || tiePoints.length <= 0) { return null; } final int numTiePoints = tiePoints.length / 6; final TiePoint retVal[] = new TiePoint[numTiePoints]; int initialIndex = 0; for (int i = 0; i < numTiePoints; i++) { initialIndex = i * 6; retVal[i] = new TiePoint(tiePoints[initialIndex], tiePoints[initialIndex + 1], tiePoints[initialIndex + 2], tiePoints[initialIndex + 3], tiePoints[initialIndex + 4], tiePoints[initialIndex + 5]); } return retVal; } static double calculateNoData(Node rootNode) { final IIOMetadataNode noDataNode = getTiffField(rootNode, GeoTiffConstants.TIFFTAG_NODATA); if (noDataNode == null) { return Double.NaN; } final String noData = getTiffAscii(noDataNode); if (noData == null) { return Double.NaN; } try { return Double.parseDouble(noData); } catch (NumberFormatException nfe) { if(LOGGER.isLoggable(Level.INFO)) LOGGER.log(Level.INFO,nfe.getLocalizedMessage(),nfe); return Double.NaN; } } static AffineTransform calculateModelTransformation(Node rootNode) { final IIOMetadataNode node = getTiffField(rootNode, GeoTIFFTagSet.TAG_MODEL_TRANSFORMATION); if (node == null) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,"Unable to find the model transfomation tag"); return null; } final double[] modelTransformation = getTiffDoubles(node); if (modelTransformation == null) { return null; } AffineTransform transform = null; if (modelTransformation.length == 9) { transform = new AffineTransform( modelTransformation[0], modelTransformation[4], modelTransformation[1], modelTransformation[5], modelTransformation[6], modelTransformation[7]); } else if (modelTransformation.length == 16) { transform = new AffineTransform( modelTransformation[0], modelTransformation[4], modelTransformation[1], modelTransformation[5], modelTransformation[3], modelTransformation[7]); } return transform; } /** * Gets the value attribute of the given Node. * * @param node * A Node containing a value attribute, for example the node <TIFFShort * value="123"> * * @return A String containing the text from the value attribute. In the above example, the * string would be 123 */ static String getValueAttribute(Node node) { return node.getAttributes().getNamedItem(GeoTiffConstants.VALUE_ATTRIBUTE).getNodeValue(); } /** * Gets the value attribute's contents and parses it as an int * * @param node * DOCUMENT ME! * * @return DOCUMENT ME! */ static int getIntValueAttribute(Node node) { return Integer.parseInt(getValueAttribute(node)); } /** * Gets a TIFFField node with the given tag number. This is done by searching for a TIFFField * with attribute number whose value is the specified tag value. * * @param tag DOCUMENT ME! * * @return DOCUMENT ME! */ static IIOMetadataNode getTiffField(Node rootNode, final int tag) { Node node = rootNode.getFirstChild(); final String tag_=Integer.toString(tag); if (node != null){ node = node.getFirstChild(); for (; node != null; node = node.getNextSibling()) { Node number = node.getAttributes().getNamedItem(GeoTiffConstants.NUMBER_ATTRIBUTE); // TODO check this optimization // if (number != null && tag == Integer.parseInt(number.getNodeValue())) { if (number != null && tag_.equalsIgnoreCase(number.getNodeValue())) { return (IIOMetadataNode) node; } } } return null; } /** * Gets a single TIFFShort value at the given index. * * @param tiffField * An IIOMetadataNode pointing to a TIFFField element that contains a TIFFShorts * element. * @param index * The 0-based index of the desired short value * * @return DOCUMENT ME! */ static int getTiffShort(final IIOMetadataNode tiffField, final int index) { return getIntValueAttribute(((IIOMetadataNode) tiffField.getFirstChild()) .getElementsByTagName(GeoTiffConstants.GEOTIFF_SHORT_TAG).item(index)); } /** * Gets an array of double values from a TIFFDoubles TIFFField. * * @param tiffField * An IIOMetadataNode pointing to a TIFFField element that contains a TIFFDoubles * element. * * @return DOCUMENT ME! */ static double[] getTiffDoubles(final IIOMetadataNode tiffField) { if (tiffField == null) { return null; } final NodeList doubles = ((IIOMetadataNode) tiffField.getFirstChild()) .getElementsByTagName(GeoTiffConstants.GEOTIFF_DOUBLE_TAG); final int length = doubles.getLength(); final double[] result = new double[length]; for (int i = 0; i < length; i++) { result[i] = Double.parseDouble(getValueAttribute(doubles.item(i))); } return result; } /** * Gets a portion of a TIFFAscii string with the specified start character and length; * * @param tiffField * An IIOMetadataNode pointing to a TIFFField element that contains a TIFFAsciis * element. This element should contain a single TiffAscii element. * @param start * DOCUMENT ME! * @param length * DOCUMENT ME! * * @return A substring of the value contained in the TIFFAscii node, with the final '|' * character removed. */ static String getTiffAscii(final IIOMetadataNode tiffField, int start, int length) { // there should be only one, so get the first // GeoTIFFWritingUtilities specification places a vertical bar '|' in // place of \0 // null delimiters so drop off the vertical bar for Java Strings final String valueAttribute = getValueAttribute(((IIOMetadataNode) tiffField .getFirstChild()).getElementsByTagName(GeoTiffConstants.GEOTIFF_ASCII_TAG).item(0)); if (start == -1) start = 0; if (length == -1) length = valueAttribute.length() + 1; return valueAttribute.substring(start, start + length - 1); } /** * Gets the TIFFAscii string * * @param tiffField * An IIOMetadataNode pointing to a TIFFField element that contains a TIFFAsciis * element. This element should contain a single TIFFAscii element. * * @return The value contained in the TIFFAscii node, with the final '|' character removed. */ static String getTiffAscii(final IIOMetadataNode tiffField) { return getTiffAscii(tiffField, -1, -1); } }