Changeset 8243 in josm for trunk/src/com/drew
- Timestamp:
- 2015-04-21T00:42:50+02:00 (10 years ago)
- Location:
- trunk/src/com/drew
- Files:
-
- 7 added
- 28 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/com/drew/imaging/jpeg/JpegMetadataReader.java
r8132 r8243 35 35 //import com.drew.metadata.adobe.AdobeJpegReader; 36 36 import com.drew.metadata.exif.ExifReader; 37 import com.drew.metadata.file.FileMetadataReader; 37 38 //import com.drew.metadata.icc.IccReader; 38 39 import com.drew.metadata.iptc.IptcReader; … … 79 80 public static Metadata readMetadata(@NotNull File file, @Nullable Iterable<JpegSegmentMetadataReader> readers) throws JpegProcessingException, IOException 80 81 { 81 InputStream inputStream = null; 82 try 83 { 84 inputStream = new FileInputStream(file); 85 return readMetadata(inputStream, readers); 82 InputStream inputStream = new FileInputStream(file); 83 Metadata metadata; 84 try { 85 metadata = readMetadata(inputStream, readers); 86 86 } finally { 87 if (inputStream != null) 88 inputStream.close(); 87 inputStream.close(); 89 88 } 89 new FileMetadataReader().read(file, metadata); 90 return metadata; 90 91 } 91 92 … … 123 124 for (JpegSegmentMetadataReader reader : readers) { 124 125 for (JpegSegmentType segmentType : reader.getSegmentTypes()) { 125 for (byte[] segmentBytes : segmentData.getSegments(segmentType)) { 126 if (reader.canProcess(segmentBytes, segmentType)) { 127 reader.extract(segmentBytes, metadata, segmentType); 128 } 129 } 126 reader.readJpegSegments(segmentData.getSegments(segmentType), metadata, segmentType); 130 127 } 131 128 } -
trunk/src/com/drew/imaging/jpeg/JpegSegmentMetadataReader.java
r8132 r8243 16 16 17 17 /** 18 * Gets a value indicating whether the supplied byte data can be processed by this reader. This is not a guarantee 19 * that no errors will occur, but rather a best-effort indication of whether the parse is likely to succeed. 20 * Implementations are expected to check things such as the opening bytes, data length, etc. 21 */ 22 public boolean canProcess(@NotNull final byte[] segmentBytes, @NotNull final JpegSegmentType segmentType); 23 24 /** 25 * Extracts metadata from a JPEG segment's byte array and merges it into the specified {@link Metadata} object. 18 * Extracts metadata from all instances of a particular JPEG segment type. 26 19 * 27 * @param segmentBytes The byte array from which the metadata should be extracted. 20 * @param segments A sequence of byte arrays from which the metadata should be extracted. These are in the order 21 * encountered in the original file. 28 22 * @param metadata The {@link Metadata} object into which extracted values should be merged. 29 23 * @param segmentType The {@link JpegSegmentType} being read. 30 24 */ 31 public void extract(@NotNull final byte[] segmentBytes, @NotNull final Metadata metadata, @NotNull final JpegSegmentType segmentType);25 public void readJpegSegments(@NotNull final Iterable<byte[]> segments, @NotNull final Metadata metadata, @NotNull final JpegSegmentType segmentType); 32 26 } -
trunk/src/com/drew/imaging/tiff/TiffHandler.java
r8132 r8243 29 29 30 30 /** 31 * Interface of an class capable of handling events raised during the reading of a TIFF file 32 * via {@link TiffReader}. 33 * 31 34 * @author Drew Noakes https://drewnoakes.com 32 35 */ -
trunk/src/com/drew/lang/RandomAccessReader.java
r8132 r8243 127 127 128 128 /** 129 * Gets whether a bit at a specific index is set or not. 130 * 131 * @param index the number of bits at which to test 132 * @return true if the bit is set, otherwise false 133 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative 134 */ 135 public boolean getBit(int index) throws IOException 136 { 137 int byteIndex = index / 8; 138 int bitIndex = index % 8; 139 140 validateIndex(byteIndex, 1); 141 142 byte b = getByte(byteIndex); 143 return ((b >> bitIndex) & 1) == 1; 144 } 145 146 /** 129 147 * Returns an unsigned 8-bit int calculated from one byte of data at the specified index. 130 148 * … … 195 213 return (short) (((short)getByte(index + 1) << 8 & (short)0xFF00) | 196 214 ((short)getByte(index ) & (short)0xFF)); 215 } 216 } 217 218 /** 219 * Get a 24-bit unsigned integer from the buffer, returning it as an int. 220 * 221 * @param index position within the data buffer to read first byte 222 * @return the unsigned 24-bit int value as a long, between 0x00000000 and 0x00FFFFFF 223 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative 224 */ 225 public int getInt24(int index) throws IOException 226 { 227 validateIndex(index, 3); 228 229 if (_isMotorolaByteOrder) { 230 // Motorola - MSB first (big endian) 231 return (((int)getByte(index )) << 16 & 0xFF0000) | 232 (((int)getByte(index + 1)) << 8 & 0xFF00) | 233 (((int)getByte(index + 2)) & 0xFF); 234 } else { 235 // Intel ordering - LSB first (little endian) 236 return (((int)getByte(index + 2)) << 16 & 0xFF0000) | 237 (((int)getByte(index + 1)) << 8 & 0xFF00) | 238 (((int)getByte(index )) & 0xFF); 197 239 } 198 240 } -
trunk/src/com/drew/lang/SequentialByteArrayReader.java
r8132 r8243 37 37 private int _index; 38 38 39 public SequentialByteArrayReader(@NotNull byte[] bytes) 40 { 41 this(bytes, 0); 42 } 43 39 44 @SuppressWarnings("ConstantConditions") 40 public SequentialByteArrayReader(@NotNull byte[] bytes )45 public SequentialByteArrayReader(@NotNull byte[] bytes, int baseIndex) 41 46 { 42 47 if (bytes == null) … … 44 49 45 50 _bytes = bytes; 46 _index = 0;51 _index = baseIndex; 47 52 } 48 53 -
trunk/src/com/drew/metadata/Directory.java
r8132 r8243 81 81 82 82 // VARIOUS METHODS 83 84 /** 85 * Gets a value indicating whether the directory is empty, meaning it contains no errors and no tag values. 86 */ 87 public boolean isEmpty() 88 { 89 return _errorList.isEmpty() && _definedTagList.isEmpty(); 90 } 83 91 84 92 /** … … 759 767 if (timeZone != null) 760 768 parser.setTimeZone(timeZone); 769 else 770 parser.setTimeZone(TimeZone.getTimeZone("GMT")); // don't interpret zone time 771 761 772 return parser.parse(dateString); 762 773 } catch (ParseException ex) { -
trunk/src/com/drew/metadata/Metadata.java
r8132 r8243 37 37 { 38 38 @NotNull 39 private final Map<Class<? extends Directory>,Directory> _directoryByClass = new HashMap<Class<? extends Directory>, Directory>(); 40 41 /** 42 * List of Directory objects set against this object. Keeping a list handy makes 43 * creation of an Iterator and counting tags simple. 44 */ 45 @NotNull 46 private final Collection<Directory> _directoryList = new ArrayList<Directory>(); 47 48 /** 49 * Returns an objects for iterating over Directory objects in the order in which they were added. 50 * 51 * @return an iterable collection of directories 39 private final Map<Class<? extends Directory>,Collection<Directory>> _directoryListByClass = new HashMap<Class<? extends Directory>, Collection<Directory>>(); 40 41 /** 42 * Returns an iterable set of the {@link Directory} instances contained in this metadata collection. 43 * 44 * @return an iterable set of directories 52 45 */ 53 46 @NotNull 54 47 public Iterable<Directory> getDirectories() 55 48 { 56 return Collections.unmodifiableCollection(_directoryList); 57 } 58 59 /** 60 * Returns a count of unique directories in this metadata collection. 49 return new DirectoryIterable(_directoryListByClass); 50 } 51 52 @Nullable 53 public <T extends Directory> Collection<T> getDirectoriesOfType(Class<T> type) 54 { 55 return (Collection<T>)_directoryListByClass.get(type); 56 } 57 58 /** 59 * Returns the count of directories in this metadata collection. 61 60 * 62 61 * @return the number of unique directory types set for this metadata collection … … 64 63 public int getDirectoryCount() 65 64 { 66 return _directoryList.size(); 67 } 68 69 /** 70 * Returns a {@link Directory} of specified type. If this {@link Metadata} object already contains 71 * such a directory, it is returned. Otherwise a new instance of this directory will be created and stored within 72 * this {@link Metadata} object. 73 * 74 * @param type the type of the Directory implementation required. 75 * @return a directory of the specified type. 76 */ 77 @NotNull 65 int count = 0; 66 for (Map.Entry<Class<? extends Directory>,Collection<Directory>> pair : _directoryListByClass.entrySet()) 67 count += pair.getValue().size(); 68 return count; 69 } 70 71 /** 72 * Adds a directory to this metadata collection. 73 * 74 * @param directory the {@link Directory} to add into this metadata collection. 75 */ 76 public <T extends Directory> void addDirectory(@NotNull T directory) 77 { 78 getOrCreateDirectoryList(directory.getClass()).add(directory); 79 } 80 81 /** 82 * Gets the first {@link Directory} of the specified type contained within this metadata collection. 83 * If no instances of this type are present, <code>null</code> is returned. 84 * 85 * @param type the Directory type 86 * @param <T> the Directory type 87 * @return the first Directory of type T in this metadata collection, or <code>null</code> if none exist 88 */ 89 @Nullable 78 90 @SuppressWarnings("unchecked") 79 public <T extends Directory> T get OrCreateDirectory(@NotNull Class<T> type)91 public <T extends Directory> T getFirstDirectoryOfType(@NotNull Class<T> type) 80 92 { 81 93 // We suppress the warning here as the code asserts a map signature of Class<T>,T. 82 94 // So after get(Class<T>) it is for sure the result is from type T. 83 95 84 // check if we've already issued this type of directory 85 if (_directoryByClass.containsKey(type)) 86 return (T)_directoryByClass.get(type); 87 88 T directory; 89 try { 90 directory = type.newInstance(); 91 } catch (Exception e) { 92 throw new RuntimeException("Cannot instantiate provided Directory type: " + type.toString()); 93 } 94 // store the directory 95 _directoryByClass.put(type, directory); 96 _directoryList.add(directory); 97 98 return directory; 99 } 100 101 /** 102 * If this {@link Metadata} object contains a {@link Directory} of the specified type, it is returned. 103 * Otherwise <code>null</code> is returned. 104 * 105 * @param type the Directory type 106 * @param <T> the Directory type 107 * @return a Directory of type T if it exists in this {@link Metadata} object, otherwise <code>null</code>. 108 */ 109 @Nullable 110 @SuppressWarnings("unchecked") 111 public <T extends Directory> T getDirectory(@NotNull Class<T> type) 112 { 113 // We suppress the warning here as the code asserts a map signature of Class<T>,T. 114 // So after get(Class<T>) it is for sure the result is from type T. 115 116 return (T)_directoryByClass.get(type); 117 } 118 119 /** 120 * Indicates whether a given directory type has been created in this metadata 121 * repository. Directories are created by calling {@link Metadata#getOrCreateDirectory(Class)}. 96 Collection<Directory> list = getDirectoryList(type); 97 98 if (list == null || list.isEmpty()) 99 return null; 100 101 return (T)list.iterator().next(); 102 } 103 104 /** 105 * Indicates whether an instance of the given directory type exists in this Metadata instance. 122 106 * 123 107 * @param type the {@link Directory} type 124 * @return true if the {@link Directory} has been created 125 */ 126 public boolean containsDirectory(Class<? extends Directory> type) 127 { 128 return _directoryByClass.containsKey(type); 108 * @return <code>true</code> if a {@link Directory} of the specified type exists, otherwise <code>false</code> 109 */ 110 public boolean containsDirectoryOfType(Class<? extends Directory> type) 111 { 112 Collection<Directory> list = getDirectoryList(type); 113 return list != null && !list.isEmpty(); 129 114 } 130 115 … … 137 122 public boolean hasErrors() 138 123 { 139 for (Directory directory : _directoryList) {124 for (Directory directory : getDirectories()) { 140 125 if (directory.hasErrors()) 141 126 return true; … … 147 132 public String toString() 148 133 { 134 int count = getDirectoryCount(); 149 135 return String.format("Metadata (%d %s)", 150 _directoryList.size(),151 _directoryList.size()== 1136 count, 137 count == 1 152 138 ? "directory" 153 139 : "directories"); 154 140 } 141 142 @Nullable 143 private <T extends Directory> Collection<Directory> getDirectoryList(@NotNull Class<T> type) 144 { 145 return _directoryListByClass.get(type); 146 } 147 148 @NotNull 149 private <T extends Directory> Collection<Directory> getOrCreateDirectoryList(@NotNull Class<T> type) 150 { 151 Collection<Directory> collection = getDirectoryList(type); 152 if (collection != null) 153 return collection; 154 collection = new ArrayList<Directory>(); 155 _directoryListByClass.put(type, collection); 156 return collection; 157 } 158 159 private static class DirectoryIterable implements Iterable<Directory> 160 { 161 private final Map<Class<? extends Directory>, Collection<Directory>> _map; 162 163 public DirectoryIterable(Map<Class<? extends Directory>, Collection<Directory>> map) 164 { 165 _map = map; 166 } 167 168 public Iterator<Directory> iterator() 169 { 170 return new DirectoryIterator(_map); 171 } 172 173 private static class DirectoryIterator implements Iterator<Directory> 174 { 175 @NotNull 176 private final Iterator<Map.Entry<Class<? extends Directory>, Collection<Directory>>> _mapIterator; 177 @Nullable 178 private Iterator<Directory> _listIterator; 179 180 public DirectoryIterator(Map<Class<? extends Directory>, Collection<Directory>> map) 181 { 182 _mapIterator = map.entrySet().iterator(); 183 184 if (_mapIterator.hasNext()) 185 _listIterator = _mapIterator.next().getValue().iterator(); 186 } 187 188 public boolean hasNext() 189 { 190 return _listIterator != null && (_listIterator.hasNext() || _mapIterator.hasNext()); 191 } 192 193 public Directory next() 194 { 195 if (_listIterator == null || (!_listIterator.hasNext() && !_mapIterator.hasNext())) 196 throw new NoSuchElementException(); 197 198 while (!_listIterator.hasNext()) 199 _listIterator = _mapIterator.next().getValue().iterator(); 200 201 return _listIterator.next(); 202 } 203 204 public void remove() 205 { 206 throw new UnsupportedOperationException(); 207 } 208 } 209 } 155 210 } -
trunk/src/com/drew/metadata/exif/ExifIFD0Descriptor.java
r8132 r8243 22 22 package com.drew.metadata.exif; 23 23 24 import com.drew.lang.Rational;25 24 import com.drew.lang.annotations.NotNull; 26 import com.drew.lang.annotations.Nullable;27 import com.drew.metadata.TagDescriptor;28 29 import java.io.UnsupportedEncodingException;30 31 import static com.drew.metadata.exif.ExifIFD0Directory.*;32 25 33 26 /** … … 36 29 * @author Drew Noakes https://drewnoakes.com 37 30 */ 38 public class ExifIFD0Descriptor extends TagDescriptor<ExifIFD0Directory>31 public class ExifIFD0Descriptor extends ExifDescriptorBase<ExifIFD0Directory> 39 32 { 40 /**41 * Dictates whether rational values will be represented in decimal format in instances42 * where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3).43 */44 private final boolean _allowDecimalRepresentationOfRationals = true;45 46 33 public ExifIFD0Descriptor(@NotNull ExifIFD0Directory directory) 47 34 { 48 35 super(directory); 49 36 } 50 51 // Note for the potential addition of brightness presentation in eV:52 // Brightness of taken subject. To calculate Exposure(Ev) from BrightnessValue(Bv),53 // you must add SensitivityValue(Sv).54 // Ev=BV+Sv Sv=log2(ISOSpeedRating/3.125)55 // ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.56 57 /**58 * Returns a descriptive value of the specified tag for this image.59 * Where possible, known values will be substituted here in place of the raw60 * tokens actually kept in the Exif segment. If no substitution is61 * available, the value provided by getString(int) will be returned.62 * @param tagType the tag to find a description for63 * @return a description of the image's value for the specified tag, or64 * <code>null</code> if the tag hasn't been defined.65 */66 @Override67 @Nullable68 public String getDescription(int tagType)69 {70 switch (tagType) {71 case TAG_RESOLUTION_UNIT:72 return getResolutionDescription();73 case TAG_YCBCR_POSITIONING:74 return getYCbCrPositioningDescription();75 case TAG_X_RESOLUTION:76 return getXResolutionDescription();77 case TAG_Y_RESOLUTION:78 return getYResolutionDescription();79 case TAG_REFERENCE_BLACK_WHITE:80 return getReferenceBlackWhiteDescription();81 case TAG_ORIENTATION:82 return getOrientationDescription();83 84 case TAG_WIN_AUTHOR:85 return getWindowsAuthorDescription();86 case TAG_WIN_COMMENT:87 return getWindowsCommentDescription();88 case TAG_WIN_KEYWORDS:89 return getWindowsKeywordsDescription();90 case TAG_WIN_SUBJECT:91 return getWindowsSubjectDescription();92 case TAG_WIN_TITLE:93 return getWindowsTitleDescription();94 95 default:96 return super.getDescription(tagType);97 }98 }99 100 @Nullable101 public String getReferenceBlackWhiteDescription()102 {103 int[] ints = _directory.getIntArray(TAG_REFERENCE_BLACK_WHITE);104 if (ints==null || ints.length < 6)105 return null;106 int blackR = ints[0];107 int whiteR = ints[1];108 int blackG = ints[2];109 int whiteG = ints[3];110 int blackB = ints[4];111 int whiteB = ints[5];112 return String.format("[%d,%d,%d] [%d,%d,%d]", blackR, blackG, blackB, whiteR, whiteG, whiteB);113 }114 115 @Nullable116 public String getYResolutionDescription()117 {118 Rational value = _directory.getRational(TAG_Y_RESOLUTION);119 if (value==null)120 return null;121 final String unit = getResolutionDescription();122 return String.format("%s dots per %s",123 value.toSimpleString(_allowDecimalRepresentationOfRationals),124 unit == null ? "unit" : unit.toLowerCase());125 }126 127 @Nullable128 public String getXResolutionDescription()129 {130 Rational value = _directory.getRational(TAG_X_RESOLUTION);131 if (value==null)132 return null;133 final String unit = getResolutionDescription();134 return String.format("%s dots per %s",135 value.toSimpleString(_allowDecimalRepresentationOfRationals),136 unit == null ? "unit" : unit.toLowerCase());137 }138 139 @Nullable140 public String getYCbCrPositioningDescription()141 {142 return getIndexedDescription(TAG_YCBCR_POSITIONING, 1, "Center of pixel array", "Datum point");143 }144 145 @Nullable146 public String getOrientationDescription()147 {148 return getIndexedDescription(TAG_ORIENTATION, 1,149 "Top, left side (Horizontal / normal)",150 "Top, right side (Mirror horizontal)",151 "Bottom, right side (Rotate 180)",152 "Bottom, left side (Mirror vertical)",153 "Left side, top (Mirror horizontal and rotate 270 CW)",154 "Right side, top (Rotate 90 CW)",155 "Right side, bottom (Mirror horizontal and rotate 90 CW)",156 "Left side, bottom (Rotate 270 CW)");157 }158 159 @Nullable160 public String getResolutionDescription()161 {162 // '1' means no-unit, '2' means inch, '3' means centimeter. Default value is '2'(inch)163 return getIndexedDescription(TAG_RESOLUTION_UNIT, 1, "(No unit)", "Inch", "cm");164 }165 166 /** The Windows specific tags uses plain Unicode. */167 @Nullable168 private String getUnicodeDescription(int tag)169 {170 byte[] bytes = _directory.getByteArray(tag);171 if (bytes == null)172 return null;173 try {174 // Decode the unicode string and trim the unicode zero "\0" from the end.175 return new String(bytes, "UTF-16LE").trim();176 } catch (UnsupportedEncodingException ex) {177 return null;178 }179 }180 181 @Nullable182 public String getWindowsAuthorDescription()183 {184 return getUnicodeDescription(TAG_WIN_AUTHOR);185 }186 187 @Nullable188 public String getWindowsCommentDescription()189 {190 return getUnicodeDescription(TAG_WIN_COMMENT);191 }192 193 @Nullable194 public String getWindowsKeywordsDescription()195 {196 return getUnicodeDescription(TAG_WIN_KEYWORDS);197 }198 199 @Nullable200 public String getWindowsTitleDescription()201 {202 return getUnicodeDescription(TAG_WIN_TITLE);203 }204 205 @Nullable206 public String getWindowsSubjectDescription()207 {208 return getUnicodeDescription(TAG_WIN_SUBJECT);209 }210 37 } -
trunk/src/com/drew/metadata/exif/ExifIFD0Directory.java
r8132 r8243 23 23 24 24 import com.drew.lang.annotations.NotNull; 25 import com.drew.metadata.Directory;26 25 27 26 import java.util.HashMap; … … 32 31 * @author Drew Noakes https://drewnoakes.com 33 32 */ 34 public class ExifIFD0Directory extends Directory33 public class ExifIFD0Directory extends ExifDirectoryBase 35 34 { 36 public static final int TAG_IMAGE_DESCRIPTION = 0x010E;37 public static final int TAG_MAKE = 0x010F;38 public static final int TAG_MODEL = 0x0110;39 public static final int TAG_ORIENTATION = 0x0112;40 public static final int TAG_X_RESOLUTION = 0x011A;41 public static final int TAG_Y_RESOLUTION = 0x011B;42 public static final int TAG_RESOLUTION_UNIT = 0x0128;43 public static final int TAG_SOFTWARE = 0x0131;44 public static final int TAG_DATETIME = 0x0132;45 public static final int TAG_ARTIST = 0x013B;46 public static final int TAG_WHITE_POINT = 0x013E;47 public static final int TAG_PRIMARY_CHROMATICITIES = 0x013F;48 49 public static final int TAG_YCBCR_COEFFICIENTS = 0x0211;50 public static final int TAG_YCBCR_POSITIONING = 0x0213;51 public static final int TAG_REFERENCE_BLACK_WHITE = 0x0214;52 53 54 35 /** This tag is a pointer to the Exif SubIFD. */ 55 36 public static final int TAG_EXIF_SUB_IFD_OFFSET = 0x8769; … … 58 39 public static final int TAG_GPS_INFO_OFFSET = 0x8825; 59 40 60 public static final int TAG_COPYRIGHT = 0x8298; 61 62 /** Non-standard, but in use. */ 63 public static final int TAG_TIME_ZONE_OFFSET = 0x882a; 64 65 /** The image title, as used by Windows XP. */ 66 public static final int TAG_WIN_TITLE = 0x9C9B; 67 /** The image comment, as used by Windows XP. */ 68 public static final int TAG_WIN_COMMENT = 0x9C9C; 69 /** The image author, as used by Windows XP (called Artist in the Windows shell). */ 70 public static final int TAG_WIN_AUTHOR = 0x9C9D; 71 /** The image keywords, as used by Windows XP. */ 72 public static final int TAG_WIN_KEYWORDS = 0x9C9E; 73 /** The image subject, as used by Windows XP. */ 74 public static final int TAG_WIN_SUBJECT = 0x9C9F; 41 public ExifIFD0Directory() 42 { 43 this.setDescriptor(new ExifIFD0Descriptor(this)); 44 } 75 45 76 46 @NotNull … … 79 49 static 80 50 { 81 _tagNameMap.put(TAG_IMAGE_DESCRIPTION, "Image Description"); 82 _tagNameMap.put(TAG_MAKE, "Make"); 83 _tagNameMap.put(TAG_MODEL, "Model"); 84 _tagNameMap.put(TAG_ORIENTATION, "Orientation"); 85 _tagNameMap.put(TAG_X_RESOLUTION, "X Resolution"); 86 _tagNameMap.put(TAG_Y_RESOLUTION, "Y Resolution"); 87 _tagNameMap.put(TAG_RESOLUTION_UNIT, "Resolution Unit"); 88 _tagNameMap.put(TAG_SOFTWARE, "Software"); 89 _tagNameMap.put(TAG_DATETIME, "Date/Time"); 90 _tagNameMap.put(TAG_ARTIST, "Artist"); 91 _tagNameMap.put(TAG_WHITE_POINT, "White Point"); 92 _tagNameMap.put(TAG_PRIMARY_CHROMATICITIES, "Primary Chromaticities"); 93 _tagNameMap.put(TAG_YCBCR_COEFFICIENTS, "YCbCr Coefficients"); 94 _tagNameMap.put(TAG_YCBCR_POSITIONING, "YCbCr Positioning"); 95 _tagNameMap.put(TAG_REFERENCE_BLACK_WHITE, "Reference Black/White"); 96 97 _tagNameMap.put(TAG_COPYRIGHT, "Copyright"); 98 99 _tagNameMap.put(TAG_TIME_ZONE_OFFSET, "Time Zone Offset"); 100 101 _tagNameMap.put(TAG_WIN_AUTHOR, "Windows XP Author"); 102 _tagNameMap.put(TAG_WIN_COMMENT, "Windows XP Comment"); 103 _tagNameMap.put(TAG_WIN_KEYWORDS, "Windows XP Keywords"); 104 _tagNameMap.put(TAG_WIN_SUBJECT, "Windows XP Subject"); 105 _tagNameMap.put(TAG_WIN_TITLE, "Windows XP Title"); 106 } 107 108 public ExifIFD0Directory() 109 { 110 this.setDescriptor(new ExifIFD0Descriptor(this)); 51 addExifTagNames(_tagNameMap); 111 52 } 112 53 -
trunk/src/com/drew/metadata/exif/ExifInteropDescriptor.java
r8132 r8243 22 22 23 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable;25 import com.drew.metadata.TagDescriptor;26 27 import static com.drew.metadata.exif.ExifInteropDirectory.*;28 24 29 25 /** … … 32 28 * @author Drew Noakes https://drewnoakes.com 33 29 */ 34 public class ExifInteropDescriptor extends TagDescriptor<ExifInteropDirectory>30 public class ExifInteropDescriptor extends ExifDescriptorBase<ExifInteropDirectory> 35 31 { 36 32 public ExifInteropDescriptor(@NotNull ExifInteropDirectory directory) … … 38 34 super(directory); 39 35 } 40 41 @Override42 @Nullable43 public String getDescription(int tagType)44 {45 switch (tagType) {46 case TAG_INTEROP_INDEX:47 return getInteropIndexDescription();48 case TAG_INTEROP_VERSION:49 return getInteropVersionDescription();50 default:51 return super.getDescription(tagType);52 }53 }54 55 @Nullable56 public String getInteropVersionDescription()57 {58 return getVersionBytesDescription(TAG_INTEROP_VERSION, 2);59 }60 61 @Nullable62 public String getInteropIndexDescription()63 {64 String value = _directory.getString(TAG_INTEROP_INDEX);65 66 if (value == null)67 return null;68 69 return "R98".equalsIgnoreCase(value.trim())70 ? "Recommended Exif Interoperability Rules (ExifR98)"71 : "Unknown (" + value + ")";72 }73 36 } -
trunk/src/com/drew/metadata/exif/ExifInteropDirectory.java
r8132 r8243 22 22 23 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.metadata.Directory;25 24 26 25 import java.util.HashMap; … … 31 30 * @author Drew Noakes https://drewnoakes.com 32 31 */ 33 public class ExifInteropDirectory extends Directory32 public class ExifInteropDirectory extends ExifDirectoryBase 34 33 { 35 public static final int TAG_INTEROP_INDEX = 0x0001;36 public static final int TAG_INTEROP_VERSION = 0x0002;37 public static final int TAG_RELATED_IMAGE_FILE_FORMAT = 0x1000;38 public static final int TAG_RELATED_IMAGE_WIDTH = 0x1001;39 public static final int TAG_RELATED_IMAGE_LENGTH = 0x1002;40 41 34 @NotNull 42 35 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); … … 44 37 static 45 38 { 46 _tagNameMap.put(TAG_INTEROP_INDEX, "Interoperability Index"); 47 _tagNameMap.put(TAG_INTEROP_VERSION, "Interoperability Version"); 48 _tagNameMap.put(TAG_RELATED_IMAGE_FILE_FORMAT, "Related Image File Format"); 49 _tagNameMap.put(TAG_RELATED_IMAGE_WIDTH, "Related Image Width"); 50 _tagNameMap.put(TAG_RELATED_IMAGE_LENGTH, "Related Image Length"); 39 addExifTagNames(_tagNameMap); 51 40 } 52 41 -
trunk/src/com/drew/metadata/exif/ExifReader.java
r8132 r8243 26 26 import com.drew.imaging.tiff.TiffReader; 27 27 import com.drew.lang.ByteArrayReader; 28 import com.drew.lang.RandomAccessReader; 28 29 import com.drew.lang.annotations.NotNull; 29 30 import com.drew.metadata.Metadata; … … 41 42 public class ExifReader implements JpegSegmentMetadataReader 42 43 { 43 /** 44 * The offset at which the TIFF data actually starts. This may be necessary when, for example, processing 45 * JPEG Exif data from APP0 which has a 6-byte preamble before starting the TIFF data. 46 */ 47 private static final String JPEG_EXIF_SEGMENT_PREAMBLE = "Exif\0\0"; 44 /** Exif data stored in JPEG files' APP1 segment are preceded by this six character preamble. */ 45 public static final String JPEG_SEGMENT_PREAMBLE = "Exif\0\0"; 48 46 49 47 private boolean _storeThumbnailBytes = true; … … 65 63 } 66 64 67 public boolean canProcess(@NotNull final byte[] segmentBytes, @NotNull final JpegSegmentType segmentType)65 public void readJpegSegments(@NotNull final Iterable<byte[]> segments, @NotNull final Metadata metadata, @NotNull final JpegSegmentType segmentType) 68 66 { 69 return segmentBytes.length >= JPEG_EXIF_SEGMENT_PREAMBLE.length() && new String(segmentBytes, 0, JPEG_EXIF_SEGMENT_PREAMBLE.length()).equalsIgnoreCase(JPEG_EXIF_SEGMENT_PREAMBLE); 67 assert(segmentType == JpegSegmentType.APP1); 68 69 for (byte[] segmentBytes : segments) { 70 // Filter any segments containing unexpected preambles 71 if (segmentBytes.length < JPEG_SEGMENT_PREAMBLE.length() || !new String(segmentBytes, 0, JPEG_SEGMENT_PREAMBLE.length()).equals(JPEG_SEGMENT_PREAMBLE)) 72 continue; 73 extract(new ByteArrayReader(segmentBytes), metadata, JPEG_SEGMENT_PREAMBLE.length()); 74 } 70 75 } 71 76 72 public void extract(@NotNull final byte[] segmentBytes, @NotNull final Metadata metadata, @NotNull final JpegSegmentType segmentType) 77 /** Reads TIFF formatted Exif data from start of the specified {@link RandomAccessReader}. */ 78 public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata) 73 79 { 74 if (segmentBytes == null) 75 throw new NullPointerException("segmentBytes cannot be null"); 76 if (metadata == null) 77 throw new NullPointerException("metadata cannot be null"); 78 if (segmentType == null) 79 throw new NullPointerException("segmentType cannot be null"); 80 extract(reader, metadata, 0); 81 } 80 82 83 /** Reads TIFF formatted Exif data a specified offset within a {@link RandomAccessReader}. */ 84 public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata, int readerOffset) 85 { 81 86 try { 82 ByteArrayReader reader = new ByteArrayReader(segmentBytes);83 84 //85 // Check for the header preamble86 //87 try {88 if (!reader.getString(0, JPEG_EXIF_SEGMENT_PREAMBLE.length()).equals(JPEG_EXIF_SEGMENT_PREAMBLE)) {89 // TODO what do to with this error state?90 System.err.println("Invalid JPEG Exif segment preamble");91 return;92 }93 } catch (IOException e) {94 // TODO what do to with this error state?95 e.printStackTrace(System.err);96 return;97 }98 99 //100 87 // Read the TIFF-formatted Exif data 101 //102 88 new TiffReader().processTiff( 103 89 reader, 104 90 new ExifTiffHandler(metadata, _storeThumbnailBytes), 105 JPEG_EXIF_SEGMENT_PREAMBLE.length()91 readerOffset 106 92 ); 107 108 93 } catch (TiffProcessingException e) { 109 94 // TODO what do to with this error state? -
trunk/src/com/drew/metadata/exif/ExifSubIFDDescriptor.java
r8132 r8243 21 21 package com.drew.metadata.exif; 22 22 23 import com.drew.imaging.PhotographicConversions;24 import com.drew.lang.Rational;25 23 import com.drew.lang.annotations.NotNull; 26 import com.drew.lang.annotations.Nullable;27 import com.drew.metadata.TagDescriptor;28 29 import java.io.UnsupportedEncodingException;30 import java.text.DecimalFormat;31 import java.util.HashMap;32 import java.util.Map;33 34 import static com.drew.metadata.exif.ExifSubIFDDirectory.*;35 24 36 25 /** … … 39 28 * @author Drew Noakes https://drewnoakes.com 40 29 */ 41 public class ExifSubIFDDescriptor extends TagDescriptor<ExifSubIFDDirectory>30 public class ExifSubIFDDescriptor extends ExifDescriptorBase<ExifSubIFDDirectory> 42 31 { 43 /**44 * Dictates whether rational values will be represented in decimal format in instances45 * where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3).46 */47 private final boolean _allowDecimalRepresentationOfRationals = true;48 49 @NotNull50 private static final java.text.DecimalFormat SimpleDecimalFormatter = new DecimalFormat("0.#");51 52 32 public ExifSubIFDDescriptor(@NotNull ExifSubIFDDirectory directory) 53 33 { 54 34 super(directory); 55 35 } 56 57 // Note for the potential addition of brightness presentation in eV:58 // Brightness of taken subject. To calculate Exposure(Ev) from BrightnessValue(Bv),59 // you must add SensitivityValue(Sv).60 // Ev=BV+Sv Sv=log2(ISOSpeedRating/3.125)61 // ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.62 63 /**64 * Returns a descriptive value of the specified tag for this image.65 * Where possible, known values will be substituted here in place of the raw66 * tokens actually kept in the Exif segment. If no substitution is67 * available, the value provided by getString(int) will be returned.68 *69 * @param tagType the tag to find a description for70 * @return a description of the image's value for the specified tag, or71 * <code>null</code> if the tag hasn't been defined.72 */73 @Override74 @Nullable75 public String getDescription(int tagType)76 {77 switch (tagType) {78 case TAG_NEW_SUBFILE_TYPE:79 return getNewSubfileTypeDescription();80 case TAG_SUBFILE_TYPE:81 return getSubfileTypeDescription();82 case TAG_THRESHOLDING:83 return getThresholdingDescription();84 case TAG_FILL_ORDER:85 return getFillOrderDescription();86 case TAG_EXPOSURE_TIME:87 return getExposureTimeDescription();88 case TAG_SHUTTER_SPEED:89 return getShutterSpeedDescription();90 case TAG_FNUMBER:91 return getFNumberDescription();92 case TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL:93 return getCompressedAverageBitsPerPixelDescription();94 case TAG_SUBJECT_DISTANCE:95 return getSubjectDistanceDescription();96 case TAG_METERING_MODE:97 return getMeteringModeDescription();98 case TAG_WHITE_BALANCE:99 return getWhiteBalanceDescription();100 case TAG_FLASH:101 return getFlashDescription();102 case TAG_FOCAL_LENGTH:103 return getFocalLengthDescription();104 case TAG_COLOR_SPACE:105 return getColorSpaceDescription();106 case TAG_EXIF_IMAGE_WIDTH:107 return getExifImageWidthDescription();108 case TAG_EXIF_IMAGE_HEIGHT:109 return getExifImageHeightDescription();110 case TAG_FOCAL_PLANE_RESOLUTION_UNIT:111 return getFocalPlaneResolutionUnitDescription();112 case TAG_FOCAL_PLANE_X_RESOLUTION:113 return getFocalPlaneXResolutionDescription();114 case TAG_FOCAL_PLANE_Y_RESOLUTION:115 return getFocalPlaneYResolutionDescription();116 case TAG_BITS_PER_SAMPLE:117 return getBitsPerSampleDescription();118 case TAG_PHOTOMETRIC_INTERPRETATION:119 return getPhotometricInterpretationDescription();120 case TAG_ROWS_PER_STRIP:121 return getRowsPerStripDescription();122 case TAG_STRIP_BYTE_COUNTS:123 return getStripByteCountsDescription();124 case TAG_SAMPLES_PER_PIXEL:125 return getSamplesPerPixelDescription();126 case TAG_PLANAR_CONFIGURATION:127 return getPlanarConfigurationDescription();128 case TAG_YCBCR_SUBSAMPLING:129 return getYCbCrSubsamplingDescription();130 case TAG_EXPOSURE_PROGRAM:131 return getExposureProgramDescription();132 case TAG_APERTURE:133 return getApertureValueDescription();134 case TAG_MAX_APERTURE:135 return getMaxApertureValueDescription();136 case TAG_SENSING_METHOD:137 return getSensingMethodDescription();138 case TAG_EXPOSURE_BIAS:139 return getExposureBiasDescription();140 case TAG_FILE_SOURCE:141 return getFileSourceDescription();142 case TAG_SCENE_TYPE:143 return getSceneTypeDescription();144 case TAG_COMPONENTS_CONFIGURATION:145 return getComponentConfigurationDescription();146 case TAG_EXIF_VERSION:147 return getExifVersionDescription();148 case TAG_FLASHPIX_VERSION:149 return getFlashPixVersionDescription();150 case TAG_ISO_EQUIVALENT:151 return getIsoEquivalentDescription();152 case TAG_USER_COMMENT:153 return getUserCommentDescription();154 case TAG_CUSTOM_RENDERED:155 return getCustomRenderedDescription();156 case TAG_EXPOSURE_MODE:157 return getExposureModeDescription();158 case TAG_WHITE_BALANCE_MODE:159 return getWhiteBalanceModeDescription();160 case TAG_DIGITAL_ZOOM_RATIO:161 return getDigitalZoomRatioDescription();162 case TAG_35MM_FILM_EQUIV_FOCAL_LENGTH:163 return get35mmFilmEquivFocalLengthDescription();164 case TAG_SCENE_CAPTURE_TYPE:165 return getSceneCaptureTypeDescription();166 case TAG_GAIN_CONTROL:167 return getGainControlDescription();168 case TAG_CONTRAST:169 return getContrastDescription();170 case TAG_SATURATION:171 return getSaturationDescription();172 case TAG_SHARPNESS:173 return getSharpnessDescription();174 case TAG_SUBJECT_DISTANCE_RANGE:175 return getSubjectDistanceRangeDescription();176 default:177 return super.getDescription(tagType);178 }179 }180 181 @Nullable182 public String getNewSubfileTypeDescription()183 {184 return getIndexedDescription(TAG_NEW_SUBFILE_TYPE, 1,185 "Full-resolution image",186 "Reduced-resolution image",187 "Single page of multi-page reduced-resolution image",188 "Transparency mask",189 "Transparency mask of reduced-resolution image",190 "Transparency mask of multi-page image",191 "Transparency mask of reduced-resolution multi-page image"192 );193 }194 195 @Nullable196 public String getSubfileTypeDescription()197 {198 return getIndexedDescription(TAG_SUBFILE_TYPE, 1,199 "Full-resolution image",200 "Reduced-resolution image",201 "Single page of multi-page image"202 );203 }204 205 @Nullable206 public String getThresholdingDescription()207 {208 return getIndexedDescription(TAG_THRESHOLDING, 1,209 "No dithering or halftoning",210 "Ordered dither or halftone",211 "Randomized dither"212 );213 }214 215 @Nullable216 public String getFillOrderDescription()217 {218 return getIndexedDescription(TAG_FILL_ORDER, 1,219 "Normal",220 "Reversed"221 );222 }223 224 @Nullable225 public String getSubjectDistanceRangeDescription()226 {227 return getIndexedDescription(TAG_SUBJECT_DISTANCE_RANGE,228 "Unknown",229 "Macro",230 "Close view",231 "Distant view"232 );233 }234 235 @Nullable236 public String getSharpnessDescription()237 {238 return getIndexedDescription(TAG_SHARPNESS,239 "None",240 "Low",241 "Hard"242 );243 }244 245 @Nullable246 public String getSaturationDescription()247 {248 return getIndexedDescription(TAG_SATURATION,249 "None",250 "Low saturation",251 "High saturation"252 );253 }254 255 @Nullable256 public String getContrastDescription()257 {258 return getIndexedDescription(TAG_CONTRAST,259 "None",260 "Soft",261 "Hard"262 );263 }264 265 @Nullable266 public String getGainControlDescription()267 {268 return getIndexedDescription(TAG_GAIN_CONTROL,269 "None",270 "Low gain up",271 "Low gain down",272 "High gain up",273 "High gain down"274 );275 }276 277 @Nullable278 public String getSceneCaptureTypeDescription()279 {280 return getIndexedDescription(TAG_SCENE_CAPTURE_TYPE,281 "Standard",282 "Landscape",283 "Portrait",284 "Night scene"285 );286 }287 288 @Nullable289 public String get35mmFilmEquivFocalLengthDescription()290 {291 Integer value = _directory.getInteger(TAG_35MM_FILM_EQUIV_FOCAL_LENGTH);292 return value == null293 ? null294 : value == 0295 ? "Unknown"296 : SimpleDecimalFormatter.format(value) + "mm";297 }298 299 @Nullable300 public String getDigitalZoomRatioDescription()301 {302 Rational value = _directory.getRational(TAG_DIGITAL_ZOOM_RATIO);303 return value == null304 ? null305 : value.getNumerator() == 0306 ? "Digital zoom not used."307 : SimpleDecimalFormatter.format(value.doubleValue());308 }309 310 @Nullable311 public String getWhiteBalanceModeDescription()312 {313 return getIndexedDescription(TAG_WHITE_BALANCE_MODE,314 "Auto white balance",315 "Manual white balance"316 );317 }318 319 @Nullable320 public String getExposureModeDescription()321 {322 return getIndexedDescription(TAG_EXPOSURE_MODE,323 "Auto exposure",324 "Manual exposure",325 "Auto bracket"326 );327 }328 329 @Nullable330 public String getCustomRenderedDescription()331 {332 return getIndexedDescription(TAG_CUSTOM_RENDERED,333 "Normal process",334 "Custom process"335 );336 }337 338 @Nullable339 public String getUserCommentDescription()340 {341 byte[] commentBytes = _directory.getByteArray(TAG_USER_COMMENT);342 if (commentBytes == null)343 return null;344 if (commentBytes.length == 0)345 return "";346 347 final Map<String, String> encodingMap = new HashMap<String, String>();348 encodingMap.put("ASCII", System.getProperty("file.encoding")); // Someone suggested "ISO-8859-1".349 encodingMap.put("UNICODE", "UTF-16LE");350 encodingMap.put("JIS", "Shift-JIS"); // We assume this charset for now. Another suggestion is "JIS".351 352 try {353 if (commentBytes.length >= 10) {354 String firstTenBytesString = new String(commentBytes, 0, 10);355 356 // try each encoding name357 for (Map.Entry<String, String> pair : encodingMap.entrySet()) {358 String encodingName = pair.getKey();359 String charset = pair.getValue();360 if (firstTenBytesString.startsWith(encodingName)) {361 // skip any null or blank characters commonly present after the encoding name, up to a limit of 10 from the start362 for (int j = encodingName.length(); j < 10; j++) {363 byte b = commentBytes[j];364 if (b != '\0' && b != ' ')365 return new String(commentBytes, j, commentBytes.length - j, charset).trim();366 }367 return new String(commentBytes, 10, commentBytes.length - 10, charset).trim();368 }369 }370 }371 // special handling fell through, return a plain string representation372 return new String(commentBytes, System.getProperty("file.encoding")).trim();373 } catch (UnsupportedEncodingException ex) {374 return null;375 }376 }377 378 @Nullable379 public String getIsoEquivalentDescription()380 {381 // Have seen an exception here from files produced by ACDSEE that stored an int[] here with two values382 Integer isoEquiv = _directory.getInteger(TAG_ISO_EQUIVALENT);383 // There used to be a check here that multiplied ISO values < 50 by 200.384 // Issue 36 shows a smart-phone image from a Samsung Galaxy S2 with ISO-40.385 return isoEquiv != null386 ? Integer.toString(isoEquiv)387 : null;388 }389 390 @Nullable391 public String getExifVersionDescription()392 {393 return getVersionBytesDescription(TAG_EXIF_VERSION, 2);394 }395 396 @Nullable397 public String getFlashPixVersionDescription()398 {399 return getVersionBytesDescription(TAG_FLASHPIX_VERSION, 2);400 }401 402 @Nullable403 public String getSceneTypeDescription()404 {405 return getIndexedDescription(TAG_SCENE_TYPE,406 1,407 "Directly photographed image"408 );409 }410 411 @Nullable412 public String getFileSourceDescription()413 {414 return getIndexedDescription(TAG_FILE_SOURCE,415 1,416 "Film Scanner",417 "Reflection Print Scanner",418 "Digital Still Camera (DSC)"419 );420 }421 422 @Nullable423 public String getExposureBiasDescription()424 {425 Rational value = _directory.getRational(TAG_EXPOSURE_BIAS);426 if (value == null)427 return null;428 return value.toSimpleString(true) + " EV";429 }430 431 @Nullable432 public String getMaxApertureValueDescription()433 {434 Double aperture = _directory.getDoubleObject(TAG_MAX_APERTURE);435 if (aperture == null)436 return null;437 double fStop = PhotographicConversions.apertureToFStop(aperture);438 return "F" + SimpleDecimalFormatter.format(fStop);439 }440 441 @Nullable442 public String getApertureValueDescription()443 {444 Double aperture = _directory.getDoubleObject(TAG_APERTURE);445 if (aperture == null)446 return null;447 double fStop = PhotographicConversions.apertureToFStop(aperture);448 return "F" + SimpleDecimalFormatter.format(fStop);449 }450 451 @Nullable452 public String getExposureProgramDescription()453 {454 return getIndexedDescription(TAG_EXPOSURE_PROGRAM,455 1,456 "Manual control",457 "Program normal",458 "Aperture priority",459 "Shutter priority",460 "Program creative (slow program)",461 "Program action (high-speed program)",462 "Portrait mode",463 "Landscape mode"464 );465 }466 467 @Nullable468 public String getYCbCrSubsamplingDescription()469 {470 int[] positions = _directory.getIntArray(TAG_YCBCR_SUBSAMPLING);471 if (positions == null)472 return null;473 if (positions[0] == 2 && positions[1] == 1) {474 return "YCbCr4:2:2";475 } else if (positions[0] == 2 && positions[1] == 2) {476 return "YCbCr4:2:0";477 } else {478 return "(Unknown)";479 }480 }481 482 @Nullable483 public String getPlanarConfigurationDescription()484 {485 // When image format is no compression YCbCr, this value shows byte aligns of YCbCr486 // data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling487 // pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr488 // plane format.489 return getIndexedDescription(TAG_PLANAR_CONFIGURATION,490 1,491 "Chunky (contiguous for each subsampling pixel)",492 "Separate (Y-plane/Cb-plane/Cr-plane format)"493 );494 }495 496 @Nullable497 public String getSamplesPerPixelDescription()498 {499 String value = _directory.getString(TAG_SAMPLES_PER_PIXEL);500 return value == null ? null : value + " samples/pixel";501 }502 503 @Nullable504 public String getRowsPerStripDescription()505 {506 final String value = _directory.getString(TAG_ROWS_PER_STRIP);507 return value == null ? null : value + " rows/strip";508 }509 510 @Nullable511 public String getStripByteCountsDescription()512 {513 final String value = _directory.getString(TAG_STRIP_BYTE_COUNTS);514 return value == null ? null : value + " bytes";515 }516 517 @Nullable518 public String getPhotometricInterpretationDescription()519 {520 // Shows the color space of the image data components521 Integer value = _directory.getInteger(TAG_PHOTOMETRIC_INTERPRETATION);522 if (value == null)523 return null;524 switch (value) {525 case 0: return "WhiteIsZero";526 case 1: return "BlackIsZero";527 case 2: return "RGB";528 case 3: return "RGB Palette";529 case 4: return "Transparency Mask";530 case 5: return "CMYK";531 case 6: return "YCbCr";532 case 8: return "CIELab";533 case 9: return "ICCLab";534 case 10: return "ITULab";535 case 32803: return "Color Filter Array";536 case 32844: return "Pixar LogL";537 case 32845: return "Pixar LogLuv";538 case 32892: return "Linear Raw";539 default:540 return "Unknown colour space";541 }542 }543 544 @Nullable545 public String getBitsPerSampleDescription()546 {547 String value = _directory.getString(TAG_BITS_PER_SAMPLE);548 return value == null ? null : value + " bits/component/pixel";549 }550 551 @Nullable552 public String getFocalPlaneXResolutionDescription()553 {554 Rational rational = _directory.getRational(TAG_FOCAL_PLANE_X_RESOLUTION);555 if (rational == null)556 return null;557 final String unit = getFocalPlaneResolutionUnitDescription();558 return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals)559 + (unit == null ? "" : " " + unit.toLowerCase());560 }561 562 @Nullable563 public String getFocalPlaneYResolutionDescription()564 {565 Rational rational = _directory.getRational(TAG_FOCAL_PLANE_Y_RESOLUTION);566 if (rational == null)567 return null;568 final String unit = getFocalPlaneResolutionUnitDescription();569 return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals)570 + (unit == null ? "" : " " + unit.toLowerCase());571 }572 573 @Nullable574 public String getFocalPlaneResolutionUnitDescription()575 {576 // Unit of FocalPlaneXResolution/FocalPlaneYResolution.577 // '1' means no-unit, '2' inch, '3' centimeter.578 return getIndexedDescription(TAG_FOCAL_PLANE_RESOLUTION_UNIT,579 1,580 "(No unit)",581 "Inches",582 "cm"583 );584 }585 586 @Nullable587 public String getExifImageWidthDescription()588 {589 final Integer value = _directory.getInteger(TAG_EXIF_IMAGE_WIDTH);590 return value == null ? null : value + " pixels";591 }592 593 @Nullable594 public String getExifImageHeightDescription()595 {596 final Integer value = _directory.getInteger(TAG_EXIF_IMAGE_HEIGHT);597 return value == null ? null : value + " pixels";598 }599 600 @Nullable601 public String getColorSpaceDescription()602 {603 final Integer value = _directory.getInteger(TAG_COLOR_SPACE);604 if (value == null)605 return null;606 if (value == 1)607 return "sRGB";608 if (value == 65535)609 return "Undefined";610 return "Unknown (" + value + ")";611 }612 613 @Nullable614 public String getFocalLengthDescription()615 {616 Rational value = _directory.getRational(TAG_FOCAL_LENGTH);617 if (value == null)618 return null;619 java.text.DecimalFormat formatter = new DecimalFormat("0.0##");620 return formatter.format(value.doubleValue()) + " mm";621 }622 623 @Nullable624 public String getFlashDescription()625 {626 /*627 * This is a bit mask.628 * 0 = flash fired629 * 1 = return detected630 * 2 = return able to be detected631 * 3 = unknown632 * 4 = auto used633 * 5 = unknown634 * 6 = red eye reduction used635 */636 637 final Integer value = _directory.getInteger(TAG_FLASH);638 639 if (value == null)640 return null;641 642 StringBuilder sb = new StringBuilder();643 644 if ((value & 0x1) != 0)645 sb.append("Flash fired");646 else647 sb.append("Flash did not fire");648 649 // check if we're able to detect a return, before we mention it650 if ((value & 0x4) != 0) {651 if ((value & 0x2) != 0)652 sb.append(", return detected");653 else654 sb.append(", return not detected");655 }656 657 if ((value & 0x10) != 0)658 sb.append(", auto");659 660 if ((value & 0x40) != 0)661 sb.append(", red-eye reduction");662 663 return sb.toString();664 }665 666 @Nullable667 public String getWhiteBalanceDescription()668 {669 // '0' means unknown, '1' daylight, '2' fluorescent, '3' tungsten, '10' flash,670 // '17' standard light A, '18' standard light B, '19' standard light C, '20' D55,671 // '21' D65, '22' D75, '255' other.672 final Integer value = _directory.getInteger(TAG_WHITE_BALANCE);673 if (value == null)674 return null;675 switch (value) {676 case 0: return "Unknown";677 case 1: return "Daylight";678 case 2: return "Florescent";679 case 3: return "Tungsten";680 case 10: return "Flash";681 case 17: return "Standard light";682 case 18: return "Standard light (B)";683 case 19: return "Standard light (C)";684 case 20: return "D55";685 case 21: return "D65";686 case 22: return "D75";687 case 255: return "(Other)";688 default:689 return "Unknown (" + value + ")";690 }691 }692 693 @Nullable694 public String getMeteringModeDescription()695 {696 // '0' means unknown, '1' average, '2' center weighted average, '3' spot697 // '4' multi-spot, '5' multi-segment, '6' partial, '255' other698 Integer value = _directory.getInteger(TAG_METERING_MODE);699 if (value == null)700 return null;701 switch (value) {702 case 0: return "Unknown";703 case 1: return "Average";704 case 2: return "Center weighted average";705 case 3: return "Spot";706 case 4: return "Multi-spot";707 case 5: return "Multi-segment";708 case 6: return "Partial";709 case 255: return "(Other)";710 default:711 return "";712 }713 }714 715 @Nullable716 public String getSubjectDistanceDescription()717 {718 Rational value = _directory.getRational(TAG_SUBJECT_DISTANCE);719 if (value == null)720 return null;721 java.text.DecimalFormat formatter = new DecimalFormat("0.0##");722 return formatter.format(value.doubleValue()) + " metres";723 }724 725 @Nullable726 public String getCompressedAverageBitsPerPixelDescription()727 {728 Rational value = _directory.getRational(TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL);729 if (value == null)730 return null;731 String ratio = value.toSimpleString(_allowDecimalRepresentationOfRationals);732 return value.isInteger() && value.intValue() == 1733 ? ratio + " bit/pixel"734 : ratio + " bits/pixel";735 }736 737 @Nullable738 public String getExposureTimeDescription()739 {740 String value = _directory.getString(TAG_EXPOSURE_TIME);741 return value == null ? null : value + " sec";742 }743 744 @Nullable745 public String getShutterSpeedDescription()746 {747 // I believe this method to now be stable, but am leaving some alternative snippets of748 // code in here, to assist anyone who's looking into this (given that I don't have a public CVS).749 750 // float apexValue = _directory.getFloat(ExifSubIFDDirectory.TAG_SHUTTER_SPEED);751 // int apexPower = (int)Math.pow(2.0, apexValue);752 // return "1/" + apexPower + " sec";753 // TODO test this method754 // thanks to Mark Edwards for spotting and patching a bug in the calculation of this755 // description (spotted bug using a Canon EOS 300D)756 // thanks also to Gli Blr for spotting this bug757 Float apexValue = _directory.getFloatObject(TAG_SHUTTER_SPEED);758 if (apexValue == null)759 return null;760 if (apexValue <= 1) {761 float apexPower = (float)(1 / (Math.exp(apexValue * Math.log(2))));762 long apexPower10 = Math.round((double)apexPower * 10.0);763 float fApexPower = (float)apexPower10 / 10.0f;764 return fApexPower + " sec";765 } else {766 int apexPower = (int)((Math.exp(apexValue * Math.log(2))));767 return "1/" + apexPower + " sec";768 }769 770 /*771 // This alternative implementation offered by Bill Richards772 // TODO determine which is the correct / more-correct implementation773 double apexValue = _directory.getDouble(ExifSubIFDDirectory.TAG_SHUTTER_SPEED);774 double apexPower = Math.pow(2.0, apexValue);775 776 StringBuffer sb = new StringBuffer();777 if (apexPower > 1)778 apexPower = Math.floor(apexPower);779 780 if (apexPower < 1) {781 sb.append((int)Math.round(1/apexPower));782 } else {783 sb.append("1/");784 sb.append((int)apexPower);785 }786 sb.append(" sec");787 return sb.toString();788 */789 }790 791 @Nullable792 public String getFNumberDescription()793 {794 Rational value = _directory.getRational(TAG_FNUMBER);795 if (value == null)796 return null;797 return "F" + SimpleDecimalFormatter.format(value.doubleValue());798 }799 800 @Nullable801 public String getSensingMethodDescription()802 {803 // '1' Not defined, '2' One-chip color area sensor, '3' Two-chip color area sensor804 // '4' Three-chip color area sensor, '5' Color sequential area sensor805 // '7' Trilinear sensor '8' Color sequential linear sensor, 'Other' reserved806 return getIndexedDescription(TAG_SENSING_METHOD,807 1,808 "(Not defined)",809 "One-chip color area sensor",810 "Two-chip color area sensor",811 "Three-chip color area sensor",812 "Color sequential area sensor",813 null,814 "Trilinear sensor",815 "Color sequential linear sensor"816 );817 }818 819 @Nullable820 public String getComponentConfigurationDescription()821 {822 int[] components = _directory.getIntArray(TAG_COMPONENTS_CONFIGURATION);823 if (components == null)824 return null;825 String[] componentStrings = {"", "Y", "Cb", "Cr", "R", "G", "B"};826 StringBuilder componentConfig = new StringBuilder();827 for (int i = 0; i < Math.min(4, components.length); i++) {828 int j = components[i];829 if (j > 0 && j < componentStrings.length) {830 componentConfig.append(componentStrings[j]);831 }832 }833 return componentConfig.toString();834 }835 36 } -
trunk/src/com/drew/metadata/exif/ExifSubIFDDirectory.java
r8132 r8243 22 22 23 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.metadata.Directory;25 24 26 25 import java.util.HashMap; … … 31 30 * @author Drew Noakes https://drewnoakes.com 32 31 */ 33 public class ExifSubIFDDirectory extends Directory32 public class ExifSubIFDDirectory extends ExifDirectoryBase 34 33 { 35 /**36 * The actual aperture value of lens when the image was taken. Unit is APEX.37 * To convert this value to ordinary F-number (F-stop), calculate this value's38 * power of root 2 (=1.4142). For example, if the ApertureValue is '5',39 * F-number is 1.4142^5 = F5.6.40 */41 public static final int TAG_APERTURE = 0x9202;42 /**43 * When image format is no compression, this value shows the number of bits44 * per component for each pixel. Usually this value is '8,8,8'.45 */46 public static final int TAG_BITS_PER_SAMPLE = 0x0102;47 48 /**49 * Shows the color space of the image data components.50 * 0 = WhiteIsZero51 * 1 = BlackIsZero52 * 2 = RGB53 * 3 = RGB Palette54 * 4 = Transparency Mask55 * 5 = CMYK56 * 6 = YCbCr57 * 8 = CIELab58 * 9 = ICCLab59 * 10 = ITULab60 * 32803 = Color Filter Array61 * 32844 = Pixar LogL62 * 32845 = Pixar LogLuv63 * 34892 = Linear Raw64 */65 public static final int TAG_PHOTOMETRIC_INTERPRETATION = 0x0106;66 67 /**68 * 1 = No dithering or halftoning69 * 2 = Ordered dither or halftone70 * 3 = Randomized dither71 */72 public static final int TAG_THRESHOLDING = 0x0107;73 74 /**75 * 1 = Normal76 * 2 = Reversed77 */78 public static final int TAG_FILL_ORDER = 0x010A;79 public static final int TAG_DOCUMENT_NAME = 0x010D;80 81 /** The position in the file of raster data. */82 public static final int TAG_STRIP_OFFSETS = 0x0111;83 /** Each pixel is composed of this many samples. */84 public static final int TAG_SAMPLES_PER_PIXEL = 0x0115;85 /** The raster is codified by a single block of data holding this many rows. */86 public static final int TAG_ROWS_PER_STRIP = 0x116;87 /** The size of the raster data in bytes. */88 public static final int TAG_STRIP_BYTE_COUNTS = 0x0117;89 public static final int TAG_MIN_SAMPLE_VALUE = 0x0118;90 public static final int TAG_MAX_SAMPLE_VALUE = 0x0119;91 /**92 * When image format is no compression YCbCr, this value shows byte aligns of93 * YCbCr data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for94 * each subsampling pixel. If value is '2', Y/Cb/Cr value is separated and95 * stored to Y plane/Cb plane/Cr plane format.96 */97 public static final int TAG_PLANAR_CONFIGURATION = 0x011C;98 public static final int TAG_YCBCR_SUBSAMPLING = 0x0212;99 100 /**101 * The new subfile type tag.102 * 0 = Full-resolution Image103 * 1 = Reduced-resolution image104 * 2 = Single page of multi-page image105 * 3 = Single page of multi-page reduced-resolution image106 * 4 = Transparency mask107 * 5 = Transparency mask of reduced-resolution image108 * 6 = Transparency mask of multi-page image109 * 7 = Transparency mask of reduced-resolution multi-page image110 */111 public static final int TAG_NEW_SUBFILE_TYPE = 0x00FE;112 /**113 * The old subfile type tag.114 * 1 = Full-resolution image (Main image)115 * 2 = Reduced-resolution image (Thumbnail)116 * 3 = Single page of multi-page image117 */118 public static final int TAG_SUBFILE_TYPE = 0x00FF;119 public static final int TAG_TRANSFER_FUNCTION = 0x012D;120 public static final int TAG_PREDICTOR = 0x013D;121 public static final int TAG_TILE_WIDTH = 0x0142;122 public static final int TAG_TILE_LENGTH = 0x0143;123 public static final int TAG_TILE_OFFSETS = 0x0144;124 public static final int TAG_TILE_BYTE_COUNTS = 0x0145;125 public static final int TAG_JPEG_TABLES = 0x015B;126 public static final int TAG_CFA_REPEAT_PATTERN_DIM = 0x828D;127 /** There are two definitions for CFA pattern, I don't know the difference... */128 public static final int TAG_CFA_PATTERN_2 = 0x828E;129 public static final int TAG_BATTERY_LEVEL = 0x828F;130 public static final int TAG_IPTC_NAA = 0x83BB;131 public static final int TAG_INTER_COLOR_PROFILE = 0x8773;132 public static final int TAG_SPECTRAL_SENSITIVITY = 0x8824;133 /**134 * Indicates the Opto-Electric Conversion Function (OECF) specified in ISO 14524.135 * <p>136 * OECF is the relationship between the camera optical input and the image values.137 * <p>138 * The values are:139 * <ul>140 * <li>Two shorts, indicating respectively number of columns, and number of rows.</li>141 * <li>For each column, the column name in a null-terminated ASCII string.</li>142 * <li>For each cell, an SRATIONAL value.</li>143 * </ul>144 */145 public static final int TAG_OPTO_ELECTRIC_CONVERSION_FUNCTION = 0x8828;146 public static final int TAG_INTERLACE = 0x8829;147 public static final int TAG_TIME_ZONE_OFFSET = 0x882A;148 public static final int TAG_SELF_TIMER_MODE = 0x882B;149 public static final int TAG_FLASH_ENERGY = 0x920B;150 public static final int TAG_SPATIAL_FREQ_RESPONSE = 0x920C;151 public static final int TAG_NOISE = 0x920D;152 public static final int TAG_IMAGE_NUMBER = 0x9211;153 public static final int TAG_SECURITY_CLASSIFICATION = 0x9212;154 public static final int TAG_IMAGE_HISTORY = 0x9213;155 public static final int TAG_SUBJECT_LOCATION = 0x9214;156 /** There are two definitions for exposure index, I don't know the difference... */157 public static final int TAG_EXPOSURE_INDEX_2 = 0x9215;158 public static final int TAG_TIFF_EP_STANDARD_ID = 0x9216;159 public static final int TAG_FLASH_ENERGY_2 = 0xA20B;160 public static final int TAG_SPATIAL_FREQ_RESPONSE_2 = 0xA20C;161 public static final int TAG_SUBJECT_LOCATION_2 = 0xA214;162 public static final int TAG_PAGE_NAME = 0x011D;163 /**164 * Exposure time (reciprocal of shutter speed). Unit is second.165 */166 public static final int TAG_EXPOSURE_TIME = 0x829A;167 /**168 * The actual F-number(F-stop) of lens when the image was taken.169 */170 public static final int TAG_FNUMBER = 0x829D;171 /**172 * Exposure program that the camera used when image was taken. '1' means173 * manual control, '2' program normal, '3' aperture priority, '4' shutter174 * priority, '5' program creative (slow program), '6' program action175 * (high-speed program), '7' portrait mode, '8' landscape mode.176 */177 public static final int TAG_EXPOSURE_PROGRAM = 0x8822;178 public static final int TAG_ISO_EQUIVALENT = 0x8827;179 public static final int TAG_EXIF_VERSION = 0x9000;180 public static final int TAG_DATETIME_ORIGINAL = 0x9003;181 public static final int TAG_DATETIME_DIGITIZED = 0x9004;182 public static final int TAG_COMPONENTS_CONFIGURATION = 0x9101;183 /**184 * Average (rough estimate) compression level in JPEG bits per pixel.185 * */186 public static final int TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL = 0x9102;187 /**188 * Shutter speed by APEX value. To convert this value to ordinary 'Shutter Speed';189 * calculate this value's power of 2, then reciprocal. For example, if the190 * ShutterSpeedValue is '4', shutter speed is 1/(24)=1/16 second.191 */192 public static final int TAG_SHUTTER_SPEED = 0x9201;193 public static final int TAG_BRIGHTNESS_VALUE = 0x9203;194 public static final int TAG_EXPOSURE_BIAS = 0x9204;195 /**196 * Maximum aperture value of lens. You can convert to F-number by calculating197 * power of root 2 (same process of ApertureValue:0x9202).198 * The actual aperture value of lens when the image was taken. To convert this199 * value to ordinary f-number(f-stop), calculate the value's power of root 2200 * (=1.4142). For example, if the ApertureValue is '5', f-number is 1.41425^5 = F5.6.201 */202 public static final int TAG_MAX_APERTURE = 0x9205;203 /**204 * Indicates the distance the autofocus camera is focused to. Tends to be less accurate as distance increases.205 */206 public static final int TAG_SUBJECT_DISTANCE = 0x9206;207 /**208 * Exposure metering method. '0' means unknown, '1' average, '2' center209 * weighted average, '3' spot, '4' multi-spot, '5' multi-segment, '6' partial,210 * '255' other.211 */212 public static final int TAG_METERING_MODE = 0x9207;213 214 public static final int TAG_LIGHT_SOURCE = 0x9208;215 /**216 * White balance (aka light source). '0' means unknown, '1' daylight,217 * '2' fluorescent, '3' tungsten, '10' flash, '17' standard light A,218 * '18' standard light B, '19' standard light C, '20' D55, '21' D65,219 * '22' D75, '255' other.220 */221 public static final int TAG_WHITE_BALANCE = 0x9208;222 /**223 * 0x0 = 0000000 = No Flash224 * 0x1 = 0000001 = Fired225 * 0x5 = 0000101 = Fired, Return not detected226 * 0x7 = 0000111 = Fired, Return detected227 * 0x9 = 0001001 = On228 * 0xd = 0001101 = On, Return not detected229 * 0xf = 0001111 = On, Return detected230 * 0x10 = 0010000 = Off231 * 0x18 = 0011000 = Auto, Did not fire232 * 0x19 = 0011001 = Auto, Fired233 * 0x1d = 0011101 = Auto, Fired, Return not detected234 * 0x1f = 0011111 = Auto, Fired, Return detected235 * 0x20 = 0100000 = No flash function236 * 0x41 = 1000001 = Fired, Red-eye reduction237 * 0x45 = 1000101 = Fired, Red-eye reduction, Return not detected238 * 0x47 = 1000111 = Fired, Red-eye reduction, Return detected239 * 0x49 = 1001001 = On, Red-eye reduction240 * 0x4d = 1001101 = On, Red-eye reduction, Return not detected241 * 0x4f = 1001111 = On, Red-eye reduction, Return detected242 * 0x59 = 1011001 = Auto, Fired, Red-eye reduction243 * 0x5d = 1011101 = Auto, Fired, Red-eye reduction, Return not detected244 * 0x5f = 1011111 = Auto, Fired, Red-eye reduction, Return detected245 * 6543210 (positions)246 *247 * This is a bitmask.248 * 0 = flash fired249 * 1 = return detected250 * 2 = return able to be detected251 * 3 = unknown252 * 4 = auto used253 * 5 = unknown254 * 6 = red eye reduction used255 */256 public static final int TAG_FLASH = 0x9209;257 /**258 * Focal length of lens used to take image. Unit is millimeter.259 * Nice digital cameras actually save the focal length as a function of how far they are zoomed in.260 */261 public static final int TAG_FOCAL_LENGTH = 0x920A;262 263 /**264 * This tag holds the Exif Makernote. Makernotes are free to be in any format, though they are often IFDs.265 * To determine the format, we consider the starting bytes of the makernote itself and sometimes the266 * camera model and make.267 * <p>268 * The component count for this tag includes all of the bytes needed for the makernote.269 */270 public static final int TAG_MAKERNOTE = 0x927C;271 272 public static final int TAG_USER_COMMENT = 0x9286;273 274 public static final int TAG_SUBSECOND_TIME = 0x9290;275 public static final int TAG_SUBSECOND_TIME_ORIGINAL = 0x9291;276 public static final int TAG_SUBSECOND_TIME_DIGITIZED = 0x9292;277 278 public static final int TAG_FLASHPIX_VERSION = 0xA000;279 /**280 * Defines Color Space. DCF image must use sRGB color space so value is281 * always '1'. If the picture uses the other color space, value is282 * '65535':Uncalibrated.283 */284 public static final int TAG_COLOR_SPACE = 0xA001;285 public static final int TAG_EXIF_IMAGE_WIDTH = 0xA002;286 public static final int TAG_EXIF_IMAGE_HEIGHT = 0xA003;287 public static final int TAG_RELATED_SOUND_FILE = 0xA004;288 289 34 /** This tag is a pointer to the Exif Interop IFD. */ 290 35 public static final int TAG_INTEROP_OFFSET = 0xA005; 291 36 292 public static final int TAG_FOCAL_PLANE_X_RESOLUTION = 0xA20E; 293 public static final int TAG_FOCAL_PLANE_Y_RESOLUTION = 0xA20F; 294 /** 295 * Unit of FocalPlaneXResolution/FocalPlaneYResolution. '1' means no-unit, 296 * '2' inch, '3' centimeter. 297 * 298 * Note: Some of Fujifilm's digicam(e.g.FX2700,FX2900,Finepix4700Z/40i etc) 299 * uses value '3' so it must be 'centimeter', but it seems that they use a 300 * '8.3mm?'(1/3in.?) to their ResolutionUnit. Fuji's BUG? Finepix4900Z has 301 * been changed to use value '2' but it doesn't match to actual value also. 302 */ 303 public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT = 0xA210; 304 public static final int TAG_EXPOSURE_INDEX = 0xA215; 305 public static final int TAG_SENSING_METHOD = 0xA217; 306 public static final int TAG_FILE_SOURCE = 0xA300; 307 public static final int TAG_SCENE_TYPE = 0xA301; 308 public static final int TAG_CFA_PATTERN = 0xA302; 309 310 // these tags new with Exif 2.2 (?) [A401 - A4 311 /** 312 * This tag indicates the use of special processing on image data, such as rendering 313 * geared to output. When special processing is performed, the reader is expected to 314 * disable or minimize any further processing. 315 * Tag = 41985 (A401.H) 316 * Type = SHORT 317 * Count = 1 318 * Default = 0 319 * 0 = Normal process 320 * 1 = Custom process 321 * Other = reserved 322 */ 323 public static final int TAG_CUSTOM_RENDERED = 0xA401; 324 325 /** 326 * This tag indicates the exposure mode set when the image was shot. In auto-bracketing 327 * mode, the camera shoots a series of frames of the same scene at different exposure settings. 328 * Tag = 41986 (A402.H) 329 * Type = SHORT 330 * Count = 1 331 * Default = none 332 * 0 = Auto exposure 333 * 1 = Manual exposure 334 * 2 = Auto bracket 335 * Other = reserved 336 */ 337 public static final int TAG_EXPOSURE_MODE = 0xA402; 338 339 /** 340 * This tag indicates the white balance mode set when the image was shot. 341 * Tag = 41987 (A403.H) 342 * Type = SHORT 343 * Count = 1 344 * Default = none 345 * 0 = Auto white balance 346 * 1 = Manual white balance 347 * Other = reserved 348 */ 349 public static final int TAG_WHITE_BALANCE_MODE = 0xA403; 350 351 /** 352 * This tag indicates the digital zoom ratio when the image was shot. If the 353 * numerator of the recorded value is 0, this indicates that digital zoom was 354 * not used. 355 * Tag = 41988 (A404.H) 356 * Type = RATIONAL 357 * Count = 1 358 * Default = none 359 */ 360 public static final int TAG_DIGITAL_ZOOM_RATIO = 0xA404; 361 362 /** 363 * This tag indicates the equivalent focal length assuming a 35mm film camera, 364 * in mm. A value of 0 means the focal length is unknown. Note that this tag 365 * differs from the FocalLength tag. 366 * Tag = 41989 (A405.H) 367 * Type = SHORT 368 * Count = 1 369 * Default = none 370 */ 371 public static final int TAG_35MM_FILM_EQUIV_FOCAL_LENGTH = 0xA405; 372 373 /** 374 * This tag indicates the type of scene that was shot. It can also be used to 375 * record the mode in which the image was shot. Note that this differs from 376 * the scene type (SceneType) tag. 377 * Tag = 41990 (A406.H) 378 * Type = SHORT 379 * Count = 1 380 * Default = 0 381 * 0 = Standard 382 * 1 = Landscape 383 * 2 = Portrait 384 * 3 = Night scene 385 * Other = reserved 386 */ 387 public static final int TAG_SCENE_CAPTURE_TYPE = 0xA406; 388 389 /** 390 * This tag indicates the degree of overall image gain adjustment. 391 * Tag = 41991 (A407.H) 392 * Type = SHORT 393 * Count = 1 394 * Default = none 395 * 0 = None 396 * 1 = Low gain up 397 * 2 = High gain up 398 * 3 = Low gain down 399 * 4 = High gain down 400 * Other = reserved 401 */ 402 public static final int TAG_GAIN_CONTROL = 0xA407; 403 404 /** 405 * This tag indicates the direction of contrast processing applied by the camera 406 * when the image was shot. 407 * Tag = 41992 (A408.H) 408 * Type = SHORT 409 * Count = 1 410 * Default = 0 411 * 0 = Normal 412 * 1 = Soft 413 * 2 = Hard 414 * Other = reserved 415 */ 416 public static final int TAG_CONTRAST = 0xA408; 417 418 /** 419 * This tag indicates the direction of saturation processing applied by the camera 420 * when the image was shot. 421 * Tag = 41993 (A409.H) 422 * Type = SHORT 423 * Count = 1 424 * Default = 0 425 * 0 = Normal 426 * 1 = Low saturation 427 * 2 = High saturation 428 * Other = reserved 429 */ 430 public static final int TAG_SATURATION = 0xA409; 431 432 /** 433 * This tag indicates the direction of sharpness processing applied by the camera 434 * when the image was shot. 435 * Tag = 41994 (A40A.H) 436 * Type = SHORT 437 * Count = 1 438 * Default = 0 439 * 0 = Normal 440 * 1 = Soft 441 * 2 = Hard 442 * Other = reserved 443 */ 444 public static final int TAG_SHARPNESS = 0xA40A; 445 446 // TODO support this tag (I haven't seen a camera's actual implementation of this yet) 447 448 /** 449 * This tag indicates information on the picture-taking conditions of a particular 450 * camera model. The tag is used only to indicate the picture-taking conditions in 451 * the reader. 452 * Tag = 41995 (A40B.H) 453 * Type = UNDEFINED 454 * Count = Any 455 * Default = none 456 * 457 * The information is recorded in the format shown below. The data is recorded 458 * in Unicode using SHORT type for the number of display rows and columns and 459 * UNDEFINED type for the camera settings. The Unicode (UCS-2) string including 460 * Signature is NULL terminated. The specifics of the Unicode string are as given 461 * in ISO/IEC 10464-1. 462 * 463 * Length Type Meaning 464 * ------+-----------+------------------ 465 * 2 SHORT Display columns 466 * 2 SHORT Display rows 467 * Any UNDEFINED Camera setting-1 468 * Any UNDEFINED Camera setting-2 469 * : : : 470 * Any UNDEFINED Camera setting-n 471 */ 472 public static final int TAG_DEVICE_SETTING_DESCRIPTION = 0xA40B; 473 474 /** 475 * This tag indicates the distance to the subject. 476 * Tag = 41996 (A40C.H) 477 * Type = SHORT 478 * Count = 1 479 * Default = none 480 * 0 = unknown 481 * 1 = Macro 482 * 2 = Close view 483 * 3 = Distant view 484 * Other = reserved 485 */ 486 public static final int TAG_SUBJECT_DISTANCE_RANGE = 0xA40C; 487 488 /** 489 * This tag indicates an identifier assigned uniquely to each image. It is 490 * recorded as an ASCII string equivalent to hexadecimal notation and 128-bit 491 * fixed length. 492 * Tag = 42016 (A420.H) 493 * Type = ASCII 494 * Count = 33 495 * Default = none 496 */ 497 public static final int TAG_IMAGE_UNIQUE_ID = 0xA420; 498 499 /** String. */ 500 public static final int TAG_CAMERA_OWNER_NAME = 0xA430; 501 /** String. */ 502 public static final int TAG_BODY_SERIAL_NUMBER = 0xA431; 503 /** An array of four Rational64u numbers giving focal and aperture ranges. */ 504 public static final int TAG_LENS_SPECIFICATION = 0xA432; 505 /** String. */ 506 public static final int TAG_LENS_MAKE = 0xA433; 507 /** String. */ 508 public static final int TAG_LENS_MODEL = 0xA434; 509 /** String. */ 510 public static final int TAG_LENS_SERIAL_NUMBER = 0xA435; 511 /** Rational64u. */ 512 public static final int TAG_GAMMA = 0xA500; 513 514 public static final int TAG_LENS = 0xFDEA; 37 public ExifSubIFDDirectory() 38 { 39 this.setDescriptor(new ExifSubIFDDescriptor(this)); 40 } 515 41 516 42 @NotNull … … 519 45 static 520 46 { 521 _tagNameMap.put(TAG_FILL_ORDER, "Fill Order"); 522 _tagNameMap.put(TAG_DOCUMENT_NAME, "Document Name"); 523 // TODO why don't these tags have fields associated with them? 524 _tagNameMap.put(0x1000, "Related Image File Format"); 525 _tagNameMap.put(0x1001, "Related Image Width"); 526 _tagNameMap.put(0x1002, "Related Image Length"); 527 _tagNameMap.put(0x0156, "Transfer Range"); 528 _tagNameMap.put(0x0200, "JPEG Proc"); 529 _tagNameMap.put(TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL, "Compressed Bits Per Pixel"); 530 _tagNameMap.put(TAG_MAKERNOTE, "Makernote"); 531 _tagNameMap.put(TAG_INTEROP_OFFSET, "Interoperability Offset"); 532 533 _tagNameMap.put(TAG_NEW_SUBFILE_TYPE, "New Subfile Type"); 534 _tagNameMap.put(TAG_SUBFILE_TYPE, "Subfile Type"); 535 _tagNameMap.put(TAG_BITS_PER_SAMPLE, "Bits Per Sample"); 536 _tagNameMap.put(TAG_PHOTOMETRIC_INTERPRETATION, "Photometric Interpretation"); 537 _tagNameMap.put(TAG_THRESHOLDING, "Thresholding"); 538 _tagNameMap.put(TAG_STRIP_OFFSETS, "Strip Offsets"); 539 _tagNameMap.put(TAG_SAMPLES_PER_PIXEL, "Samples Per Pixel"); 540 _tagNameMap.put(TAG_ROWS_PER_STRIP, "Rows Per Strip"); 541 _tagNameMap.put(TAG_STRIP_BYTE_COUNTS, "Strip Byte Counts"); 542 _tagNameMap.put(TAG_PAGE_NAME, "Page Name"); 543 _tagNameMap.put(TAG_PLANAR_CONFIGURATION, "Planar Configuration"); 544 _tagNameMap.put(TAG_TRANSFER_FUNCTION, "Transfer Function"); 545 _tagNameMap.put(TAG_PREDICTOR, "Predictor"); 546 _tagNameMap.put(TAG_TILE_WIDTH, "Tile Width"); 547 _tagNameMap.put(TAG_TILE_LENGTH, "Tile Length"); 548 _tagNameMap.put(TAG_TILE_OFFSETS, "Tile Offsets"); 549 _tagNameMap.put(TAG_TILE_BYTE_COUNTS, "Tile Byte Counts"); 550 _tagNameMap.put(TAG_JPEG_TABLES, "JPEG Tables"); 551 _tagNameMap.put(TAG_YCBCR_SUBSAMPLING, "YCbCr Sub-Sampling"); 552 _tagNameMap.put(TAG_CFA_REPEAT_PATTERN_DIM, "CFA Repeat Pattern Dim"); 553 _tagNameMap.put(TAG_CFA_PATTERN_2, "CFA Pattern"); 554 _tagNameMap.put(TAG_BATTERY_LEVEL, "Battery Level"); 555 _tagNameMap.put(TAG_EXPOSURE_TIME, "Exposure Time"); 556 _tagNameMap.put(TAG_FNUMBER, "F-Number"); 557 _tagNameMap.put(TAG_IPTC_NAA, "IPTC/NAA"); 558 _tagNameMap.put(TAG_INTER_COLOR_PROFILE, "Inter Color Profile"); 559 _tagNameMap.put(TAG_EXPOSURE_PROGRAM, "Exposure Program"); 560 _tagNameMap.put(TAG_SPECTRAL_SENSITIVITY, "Spectral Sensitivity"); 561 _tagNameMap.put(TAG_ISO_EQUIVALENT, "ISO Speed Ratings"); 562 _tagNameMap.put(TAG_OPTO_ELECTRIC_CONVERSION_FUNCTION, "Opto-electric Conversion Function (OECF)"); 563 _tagNameMap.put(TAG_INTERLACE, "Interlace"); 564 _tagNameMap.put(TAG_TIME_ZONE_OFFSET, "Time Zone Offset"); 565 _tagNameMap.put(TAG_SELF_TIMER_MODE, "Self Timer Mode"); 566 _tagNameMap.put(TAG_EXIF_VERSION, "Exif Version"); 567 _tagNameMap.put(TAG_DATETIME_ORIGINAL, "Date/Time Original"); 568 _tagNameMap.put(TAG_DATETIME_DIGITIZED, "Date/Time Digitized"); 569 _tagNameMap.put(TAG_COMPONENTS_CONFIGURATION, "Components Configuration"); 570 _tagNameMap.put(TAG_SHUTTER_SPEED, "Shutter Speed Value"); 571 _tagNameMap.put(TAG_APERTURE, "Aperture Value"); 572 _tagNameMap.put(TAG_BRIGHTNESS_VALUE, "Brightness Value"); 573 _tagNameMap.put(TAG_EXPOSURE_BIAS, "Exposure Bias Value"); 574 _tagNameMap.put(TAG_MAX_APERTURE, "Max Aperture Value"); 575 _tagNameMap.put(TAG_SUBJECT_DISTANCE, "Subject Distance"); 576 _tagNameMap.put(TAG_METERING_MODE, "Metering Mode"); 577 _tagNameMap.put(TAG_LIGHT_SOURCE, "Light Source"); 578 _tagNameMap.put(TAG_WHITE_BALANCE, "White Balance"); 579 _tagNameMap.put(TAG_FLASH, "Flash"); 580 _tagNameMap.put(TAG_FOCAL_LENGTH, "Focal Length"); 581 _tagNameMap.put(TAG_FLASH_ENERGY, "Flash Energy"); 582 _tagNameMap.put(TAG_SPATIAL_FREQ_RESPONSE, "Spatial Frequency Response"); 583 _tagNameMap.put(TAG_NOISE, "Noise"); 584 _tagNameMap.put(TAG_IMAGE_NUMBER, "Image Number"); 585 _tagNameMap.put(TAG_SECURITY_CLASSIFICATION, "Security Classification"); 586 _tagNameMap.put(TAG_IMAGE_HISTORY, "Image History"); 587 _tagNameMap.put(TAG_SUBJECT_LOCATION, "Subject Location"); 588 _tagNameMap.put(TAG_EXPOSURE_INDEX, "Exposure Index"); 589 _tagNameMap.put(TAG_TIFF_EP_STANDARD_ID, "TIFF/EP Standard ID"); 590 _tagNameMap.put(TAG_USER_COMMENT, "User Comment"); 591 _tagNameMap.put(TAG_SUBSECOND_TIME, "Sub-Sec Time"); 592 _tagNameMap.put(TAG_SUBSECOND_TIME_ORIGINAL, "Sub-Sec Time Original"); 593 _tagNameMap.put(TAG_SUBSECOND_TIME_DIGITIZED, "Sub-Sec Time Digitized"); 594 _tagNameMap.put(TAG_FLASHPIX_VERSION, "FlashPix Version"); 595 _tagNameMap.put(TAG_COLOR_SPACE, "Color Space"); 596 _tagNameMap.put(TAG_EXIF_IMAGE_WIDTH, "Exif Image Width"); 597 _tagNameMap.put(TAG_EXIF_IMAGE_HEIGHT, "Exif Image Height"); 598 _tagNameMap.put(TAG_RELATED_SOUND_FILE, "Related Sound File"); 599 // 0x920B in TIFF/EP 600 _tagNameMap.put(TAG_FLASH_ENERGY_2, "Flash Energy"); 601 // 0x920C in TIFF/EP 602 _tagNameMap.put(TAG_SPATIAL_FREQ_RESPONSE_2, "Spatial Frequency Response"); 603 // 0x920E in TIFF/EP 604 _tagNameMap.put(TAG_FOCAL_PLANE_X_RESOLUTION, "Focal Plane X Resolution"); 605 // 0x920F in TIFF/EP 606 _tagNameMap.put(TAG_FOCAL_PLANE_Y_RESOLUTION, "Focal Plane Y Resolution"); 607 // 0x9210 in TIFF/EP 608 _tagNameMap.put(TAG_FOCAL_PLANE_RESOLUTION_UNIT, "Focal Plane Resolution Unit"); 609 // 0x9214 in TIFF/EP 610 _tagNameMap.put(TAG_SUBJECT_LOCATION_2, "Subject Location"); 611 // 0x9215 in TIFF/EP 612 _tagNameMap.put(TAG_EXPOSURE_INDEX_2, "Exposure Index"); 613 // 0x9217 in TIFF/EP 614 _tagNameMap.put(TAG_SENSING_METHOD, "Sensing Method"); 615 _tagNameMap.put(TAG_FILE_SOURCE, "File Source"); 616 _tagNameMap.put(TAG_SCENE_TYPE, "Scene Type"); 617 _tagNameMap.put(TAG_CFA_PATTERN, "CFA Pattern"); 618 619 _tagNameMap.put(TAG_CUSTOM_RENDERED, "Custom Rendered"); 620 _tagNameMap.put(TAG_EXPOSURE_MODE, "Exposure Mode"); 621 _tagNameMap.put(TAG_WHITE_BALANCE_MODE, "White Balance Mode"); 622 _tagNameMap.put(TAG_DIGITAL_ZOOM_RATIO, "Digital Zoom Ratio"); 623 _tagNameMap.put(TAG_35MM_FILM_EQUIV_FOCAL_LENGTH, "Focal Length 35"); 624 _tagNameMap.put(TAG_SCENE_CAPTURE_TYPE, "Scene Capture Type"); 625 _tagNameMap.put(TAG_GAIN_CONTROL, "Gain Control"); 626 _tagNameMap.put(TAG_CONTRAST, "Contrast"); 627 _tagNameMap.put(TAG_SATURATION, "Saturation"); 628 _tagNameMap.put(TAG_SHARPNESS, "Sharpness"); 629 _tagNameMap.put(TAG_DEVICE_SETTING_DESCRIPTION, "Device Setting Description"); 630 _tagNameMap.put(TAG_SUBJECT_DISTANCE_RANGE, "Subject Distance Range"); 631 _tagNameMap.put(TAG_IMAGE_UNIQUE_ID, "Unique Image ID"); 632 633 _tagNameMap.put(TAG_CAMERA_OWNER_NAME, "Camera Owner Name"); 634 _tagNameMap.put(TAG_BODY_SERIAL_NUMBER, "Body Serial Number"); 635 _tagNameMap.put(TAG_LENS_SPECIFICATION, "Lens Specification"); 636 _tagNameMap.put(TAG_LENS_MAKE, "Lens Make"); 637 _tagNameMap.put(TAG_LENS_MODEL, "Lens Model"); 638 _tagNameMap.put(TAG_LENS_SERIAL_NUMBER, "Lens Serial Number"); 639 _tagNameMap.put(TAG_GAMMA, "Gamma"); 640 641 _tagNameMap.put(TAG_MIN_SAMPLE_VALUE, "Minimum sample value"); 642 _tagNameMap.put(TAG_MAX_SAMPLE_VALUE, "Maximum sample value"); 643 644 _tagNameMap.put(TAG_LENS, "Lens"); 645 } 646 647 public ExifSubIFDDirectory() 648 { 649 this.setDescriptor(new ExifSubIFDDescriptor(this)); 47 addExifTagNames(_tagNameMap); 650 48 } 651 49 -
trunk/src/com/drew/metadata/exif/ExifThumbnailDescriptor.java
r8132 r8243 22 22 package com.drew.metadata.exif; 23 23 24 import com.drew.lang.Rational;25 24 import com.drew.lang.annotations.NotNull; 26 25 import com.drew.lang.annotations.Nullable; 27 import com.drew.metadata.TagDescriptor;28 26 29 27 import static com.drew.metadata.exif.ExifThumbnailDirectory.*; … … 34 32 * @author Drew Noakes https://drewnoakes.com 35 33 */ 36 public class ExifThumbnailDescriptor extends TagDescriptor<ExifThumbnailDirectory>34 public class ExifThumbnailDescriptor extends ExifDescriptorBase<ExifThumbnailDirectory> 37 35 { 38 /**39 * Dictates whether rational values will be represented in decimal format in instances40 * where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3).41 */42 private final boolean _allowDecimalRepresentationOfRationals = true;43 44 36 public ExifThumbnailDescriptor(@NotNull ExifThumbnailDirectory directory) 45 37 { … … 47 39 } 48 40 49 // Note for the potential addition of brightness presentation in eV:50 // Brightness of taken subject. To calculate Exposure(Ev) from BrightnessValue(Bv),51 // you must add SensitivityValue(Sv).52 // Ev=BV+Sv Sv=log2(ISOSpeedRating/3.125)53 // ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.54 55 /**56 * Returns a descriptive value of the specified tag for this image.57 * Where possible, known values will be substituted here in place of the raw58 * tokens actually kept in the Exif segment. If no substitution is59 * available, the value provided by getString(int) will be returned.60 *61 * @param tagType the tag to find a description for62 * @return a description of the image's value for the specified tag, or63 * <code>null</code> if the tag hasn't been defined.64 */65 41 @Override 66 42 @Nullable … … 68 44 { 69 45 switch (tagType) { 70 case TAG_ORIENTATION:71 return getOrientationDescription();72 case TAG_RESOLUTION_UNIT:73 return getResolutionDescription();74 case TAG_YCBCR_POSITIONING:75 return getYCbCrPositioningDescription();76 case TAG_X_RESOLUTION:77 return getXResolutionDescription();78 case TAG_Y_RESOLUTION:79 return getYResolutionDescription();80 46 case TAG_THUMBNAIL_OFFSET: 81 47 return getThumbnailOffsetDescription(); 82 48 case TAG_THUMBNAIL_LENGTH: 83 49 return getThumbnailLengthDescription(); 84 case TAG_THUMBNAIL_IMAGE_WIDTH:85 return getThumbnailImageWidthDescription();86 case TAG_THUMBNAIL_IMAGE_HEIGHT:87 return getThumbnailImageHeightDescription();88 case TAG_BITS_PER_SAMPLE:89 return getBitsPerSampleDescription();90 50 case TAG_THUMBNAIL_COMPRESSION: 91 51 return getCompressionDescription(); 92 case TAG_PHOTOMETRIC_INTERPRETATION:93 return getPhotometricInterpretationDescription();94 case TAG_ROWS_PER_STRIP:95 return getRowsPerStripDescription();96 case TAG_STRIP_BYTE_COUNTS:97 return getStripByteCountsDescription();98 case TAG_SAMPLES_PER_PIXEL:99 return getSamplesPerPixelDescription();100 case TAG_PLANAR_CONFIGURATION:101 return getPlanarConfigurationDescription();102 case TAG_YCBCR_SUBSAMPLING:103 return getYCbCrSubsamplingDescription();104 case TAG_REFERENCE_BLACK_WHITE:105 return getReferenceBlackWhiteDescription();106 52 default: 107 53 return super.getDescription(tagType); 108 }109 }110 111 @Nullable112 public String getReferenceBlackWhiteDescription()113 {114 int[] ints = _directory.getIntArray(TAG_REFERENCE_BLACK_WHITE);115 if (ints == null || ints.length < 6)116 return null;117 int blackR = ints[0];118 int whiteR = ints[1];119 int blackG = ints[2];120 int whiteG = ints[3];121 int blackB = ints[4];122 int whiteB = ints[5];123 return String.format("[%d,%d,%d] [%d,%d,%d]", blackR, blackG, blackB, whiteR, whiteG, whiteB);124 }125 126 @Nullable127 public String getYCbCrSubsamplingDescription()128 {129 int[] positions = _directory.getIntArray(TAG_YCBCR_SUBSAMPLING);130 if (positions == null || positions.length < 2)131 return null;132 if (positions[0] == 2 && positions[1] == 1) {133 return "YCbCr4:2:2";134 } else if (positions[0] == 2 && positions[1] == 2) {135 return "YCbCr4:2:0";136 } else {137 return "(Unknown)";138 }139 }140 141 @Nullable142 public String getPlanarConfigurationDescription()143 {144 // When image format is no compression YCbCr, this value shows byte aligns of YCbCr145 // data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling146 // pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr147 // plane format.148 return getIndexedDescription(TAG_PLANAR_CONFIGURATION,149 1,150 "Chunky (contiguous for each subsampling pixel)",151 "Separate (Y-plane/Cb-plane/Cr-plane format)"152 );153 }154 155 @Nullable156 public String getSamplesPerPixelDescription()157 {158 String value = _directory.getString(TAG_SAMPLES_PER_PIXEL);159 return value == null ? null : value + " samples/pixel";160 }161 162 @Nullable163 public String getRowsPerStripDescription()164 {165 final String value = _directory.getString(TAG_ROWS_PER_STRIP);166 return value == null ? null : value + " rows/strip";167 }168 169 @Nullable170 public String getStripByteCountsDescription()171 {172 final String value = _directory.getString(TAG_STRIP_BYTE_COUNTS);173 return value == null ? null : value + " bytes";174 }175 176 @Nullable177 public String getPhotometricInterpretationDescription()178 {179 // Shows the color space of the image data components180 Integer value = _directory.getInteger(TAG_PHOTOMETRIC_INTERPRETATION);181 if (value == null)182 return null;183 switch (value) {184 case 0: return "WhiteIsZero";185 case 1: return "BlackIsZero";186 case 2: return "RGB";187 case 3: return "RGB Palette";188 case 4: return "Transparency Mask";189 case 5: return "CMYK";190 case 6: return "YCbCr";191 case 8: return "CIELab";192 case 9: return "ICCLab";193 case 10: return "ITULab";194 case 32803: return "Color Filter Array";195 case 32844: return "Pixar LogL";196 case 32845: return "Pixar LogLuv";197 case 32892: return "Linear Raw";198 default:199 return "Unknown colour space";200 54 } 201 55 } … … 241 95 242 96 @Nullable 243 public String getBitsPerSampleDescription()244 {245 String value = _directory.getString(TAG_BITS_PER_SAMPLE);246 return value == null ? null : value + " bits/component/pixel";247 }248 249 @Nullable250 public String getThumbnailImageWidthDescription()251 {252 String value = _directory.getString(TAG_THUMBNAIL_IMAGE_WIDTH);253 return value == null ? null : value + " pixels";254 }255 256 @Nullable257 public String getThumbnailImageHeightDescription()258 {259 String value = _directory.getString(TAG_THUMBNAIL_IMAGE_HEIGHT);260 return value == null ? null : value + " pixels";261 }262 263 @Nullable264 97 public String getThumbnailLengthDescription() 265 98 { … … 274 107 return value == null ? null : value + " bytes"; 275 108 } 276 277 @Nullable278 public String getYResolutionDescription()279 {280 Rational value = _directory.getRational(TAG_Y_RESOLUTION);281 if (value == null)282 return null;283 final String unit = getResolutionDescription();284 return value.toSimpleString(_allowDecimalRepresentationOfRationals) +285 " dots per " +286 (unit == null ? "unit" : unit.toLowerCase());287 }288 289 @Nullable290 public String getXResolutionDescription()291 {292 Rational value = _directory.getRational(TAG_X_RESOLUTION);293 if (value == null)294 return null;295 final String unit = getResolutionDescription();296 return value.toSimpleString(_allowDecimalRepresentationOfRationals) +297 " dots per " +298 (unit == null ? "unit" : unit.toLowerCase());299 }300 301 @Nullable302 public String getYCbCrPositioningDescription()303 {304 return getIndexedDescription(TAG_YCBCR_POSITIONING, 1, "Center of pixel array", "Datum point");305 }306 307 @Nullable308 public String getOrientationDescription()309 {310 return getIndexedDescription(TAG_ORIENTATION, 1,311 "Top, left side (Horizontal / normal)",312 "Top, right side (Mirror horizontal)",313 "Bottom, right side (Rotate 180)",314 "Bottom, left side (Mirror vertical)",315 "Left side, top (Mirror horizontal and rotate 270 CW)",316 "Right side, top (Rotate 90 CW)",317 "Right side, bottom (Mirror horizontal and rotate 90 CW)",318 "Left side, bottom (Rotate 270 CW)");319 }320 321 @Nullable322 public String getResolutionDescription()323 {324 // '1' means no-unit, '2' means inch, '3' means centimeter. Default value is '2'(inch)325 return getIndexedDescription(TAG_RESOLUTION_UNIT, 1, "(No unit)", "Inch", "cm");326 }327 109 } -
trunk/src/com/drew/metadata/exif/ExifThumbnailDirectory.java
r8132 r8243 24 24 import com.drew.lang.annotations.NotNull; 25 25 import com.drew.lang.annotations.Nullable; 26 import com.drew.metadata.Directory;27 26 import com.drew.metadata.MetadataException; 28 27 … … 36 35 * @author Drew Noakes https://drewnoakes.com 37 36 */ 38 public class ExifThumbnailDirectory extends Directory37 public class ExifThumbnailDirectory extends ExifDirectoryBase 39 38 { 40 public static final int TAG_THUMBNAIL_IMAGE_WIDTH = 0x0100; 41 public static final int TAG_THUMBNAIL_IMAGE_HEIGHT = 0x0101; 42 43 /** 44 * When image format is no compression, this value shows the number of bits 45 * per component for each pixel. Usually this value is '8,8,8'. 39 /** 40 * The offset to thumbnail image bytes. 46 41 */ 47 public static final int TAG_BITS_PER_SAMPLE = 0x0102; 42 public static final int TAG_THUMBNAIL_OFFSET = 0x0201; 43 /** 44 * The size of the thumbnail image data in bytes. 45 */ 46 public static final int TAG_THUMBNAIL_LENGTH = 0x0202; 48 47 49 48 /** … … 79 78 public static final int TAG_THUMBNAIL_COMPRESSION = 0x0103; 80 79 81 /**82 * Shows the color space of the image data components.83 * 0 = WhiteIsZero84 * 1 = BlackIsZero85 * 2 = RGB86 * 3 = RGB Palette87 * 4 = Transparency Mask88 * 5 = CMYK89 * 6 = YCbCr90 * 8 = CIELab91 * 9 = ICCLab92 * 10 = ITULab93 * 32803 = Color Filter Array94 * 32844 = Pixar LogL95 * 32845 = Pixar LogLuv96 * 34892 = Linear Raw97 */98 public static final int TAG_PHOTOMETRIC_INTERPRETATION = 0x0106;99 100 /**101 * The position in the file of raster data.102 */103 public static final int TAG_STRIP_OFFSETS = 0x0111;104 public static final int TAG_ORIENTATION = 0x0112;105 /**106 * Each pixel is composed of this many samples.107 */108 public static final int TAG_SAMPLES_PER_PIXEL = 0x0115;109 /**110 * The raster is codified by a single block of data holding this many rows.111 */112 public static final int TAG_ROWS_PER_STRIP = 0x116;113 /**114 * The size of the raster data in bytes.115 */116 public static final int TAG_STRIP_BYTE_COUNTS = 0x0117;117 /**118 * When image format is no compression YCbCr, this value shows byte aligns of119 * YCbCr data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for120 * each subsampling pixel. If value is '2', Y/Cb/Cr value is separated and121 * stored to Y plane/Cb plane/Cr plane format.122 */123 public static final int TAG_X_RESOLUTION = 0x011A;124 public static final int TAG_Y_RESOLUTION = 0x011B;125 public static final int TAG_PLANAR_CONFIGURATION = 0x011C;126 public static final int TAG_RESOLUTION_UNIT = 0x0128;127 /**128 * The offset to thumbnail image bytes.129 */130 public static final int TAG_THUMBNAIL_OFFSET = 0x0201;131 /**132 * The size of the thumbnail image data in bytes.133 */134 public static final int TAG_THUMBNAIL_LENGTH = 0x0202;135 public static final int TAG_YCBCR_COEFFICIENTS = 0x0211;136 public static final int TAG_YCBCR_SUBSAMPLING = 0x0212;137 public static final int TAG_YCBCR_POSITIONING = 0x0213;138 public static final int TAG_REFERENCE_BLACK_WHITE = 0x0214;139 140 80 @NotNull 141 81 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 142 82 143 static {144 _tagNameMap.put(TAG_THUMBNAIL_IMAGE_WIDTH, "Thumbnail Image Width");145 _tagNameMap.put(TAG_THUMBNAIL_IMAGE_HEIGHT, "Thumbnail Image Height");146 _tagNameMap.put(TAG_BITS_PER_SAMPLE, "Bits Per Sample"); 83 static 84 { 85 addExifTagNames(_tagNameMap); 86 147 87 _tagNameMap.put(TAG_THUMBNAIL_COMPRESSION, "Thumbnail Compression"); 148 _tagNameMap.put(TAG_PHOTOMETRIC_INTERPRETATION, "Photometric Interpretation");149 _tagNameMap.put(TAG_STRIP_OFFSETS, "Strip Offsets");150 _tagNameMap.put(TAG_ORIENTATION, "Orientation");151 _tagNameMap.put(TAG_SAMPLES_PER_PIXEL, "Samples Per Pixel");152 _tagNameMap.put(TAG_ROWS_PER_STRIP, "Rows Per Strip");153 _tagNameMap.put(TAG_STRIP_BYTE_COUNTS, "Strip Byte Counts");154 _tagNameMap.put(TAG_X_RESOLUTION, "X Resolution");155 _tagNameMap.put(TAG_Y_RESOLUTION, "Y Resolution");156 _tagNameMap.put(TAG_PLANAR_CONFIGURATION, "Planar Configuration");157 _tagNameMap.put(TAG_RESOLUTION_UNIT, "Resolution Unit");158 88 _tagNameMap.put(TAG_THUMBNAIL_OFFSET, "Thumbnail Offset"); 159 89 _tagNameMap.put(TAG_THUMBNAIL_LENGTH, "Thumbnail Length"); 160 _tagNameMap.put(TAG_YCBCR_COEFFICIENTS, "YCbCr Coefficients");161 _tagNameMap.put(TAG_YCBCR_SUBSAMPLING, "YCbCr Sub-Sampling");162 _tagNameMap.put(TAG_YCBCR_POSITIONING, "YCbCr Positioning");163 _tagNameMap.put(TAG_REFERENCE_BLACK_WHITE, "Reference Black/White");164 90 } 165 91 -
trunk/src/com/drew/metadata/exif/ExifTiffHandler.java
r8132 r8243 57 57 final int standardTiffMarker = 0x002A; 58 58 final int olympusRawTiffMarker = 0x4F52; // for ORF files 59 final int olympusRawTiffMarker2 = 0x5352; // for ORF files 59 60 final int panasonicRawTiffMarker = 0x0055; // for RW2 files 60 61 61 if (marker != standardTiffMarker && marker != olympusRawTiffMarker && marker != panasonicRawTiffMarker) {62 if (marker != standardTiffMarker && marker != olympusRawTiffMarker && marker != olympusRawTiffMarker2 && marker != panasonicRawTiffMarker) { 62 63 throw new TiffProcessingException("Unexpected TIFF marker: 0x" + Integer.toHexString(marker)); 63 64 } … … 127 128 if (_storeThumbnailBytes) { 128 129 // after the extraction process, if we have the correct tags, we may be able to store thumbnail information 129 ExifThumbnailDirectory thumbnailDirectory = _metadata.get Directory(ExifThumbnailDirectory.class);130 ExifThumbnailDirectory thumbnailDirectory = _metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class); 130 131 if (thumbnailDirectory != null && thumbnailDirectory.containsTag(ExifThumbnailDirectory.TAG_THUMBNAIL_COMPRESSION)) { 131 132 Integer offset = thumbnailDirectory.getInteger(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET); … … 149 150 { 150 151 // Determine the camera model and makernote format. 151 Directory ifd0Directory = _metadata.get Directory(ExifIFD0Directory.class);152 Directory ifd0Directory = _metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); 152 153 153 154 if (ifd0Directory == null) … … 219 220 } else if ("KDK".equals(firstThreeChars)) { 220 221 reader.setMotorolaByteOrder(firstSevenChars.equals("KDK INFO")); 221 processKodakMakernote(_metadata.getOrCreateDirectory(KodakMakernoteDirectory.class), makernoteOffset, reader); 222 KodakMakernoteDirectory directory = new KodakMakernoteDirectory(); 223 _metadata.addDirectory(directory); 224 processKodakMakernote(directory, makernoteOffset, reader); 222 225 } else if ("Canon".equalsIgnoreCase(cameraMake)) { 223 226 pushDirectory(CanonMakernoteDirectory.class); -
trunk/src/com/drew/metadata/exif/GpsDescriptor.java
r8132 r8243 109 109 { 110 110 // time in hour, min, sec 111 int[] timeComponents = _directory.getIntArray(TAG_TIME_STAMP); 112 return timeComponents == null ? null : String.format("%d:%d:%d UTC", timeComponents[0], timeComponents[1], timeComponents[2]); 111 Rational[] timeComponents = _directory.getRationalArray(TAG_TIME_STAMP); 112 DecimalFormat df = new DecimalFormat("00.00"); 113 return timeComponents == null 114 ? null 115 : String.format("%02d:%02d:%s UTC", 116 timeComponents[0].intValue(), 117 timeComponents[1].intValue(), 118 df.format(timeComponents[2].doubleValue())); 113 119 } 114 120 -
trunk/src/com/drew/metadata/exif/GpsDirectory.java
r8132 r8243 25 25 import com.drew.lang.annotations.NotNull; 26 26 import com.drew.lang.annotations.Nullable; 27 import com.drew.metadata.Directory;28 27 29 28 import java.util.HashMap; … … 34 33 * @author Drew Noakes https://drewnoakes.com 35 34 */ 36 public class GpsDirectory extends Directory35 public class GpsDirectory extends ExifDirectoryBase 37 36 { 38 37 /** GPS tag version GPSVersionID 0 0 BYTE 4 */ … … 102 101 static 103 102 { 103 addExifTagNames(_tagNameMap); 104 104 105 _tagNameMap.put(TAG_VERSION_ID, "GPS Version ID"); 105 106 _tagNameMap.put(TAG_LATITUDE_REF, "GPS Latitude Ref"); -
trunk/src/com/drew/metadata/exif/makernotes/CanonMakernoteDescriptor.java
r8132 r8243 82 82 case CameraSettings.TAG_EXPOSURE_MODE: 83 83 return getExposureModeDescription(); 84 case CameraSettings.TAG_LENS_TYPE: 85 return getLensTypeDescription(); 84 86 case CameraSettings.TAG_LONG_FOCAL_LENGTH: 85 87 return getLongFocalLengthDescription(); … … 451 453 452 454 @Nullable 455 public String getLensTypeDescription() { 456 Integer value = _directory.getInteger(CameraSettings.TAG_LENS_TYPE); 457 if (value == null) 458 return null; 459 460 return "Lens type: " + Integer.toString(value); 461 } 462 463 @Nullable 453 464 public String getAfPointSelectedDescription() 454 465 { -
trunk/src/com/drew/metadata/exif/makernotes/CanonMakernoteDirectory.java
r8132 r8243 245 245 public static final int TAG_EXPOSURE_MODE = OFFSET + 0x14; 246 246 public static final int TAG_UNKNOWN_7 = OFFSET + 0x15; 247 public static final int TAG_ UNKNOWN_8= OFFSET + 0x16;247 public static final int TAG_LENS_TYPE = OFFSET + 0x16; 248 248 public static final int TAG_LONG_FOCAL_LENGTH = OFFSET + 0x17; 249 249 public static final int TAG_SHORT_FOCAL_LENGTH = OFFSET + 0x18; … … 519 519 _tagNameMap.put(CameraSettings.TAG_FOCUS_TYPE, "Focus Type"); 520 520 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_7, "Unknown Camera Setting 7"); 521 _tagNameMap.put(CameraSettings.TAG_ UNKNOWN_8, "Unknown Camera Setting 8");521 _tagNameMap.put(CameraSettings.TAG_LENS_TYPE, "Lens Type"); 522 522 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_9, "Unknown Camera Setting 9"); 523 523 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_10, "Unknown Camera Setting 10"); -
trunk/src/com/drew/metadata/exif/makernotes/OlympusMakernoteDirectory.java
r8132 r8243 51 51 public static final int TAG_MINOLTA_THUMBNAIL_LENGTH = 0x0089; 52 52 53 public static final int TAG_THUMBNAIL_IMAGE = 0x0100; 54 53 55 /** 54 56 * Used by Konica / Minolta cameras … … 83 85 public static final int TAG_IMAGE_QUALITY_2 = 0x0103; 84 86 87 public static final int TAG_BODY_FIRMWARE_VERSION = 0x0104; 85 88 86 89 /** … … 136 139 public static final int TAG_ORIGINAL_MANUFACTURER_MODEL = 0x020D; 137 140 141 public static final int TAG_PREVIEW_IMAGE = 0x0280; 142 public static final int TAG_PRE_CAPTURE_FRAMES = 0x0300; 143 public static final int TAG_WHITE_BOARD = 0x0301; 144 public static final int TAG_ONE_TOUCH_WB = 0x0302; 145 public static final int TAG_WHITE_BALANCE_BRACKET = 0x0303; 146 public static final int TAG_WHITE_BALANCE_BIAS = 0x0304; 147 public static final int TAG_SCENE_MODE = 0x0403; 148 public static final int TAG_FIRMWARE = 0x0404; 149 138 150 /** 139 151 * See the PIM specification here: … … 142 154 public static final int TAG_PRINT_IMAGE_MATCHING_INFO = 0x0E00; 143 155 144 public static final int TAG_DATA_DUMP = 0x0F00; 156 public static final int TAG_DATA_DUMP_1 = 0x0F00; 157 public static final int TAG_DATA_DUMP_2 = 0x0F01; 145 158 146 159 public static final int TAG_SHUTTER_SPEED_VALUE = 0x1000; … … 149 162 public static final int TAG_BRIGHTNESS_VALUE = 0x1003; 150 163 public static final int TAG_FLASH_MODE = 0x1004; 164 public static final int TAG_FLASH_DEVICE = 0x1005; 151 165 public static final int TAG_BRACKET = 0x1006; 166 public static final int TAG_SENSOR_TEMPERATURE = 0x1007; 167 public static final int TAG_LENS_TEMPERATURE = 0x1008; 168 public static final int TAG_LIGHT_CONDITION = 0x1009; 152 169 public static final int TAG_FOCUS_RANGE = 0x100A; 153 170 public static final int TAG_FOCUS_MODE = 0x100B; … … 156 173 public static final int TAG_MACRO_FOCUS = 0x100E; 157 174 public static final int TAG_SHARPNESS = 0x100F; 175 public static final int TAG_FLASH_CHARGE_LEVEL = 0x1010; 158 176 public static final int TAG_COLOUR_MATRIX = 0x1011; 159 177 public static final int TAG_BLACK_LEVEL = 0x1012; 178 // public static final int TAG_ = 0x1013; 179 // public static final int TAG_ = 0x1014; 160 180 public static final int TAG_WHITE_BALANCE = 0x1015; 181 // public static final int TAG_ = 0x1016; 161 182 public static final int TAG_RED_BIAS = 0x1017; 162 183 public static final int TAG_BLUE_BIAS = 0x1018; 184 public static final int TAG_COLOR_MATRIX_NUMBER = 0x1019; 163 185 public static final int TAG_SERIAL_NUMBER = 0x101A; 186 // public static final int TAG_ = 0x101B; 187 // public static final int TAG_ = 0x101C; 188 // public static final int TAG_ = 0x101D; 189 // public static final int TAG_ = 0x101E; 190 // public static final int TAG_ = 0x101F; 191 // public static final int TAG_ = 0x1020; 192 // public static final int TAG_ = 0x1021; 193 // public static final int TAG_ = 0x1022; 164 194 public static final int TAG_FLASH_BIAS = 0x1023; 195 // public static final int TAG_ = 0x1024; 196 // public static final int TAG_ = 0x1025; 197 public static final int TAG_EXTERNAL_FLASH_BOUNCE = 0x1026; 198 public static final int TAG_EXTERNAL_FLASH_ZOOM = 0x1027; 199 public static final int TAG_EXTERNAL_FLASH_MODE = 0x1028; 165 200 public static final int TAG_CONTRAST = 0x1029; 166 201 public static final int TAG_SHARPNESS_FACTOR = 0x102A; … … 170 205 public static final int TAG_FINAL_WIDTH = 0x102E; 171 206 public static final int TAG_FINAL_HEIGHT = 0x102F; 207 // public static final int TAG_ = 0x1030; 208 // public static final int TAG_ = 0x1031; 209 // public static final int TAG_ = 0x1032; 210 // public static final int TAG_ = 0x1033; 172 211 public static final int TAG_COMPRESSION_RATIO = 0x1034; 212 public static final int TAG_THUMBNAIL = 0x1035; 213 public static final int TAG_THUMBNAIL_OFFSET = 0x1036; 214 public static final int TAG_THUMBNAIL_LENGTH = 0x1037; 215 // public static final int TAG_ = 0x1038; 216 public static final int TAG_CCD_SCAN_MODE = 0x1039; 217 public static final int TAG_NOISE_REDUCTION = 0x103A; 218 public static final int TAG_INFINITY_LENS_STEP = 0x103B; 219 public static final int TAG_NEAR_LENS_STEP = 0x103C; 220 public static final int TAG_EQUIPMENT = 0x2010; 221 public static final int TAG_CAMERA_SETTINGS = 0x2020; 222 public static final int TAG_RAW_DEVELOPMENT = 0x2030; 223 public static final int TAG_RAW_DEVELOPMENT_2 = 0x2031; 224 public static final int TAG_IMAGE_PROCESSING = 0x2040; 225 public static final int TAG_FOCUS_INFO = 0x2050; 226 public static final int TAG_RAW_INFO = 0x3000; 173 227 174 228 public final static class CameraSettings … … 191 245 public static final int TAG_EXPOSURE_COMPENSATION = OFFSET + 14; 192 246 public static final int TAG_BRACKET_STEP = OFFSET + 15; 193 247 // 16 missing 194 248 public static final int TAG_INTERVAL_LENGTH = OFFSET + 17; 195 249 public static final int TAG_INTERVAL_NUMBER = OFFSET + 18; … … 200 254 public static final int TAG_TIME = OFFSET + 23; 201 255 public static final int TAG_MAX_APERTURE_AT_FOCAL_LENGTH = OFFSET + 24; 202 256 // 25, 26 missing 203 257 public static final int TAG_FILE_NUMBER_MEMORY = OFFSET + 27; 204 258 public static final int TAG_LAST_FILE_NUMBER = OFFSET + 28; … … 232 286 233 287 static { 288 _tagNameMap.put(TAG_MAKERNOTE_VERSION, "Makernote Version"); 289 _tagNameMap.put(TAG_CAMERA_SETTINGS_1, "Camera Settings"); 290 _tagNameMap.put(TAG_CAMERA_SETTINGS_2, "Camera Settings"); 291 _tagNameMap.put(TAG_COMPRESSED_IMAGE_SIZE, "Compressed Image Size"); 292 _tagNameMap.put(TAG_MINOLTA_THUMBNAIL_OFFSET_1, "Thumbnail Offset"); 293 _tagNameMap.put(TAG_MINOLTA_THUMBNAIL_OFFSET_2, "Thumbnail Offset"); 294 _tagNameMap.put(TAG_MINOLTA_THUMBNAIL_LENGTH, "Thumbnail Length"); 295 _tagNameMap.put(TAG_THUMBNAIL_IMAGE, "Thumbnail Image"); 296 _tagNameMap.put(TAG_COLOUR_MODE, "Colour Mode"); 297 _tagNameMap.put(TAG_IMAGE_QUALITY_1, "Image Quality"); 298 _tagNameMap.put(TAG_IMAGE_QUALITY_2, "Image Quality"); 299 _tagNameMap.put(TAG_BODY_FIRMWARE_VERSION, "Body Firmware Version"); 234 300 _tagNameMap.put(TAG_SPECIAL_MODE, "Special Mode"); 235 301 _tagNameMap.put(TAG_JPEG_QUALITY, "JPEG Quality"); … … 242 308 _tagNameMap.put(TAG_PICT_INFO, "Pict Info"); 243 309 _tagNameMap.put(TAG_CAMERA_ID, "Camera Id"); 244 _tagNameMap.put(TAG_DATA_DUMP, "Data Dump"); 245 _tagNameMap.put(TAG_MAKERNOTE_VERSION, "Makernote Version"); 246 _tagNameMap.put(TAG_CAMERA_SETTINGS_1, "Camera Settings"); 247 _tagNameMap.put(TAG_CAMERA_SETTINGS_2, "Camera Settings"); 248 _tagNameMap.put(TAG_COMPRESSED_IMAGE_SIZE, "Compressed Image Size"); 249 _tagNameMap.put(TAG_MINOLTA_THUMBNAIL_OFFSET_1, "Thumbnail Offset"); 250 _tagNameMap.put(TAG_MINOLTA_THUMBNAIL_OFFSET_2, "Thumbnail Offset"); 251 _tagNameMap.put(TAG_MINOLTA_THUMBNAIL_LENGTH, "Thumbnail Length"); 252 _tagNameMap.put(TAG_COLOUR_MODE, "Colour Mode"); 253 _tagNameMap.put(TAG_IMAGE_QUALITY_1, "Image Quality"); 254 _tagNameMap.put(TAG_IMAGE_QUALITY_2, "Image Quality"); 310 _tagNameMap.put(TAG_IMAGE_WIDTH, "Image Width"); 255 311 _tagNameMap.put(TAG_IMAGE_HEIGHT, "Image Height"); 256 _tagNameMap.put(TAG_IMAGE_WIDTH, "Image Width");257 312 _tagNameMap.put(TAG_ORIGINAL_MANUFACTURER_MODEL, "Original Manufacturer Model"); 313 _tagNameMap.put(TAG_PREVIEW_IMAGE, "Preview Image"); 314 _tagNameMap.put(TAG_PRE_CAPTURE_FRAMES, "Pre Capture Frames"); 315 _tagNameMap.put(TAG_WHITE_BOARD, "White Board"); 316 _tagNameMap.put(TAG_ONE_TOUCH_WB, "One Touch WB"); 317 _tagNameMap.put(TAG_WHITE_BALANCE_BRACKET, "White Balance Bracket"); 318 _tagNameMap.put(TAG_WHITE_BALANCE_BIAS, "White Balance Bias"); 319 _tagNameMap.put(TAG_SCENE_MODE, "Scene Mode"); 320 _tagNameMap.put(TAG_FIRMWARE, "Firmware"); 258 321 _tagNameMap.put(TAG_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info"); 259 322 _tagNameMap.put(TAG_DATA_DUMP_1, "Data Dump"); 323 _tagNameMap.put(TAG_DATA_DUMP_2, "Data Dump 2"); 260 324 _tagNameMap.put(TAG_SHUTTER_SPEED_VALUE, "Shutter Speed Value"); 261 325 _tagNameMap.put(TAG_ISO_VALUE, "ISO Value"); … … 263 327 _tagNameMap.put(TAG_BRIGHTNESS_VALUE, "Brightness Value"); 264 328 _tagNameMap.put(TAG_FLASH_MODE, "Flash Mode"); 329 _tagNameMap.put(TAG_FLASH_DEVICE, "Flash Device"); 265 330 _tagNameMap.put(TAG_BRACKET, "Bracket"); 331 _tagNameMap.put(TAG_SENSOR_TEMPERATURE, "Sensor Temperature"); 332 _tagNameMap.put(TAG_LENS_TEMPERATURE, "Lens Temperature"); 333 _tagNameMap.put(TAG_LIGHT_CONDITION, "Light Condition"); 266 334 _tagNameMap.put(TAG_FOCUS_RANGE, "Focus Range"); 267 335 _tagNameMap.put(TAG_FOCUS_MODE, "Focus Mode"); … … 270 338 _tagNameMap.put(TAG_MACRO_FOCUS, "Macro Focus"); 271 339 _tagNameMap.put(TAG_SHARPNESS, "Sharpness"); 340 _tagNameMap.put(TAG_FLASH_CHARGE_LEVEL, "Flash Charge Level"); 272 341 _tagNameMap.put(TAG_COLOUR_MATRIX, "Colour Matrix"); 273 342 _tagNameMap.put(TAG_BLACK_LEVEL, "Black Level"); … … 275 344 _tagNameMap.put(TAG_RED_BIAS, "Red Bias"); 276 345 _tagNameMap.put(TAG_BLUE_BIAS, "Blue Bias"); 346 _tagNameMap.put(TAG_COLOR_MATRIX_NUMBER, "Color Matrix Number"); 277 347 _tagNameMap.put(TAG_SERIAL_NUMBER, "Serial Number"); 278 348 _tagNameMap.put(TAG_FLASH_BIAS, "Flash Bias"); 349 _tagNameMap.put(TAG_EXTERNAL_FLASH_BOUNCE, "External Flash Bounce"); 350 _tagNameMap.put(TAG_EXTERNAL_FLASH_ZOOM, "External Flash Zoom"); 351 _tagNameMap.put(TAG_EXTERNAL_FLASH_MODE, "External Flash Mode"); 279 352 _tagNameMap.put(TAG_CONTRAST, "Contrast"); 280 353 _tagNameMap.put(TAG_SHARPNESS_FACTOR, "Sharpness Factor"); … … 285 358 _tagNameMap.put(TAG_FINAL_HEIGHT, "Final Height"); 286 359 _tagNameMap.put(TAG_COMPRESSION_RATIO, "Compression Ratio"); 360 _tagNameMap.put(TAG_THUMBNAIL, "Thumbnail"); 361 _tagNameMap.put(TAG_THUMBNAIL_OFFSET, "Thumbnail Offset"); 362 _tagNameMap.put(TAG_THUMBNAIL_LENGTH, "Thumbnail Length"); 363 _tagNameMap.put(TAG_CCD_SCAN_MODE, "CCD Scan Mode"); 364 _tagNameMap.put(TAG_NOISE_REDUCTION, "Noise Reduction"); 365 _tagNameMap.put(TAG_INFINITY_LENS_STEP, "Infinity Lens Step"); 366 _tagNameMap.put(TAG_NEAR_LENS_STEP, "Near Lens Step"); 367 _tagNameMap.put(TAG_EQUIPMENT, "Equipment"); 368 _tagNameMap.put(TAG_CAMERA_SETTINGS, "Camera Settings"); 369 _tagNameMap.put(TAG_RAW_DEVELOPMENT, "Raw Development"); 370 _tagNameMap.put(TAG_RAW_DEVELOPMENT_2, "Raw Development 2"); 371 _tagNameMap.put(TAG_IMAGE_PROCESSING, "Image Processing"); 372 _tagNameMap.put(TAG_FOCUS_INFO, "Focus Info"); 373 _tagNameMap.put(TAG_RAW_INFO, "Raw Info"); 287 374 288 375 _tagNameMap.put(CameraSettings.TAG_EXPOSURE_MODE, "Exposure Mode"); -
trunk/src/com/drew/metadata/exif/makernotes/PanasonicMakernoteDirectory.java
r8132 r8243 35 35 * Describes tags specific to Panasonic and Leica cameras. 36 36 * 37 * @author Drew Noakes https://drewnoakes.com, Philipp Sandhaus 37 * @author Drew Noakes https://drewnoakes.com 38 * @author Philipp Sandhaus 38 39 */ 39 40 public class PanasonicMakernoteDirectory extends Directory -
trunk/src/com/drew/metadata/iptc/IptcDescriptor.java
r8132 r8243 49 49 case IptcDirectory.TAG_KEYWORDS: 50 50 return getKeywordsDescription(); 51 case IptcDirectory.TAG_TIME_CREATED: 52 return getTimeCreatedDescription(); 53 case IptcDirectory.TAG_DIGITAL_TIME_CREATED: 54 return getDigitalTimeCreatedDescription(); 51 55 default: 52 56 return super.getDescription(tagType); … … 227 231 public String getTimeCreatedDescription() 228 232 { 229 return _directory.getString(IptcDirectory.TAG_TIME_CREATED); 233 String s = _directory.getString(IptcDirectory.TAG_TIME_CREATED); 234 if (s == null) 235 return null; 236 if (s.length() == 6 || s.length() == 11) 237 return s.substring(0, 2) + ':' + s.substring(2, 4) + ':' + s.substring(4); 238 return s; 239 } 240 241 @Nullable 242 public String getDigitalTimeCreatedDescription() 243 { 244 String s = _directory.getString(IptcDirectory.TAG_DIGITAL_TIME_CREATED); 245 if (s == null) 246 return null; 247 if (s.length() == 6 || s.length() == 11) 248 return s.substring(0, 2) + ':' + s.substring(2, 4) + ':' + s.substring(4); 249 return s; 230 250 } 231 251 -
trunk/src/com/drew/metadata/iptc/IptcReader.java
r8132 r8243 63 63 } 64 64 65 public boolean canProcess(@NotNull byte[] segmentBytes, @NotNull JpegSegmentType segmentType) 66 { 67 // Check whether the first byte resembles 68 return segmentBytes.length != 0 && segmentBytes[0] == 0x1c; 69 } 70 71 public void extract(@NotNull byte[] segmentBytes, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType) 72 { 73 extract(new SequentialByteArrayReader(segmentBytes), metadata, segmentBytes.length); 65 public void readJpegSegments(@NotNull Iterable<byte[]> segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType) 66 { 67 for (byte[] segmentBytes : segments) { 68 // Ensure data starts with the IPTC marker byte 69 if (segmentBytes.length != 0 && segmentBytes[0] == 0x1c) { 70 extract(new SequentialByteArrayReader(segmentBytes), metadata, segmentBytes.length); 71 } 72 } 74 73 } 75 74 … … 79 78 public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata, long length) 80 79 { 81 IptcDirectory directory = metadata.getOrCreateDirectory(IptcDirectory.class); 80 IptcDirectory directory = new IptcDirectory(); 81 metadata.addDirectory(directory); 82 82 83 83 int offset = 0; -
trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java
r8132 r8243 48 48 } 49 49 50 public void extract(@NotNull byte[] segmentBytes, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)50 public void readJpegSegments(@NotNull Iterable<byte[]> segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType) 51 51 { 52 JpegCommentDirectory directory = metadata.getOrCreateDirectory(JpegCommentDirectory.class); 52 for (byte[] segmentBytes : segments) { 53 JpegCommentDirectory directory = new JpegCommentDirectory(); 54 metadata.addDirectory(directory); 53 55 54 // The entire contents of the directory are the comment 55 directory.setString(JpegCommentDirectory.TAG_COMMENT, new String(segmentBytes)); 56 // The entire contents of the directory are the comment 57 directory.setString(JpegCommentDirectory.TAG_COMMENT, new String(segmentBytes)); 58 } 56 59 } 57 60 } -
trunk/src/com/drew/metadata/jpeg/JpegReader.java
r8132 r8243 63 63 } 64 64 65 public boolean canProcess(@NotNull byte[] segmentBytes, @NotNull JpegSegmentType segmentType)65 public void readJpegSegments(@NotNull Iterable<byte[]> segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType) 66 66 { 67 return true; 67 for (byte[] segmentBytes : segments) { 68 extract(segmentBytes, metadata, segmentType); 69 } 68 70 } 69 71 70 public void extract( @NotNull byte[] segmentBytes, @NotNull Metadata metadata, @NotNullJpegSegmentType segmentType)72 public void extract(byte[] segmentBytes, Metadata metadata, JpegSegmentType segmentType) 71 73 { 72 if (metadata.containsDirectory(JpegDirectory.class)) { 73 // If this directory is already present, discontinue this operation. 74 // We only store metadata for the *first* matching SOFn segment. 75 return; 76 } 77 78 JpegDirectory directory = metadata.getOrCreateDirectory(JpegDirectory.class); 74 JpegDirectory directory = new JpegDirectory(); 75 metadata.addDirectory(directory); 79 76 80 77 // The value of TAG_COMPRESSION_TYPE is determined by the segment type found … … 101 98 directory.setObject(JpegDirectory.TAG_COMPONENT_DATA_1 + i, component); 102 99 } 103 104 100 } catch (IOException ex) { 105 101 directory.addError(ex.getMessage()); -
trunk/src/com/drew/metadata/tiff/DirectoryTiffHandler.java
r8132 r8243 41 41 protected final Metadata _metadata; 42 42 43 protected DirectoryTiffHandler(Metadata metadata, Class<? extends Directory> initialDirectory )43 protected DirectoryTiffHandler(Metadata metadata, Class<? extends Directory> initialDirectoryClass) 44 44 { 45 45 _metadata = metadata; 46 _currentDirectory = _metadata.getOrCreateDirectory(initialDirectory); 46 try { 47 _currentDirectory = initialDirectoryClass.newInstance(); 48 } catch (InstantiationException e) { 49 throw new RuntimeException(e); 50 } catch (IllegalAccessException e) { 51 throw new RuntimeException(e); 52 } 53 _metadata.addDirectory(_currentDirectory); 47 54 } 48 55 … … 54 61 protected void pushDirectory(@NotNull Class<? extends Directory> directoryClass) 55 62 { 56 assert(directoryClass != _currentDirectory.getClass());57 63 _directoryStack.push(_currentDirectory); 58 _currentDirectory = _metadata.getOrCreateDirectory(directoryClass); 64 try { 65 _currentDirectory = directoryClass.newInstance(); 66 } catch (InstantiationException e) { 67 throw new RuntimeException(e); 68 } catch (IllegalAccessException e) { 69 throw new RuntimeException(e); 70 } 71 _metadata.addDirectory(_currentDirectory); 59 72 } 60 73
Note:
See TracChangeset
for help on using the changeset viewer.