This discussion is archived
2 Replies Latest reply: Apr 21, 2012 8:56 PM by Maxideon RSS

Add geo tags to TIFF image

865020 Newbie
Currently Being Moderated
Hello ..
I struck with adding geotags such as GTModelType_TAG,GTRasterType_TAG,Projection_TAG etc.to TIFF image.Can i add tags to IIOMetadata or TIFFDirectory or anyother.Please suggest me ,if possible give code snippet also.

Is adding geotags is same as adding our own tag to TIFF image.

Thanks in advance.
  • 1. Re: Add geo tags to TIFF image
    Maxideon Explorer
    Currently Being Moderated
    Try this. This code assumes you hava JAI-ImageIO, and consequently have the ImageReader/Writer plugin for tiff files.
    public static IIOMetadata addGeoMeta(
            IIOMetadata existingMeta, 
            int[] geoKeyDirectory,
            double[] geoDoubleParams,
            String geoAsciiParams) {
    
        if(geoKeyDirectory.length%4 != 0) {
            throw new IllegalArgumentException("Keys come in blocks of 4.  The "
                    + "geoKeyDirectory needs to have a multiple length of 4.");
        }
    
        //some declarations from the various specificiations
        final String METADATA_FORMAT = 
                "com_sun_media_imageio_plugins_tiff_image_1.0";
        final String GEO_TAGSET = 
                "com.sun.media.imageio.plugins.tiff.GeoTIFFTagSet";
        final String GEO_KEY_TAG_NUMBER = "34735";
        final String GEO_KEY_TAG_NAME = "GeoKeyDirectory";
        final String GEO_DOUBLES_TAG_NUMBER = "34736";
        final String GEO_DOUBLES_TAG_NAME = "GeoDoubleParams";
        final String GEO_ASCII_TAG_NUMBER = "34737";
        final String GEO_ASCII_TAG_NAME = "GeoAsciiParams";
    
    
        IIOMetadataNode root =  
                (IIOMetadataNode) existingMeta.getAsTree(METADATA_FORMAT);
    
        IIOMetadataNode ifd = 
            (IIOMetadataNode) root.getElementsByTagName("TIFFIFD").item(0);
    
    
        //remove old geo data if present
        NodeList children = ifd.getElementsByTagName("TIFFField");
        for(int i = 0; i < children.getLength(); i++) {
            IIOMetadataNode child = (IIOMetadataNode) children.item(i);
    
            String tagNumber = child.getAttribute("number");
            if(GEO_KEY_TAG_NUMBER.equals(tagNumber) || 
               GEO_DOUBLES_TAG_NUMBER.equals(tagNumber) ||
               GEO_ASCII_TAG_NUMBER.equals(tagNumber)) {
                ifd.removeChild(child);
            }
        }
    
        /**Metadata tree structure:
         * 
         * com_sun_media_imageio_plugins_tiff_image_1.0";
         *   TIFFIFD (attributes: tagSets)
         *     TIFFField (attribues: name & number)
         *     TIFFField (attribues: name & number)
         *     ...
         *     TIFFField (attribues: name & number) <-- GeoKeyDirectory
         *       TIFFShorts
         *         TIFFShort (attribute: value) --
         *         TIFFShort (attribute: value)   | Keys have 4 entries each
         *         TIFFShort (attribute: value)   |
         *         TIFFSshor (attribute: value) --
         *         ...
         *     TIFFField (attributes: name & number) <-- GeoDoubleParams
         *       TIFFDoubles
         *         TIFFDouble (attribute: value)
         *         TIFFDouble (attribute: value)
         *         TIFFDouble (attribute: value)
         *         ...
         *     TIFFField (attributes: name & number) <--GeoAsciiParams
         *       TIFFAsciis
         *         TIFFAscii (atrribute: value) <-- single string containing
         *                                          all ASCII valued GeoKeys
         */
    
    
        //construct GeoKeyDirectory
        IIOMetadataNode keyDirectoryTag = new IIOMetadataNode("TIFFField");
        keyDirectoryTag.setAttribute("number",GEO_KEY_TAG_NUMBER);
        keyDirectoryTag.setAttribute("name",GEO_KEY_TAG_NAME);
    
        IIOMetadataNode keys = new IIOMetadataNode("TIFFShorts");
    
        for(int i = 0; i < geoKeyDirectory.length; i++) {
            if(geoKeyDirectory[i] < 0 || geoKeyDirectory[i] > 65535)
                throw new IllegalArgumentException("Invalide key value: " + 
                        geoKeyDirectory[i] + " Must be unsigned short.");
    
            IIOMetadataNode tiffShort = new IIOMetadataNode("TIFFShort");
            tiffShort.setAttribute("value",""+geoKeyDirectory);
    keys.appendChild(tiffShort);
    }

    keyDirectoryTag.appendChild(keys);
    ifd.appendChild(keyDirectoryTag);

    //construct GeoDoubleParams of needed
    if(geoDoubleParams != null) {
    IIOMetadataNode doubleParamsTag = new IIOMetadataNode("TIFFField");
    doubleParamsTag.setAttribute("number",GEO_DOUBLES_TAG_NUMBER);
    doubleParamsTag.setAttribute("name",GEO_DOUBLES_TAG_NAME);

    IIOMetadataNode doubles = new IIOMetadataNode("TIFFDoubles");

    for(int i = 0; i < geoDoubleParams.length; i++) {
    IIOMetadataNode tiffDouble = new IIOMetadataNode("TIFFDouble");
    tiffDouble.setAttribute("value",""+geoDoubleParams[i]);
    doubles.appendChild(tiffDouble);
    }

    doubleParamsTag.appendChild(doubles);
    ifd.appendChild(doubleParamsTag);
    }

    //construct GeoAsciiParams if needed
    if(geoAsciiParams != null) {
    IIOMetadataNode asciiParamsTag = new IIOMetadataNode("TIFFField");
    asciiParamsTag.setAttribute("number",GEO_ASCII_TAG_NUMBER);
    asciiParamsTag.setAttribute("name",GEO_ASCII_TAG_NAME);

    IIOMetadataNode asciis = new IIOMetadataNode("TIFFAsciis");

    IIOMetadataNode tiffAscii = new IIOMetadataNode("TIFFAscii");
    tiffAscii.setAttribute("value",geoAsciiParams);

    asciis.appendChild(tiffAscii);
    asciiParamsTag.appendChild(asciis);
    ifd.appendChild(asciiParamsTag);
    }

    //append geo tag set to IFD if needed
    String tagSets = ifd.getAttribute("tagSets");
    if(!tagSets.contains(GEO_TAGSET)) {
    tagSets += "," + GEO_TAGSET;
    ifd.setAttribute("tagSets",tagSets);
    }

    try {
    existingMeta.setFromTree(METADATA_FORMAT,root);
    }catch(Exception e) {
    //failed to add new geo data
    e.printStackTrace();
    }
    return existingMeta;
    };


    It may be a little easier using JAI, but I don't know how you would do it off the top of my head. JAI is build more for image processing than metadata manipulation.
  • 2. Re: Add geo tags to TIFF image
    Maxideon Explorer
    Currently Being Moderated
    An example from the GeoTiff specification:
    Example:
      GeoKeyDirectoryTag=(   1,     1, 2,     6,
                          1024,     0, 1,     2,
                          1026, 34737,12,     0,
                          2048,     0, 1, 32767,
                          2049, 34737,14,    12,
                          2050,     0, 1,     6,
                          2051, 34736, 1,     0 )
      GeoDoubleParamsTag(34736)=(1.5)
      GeoAsciiParamsTag(34737)=("Custom File|My Geographic|")
    The first line indicates that this is a Version 1 GeoTIFF GeoKey directory, the keys are Rev. 1.2, and there are 6 Keys defined in this tag.

    The next line indicates that the first Key (ID=1024 = GTModelTypeGeoKey) has the value 2 (Geographic), explicitly placed in the entry list (since TIFFTagLocation=0). The next line indicates that the Key 1026 (the GTCitationGeoKey) is listed in the GeoAsciiParamsTag (34737) array, starting at offset 0 (the first in array), and running for 12 bytes and so has the value "Custom File" (the "|" is converted to a null delimiter at the end). Going further down the list, the Key 2051 (GeogLinearUnitSizeGeoKey) is located in the GeoDoubleParamsTag (34736), at offset 0 and has the value 1.5; the value of key 2049 (GeogCitationGeoKey) is "My Geographic".
    Using the code I posted it would be something like this
    int[] keys = {       1,     1, 2,     6,
                      1024,     0, 1,     2,
                      1026, 34737,12,     0,
                      2048,     0, 1, 32767,
                      2049, 34737,14,    12,
                      2050,     0, 1,     6,
                      2051, 34736, 1,     0};
    double[] doubles = {1.5};
    String   ascii = "Custom File|My Geographic|";
    
    ImageReader reader = ImageIO.getImageReadersByFormatName("tiff").next();
    
    ImageInputStream in = ImageIO.createImageInputStream(...)
    reader.setInput(in, true, false);
            
    IIOImage image = reader.readAll(0, null);
    addGeoMeta(image.getMetadata(),keys,doubles,ascii)
    
    //write out IIOImage
    So it's a pretty low level solution. But a solution nonetheless.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points