All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sanselan.formats.tiff.TiffField Maven / Gradle / Ivy

The newest version!
/*
 * 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.sanselan.formats.tiff;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.formats.tiff.constants.TagInfo;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
import org.apache.sanselan.formats.tiff.fieldtypes.FieldType;

public class TiffField implements TiffConstants
{
    public final TagInfo tagInfo;
    public final FieldType fieldType;

    public final int tag;
    public final int directoryType;
    public final int type;
    public final int length;
    public final int valueOffset;
    public final byte valueOffsetBytes[];

    public byte oversizeValue[] = null;
    public final int byteOrder;

    public TiffField(int tag, int directoryType, int type, int Length,
            int ValueOffset, byte ValueOffsetBytes[], int byteOrder)
    {

        this.tag = tag;
        this.directoryType = directoryType;
        this.type = type;
        this.length = Length;
        this.valueOffset = ValueOffset;
        this.valueOffsetBytes = ValueOffsetBytes;
        this.byteOrder = byteOrder;

        fieldType = getFieldType(type);
        tagInfo = getTag(directoryType, tag);
    }

    private int sortHint = -1;

    public boolean isLocalValue()
    {
        return fieldType.isLocalValue(this);
    }

    public int getBytesLength() throws ImageReadException
    {
        return fieldType.getBytesLength(this);
    }

    public final class OversizeValueElement extends TiffElement
    {
        public OversizeValueElement(int offset, int length)
        {
            super(offset, length);
        }

        public String getElementDescription(boolean verbose)
        {
            if (verbose)
                return null;

            return "OversizeValueElement, tag: " + tagInfo.name
                    + ", fieldType: " + fieldType.name;
        }
    }

    public TiffElement getOversizeValueElement()
    {
        if (fieldType.isLocalValue(this))
            return null;

        return new OversizeValueElement(valueOffset, oversizeValue.length);
    }

    public void setOversizeValue(byte bytes[])
    {
        this.oversizeValue = bytes;
    }

    private static FieldType getFieldType(int value)
    {
        for (int i = 0; i < FIELD_TYPES.length; i++)
        {
            FieldType fieldType = FIELD_TYPES[i];
            if (fieldType.type == value)
                return fieldType;
        }

        return FIELD_TYPE_UNKNOWN;
    }

    private static TagInfo getTag(int directoryType, int tag,
            List possibleMatches)
    {
        if (possibleMatches.size() < 1)
            return null;
        // else if (possibleMatches.size() == 1)
        // {
        // TagInfo tagInfo = (TagInfo) possibleMatches.get(0);
        // return tagInfo;
        // }

        // first search for exact match.
        for (int i = 0; i < possibleMatches.size(); i++)
        {
            TagInfo tagInfo = (TagInfo) possibleMatches.get(i);
            if (tagInfo.directoryType == EXIF_DIRECTORY_UNKNOWN)
                // pass
                continue;
            else if (directoryType == DIRECTORY_TYPE_EXIF
                    && tagInfo.directoryType == EXIF_DIRECTORY_EXIF_IFD)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_INTEROPERABILITY
                    && tagInfo.directoryType == EXIF_DIRECTORY_INTEROP_IFD)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_GPS
                    && tagInfo.directoryType == EXIF_DIRECTORY_GPS)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_MAKER_NOTES
                    && tagInfo.directoryType == EXIF_DIRECTORY_MAKER_NOTES)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_DIR_0
                    && tagInfo.directoryType == TIFF_DIRECTORY_IFD0)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_DIR_1
                    && tagInfo.directoryType == TIFF_DIRECTORY_IFD1)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_DIR_2
                    && tagInfo.directoryType == TIFF_DIRECTORY_IFD2)
                return tagInfo;
            else if (directoryType == DIRECTORY_TYPE_DIR_3
                    && tagInfo.directoryType == TIFF_DIRECTORY_IFD3)
                return tagInfo;
        }

        // accept an inexact match.
        for (int i = 0; i < possibleMatches.size(); i++)
        {
            TagInfo tagInfo = (TagInfo) possibleMatches.get(i);

            if (tagInfo.directoryType == EXIF_DIRECTORY_UNKNOWN)
                // pass
                continue;
            else if (directoryType >= 0
                    && tagInfo.directoryType.isImageDirectory())
                return tagInfo;
            else if (directoryType < 0
                    && !tagInfo.directoryType.isImageDirectory())
                return tagInfo;
        }

        // accept a wildcard match.
        for (int i = 0; i < possibleMatches.size(); i++)
        {
            TagInfo tagInfo = (TagInfo) possibleMatches.get(i);

            if (tagInfo.directoryType == EXIF_DIRECTORY_UNKNOWN)
                return tagInfo;
        }

        // // accept a very rough match.
        // for (int i = 0; i < possibleMatches.size(); i++)
        // {
        // TagInfo tagInfo = (TagInfo) possibleMatches.get(i);
        // if (tagInfo.exifDirectory == EXIF_DIRECTORY_UNKNOWN)
        // return tagInfo;
        // else if (directoryType == DIRECTORY_TYPE_EXIF
        // && tagInfo.exifDirectory == EXIF_DIRECTORY_EXIF_IFD)
        // return tagInfo;
        // else if (directoryType == DIRECTORY_TYPE_INTEROPERABILITY
        // && tagInfo.exifDirectory == EXIF_DIRECTORY_INTEROP_IFD)
        // return tagInfo;
        // else if (directoryType == DIRECTORY_TYPE_GPS
        // && tagInfo.exifDirectory == EXIF_DIRECTORY_GPS)
        // return tagInfo;
        // else if (directoryType == DIRECTORY_TYPE_MAKER_NOTES
        // && tagInfo.exifDirectory == EXIF_DIRECTORY_MAKER_NOTES)
        // return tagInfo;
        // else if (directoryType >= 0
        // && tagInfo.exifDirectory.isImageDirectory())
        // return tagInfo;
        // else if (directoryType < 0
        // && !tagInfo.exifDirectory.isImageDirectory())
        // return tagInfo;
        // }

        return TIFF_TAG_UNKNOWN;

        // if (true)
        // throw new Error("Why didn't this algorithm work?");
        //
        // {
        // TagInfo tagInfo = (TagInfo) possibleMatches.get(0);
        // return tagInfo;
        // }

        // Object key = new Integer(tag);
        //
        // if (directoryType == DIRECTORY_TYPE_EXIF
        // || directoryType == DIRECTORY_TYPE_INTEROPERABILITY)
        // {
        // if (EXIF_TAG_MAP.containsKey(key))
        // return (TagInfo) EXIF_TAG_MAP.get(key);
        // }
        // else if (directoryType == DIRECTORY_TYPE_GPS)
        // {
        // if (GPS_TAG_MAP.containsKey(key))
        // return (TagInfo) GPS_TAG_MAP.get(key);
        // }
        // else
        // {
        // if (TIFF_TAG_MAP.containsKey(key))
        // return (TagInfo) TIFF_TAG_MAP.get(key);
        // }
        //
        // if (ALL_TAG_MAP.containsKey(key))
        // return (TagInfo) ALL_TAG_MAP.get(key);

        // public static final int DIRECTORY_TYPE_EXIF = -2;
        // // public static final int DIRECTORY_TYPE_SUB = 5;
        // public static final int DIRECTORY_TYPE_GPS = -3;
        // public static final int DIRECTORY_TYPE_INTEROPERABILITY = -4;
        //
        // private static final Map GPS_TAG_MAP = makeTagMap(ALL_GPS_TAGS,
        // false);
        // private static final Map TIFF_TAG_MAP = makeTagMap(ALL_TIFF_TAGS,
        // false);
        // private static final Map EXIF_TAG_MAP = makeTagMap(ALL_EXIF_TAGS,
        // false);
        // private static final Map ALL_TAG_MAP = makeTagMap(ALL_TAGS, true);
        //
        // for (int i = 0; i < ALL_TAGS.length; i++)
        // {
        // TagInfo2 tag = ALL_TAGS[i];
        // if (tag.tag == value)
        // return tag;
        // }

        // return TIFF_TAG_UNKNOWN;
    }

    private static TagInfo getTag(int directoryType, int tag)
    {
        Object key = new Integer(tag);

        List possibleMatches = (List) EXIF_TAG_MAP.get(key);

        if (null == possibleMatches)
        {
            return TIFF_TAG_UNKNOWN;
        }

        TagInfo result = getTag(directoryType, tag, possibleMatches);
        return result;
    }

    private int getValueLengthInBytes()
    {
        int unit_length = fieldType.length;
        int valueLength = unit_length * length;

        // Debug.debug("getValueLengthInBytes unit_length", unit_length);
        // Debug.debug("getValueLengthInBytes length", length);

        return valueLength;
    }

    public void fillInValue(ByteSource byteSource) throws ImageReadException,
            IOException
    {
        if (fieldType.isLocalValue(this))
            return;

        int valueLength = getValueLengthInBytes();

        // Debug.debug("fillInValue tag", tag);
        // Debug.debug("fillInValue tagInfo", tagInfo);
        // Debug.debug("fillInValue valueOffset", valueOffset);
        // Debug.debug("fillInValue valueLength", valueLength);

        byte bytes[] = byteSource.getBlock(valueOffset, valueLength);
        setOversizeValue(bytes);
    }

    public String getValueDescription()
    {
        try
        {
            return getValueDescription(getValue());
        } catch (ImageReadException e)
        {
            return "Invalid value: " + e.getMessage();
        }
    }

    private String getValueDescription(Object o)
    {
        if (o == null)
            return null;

        if (o instanceof Number)
        {
            return o.toString();
        } else if (o instanceof String)
        {
            return "'" + o.toString().trim() + "'";
        } else if (o instanceof Date)
        {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            return df.format((Date) o);
        } else if (o instanceof Object[])
        {
            Object objects[] = (Object[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < objects.length; i++)
            {
                Object object = objects[i];

                if (i > 50)
                {
                    result.append("... (" + objects.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + object);
            }
            return result.toString();
        }
        // else if (o instanceof Number[])
        // {
        // Number numbers[] = (Number[]) o;
        // StringBuffer result = new StringBuffer();
        //
        // for (int i = 0; i < numbers.length; i++)
        // {
        // Number number = numbers[i];
        //
        // if (i > 0)
        // result.append(", ");
        // result.append("" + number);
        // }
        // return result.toString();
        // }
        else if (o instanceof int[])
        {
            int values[] = (int[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < values.length; i++)
            {
                int value = values[i];

                if (i > 50)
                {
                    result.append("... (" + values.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + value);
            }
            return result.toString();
        } else if (o instanceof long[])
        {
            long values[] = (long[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < values.length; i++)
            {
                long value = values[i];

                if (i > 50)
                {
                    result.append("... (" + values.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + value);
            }
            return result.toString();
        } else if (o instanceof double[])
        {
            double values[] = (double[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < values.length; i++)
            {
                double value = values[i];

                if (i > 50)
                {
                    result.append("... (" + values.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + value);
            }
            return result.toString();
        } else if (o instanceof byte[])
        {
            byte values[] = (byte[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < values.length; i++)
            {
                byte value = values[i];

                if (i > 50)
                {
                    result.append("... (" + values.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + value);
            }
            return result.toString();
        } else if (o instanceof char[])
        {
            char values[] = (char[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < values.length; i++)
            {
                char value = values[i];

                if (i > 50)
                {
                    result.append("... (" + values.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + value);
            }
            return result.toString();
        } else if (o instanceof float[])
        {
            float values[] = (float[]) o;
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < values.length; i++)
            {
                float value = values[i];

                if (i > 50)
                {
                    result.append("... (" + values.length + ")");
                    break;
                }
                if (i > 0)
                    result.append(", ");
                result.append("" + value);
            }
            return result.toString();
        }
        // else if (o instanceof short[])
        // {
        // short numbers[] = (short[]) o;
        // StringBuffer result = new StringBuffer();
        //
        // for (int i = 0; i < numbers.length; i++)
        // {
        // short number = numbers[i];
        //
        // if (i > 0)
        // result.append(", ");
        // result.append("" + number);
        // }
        // return result.toString();
        // }

        return "Unknown: " + o.getClass().getName();
    }

    public void dump()
    {
        PrintWriter pw = new PrintWriter(System.out);
        dump(pw);
        pw.flush();
    }

    public void dump(PrintWriter pw)
    {
        dump(pw, null);
    }

    public void dump(PrintWriter pw, String prefix)
    {
        if (prefix != null)
            pw.print(prefix + ": ");

        pw.println(toString());
        pw.flush();
    }

    // private void errorDump()
    // {
    // Debug.debug("tagInfo", tagInfo);
    // Debug.debug("fieldType", fieldType);
    // Debug.debug("tag", tag);
    // Debug.debug("type", type);
    // Debug.debug("length", length);
    // Debug.debug("valueOffset", valueOffset);
    // Debug.debug("valueOffsetBytes", valueOffsetBytes);
    // Debug.debug("oversizeValue", oversizeValue);
    // Debug.debug("byteOrder", byteOrder);
    // }

    public String getDescriptionWithoutValue()
    {
        return tag + " (0x" + Integer.toHexString(tag) + ": " + tagInfo.name
                + "): ";
    }

    public String toString()
    {
        StringBuffer result = new StringBuffer();

        result.append(tag + " (0x" + Integer.toHexString(tag) + ": "
                + tagInfo.name + "): ");
        result.append(getValueDescription() + " (" + length + " "
                + fieldType.name + ")");

        return result.toString();
    }

    public String getTagName()
    {
        if (tagInfo == TIFF_TAG_UNKNOWN)
            return tagInfo.name + " (0x" + Integer.toHexString(tag) + ")";
        return tagInfo.name;
    }

    public String getFieldTypeName()
    {
        return fieldType.name;
    }

    public static final String Attribute_Tag = "Tag";

    public Object getValue() throws ImageReadException
    {
        // System.out.print("getValue");
        return tagInfo.getValue(this);
    }

    public String getStringValue() throws ImageReadException
    {
        Object o = getValue();
        if (o == null)
            return null;
        if (!(o instanceof String))
            throw new ImageReadException("Expected String value("
                    + tagInfo.getDescription() + "): " + o);
        return (String) o;
    }

    private static final Map makeTagMap(TagInfo tags[],
            boolean ignoreDuplicates, String name)
    {
        // make sure to use the thread-safe version; this is shared state.
        Map map = new Hashtable();

        for (int i = 0; i < tags.length; i++)
        {
            TagInfo tag = tags[i];
            Object key = new Integer(tag.tag);

            List tagList = (List) map.get(key);
            if (tagList == null)
            {
                tagList = new ArrayList();
                map.put(key, tagList);
            }
            tagList.add(tag);

            // if (map.get(key) == null)
            // map.put(key, tag);
            // else if (!ignoreDuplicates)
            // {
            // System.out.println("Duplicate tag in " + name + ": " + tag.tag
            // + " (0x" + Integer.toHexString(tag.tag) + ")");
            // System.out.println("\t" + "New name: " + tag.name);
            // System.out.println("\t" + "Old name: "
            // + ((TagInfo) map.get(key)).name);
            // }
        }

        return map;
    }

    private static final Map GPS_TAG_MAP = makeTagMap(ALL_GPS_TAGS, false,
            "GPS");
    private static final Map TIFF_TAG_MAP = makeTagMap(ALL_TIFF_TAGS, false,
            "TIFF");
    private static final Map EXIF_TAG_MAP = makeTagMap(ALL_EXIF_TAGS, true,
            "EXIF");
    private static final Map ALL_TAG_MAP = makeTagMap(ALL_TAGS, true, "All");

    // static
    // {
    // Map map = new HashMap();
    //
    // for (int i = 0; i < ALL_TAGS.length; i++)
    // {
    // TagInfo2 tag = ALL_TAGS[i];
    // Object o = map.get("" + tag.tag);
    // if (o == null)
    // map.put("" + tag.tag, tag);
    // else
    // {
    // System.out.println("Duplicate tag: " + tag.tag);
    // System.out.println("\t" + "New name: " + tag.name);
    // System.out.println("\t" + "Old name: " + ((TagInfo2) o).name);
    // }
    // }
    //
    // }

    // public static final TagInfo2 ALL_TAGS[] = TagConstantsUtils
    // .mergeTagLists(new TagInfo2[][]{
    // ALL_EXIF_TAGS, ALL_TIFF_TAGS, ALL_GPS_TAGS,
    // });
    //
    //

    public int[] getIntArrayValue() throws ImageReadException
    {
        Object o = getValue();
        // if (o == null)
        // return null;

        if (o instanceof Number)
            return new int[] { ((Number) o).intValue() };
        else if (o instanceof Number[])
        {
            Number numbers[] = (Number[]) o;
            int result[] = new int[numbers.length];
            for (int i = 0; i < numbers.length; i++)
                result[i] = numbers[i].intValue();
            return result;
        } else if (o instanceof int[])
        {
            int numbers[] = (int[]) o;
            int result[] = new int[numbers.length];
            for (int i = 0; i < numbers.length; i++)
                result[i] = numbers[i];
            return result;
        }

        throw new ImageReadException("Unknown value: " + o + " for: "
                + tagInfo.getDescription());
        // return null;
    }

    public double[] getDoubleArrayValue() throws ImageReadException
    {
        Object o = getValue();
        // if (o == null)
        // return null;

        if (o instanceof Number)
        {
            return new double[] { ((Number) o).doubleValue() };
        } else if (o instanceof Number[])
        {
            Number numbers[] = (Number[]) o;
            double result[] = new double[numbers.length];
            for (int i = 0; i < numbers.length; i++)
                result[i] = numbers[i].doubleValue();
            return result;
        } else if (o instanceof int[])
        {
            int numbers[] = (int[]) o;
            double result[] = new double[numbers.length];
            for (int i = 0; i < numbers.length; i++)
                result[i] = numbers[i];
            return result;
        } else if (o instanceof float[])
        {
            float numbers[] = (float[]) o;
            double result[] = new double[numbers.length];
            for (int i = 0; i < numbers.length; i++)
                result[i] = numbers[i];
            return result;
        } else if (o instanceof double[])
        {
            double numbers[] = (double[]) o;
            double result[] = new double[numbers.length];
            for (int i = 0; i < numbers.length; i++)
                result[i] = numbers[i];
            return result;
        }

        throw new ImageReadException("Unknown value: " + o + " for: "
                + tagInfo.getDescription());
        // return null;
    }

    public int getIntValueOrArraySum() throws ImageReadException
    {
        Object o = getValue();
        // if (o == null)
        // return -1;

        if (o instanceof Number)
            return ((Number) o).intValue();
        else if (o instanceof Number[])
        {
            Number numbers[] = (Number[]) o;
            int sum = 0;
            for (int i = 0; i < numbers.length; i++)
                sum += numbers[i].intValue();
            return sum;
        } else if (o instanceof int[])
        {
            int numbers[] = (int[]) o;
            int sum = 0;
            for (int i = 0; i < numbers.length; i++)
                sum += numbers[i];
            return sum;
        }

        throw new ImageReadException("Unknown value: " + o + " for: "
                + tagInfo.getDescription());
        // return -1;
    }

    public int getIntValue() throws ImageReadException
    {
        Object o = getValue();
        if (o == null)
            throw new ImageReadException("Missing value: "
                    + tagInfo.getDescription());

        return ((Number) o).intValue();
    }

    public double getDoubleValue() throws ImageReadException
    {
        Object o = getValue();
        if (o == null)
            throw new ImageReadException("Missing value: "
                    + tagInfo.getDescription());

        return ((Number) o).doubleValue();
    }

    public byte[] getByteArrayValue() throws ImageReadException
    {
        return fieldType.getRawBytes(this);
    }

    public int getSortHint()
    {
        return sortHint;
    }

    public void setSortHint(int sortHint)
    {
        this.sortHint = sortHint;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy