Changeset 6127 in josm for trunk/src/com/drew
- Timestamp:
- 2013-08-09T18:05:11+02:00 (12 years ago)
- Location:
- trunk/src/com/drew
- Files:
-
- 24 added
- 7 deleted
- 53 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/com/drew/imaging/PhotographicConversions.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.imaging; … … 17 23 /** 18 24 * Contains helper methods that perform photographic conversions. 25 * 26 * @author Drew Noakes http://drewnoakes.com 19 27 */ 20 public class PhotographicConversions 28 public final class PhotographicConversions 21 29 { 22 30 public final static double ROOT_TWO = Math.sqrt(2); 23 31 24 private PhotographicConversions() 25 {} 32 private PhotographicConversions() throws Exception 33 { 34 throw new Exception("Not intended for instantiation."); 35 } 26 36 27 37 /** 28 38 * Converts an aperture value to its corresponding F-stop number. 39 * 29 40 * @param aperture the aperture value to convert 30 41 * @return the F-stop number of the specified aperture … … 32 43 public static double apertureToFStop(double aperture) 33 44 { 34 double fStop = Math.pow(ROOT_TWO, aperture); 35 return fStop; 45 return Math.pow(ROOT_TWO, aperture); 36 46 37 // Puzzle?! 38 // jhead uses a different calculation as far as i can tell... this confuses me... 47 // NOTE jhead uses a different calculation as far as i can tell... this confuses me... 39 48 // fStop = (float)Math.exp(aperture * Math.log(2) * 0.5)); 40 49 } … … 42 51 /** 43 52 * Converts a shutter speed to an exposure time. 53 * 44 54 * @param shutterSpeed the shutter speed to convert 45 55 * @return the exposure time of the specified shutter speed … … 47 57 public static double shutterSpeedToExposureTime(double shutterSpeed) 48 58 { 49 return (float)(1 / Math.exp(shutterSpeed * Math.log(2))); 59 return (float) (1 / Math.exp(shutterSpeed * Math.log(2))); 50 60 } 51 61 } -
trunk/src/com/drew/imaging/jpeg/JpegMetadataReader.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 12-Nov-2002 18:51:36 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.imaging.jpeg; 18 22 19 import com.drew.metadata.Directory; 23 import com.drew.lang.ByteArrayReader; 24 import com.drew.lang.annotations.NotNull; 20 25 import com.drew.metadata.Metadata; 21 import com.drew.metadata.MetadataException;22 import com.drew.metadata.Tag;23 import com.drew.metadata.exif.ExifDirectory;24 26 import com.drew.metadata.exif.ExifReader; 25 27 import com.drew.metadata.iptc.IptcReader; 26 28 import com.drew.metadata.jpeg.JpegCommentReader; 29 import com.drew.metadata.jpeg.JpegDirectory; 27 30 import com.drew.metadata.jpeg.JpegReader; 28 31 … … 30 33 import java.io.IOException; 31 34 import java.io.InputStream; 32 import java.util.Iterator;33 35 34 36 /** 37 * Obtains all available metadata from Jpeg formatted files. 35 38 * 39 * @author Drew Noakes http://drewnoakes.com 36 40 */ 37 41 public class JpegMetadataReader 38 42 { 43 // TODO investigate supporting javax.imageio 39 44 // public static Metadata readMetadata(IIOMetadata metadata) throws JpegProcessingException {} 40 45 // public static Metadata readMetadata(ImageInputStream in) throws JpegProcessingException{} … … 42 47 // public static Metadata readMetadata(ImageReader reader) throws JpegProcessingException{} 43 48 44 public static Metadata readMetadata(InputStream in) throws JpegProcessingException 49 @NotNull 50 public static Metadata readMetadata(@NotNull InputStream inputStream) throws JpegProcessingException 45 51 { 46 JpegSegmentReader segmentReader = new JpegSegmentReader(in); 47 return extractMetadataFromJpegSegmentReader(segmentReader); 52 return readMetadata(inputStream, true); 48 53 } 49 54 50 public static Metadata readMetadata(File file) throws JpegProcessingException 55 @NotNull 56 public static Metadata readMetadata(@NotNull InputStream inputStream, final boolean waitForBytes) throws JpegProcessingException 57 { 58 JpegSegmentReader segmentReader = new JpegSegmentReader(inputStream, waitForBytes); 59 return extractMetadataFromJpegSegmentReader(segmentReader.getSegmentData()); 60 } 61 62 @NotNull 63 public static Metadata readMetadata(@NotNull File file) throws JpegProcessingException, IOException 51 64 { 52 65 JpegSegmentReader segmentReader = new JpegSegmentReader(file); 53 return extractMetadataFromJpegSegmentReader(segmentReader); 66 return extractMetadataFromJpegSegmentReader(segmentReader.getSegmentData()); 54 67 } 55 68 56 public static Metadata extractMetadataFromJpegSegmentReader(JpegSegmentReader segmentReader) 69 @NotNull 70 public static Metadata extractMetadataFromJpegSegmentReader(@NotNull JpegSegmentData segmentReader) 57 71 { 58 72 final Metadata metadata = new Metadata(); 59 try { 60 byte[] exifSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1); 61 new ExifReader(exifSegment).extract(metadata); 62 } catch (JpegProcessingException e) { 63 // in the interests of catching as much data as possible, continue 64 // TODO lodge error message within exif directory? 73 74 // Loop through looking for all SOFn segments. When we find one, we know what type of compression 75 // was used for the JPEG, and we can process the JPEG metadata in the segment too. 76 for (byte i = 0; i < 16; i++) { 77 // There are no SOF4 or SOF12 segments, so don't bother 78 if (i == 4 || i == 12) 79 continue; 80 // Should never have more than one SOFn for a given 'n'. 81 byte[] jpegSegment = segmentReader.getSegment((byte)(JpegSegmentReader.SEGMENT_SOF0 + i)); 82 if (jpegSegment == null) 83 continue; 84 JpegDirectory directory = metadata.getOrCreateDirectory(JpegDirectory.class); 85 directory.setInt(JpegDirectory.TAG_JPEG_COMPRESSION_TYPE, i); 86 new JpegReader().extract(new ByteArrayReader(jpegSegment), metadata); 87 break; 65 88 } 66 89 67 try { 68 byte[] iptcSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD); 69 new IptcReader(iptcSegment).extract(metadata); 70 } catch (JpegProcessingException e) { 71 // TODO lodge error message within iptc directory? 90 // There should never be more than one COM segment. 91 byte[] comSegment = segmentReader.getSegment(JpegSegmentReader.SEGMENT_COM); 92 if (comSegment != null) 93 new JpegCommentReader().extract(new ByteArrayReader(comSegment), metadata); 94 95 // Loop through all APP1 segments, checking the leading bytes to identify the format of each. 96 for (byte[] app1Segment : segmentReader.getSegments(JpegSegmentReader.SEGMENT_APP1)) { 97 if (app1Segment.length > 3 && "EXIF".equalsIgnoreCase(new String(app1Segment, 0, 4))) 98 new ExifReader().extract(new ByteArrayReader(app1Segment), metadata); 99 100 //if (app1Segment.length > 27 && "http://ns.adobe.com/xap/1.0/".equalsIgnoreCase(new String(app1Segment, 0, 28))) 101 // new XmpReader().extract(new ByteArrayReader(app1Segment), metadata); 72 102 } 73 103 74 try { 75 byte[] jpegSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_SOF0); 76 new JpegReader(jpegSegment).extract(metadata); 77 } catch (JpegProcessingException e) { 78 // TODO lodge error message within jpeg directory? 79 } 80 81 try { 82 byte[] jpegCommentSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_COM); 83 new JpegCommentReader(jpegCommentSegment).extract(metadata); 84 } catch (JpegProcessingException e) { 85 // TODO lodge error message within jpegcomment directory? 86 } 104 // Loop through all APPD segments, checking the leading bytes to identify the format of each. 105 for (byte[] appdSegment : segmentReader.getSegments(JpegSegmentReader.SEGMENT_APPD)) { 106 if (appdSegment.length > 12 && "Photoshop 3.0".compareTo(new String(appdSegment, 0, 13))==0) { 107 //new PhotoshopReader().extract(new ByteArrayReader(appdSegment), metadata); 108 } else { 109 // TODO might be able to check for a leading 0x1c02 for IPTC data... 110 new IptcReader().extract(new ByteArrayReader(appdSegment), metadata); 111 } 112 } 87 113 88 114 return metadata; 89 115 } 90 116 91 private JpegMetadataReader() 117 private JpegMetadataReader() throws Exception 92 118 { 93 } 94 95 public static void main(String[] args) throws MetadataException, IOException 96 { 97 Metadata metadata = null; 98 try { 99 metadata = JpegMetadataReader.readMetadata(new File(args[0])); 100 } catch (Exception e) { 101 e.printStackTrace(System.err); 102 System.exit(1); 103 } 104 105 // iterate over the exif data and print to System.out 106 Iterator directories = metadata.getDirectoryIterator(); 107 while (directories.hasNext()) { 108 Directory directory = (Directory)directories.next(); 109 Iterator tags = directory.getTagIterator(); 110 while (tags.hasNext()) { 111 Tag tag = (Tag)tags.next(); 112 try { 113 System.out.println("[" + directory.getName() + "] " + tag.getTagName() + " = " + tag.getDescription()); 114 } catch (MetadataException e) { 115 System.err.println(e.getMessage()); 116 System.err.println(tag.getDirectoryName() + " " + tag.getTagName() + " (error)"); 117 } 118 } 119 if (directory.hasErrors()) { 120 Iterator errors = directory.getErrors(); 121 while (errors.hasNext()) { 122 System.out.println("ERROR: " + errors.next()); 123 } 124 } 125 } 126 127 if (args.length>1 && args[1].trim().equals("/thumb")) 128 { 129 ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); 130 if (directory.containsThumbnail()) 131 { 132 System.out.println("Writing thumbnail..."); 133 directory.writeThumbnail(args[0].trim() + ".thumb.jpg"); 134 } 135 else 136 { 137 System.out.println("No thumbnail data exists in this image"); 138 } 139 } 119 throw new Exception("Not intended for instantiation"); 140 120 } 141 121 } 122 -
trunk/src/com/drew/imaging/jpeg/JpegProcessingException.java
r4231 r6127 1 1 /* 2 * JpegProcessingException.java2 * Copyright 2002-2012 Drew Noakes 3 3 * 4 * This class is public domain software - that is, you can do whatever you want 5 * with it, and include it software that is licensed under the GNU or the 6 * BSD license, or whatever other licence you choose, including proprietary 7 * closed source licenses. I do ask that you leave this header in tact. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 8 7 * 9 * If you make modifications to this code that you think would benefit the 10 * wider community, please send me a copy and I'll post it on my site. 8 * http://www.apache.org/licenses/LICENSE-2.0 11 9 * 12 * If you make use of this code, I'd appreciate hearing about it. 13 * drew@drewnoakes.com 14 * Latest version of this software kept at 15 * http://drewnoakes.com/ 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 16 15 * 17 * Created by dnoakes on 04-Nov-2002 19:31:29 using IntelliJ IDEA. 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 18 20 */ 19 21 package com.drew.imaging.jpeg; 20 22 21 import com.drew.lang.CompoundException; 23 import com.drew.imaging.ImageProcessingException; 24 import com.drew.lang.annotations.Nullable; 22 25 23 26 /** 24 * An exception class thrown upon unexpected and fatal conditions while processing 25 * a Jpeg file.26 * @author 27 * An exception class thrown upon unexpected and fatal conditions while processing a Jpeg file. 28 * 29 * @author Drew Noakes http://drewnoakes.com 27 30 */ 28 public class JpegProcessingException extends CompoundException31 public class JpegProcessingException extends ImageProcessingException 29 32 { 30 public JpegProcessingException(String message) 33 private static final long serialVersionUID = -7870179776125450158L; 34 35 public JpegProcessingException(@Nullable String message) 31 36 { 32 37 super(message); 33 38 } 34 39 35 public JpegProcessingException(String message, Throwable cause) 40 public JpegProcessingException(@Nullable String message, @Nullable Throwable cause) 36 41 { 37 42 super(message, cause); 38 43 } 39 44 40 public JpegProcessingException(Throwable cause) 45 public JpegProcessingException(@Nullable Throwable cause) 41 46 { 42 47 super(cause); -
trunk/src/com/drew/imaging/jpeg/JpegSegmentData.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.imaging.jpeg; 22 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 16 25 17 26 import java.io.*; … … 22 31 /** 23 32 * Holds a collection of Jpeg data segments. This need not necessarily be all segments 24 * within the Jpeg. For example, it may be convenient to port aboutonly the non-image33 * within the Jpeg. For example, it may be convenient to store only the non-image 25 34 * segments when analysing (or serializing) metadata. 35 * <p/> 36 * Segments are keyed via their segment marker (a byte). Where multiple segments use the 37 * same segment marker, they will all be stored and available. 38 * 39 * @author Drew Noakes http://drewnoakes.com 26 40 */ 27 41 public class JpegSegmentData implements Serializable 28 42 { 29 static final long serialVersionUID = 7110175216435025451L; 43 private static final long serialVersionUID = 7110175216435025451L; 30 44 31 45 /** A map of byte[], keyed by the segment marker */ 32 private final HashMap _segmentDataMap; 33 34 public JpegSegmentData() 35 { 36 _segmentDataMap = new HashMap(10); 37 } 38 39 public void addSegment(byte segmentMarker, byte[] segmentBytes) 40 { 41 List segmentList = getOrCreateSegmentList(segmentMarker); 46 @NotNull 47 private final HashMap<Byte, List<byte[]>> _segmentDataMap = new HashMap<Byte, List<byte[]>>(10); 48 49 /** 50 * Adds segment bytes to the collection. 51 * @param segmentMarker 52 * @param segmentBytes 53 */ 54 @SuppressWarnings({ "MismatchedQueryAndUpdateOfCollection" }) 55 public void addSegment(byte segmentMarker, @NotNull byte[] segmentBytes) 56 { 57 final List<byte[]> segmentList = getOrCreateSegmentList(segmentMarker); 42 58 segmentList.add(segmentBytes); 43 59 } 44 60 61 /** 62 * Gets the first Jpeg segment data for the specified marker. 63 * @param segmentMarker the byte identifier for the desired segment 64 * @return a byte[] containing segment data or null if no data exists for that segment 65 */ 66 @Nullable 45 67 public byte[] getSegment(byte segmentMarker) 46 68 { … … 48 70 } 49 71 72 /** 73 * Gets segment data for a specific occurrence and marker. Use this method when more than one occurrence 74 * of segment data for a given marker exists. 75 * @param segmentMarker identifies the required segment 76 * @param occurrence the zero-based index of the occurrence 77 * @return the segment data as a byte[], or null if no segment exists for the marker & occurrence 78 */ 79 @Nullable 50 80 public byte[] getSegment(byte segmentMarker, int occurrence) 51 81 { 52 final List segmentList = getSegmentList(segmentMarker); 82 final List<byte[]> segmentList = getSegmentList(segmentMarker); 53 83 54 84 if (segmentList==null || segmentList.size()<=occurrence) 55 85 return null; 56 86 else 57 return (byte[]) segmentList.get(occurrence); 58 } 59 87 return segmentList.get(occurrence); 88 } 89 90 /** 91 * Returns all instances of a given Jpeg segment. If no instances exist, an empty sequence is returned. 92 * 93 * @param segmentMarker a number which identifies the type of Jpeg segment being queried 94 * @return zero or more byte arrays, each holding the data of a Jpeg segment 95 */ 96 @NotNull 97 public Iterable<byte[]> getSegments(byte segmentMarker) 98 { 99 final List<byte[]> segmentList = getSegmentList(segmentMarker); 100 return segmentList==null ? new ArrayList<byte[]>() : segmentList; 101 } 102 103 @Nullable 104 public List<byte[]> getSegmentList(byte segmentMarker) 105 { 106 return _segmentDataMap.get(Byte.valueOf(segmentMarker)); 107 } 108 109 @NotNull 110 private List<byte[]> getOrCreateSegmentList(byte segmentMarker) 111 { 112 List<byte[]> segmentList; 113 if (_segmentDataMap.containsKey(segmentMarker)) { 114 segmentList = _segmentDataMap.get(segmentMarker); 115 } else { 116 segmentList = new ArrayList<byte[]>(); 117 _segmentDataMap.put(segmentMarker, segmentList); 118 } 119 return segmentList; 120 } 121 122 /** 123 * Returns the count of segment data byte arrays stored for a given segment marker. 124 * @param segmentMarker identifies the required segment 125 * @return the segment count (zero if no segments exist). 126 */ 60 127 public int getSegmentCount(byte segmentMarker) 61 128 { 62 final List segmentList = getSegmentList(segmentMarker); 63 if (segmentList==null) 64 return 0; 65 else 66 return segmentList.size(); 67 } 68 129 final List<byte[]> segmentList = getSegmentList(segmentMarker); 130 return segmentList == null ? 0 : segmentList.size(); 131 } 132 133 /** 134 * Removes a specified instance of a segment's data from the collection. Use this method when more than one 135 * occurrence of segment data for a given marker exists. 136 * @param segmentMarker identifies the required segment 137 * @param occurrence the zero-based index of the segment occurrence to remove. 138 */ 139 @SuppressWarnings({ "MismatchedQueryAndUpdateOfCollection" }) 69 140 public void removeSegmentOccurrence(byte segmentMarker, int occurrence) 70 141 { 71 final List segmentList = (List)_segmentDataMap.get(new Byte(segmentMarker));142 final List<byte[]> segmentList = _segmentDataMap.get(Byte.valueOf(segmentMarker)); 72 143 segmentList.remove(occurrence); 73 144 } 74 145 146 /** 147 * Removes all segments from the collection having the specified marker. 148 * @param segmentMarker identifies the required segment 149 */ 75 150 public void removeSegment(byte segmentMarker) 76 151 { 77 _segmentDataMap.remove(new Byte(segmentMarker)); 78 } 79 80 private List getSegmentList(byte segmentMarker) 81 { 82 return (List)_segmentDataMap.get(new Byte(segmentMarker)); 83 } 84 85 private List getOrCreateSegmentList(byte segmentMarker) 86 { 87 List segmentList; 88 Byte key = new Byte(segmentMarker); 89 if (_segmentDataMap.containsKey(key)) { 90 segmentList = (List)_segmentDataMap.get(key); 91 } else { 92 segmentList = new ArrayList(); 93 _segmentDataMap.put(key, segmentList); 94 } 95 return segmentList; 96 } 97 152 _segmentDataMap.remove(Byte.valueOf(segmentMarker)); 153 } 154 155 /** 156 * Determines whether data is present for a given segment marker. 157 * @param segmentMarker identifies the required segment 158 * @return true if data exists, otherwise false 159 */ 98 160 public boolean containsSegment(byte segmentMarker) 99 161 { 100 return _segmentDataMap.containsKey(new Byte(segmentMarker)); 101 } 102 103 public static void ToFile(File file, JpegSegmentData segmentData) throws IOException 104 { 105 ObjectOutputStream outputStream = null; 162 return _segmentDataMap.containsKey(Byte.valueOf(segmentMarker)); 163 } 164 165 /** 166 * Serialises the contents of a JpegSegmentData to a file. 167 * @param file to file to write from 168 * @param segmentData the data to write 169 * @throws IOException if problems occur while writing 170 */ 171 public static void toFile(@NotNull File file, @NotNull JpegSegmentData segmentData) throws IOException 172 { 173 FileOutputStream fileOutputStream = null; 106 174 try 107 175 { 108 outputStream =new ObjectOutputStream(new FileOutputStream(file));109 outputStream.writeObject(segmentData);176 fileOutputStream = new FileOutputStream(file); 177 new ObjectOutputStream(fileOutputStream).writeObject(segmentData); 110 178 } 111 179 finally 112 180 { 113 if (outputStream!=null) 114 outputStream.close(); 115 } 116 } 117 118 public static JpegSegmentData FromFile(File file) throws IOException, ClassNotFoundException 181 if (fileOutputStream!=null) 182 fileOutputStream.close(); 183 } 184 } 185 186 /** 187 * Deserialises the contents of a JpegSegmentData from a file. 188 * @param file the file to read from 189 * @return the JpegSegmentData as read 190 * @throws IOException if problems occur while reading 191 * @throws ClassNotFoundException if problems occur while deserialising 192 */ 193 @NotNull 194 public static JpegSegmentData fromFile(@NotNull File file) throws IOException, ClassNotFoundException 119 195 { 120 196 ObjectInputStream inputStream = null; -
trunk/src/com/drew/imaging/jpeg/JpegSegmentReader.java
r4231 r6127 1 1 /* 2 * JpegSegmentReader.java3 * 4 * This class written by Drew Noakes, in accordance with the Jpeg specification.5 * 6 * This is public domain software - that is, you can do whatever you want7 * with it, and include it software that is licensed under the GNU or the8 * BSDlicense, or whatever other licence you choose, including proprietary9 * closed source licenses. I do ask that you leave this header in tact.10 * 11 * If you make modifications to this code that you think would benefit the12 * wider community, please send me a copy and I'll post it on my site.13 * 14 * If you make use of this code, I'd appreciate hearing about it.15 * drew@drewnoakes.com16 * Latest version of this software kept at17 * http://drewnoakes.com/18 * 19 * Created by dnoakes on 04-Nov-2002 00:54:00 using IntelliJ IDEA2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 20 20 */ 21 21 package com.drew.imaging.jpeg; 22 22 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 25 23 26 import java.io.*; 24 27 25 28 /** 26 29 * Performs read functions of Jpeg files, returning specific file segments. 27 * TODO add a findAvailableSegments() method28 * TODO add more segment identifiers29 * TODO add a getSegmentDescription() method, returning for example 'App1 application data segment, commonly containing Exif data'30 30 * @author Drew Noakes http://drewnoakes.com 31 31 */ 32 32 public class JpegSegmentReader 33 33 { 34 // Jpeg data can be sourced from either a file, byte[] or InputStream 35 36 /** Jpeg file */ 37 private final File _file; 38 /** Jpeg data as byte array */ 39 private final byte[] _data; 40 /** Jpeg data as an InputStream */ 41 private final InputStream _stream; 42 43 private JpegSegmentData _segmentData; 44 45 /** 46 * Private, because this segment crashes my algorithm, and searching for 47 * it doesn't work (yet). 34 // TODO add a findAvailableSegments() method 35 // TODO add more segment identifiers 36 // TODO add a getSegmentDescription() method, returning for example 'App1 application data segment, commonly containing Exif data' 37 38 @NotNull 39 private final JpegSegmentData _segmentData; 40 41 /** 42 * Private, because this segment crashes my algorithm, and searching for it doesn't work (yet). 48 43 */ 49 44 private static final byte SEGMENT_SOS = (byte)0xDA; … … 54 49 private static final byte MARKER_EOI = (byte)0xD9; 55 50 56 /** APP0 Jpeg segment identifier -- J fif data. */51 /** APP0 Jpeg segment identifier -- JFIF data (also JFXX apparently). */ 57 52 public static final byte SEGMENT_APP0 = (byte)0xE0; 58 /** APP1 Jpeg segment identifier -- where Exif data is kept. */ 53 /** APP1 Jpeg segment identifier -- where Exif data is kept. XMP data is also kept in here, though usually in a second instance. */ 59 54 public static final byte SEGMENT_APP1 = (byte)0xE1; 60 55 /** APP2 Jpeg segment identifier. */ … … 74 69 /** APP9 Jpeg segment identifier. */ 75 70 public static final byte SEGMENT_APP9 = (byte)0xE9; 76 /** APPA Jpeg segment identifier -- can hold Unicode comments. */ 71 /** APPA (App10) Jpeg segment identifier -- can hold Unicode comments. */ 77 72 public static final byte SEGMENT_APPA = (byte)0xEA; 78 /** APPB Jpeg segment identifier. */ 73 /** APPB (App11) Jpeg segment identifier. */ 79 74 public static final byte SEGMENT_APPB = (byte)0xEB; 80 /** APPC Jpeg segment identifier. */ 75 /** APPC (App12) Jpeg segment identifier. */ 81 76 public static final byte SEGMENT_APPC = (byte)0xEC; 82 /** APPD Jpeg segment identifier -- IPTC data in here. */ 77 /** APPD (App13) Jpeg segment identifier -- IPTC data in here. */ 83 78 public static final byte SEGMENT_APPD = (byte)0xED; 84 /** APPE Jpeg segment identifier. */ 79 /** APPE (App14) Jpeg segment identifier. */ 85 80 public static final byte SEGMENT_APPE = (byte)0xEE; 86 /** APPF Jpeg segment identifier. */ 81 /** APPF (App15) Jpeg segment identifier. */ 87 82 public static final byte SEGMENT_APPF = (byte)0xEF; 88 83 /** Start Of Image segment identifier. */ … … 101 96 * @param file the Jpeg file to read segments from 102 97 */ 103 public JpegSegmentReader(File file) throws JpegProcessingException 104 { 105 _file = file; 106 _data = null; 107 _stream = null; 108 109 readSegments(); 98 @SuppressWarnings({ "ConstantConditions" }) 99 public JpegSegmentReader(@NotNull File file) throws JpegProcessingException, IOException 100 { 101 if (file==null) 102 throw new NullPointerException(); 103 104 InputStream inputStream = null; 105 try { 106 inputStream = new FileInputStream(file); 107 _segmentData = readSegments(new BufferedInputStream(inputStream), false); 108 } finally { 109 if (inputStream != null) 110 inputStream.close(); 111 } 110 112 } 111 113 … … 114 116 * @param fileContents the byte array containing Jpeg data 115 117 */ 116 public JpegSegmentReader(byte[] fileContents) throws JpegProcessingException117 {118 _file = null;119 _data =fileContents;120 _stream = null;121 122 readSegments();123 }124 125 public JpegSegmentReader(InputStream in) throws JpegProcessingException 126 {127 _stream = in;128 _file = null;129 _data = null;130 131 readSegments();132 }133 134 public JpegSegmentReader(JpegSegmentData segmentData)135 { 136 _file = null;137 _data = null;138 _stream = null;139 140 _segmentData = segmentData;118 @SuppressWarnings({ "ConstantConditions" }) 119 public JpegSegmentReader(@NotNull byte[] fileContents) throws JpegProcessingException 120 { 121 if (fileContents==null) 122 throw new NullPointerException(); 123 124 BufferedInputStream stream = new BufferedInputStream(new ByteArrayInputStream(fileContents)); 125 _segmentData = readSegments(stream, false); 126 } 127 128 /** 129 * Creates a JpegSegmentReader for an InputStream. 130 * @param inputStream the InputStream containing Jpeg data 131 */ 132 @SuppressWarnings({ "ConstantConditions" }) 133 public JpegSegmentReader(@NotNull InputStream inputStream, boolean waitForBytes) throws JpegProcessingException 134 { 135 if (inputStream==null) 136 throw new NullPointerException(); 137 138 BufferedInputStream bufferedInputStream = inputStream instanceof BufferedInputStream 139 ? (BufferedInputStream)inputStream 140 : new BufferedInputStream(inputStream); 141 142 _segmentData = readSegments(bufferedInputStream, waitForBytes); 141 143 } 142 144 … … 146 148 * @param segmentMarker the byte identifier for the desired segment 147 149 * @return the byte array if found, else null 148 * @throws JpegProcessingException for any problems processing the Jpeg data, 149 * including inner IOExceptions 150 */ 151 public byte[] readSegment(byte segmentMarker) throws JpegProcessingException 150 */ 151 @Nullable 152 public byte[] readSegment(byte segmentMarker) 152 153 { 153 154 return readSegment(segmentMarker, 0); … … 155 156 156 157 /** 157 * Reads the firstinstance of a given Jpeg segment, returning the contents as158 * a byte array.158 * Reads the Nth instance of a given Jpeg segment, returning the contents as a byte array. 159 * 159 160 * @param segmentMarker the byte identifier for the desired segment 160 161 * @param occurrence the occurrence of the specified segment within the jpeg file 161 162 * @return the byte array if found, else null 162 163 */ 164 @Nullable 163 165 public byte[] readSegment(byte segmentMarker, int occurrence) 164 166 { … … 166 168 } 167 169 170 /** 171 * Returns all instances of a given Jpeg segment. If no instances exist, an empty sequence is returned. 172 * 173 * @param segmentMarker a number which identifies the type of Jpeg segment being queried 174 * @return zero or more byte arrays, each holding the data of a Jpeg segment 175 */ 176 @NotNull 177 public Iterable<byte[]> readSegments(byte segmentMarker) 178 { 179 return _segmentData.getSegments(segmentMarker); 180 } 181 182 /** 183 * Returns the number of segments having the specified JPEG segment marker. 184 * @param segmentMarker the JPEG segment identifying marker. 185 * @return the count of matching segments. 186 */ 168 187 public final int getSegmentCount(byte segmentMarker) 169 188 { … … 171 190 } 172 191 192 /** 193 * Returns the JpegSegmentData object used by this reader. 194 * @return the JpegSegmentData object. 195 */ 196 @NotNull 173 197 public final JpegSegmentData getSegmentData() 174 198 { … … 176 200 } 177 201 178 private void readSegments() throws JpegProcessingException179 {180 _segmentData = new JpegSegmentData();181 182 BufferedInputStream inStream = getJpegInputStream(); 202 @NotNull 203 private JpegSegmentData readSegments(@NotNull final BufferedInputStream jpegInputStream, boolean waitForBytes) throws JpegProcessingException 204 { 205 JpegSegmentData segmentData = new JpegSegmentData(); 206 183 207 try { 184 208 int offset = 0; 185 209 // first two bytes should be jpeg magic number 186 if (!isValidJpegHeaderBytes(inStream)) { 210 byte[] headerBytes = new byte[2]; 211 if (jpegInputStream.read(headerBytes, 0, 2)!=2) 187 212 throw new JpegProcessingException("not a jpeg file"); 188 } 213 final boolean hasValidHeader = (headerBytes[0] & 0xFF) == 0xFF && (headerBytes[1] & 0xFF) == 0xD8; 214 if (!hasValidHeader) 215 throw new JpegProcessingException("not a jpeg file"); 216 189 217 offset += 2; 190 218 do { 219 // need four bytes from stream for segment header before continuing 220 if (!checkForBytesOnStream(jpegInputStream, 4, waitForBytes)) 221 throw new JpegProcessingException("stream ended before segment header could be read"); 222 191 223 // next byte is 0xFF 192 byte segmentIdentifier = (byte)( inStream.read() & 0xFF);224 byte segmentIdentifier = (byte)(jpegInputStream.read() & 0xFF); 193 225 if ((segmentIdentifier & 0xFF) != 0xFF) { 194 226 throw new JpegProcessingException("expected jpeg segment start identifier 0xFF at offset " + offset + ", not 0x" + Integer.toHexString(segmentIdentifier & 0xFF)); … … 196 228 offset++; 197 229 // next byte is <segment-marker> 198 byte thisSegmentMarker = (byte)( inStream.read() & 0xFF);230 byte thisSegmentMarker = (byte)(jpegInputStream.read() & 0xFF); 199 231 offset++; 200 232 // next 2-bytes are <segment-size>: [high-byte] [low-byte] 201 233 byte[] segmentLengthBytes = new byte[2]; 202 inStream.read(segmentLengthBytes, 0, 2); 234 if (jpegInputStream.read(segmentLengthBytes, 0, 2) != 2) 235 throw new JpegProcessingException("Jpeg data ended unexpectedly."); 203 236 offset += 2; 204 237 int segmentLength = ((segmentLengthBytes[0] << 8) & 0xFF00) | (segmentLengthBytes[1] & 0xFF); 205 238 // segment length includes size bytes, so subtract two 206 239 segmentLength -= 2; 207 if (segmentLength > inStream.available())240 if (!checkForBytesOnStream(jpegInputStream, segmentLength, waitForBytes)) 208 241 throw new JpegProcessingException("segment size would extend beyond file stream length"); 209 elseif (segmentLength < 0)242 if (segmentLength < 0) 210 243 throw new JpegProcessingException("segment size would be less than zero"); 211 244 byte[] segmentBytes = new byte[segmentLength]; 212 inStream.read(segmentBytes, 0, segmentLength); 245 if (jpegInputStream.read(segmentBytes, 0, segmentLength) != segmentLength) 246 throw new JpegProcessingException("Jpeg data ended unexpectedly."); 213 247 offset += segmentLength; 214 248 if ((thisSegmentMarker & 0xFF) == (SEGMENT_SOS & 0xFF)) { … … 216 250 // have to search for the two bytes: 0xFF 0xD9 (EOI). 217 251 // It comes last so simply return at this point 218 return; 252 return segmentData; 219 253 } else if ((thisSegmentMarker & 0xFF) == (MARKER_EOI & 0xFF)) { 220 254 // the 'End-Of-Image' segment -- this should never be found in this fashion 221 return; 255 return segmentData; 222 256 } else { 223 _segmentData.addSegment(thisSegmentMarker, segmentBytes);257 segmentData.addSegment(thisSegmentMarker, segmentBytes); 224 258 } 225 // didn't find the one we're looking for, loop through to the next segment226 259 } while (true); 227 260 } catch (IOException ioe) { 228 //throw new JpegProcessingException("IOException processing Jpeg file", ioe);229 261 throw new JpegProcessingException("IOException processing Jpeg file: " + ioe.getMessage(), ioe); 230 262 } finally { 231 263 try { 232 if ( inStream != null) {233 inStream.close();264 if (jpegInputStream != null) { 265 jpegInputStream.close(); 234 266 } 235 267 } catch (IOException ioe) { 236 //throw new JpegProcessingException("IOException processing Jpeg file", ioe);237 268 throw new JpegProcessingException("IOException processing Jpeg file: " + ioe.getMessage(), ioe); 238 269 } … … 240 271 } 241 272 242 /** 243 * Private helper method to create a BufferedInputStream of Jpeg data from whichever 244 * data source was specified upon construction of this instance. 245 * @return a a BufferedInputStream of Jpeg data 246 * @throws JpegProcessingException for any problems obtaining the stream 247 */ 248 private BufferedInputStream getJpegInputStream() throws JpegProcessingException 249 { 250 if (_stream!=null) { 251 if (_stream instanceof BufferedInputStream) { 252 return (BufferedInputStream) _stream; 253 } else { 254 return new BufferedInputStream(_stream); 273 private boolean checkForBytesOnStream(@NotNull BufferedInputStream stream, int bytesNeeded, boolean waitForBytes) throws IOException 274 { 275 // NOTE waiting is essential for network streams where data can be delayed, but it is not necessary for byte[] or filesystems 276 277 if (!waitForBytes) 278 return bytesNeeded <= stream.available(); 279 280 int count = 40; // * 100ms = approx 4 seconds 281 while (count > 0) { 282 if (bytesNeeded <= stream.available()) 283 return true; 284 try { 285 Thread.sleep(100); 286 } catch (InterruptedException e) { 287 // continue 255 288 } 289 count--; 256 290 } 257 InputStream inputStream; 258 if (_data == null) { 259 try { 260 inputStream = new FileInputStream(_file); 261 } catch (FileNotFoundException e) { 262 throw new JpegProcessingException("Jpeg file does not exist", e); 263 } 264 } else { 265 inputStream = new ByteArrayInputStream(_data); 266 } 267 return new BufferedInputStream(inputStream); 268 } 269 270 /** 271 * Helper method that validates the Jpeg file's magic number. 272 * @param fileStream the InputStream to read bytes from, which must be positioned 273 * at its start (i.e. no bytes read yet) 274 * @return true if the magic number is Jpeg (0xFFD8) 275 * @throws IOException for any problem in reading the file 276 */ 277 private boolean isValidJpegHeaderBytes(InputStream fileStream) throws IOException 278 { 279 byte[] header = new byte[2]; 280 fileStream.read(header, 0, 2); 281 return (header[0] & 0xFF) == 0xFF && (header[1] & 0xFF) == 0xD8; 291 return false; 282 292 } 283 293 } -
trunk/src/com/drew/lang/CompoundException.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.lang; 22 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 16 25 17 26 import java.io.PrintStream; … … 22 31 * unavailable in previous versions. This class allows support 23 32 * of these previous JDK versions. 33 * 34 * @author Drew Noakes http://drewnoakes.com 24 35 */ 25 36 public class CompoundException extends Exception 26 37 { 27 private final Throwable _innnerException;38 private static final long serialVersionUID = -9207883813472069925L; 28 39 29 public CompoundException(String msg) 40 @Nullable 41 private final Throwable _innerException; 42 43 public CompoundException(@Nullable String msg) 30 44 { 31 45 this(msg, null); 32 46 } 33 47 34 public CompoundException(Throwable exception) 48 public CompoundException(@Nullable Throwable exception) 35 49 { 36 50 this(null, exception); 37 51 } 38 52 39 public CompoundException(String msg, Throwable innerException) 53 public CompoundException(@Nullable String msg, @Nullable Throwable innerException) 40 54 { 41 55 super(msg); 42 _inn nerException = innerException;56 _innerException = innerException; 43 57 } 44 58 59 @Nullable 45 60 public Throwable getInnerException() 46 61 { 47 return _inn nerException;62 return _innerException; 48 63 } 49 64 65 @NotNull 50 66 public String toString() 51 67 { 52 StringBu ffer sbuffer= new StringBuffer();53 s buffer.append(super.toString());54 if (_inn nerException != null) {55 s buffer.append("\n");56 s buffer.append("--- inner exception ---");57 s buffer.append("\n");58 s buffer.append(_innnerException.toString());68 StringBuilder string = new StringBuilder(); 69 string.append(super.toString()); 70 if (_innerException != null) { 71 string.append("\n"); 72 string.append("--- inner exception ---"); 73 string.append("\n"); 74 string.append(_innerException.toString()); 59 75 } 60 return s buffer.toString();76 return string.toString(); 61 77 } 62 78 63 public void printStackTrace(PrintStream s) 79 public void printStackTrace(@NotNull PrintStream s) 64 80 { 65 81 super.printStackTrace(s); 66 if (_inn nerException != null) {82 if (_innerException != null) { 67 83 s.println("--- inner exception ---"); 68 _inn nerException.printStackTrace(s);84 _innerException.printStackTrace(s); 69 85 } 70 86 } 71 87 72 public void printStackTrace(PrintWriter s) 88 public void printStackTrace(@NotNull PrintWriter s) 73 89 { 74 90 super.printStackTrace(s); 75 if (_inn nerException != null) {91 if (_innerException != null) { 76 92 s.println("--- inner exception ---"); 77 _inn nerException.printStackTrace(s);93 _innerException.printStackTrace(s); 78 94 } 79 95 } … … 82 98 { 83 99 super.printStackTrace(); 84 if (_inn nerException != null) {100 if (_innerException != null) { 85 101 System.err.println("--- inner exception ---"); 86 _inn nerException.printStackTrace();102 _innerException.printStackTrace(); 87 103 } 88 104 } -
trunk/src/com/drew/lang/NullOutputStream.java
r4231 r6127 1 /** 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 1 /* 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on Dec 15, 2002 3:30:59 PM using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.lang; … … 20 24 import java.io.OutputStream; 21 25 26 /** 27 * An implementation of OutputSteam that ignores write requests by doing nothing. This class may be useful in tests. 28 * 29 * @author Drew Noakes http://drewnoakes.com 30 */ 22 31 public class NullOutputStream extends OutputStream 23 32 { -
trunk/src/com/drew/lang/Rational.java
r4231 r6127 1 1 /* 2 * Rational.java 3 * 4 * This class is public domain software - that is, you can do whatever you want 5 * with it, and include it software that is licensed under the GNU or the 6 * BSD license, or whatever other licence you choose, including proprietary 7 * closed source licenses. Similarly, I release this Java version under the 8 * same license, though I do ask that you leave this header in tact. 9 * 10 * If you make modifications to this code that you think would benefit the 11 * wider community, please send me a copy and I'll post it on my site. 12 * 13 * If you make use of this code, I'd appreciate hearing about it. 14 * drew.noakes@drewnoakes.com 15 * Latest version of this software kept at 16 * http://drewnoakes.com/ 17 * 18 * Created on 6 May 2002, 18:06 19 * Updated 26 Aug 2002 by Drew 20 * - Added toSimpleString() method, which returns a simplified and hopefully more 21 * readable version of the Rational. i.e. 2/10 -> 1/5, and 10/2 -> 5 22 * Modified 29 Oct 2002 (v1.2) 23 * - Improved toSimpleString() to factor more complex rational numbers into 24 * a simpler form 25 * i.e. 26 * 10/15 -> 2/3 27 * - toSimpleString() now accepts a boolean flag, 'allowDecimals' which will 28 * display the rational number in decimal form if it fits within 5 digits 29 * i.e. 30 * 3/4 -> 0.75 when allowDecimal == true 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 31 20 */ 32 21 33 22 package com.drew.lang; 23 24 import com.drew.lang.annotations.NotNull; 25 import com.drew.lang.annotations.Nullable; 34 26 35 27 import java.io.Serializable; … … 38 30 * Immutable class for holding a rational number without loss of precision. Provides 39 31 * a familiar representation via toString() in form <code>numerator/denominator</code>. 40 * <p>41 * @author 32 * 33 * @author Drew Noakes http://drewnoakes.com 42 34 */ 43 35 public class Rational extends java.lang.Number implements Serializable 44 36 { 45 /** 46 * Holds the numerator. 47 */ 48 private final int numerator; 49 50 /** 51 * Holds the denominator. 52 */ 53 private final int denominator; 54 55 private int maxSimplificationCalculations = 1000; 37 private static final long serialVersionUID = 510688928138848770L; 38 39 /** Holds the numerator. */ 40 private final long _numerator; 41 42 /** Holds the denominator. */ 43 private final long _denominator; 56 44 57 45 /** … … 60 48 * with them! 61 49 */ 62 public Rational( intnumerator,intdenominator)63 { 64 this.numerator = numerator;65 this.denominator = denominator;50 public Rational(long numerator, long denominator) 51 { 52 _numerator = numerator; 53 _denominator = denominator; 66 54 } 67 55 … … 70 58 * This may involve rounding. 71 59 * 72 * @return 73 * 60 * @return the numeric value represented by this object after conversion 61 * to type <code>double</code>. 74 62 */ 75 63 public double doubleValue() 76 64 { 77 return (double)numerator / (double)denominator; 65 return (double) _numerator / (double) _denominator; 78 66 } 79 67 … … 82 70 * This may involve rounding. 83 71 * 84 * @return 85 * 72 * @return the numeric value represented by this object after conversion 73 * to type <code>float</code>. 86 74 */ 87 75 public float floatValue() 88 76 { 89 return (float)numerator / (float)denominator; 77 return (float) _numerator / (float) _denominator; 90 78 } 91 79 … … 95 83 * casts the result of <code>doubleValue()</code> to <code>byte</code>. 96 84 * 97 * @return 98 * 85 * @return the numeric value represented by this object after conversion 86 * to type <code>byte</code>. 99 87 */ 100 88 public final byte byteValue() 101 89 { 102 return (byte)doubleValue(); 90 return (byte) doubleValue(); 103 91 } 104 92 … … 108 96 * casts the result of <code>doubleValue()</code> to <code>int</code>. 109 97 * 110 * @return 111 * 98 * @return the numeric value represented by this object after conversion 99 * to type <code>int</code>. 112 100 */ 113 101 public final int intValue() 114 102 { 115 return (int)doubleValue(); 103 return (int) doubleValue(); 116 104 } 117 105 … … 121 109 * casts the result of <code>doubleValue()</code> to <code>long</code>. 122 110 * 123 * @return 124 * 111 * @return the numeric value represented by this object after conversion 112 * to type <code>long</code>. 125 113 */ 126 114 public final long longValue() 127 115 { 128 return (long)doubleValue(); 116 return (long) doubleValue(); 129 117 } 130 118 … … 134 122 * casts the result of <code>doubleValue()</code> to <code>short</code>. 135 123 * 136 * @return 137 * 124 * @return the numeric value represented by this object after conversion 125 * to type <code>short</code>. 138 126 */ 139 127 public final short shortValue() 140 128 { 141 return (short)doubleValue(); 142 } 143 144 145 /** 146 * Returns the denominator. 147 */ 148 public final int getDenominator() 149 { 150 return this.denominator; 151 } 152 153 /** 154 * Returns the numerator. 155 */ 156 public final int getNumerator() 157 { 158 return this.numerator; 159 } 160 161 /** 162 * Returns the reciprocal value of this obejct as a new Rational. 129 return (short) doubleValue(); 130 } 131 132 133 /** Returns the denominator. */ 134 public final long getDenominator() 135 { 136 return this._denominator; 137 } 138 139 /** Returns the numerator. */ 140 public final long getNumerator() 141 { 142 return this._numerator; 143 } 144 145 /** 146 * Returns the reciprocal value of this object as a new Rational. 147 * 163 148 * @return the reciprocal in a new object 164 149 */ 150 @NotNull 165 151 public Rational getReciprocal() 166 152 { 167 return new Rational(this.denominator, this.numerator); 168 } 169 170 /** 171 * Checks if this rational number is an Integer, either positive or negative. 172 */ 153 return new Rational(this._denominator, this._numerator); 154 } 155 156 /** Checks if this rational number is an Integer, either positive or negative. */ 173 157 public boolean isInteger() 174 158 { 175 if (denominator == 1 || 176 (denominator != 0 && (numerator % denominator == 0)) || 177 (denominator == 0 && numerator == 0) 178 ) { 179 return true; 180 } else { 181 return false; 182 } 159 return _denominator == 1 || 160 (_denominator != 0 && (_numerator % _denominator == 0)) || 161 (_denominator == 0 && _numerator == 0); 183 162 } 184 163 185 164 /** 186 165 * Returns a string representation of the object of form <code>numerator/denominator</code>. 187 * @return a string representation of the object. 188 */ 166 * 167 * @return a string representation of the object. 168 */ 169 @NotNull 189 170 public String toString() 190 171 { 191 return numerator + "/" + denominator; 192 } 193 194 /** 195 * Returns the simplest represenation of this Rational's value possible. 196 */ 172 return _numerator + "/" + _denominator; 173 } 174 175 /** Returns the simplest representation of this Rational's value possible. */ 176 @NotNull 197 177 public String toSimpleString(boolean allowDecimal) 198 178 { 199 if (denominator == 0 && numerator != 0) { 179 if (_denominator == 0 && _numerator != 0) { 200 180 return toString(); 201 181 } else if (isInteger()) { 202 182 return Integer.toString(intValue()); 203 } else if (numerator != 1 && denominator % numerator == 0) { 183 } else if (_numerator != 1 && _denominator % _numerator == 0) { 204 184 // common factor between denominator and numerator 205 intnewDenominator = denominator / numerator;185 long newDenominator = _denominator / _numerator; 206 186 return new Rational(1, newDenominator).toSimpleString(allowDecimal); 207 187 } else { … … 220 200 * Decides whether a brute-force simplification calculation should be avoided 221 201 * by comparing the maximum number of possible calculations with some threshold. 202 * 222 203 * @return true if the simplification should be performed, otherwise false 223 204 */ 224 205 private boolean tooComplexForSimplification() 225 206 { 226 double maxPossibleCalculations = (((double)(Math.min(denominator, numerator) - 1) / 5d) + 2); 207 double maxPossibleCalculations = (((double) (Math.min(_denominator, _numerator) - 1) / 5d) + 2); 208 final int maxSimplificationCalculations = 1000; 227 209 return maxPossibleCalculations > maxSimplificationCalculations; 228 210 } … … 231 213 * Compares two <code>Rational</code> instances, returning true if they are mathematically 232 214 * equivalent. 215 * 233 216 * @param obj the Rational to compare this instance to. 234 217 * @return true if instances are mathematically equivalent, otherwise false. Will also 235 218 * return false if <code>obj</code> is not an instance of <code>Rational</code>. 236 219 */ 237 public boolean equals(Object obj) 238 { 239 if (!(obj instanceof Rational)) { 220 @Override 221 public boolean equals(@Nullable Object obj) 222 { 223 if (obj==null || !(obj instanceof Rational)) 240 224 return false; 241 } 242 Rational that = (Rational)obj; 225 Rational that = (Rational) obj; 243 226 return this.doubleValue() == that.doubleValue(); 227 } 228 229 @Override 230 public int hashCode() 231 { 232 return (23 * (int)_denominator) + (int)_numerator; 244 233 } 245 234 … … 252 241 * To reduce a rational, need to see if both numerator and denominator are divisible 253 242 * by a common factor. Using the prime number series in ascending order guarantees 254 * the minimu nnumber of checks required.</p>243 * the minimum number of checks required.</p> 255 244 * <p> 256 245 * However, generating the prime number series seems to be a hefty task. Perhaps … … 265 254 * -- * ------------------------------------ + 2 266 255 * 10 2 267 * 256 * <p/> 268 257 * Math.min(denominator, numerator) - 1 269 258 * = ------------------------------------ + 2 270 259 * 5 271 260 * </pre></code> 272 * @return a simplified instance, or if the Rational could not be simpliffied, 261 * 262 * @return a simplified instance, or if the Rational could not be simplified, 273 263 * returns itself (unchanged) 274 264 */ 265 @NotNull 275 266 public Rational getSimplifiedInstance() 276 267 { … … 278 269 return this; 279 270 } 280 for (int factor = 2; factor <= Math.min(denominator, numerator); factor++) { 271 for (int factor = 2; factor <= Math.min(_denominator, _numerator); factor++) { 281 272 if ((factor % 2 == 0 && factor > 2) || (factor % 5 == 0 && factor > 5)) { 282 273 continue; 283 274 } 284 if (denominator % factor == 0 && numerator % factor == 0) { 275 if (_denominator % factor == 0 && _numerator % factor == 0) { 285 276 // found a common factor 286 return new Rational(numerator / factor, denominator / factor); 277 return new Rational(_numerator / factor, _denominator / factor); 287 278 } 288 279 } -
trunk/src/com/drew/metadata/DefaultTagDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 22-Nov-2002 16:45:19 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata; 18 22 23 import com.drew.lang.annotations.NotNull; 24 19 25 /** 26 * A default implementation of the abstract TagDescriptor. As this class is not coded with awareness of any metadata 27 * tags, it simply reports tag names using the format 'Unknown tag 0x00' (with the corresponding tag number in hex) 28 * and gives descriptions using the default string representation of the value. 20 29 * 30 * @author Drew Noakes http://drewnoakes.com 21 31 */ 22 public class DefaultTagDescriptor extends TagDescriptor 32 public class DefaultTagDescriptor extends TagDescriptor<Directory> 23 33 { 24 public DefaultTagDescriptor(Directory directory) 34 public DefaultTagDescriptor(@NotNull Directory directory) 25 35 { 26 36 super(directory); 27 37 } 28 38 39 /** 40 * Gets a best-effort tag name using the format 'Unknown tag 0x00' (with the corresponding tag type in hex). 41 * @param tagType the tag type identifier. 42 * @return a string representation of the tag name. 43 */ 44 @NotNull 29 45 public String getTagName(int tagType) 30 46 { … … 33 49 return "Unknown tag 0x" + hex; 34 50 } 35 36 public String getDescription(int tagType)37 {38 return _directory.getString(tagType);39 }40 51 } -
trunk/src/com/drew/metadata/Directory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 25-Nov-2002 20:30:39 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata; 18 22 19 23 import com.drew.lang.Rational; 20 21 import java.io.Serializable; 24 import com.drew.lang.annotations.NotNull; 25 import com.drew.lang.annotations.Nullable; 26 import com.drew.lang.annotations.SuppressWarnings; 27 28 import java.io.UnsupportedEncodingException; 22 29 import java.lang.reflect.Array; 23 30 import java.text.DateFormat; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.Iterator; 27 import java.util.List; 31 import java.text.ParseException; 32 import java.text.SimpleDateFormat; 33 import java.util.*; 28 34 29 35 /** 30 * Base class for all Metadata directory types with supporting methods for setting and 31 * getting tag values. 36 * Abstract base class for all directory implementations, having methods for getting and setting tag values of various 37 * data types. 38 * 39 * @author Drew Noakes http://drewnoakes.com 32 40 */ 33 public abstract class Directory implements Serializable41 public abstract class Directory 34 42 { 35 /** 36 * Map of values hashed by type identifiers. 37 */ 38 protected final HashMap _tagMap; 39 40 /** 41 * The descriptor used to interperet tag values. 42 */ 43 protected TagDescriptor _descriptor; 43 // TODO get Array methods need to return cloned data, to maintain this directory's integrity 44 45 /** Map of values hashed by type identifiers. */ 46 @NotNull 47 protected final Map<Integer, Object> _tagMap = new HashMap<Integer, Object>(); 44 48 45 49 /** … … 48 52 * defined tags. 49 53 */ 50 protected final List _definedTagList; 51 52 private List _errorList; 54 @NotNull 55 protected final Collection<Tag> _definedTagList = new ArrayList<Tag>(); 56 57 @NotNull 58 private final Collection<String> _errorList = new ArrayList<String>(4); 59 60 /** The descriptor used to interpret tag values. */ 61 protected TagDescriptor _descriptor; 53 62 54 63 // ABSTRACT METHODS … … 56 65 /** 57 66 * Provides the name of the directory, for display purposes. E.g. <code>Exif</code> 67 * 58 68 * @return the name of the directory 59 69 */ 70 @NotNull 60 71 public abstract String getName(); 61 72 62 73 /** 63 74 * Provides the map of tag names, hashed by tag type identifier. 75 * 64 76 * @return the map of tag names 65 77 */ 66 protected abstract HashMap getTagNameMap(); 67 68 // CONSTRUCTORS 69 70 /** 71 * Creates a new Directory. 72 */ 73 public Directory() 74 { 75 _tagMap = new HashMap(); 76 _definedTagList = new ArrayList(); 77 } 78 @NotNull 79 protected abstract HashMap<Integer, String> getTagNameMap(); 80 81 protected Directory() 82 {} 78 83 79 84 // VARIOUS METHODS … … 81 86 /** 82 87 * Indicates whether the specified tag type has been set. 88 * 83 89 * @param tagType the tag type to check for 84 90 * @return true if a value exists for the specified tag type, false if not 85 91 */ 92 @java.lang.SuppressWarnings({ "UnnecessaryBoxing" }) 86 93 public boolean containsTag(int tagType) 87 94 { 88 return _tagMap.containsKey( newInteger(tagType));95 return _tagMap.containsKey(Integer.valueOf(tagType)); 89 96 } 90 97 91 98 /** 92 99 * Returns an Iterator of Tag instances that have been set in this Directory. 100 * 93 101 * @return an Iterator of Tag instances 94 102 */ 95 public Iterator getTagIterator() 96 { 97 return _definedTagList.iterator(); 103 @NotNull 104 public Collection<Tag> getTags() 105 { 106 return _definedTagList; 98 107 } 99 108 100 109 /** 101 110 * Returns the number of tags set in this Directory. 111 * 102 112 * @return the number of tags set in this Directory 103 113 */ … … 108 118 109 119 /** 110 * Sets the descriptor used to interperet tag values. 111 * @param descriptor the descriptor used to interperet tag values 112 */ 113 public void setDescriptor(TagDescriptor descriptor) 114 { 115 if (descriptor==null) { 120 * Sets the descriptor used to interpret tag values. 121 * 122 * @param descriptor the descriptor used to interpret tag values 123 */ 124 @java.lang.SuppressWarnings({ "ConstantConditions" }) 125 public void setDescriptor(@NotNull TagDescriptor descriptor) 126 { 127 if (descriptor == null) 116 128 throw new NullPointerException("cannot set a null descriptor"); 117 }118 129 _descriptor = descriptor; 119 130 } 120 131 121 public void addError(String message) 122 { 123 if (_errorList==null) { 124 _errorList = new ArrayList(); 125 } 132 /** 133 * Registers an error message with this directory. 134 * 135 * @param message an error message. 136 */ 137 public void addError(@NotNull String message) 138 { 126 139 _errorList.add(message); 127 140 } 128 141 142 /** 143 * Gets a value indicating whether this directory has any error messages. 144 * 145 * @return true if the directory contains errors, otherwise false 146 */ 129 147 public boolean hasErrors() 130 148 { 131 return (_errorList!=null && _errorList.size()>0); 132 } 133 134 public Iterator getErrors() 135 { 136 return _errorList.iterator(); 137 } 138 149 return _errorList.size() > 0; 150 } 151 152 /** 153 * Used to iterate over any error messages contained in this directory. 154 * 155 * @return an iterable collection of error message strings. 156 */ 157 @NotNull 158 public Iterable<String> getErrors() 159 { 160 return _errorList; 161 } 162 163 /** Returns the count of error messages in this directory. */ 139 164 public int getErrorCount() 140 165 { … … 145 170 146 171 /** 147 * Sets an int value for the specified tag. 172 * Sets an <code>int</code> value for the specified tag. 173 * 148 174 * @param tagType the tag's value as an int 149 * @param value the value for the specified tag as an int 175 * @param value the value for the specified tag as an int 150 176 */ 151 177 public void setInt(int tagType, int value) 152 178 { 153 setObject(tagType, new Integer(value)); 154 } 155 156 /** 157 * Sets a double value for the specified tag. 179 setObject(tagType, value); 180 } 181 182 /** 183 * Sets an <code>int[]</code> (array) for the specified tag. 184 * 185 * @param tagType the tag identifier 186 * @param ints the int array to store 187 */ 188 public void setIntArray(int tagType, @NotNull int[] ints) 189 { 190 setObjectArray(tagType, ints); 191 } 192 193 /** 194 * Sets a <code>float</code> value for the specified tag. 195 * 158 196 * @param tagType the tag's value as an int 159 * @param value the value for the specified tag as a double 197 * @param value the value for the specified tag as a float 198 */ 199 public void setFloat(int tagType, float value) 200 { 201 setObject(tagType, value); 202 } 203 204 /** 205 * Sets a <code>float[]</code> (array) for the specified tag. 206 * 207 * @param tagType the tag identifier 208 * @param floats the float array to store 209 */ 210 public void setFloatArray(int tagType, @NotNull float[] floats) 211 { 212 setObjectArray(tagType, floats); 213 } 214 215 /** 216 * Sets a <code>double</code> value for the specified tag. 217 * 218 * @param tagType the tag's value as an int 219 * @param value the value for the specified tag as a double 160 220 */ 161 221 public void setDouble(int tagType, double value) 162 222 { 163 setObject(tagType, new Double(value)); 164 } 165 166 /** 167 * Sets a float value for the specified tag. 223 setObject(tagType, value); 224 } 225 226 /** 227 * Sets a <code>double[]</code> (array) for the specified tag. 228 * 229 * @param tagType the tag identifier 230 * @param doubles the double array to store 231 */ 232 public void setDoubleArray(int tagType, @NotNull double[] doubles) 233 { 234 setObjectArray(tagType, doubles); 235 } 236 237 /** 238 * Sets a <code>String</code> value for the specified tag. 239 * 168 240 * @param tagType the tag's value as an int 169 * @param value the value for the specified tag as a float 170 */ 171 public void setFloat(int tagType, float value) 172 { 173 setObject(tagType, new Float(value)); 174 } 175 176 /** 177 * Sets an int value for the specified tag. 178 * @param tagType the tag's value as an int 179 * @param value the value for the specified tag as a String 180 */ 181 public void setString(int tagType, String value) 182 { 241 * @param value the value for the specified tag as a String 242 */ 243 @java.lang.SuppressWarnings({ "ConstantConditions" }) 244 public void setString(int tagType, @NotNull String value) 245 { 246 if (value == null) 247 throw new NullPointerException("cannot set a null String"); 183 248 setObject(tagType, value); 184 249 } 185 250 186 251 /** 187 * Sets an int value for the specified tag. 188 * @param tagType the tag's value as an int 189 * @param value the value for the specified tag as a boolean 190 */ 191 public void setBoolean(int tagType, boolean value) 192 { 193 setObject(tagType, new Boolean(value)); 194 } 195 196 /** 197 * Sets a long value for the specified tag. 198 * @param tagType the tag's value as an int 199 * @param value the value for the specified tag as a long 200 */ 201 public void setLong(int tagType, long value) 202 { 203 setObject(tagType, new Long(value)); 204 } 205 206 /** 207 * Sets a java.util.Date value for the specified tag. 208 * @param tagType the tag's value as an int 209 * @param value the value for the specified tag as a java.util.Date 210 */ 211 public void setDate(int tagType, java.util.Date value) 212 { 213 setObject(tagType, value); 214 } 215 216 /** 217 * Sets a Rational value for the specified tag. 218 * @param tagType the tag's value as an int 219 * @param rational rational number 220 */ 221 public void setRational(int tagType, Rational rational) 222 { 223 setObject(tagType, rational); 224 } 225 226 /** 227 * Sets a Rational array for the specified tag. 228 * @param tagType the tag identifier 229 * @param rationals the Rational array to store 230 */ 231 public void setRationalArray(int tagType, Rational[] rationals) 232 { 233 setObjectArray(tagType, rationals); 234 } 235 236 /** 237 * Sets an int array for the specified tag. 238 * @param tagType the tag identifier 239 * @param ints the int array to store 240 */ 241 public void setIntArray(int tagType, int[] ints) 242 { 243 setObjectArray(tagType, ints); 244 } 245 246 /** 247 * Sets a byte array for the specified tag. 248 * @param tagType the tag identifier 249 * @param bytes the byte array to store 250 */ 251 public void setByteArray(int tagType, byte[] bytes) 252 { 253 setObjectArray(tagType, bytes); 254 } 255 256 /** 257 * Sets a String array for the specified tag. 252 * Sets a <code>String[]</code> (array) for the specified tag. 253 * 258 254 * @param tagType the tag identifier 259 255 * @param strings the String array to store 260 256 */ 261 public void setStringArray(int tagType, String[] strings) 257 public void setStringArray(int tagType, @NotNull String[] strings) 262 258 { 263 259 setObjectArray(tagType, strings); … … 265 261 266 262 /** 267 * Private helper method, containing common functionality for all 'add'268 * methods.263 * Sets a <code>boolean</code> value for the specified tag. 264 * 269 265 * @param tagType the tag's value as an int 270 * @param value the value for the specified tag 266 * @param value the value for the specified tag as a boolean 267 */ 268 public void setBoolean(int tagType, boolean value) 269 { 270 setObject(tagType, value); 271 } 272 273 /** 274 * Sets a <code>long</code> value for the specified tag. 275 * 276 * @param tagType the tag's value as an int 277 * @param value the value for the specified tag as a long 278 */ 279 public void setLong(int tagType, long value) 280 { 281 setObject(tagType, value); 282 } 283 284 /** 285 * Sets a <code>java.util.Date</code> value for the specified tag. 286 * 287 * @param tagType the tag's value as an int 288 * @param value the value for the specified tag as a java.util.Date 289 */ 290 public void setDate(int tagType, @NotNull java.util.Date value) 291 { 292 setObject(tagType, value); 293 } 294 295 /** 296 * Sets a <code>Rational</code> value for the specified tag. 297 * 298 * @param tagType the tag's value as an int 299 * @param rational rational number 300 */ 301 public void setRational(int tagType, @NotNull Rational rational) 302 { 303 setObject(tagType, rational); 304 } 305 306 /** 307 * Sets a <code>Rational[]</code> (array) for the specified tag. 308 * 309 * @param tagType the tag identifier 310 * @param rationals the Rational array to store 311 */ 312 public void setRationalArray(int tagType, @NotNull Rational[] rationals) 313 { 314 setObjectArray(tagType, rationals); 315 } 316 317 /** 318 * Sets a <code>byte[]</code> (array) for the specified tag. 319 * 320 * @param tagType the tag identifier 321 * @param bytes the byte array to store 322 */ 323 public void setByteArray(int tagType, @NotNull byte[] bytes) 324 { 325 setObjectArray(tagType, bytes); 326 } 327 328 /** 329 * Sets a <code>Object</code> for the specified tag. 330 * 331 * @param tagType the tag's value as an int 332 * @param value the value for the specified tag 271 333 * @throws NullPointerException if value is <code>null</code> 272 334 */ 273 public void setObject(int tagType, Object value) 274 { 275 if (value==null) { 335 @java.lang.SuppressWarnings( { "ConstantConditions", "UnnecessaryBoxing" }) 336 public void setObject(int tagType, @NotNull Object value) 337 { 338 if (value == null) 276 339 throw new NullPointerException("cannot set a null object"); 277 } 278 279 Integer key = new Integer(tagType); 280 if (!_tagMap.containsKey(key)) { 340 341 if (!_tagMap.containsKey(Integer.valueOf(tagType))) { 281 342 _definedTagList.add(new Tag(tagType, this)); 282 343 } 283 _tagMap.put(key, value); 284 } 285 286 /** 287 * Private helper method, containing common functionality for all 'add...Array' 288 * methods. 344 // else { 345 // final Object oldValue = _tagMap.get(tagType); 346 // if (!oldValue.equals(value)) 347 // addError(String.format("Overwritten tag 0x%s (%s). Old=%s, New=%s", Integer.toHexString(tagType), getTagName(tagType), oldValue, value)); 348 // } 349 _tagMap.put(tagType, value); 350 } 351 352 /** 353 * Sets an array <code>Object</code> for the specified tag. 354 * 289 355 * @param tagType the tag's value as an int 290 * @param array the array of values for the specified tag 291 */ 292 public void setObjectArray(int tagType, Object array) 356 * @param array the array of values for the specified tag 357 */ 358 public void setObjectArray(int tagType, @NotNull Object array) 293 359 { 294 360 // for now, we don't do anything special -- this method might be a candidate for removal once the dust settles … … 299 365 300 366 /** 301 * Returns the specified tag's value as an int, if possible. 367 * Returns the specified tag's value as an int, if possible. Every attempt to represent the tag's value as an int 368 * is taken. Here is a list of the action taken depending upon the tag's original type: 369 * <ul> 370 * <li> int - Return unchanged. 371 * <li> Number - Return an int value (real numbers are truncated). 372 * <li> Rational - Truncate any fractional part and returns remaining int. 373 * <li> String - Attempt to parse string as an int. If this fails, convert the char[] to an int (using shifts and OR). 374 * <li> Rational[] - Return int value of first item in array. 375 * <li> byte[] - Return int value of first item in array. 376 * <li> int[] - Return int value of first item in array. 377 * </ul> 378 * 379 * @throws MetadataException if no value exists for tagType or if it cannot be converted to an int. 302 380 */ 303 381 public int getInt(int tagType) throws MetadataException 304 382 { 305 Object o = getObject(tagType); 306 if (o==null) { 307 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 308 } else if (o instanceof String) { 383 Integer integer = getInteger(tagType); 384 if (integer!=null) 385 return integer; 386 387 Object o = getObject(tagType); 388 if (o == null) 389 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 390 throw new MetadataException("Tag '" + tagType + "' cannot be converted to int. It is of type '" + o.getClass() + "'."); 391 } 392 393 /** 394 * Returns the specified tag's value as an Integer, if possible. Every attempt to represent the tag's value as an 395 * Integer is taken. Here is a list of the action taken depending upon the tag's original type: 396 * <ul> 397 * <li> int - Return unchanged 398 * <li> Number - Return an int value (real numbers are truncated) 399 * <li> Rational - Truncate any fractional part and returns remaining int 400 * <li> String - Attempt to parse string as an int. If this fails, convert the char[] to an int (using shifts and OR) 401 * <li> Rational[] - Return int value of first item in array if length > 0 402 * <li> byte[] - Return int value of first item in array if length > 0 403 * <li> int[] - Return int value of first item in array if length > 0 404 * </ul> 405 * 406 * If the value is not found or cannot be converted to int, <code>null</code> is returned. 407 */ 408 @Nullable 409 public Integer getInteger(int tagType) 410 { 411 Object o = getObject(tagType); 412 413 if (o == null) 414 return null; 415 416 if (o instanceof String) { 309 417 try { 310 418 return Integer.parseInt((String)o); … … 314 422 byte[] bytes = s.getBytes(); 315 423 long val = 0; 316 for ( int i = 0; i < bytes.length; i++) {424 for (byte aByte : bytes) { 317 425 val = val << 8; 318 val += bytes[i];426 val += (aByte & 0xff); 319 427 } 320 428 return (int)val; … … 324 432 } else if (o instanceof Rational[]) { 325 433 Rational[] rationals = (Rational[])o; 326 if (rationals.length ==1)434 if (rationals.length == 1) 327 435 return rationals[0].intValue(); 328 436 } else if (o instanceof byte[]) { 329 437 byte[] bytes = (byte[])o; 330 if (bytes.length ==1)331 return bytes[0]; 438 if (bytes.length == 1) 439 return (int)bytes[0]; 332 440 } else if (o instanceof int[]) { 333 441 int[] ints = (int[])o; 334 if (ints.length ==1)442 if (ints.length == 1) 335 443 return ints[0]; 336 444 } 337 throw new MetadataException("Tag '" + tagType + "' cannot be cast to int. It is of type '" + o.getClass() + "'."); 338 } 339 340 // TODO get Array methods need to return cloned data, to maintain this directory's integrity 445 return null; 446 } 341 447 342 448 /** 343 449 * Gets the specified tag's value as a String array, if possible. Only supported 344 450 * where the tag is set as String[], String, int[], byte[] or Rational[]. 451 * 345 452 * @param tagType the tag identifier 346 * @return the tag's value as an array of Strings 347 * @throws MetadataException if the tag has not been set or cannot be represented 348 * as a String[] 349 */ 350 public String[] getStringArray(int tagType) throws MetadataException 351 { 352 Object o = getObject(tagType); 353 if (o==null) { 354 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 355 } else if (o instanceof String[]) { 453 * @return the tag's value as an array of Strings. If the value is unset or cannot be converted, <code>null</code> is returned. 454 */ 455 @Nullable 456 public String[] getStringArray(int tagType) 457 { 458 Object o = getObject(tagType); 459 if (o == null) 460 return null; 461 if (o instanceof String[]) 356 462 return (String[])o; 357 } else if (o instanceof String) { 358 String[] strings = {(String)o}; 359 return strings; 360 } else if (o instanceof int[]) { 463 if (o instanceof String) 464 return new String[] { (String)o }; 465 if (o instanceof int[]) { 361 466 int[] ints = (int[])o; 362 467 String[] strings = new String[ints.length]; 363 for (int i = 0; i <strings.length; i++){468 for (int i = 0; i < strings.length; i++) 364 469 strings[i] = Integer.toString(ints[i]); 365 }366 470 return strings; 367 471 } else if (o instanceof byte[]) { 368 472 byte[] bytes = (byte[])o; 369 473 String[] strings = new String[bytes.length]; 370 for (int i = 0; i <strings.length; i++){474 for (int i = 0; i < strings.length; i++) 371 475 strings[i] = Byte.toString(bytes[i]); 372 }373 476 return strings; 374 477 } else if (o instanceof Rational[]) { 375 478 Rational[] rationals = (Rational[])o; 376 479 String[] strings = new String[rationals.length]; 377 for (int i = 0; i <strings.length; i++){480 for (int i = 0; i < strings.length; i++) 378 481 strings[i] = rationals[i].toSimpleString(false); 379 }380 482 return strings; 381 483 } 382 throw new MetadataException("Tag '" + tagType + "' cannot be cast to an String array. It is of type '" + o.getClass() + "'.");484 return null; 383 485 } 384 486 385 487 /** 386 488 * Gets the specified tag's value as an int array, if possible. Only supported 387 * where the tag is set as String, int[], byte[] or Rational[]. 489 * where the tag is set as String, Integer, int[], byte[] or Rational[]. 490 * 388 491 * @param tagType the tag identifier 389 492 * @return the tag's value as an int array 390 * @throws MetadataException if the tag has not been set, or cannot be converted to 391 * an int array 392 */ 393 public int[] getIntArray(int tagType) throws MetadataException 394 { 395 Object o = getObject(tagType); 396 if (o==null) { 397 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 398 } else if (o instanceof Rational[]) { 493 */ 494 @Nullable 495 public int[] getIntArray(int tagType) 496 { 497 Object o = getObject(tagType); 498 if (o == null) 499 return null; 500 if (o instanceof Rational[]) { 399 501 Rational[] rationals = (Rational[])o; 400 502 int[] ints = new int[rationals.length]; 401 for (int i = 0; i <ints.length; i++) {503 for (int i = 0; i < ints.length; i++) { 402 504 ints[i] = rationals[i].intValue(); 403 505 } 404 506 return ints; 405 } else if (o instanceof int[]) { 507 } 508 if (o instanceof int[]) 406 509 return (int[])o; 407 } elseif (o instanceof byte[]) {510 if (o instanceof byte[]) { 408 511 byte[] bytes = (byte[])o; 409 512 int[] ints = new int[bytes.length]; 410 for (int i = 0; i <bytes.length; i++) {513 for (int i = 0; i < bytes.length; i++) { 411 514 byte b = bytes[i]; 412 515 ints[i] = b; 413 516 } 414 517 return ints; 415 } else if (o instanceof String) { 416 String str = (String)o; 518 } 519 if (o instanceof CharSequence) { 520 CharSequence str = (CharSequence)o; 417 521 int[] ints = new int[str.length()]; 418 for (int i = 0; i <str.length(); i++) {522 for (int i = 0; i < str.length(); i++) { 419 523 ints[i] = str.charAt(i); 420 524 } 421 525 return ints; 422 526 } 423 throw new MetadataException("Tag '" + tagType + "' cannot be cast to an int array. It is of type '" + o.getClass() + "'."); 527 if (o instanceof Integer) 528 return new int[] { (Integer)o }; 529 530 return null; 424 531 } 425 532 426 533 /** 427 534 * Gets the specified tag's value as an byte array, if possible. Only supported 428 * where the tag is set as String, int[], byte[] or Rational[]. 535 * where the tag is set as String, Integer, int[], byte[] or Rational[]. 536 * 429 537 * @param tagType the tag identifier 430 538 * @return the tag's value as a byte array 431 * @throws MetadataException if the tag has not been set, or cannot be converted to 432 * a byte array 433 */ 434 public byte[] getByteArray(int tagType) throws MetadataException 435 { 436 Object o = getObject(tagType); 437 if (o==null) { 438 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 539 */ 540 @Nullable 541 public byte[] getByteArray(int tagType) 542 { 543 Object o = getObject(tagType); 544 if (o == null) { 545 return null; 439 546 } else if (o instanceof Rational[]) { 440 547 Rational[] rationals = (Rational[])o; 441 548 byte[] bytes = new byte[rationals.length]; 442 for (int i = 0; i <bytes.length; i++) {549 for (int i = 0; i < bytes.length; i++) { 443 550 bytes[i] = rationals[i].byteValue(); 444 551 } … … 449 556 int[] ints = (int[])o; 450 557 byte[] bytes = new byte[ints.length]; 451 for (int i = 0; i <ints.length; i++) {558 for (int i = 0; i < ints.length; i++) { 452 559 bytes[i] = (byte)ints[i]; 453 560 } 454 561 return bytes; 455 } else if (o instanceof String) {456 Stringstr = (String)o;562 } else if (o instanceof CharSequence) { 563 CharSequence str = (CharSequence)o; 457 564 byte[] bytes = new byte[str.length()]; 458 for (int i = 0; i <str.length(); i++) {565 for (int i = 0; i < str.length(); i++) { 459 566 bytes[i] = (byte)str.charAt(i); 460 567 } 461 568 return bytes; 462 569 } 463 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a byte array. It is of type '" + o.getClass() + "'."); 464 } 465 466 /** 467 * Returns the specified tag's value as a double, if possible. 468 */ 570 if (o instanceof Integer) 571 return new byte[] { ((Integer)o).byteValue() }; 572 573 return null; 574 } 575 576 /** Returns the specified tag's value as a double, if possible. */ 469 577 public double getDouble(int tagType) throws MetadataException 470 578 { 471 Object o = getObject(tagType); 472 if (o==null) { 473 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 474 } else if (o instanceof String) { 579 Double value = getDoubleObject(tagType); 580 if (value!=null) 581 return value; 582 Object o = getObject(tagType); 583 if (o == null) 584 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 585 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a double. It is of type '" + o.getClass() + "'."); 586 } 587 /** Returns the specified tag's value as a Double. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 588 @Nullable 589 public Double getDoubleObject(int tagType) 590 { 591 Object o = getObject(tagType); 592 if (o == null) 593 return null; 594 if (o instanceof String) { 475 595 try { 476 596 return Double.parseDouble((String)o); 477 597 } catch (NumberFormatException nfe) { 478 throw new MetadataException("unable to parse string " + o + " as a double", nfe); 479 } 480 } else if (o instanceof Number) { 598 return null; 599 } 600 } 601 if (o instanceof Number) 481 602 return ((Number)o).doubleValue(); 482 } 483 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a double. It is of type '" + o.getClass() + "'."); 484 } 485 486 /** 487 * Returns the specified tag's value as a float, if possible. 488 */ 603 604 return null; 605 } 606 607 /** Returns the specified tag's value as a float, if possible. */ 489 608 public float getFloat(int tagType) throws MetadataException 490 609 { 491 Object o = getObject(tagType); 492 if (o==null) { 493 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 494 } else if (o instanceof String) { 610 Float value = getFloatObject(tagType); 611 if (value!=null) 612 return value; 613 Object o = getObject(tagType); 614 if (o == null) 615 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 616 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a float. It is of type '" + o.getClass() + "'."); 617 } 618 619 /** Returns the specified tag's value as a float. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 620 @Nullable 621 public Float getFloatObject(int tagType) 622 { 623 Object o = getObject(tagType); 624 if (o == null) 625 return null; 626 if (o instanceof String) { 495 627 try { 496 628 return Float.parseFloat((String)o); 497 629 } catch (NumberFormatException nfe) { 498 throw new MetadataException("unable to parse string " + o + " as a float", nfe); 499 } 500 } else if (o instanceof Number) { 630 return null; 631 } 632 } 633 if (o instanceof Number) 501 634 return ((Number)o).floatValue(); 502 } 503 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a float. It is of type '" + o.getClass() + "'."); 504 } 505 506 /** 507 * Returns the specified tag's value as a long, if possible. 508 */ 635 return null; 636 } 637 638 /** Returns the specified tag's value as a long, if possible. */ 509 639 public long getLong(int tagType) throws MetadataException 510 640 { 511 Object o = getObject(tagType); 512 if (o==null) { 513 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 514 } else if (o instanceof String) { 641 Long value = getLongObject(tagType); 642 if (value!=null) 643 return value; 644 Object o = getObject(tagType); 645 if (o == null) 646 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 647 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a long. It is of type '" + o.getClass() + "'."); 648 } 649 650 /** Returns the specified tag's value as a long. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 651 @Nullable 652 public Long getLongObject(int tagType) 653 { 654 Object o = getObject(tagType); 655 if (o == null) 656 return null; 657 if (o instanceof String) { 515 658 try { 516 659 return Long.parseLong((String)o); 517 660 } catch (NumberFormatException nfe) { 518 throw new MetadataException("unable to parse string " + o + " as a long", nfe); 519 } 520 } else if (o instanceof Number) { 661 return null; 662 } 663 } 664 if (o instanceof Number) 521 665 return ((Number)o).longValue(); 522 } 523 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a long. It is of type '" + o.getClass() + "'."); 524 } 525 526 /** 527 * Returns the specified tag's value as a boolean, if possible. 528 */ 666 return null; 667 } 668 669 /** Returns the specified tag's value as a boolean, if possible. */ 529 670 public boolean getBoolean(int tagType) throws MetadataException 530 671 { 531 Object o = getObject(tagType); 532 if (o==null) { 533 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 534 } else if (o instanceof Boolean) { 535 return ((Boolean)o).booleanValue(); 536 } else if (o instanceof String) { 672 Boolean value = getBooleanObject(tagType); 673 if (value!=null) 674 return value; 675 Object o = getObject(tagType); 676 if (o == null) 677 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 678 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a boolean. It is of type '" + o.getClass() + "'."); 679 } 680 681 /** Returns the specified tag's value as a boolean. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 682 @Nullable 683 @SuppressWarnings(value = "NP_BOOLEAN_RETURN_NULL", justification = "keep API interface consistent") 684 public Boolean getBooleanObject(int tagType) 685 { 686 Object o = getObject(tagType); 687 if (o == null) 688 return null; 689 if (o instanceof Boolean) 690 return (Boolean)o; 691 if (o instanceof String) { 537 692 try { 538 693 return Boolean.getBoolean((String)o); 539 694 } catch (NumberFormatException nfe) { 540 throw new MetadataException("unable to parse string " + o + " as a boolean", nfe); 541 } 542 } else if (o instanceof Number) { 543 return (((Number)o).doubleValue()!=0); 544 } 545 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a boolean. It is of type '" + o.getClass() + "'."); 546 } 547 548 /** 549 * Returns the specified tag's value as a java.util.Date, if possible. 550 */ 551 public java.util.Date getDate(int tagType) throws MetadataException 552 { 553 Object o = getObject(tagType); 554 if (o==null) { 555 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 556 } else if (o instanceof java.util.Date) { 695 return null; 696 } 697 } 698 if (o instanceof Number) 699 return (((Number)o).doubleValue() != 0); 700 return null; 701 } 702 703 /** 704 * Returns the specified tag's value as a java.util.Date. If the value is unset or cannot be converted, <code>null</code> is returned. 705 * <p/> 706 * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in 707 * the current {@link TimeZone}. If the {@link TimeZone} is known, call the overload that accepts one as an argument. 708 */ 709 @Nullable 710 public java.util.Date getDate(int tagType) 711 { 712 return getDate(tagType, null); 713 } 714 715 /** 716 * Returns the specified tag's value as a java.util.Date. If the value is unset or cannot be converted, <code>null</code> is returned. 717 * <p/> 718 * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in 719 * the {@link TimeZone} represented by the {@code timeZone} parameter (if it is non-null). Note that this parameter 720 * is only considered if the underlying value is a string and parsing occurs, otherwise it has no effect. 721 */ 722 @Nullable 723 public java.util.Date getDate(int tagType, @Nullable TimeZone timeZone) 724 { 725 Object o = getObject(tagType); 726 727 if (o == null) 728 return null; 729 730 if (o instanceof java.util.Date) 557 731 return (java.util.Date)o; 558 } else if (o instanceof String) { 559 // add new dateformat strings to make this method even smarter560 // so far, this seems to cover all known date strings561 // (for example, AM and PM strings are not supported...)732 733 if (o instanceof String) { 734 // This seems to cover all known Exif date strings 735 // Note that " : : : : " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html 562 736 String datePatterns[] = { 563 "yyyy:MM:dd HH:mm:ss", 564 "yyyy:MM:dd HH:mm", 565 "yyyy-MM-dd HH:mm:ss", 566 "yyyy-MM-dd HH:mm"}; 737 "yyyy:MM:dd HH:mm:ss", 738 "yyyy:MM:dd HH:mm", 739 "yyyy-MM-dd HH:mm:ss", 740 "yyyy-MM-dd HH:mm", 741 "yyyy.MM.dd HH:mm:ss", 742 "yyyy.MM.dd HH:mm" }; 567 743 String dateString = (String)o; 568 for ( int i = 0; i<datePatterns.length; i++) {744 for (String datePattern : datePatterns) { 569 745 try { 570 DateFormat parser = new java.text.SimpleDateFormat(datePatterns[i]); 746 DateFormat parser = new SimpleDateFormat(datePattern); 747 if (timeZone != null) 748 parser.setTimeZone(timeZone); 571 749 return parser.parse(dateString); 572 } catch ( java.text.ParseException ex) {750 } catch (ParseException ex) { 573 751 // simply try the next pattern 574 752 } 575 753 } 576 754 } 577 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a java.util.Date. It is of type '" + o.getClass() + "'."); 578 } 579 580 /** 581 * Returns the specified tag's value as a Rational, if possible. 582 */ 583 public Rational getRational(int tagType) throws MetadataException 584 { 585 Object o = getObject(tagType); 586 if (o==null) { 587 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 588 } else if (o instanceof Rational) { 755 return null; 756 } 757 758 /** Returns the specified tag's value as a Rational. If the value is unset or cannot be converted, <code>null</code> is returned. */ 759 @Nullable 760 public Rational getRational(int tagType) 761 { 762 Object o = getObject(tagType); 763 764 if (o == null) 765 return null; 766 767 if (o instanceof Rational) 589 768 return (Rational)o; 590 } 591 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational. It is of type '" + o.getClass() + "'."); 592 } 593 594 public Rational[] getRationalArray(int tagType) throws MetadataException 595 { 596 Object o = getObject(tagType); 597 if (o==null) { 598 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 599 } else if (o instanceof Rational[]) { 769 if (o instanceof Integer) 770 return new Rational((Integer)o, 1); 771 if (o instanceof Long) 772 return new Rational((Long)o, 1); 773 774 // NOTE not doing conversions for real number types 775 776 return null; 777 } 778 779 /** Returns the specified tag's value as an array of Rational. If the value is unset or cannot be converted, <code>null</code> is returned. */ 780 @Nullable 781 public Rational[] getRationalArray(int tagType) 782 { 783 Object o = getObject(tagType); 784 if (o == null) 785 return null; 786 787 if (o instanceof Rational[]) 600 788 return (Rational[])o; 601 } 602 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational array. It is of type '" + o.getClass() + "'.");789 790 return null; 603 791 } 604 792 … … 606 794 * Returns the specified tag's value as a String. This value is the 'raw' value. A more presentable decoding 607 795 * of this value may be obtained from the corresponding Descriptor. 608 * @return the String reprensentation of the tag's value, or 796 * 797 * @return the String representation of the tag's value, or 609 798 * <code>null</code> if the tag hasn't been defined. 610 799 */ 800 @Nullable 611 801 public String getString(int tagType) 612 802 { 613 803 Object o = getObject(tagType); 614 if (o ==null)804 if (o == null) 615 805 return null; 616 806 … … 618 808 return ((Rational)o).toSimpleString(true); 619 809 620 if (o.getClass().isArray()) 621 { 810 if (o.getClass().isArray()) { 622 811 // handle arrays of objects and primitives 623 812 int arrayLength = Array.getLength(o); 624 // determine if this is an array of objects i.e. [Lcom.drew.blah 625 boolean isObjectArray = o.getClass().toString().startsWith("class [L"); 626 StringBuffer sbuffer = new StringBuffer(); 627 for (int i = 0; i<arrayLength; i++) 628 { 629 if (i!=0) 630 sbuffer.append(' '); 813 final Class<?> componentType = o.getClass().getComponentType(); 814 boolean isObjectArray = Object.class.isAssignableFrom(componentType); 815 boolean isFloatArray = componentType.getName().equals("float"); 816 boolean isDoubleArray = componentType.getName().equals("double"); 817 boolean isIntArray = componentType.getName().equals("int"); 818 boolean isLongArray = componentType.getName().equals("long"); 819 boolean isByteArray = componentType.getName().equals("byte"); 820 StringBuilder string = new StringBuilder(); 821 for (int i = 0; i < arrayLength; i++) { 822 if (i != 0) 823 string.append(' '); 631 824 if (isObjectArray) 632 sbuffer.append(Array.get(o, i).toString()); 825 string.append(Array.get(o, i).toString()); 826 else if (isIntArray) 827 string.append(Array.getInt(o, i)); 828 else if (isLongArray) 829 string.append(Array.getLong(o, i)); 830 else if (isFloatArray) 831 string.append(Array.getFloat(o, i)); 832 else if (isDoubleArray) 833 string.append(Array.getDouble(o, i)); 834 else if (isByteArray) 835 string.append(Array.getByte(o, i)); 633 836 else 634 sbuffer.append(Array.getInt(o, i)); 635 } 636 return sbuffer.toString(); 637 } 638 837 addError("Unexpected array component type: " + componentType.getName()); 838 } 839 return string.toString(); 840 } 841 842 // Note that several cameras leave trailing spaces (Olympus, Nikon) but this library is intended to show 843 // the actual data within the file. It is not inconceivable that whitespace may be significant here, so we 844 // do not trim. Also, if support is added for writing data back to files, this may cause issues. 845 // We leave trimming to the presentation layer. 639 846 return o.toString(); 640 847 } 641 848 849 @Nullable 850 public String getString(int tagType, String charset) 851 { 852 byte[] bytes = getByteArray(tagType); 853 if (bytes==null) 854 return null; 855 try { 856 return new String(bytes, charset); 857 } catch (UnsupportedEncodingException e) { 858 return null; 859 } 860 } 861 642 862 /** 643 863 * Returns the object hashed for the particular tag type specified, if available. 864 * 644 865 * @param tagType the tag type identifier 645 * @return the tag's value as an Object if available, else null 646 */ 866 * @return the tag's value as an Object if available, else <code>null</code> 867 */ 868 @java.lang.SuppressWarnings({ "UnnecessaryBoxing" }) 869 @Nullable 647 870 public Object getObject(int tagType) 648 871 { 649 return _tagMap.get( newInteger(tagType));872 return _tagMap.get(Integer.valueOf(tagType)); 650 873 } 651 874 … … 654 877 /** 655 878 * Returns the name of a specified tag as a String. 879 * 656 880 * @param tagType the tag type identifier 657 881 * @return the tag's name as a String 658 882 */ 883 @NotNull 659 884 public String getTagName(int tagType) 660 885 { 661 Integer key = new Integer(tagType); 662 HashMap nameMap = getTagNameMap(); 663 if (!nameMap.containsKey(key)) { 886 HashMap<Integer, String> nameMap = getTagNameMap(); 887 if (!nameMap.containsKey(tagType)) { 664 888 String hex = Integer.toHexString(tagType); 665 while (hex.length() <4) {889 while (hex.length() < 4) { 666 890 hex = "0" + hex; 667 891 } 668 892 return "Unknown tag (0x" + hex + ")"; 669 893 } 670 return (String)nameMap.get(key);894 return nameMap.get(tagType); 671 895 } 672 896 … … 674 898 * Provides a description of a tag's value using the descriptor set by 675 899 * <code>setDescriptor(Descriptor)</code>. 900 * 676 901 * @param tagType the tag type identifier 677 902 * @return the tag value's description as a String 678 * @throws MetadataException if a descriptor hasn't been set, or if an error 679 * occurs during calculation of the description within the Descriptor 680 */ 681 public String getDescription(int tagType) throws MetadataException 682 { 683 if (_descriptor==null) { 684 throw new MetadataException("a descriptor must be set using setDescriptor(...) before descriptions can be provided"); 685 } 686 903 */ 904 @Nullable 905 public String getDescription(int tagType) 906 { 907 assert(_descriptor != null); 687 908 return _descriptor.getDescription(tagType); 688 909 } -
trunk/src/com/drew/metadata/Metadata.java
r4231 r6127 1 1 /* 2 * Metadata.java2 * Copyright 2002-2012 Drew Noakes 3 3 * 4 * This class is public domain software - that is, you can do whatever you want 5 * with it, and include it software that is licensed under the GNU or the 6 * BSD license, or whatever other licence you choose, including proprietary 7 * closed source licenses. Similarly, I release this Java version under the 8 * same license, though I do ask that you leave this header in tact. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make modifications to this code that you think would benefit the 11 * wider community, please send me a copy and I'll post it on my site. 8 * http://www.apache.org/licenses/LICENSE-2.0 12 9 * 13 * If you make use of this code, I'd appreciate hearing about it. 14 * drew.noakes@drewnoakes.com 15 * Latest version of this software kept at 16 * http://drewnoakes.com/ 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 17 15 * 18 * Created on 28 April 2002, 17:40 19 * Modified 04 Aug 2002 20 * - Adjusted javadoc 21 * - Added 22 * Modified 29 Oct 2002 (v1.2) 23 * - Stored IFD directories in separate tag-spaces 24 * - iterator() now returns an Iterator over a list of TagValue objects 25 * - More get*Description() methods to detail GPS tags, among others 26 * - Put spaces between words of tag name for presentation reasons (they had no 27 * significance in compound form) 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 28 20 */ 29 21 package com.drew.metadata; 30 22 31 import java.io.Serializable; 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 25 32 26 import java.util.ArrayList; 27 import java.util.Collection; 33 28 import java.util.HashMap; 34 import java.util. Iterator;29 import java.util.Map; 35 30 36 31 /** 37 * Result from an exif extraction operation, containing all tags, their 38 * values and support for retrieving them. 39 * @author Drew Noakes http://drewnoakes.com 32 * A top-level object to hold the various types of metadata (Exif/IPTC/etc) related to one entity (such as a file 33 * or stream). 34 * <p/> 35 * Metadata objects may contain zero or more directories. Each directory may contain zero or more tags with 36 * corresponding values. 37 * 38 * @author Drew Noakes http://drewnoakes.com 40 39 */ 41 public final class Metadata implements Serializable40 public final class Metadata 42 41 { 43 /** 44 * 45 */ 46 private final HashMap directoryMap; 47 42 @NotNull 43 private final Map<Class<? extends Directory>,Directory> _directoryByClass = new HashMap<Class<? extends Directory>, Directory>(); 44 48 45 /** 49 46 * List of Directory objects set against this object. Keeping a list handy makes 50 47 * creation of an Iterator and counting tags simple. 51 48 */ 52 private final ArrayList directoryList; 49 @NotNull 50 private final Collection<Directory> _directoryList = new ArrayList<Directory>(); 53 51 54 52 /** 55 * Creates a new instance of Metadata. Package private. 53 * Returns an objects for iterating over Directory objects in the order in which they were added. 54 * 55 * @return an iterable collection of directories 56 56 */ 57 public Metadata() 57 @NotNull 58 public Iterable<Directory> getDirectories() 58 59 { 59 directoryMap = new HashMap(); 60 directoryList = new ArrayList(); 61 } 62 63 64 // OTHER METHODS 65 66 /** 67 * Creates an Iterator over the tag types set against this image, preserving the order 68 * in which they were set. Should the same tag have been set more than once, it's first 69 * position is maintained, even though the final value is used. 70 * @return an Iterator of tag types set for this image 71 */ 72 public Iterator getDirectoryIterator() 73 { 74 return directoryList.iterator(); 60 return _directoryList; 75 61 } 76 62 77 63 /** 78 64 * Returns a count of unique directories in this metadata collection. 65 * 79 66 * @return the number of unique directory types set for this metadata collection 80 67 */ 81 68 public int getDirectoryCount() 82 69 { 83 return directoryList.size(); 70 return _directoryList.size(); 84 71 } 85 72 … … 88 75 * such a directory, it is returned. Otherwise a new instance of this directory will be created and stored within 89 76 * this Metadata object. 77 * 90 78 * @param type the type of the Directory implementation required. 91 79 * @return a directory of the specified type. 92 80 */ 93 public Directory getDirectory(Class type) 81 @NotNull 82 @SuppressWarnings("unchecked") 83 public <T extends Directory> T getOrCreateDirectory(@NotNull Class<T> type) 94 84 { 95 if (!Directory.class.isAssignableFrom(type)) {96 throw new RuntimeException("Class type passed to getDirectory must be an implementation of com.drew.metadata.Directory");97 } 85 // We suppress the warning here as the code asserts a map signature of Class<T>,T. 86 // So after get(Class<T>) it is for sure the result is from type T. 87 98 88 // check if we've already issued this type of directory 99 if (directory Map.containsKey(type)){100 return ( Directory)directoryMap.get(type);101 } 102 Objectdirectory;89 if (_directoryByClass.containsKey(type)) 90 return (T)_directoryByClass.get(type); 91 92 T directory; 103 93 try { 104 94 directory = type.newInstance(); … … 106 96 throw new RuntimeException("Cannot instantiate provided Directory type: " + type.toString()); 107 97 } 108 // store the directory in case it's requested later 109 directoryMap.put(type, directory); 110 directoryList.add(directory); 111 return (Directory)directory; 98 // store the directory 99 _directoryByClass.put(type, directory); 100 _directoryList.add(directory); 101 102 return directory; 103 } 104 105 /** 106 * If this <code>Metadata</code> object contains a <code>Directory</code> of the specified type, it is returned. 107 * Otherwise <code>null</code> is returned. 108 * 109 * @param type the Directory type 110 * @param <T> the Directory type 111 * @return a Directory of type T if it exists in this Metadata object, otherwise <code>null</code>. 112 */ 113 @Nullable 114 @SuppressWarnings("unchecked") 115 public <T extends Directory> T getDirectory(@NotNull Class<T> type) 116 { 117 // We suppress the warning here as the code asserts a map signature of Class<T>,T. 118 // So after get(Class<T>) it is for sure the result is from type T. 119 120 return (T)_directoryByClass.get(type); 112 121 } 113 122 114 123 /** 115 124 * Indicates whether a given directory type has been created in this metadata 116 * repository. Directories are created by calling getDirectory(Class). 125 * repository. Directories are created by calling <code>getOrCreateDirectory(Class)</code>. 126 * 117 127 * @param type the Directory type 118 128 * @return true if the metadata directory has been created 119 129 */ 120 public boolean containsDirectory(Class type) 130 public boolean containsDirectory(Class<? extends Directory> type) 121 131 { 122 return directoryMap.containsKey(type); 132 return _directoryByClass.containsKey(type); 133 } 134 135 /** 136 * Indicates whether any errors were reported during the reading of metadata values. 137 * This value will be true if Directory.hasErrors() is true for one of the contained Directory objects. 138 * 139 * @return whether one of the contained directories has an error 140 */ 141 public boolean hasErrors() 142 { 143 for (Directory directory : _directoryList) { 144 if (directory.hasErrors()) 145 return true; 146 } 147 return false; 123 148 } 124 149 } -
trunk/src/com/drew/metadata/MetadataException.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 13-Nov-2002 18:10:23 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata; 18 22 19 23 import com.drew.lang.CompoundException; 24 import com.drew.lang.annotations.Nullable; 20 25 21 26 /** 27 * Base class for all metadata specific exceptions. 22 28 * 29 * @author Drew Noakes http://drewnoakes.com 23 30 */ 24 31 public class MetadataException extends CompoundException 25 32 { 26 public MetadataException(String msg) 33 private static final long serialVersionUID = 8612756143363919682L; 34 35 public MetadataException(@Nullable String msg) 27 36 { 28 37 super(msg); 29 38 } 30 39 31 public MetadataException(Throwable exception) 40 public MetadataException(@Nullable Throwable exception) 32 41 { 33 42 super(exception); 34 43 } 35 44 36 public MetadataException(String msg, Throwable innerException) 45 public MetadataException(@Nullable String msg, @Nullable Throwable innerException) 37 46 { 38 47 super(msg, innerException); -
trunk/src/com/drew/metadata/MetadataReader.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 26-Nov-2002 11:21:43 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata; 18 22 23 import com.drew.lang.BufferReader; 24 import com.drew.lang.annotations.NotNull; 25 19 26 /** 27 * Interface through which all classes responsible for decoding a particular type of metadata may be called. 28 * Note that the data source is not specified on this interface. Instead it is suggested that implementations 29 * take their data within a constructor. Constructors might be overloaded to allow for different sources, such as 30 * files, streams and byte arrays. As such, instances of implementations of this interface would be single-use and 31 * not thread-safe. 20 32 * 33 * @author Drew Noakes http://drewnoakes.com 21 34 */ 22 35 public interface MetadataReader 23 36 { 24 public Metadata extract(); 25 26 public Metadata extract(Metadata metadata); 37 /** 38 * Extract metadata from the source and merge it into an existing Metadata object. 39 * 40 * @param reader The reader from which the metadata should be extracted. 41 * @param metadata The Metadata object into which extracted values should be merged. 42 */ 43 public void extract(@NotNull final BufferReader reader, @NotNull final Metadata metadata); 27 44 } -
trunk/src/com/drew/metadata/Tag.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 26-Nov-2002 18:29:12 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata; 18 22 19 import java.io.Serializable; 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 20 25 21 26 /** 27 * Models a particular tag within a directory and provides methods for obtaining its value. Note that a Tag instance is 28 * specific to a particular metadata extraction and cannot be reused. 22 29 * 30 * @author Drew Noakes http://drewnoakes.com 23 31 */ 24 public class Tag implements Serializable32 public class Tag 25 33 { 26 34 private final int _tagType; 35 @NotNull 27 36 private final Directory _directory; 28 37 29 public Tag(int tagType, Directory directory) 38 public Tag(int tagType, @NotNull Directory directory) 30 39 { 31 40 _tagType = tagType; … … 35 44 /** 36 45 * Gets the tag type as an int 46 * 37 47 * @return the tag type as an int 38 48 */ … … 45 55 * Gets the tag type in hex notation as a String with padded leading 46 56 * zeroes if necessary (i.e. <code>0x100E</code>). 57 * 47 58 * @return the tag type as a string in hexadecimal notation 48 59 */ 60 @NotNull 49 61 public String getTagTypeHex() 50 62 { … … 57 69 * Get a description of the tag's value, considering enumerated values 58 70 * and units. 71 * 59 72 * @return a description of the tag's value 60 73 */ 61 public String getDescription() throws MetadataException 74 @Nullable 75 public String getDescription() 62 76 { 63 77 return _directory.getDescription(_tagType); … … 67 81 * Get the name of the tag, such as <code>Aperture</code>, or 68 82 * <code>InteropVersion</code>. 83 * 69 84 * @return the tag's name 70 85 */ 86 @NotNull 71 87 public String getTagName() 72 88 { … … 77 93 * Get the name of the directory in which the tag exists, such as 78 94 * <code>Exif</code>, <code>GPS</code> or <code>Interoperability</code>. 95 * 79 96 * @return name of the directory in which this tag exists 80 97 */ 98 @NotNull 81 99 public String getDirectoryName() 82 100 { … … 85 103 86 104 /** 87 * A basic representation of the tag's type and value in format:88 * <code>FNumber - F2.8</code>.105 * A basic representation of the tag's type and value. EG: <code>[FNumber] F2.8</code>. 106 * 89 107 * @return the tag's type and value 90 108 */ 109 @NotNull 91 110 public String toString() 92 111 { 93 String description; 94 try { 95 description = getDescription(); 96 } catch (MetadataException e) { 112 String description = getDescription(); 113 if (description==null) 97 114 description = _directory.getString(getTagType()) + " (unable to formulate description)"; 98 }99 115 return "[" + _directory.getName() + "] " + getTagName() + " - " + description; 100 116 } -
trunk/src/com/drew/metadata/TagDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata; 16 22 17 import java.io.Serializable; 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 25 26 import java.lang.reflect.Array; 18 27 19 28 /** 20 29 * Abstract base class for all tag descriptor classes. Implementations are responsible for 21 * providing the human-readable string represenation of tag values stored in a directory. 30 * providing the human-readable string representation of tag values stored in a directory. 22 31 * The directory is provided to the tag descriptor via its constructor. 32 * 33 * @author Drew Noakes http://drewnoakes.com 23 34 */ 24 public abstract class TagDescriptor implements Serializable35 public abstract class TagDescriptor<T extends Directory> 25 36 { 26 protected final Directory _directory; 37 @NotNull 38 protected final T _directory; 27 39 28 public TagDescriptor( Directorydirectory)40 public TagDescriptor(@NotNull T directory) 29 41 { 30 42 _directory = directory; … … 34 46 * Returns a descriptive value of the the specified tag for this image. 35 47 * Where possible, known values will be substituted here in place of the raw 36 * tokens actually kept in the Exif segment. If no substitution is 37 * available, the value provided by getString(int) will be returned. 38 * <p> 39 * This and getString(int) are the only 'get' methods that won't throw an 40 * exception. 48 * tokens actually kept in the metadata segment. If no substitution is 49 * available, the value provided by <code>getString(tagType)</code> will be returned. 50 * 41 51 * @param tagType the tag to find a description for 42 52 * @return a description of the image's value for the specified tag, or 43 53 * <code>null</code> if the tag hasn't been defined. 44 54 */ 45 public abstract String getDescription(int tagType) throws MetadataException; 55 @Nullable 56 public String getDescription(int tagType) 57 { 58 Object object = _directory.getObject(tagType); 59 60 if (object==null) 61 return null; 62 63 // special presentation for long arrays 64 if (object.getClass().isArray()) { 65 final int length = Array.getLength(object); 66 if (length > 16) { 67 final String componentTypeName = object.getClass().getComponentType().getName(); 68 return String.format("[%d %s%s]", length, componentTypeName, length==1 ? "" : "s"); 69 } 70 } 71 72 // no special handling required, so use default conversion to a string 73 return _directory.getString(tagType); 74 } 75 76 /** 77 * Takes a series of 4 bytes from the specified offset, and converts these to a 78 * well-known version number, where possible. 79 * <p/> 80 * Two different formats are processed: 81 * <ul> 82 * <li>[30 32 31 30] -> 2.10</li> 83 * <li>[0 1 0 0] -> 1.00</li> 84 * </ul> 85 * @param components the four version values 86 * @param majorDigits the number of components to be 87 * @return the version as a string of form "2.10" or null if the argument cannot be converted 88 */ 89 @Nullable 90 public static String convertBytesToVersionString(@Nullable int[] components, final int majorDigits) 91 { 92 if (components==null) 93 return null; 94 StringBuilder version = new StringBuilder(); 95 for (int i = 0; i < 4 && i < components.length; i++) { 96 if (i == majorDigits) 97 version.append('.'); 98 char c = (char)components[i]; 99 if (c < '0') 100 c += '0'; 101 if (i == 0 && c=='0') 102 continue; 103 version.append(c); 104 } 105 return version.toString(); 106 } 46 107 } -
trunk/src/com/drew/metadata/exif/CanonMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 19 import com.drew. metadata.Directory;20 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 21 25 import com.drew.metadata.TagDescriptor; 22 26 23 27 /** 28 * Provides human-readable string representations of tag values stored in a <code>CanonMakernoteDirectory</code>. 24 29 * 30 * @author Drew Noakes http://drewnoakes.com 25 31 */ 26 public class CanonMakernoteDescriptor extends TagDescriptor 32 public class CanonMakernoteDescriptor extends TagDescriptor<CanonMakernoteDirectory> 27 33 { 28 public CanonMakernoteDescriptor(Directory directory) 34 public CanonMakernoteDescriptor(@NotNull CanonMakernoteDirectory directory) 29 35 { 30 36 super(directory); 31 37 } 32 38 33 public String getDescription(int tagType) throws MetadataException 39 @Nullable 40 public String getDescription(int tagType) 34 41 { 35 42 switch (tagType) { 36 case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY: 43 case CanonMakernoteDirectory.TAG_CANON_SERIAL_NUMBER: 44 return getSerialNumberDescription(); 45 case CanonMakernoteDirectory.CameraSettings.TAG_FLASH_ACTIVITY: 37 46 return getFlashActivityDescription(); 38 case CanonMakernoteDirectory. TAG_CANON_STATE1_FOCUS_TYPE:47 case CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_TYPE: 39 48 return getFocusTypeDescription(); 40 case CanonMakernoteDirectory. TAG_CANON_STATE1_DIGITAL_ZOOM:49 case CanonMakernoteDirectory.CameraSettings.TAG_DIGITAL_ZOOM: 41 50 return getDigitalZoomDescription(); 42 case CanonMakernoteDirectory. TAG_CANON_STATE1_QUALITY:51 case CanonMakernoteDirectory.CameraSettings.TAG_QUALITY: 43 52 return getQualityDescription(); 44 case CanonMakernoteDirectory. TAG_CANON_STATE1_MACRO_MODE:53 case CanonMakernoteDirectory.CameraSettings.TAG_MACRO_MODE: 45 54 return getMacroModeDescription(); 46 case CanonMakernoteDirectory. TAG_CANON_STATE1_SELF_TIMER_DELAY:55 case CanonMakernoteDirectory.CameraSettings.TAG_SELF_TIMER_DELAY: 47 56 return getSelfTimerDelayDescription(); 48 case CanonMakernoteDirectory. TAG_CANON_STATE1_FLASH_MODE:57 case CanonMakernoteDirectory.CameraSettings.TAG_FLASH_MODE: 49 58 return getFlashModeDescription(); 50 case CanonMakernoteDirectory. TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE:59 case CanonMakernoteDirectory.CameraSettings.TAG_CONTINUOUS_DRIVE_MODE: 51 60 return getContinuousDriveModeDescription(); 52 case CanonMakernoteDirectory. TAG_CANON_STATE1_FOCUS_MODE_1:61 case CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_1: 53 62 return getFocusMode1Description(); 54 case CanonMakernoteDirectory. TAG_CANON_STATE1_IMAGE_SIZE:63 case CanonMakernoteDirectory.CameraSettings.TAG_IMAGE_SIZE: 55 64 return getImageSizeDescription(); 56 case CanonMakernoteDirectory. TAG_CANON_STATE1_EASY_SHOOTING_MODE:65 case CanonMakernoteDirectory.CameraSettings.TAG_EASY_SHOOTING_MODE: 57 66 return getEasyShootingModeDescription(); 58 case CanonMakernoteDirectory. TAG_CANON_STATE1_CONTRAST:67 case CanonMakernoteDirectory.CameraSettings.TAG_CONTRAST: 59 68 return getContrastDescription(); 60 case CanonMakernoteDirectory. TAG_CANON_STATE1_SATURATION:69 case CanonMakernoteDirectory.CameraSettings.TAG_SATURATION: 61 70 return getSaturationDescription(); 62 case CanonMakernoteDirectory. TAG_CANON_STATE1_SHARPNESS:71 case CanonMakernoteDirectory.CameraSettings.TAG_SHARPNESS: 63 72 return getSharpnessDescription(); 64 case CanonMakernoteDirectory. TAG_CANON_STATE1_ISO:73 case CanonMakernoteDirectory.CameraSettings.TAG_ISO: 65 74 return getIsoDescription(); 66 case CanonMakernoteDirectory. TAG_CANON_STATE1_METERING_MODE:75 case CanonMakernoteDirectory.CameraSettings.TAG_METERING_MODE: 67 76 return getMeteringModeDescription(); 68 case CanonMakernoteDirectory. TAG_CANON_STATE1_AF_POINT_SELECTED:77 case CanonMakernoteDirectory.CameraSettings.TAG_AF_POINT_SELECTED: 69 78 return getAfPointSelectedDescription(); 70 case CanonMakernoteDirectory. TAG_CANON_STATE1_EXPOSURE_MODE:79 case CanonMakernoteDirectory.CameraSettings.TAG_EXPOSURE_MODE: 71 80 return getExposureModeDescription(); 72 case CanonMakernoteDirectory. TAG_CANON_STATE1_LONG_FOCAL_LENGTH:81 case CanonMakernoteDirectory.CameraSettings.TAG_LONG_FOCAL_LENGTH: 73 82 return getLongFocalLengthDescription(); 74 case CanonMakernoteDirectory. TAG_CANON_STATE1_SHORT_FOCAL_LENGTH:83 case CanonMakernoteDirectory.CameraSettings.TAG_SHORT_FOCAL_LENGTH: 75 84 return getShortFocalLengthDescription(); 76 case CanonMakernoteDirectory. TAG_CANON_STATE1_FOCAL_UNITS_PER_MM:85 case CanonMakernoteDirectory.CameraSettings.TAG_FOCAL_UNITS_PER_MM: 77 86 return getFocalUnitsPerMillimetreDescription(); 78 case CanonMakernoteDirectory. TAG_CANON_STATE1_FLASH_DETAILS:87 case CanonMakernoteDirectory.CameraSettings.TAG_FLASH_DETAILS: 79 88 return getFlashDetailsDescription(); 80 case CanonMakernoteDirectory. TAG_CANON_STATE1_FOCUS_MODE_2:89 case CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_2: 81 90 return getFocusMode2Description(); 82 case CanonMakernoteDirectory. TAG_CANON_STATE2_WHITE_BALANCE:91 case CanonMakernoteDirectory.FocalLength.TAG_WHITE_BALANCE: 83 92 return getWhiteBalanceDescription(); 84 case CanonMakernoteDirectory. TAG_CANON_STATE2_AF_POINT_USED:93 case CanonMakernoteDirectory.FocalLength.TAG_AF_POINT_USED: 85 94 return getAfPointUsedDescription(); 86 case CanonMakernoteDirectory. TAG_CANON_STATE2_FLASH_BIAS:95 case CanonMakernoteDirectory.FocalLength.TAG_FLASH_BIAS: 87 96 return getFlashBiasDescription(); 88 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION: 89 return getLongExposureNoiseReductionDescription(); 90 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS: 91 return getShutterAutoExposureLockButtonDescription(); 92 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP: 93 return getMirrorLockupDescription(); 94 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL: 95 return getTvAndAvExposureLevelDescription(); 96 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT: 97 return getAutoFocusAssistLightDescription(); 98 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE: 99 return getShutterSpeedInAvModeDescription(); 100 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING: 101 return getAutoExposureBrackettingSequenceAndAutoCancellationDescription(); 102 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC: 103 return getShutterCurtainSyncDescription(); 104 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP: 105 return getLensAutoFocusStopButtonDescription(); 106 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION: 107 return getFillFlashReductionDescription(); 108 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN: 109 return getMenuButtonReturnPositionDescription(); 110 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION: 111 return getSetButtonFunctionWhenShootingDescription(); 112 case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING: 113 return getSensorCleaningDescription(); 114 default: 115 return _directory.getString(tagType); 116 } 117 } 118 119 public String getLongExposureNoiseReductionDescription() throws MetadataException 120 { 121 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION)) return null; 122 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION); 97 98 // It turns out that these values are dependent upon the camera model and therefore the below code was 99 // incorrect for some Canon models. This needs to be revisited. 100 101 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION: 102 // return getLongExposureNoiseReductionDescription(); 103 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS: 104 // return getShutterAutoExposureLockButtonDescription(); 105 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP: 106 // return getMirrorLockupDescription(); 107 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL: 108 // return getTvAndAvExposureLevelDescription(); 109 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT: 110 // return getAutoFocusAssistLightDescription(); 111 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE: 112 // return getShutterSpeedInAvModeDescription(); 113 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING: 114 // return getAutoExposureBrackettingSequenceAndAutoCancellationDescription(); 115 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC: 116 // return getShutterCurtainSyncDescription(); 117 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP: 118 // return getLensAutoFocusStopButtonDescription(); 119 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION: 120 // return getFillFlashReductionDescription(); 121 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN: 122 // return getMenuButtonReturnPositionDescription(); 123 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION: 124 // return getSetButtonFunctionWhenShootingDescription(); 125 // case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING: 126 // return getSensorCleaningDescription(); 127 default: 128 return super.getDescription(tagType); 129 } 130 } 131 132 @Nullable 133 public String getSerialNumberDescription() 134 { 135 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_SERIAL_NUMBER); 136 if (value==null) 137 return null; 138 return String.format("%04X%05d", (value >> 8) & 0xFF, value & 0xFF); 139 } 140 141 /* 142 @Nullable 143 public String getLongExposureNoiseReductionDescription() 144 { 145 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION); 146 if (value==null) 147 return null; 123 148 switch (value) { 124 149 case 0: return "Off"; … … 127 152 } 128 153 } 129 public String getShutterAutoExposureLockButtonDescription() throws MetadataException 130 { 131 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS)) return null; 132 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS); 154 155 @Nullable 156 public String getShutterAutoExposureLockButtonDescription() 157 { 158 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS); 159 if (value==null) 160 return null; 133 161 switch (value) { 134 162 case 0: return "AF/AE lock"; … … 139 167 } 140 168 } 141 public String getMirrorLockupDescription() throws MetadataException 142 { 143 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP)) return null; 144 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP); 169 170 @Nullable 171 public String getMirrorLockupDescription() 172 { 173 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP); 174 if (value==null) 175 return null; 145 176 switch (value) { 146 177 case 0: return "Disabled"; … … 149 180 } 150 181 } 151 public String getTvAndAvExposureLevelDescription() throws MetadataException 152 { 153 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL)) return null; 154 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL); 182 183 @Nullable 184 public String getTvAndAvExposureLevelDescription() 185 { 186 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL); 187 if (value==null) 188 return null; 155 189 switch (value) { 156 190 case 0: return "1/2 stop"; … … 159 193 } 160 194 } 161 public String getAutoFocusAssistLightDescription() throws MetadataException 162 { 163 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT)) return null; 164 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT); 195 196 @Nullable 197 public String getAutoFocusAssistLightDescription() 198 { 199 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT); 200 if (value==null) 201 return null; 165 202 switch (value) { 166 203 case 0: return "On (Auto)"; … … 169 206 } 170 207 } 171 public String getShutterSpeedInAvModeDescription() throws MetadataException 172 { 173 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE)) return null; 174 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE); 208 209 @Nullable 210 public String getShutterSpeedInAvModeDescription() 211 { 212 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE); 213 if (value==null) 214 return null; 175 215 switch (value) { 176 216 case 0: return "Automatic"; … … 179 219 } 180 220 } 181 public String getAutoExposureBrackettingSequenceAndAutoCancellationDescription() throws MetadataException 182 { 183 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING)) return null; 184 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING); 221 222 @Nullable 223 public String getAutoExposureBrackettingSequenceAndAutoCancellationDescription() 224 { 225 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING); 226 if (value==null) 227 return null; 185 228 switch (value) { 186 229 case 0: return "0,-,+ / Enabled"; … … 191 234 } 192 235 } 193 public String getShutterCurtainSyncDescription() throws MetadataException 194 { 195 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC)) return null; 196 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC); 236 237 @Nullable 238 public String getShutterCurtainSyncDescription() 239 { 240 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC); 241 if (value==null) 242 return null; 197 243 switch (value) { 198 244 case 0: return "1st Curtain Sync"; … … 201 247 } 202 248 } 203 public String getLensAutoFocusStopButtonDescription() throws MetadataException 204 { 205 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP)) return null; 206 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP); 249 250 @Nullable 251 public String getLensAutoFocusStopButtonDescription() 252 { 253 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP); 254 if (value==null) 255 return null; 207 256 switch (value) { 208 257 case 0: return "AF stop"; … … 212 261 } 213 262 } 214 public String getFillFlashReductionDescription() throws MetadataException 215 { 216 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION)) return null; 217 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION); 263 264 @Nullable 265 public String getFillFlashReductionDescription() 266 { 267 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION); 268 if (value==null) 269 return null; 218 270 switch (value) { 219 271 case 0: return "Enabled"; … … 222 274 } 223 275 } 224 public String getMenuButtonReturnPositionDescription() throws MetadataException 225 { 226 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN)) return null; 227 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN); 276 277 @Nullable 278 public String getMenuButtonReturnPositionDescription() 279 { 280 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN); 281 if (value==null) 282 return null; 228 283 switch (value) { 229 284 case 0: return "Top"; … … 233 288 } 234 289 } 235 public String getSetButtonFunctionWhenShootingDescription() throws MetadataException 236 { 237 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION)) return null; 238 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION); 290 291 @Nullable 292 public String getSetButtonFunctionWhenShootingDescription() 293 { 294 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION); 295 if (value==null) 296 return null; 239 297 switch (value) { 240 298 case 0: return "Not Assigned"; … … 245 303 } 246 304 } 247 public String getSensorCleaningDescription() throws MetadataException 248 { 249 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING)) return null; 250 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING); 305 306 @Nullable 307 public String getSensorCleaningDescription() 308 { 309 Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING); 310 if (value==null) 311 return null; 251 312 switch (value) { 252 313 case 0: return "Disabled"; … … 255 316 } 256 317 } 257 258 public String getFlashBiasDescription() throws MetadataException 259 { 260 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)) return null; 261 262 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS); 318 */ 319 320 @Nullable 321 public String getFlashBiasDescription() 322 { 323 Integer value = _directory.getInteger(CanonMakernoteDirectory.FocalLength.TAG_FLASH_BIAS); 324 325 if (value==null) 326 return null; 263 327 264 328 boolean isNegative = false; … … 278 342 } 279 343 280 public String getAfPointUsedDescription() throws MetadataException 281 { 282 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED)) return null; 283 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED); 344 @Nullable 345 public String getAfPointUsedDescription() 346 { 347 Integer value = _directory.getInteger(CanonMakernoteDirectory.FocalLength.TAG_AF_POINT_USED); 348 if (value==null) 349 return null; 284 350 if ((value & 0x7) == 0) { 285 351 return "Right"; … … 293 359 } 294 360 295 public String getWhiteBalanceDescription() throws MetadataException 296 { 297 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE)) return null; 298 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE); 361 @Nullable 362 public String getWhiteBalanceDescription() 363 { 364 Integer value = _directory.getInteger(CanonMakernoteDirectory.FocalLength.TAG_WHITE_BALANCE); 365 if (value==null) 366 return null; 299 367 switch (value) { 300 368 case 0: … … 307 375 return "Tungsten"; 308 376 case 4: 309 return "Flo urescent";377 return "Florescent"; 310 378 case 5: 311 379 return "Flash"; … … 317 385 } 318 386 319 public String getFocusMode2Description() throws MetadataException 320 { 321 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2)) return null; 322 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2); 387 @Nullable 388 public String getFocusMode2Description() 389 { 390 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_2); 391 if (value==null) 392 return null; 323 393 switch (value) { 324 394 case 0: … … 331 401 } 332 402 333 public String getFlashDetailsDescription() throws MetadataException 334 { 335 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS)) return null; 336 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS); 337 if (((value << 14) & 1) > 0) { 403 @Nullable 404 public String getFlashDetailsDescription() 405 { 406 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FLASH_DETAILS); 407 if (value==null) 408 return null; 409 if (((value >> 14) & 1) > 0) { 338 410 return "External E-TTL"; 339 411 } 340 if (((value <<13) & 1) > 0) {412 if (((value >> 13) & 1) > 0) { 341 413 return "Internal flash"; 342 414 } 343 if (((value <<11) & 1) > 0) {415 if (((value >> 11) & 1) > 0) { 344 416 return "FP sync used"; 345 417 } 346 if (((value <<4) & 1) > 0) {418 if (((value >> 4) & 1) > 0) { 347 419 return "FP sync enabled"; 348 420 } … … 350 422 } 351 423 352 public String getFocalUnitsPerMillimetreDescription() throws MetadataException 353 { 354 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM)) return ""; 355 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM); 424 @Nullable 425 public String getFocalUnitsPerMillimetreDescription() 426 { 427 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCAL_UNITS_PER_MM); 428 if (value==null) 429 return null; 356 430 if (value != 0) { 357 431 return Integer.toString(value); … … 361 435 } 362 436 363 public String getShortFocalLengthDescription() throws MetadataException 364 { 365 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH)) return null; 366 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH); 437 @Nullable 438 public String getShortFocalLengthDescription() 439 { 440 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SHORT_FOCAL_LENGTH); 441 if (value==null) 442 return null; 367 443 String units = getFocalUnitsPerMillimetreDescription(); 368 444 return Integer.toString(value) + " " + units; 369 445 } 370 446 371 public String getLongFocalLengthDescription() throws MetadataException 372 { 373 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH)) return null; 374 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH); 447 @Nullable 448 public String getLongFocalLengthDescription() 449 { 450 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_LONG_FOCAL_LENGTH); 451 if (value==null) 452 return null; 375 453 String units = getFocalUnitsPerMillimetreDescription(); 376 454 return Integer.toString(value) + " " + units; 377 455 } 378 456 379 public String getExposureModeDescription() throws MetadataException 380 { 381 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE)) return null; 382 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE); 457 @Nullable 458 public String getExposureModeDescription() 459 { 460 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_EXPOSURE_MODE); 461 if (value==null) 462 return null; 383 463 switch (value) { 384 464 case 0: … … 399 479 } 400 480 401 public String getAfPointSelectedDescription() throws MetadataException 402 { 403 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED)) return null; 404 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED); 481 @Nullable 482 public String getAfPointSelectedDescription() 483 { 484 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_AF_POINT_SELECTED); 485 if (value==null) 486 return null; 405 487 switch (value) { 406 488 case 0x3000: … … 419 501 } 420 502 421 public String getMeteringModeDescription() throws MetadataException 422 { 423 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE)) return null; 424 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE); 503 @Nullable 504 public String getMeteringModeDescription() 505 { 506 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_METERING_MODE); 507 if (value==null) 508 return null; 425 509 switch (value) { 426 510 case 3: … … 435 519 } 436 520 437 public String getIsoDescription() throws MetadataException 438 { 439 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO)) return null; 440 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO); 521 @Nullable 522 public String getIsoDescription() 523 { 524 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_ISO); 525 if (value==null) 526 return null; 527 528 // Canon PowerShot S3 is special 529 int canonMask = 0x4000; 530 if ((value & canonMask) > 0) 531 return "" + (value & ~canonMask); 532 441 533 switch (value) { 442 534 case 0: … … 457 549 } 458 550 459 public String getSharpnessDescription() throws MetadataException 460 { 461 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS)) return null; 462 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS); 551 @Nullable 552 public String getSharpnessDescription() 553 { 554 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SHARPNESS); 555 if (value==null) 556 return null; 463 557 switch (value) { 464 558 case 0xFFFF: … … 473 567 } 474 568 475 public String getSaturationDescription() throws MetadataException 476 { 477 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION)) return null; 478 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION); 569 @Nullable 570 public String getSaturationDescription() 571 { 572 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SATURATION); 573 if (value==null) 574 return null; 479 575 switch (value) { 480 576 case 0xFFFF: … … 489 585 } 490 586 491 public String getContrastDescription() throws MetadataException 492 { 493 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST)) return null; 494 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST); 587 @Nullable 588 public String getContrastDescription() 589 { 590 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_CONTRAST); 591 if (value==null) 592 return null; 495 593 switch (value) { 496 594 case 0xFFFF: … … 505 603 } 506 604 507 public String getEasyShootingModeDescription() throws MetadataException 508 { 509 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE)) return null; 510 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE); 605 @Nullable 606 public String getEasyShootingModeDescription() 607 { 608 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_EASY_SHOOTING_MODE); 609 if (value==null) 610 return null; 511 611 switch (value) { 512 612 case 0: … … 539 639 } 540 640 541 public String getImageSizeDescription() throws MetadataException 542 { 543 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE)) return null; 544 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE); 641 @Nullable 642 public String getImageSizeDescription() 643 { 644 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_IMAGE_SIZE); 645 if (value==null) 646 return null; 545 647 switch (value) { 546 648 case 0: … … 555 657 } 556 658 557 public String getFocusMode1Description() throws MetadataException 558 { 559 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1)) return null; 560 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1); 659 @Nullable 660 public String getFocusMode1Description() 661 { 662 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_1); 663 if (value==null) 664 return null; 561 665 switch (value) { 562 666 case 0: … … 580 684 } 581 685 582 public String getContinuousDriveModeDescription() throws MetadataException583 {584 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE)) return null;585 intvalue = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE);586 switch(value) {587 case 0:588 if (_directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY) == 0) {589 return "Single shot";590 } else {591 return "Single shot with self-timer";592 }686 @Nullable 687 public String getContinuousDriveModeDescription() 688 { 689 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_CONTINUOUS_DRIVE_MODE); 690 if (value==null) 691 return null; 692 switch (value) { 693 case 0: 694 final Integer delay = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SELF_TIMER_DELAY); 695 if (delay!=null) 696 return delay == 0 ? "Single shot" : "Single shot with self-timer"; 593 697 case 1: 594 698 return "Continuous"; 595 default: 596 return "Unknown (" + value + ")"; 597 } 598 } 599 600 public String getFlashModeDescription() throws MetadataException 601 { 602 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE)) return null; 603 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE); 699 } 700 return "Unknown (" + value + ")"; 701 } 702 703 @Nullable 704 public String getFlashModeDescription() 705 { 706 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FLASH_MODE); 707 if (value==null) 708 return null; 604 709 switch (value) { 605 710 case 0: … … 619 724 case 16: 620 725 // note: this value not set on Canon D30 621 return "Extenal flash"; 622 default: 623 return "Unknown (" + value + ")"; 624 } 625 } 626 627 public String getSelfTimerDelayDescription() throws MetadataException 628 { 629 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY)) return null; 630 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY); 726 return "External flash"; 727 default: 728 return "Unknown (" + value + ")"; 729 } 730 } 731 732 @Nullable 733 public String getSelfTimerDelayDescription() 734 { 735 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SELF_TIMER_DELAY); 736 if (value==null) 737 return null; 631 738 if (value == 0) { 632 739 return "Self timer not used"; … … 637 744 } 638 745 639 public String getMacroModeDescription() throws MetadataException 640 { 641 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE)) return null; 642 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE); 746 @Nullable 747 public String getMacroModeDescription() 748 { 749 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_MACRO_MODE); 750 if (value==null) 751 return null; 643 752 switch (value) { 644 753 case 1: … … 651 760 } 652 761 653 public String getQualityDescription() throws MetadataException 654 { 655 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY)) return null; 656 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY); 762 @Nullable 763 public String getQualityDescription() 764 { 765 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_QUALITY); 766 if (value==null) 767 return null; 657 768 switch (value) { 658 769 case 2: … … 667 778 } 668 779 669 public String getDigitalZoomDescription() throws MetadataException 670 { 671 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM)) return null; 672 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM); 780 @Nullable 781 public String getDigitalZoomDescription() 782 { 783 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_DIGITAL_ZOOM); 784 if (value==null) 785 return null; 673 786 switch (value) { 674 787 case 0: … … 683 796 } 684 797 685 public String getFocusTypeDescription() throws MetadataException 686 { 687 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE)) return null; 688 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE); 798 @Nullable 799 public String getFocusTypeDescription() 800 { 801 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_TYPE); 802 if (value==null) 803 return null; 689 804 switch (value) { 690 805 case 0: … … 701 816 } 702 817 703 public String getFlashActivityDescription() throws MetadataException 704 { 705 if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY)) return null; 706 int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY); 818 @Nullable 819 public String getFlashActivityDescription() 820 { 821 Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FLASH_ACTIVITY); 822 if (value==null) 823 return null; 707 824 switch (value) { 708 825 case 0: -
trunk/src/com/drew/metadata/exif/CanonMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 27 32 * 28 33 * Many tag definitions explained here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/canon_mn.html 34 * 35 * @author Drew Noakes http://drewnoakes.com 29 36 */ 30 37 public class CanonMakernoteDirectory extends Directory 31 38 { 32 // CANON cameras have some funny bespoke fields that need further processing... 33 public static final int TAG_CANON_CAMERA_STATE_1 = 0x0001; 34 public static final int TAG_CANON_CAMERA_STATE_2 = 0x0004; 35 36 public static final int TAG_CANON_IMAGE_TYPE = 0x0006; 37 public static final int TAG_CANON_FIRMWARE_VERSION = 0x0007; 38 public static final int TAG_CANON_IMAGE_NUMBER = 0x0008; 39 public static final int TAG_CANON_OWNER_NAME = 0x0009; 40 /** 41 * To display serial number as on camera use: printf( "%04X%05d", highbyte, lowbyte ) 42 * TODO handle this in CanonMakernoteDescriptor 43 */ 44 public static final int TAG_CANON_SERIAL_NUMBER = 0x000C; 45 public static final int TAG_CANON_UNKNOWN_1 = 0x000D; 46 public static final int TAG_CANON_CUSTOM_FUNCTIONS = 0x000F; 47 48 // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment 49 /** 50 * 1 = Macro 51 * 2 = Normal 52 */ 53 public static final int TAG_CANON_STATE1_MACRO_MODE = 0xC101; 54 public static final int TAG_CANON_STATE1_SELF_TIMER_DELAY = 0xC102; 55 /** 56 * 2 = Normal 57 * 3 = Fine 58 * 5 = Superfine 59 */ 60 public static final int TAG_CANON_STATE1_QUALITY = 0xC103; 61 /** 62 * 0 = Flash Not Fired 63 * 1 = Auto 64 * 2 = On 65 * 3 = Red Eye Reduction 66 * 4 = Slow Synchro 67 * 5 = Auto + Red Eye Reduction 68 * 6 = On + Red Eye Reduction 69 * 16 = External Flash 70 */ 71 public static final int TAG_CANON_STATE1_FLASH_MODE = 0xC104; 72 /** 73 * 0 = Single Frame or Timer Mode 74 * 1 = Continuous 75 */ 76 public static final int TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE = 0xC105; 77 public static final int TAG_CANON_STATE1_UNKNOWN_2 = 0xC106; 78 /** 79 * 0 = One-Shot 80 * 1 = AI Servo 81 * 2 = AI Focus 82 * 3 = Manual Focus 83 * 4 = Single 84 * 5 = Continuous 85 * 6 = Manual Focus 86 */ 87 public static final int TAG_CANON_STATE1_FOCUS_MODE_1 = 0xC107; 88 public static final int TAG_CANON_STATE1_UNKNOWN_3 = 0xC108; 89 public static final int TAG_CANON_STATE1_UNKNOWN_4 = 0xC109; 90 /** 91 * 0 = Large 92 * 1 = Medium 93 * 2 = Small 94 */ 95 public static final int TAG_CANON_STATE1_IMAGE_SIZE = 0xC10A; 96 /** 97 * 0 = Full Auto 98 * 1 = Manual 99 * 2 = Landscape 100 * 3 = Fast Shutter 101 * 4 = Slow Shutter 102 * 5 = Night 103 * 6 = Black & White 104 * 7 = Sepia 105 * 8 = Portrait 106 * 9 = Sports 107 * 10 = Macro / Close-Up 108 * 11 = Pan Focus 109 */ 110 public static final int TAG_CANON_STATE1_EASY_SHOOTING_MODE = 0xC10B; 111 /** 112 * 0 = No Digital Zoom 113 * 1 = 2x 114 * 2 = 4x 115 */ 116 public static final int TAG_CANON_STATE1_DIGITAL_ZOOM = 0xC10C; 117 /** 118 * 0 = Normal 119 * 1 = High 120 * 65535 = Low 121 */ 122 public static final int TAG_CANON_STATE1_CONTRAST = 0xC10D; 123 /** 124 * 0 = Normal 125 * 1 = High 126 * 65535 = Low 127 */ 128 public static final int TAG_CANON_STATE1_SATURATION = 0xC10E; 129 /** 130 * 0 = Normal 131 * 1 = High 132 * 65535 = Low 133 */ 134 public static final int TAG_CANON_STATE1_SHARPNESS = 0xC10F; 135 /** 136 * 0 = Check ISOSpeedRatings EXIF tag for ISO Speed 137 * 15 = Auto ISO 138 * 16 = ISO 50 139 * 17 = ISO 100 140 * 18 = ISO 200 141 * 19 = ISO 400 142 */ 143 public static final int TAG_CANON_STATE1_ISO = 0xC110; 144 /** 145 * 3 = Evaluative 146 * 4 = Partial 147 * 5 = Centre Weighted 148 */ 149 public static final int TAG_CANON_STATE1_METERING_MODE = 0xC111; 150 /** 151 * 0 = Manual 152 * 1 = Auto 153 * 3 = Close-up (Macro) 154 * 8 = Locked (Pan Mode) 155 */ 156 public static final int TAG_CANON_STATE1_FOCUS_TYPE = 0xC112; 157 /** 158 * 12288 = None (Manual Focus) 159 * 12289 = Auto Selected 160 * 12290 = Right 161 * 12291 = Centre 162 * 12292 = Left 163 */ 164 public static final int TAG_CANON_STATE1_AF_POINT_SELECTED = 0xC113; 165 /** 166 * 0 = Easy Shooting (See Easy Shooting Mode) 167 * 1 = Program 168 * 2 = Tv-Priority 169 * 3 = Av-Priority 170 * 4 = Manual 171 * 5 = A-DEP 172 */ 173 public static final int TAG_CANON_STATE1_EXPOSURE_MODE = 0xC114; 174 public static final int TAG_CANON_STATE1_UNKNOWN_7 = 0xC115; 175 public static final int TAG_CANON_STATE1_UNKNOWN_8 = 0xC116; 176 public static final int TAG_CANON_STATE1_LONG_FOCAL_LENGTH = 0xC117; 177 public static final int TAG_CANON_STATE1_SHORT_FOCAL_LENGTH = 0xC118; 178 public static final int TAG_CANON_STATE1_FOCAL_UNITS_PER_MM = 0xC119; 179 public static final int TAG_CANON_STATE1_UNKNOWN_9 = 0xC11A; 180 public static final int TAG_CANON_STATE1_UNKNOWN_10 = 0xC11B; 181 /** 182 * 0 = Flash Did Not Fire 183 * 1 = Flash Fired 184 */ 185 public static final int TAG_CANON_STATE1_FLASH_ACTIVITY = 0xC11C; 186 public static final int TAG_CANON_STATE1_FLASH_DETAILS = 0xC11D; 187 public static final int TAG_CANON_STATE1_UNKNOWN_12 = 0xC11E; 188 public static final int TAG_CANON_STATE1_UNKNOWN_13 = 0xC11F; 189 /** 190 * 0 = Focus Mode: Single 191 * 1 = Focus Mode: Continuous 192 */ 193 public static final int TAG_CANON_STATE1_FOCUS_MODE_2 = 0xC120; 194 195 /** 196 * 0 = Auto 197 * 1 = Sunny 198 * 2 = Cloudy 199 * 3 = Tungsten 200 * 4 = Flourescent 201 * 5 = Flash 202 * 6 = Custom 203 */ 204 public static final int TAG_CANON_STATE2_WHITE_BALANCE = 0xC207; 205 public static final int TAG_CANON_STATE2_SEQUENCE_NUMBER = 0xC209; 206 public static final int TAG_CANON_STATE2_AF_POINT_USED = 0xC20E; 207 /** 208 * The value of this tag may be translated into a flash bias value, in EV. 209 * 210 * 0xffc0 = -2 EV 211 * 0xffcc = -1.67 EV 212 * 0xffd0 = -1.5 EV 213 * 0xffd4 = -1.33 EV 214 * 0xffe0 = -1 EV 215 * 0xffec = -0.67 EV 216 * 0xfff0 = -0.5 EV 217 * 0xfff4 = -0.33 EV 218 * 0x0000 = 0 EV 219 * 0x000c = 0.33 EV 220 * 0x0010 = 0.5 EV 221 * 0x0014 = 0.67 EV 222 * 0x0020 = 1 EV 223 * 0x002c = 1.33 EV 224 * 0x0030 = 1.5 EV 225 * 0x0034 = 1.67 EV 226 * 0x0040 = 2 EV 227 */ 228 public static final int TAG_CANON_STATE2_FLASH_BIAS = 0xC20F; 229 public static final int TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING = 0xC210; 230 public static final int TAG_CANON_STATE2_AEB_BRACKET_VALUE = 0xC211; 231 public static final int TAG_CANON_STATE2_SUBJECT_DISTANCE = 0xC213; 232 233 /** 234 * Long Exposure Noise Reduction 235 * 0 = Off 236 * 1 = On 237 */ 238 public static final int TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION = 0xC301; 239 240 /** 241 * Shutter/Auto Exposure-lock buttons 242 * 0 = AF/AE lock 243 * 1 = AE lock/AF 244 * 2 = AF/AF lock 245 * 3 = AE+release/AE+AF 246 */ 247 public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS = 0xC302; 248 249 /** 250 * Mirror lockup 251 * 0 = Disable 252 * 1 = Enable 253 */ 254 public static final int TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP = 0xC303; 255 256 /** 257 * Tv/Av and exposure level 258 * 0 = 1/2 stop 259 * 1 = 1/3 stop 260 */ 261 public static final int TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL = 0xC304; 262 263 /** 264 * AF-assist light 265 * 0 = On (Auto) 266 * 1 = Off 267 */ 268 public static final int TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT = 0xC305; 269 270 /** 271 * Shutter speed in Av mode 272 * 0 = Automatic 273 * 1 = 1/200 (fixed) 274 */ 275 public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE = 0xC306; 276 277 /** 278 * Auto-Exposure Bracketting sequence/auto cancellation 279 * 0 = 0,-,+ / Enabled 280 * 1 = 0,-,+ / Disabled 281 * 2 = -,0,+ / Enabled 282 * 3 = -,0,+ / Disabled 283 */ 284 public static final int TAG_CANON_CUSTOM_FUNCTION_BRACKETTING = 0xC307; 285 286 /** 287 * Shutter Curtain Sync 288 * 0 = 1st Curtain Sync 289 * 1 = 2nd Curtain Sync 290 */ 291 public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC = 0xC308; 292 293 /** 294 * Lens Auto-Focus stop button Function Switch 295 * 0 = AF stop 296 * 1 = Operate AF 297 * 2 = Lock AE and start timer 298 */ 299 public static final int TAG_CANON_CUSTOM_FUNCTION_AF_STOP = 0xC309; 300 301 /** 302 * Auto reduction of fill flash 303 * 0 = Enable 304 * 1 = Disable 305 */ 306 public static final int TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION = 0xC30A; 307 308 /** 309 * Menu button return position 310 * 0 = Top 311 * 1 = Previous (volatile) 312 * 2 = Previous 313 */ 314 public static final int TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN = 0xC30B; 315 316 /** 317 * SET button function when shooting 318 * 0 = Not Assigned 319 * 1 = Change Quality 320 * 2 = Change ISO Speed 321 * 3 = Select Parameters 322 */ 323 public static final int TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION = 0xC30C; 324 325 /** 326 * Sensor cleaning 327 * 0 = Disable 328 * 1 = Enable 329 */ 330 public static final int TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING = 0xC30D; 39 // These TAG_*_ARRAY Exif tags map to arrays of int16 values which are split out into separate 'fake' tags. 40 // When an attempt is made to set one of these on the directory, it is split and the corresponding offset added to the tagType. 41 // So the resulting tag is the offset + the index into the array. 42 43 private static final int TAG_CAMERA_SETTINGS_ARRAY = 0x0001; 44 private static final int TAG_FOCAL_LENGTH_ARRAY = 0x0002; 45 private static final int TAG_SHOT_INFO_ARRAY = 0x0004; 46 private static final int TAG_PANORAMA_ARRAY = 0x0005; 47 48 public static final int TAG_CANON_IMAGE_TYPE = 0x0006; 49 public static final int TAG_CANON_FIRMWARE_VERSION = 0x0007; 50 public static final int TAG_CANON_IMAGE_NUMBER = 0x0008; 51 public static final int TAG_CANON_OWNER_NAME = 0x0009; 52 public static final int TAG_CANON_SERIAL_NUMBER = 0x000C; 53 public static final int TAG_CAMERA_INFO_ARRAY = 0x000D; // depends upon model, so leave for now 54 public static final int TAG_CANON_FILE_LENGTH = 0x000E; 55 public static final int TAG_CANON_CUSTOM_FUNCTIONS_ARRAY = 0x000F; // depends upon model, so leave for now 56 public static final int TAG_MODEL_ID = 0x0010; 57 public static final int TAG_MOVIE_INFO_ARRAY = 0x0011; // not currently decoded as not sure we see it in still images 58 private static final int TAG_AF_INFO_ARRAY = 0x0012; // not currently decoded 59 public static final int TAG_THUMBNAIL_IMAGE_VALID_AREA = 0x0013; 60 public static final int TAG_SERIAL_NUMBER_FORMAT = 0x0015; 61 public static final int TAG_SUPER_MACRO = 0x001A; 62 public static final int TAG_DATE_STAMP_MODE = 0x001C; 63 public static final int TAG_MY_COLORS = 0x001D; 64 public static final int TAG_FIRMWARE_REVISION = 0x001E; 65 public static final int TAG_CATEGORIES = 0x0023; 66 public static final int TAG_FACE_DETECT_ARRAY_1 = 0x0024; 67 public static final int TAG_FACE_DETECT_ARRAY_2 = 0x0025; 68 public static final int TAG_AF_INFO_ARRAY_2 = 0x0026; 69 public static final int TAG_IMAGE_UNIQUE_ID = 0x0028; 70 public static final int TAG_RAW_DATA_OFFSET = 0x0081; 71 public static final int TAG_ORIGINAL_DECISION_DATA_OFFSET = 0x0083; 72 public static final int TAG_CUSTOM_FUNCTIONS_1D_ARRAY = 0x0090; // not currently decoded 73 public static final int TAG_PERSONAL_FUNCTIONS_ARRAY = 0x0091; // not currently decoded 74 public static final int TAG_PERSONAL_FUNCTION_VALUES_ARRAY = 0x0092; // not currently decoded 75 public static final int TAG_FILE_INFO_ARRAY = 0x0093; // not currently decoded 76 public static final int TAG_AF_POINTS_IN_FOCUS_1D = 0x0094; 77 public static final int TAG_LENS_MODEL = 0x0095; 78 public static final int TAG_SERIAL_INFO_ARRAY = 0x0096; // not currently decoded 79 public static final int TAG_DUST_REMOVAL_DATA = 0x0097; 80 public static final int TAG_CROP_INFO = 0x0098; // not currently decoded 81 public static final int TAG_CUSTOM_FUNCTIONS_ARRAY_2 = 0x0099; // not currently decoded 82 public static final int TAG_ASPECT_INFO_ARRAY = 0x009A; // not currently decoded 83 public static final int TAG_PROCESSING_INFO_ARRAY = 0x00A0; // not currently decoded 84 public static final int TAG_TONE_CURVE_TABLE = 0x00A1; 85 public static final int TAG_SHARPNESS_TABLE = 0x00A2; 86 public static final int TAG_SHARPNESS_FREQ_TABLE = 0x00A3; 87 public static final int TAG_WHITE_BALANCE_TABLE = 0x00A4; 88 public static final int TAG_COLOR_BALANCE_ARRAY = 0x00A9; // not currently decoded 89 public static final int TAG_MEASURED_COLOR_ARRAY = 0x00AA; // not currently decoded 90 public static final int TAG_COLOR_TEMPERATURE = 0x00AE; 91 public static final int TAG_CANON_FLAGS_ARRAY = 0x00B0; // not currently decoded 92 public static final int TAG_MODIFIED_INFO_ARRAY = 0x00B1; // not currently decoded 93 public static final int TAG_TONE_CURVE_MATCHING = 0x00B2; 94 public static final int TAG_WHITE_BALANCE_MATCHING = 0x00B3; 95 public static final int TAG_COLOR_SPACE = 0x00B4; 96 public static final int TAG_PREVIEW_IMAGE_INFO_ARRAY = 0x00B6; // not currently decoded 97 public static final int TAG_VRD_OFFSET = 0x00D0; 98 public static final int TAG_SENSOR_INFO_ARRAY = 0x00E0; // not currently decoded 99 public static final int TAG_COLOR_DATA_ARRAY_2 = 0x4001; // depends upon camera model, not currently decoded 100 public static final int TAG_COLOR_INFO_ARRAY_2 = 0x4003; // not currently decoded 101 public static final int TAG_CUSTOM_PICTURE_STYLE_FILE_NAME = 0x4010; 102 public static final int TAG_COLOR_INFO_ARRAY = 0x4013; // not currently decoded 103 public static final int TAG_VIGNETTING_CORRECTION_ARRAY_1 = 0x4015; // not currently decoded 104 public static final int TAG_VIGNETTING_CORRECTION_ARRAY_2 = 0x4016; // not currently decoded 105 public static final int TAG_LIGHTING_OPTIMIZER_ARRAY = 0x4018; // not currently decoded 106 public static final int TAG_LENS_INFO_ARRAY = 0x4019; // not currently decoded 107 public static final int TAG_AMBIANCE_INFO_ARRAY = 0x4020; // not currently decoded 108 public static final int TAG_FILTER_INFO_ARRAY = 0x4024; // not currently decoded 109 110 public final static class CameraSettings 111 { 112 // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment 113 private static final int OFFSET = 0xC100; 114 115 /** 116 * 1 = Macro 117 * 2 = Normal 118 */ 119 public static final int TAG_MACRO_MODE = OFFSET + 0x01; 120 public static final int TAG_SELF_TIMER_DELAY = OFFSET + 0x02; 121 /** 122 * 2 = Normal 123 * 3 = Fine 124 * 5 = Superfine 125 */ 126 public static final int TAG_QUALITY = OFFSET + 0x03; 127 /** 128 * 0 = Flash Not Fired 129 * 1 = Auto 130 * 2 = On 131 * 3 = Red Eye Reduction 132 * 4 = Slow Synchro 133 * 5 = Auto + Red Eye Reduction 134 * 6 = On + Red Eye Reduction 135 * 16 = External Flash 136 */ 137 public static final int TAG_FLASH_MODE = OFFSET + 0x04; 138 /** 139 * 0 = Single Frame or Timer Mode 140 * 1 = Continuous 141 */ 142 public static final int TAG_CONTINUOUS_DRIVE_MODE = OFFSET + 0x05; 143 public static final int TAG_UNKNOWN_2 = OFFSET + 0x06; 144 /** 145 * 0 = One-Shot 146 * 1 = AI Servo 147 * 2 = AI Focus 148 * 3 = Manual Focus 149 * 4 = Single 150 * 5 = Continuous 151 * 6 = Manual Focus 152 */ 153 public static final int TAG_FOCUS_MODE_1 = OFFSET + 0x07; 154 public static final int TAG_UNKNOWN_3 = OFFSET + 0x08; 155 public static final int TAG_UNKNOWN_4 = OFFSET + 0x09; 156 /** 157 * 0 = Large 158 * 1 = Medium 159 * 2 = Small 160 */ 161 public static final int TAG_IMAGE_SIZE = OFFSET + 0x0A; 162 /** 163 * 0 = Full Auto 164 * 1 = Manual 165 * 2 = Landscape 166 * 3 = Fast Shutter 167 * 4 = Slow Shutter 168 * 5 = Night 169 * 6 = Black & White 170 * 7 = Sepia 171 * 8 = Portrait 172 * 9 = Sports 173 * 10 = Macro / Close-Up 174 * 11 = Pan Focus 175 */ 176 public static final int TAG_EASY_SHOOTING_MODE = OFFSET + 0x0B; 177 /** 178 * 0 = No Digital Zoom 179 * 1 = 2x 180 * 2 = 4x 181 */ 182 public static final int TAG_DIGITAL_ZOOM = OFFSET + 0x0C; 183 /** 184 * 0 = Normal 185 * 1 = High 186 * 65535 = Low 187 */ 188 public static final int TAG_CONTRAST = OFFSET + 0x0D; 189 /** 190 * 0 = Normal 191 * 1 = High 192 * 65535 = Low 193 */ 194 public static final int TAG_SATURATION = OFFSET + 0x0E; 195 /** 196 * 0 = Normal 197 * 1 = High 198 * 65535 = Low 199 */ 200 public static final int TAG_SHARPNESS = OFFSET + 0x0F; 201 /** 202 * 0 = Check ISOSpeedRatings EXIF tag for ISO Speed 203 * 15 = Auto ISO 204 * 16 = ISO 50 205 * 17 = ISO 100 206 * 18 = ISO 200 207 * 19 = ISO 400 208 */ 209 public static final int TAG_ISO = OFFSET + 0x10; 210 /** 211 * 3 = Evaluative 212 * 4 = Partial 213 * 5 = Centre Weighted 214 */ 215 public static final int TAG_METERING_MODE = OFFSET + 0x11; 216 /** 217 * 0 = Manual 218 * 1 = Auto 219 * 3 = Close-up (Macro) 220 * 8 = Locked (Pan Mode) 221 */ 222 public static final int TAG_FOCUS_TYPE = OFFSET + 0x12; 223 /** 224 * 12288 = None (Manual Focus) 225 * 12289 = Auto Selected 226 * 12290 = Right 227 * 12291 = Centre 228 * 12292 = Left 229 */ 230 public static final int TAG_AF_POINT_SELECTED = OFFSET + 0x13; 231 /** 232 * 0 = Easy Shooting (See Easy Shooting Mode) 233 * 1 = Program 234 * 2 = Tv-Priority 235 * 3 = Av-Priority 236 * 4 = Manual 237 * 5 = A-DEP 238 */ 239 public static final int TAG_EXPOSURE_MODE = OFFSET + 0x14; 240 public static final int TAG_UNKNOWN_7 = OFFSET + 0x15; 241 public static final int TAG_UNKNOWN_8 = OFFSET + 0x16; 242 public static final int TAG_LONG_FOCAL_LENGTH = OFFSET + 0x17; 243 public static final int TAG_SHORT_FOCAL_LENGTH = OFFSET + 0x18; 244 public static final int TAG_FOCAL_UNITS_PER_MM = OFFSET + 0x19; 245 public static final int TAG_UNKNOWN_9 = OFFSET + 0x1A; 246 public static final int TAG_UNKNOWN_10 = OFFSET + 0x1B; 247 /** 248 * 0 = Flash Did Not Fire 249 * 1 = Flash Fired 250 */ 251 public static final int TAG_FLASH_ACTIVITY = OFFSET + 0x1C; 252 public static final int TAG_FLASH_DETAILS = OFFSET + 0x1D; 253 public static final int TAG_UNKNOWN_12 = OFFSET + 0x1E; 254 public static final int TAG_UNKNOWN_13 = OFFSET + 0x1F; 255 /** 256 * 0 = Focus Mode: Single 257 * 1 = Focus Mode: Continuous 258 */ 259 public static final int TAG_FOCUS_MODE_2 = OFFSET + 0x20; 260 } 261 262 public final static class FocalLength 263 { 264 // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment 265 266 private static final int OFFSET = 0xC200; 267 268 /** 269 * 0 = Auto 270 * 1 = Sunny 271 * 2 = Cloudy 272 * 3 = Tungsten 273 * 4 = Florescent 274 * 5 = Flash 275 * 6 = Custom 276 */ 277 public static final int TAG_WHITE_BALANCE = OFFSET + 0x07; 278 public static final int TAG_SEQUENCE_NUMBER = OFFSET + 0x09; 279 public static final int TAG_AF_POINT_USED = OFFSET + 0x0E; 280 /** 281 * The value of this tag may be translated into a flash bias value, in EV. 282 * 283 * 0xffc0 = -2 EV 284 * 0xffcc = -1.67 EV 285 * 0xffd0 = -1.5 EV 286 * 0xffd4 = -1.33 EV 287 * 0xffe0 = -1 EV 288 * 0xffec = -0.67 EV 289 * 0xfff0 = -0.5 EV 290 * 0xfff4 = -0.33 EV 291 * 0x0000 = 0 EV 292 * 0x000c = 0.33 EV 293 * 0x0010 = 0.5 EV 294 * 0x0014 = 0.67 EV 295 * 0x0020 = 1 EV 296 * 0x002c = 1.33 EV 297 * 0x0030 = 1.5 EV 298 * 0x0034 = 1.67 EV 299 * 0x0040 = 2 EV 300 */ 301 public static final int TAG_FLASH_BIAS = OFFSET + 0x0F; 302 public static final int TAG_AUTO_EXPOSURE_BRACKETING = OFFSET + 0x10; 303 public static final int TAG_AEB_BRACKET_VALUE = OFFSET + 0x11; 304 public static final int TAG_SUBJECT_DISTANCE = OFFSET + 0x13; 305 } 306 307 public final static class ShotInfo 308 { 309 // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment 310 311 private static final int OFFSET = 0xC400; 312 313 public static final int TAG_AUTO_ISO = OFFSET + 1; 314 public static final int TAG_BASE_ISO = OFFSET + 2; 315 public static final int TAG_MEASURED_EV = OFFSET + 3; 316 public static final int TAG_TARGET_APERTURE = OFFSET + 4; 317 public static final int TAG_TARGET_EXPOSURE_TIME = OFFSET + 5; 318 public static final int TAG_EXPOSURE_COMPENSATION = OFFSET + 6; 319 public static final int TAG_WHITE_BALANCE = OFFSET + 7; 320 public static final int TAG_SLOW_SHUTTER = OFFSET + 8; 321 public static final int TAG_SEQUENCE_NUMBER = OFFSET + 9; 322 public static final int TAG_OPTICAL_ZOOM_CODE = OFFSET + 10; 323 public static final int TAG_CAMERA_TEMPERATURE = OFFSET + 12; 324 public static final int TAG_FLASH_GUIDE_NUMBER = OFFSET + 13; 325 public static final int TAG_AF_POINTS_IN_FOCUS = OFFSET + 14; 326 public static final int TAG_FLASH_EXPOSURE_BRACKETING = OFFSET + 15; 327 public static final int TAG_AUTO_EXPOSURE_BRACKETING = OFFSET + 16; 328 public static final int TAG_AEB_BRACKET_VALUE = OFFSET + 17; 329 public static final int TAG_CONTROL_MODE = OFFSET + 18; 330 public static final int TAG_FOCUS_DISTANCE_UPPER = OFFSET + 19; 331 public static final int TAG_FOCUS_DISTANCE_LOWER = OFFSET + 20; 332 public static final int TAG_F_NUMBER = OFFSET + 21; 333 public static final int TAG_EXPOSURE_TIME = OFFSET + 22; 334 public static final int TAG_MEASURED_EV_2 = OFFSET + 23; 335 public static final int TAG_BULB_DURATION = OFFSET + 24; 336 public static final int TAG_CAMERA_TYPE = OFFSET + 26; 337 public static final int TAG_AUTO_ROTATE = OFFSET + 27; 338 public static final int TAG_ND_FILTER = OFFSET + 28; 339 public static final int TAG_SELF_TIMER_2 = OFFSET + 29; 340 public static final int TAG_FLASH_OUTPUT = OFFSET + 33; 341 } 342 343 public final static class Panorama 344 { 345 // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment 346 347 private static final int OFFSET = 0xC500; 348 349 public static final int TAG_PANORAMA_FRAME_NUMBER = OFFSET + 2; 350 public static final int TAG_PANORAMA_DIRECTION = OFFSET + 5; 351 } 352 353 public final static class AFInfo 354 { 355 // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment 356 357 private static final int OFFSET = 0xD200; 358 359 public static final int TAG_NUM_AF_POINTS = OFFSET; 360 public static final int TAG_VALID_AF_POINTS = OFFSET + 1; 361 public static final int TAG_IMAGE_WIDTH = OFFSET + 2; 362 public static final int TAG_IMAGE_HEIGHT = OFFSET + 3; 363 public static final int TAG_AF_IMAGE_WIDTH = OFFSET + 4; 364 public static final int TAG_AF_IMAGE_HEIGHT = OFFSET + 5; 365 public static final int TAG_AF_AREA_WIDTH = OFFSET + 6; 366 public static final int TAG_AF_AREA_HEIGHT = OFFSET + 7; 367 public static final int TAG_AF_AREA_X_POSITIONS = OFFSET + 8; 368 public static final int TAG_AF_AREA_Y_POSITIONS = OFFSET + 9; 369 public static final int TAG_AF_POINTS_IN_FOCUS = OFFSET + 10; 370 public static final int TAG_PRIMARY_AF_POINT_1 = OFFSET + 11; 371 public static final int TAG_PRIMARY_AF_POINT_2 = OFFSET + 12; // not sure why there are two of these 372 } 373 374 // /** 375 // * Long Exposure Noise Reduction 376 // * 0 = Off 377 // * 1 = On 378 // */ 379 // public static final int TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION = 0xC301; 380 // 381 // /** 382 // * Shutter/Auto Exposure-lock buttons 383 // * 0 = AF/AE lock 384 // * 1 = AE lock/AF 385 // * 2 = AF/AF lock 386 // * 3 = AE+release/AE+AF 387 // */ 388 // public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS = 0xC302; 389 // 390 // /** 391 // * Mirror lockup 392 // * 0 = Disable 393 // * 1 = Enable 394 // */ 395 // public static final int TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP = 0xC303; 396 // 397 // /** 398 // * Tv/Av and exposure level 399 // * 0 = 1/2 stop 400 // * 1 = 1/3 stop 401 // */ 402 // public static final int TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL = 0xC304; 403 // 404 // /** 405 // * AF-assist light 406 // * 0 = On (Auto) 407 // * 1 = Off 408 // */ 409 // public static final int TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT = 0xC305; 410 // 411 // /** 412 // * Shutter speed in Av mode 413 // * 0 = Automatic 414 // * 1 = 1/200 (fixed) 415 // */ 416 // public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE = 0xC306; 417 // 418 // /** 419 // * Auto-Exposure Bracketting sequence/auto cancellation 420 // * 0 = 0,-,+ / Enabled 421 // * 1 = 0,-,+ / Disabled 422 // * 2 = -,0,+ / Enabled 423 // * 3 = -,0,+ / Disabled 424 // */ 425 // public static final int TAG_CANON_CUSTOM_FUNCTION_BRACKETTING = 0xC307; 426 // 427 // /** 428 // * Shutter Curtain Sync 429 // * 0 = 1st Curtain Sync 430 // * 1 = 2nd Curtain Sync 431 // */ 432 // public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC = 0xC308; 433 // 434 // /** 435 // * Lens Auto-Focus stop button Function Switch 436 // * 0 = AF stop 437 // * 1 = Operate AF 438 // * 2 = Lock AE and start timer 439 // */ 440 // public static final int TAG_CANON_CUSTOM_FUNCTION_AF_STOP = 0xC309; 441 // 442 // /** 443 // * Auto reduction of fill flash 444 // * 0 = Enable 445 // * 1 = Disable 446 // */ 447 // public static final int TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION = 0xC30A; 448 // 449 // /** 450 // * Menu button return position 451 // * 0 = Top 452 // * 1 = Previous (volatile) 453 // * 2 = Previous 454 // */ 455 // public static final int TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN = 0xC30B; 456 // 457 // /** 458 // * SET button function when shooting 459 // * 0 = Not Assigned 460 // * 1 = Change Quality 461 // * 2 = Change ISO Speed 462 // * 3 = Select Parameters 463 // */ 464 // public static final int TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION = 0xC30C; 465 // 466 // /** 467 // * Sensor cleaning 468 // * 0 = Disable 469 // * 1 = Enable 470 // */ 471 // public static final int TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING = 0xC30D; 331 472 332 473 // 9 A B C D E F 10 11 12 13 333 474 // 9 10 11 12 13 14 15 16 17 18 19 334 protected static final HashMap _tagNameMap = new HashMap(); 475 @NotNull 476 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 335 477 336 478 static 337 479 { 338 _tagNameMap.put(new Integer(TAG_CANON_FIRMWARE_VERSION), "Firmware Version"); 339 _tagNameMap.put(new Integer(TAG_CANON_IMAGE_NUMBER), "Image Number"); 340 _tagNameMap.put(new Integer(TAG_CANON_IMAGE_TYPE), "Image Type"); 341 _tagNameMap.put(new Integer(TAG_CANON_OWNER_NAME), "Owner Name"); 342 _tagNameMap.put(new Integer(TAG_CANON_UNKNOWN_1), "Makernote Unknown 1"); 343 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTIONS), "Custom Functions"); 344 _tagNameMap.put(new Integer(TAG_CANON_SERIAL_NUMBER), "Camera Serial Number"); 345 _tagNameMap.put(new Integer(TAG_CANON_STATE1_AF_POINT_SELECTED), "AF Point Selected"); 346 _tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE), "Continuous Drive Mode"); 347 _tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTRAST), "Contrast"); 348 _tagNameMap.put(new Integer(TAG_CANON_STATE1_EASY_SHOOTING_MODE), "Easy Shooting Mode"); 349 _tagNameMap.put(new Integer(TAG_CANON_STATE1_EXPOSURE_MODE), "Exposure Mode"); 350 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_DETAILS), "Flash Details"); 351 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_MODE), "Flash Mode"); 352 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCAL_UNITS_PER_MM), "Focal Units per mm"); 353 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_1), "Focus Mode"); 354 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_2), "Focus Mode"); 355 _tagNameMap.put(new Integer(TAG_CANON_STATE1_IMAGE_SIZE), "Image Size"); 356 _tagNameMap.put(new Integer(TAG_CANON_STATE1_ISO), "Iso"); 357 _tagNameMap.put(new Integer(TAG_CANON_STATE1_LONG_FOCAL_LENGTH), "Long Focal Length"); 358 _tagNameMap.put(new Integer(TAG_CANON_STATE1_MACRO_MODE), "Macro Mode"); 359 _tagNameMap.put(new Integer(TAG_CANON_STATE1_METERING_MODE), "Metering Mode"); 360 _tagNameMap.put(new Integer(TAG_CANON_STATE1_SATURATION), "Saturation"); 361 _tagNameMap.put(new Integer(TAG_CANON_STATE1_SELF_TIMER_DELAY), "Self Timer Delay"); 362 _tagNameMap.put(new Integer(TAG_CANON_STATE1_SHARPNESS), "Sharpness"); 363 _tagNameMap.put(new Integer(TAG_CANON_STATE1_SHORT_FOCAL_LENGTH), "Short Focal Length"); 364 _tagNameMap.put(new Integer(TAG_CANON_STATE1_QUALITY), "Quality"); 365 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_2), "Unknown Camera State 2"); 366 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_3), "Unknown Camera State 3"); 367 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_4), "Unknown Camera State 4"); 368 _tagNameMap.put(new Integer(TAG_CANON_STATE1_DIGITAL_ZOOM), "Digital Zoom"); 369 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_TYPE), "Focus Type"); 370 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_7), "Unknown Camera State 7"); 371 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_8), "Unknown Camera State 8"); 372 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_9), "Unknown Camera State 9"); 373 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_10), "Unknown Camera State 10"); 374 _tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_ACTIVITY), "Flash Activity"); 375 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_12), "Unknown Camera State 12"); 376 _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_13), "Unknown Camera State 13"); 377 _tagNameMap.put(new Integer(TAG_CANON_STATE2_WHITE_BALANCE), "White Balance"); 378 _tagNameMap.put(new Integer(TAG_CANON_STATE2_SEQUENCE_NUMBER), "Sequence Number"); 379 _tagNameMap.put(new Integer(TAG_CANON_STATE2_AF_POINT_USED), "AF Point Used"); 380 _tagNameMap.put(new Integer(TAG_CANON_STATE2_FLASH_BIAS), "Flash Bias"); 381 _tagNameMap.put(new Integer(TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING), "Auto Exposure Bracketing"); 382 _tagNameMap.put(new Integer(TAG_CANON_STATE2_AEB_BRACKET_VALUE), "AEB Bracket Value"); 383 _tagNameMap.put(new Integer(TAG_CANON_STATE2_SUBJECT_DISTANCE), "Subject Distance"); 384 385 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION), "Long Exposure Noise Reduction"); 386 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS), "Shutter/Auto Exposure-lock Buttons"); 387 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP), "Mirror Lockup"); 388 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL), "Tv/Av And Exposure Level"); 389 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT), "AF-Assist Light"); 390 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE), "Shutter Speed in Av Mode"); 391 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_BRACKETTING), "Auto-Exposure Bracketting Sequence/Auto Cancellation"); 392 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC), "Shutter Curtain Sync"); 393 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_STOP), "Lens Auto-Focus Stop Button Function Switch"); 394 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION), "Auto Reduction of Fill Flash"); 395 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN), "Menu Button Return Position"); 396 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION), "SET Button Function When Shooting"); 397 _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING), "Sensor Cleaning"); 480 _tagNameMap.put(TAG_CANON_FIRMWARE_VERSION, "Firmware Version"); 481 _tagNameMap.put(TAG_CANON_IMAGE_NUMBER, "Image Number"); 482 _tagNameMap.put(TAG_CANON_IMAGE_TYPE, "Image Type"); 483 _tagNameMap.put(TAG_CANON_OWNER_NAME, "Owner Name"); 484 _tagNameMap.put(TAG_CANON_SERIAL_NUMBER, "Camera Serial Number"); 485 _tagNameMap.put(TAG_CAMERA_INFO_ARRAY, "Camera Info Array"); 486 _tagNameMap.put(TAG_CANON_FILE_LENGTH, "File Length"); 487 _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTIONS_ARRAY, "Custom Functions"); 488 _tagNameMap.put(TAG_MODEL_ID, "Canon Model ID"); 489 _tagNameMap.put(TAG_MOVIE_INFO_ARRAY, "Movie Info Array"); 490 491 _tagNameMap.put(CameraSettings.TAG_AF_POINT_SELECTED, "AF Point Selected"); 492 _tagNameMap.put(CameraSettings.TAG_CONTINUOUS_DRIVE_MODE, "Continuous Drive Mode"); 493 _tagNameMap.put(CameraSettings.TAG_CONTRAST, "Contrast"); 494 _tagNameMap.put(CameraSettings.TAG_EASY_SHOOTING_MODE, "Easy Shooting Mode"); 495 _tagNameMap.put(CameraSettings.TAG_EXPOSURE_MODE, "Exposure Mode"); 496 _tagNameMap.put(CameraSettings.TAG_FLASH_DETAILS, "Flash Details"); 497 _tagNameMap.put(CameraSettings.TAG_FLASH_MODE, "Flash Mode"); 498 _tagNameMap.put(CameraSettings.TAG_FOCAL_UNITS_PER_MM, "Focal Units per mm"); 499 _tagNameMap.put(CameraSettings.TAG_FOCUS_MODE_1, "Focus Mode"); 500 _tagNameMap.put(CameraSettings.TAG_FOCUS_MODE_2, "Focus Mode"); 501 _tagNameMap.put(CameraSettings.TAG_IMAGE_SIZE, "Image Size"); 502 _tagNameMap.put(CameraSettings.TAG_ISO, "Iso"); 503 _tagNameMap.put(CameraSettings.TAG_LONG_FOCAL_LENGTH, "Long Focal Length"); 504 _tagNameMap.put(CameraSettings.TAG_MACRO_MODE, "Macro Mode"); 505 _tagNameMap.put(CameraSettings.TAG_METERING_MODE, "Metering Mode"); 506 _tagNameMap.put(CameraSettings.TAG_SATURATION, "Saturation"); 507 _tagNameMap.put(CameraSettings.TAG_SELF_TIMER_DELAY, "Self Timer Delay"); 508 _tagNameMap.put(CameraSettings.TAG_SHARPNESS, "Sharpness"); 509 _tagNameMap.put(CameraSettings.TAG_SHORT_FOCAL_LENGTH, "Short Focal Length"); 510 _tagNameMap.put(CameraSettings.TAG_QUALITY, "Quality"); 511 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_2, "Unknown Camera Setting 2"); 512 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_3, "Unknown Camera Setting 3"); 513 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_4, "Unknown Camera Setting 4"); 514 _tagNameMap.put(CameraSettings.TAG_DIGITAL_ZOOM, "Digital Zoom"); 515 _tagNameMap.put(CameraSettings.TAG_FOCUS_TYPE, "Focus Type"); 516 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_7, "Unknown Camera Setting 7"); 517 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_8, "Unknown Camera Setting 8"); 518 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_9, "Unknown Camera Setting 9"); 519 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_10, "Unknown Camera Setting 10"); 520 _tagNameMap.put(CameraSettings.TAG_FLASH_ACTIVITY, "Flash Activity"); 521 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_12, "Unknown Camera Setting 12"); 522 _tagNameMap.put(CameraSettings.TAG_UNKNOWN_13, "Unknown Camera Setting 13"); 523 524 _tagNameMap.put(FocalLength.TAG_WHITE_BALANCE, "White Balance"); 525 _tagNameMap.put(FocalLength.TAG_SEQUENCE_NUMBER, "Sequence Number"); 526 _tagNameMap.put(FocalLength.TAG_AF_POINT_USED, "AF Point Used"); 527 _tagNameMap.put(FocalLength.TAG_FLASH_BIAS, "Flash Bias"); 528 _tagNameMap.put(FocalLength.TAG_AUTO_EXPOSURE_BRACKETING, "Auto Exposure Bracketing"); 529 _tagNameMap.put(FocalLength.TAG_AEB_BRACKET_VALUE, "AEB Bracket Value"); 530 _tagNameMap.put(FocalLength.TAG_SUBJECT_DISTANCE, "Subject Distance"); 531 532 _tagNameMap.put(ShotInfo.TAG_AUTO_ISO, "Auto ISO"); 533 _tagNameMap.put(ShotInfo.TAG_BASE_ISO, "Base ISO"); 534 _tagNameMap.put(ShotInfo.TAG_MEASURED_EV, "Measured EV"); 535 _tagNameMap.put(ShotInfo.TAG_TARGET_APERTURE, "Target Aperture"); 536 _tagNameMap.put(ShotInfo.TAG_TARGET_EXPOSURE_TIME, "Target Exposure Time"); 537 _tagNameMap.put(ShotInfo.TAG_EXPOSURE_COMPENSATION, "Exposure Compensation"); 538 _tagNameMap.put(ShotInfo.TAG_WHITE_BALANCE, "White Balance"); 539 _tagNameMap.put(ShotInfo.TAG_SLOW_SHUTTER, "Slow Shutter"); 540 _tagNameMap.put(ShotInfo.TAG_SEQUENCE_NUMBER, "Sequence Number"); 541 _tagNameMap.put(ShotInfo.TAG_OPTICAL_ZOOM_CODE, "Optical Zoom Code"); 542 _tagNameMap.put(ShotInfo.TAG_CAMERA_TEMPERATURE, "Camera Temperature"); 543 _tagNameMap.put(ShotInfo.TAG_FLASH_GUIDE_NUMBER, "Flash Guide Number"); 544 _tagNameMap.put(ShotInfo.TAG_AF_POINTS_IN_FOCUS, "AF Points in Focus"); 545 _tagNameMap.put(ShotInfo.TAG_FLASH_EXPOSURE_BRACKETING, "Flash Exposure Compensation"); 546 _tagNameMap.put(ShotInfo.TAG_AUTO_EXPOSURE_BRACKETING, "Auto Exposure Bracketing"); 547 _tagNameMap.put(ShotInfo.TAG_AEB_BRACKET_VALUE, "AEB Bracket Value"); 548 _tagNameMap.put(ShotInfo.TAG_CONTROL_MODE, "Control Mode"); 549 _tagNameMap.put(ShotInfo.TAG_FOCUS_DISTANCE_UPPER, "Focus Distance Upper"); 550 _tagNameMap.put(ShotInfo.TAG_FOCUS_DISTANCE_LOWER, "Focus Distance Lower"); 551 _tagNameMap.put(ShotInfo.TAG_F_NUMBER, "F Number"); 552 _tagNameMap.put(ShotInfo.TAG_EXPOSURE_TIME, "Exposure Time"); 553 _tagNameMap.put(ShotInfo.TAG_MEASURED_EV_2, "Measured EV 2"); 554 _tagNameMap.put(ShotInfo.TAG_BULB_DURATION, "Bulb Duration"); 555 _tagNameMap.put(ShotInfo.TAG_CAMERA_TYPE, "Camera Type"); 556 _tagNameMap.put(ShotInfo.TAG_AUTO_ROTATE, "Auto Rotate"); 557 _tagNameMap.put(ShotInfo.TAG_ND_FILTER, "ND Filter"); 558 _tagNameMap.put(ShotInfo.TAG_SELF_TIMER_2, "Self Timer 2"); 559 _tagNameMap.put(ShotInfo.TAG_FLASH_OUTPUT, "Flash Output"); 560 561 _tagNameMap.put(Panorama.TAG_PANORAMA_FRAME_NUMBER, "Panorama Frame Number"); 562 _tagNameMap.put(Panorama.TAG_PANORAMA_DIRECTION, "Panorama Direction"); 563 564 _tagNameMap.put(AFInfo.TAG_NUM_AF_POINTS, "AF Point Count"); 565 _tagNameMap.put(AFInfo.TAG_VALID_AF_POINTS, "Valid AF Point Count"); 566 _tagNameMap.put(AFInfo.TAG_IMAGE_WIDTH, "Image Width"); 567 _tagNameMap.put(AFInfo.TAG_IMAGE_HEIGHT, "Image Height"); 568 _tagNameMap.put(AFInfo.TAG_AF_IMAGE_WIDTH, "AF Image Width"); 569 _tagNameMap.put(AFInfo.TAG_AF_IMAGE_HEIGHT, "AF Image Height"); 570 _tagNameMap.put(AFInfo.TAG_AF_AREA_WIDTH, "AF Area Width"); 571 _tagNameMap.put(AFInfo.TAG_AF_AREA_HEIGHT, "AF Area Height"); 572 _tagNameMap.put(AFInfo.TAG_AF_AREA_X_POSITIONS, "AF Area X Positions"); 573 _tagNameMap.put(AFInfo.TAG_AF_AREA_Y_POSITIONS, "AF Area Y Positions"); 574 _tagNameMap.put(AFInfo.TAG_AF_POINTS_IN_FOCUS, "AF Points in Focus Count"); 575 _tagNameMap.put(AFInfo.TAG_PRIMARY_AF_POINT_1, "Primary AF Point 1"); 576 _tagNameMap.put(AFInfo.TAG_PRIMARY_AF_POINT_2, "Primary AF Point 2"); 577 578 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION, "Long Exposure Noise Reduction"); 579 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS, "Shutter/Auto Exposure-lock Buttons"); 580 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP, "Mirror Lockup"); 581 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL, "Tv/Av And Exposure Level"); 582 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT, "AF-Assist Light"); 583 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE, "Shutter Speed in Av Mode"); 584 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_BRACKETTING, "Auto-Exposure Bracketting Sequence/Auto Cancellation"); 585 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC, "Shutter Curtain Sync"); 586 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_AF_STOP, "Lens Auto-Focus Stop Button Function Switch"); 587 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION, "Auto Reduction of Fill Flash"); 588 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN, "Menu Button Return Position"); 589 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION, "SET Button Function When Shooting"); 590 // _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING, "Sensor Cleaning"); 591 592 _tagNameMap.put(TAG_THUMBNAIL_IMAGE_VALID_AREA, "Thumbnail Image Valid Area"); 593 _tagNameMap.put(TAG_SERIAL_NUMBER_FORMAT, "Serial Number Format"); 594 _tagNameMap.put(TAG_SUPER_MACRO, "Super Macro"); 595 _tagNameMap.put(TAG_DATE_STAMP_MODE, "Date Stamp Mode"); 596 _tagNameMap.put(TAG_MY_COLORS, "My Colors"); 597 _tagNameMap.put(TAG_FIRMWARE_REVISION, "Firmware Revision"); 598 _tagNameMap.put(TAG_CATEGORIES, "Categories"); 599 _tagNameMap.put(TAG_FACE_DETECT_ARRAY_1, "Face Detect Array 1"); 600 _tagNameMap.put(TAG_FACE_DETECT_ARRAY_2, "Face Detect Array 2"); 601 _tagNameMap.put(TAG_AF_INFO_ARRAY_2, "AF Info Array 2"); 602 _tagNameMap.put(TAG_IMAGE_UNIQUE_ID, "Image Unique ID"); 603 _tagNameMap.put(TAG_RAW_DATA_OFFSET, "Raw Data Offset"); 604 _tagNameMap.put(TAG_ORIGINAL_DECISION_DATA_OFFSET, "Original Decision Data Offset"); 605 _tagNameMap.put(TAG_CUSTOM_FUNCTIONS_1D_ARRAY, "Custom Functions (1D) Array"); 606 _tagNameMap.put(TAG_PERSONAL_FUNCTIONS_ARRAY, "Personal Functions Array"); 607 _tagNameMap.put(TAG_PERSONAL_FUNCTION_VALUES_ARRAY, "Personal Function Values Array"); 608 _tagNameMap.put(TAG_FILE_INFO_ARRAY, "File Info Array"); 609 _tagNameMap.put(TAG_AF_POINTS_IN_FOCUS_1D, "AF Points in Focus (1D)"); 610 _tagNameMap.put(TAG_LENS_MODEL, "Lens Model"); 611 _tagNameMap.put(TAG_SERIAL_INFO_ARRAY, "Serial Info Array"); 612 _tagNameMap.put(TAG_DUST_REMOVAL_DATA, "Dust Removal Data"); 613 _tagNameMap.put(TAG_CROP_INFO, "Crop Info"); 614 _tagNameMap.put(TAG_CUSTOM_FUNCTIONS_ARRAY_2, "Custom Functions Array 2"); 615 _tagNameMap.put(TAG_ASPECT_INFO_ARRAY, "Aspect Information Array"); 616 _tagNameMap.put(TAG_PROCESSING_INFO_ARRAY, "Processing Information Array"); 617 _tagNameMap.put(TAG_TONE_CURVE_TABLE, "Tone Curve Table"); 618 _tagNameMap.put(TAG_SHARPNESS_TABLE, "Sharpness Table"); 619 _tagNameMap.put(TAG_SHARPNESS_FREQ_TABLE, "Sharpness Frequency Table"); 620 _tagNameMap.put(TAG_WHITE_BALANCE_TABLE, "White Balance Table"); 621 _tagNameMap.put(TAG_COLOR_BALANCE_ARRAY, "Color Balance Array"); 622 _tagNameMap.put(TAG_MEASURED_COLOR_ARRAY, "Measured Color Array"); 623 _tagNameMap.put(TAG_COLOR_TEMPERATURE, "Color Temperature"); 624 _tagNameMap.put(TAG_CANON_FLAGS_ARRAY, "Canon Flags Array"); 625 _tagNameMap.put(TAG_MODIFIED_INFO_ARRAY, "Modified Information Array"); 626 _tagNameMap.put(TAG_TONE_CURVE_MATCHING, "Tone Curve Matching"); 627 _tagNameMap.put(TAG_WHITE_BALANCE_MATCHING, "White Balance Matching"); 628 _tagNameMap.put(TAG_COLOR_SPACE, "Color Space"); 629 _tagNameMap.put(TAG_PREVIEW_IMAGE_INFO_ARRAY, "Preview Image Info Array"); 630 _tagNameMap.put(TAG_VRD_OFFSET, "VRD Offset"); 631 _tagNameMap.put(TAG_SENSOR_INFO_ARRAY, "Sensor Information Array"); 632 _tagNameMap.put(TAG_COLOR_DATA_ARRAY_2, "Color Data Array 1"); 633 _tagNameMap.put(TAG_COLOR_INFO_ARRAY_2, "Color Data Array 2"); 634 _tagNameMap.put(TAG_CUSTOM_PICTURE_STYLE_FILE_NAME, "Custom Picture Style File Name"); 635 _tagNameMap.put(TAG_COLOR_INFO_ARRAY, "Color Info Array"); 636 _tagNameMap.put(TAG_VIGNETTING_CORRECTION_ARRAY_1, "Vignetting Correction Array 1"); 637 _tagNameMap.put(TAG_VIGNETTING_CORRECTION_ARRAY_2, "Vignetting Correction Array 2"); 638 _tagNameMap.put(TAG_LIGHTING_OPTIMIZER_ARRAY, "Lighting Optimizer Array"); 639 _tagNameMap.put(TAG_LENS_INFO_ARRAY, "Lens Info Array"); 640 _tagNameMap.put(TAG_AMBIANCE_INFO_ARRAY, "Ambiance Info Array"); 641 _tagNameMap.put(TAG_FILTER_INFO_ARRAY, "Filter Info Array"); 398 642 } 399 643 … … 403 647 } 404 648 649 @NotNull 405 650 public String getName() 406 651 { … … 408 653 } 409 654 410 protected HashMap getTagNameMap() 655 @NotNull 656 protected HashMap<Integer, String> getTagNameMap() 411 657 { 412 658 return _tagNameMap; 413 659 } 414 660 415 /** 416 * We need special handling for selected tags. 417 * @param tagType 418 * @param ints 419 */ 420 public void setIntArray(int tagType, int[] ints) 421 { 422 if (tagType == TAG_CANON_CAMERA_STATE_1) { 423 // this single tag has multiple values within 424 int subTagTypeBase = 0xC100; 425 // we intentionally skip the first array member 426 for (int i = 1; i < ints.length; i++) { 427 setInt(subTagTypeBase + i, ints[i]); 428 } 429 } else if (tagType == TAG_CANON_CAMERA_STATE_2) { 430 // this single tag has multiple values within 431 int subTagTypeBase = 0xC200; 432 // we intentionally skip the first array member 433 for (int i = 1; i < ints.length; i++) { 434 setInt(subTagTypeBase + i, ints[i]); 435 } 436 } if (tagType == TAG_CANON_CUSTOM_FUNCTIONS) { 437 // this single tag has multiple values within 438 int subTagTypeBase = 0xC300; 439 // we intentionally skip the first array member 440 for (int i = 1; i < ints.length; i++) { 441 setInt(subTagTypeBase + i + 1, ints[i] & 0x0F); 442 } 443 } else { 444 // no special handling... 445 super.setIntArray(tagType, ints); 661 @Override 662 public void setIntArray(int tagType, @NotNull int[] ints) 663 { 664 // TODO is there some way to drop out 'null' or 'zero' values that are present in the array to reduce the noise? 665 666 // Certain Canon tags contain arrays of values that we split into 'fake' tags as each 667 // index in the array has its own meaning and decoding. 668 // Pick those tags out here and throw away the original array. 669 // Otherwise just add as usual. 670 switch (tagType) { 671 case TAG_CAMERA_SETTINGS_ARRAY: 672 for (int i = 0; i < ints.length; i++) 673 setInt(CameraSettings.OFFSET + i, ints[i]); 674 break; 675 case TAG_FOCAL_LENGTH_ARRAY: 676 for (int i = 0; i < ints.length; i++) 677 setInt(FocalLength.OFFSET + i, ints[i]); 678 break; 679 case TAG_SHOT_INFO_ARRAY: 680 for (int i = 0; i < ints.length; i++) 681 setInt(ShotInfo.OFFSET + i, ints[i]); 682 break; 683 case TAG_PANORAMA_ARRAY: 684 for (int i = 0; i < ints.length; i++) 685 setInt(Panorama.OFFSET + i, ints[i]); 686 break; 687 // TODO the interpretation of the custom functions tag depends upon the camera model 688 // case TAG_CANON_CUSTOM_FUNCTIONS_ARRAY: 689 // int subTagTypeBase = 0xC300; 690 // // we intentionally skip the first array member 691 // for (int i = 1; i < ints.length; i++) 692 // setInt(subTagTypeBase + i + 1, ints[i] & 0x0F); 693 // break; 694 case TAG_AF_INFO_ARRAY: 695 for (int i = 0; i < ints.length; i++) 696 setInt(AFInfo.OFFSET + i, ints[i]); 697 break; 698 default: 699 // no special handling... 700 super.setIntArray(tagType, ints); 701 break; 446 702 } 447 703 } -
trunk/src/com/drew/metadata/exif/CasioType1MakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 19 import com.drew. metadata.Directory;20 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 21 25 import com.drew.metadata.TagDescriptor; 22 26 23 27 /** 24 * 28 * Provides human-readable string representations of tag values stored in a <code>CasioType1MakernoteDirectory</code>. 29 * 30 * @author Drew Noakes http://drewnoakes.com 25 31 */ 26 public class CasioType1MakernoteDescriptor extends TagDescriptor 32 public class CasioType1MakernoteDescriptor extends TagDescriptor<CasioType1MakernoteDirectory> 27 33 { 28 public CasioType1MakernoteDescriptor(Directory directory) 34 public CasioType1MakernoteDescriptor(@NotNull CasioType1MakernoteDirectory directory) 29 35 { 30 36 super(directory); 31 37 } 32 38 33 public String getDescription(int tagType) throws MetadataException 39 @Nullable 40 public String getDescription(int tagType) 34 41 { 35 42 switch (tagType) { … … 59 66 return getCcdSensitivityDescription(); 60 67 default: 61 return _directory.getString(tagType); 62 } 63 } 64 65 public String getCcdSensitivityDescription() throws MetadataException 66 { 67 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY)) return null; 68 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY); 68 return super.getDescription(tagType); 69 } 70 } 71 72 @Nullable 73 public String getCcdSensitivityDescription() 74 { 75 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY); 76 77 if (value == null) 78 return null; 79 69 80 switch (value) { 70 81 // these four for QV3000 … … 87 98 } 88 99 89 public String getSaturationDescription() throws MetadataException 90 { 91 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION)) return null; 92 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION); 100 @Nullable 101 public String getSaturationDescription() 102 { 103 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION); 104 105 if (value == null) 106 return null; 107 93 108 switch (value) { 94 109 case 0: … … 103 118 } 104 119 105 public String getContrastDescription() throws MetadataException 106 { 107 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST)) return null; 108 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST); 120 @Nullable 121 public String getContrastDescription() 122 { 123 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST); 124 125 if (value == null) 126 return null; 127 109 128 switch (value) { 110 129 case 0: … … 119 138 } 120 139 121 public String getSharpnessDescription() throws MetadataException 122 { 123 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS)) return null; 124 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS); 140 @Nullable 141 public String getSharpnessDescription() 142 { 143 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS); 144 145 if (value == null) 146 return null; 147 125 148 switch (value) { 126 149 case 0: … … 135 158 } 136 159 137 public String getDigitalZoomDescription() throws MetadataException 138 { 139 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM)) return null; 140 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM); 160 @Nullable 161 public String getDigitalZoomDescription() 162 { 163 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM); 164 165 if (value == null) 166 return null; 167 141 168 switch (value) { 142 169 case 0x10000: … … 153 180 } 154 181 155 public String getWhiteBalanceDescription() throws MetadataException 156 { 157 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE)) return null; 158 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE); 182 @Nullable 183 public String getWhiteBalanceDescription() 184 { 185 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE); 186 187 if (value == null) 188 return null; 189 159 190 switch (value) { 160 191 case 1: … … 165 196 return "Daylight"; 166 197 case 4: 167 return "Flo urescent";198 return "Florescent"; 168 199 case 5: 169 200 return "Shade"; … … 175 206 } 176 207 177 public String getObjectDistanceDescription() throws MetadataException 178 { 179 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE)) return null; 180 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE); 208 @Nullable 209 public String getObjectDistanceDescription() 210 { 211 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE); 212 213 if (value == null) 214 return null; 215 181 216 return value + " mm"; 182 217 } 183 218 184 public String getFlashIntensityDescription() throws MetadataException 185 { 186 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY)) return null; 187 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY); 219 @Nullable 220 public String getFlashIntensityDescription() 221 { 222 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY); 223 224 if (value == null) 225 return null; 226 188 227 switch (value) { 189 228 case 11: … … 198 237 } 199 238 200 public String getFlashModeDescription() throws MetadataException 201 { 202 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE)) return null; 203 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE); 239 @Nullable 240 public String getFlashModeDescription() 241 { 242 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE); 243 244 if (value == null) 245 return null; 246 204 247 switch (value) { 205 248 case 1: … … 218 261 } 219 262 220 public String getFocusingModeDescription() throws MetadataException 221 { 222 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE)) return null; 223 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE); 263 @Nullable 264 public String getFocusingModeDescription() 265 { 266 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE); 267 268 if (value == null) 269 return null; 270 224 271 switch (value) { 225 272 case 2: … … 236 283 } 237 284 238 public String getQualityDescription() throws MetadataException 239 { 240 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY)) return null; 241 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY); 285 @Nullable 286 public String getQualityDescription() 287 { 288 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY); 289 290 if (value == null) 291 return null; 292 242 293 switch (value) { 243 294 case 1: … … 252 303 } 253 304 254 public String getRecordingModeDescription() throws MetadataException 255 { 256 if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE)) return null; 257 int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE); 305 @Nullable 306 public String getRecordingModeDescription() 307 { 308 Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE); 309 310 if (value == null) 311 return null; 312 258 313 switch (value) { 259 314 case 1: -
trunk/src/com/drew/metadata/exif/CasioType1MakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 29 * Describes tags specific to Casio (type 1) cameras. 30 * 24 31 * A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment. 25 32 * Makernote data begins immediately (no header). 33 * 34 * @author Drew Noakes http://drewnoakes.com 26 35 */ 27 36 public class CasioType1MakernoteDirectory extends Directory … … 48 57 public static final int TAG_CASIO_CCD_SENSITIVITY = 0x0014; 49 58 50 protected static final HashMap<Integer, String> tagNameMap = new HashMap<Integer, String>(); 59 @NotNull 60 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 51 61 52 62 static 53 63 { 54 tagNameMap.put (new Integer(TAG_CASIO_CCD_SENSITIVITY), "CCD Sensitivity");55 tagNameMap.put (new Integer(TAG_CASIO_CONTRAST), "Contrast");56 tagNameMap.put (new Integer(TAG_CASIO_DIGITAL_ZOOM), "Digital Zoom");57 tagNameMap.put (new Integer(TAG_CASIO_FLASH_INTENSITY), "Flash Intensity");58 tagNameMap.put (new Integer(TAG_CASIO_FLASH_MODE), "Flash Mode");59 tagNameMap.put (new Integer(TAG_CASIO_FOCUSING_MODE), "Focussing Mode");60 tagNameMap.put (new Integer(TAG_CASIO_OBJECT_DISTANCE), "Object Distance");61 tagNameMap.put (new Integer(TAG_CASIO_QUALITY), "Quality");62 tagNameMap.put (new Integer(TAG_CASIO_RECORDING_MODE), "Recording Mode");63 tagNameMap.put (new Integer(TAG_CASIO_SATURATION), "Saturation");64 tagNameMap.put (new Integer(TAG_CASIO_SHARPNESS), "Sharpness");65 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_1), "Makernote Unknown 1");66 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_2), "Makernote Unknown 2");67 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_3), "Makernote Unknown 3");68 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_4), "Makernote Unknown 4");69 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_5), "Makernote Unknown 5");70 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_6), "Makernote Unknown 6");71 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_7), "Makernote Unknown 7");72 tagNameMap.put (new Integer(TAG_CASIO_UNKNOWN_8), "Makernote Unknown 8");73 tagNameMap.put (new Integer(TAG_CASIO_WHITE_BALANCE), "White Balance");64 _tagNameMap.put(TAG_CASIO_CCD_SENSITIVITY, "CCD Sensitivity"); 65 _tagNameMap.put(TAG_CASIO_CONTRAST, "Contrast"); 66 _tagNameMap.put(TAG_CASIO_DIGITAL_ZOOM, "Digital Zoom"); 67 _tagNameMap.put(TAG_CASIO_FLASH_INTENSITY, "Flash Intensity"); 68 _tagNameMap.put(TAG_CASIO_FLASH_MODE, "Flash Mode"); 69 _tagNameMap.put(TAG_CASIO_FOCUSING_MODE, "Focusing Mode"); 70 _tagNameMap.put(TAG_CASIO_OBJECT_DISTANCE, "Object Distance"); 71 _tagNameMap.put(TAG_CASIO_QUALITY, "Quality"); 72 _tagNameMap.put(TAG_CASIO_RECORDING_MODE, "Recording Mode"); 73 _tagNameMap.put(TAG_CASIO_SATURATION, "Saturation"); 74 _tagNameMap.put(TAG_CASIO_SHARPNESS, "Sharpness"); 75 _tagNameMap.put(TAG_CASIO_UNKNOWN_1, "Makernote Unknown 1"); 76 _tagNameMap.put(TAG_CASIO_UNKNOWN_2, "Makernote Unknown 2"); 77 _tagNameMap.put(TAG_CASIO_UNKNOWN_3, "Makernote Unknown 3"); 78 _tagNameMap.put(TAG_CASIO_UNKNOWN_4, "Makernote Unknown 4"); 79 _tagNameMap.put(TAG_CASIO_UNKNOWN_5, "Makernote Unknown 5"); 80 _tagNameMap.put(TAG_CASIO_UNKNOWN_6, "Makernote Unknown 6"); 81 _tagNameMap.put(TAG_CASIO_UNKNOWN_7, "Makernote Unknown 7"); 82 _tagNameMap.put(TAG_CASIO_UNKNOWN_8, "Makernote Unknown 8"); 83 _tagNameMap.put(TAG_CASIO_WHITE_BALANCE, "White Balance"); 74 84 } 75 85 … … 79 89 } 80 90 91 @NotNull 81 92 public String getName() 82 93 { … … 84 95 } 85 96 86 protected HashMap getTagNameMap() 97 @NotNull 98 protected HashMap<Integer, String> getTagNameMap() 87 99 { 88 return tagNameMap; 100 return _tagNameMap; 89 101 } 90 102 } -
trunk/src/com/drew/metadata/exif/CasioType2MakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 19 import com.drew. metadata.Directory;20 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 21 25 import com.drew.metadata.TagDescriptor; 22 26 23 27 /** 24 * 28 * Provides human-readable string representations of tag values stored in a <code>CasioType2MakernoteDirectory</code>. 29 * 30 * @author Drew Noakes http://drewnoakes.com 25 31 */ 26 public class CasioType2MakernoteDescriptor extends TagDescriptor 32 public class CasioType2MakernoteDescriptor extends TagDescriptor<CasioType2MakernoteDirectory> 27 33 { 28 public CasioType2MakernoteDescriptor(Directory directory) 34 public CasioType2MakernoteDescriptor(@NotNull CasioType2MakernoteDirectory directory) 29 35 { 30 36 super(directory); 31 37 } 32 38 33 public String getDescription(int tagType) throws MetadataException 39 @Nullable 40 public String getDescription(int tagType) 34 41 { 35 42 switch (tagType) { … … 91 98 return getFilterDescription(); 92 99 default: 93 return _directory.getString(tagType); 94 } 95 } 96 97 public String getFilterDescription() throws MetadataException 98 { 99 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER)) return null; 100 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER); 101 switch (value) { 102 case 0: 103 return "Off"; 104 default: 105 return "Unknown (" + value + ")"; 106 } 107 } 108 109 public String getEnhancementDescription() throws MetadataException 110 { 111 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT)) return null; 112 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT); 113 switch (value) { 114 case 0: 115 return "Off"; 116 default: 117 return "Unknown (" + value + ")"; 118 } 119 } 120 121 public String getColourModeDescription() throws MetadataException 122 { 123 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE)) return null; 124 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE); 125 switch (value) { 126 case 0: 127 return "Off"; 128 default: 129 return "Unknown (" + value + ")"; 130 } 131 } 132 133 public String getCcdIsoSensitivityDescription() throws MetadataException 134 { 135 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY)) return null; 136 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY); 100 return super.getDescription(tagType); 101 } 102 } 103 104 @Nullable 105 public String getFilterDescription() 106 { 107 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER); 108 if (value==null) 109 return null; 110 switch (value) { 111 case 0: 112 return "Off"; 113 default: 114 return "Unknown (" + value + ")"; 115 } 116 } 117 118 @Nullable 119 public String getEnhancementDescription() 120 { 121 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT); 122 if (value==null) 123 return null; 124 switch (value) { 125 case 0: 126 return "Off"; 127 default: 128 return "Unknown (" + value + ")"; 129 } 130 } 131 132 @Nullable 133 public String getColourModeDescription() 134 { 135 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE); 136 if (value==null) 137 return null; 138 switch (value) { 139 case 0: 140 return "Off"; 141 default: 142 return "Unknown (" + value + ")"; 143 } 144 } 145 146 @Nullable 147 public String getCcdIsoSensitivityDescription() 148 { 149 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY); 150 if (value==null) 151 return null; 137 152 switch (value) { 138 153 case 0: … … 145 160 } 146 161 147 public String getBestShotModeDescription() throws MetadataException 148 { 149 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE)) return null; 150 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE); 151 switch (value) { 152 default: 153 return "Unknown (" + value + ")"; 154 } 155 } 156 162 @Nullable 163 public String getBestShotModeDescription() 164 { 165 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE); 166 if (value==null) 167 return null; 168 switch (value) { 169 default: 170 return "Unknown (" + value + ")"; 171 } 172 } 173 174 @Nullable 157 175 public String getTimeZoneDescription() 158 176 { 159 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE)) return null;160 177 return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE); 161 178 } 162 179 163 public String getFocusMode2Description() throws MetadataException 164 { 165 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2)) return null; 166 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2); 180 @Nullable 181 public String getFocusMode2Description() 182 { 183 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2); 184 if (value==null) 185 return null; 167 186 switch (value) { 168 187 case 1: … … 175 194 } 176 195 177 public String getQualityDescription() throws MetadataException 178 { 179 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY)) return null; 180 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY); 196 @Nullable 197 public String getQualityDescription() 198 { 199 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY); 200 if (value==null) 201 return null; 181 202 switch (value) { 182 203 case 3: … … 187 208 } 188 209 189 public String getSelfTimerDescription() throws MetadataException 190 { 191 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER)) return null; 192 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER); 193 switch (value) { 194 case 1: 195 return "Off"; 196 default: 197 return "Unknown (" + value + ")"; 198 } 199 } 200 201 public String getRecordModeDescription() throws MetadataException 202 { 203 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE)) return null; 204 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE); 210 @Nullable 211 public String getSelfTimerDescription() 212 { 213 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER); 214 if (value==null) 215 return null; 216 switch (value) { 217 case 1: 218 return "Off"; 219 default: 220 return "Unknown (" + value + ")"; 221 } 222 } 223 224 @Nullable 225 public String getRecordModeDescription() 226 { 227 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE); 228 if (value==null) 229 return null; 205 230 switch (value) { 206 231 case 2: … … 211 236 } 212 237 213 public String getFlashDistanceDescription() throws MetadataException 214 { 215 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE)) return null; 216 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE); 217 switch (value) { 218 case 0: 219 return "Off"; 220 default: 221 return "Unknown (" + value + ")"; 222 } 223 } 224 225 public String getObjectDistanceDescription() throws MetadataException 226 { 227 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE)) return null; 228 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE); 238 @Nullable 239 public String getFlashDistanceDescription() 240 { 241 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE); 242 if (value==null) 243 return null; 244 switch (value) { 245 case 0: 246 return "Off"; 247 default: 248 return "Unknown (" + value + ")"; 249 } 250 } 251 252 @Nullable 253 public String getObjectDistanceDescription() 254 { 255 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE); 256 if (value==null) 257 return null; 229 258 return Integer.toString(value) + " mm"; 230 259 } 231 260 232 public String getWhiteBalance2Description() throws MetadataException 233 { 234 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2)) return null; 235 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2); 261 @Nullable 262 public String getWhiteBalance2Description() 263 { 264 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2); 265 if (value==null) 266 return null; 236 267 switch (value) { 237 268 case 0: … … 248 279 } 249 280 281 @Nullable 250 282 public String getWhiteBalanceBiasDescription() 251 283 { 252 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS)) return null;253 284 return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS); 254 285 } 255 286 256 public String getCasioPreviewThumbnailDescription() throws MetadataException257 {258 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL)) return null;287 @Nullable 288 public String getCasioPreviewThumbnailDescription() 289 { 259 290 final byte[] bytes = _directory.getByteArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL); 291 if (bytes==null) 292 return null; 260 293 return "<" + bytes.length + " bytes of image data>"; 261 294 } 262 295 296 @Nullable 263 297 public String getPrintImageMatchingInfoDescription() 264 298 { 265 299 // TODO research PIM specification http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html 266 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO)) return null;267 300 return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO); 268 301 } 269 302 270 public String getSharpnessDescription() throws MetadataException 271 { 272 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS)) return null; 273 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS); 303 @Nullable 304 public String getSharpnessDescription() 305 { 306 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS); 307 if (value==null) 308 return null; 274 309 switch (value) { 275 310 case 0: … … 284 319 } 285 320 286 public String getContrastDescription() throws MetadataException 287 { 288 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST)) return null; 289 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST); 321 @Nullable 322 public String getContrastDescription() 323 { 324 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST); 325 if (value==null) 326 return null; 290 327 switch (value) { 291 328 case 0: … … 300 337 } 301 338 302 public String getSaturationDescription() throws MetadataException 303 { 304 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION)) return null; 305 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION); 339 @Nullable 340 public String getSaturationDescription() 341 { 342 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION); 343 if (value==null) 344 return null; 306 345 switch (value) { 307 346 case 0: … … 316 355 } 317 356 318 public String getFocalLengthDescription() throws MetadataException 319 { 320 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH)) return null; 321 double value = _directory.getDouble(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH); 357 @Nullable 358 public String getFocalLengthDescription() 359 { 360 Double value = _directory.getDoubleObject(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH); 361 if (value==null) 362 return null; 322 363 return Double.toString(value / 10d) + " mm"; 323 364 } 324 365 325 public String getWhiteBalance1Description() throws MetadataException 326 { 327 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1)) return null; 328 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1); 366 @Nullable 367 public String getWhiteBalance1Description() 368 { 369 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1); 370 if (value==null) 371 return null; 329 372 switch (value) { 330 373 case 0: … … 337 380 return "Tungsten"; 338 381 case 4: 339 return "Flo urescent";382 return "Florescent"; 340 383 case 5: 341 384 return "Manual"; … … 345 388 } 346 389 347 public String getIsoSensitivityDescription() throws MetadataException 348 { 349 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY)) return null; 350 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY); 390 @Nullable 391 public String getIsoSensitivityDescription() 392 { 393 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY); 394 if (value==null) 395 return null; 351 396 switch (value) { 352 397 case 3: … … 363 408 } 364 409 365 public String getFocusMode1Description() throws MetadataException 366 { 367 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1)) return null; 368 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1); 410 @Nullable 411 public String getFocusMode1Description() 412 { 413 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1); 414 if (value==null) 415 return null; 369 416 switch (value) { 370 417 case 0: … … 377 424 } 378 425 379 public String getImageSizeDescription() throws MetadataException 380 { 381 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE)) return null; 382 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE); 426 @Nullable 427 public String getImageSizeDescription() 428 { 429 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE); 430 if (value==null) 431 return null; 383 432 switch (value) { 384 433 case 0: return "640 x 480 pixels"; … … 393 442 } 394 443 395 public String getQualityModeDescription() throws MetadataException 396 { 397 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE)) return null; 398 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE); 444 @Nullable 445 public String getQualityModeDescription() 446 { 447 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE); 448 if (value==null) 449 return null; 399 450 switch (value) { 400 451 case 1: … … 407 458 } 408 459 460 @Nullable 409 461 public String getThumbnailOffsetDescription() 410 462 { 411 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET)) return null;412 463 return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET); 413 464 } 414 465 415 public String getThumbnailSizeDescription() throws MetadataException 416 { 417 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE)) return null; 418 int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE); 466 @Nullable 467 public String getThumbnailSizeDescription() 468 { 469 Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE); 470 if (value==null) 471 return null; 419 472 return Integer.toString(value) + " bytes"; 420 473 } 421 474 422 public String getThumbnailDimensionsDescription() throws MetadataException423 {424 if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS)) return null;475 @Nullable 476 public String getThumbnailDimensionsDescription() 477 { 425 478 int[] dimensions = _directory.getIntArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS); 426 if (dimensions.length!=2) 479 if (dimensions==null || dimensions.length!=2) 427 480 return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS); 428 481 return dimensions[0] + " x " + dimensions[1] + " pixels"; -
trunk/src/com/drew/metadata/exif/CasioType2MakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 29 * Describes tags specific to Casio (type 2) cameras. 30 * 24 31 * A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment. 25 32 * Makernote data begins after a 6-byte header: "QVC\x00\x00\x00" 33 * 34 * @author Drew Noakes http://drewnoakes.com 26 35 */ 27 36 public class CasioType2MakernoteDirectory extends Directory … … 167 176 public static final int TAG_CASIO_TYPE2_FILTER = 0x3017; 168 177 169 protected static final HashMap tagNameMap = new HashMap(); 178 @NotNull 179 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 170 180 171 181 static 172 182 { 173 // TODO add names 174 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS), "Thumbnail Dimensions");175 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_THUMBNAIL_SIZE), "Thumbnail Size");176 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_THUMBNAIL_OFFSET), "Thumbnail Offset");177 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_QUALITY_MODE), "Quality Mode");178 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_IMAGE_SIZE), "Image Size");179 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_1), "Focus Mode");180 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_ISO_SENSITIVITY), "ISO Sensitivity");181 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_1), "White Balance");182 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_FOCAL_LENGTH), "Focal Length");183 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_SATURATION), "Saturation");184 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_CONTRAST), "Contrast");185 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_SHARPNESS), "Sharpness");186 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");187 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL), "Casio Preview Thumbnail");188 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS), "White Balance Bias");189 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_2), "White Balance");190 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_OBJECT_DISTANCE), "Object Distance");191 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_FLASH_DISTANCE), "Flash Distance");192 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_RECORD_MODE), "Record Mode");193 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_SELF_TIMER), "Self Timer");194 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_QUALITY), "Quality");195 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_2), "Focus Mode");196 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_TIME_ZONE), "Time Zone");197 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_BESTSHOT_MODE), "BestShot Mode");198 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY), "CCD ISO Sensitivity");199 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_COLOUR_MODE), "Colour Mode");200 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_ENHANCEMENT), "Enhancement");201 tagNameMap.put (new Integer(TAG_CASIO_TYPE2_FILTER), "Filter");183 // TODO add missing names 184 _tagNameMap.put(TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS, "Thumbnail Dimensions"); 185 _tagNameMap.put(TAG_CASIO_TYPE2_THUMBNAIL_SIZE, "Thumbnail Size"); 186 _tagNameMap.put(TAG_CASIO_TYPE2_THUMBNAIL_OFFSET, "Thumbnail Offset"); 187 _tagNameMap.put(TAG_CASIO_TYPE2_QUALITY_MODE, "Quality Mode"); 188 _tagNameMap.put(TAG_CASIO_TYPE2_IMAGE_SIZE, "Image Size"); 189 _tagNameMap.put(TAG_CASIO_TYPE2_FOCUS_MODE_1, "Focus Mode"); 190 _tagNameMap.put(TAG_CASIO_TYPE2_ISO_SENSITIVITY, "ISO Sensitivity"); 191 _tagNameMap.put(TAG_CASIO_TYPE2_WHITE_BALANCE_1, "White Balance"); 192 _tagNameMap.put(TAG_CASIO_TYPE2_FOCAL_LENGTH, "Focal Length"); 193 _tagNameMap.put(TAG_CASIO_TYPE2_SATURATION, "Saturation"); 194 _tagNameMap.put(TAG_CASIO_TYPE2_CONTRAST, "Contrast"); 195 _tagNameMap.put(TAG_CASIO_TYPE2_SHARPNESS, "Sharpness"); 196 _tagNameMap.put(TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info"); 197 _tagNameMap.put(TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL, "Casio Preview Thumbnail"); 198 _tagNameMap.put(TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS, "White Balance Bias"); 199 _tagNameMap.put(TAG_CASIO_TYPE2_WHITE_BALANCE_2, "White Balance"); 200 _tagNameMap.put(TAG_CASIO_TYPE2_OBJECT_DISTANCE, "Object Distance"); 201 _tagNameMap.put(TAG_CASIO_TYPE2_FLASH_DISTANCE, "Flash Distance"); 202 _tagNameMap.put(TAG_CASIO_TYPE2_RECORD_MODE, "Record Mode"); 203 _tagNameMap.put(TAG_CASIO_TYPE2_SELF_TIMER, "Self Timer"); 204 _tagNameMap.put(TAG_CASIO_TYPE2_QUALITY, "Quality"); 205 _tagNameMap.put(TAG_CASIO_TYPE2_FOCUS_MODE_2, "Focus Mode"); 206 _tagNameMap.put(TAG_CASIO_TYPE2_TIME_ZONE, "Time Zone"); 207 _tagNameMap.put(TAG_CASIO_TYPE2_BESTSHOT_MODE, "BestShot Mode"); 208 _tagNameMap.put(TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY, "CCD ISO Sensitivity"); 209 _tagNameMap.put(TAG_CASIO_TYPE2_COLOUR_MODE, "Colour Mode"); 210 _tagNameMap.put(TAG_CASIO_TYPE2_ENHANCEMENT, "Enhancement"); 211 _tagNameMap.put(TAG_CASIO_TYPE2_FILTER, "Filter"); 202 212 } 203 213 … … 207 217 } 208 218 219 @NotNull 209 220 public String getName() 210 221 { … … 212 223 } 213 224 214 protected HashMap getTagNameMap() 215 { 216 return tagNameMap; 225 @NotNull 226 protected HashMap<Integer, String> getTagNameMap() 227 { 228 return _tagNameMap; 217 229 } 218 230 } -
trunk/src/com/drew/metadata/exif/DataFormat.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 23 import com.drew.lang.annotations.NotNull; 17 24 import com.drew.metadata.MetadataException; 18 25 19 26 /** 20 27 * An enumeration of data formats used in the TIFF IFDs. 28 * 29 * @author Drew Noakes http://drewnoakes.com 21 30 */ 22 31 public class DataFormat 23 32 { 24 public static final DataFormat BYTE = new DataFormat("BYTE", 1); 25 public static final DataFormat STRING = new DataFormat("STRING", 2); 26 public static final DataFormat USHORT = new DataFormat("USHORT", 3); 27 public static final DataFormat ULONG = new DataFormat("ULONG", 4); 28 public static final DataFormat URATIONAL = new DataFormat("URATIONAL", 5); 29 public static final DataFormat SBYTE = new DataFormat("SBYTE", 6); 30 public static final DataFormat UNDEFINED = new DataFormat("UNDEFINED", 7); 31 public static final DataFormat SSHORT = new DataFormat("SSHORT", 8); 32 public static final DataFormat SLONG = new DataFormat("SLONG", 9); 33 public static final DataFormat SRATIONAL = new DataFormat("SRATIONAL", 10); 34 public static final DataFormat SINGLE = new DataFormat("SINGLE", 11); 35 public static final DataFormat DOUBLE = new DataFormat("DOUBLE", 12); 33 @NotNull public static final DataFormat BYTE = new DataFormat("BYTE", 1); 34 @NotNull public static final DataFormat STRING = new DataFormat("STRING", 2); 35 @NotNull public static final DataFormat USHORT = new DataFormat("USHORT", 3); 36 @NotNull public static final DataFormat ULONG = new DataFormat("ULONG", 4); 37 @NotNull public static final DataFormat URATIONAL = new DataFormat("URATIONAL", 5); 38 @NotNull public static final DataFormat SBYTE = new DataFormat("SBYTE", 6); 39 @NotNull public static final DataFormat UNDEFINED = new DataFormat("UNDEFINED", 7); 40 @NotNull public static final DataFormat SSHORT = new DataFormat("SSHORT", 8); 41 @NotNull public static final DataFormat SLONG = new DataFormat("SLONG", 9); 42 @NotNull public static final DataFormat SRATIONAL = new DataFormat("SRATIONAL", 10); 43 @NotNull public static final DataFormat SINGLE = new DataFormat("SINGLE", 11); 44 @NotNull public static final DataFormat DOUBLE = new DataFormat("DOUBLE", 12); 36 45 37 private final String myName;38 private final int value; 46 @NotNull private final String _name; 47 private final int _value; 39 48 49 @NotNull 40 50 public static DataFormat fromValue(int value) throws MetadataException 41 51 { … … 59 69 } 60 70 61 private DataFormat(String name, int value) 71 private DataFormat(@NotNull String name, int value) 62 72 { 63 myName = name;64 this.value = value;73 _name = name; 74 _value = value; 65 75 } 66 76 67 77 public int getValue() 68 78 { 69 return value; 79 return _value; 70 80 } 71 81 82 @NotNull 72 83 public String toString() 73 84 { 74 return myName;85 return _name; 75 86 } 76 87 } -
trunk/src/com/drew/metadata/exif/ExifInteropDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 12-Nov-2002 22:27:34 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 19 import com.drew. metadata.Directory;20 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 21 25 import com.drew.metadata.TagDescriptor; 22 26 23 27 /** 28 * Provides human-readable string representations of tag values stored in a <code>ExifInteropDirectory</code>. 24 29 * 30 * @author Drew Noakes http://drewnoakes.com 25 31 */ 26 public class ExifInteropDescriptor extends TagDescriptor 32 public class ExifInteropDescriptor extends TagDescriptor<ExifInteropDirectory> 27 33 { 28 public ExifInteropDescriptor(Directory directory) 34 public ExifInteropDescriptor(@NotNull ExifInteropDirectory directory) 29 35 { 30 36 super(directory); 31 37 } 32 38 33 public String getDescription(int tagType) throws MetadataException 39 @Nullable 40 public String getDescription(int tagType) 34 41 { 35 42 switch (tagType) { … … 39 46 return getInteropVersionDescription(); 40 47 default: 41 return _directory.getString(tagType);48 return super.getDescription(tagType); 42 49 } 43 50 } 44 51 45 public String getInteropVersionDescription() throws MetadataException 52 @Nullable 53 public String getInteropVersionDescription() 46 54 { 47 if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_VERSION)) return null;48 55 int[] ints = _directory.getIntArray(ExifInteropDirectory.TAG_INTEROP_VERSION); 49 return ExifDescriptor.convertBytesToVersionString(ints);56 return convertBytesToVersionString(ints, 2); 50 57 } 51 58 59 @Nullable 52 60 public String getInteropIndexDescription() 53 61 { 54 if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_INDEX)) return null; 55 String interopIndex = _directory.getString(ExifInteropDirectory.TAG_INTEROP_INDEX).trim(); 56 if ("R98".equalsIgnoreCase(interopIndex)) { 57 return "Recommended Exif Interoperability Rules (ExifR98)"; 58 } else { 59 return "Unknown (" + interopIndex + ")"; 60 } 62 String value = _directory.getString(ExifInteropDirectory.TAG_INTEROP_INDEX); 63 64 if (value==null) 65 return null; 66 67 return "R98".equalsIgnoreCase(value.trim()) 68 ? "Recommended Exif Interoperability Rules (ExifR98)" 69 : "Unknown (" + value + ")"; 61 70 } 62 71 } -
trunk/src/com/drew/metadata/exif/ExifInteropDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 26-Nov-2002 10:58:13 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 29 * Describes Exif interoperability tags. 24 30 * 31 * @author Drew Noakes http://drewnoakes.com 25 32 */ 26 33 public class ExifInteropDirectory extends Directory … … 32 39 public static final int TAG_RELATED_IMAGE_LENGTH = 0x1002; 33 40 34 protected static final HashMap tagNameMap; 41 @NotNull 42 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 35 43 36 44 static 37 45 { 38 tagNameMap = new HashMap(); 39 tagNameMap.put(new Integer(TAG_INTEROP_INDEX), "Interoperability Index"); 40 tagNameMap.put(new Integer(TAG_INTEROP_VERSION), "Interoperability Version"); 41 tagNameMap.put(new Integer(TAG_RELATED_IMAGE_FILE_FORMAT), "Related Image File Format"); 42 tagNameMap.put(new Integer(TAG_RELATED_IMAGE_WIDTH), "Related Image Width"); 43 tagNameMap.put(new Integer(TAG_RELATED_IMAGE_LENGTH), "Related Image Length"); 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"); 44 51 } 45 52 … … 49 56 } 50 57 58 @NotNull 51 59 public String getName() 52 60 { … … 54 62 } 55 63 56 protected HashMap getTagNameMap() 64 @NotNull 65 protected HashMap<Integer, String> getTagNameMap() 57 66 { 58 return tagNameMap; 67 return _tagNameMap; 59 68 } 60 69 } -
trunk/src/com/drew/metadata/exif/ExifReader.java
r4231 r6127 1 1 /* 2 * EXIFExtractor.java2 * Copyright 2002-2012 Drew Noakes 3 3 * 4 * This class based upon code from Jhead, a C program for extracting and5 * manipulating the Exif data within files written by Matthias Wandel.6 * http://www.sentex.net/~mwandel/jhead/4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 7 * 8 * Jhead is public domain software - that is, you can do whatever you want 9 * with it, and include it software that is licensed under the GNU or the 10 * BSD license, or whatever other licence you choose, including proprietary 11 * closed source licenses. Similarly, I release this Java version under the 12 * same license, though I do ask that you leave this header in tact. 8 * http://www.apache.org/licenses/LICENSE-2.0 13 9 * 14 * If you make modifications to this code that you think would benefit the 15 * wider community, please send me a copy and I'll post it on my site. Unlike 16 * Jhead, this code (as it stands) only supports reading of Exif data - no 17 * manipulation, and no thumbnail stuff. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 18 15 * 19 * If you make use of this code, I'd appreciate hearing about it. 20 * drew.noakes@drewnoakes.com 21 * Latest version of this software kept at 22 * http://drewnoakes.com/ 16 * More information about this project is available at: 23 17 * 24 * Created on 28 April 2002, 23:54 25 * Modified 04 Aug 2002 26 * - Renamed constants to be inline with changes to ExifTagValues interface 27 * - Substituted usage of JDK 1.4 features (java.nio package) 28 * Modified 29 Oct 2002 (v1.2) 29 * - Proper traversing of Exif file structure and complete refactor & tidy of 30 * the codebase (a few unnoticed bugs removed) 31 * - Reads makernote data for 6 families of camera (5 makes) 32 * - Tags now stored in directories... use the IFD_* constants to refer to the 33 * image file directory you require (Exif, Interop, GPS and Makernote*) -- 34 * this avoids collisions where two tags share the same code 35 * - Takes componentCount of unknown tags into account 36 * - Now understands GPS tags (thanks to Colin Briton for his help with this) 37 * - Some other bug fixes, pointed out by users around the world. Thanks! 38 * Modified 27 Nov 2002 (v2.0) 39 * - Renamed to ExifReader 40 * - Moved to new package com.drew.metadata.exif 41 * Modified since, however changes have not been logged. See release notes for 42 * library-wide modifications. 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 43 20 */ 44 21 package com.drew.metadata.exif; 45 22 46 import com.drew.imaging.jpeg.JpegProcessingException; 47 import com.drew.imaging.jpeg.JpegSegmentData; 48 import com.drew.imaging.jpeg.JpegSegmentReader; 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 49 25 import com.drew.lang.Rational; 26 import com.drew.lang.annotations.NotNull; 50 27 import com.drew.metadata.Directory; 51 28 import com.drew.metadata.Metadata; 52 29 import com.drew.metadata.MetadataReader; 53 30 54 import java.io.File; 55 import java.io.InputStream; 56 import java.util.HashMap; 31 import java.util.HashSet; 32 import java.util.Set; 57 33 58 34 /** 59 * Extracts Exifdata from a JPEG header segment, providing information about the60 * camera/scanner/capture device (if available). Information is encapsulated in61 * an <code>Metadata</code> object.62 * @author 35 * Decodes Exif binary data, populating a {@link Metadata} object with tag values in {@link ExifSubIFDDirectory}, 36 * {@link ExifThumbnailDirectory}, {@link ExifInteropDirectory}, {@link GpsDirectory} and one of the many camera makernote directories. 37 * 38 * @author Drew Noakes http://drewnoakes.com 63 39 */ 64 40 public class ExifReader implements MetadataReader 65 41 { 66 /** 67 * The JPEG segment as an array of bytes. 68 */ 69 private final byte[] _data; 70 71 /** 72 * Represents the native byte ordering used in the JPEG segment. If true, 73 * then we're using Motorolla ordering (Big endian), else we're using Intel 74 * ordering (Little endian). 75 */ 76 private boolean _isMotorollaByteOrder; 77 78 /** 79 * Bean instance to store information about the image and camera/scanner/capture 80 * device. 81 */ 82 private Metadata _metadata; 83 84 /** 85 * The number of bytes used per format descriptor. 86 */ 87 private static final int[] BYTES_PER_FORMAT = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}; 88 89 /** 90 * The number of formats known. 91 */ 42 // TODO extract a reusable TiffReader from this class with hooks for special tag handling and subdir following 43 44 /** The number of bytes used per format descriptor. */ 45 @NotNull 46 private static final int[] BYTES_PER_FORMAT = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 }; 47 48 /** The number of formats known. */ 92 49 private static final int MAX_FORMAT_CODE = 12; 93 50 94 51 // Format types 95 // Note: Cannot use the DataFormat enumeration in the case statement that uses these tags.96 / / Is there a better way?52 // TODO use an enum for these? 53 /** An 8-bit unsigned integer. */ 97 54 private static final int FMT_BYTE = 1; 55 /** A fixed-length character string. */ 98 56 private static final int FMT_STRING = 2; 57 /** An unsigned 16-bit integer. */ 99 58 private static final int FMT_USHORT = 3; 59 /** An unsigned 32-bit integer. */ 100 60 private static final int FMT_ULONG = 4; 101 61 private static final int FMT_URATIONAL = 5; 62 /** An 8-bit signed integer. */ 102 63 private static final int FMT_SBYTE = 6; 103 64 private static final int FMT_UNDEFINED = 7; 65 /** A signed 16-bit integer. */ 104 66 private static final int FMT_SSHORT = 8; 67 /** A signed 32-bit integer. */ 105 68 private static final int FMT_SLONG = 9; 106 69 private static final int FMT_SRATIONAL = 10; 70 /** A 32-bit floating point number. */ 107 71 private static final int FMT_SINGLE = 11; 72 /** A 64-bit floating point number. */ 108 73 private static final int FMT_DOUBLE = 12; 109 74 110 public static final int TAG_EXIF_OFFSET = 0x8769; 75 /** This tag is a pointer to the Exif SubIFD. */ 76 public static final int TAG_EXIF_SUB_IFD_OFFSET = 0x8769; 77 /** This tag is a pointer to the Exif Interop IFD. */ 111 78 public static final int TAG_INTEROP_OFFSET = 0xA005; 79 /** This tag is a pointer to the Exif GPS IFD. */ 112 80 public static final int TAG_GPS_INFO_OFFSET = 0x8825; 113 public static final int TAG_MAKER_NOTE = 0x927C; 81 /** This tag is a pointer to the Exif Makernote IFD. */ 82 public static final int TAG_MAKER_NOTE_OFFSET = 0x927C; 114 83 115 84 public static final int TIFF_HEADER_START_OFFSET = 6; 116 117 /**118 * Creates an ExifReader for a JpegSegmentData object.119 * @param segmentData120 */121 public ExifReader(JpegSegmentData segmentData)122 {123 this(segmentData.getSegment(JpegSegmentReader.SEGMENT_APP1));124 }125 126 /**127 * Creates an ExifReader for a Jpeg file.128 * @param file129 * @throws JpegProcessingException130 */131 public ExifReader(File file) throws JpegProcessingException132 {133 this(new JpegSegmentReader(file).readSegment(JpegSegmentReader.SEGMENT_APP1));134 }135 136 /**137 * Creates an ExifReader for a Jpeg stream.138 * @param is JPEG stream. Stream will be closed.139 */140 public ExifReader(InputStream is) throws JpegProcessingException141 {142 this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APP1));143 }144 145 /**146 * Creates an ExifReader for the given JPEG header segment.147 */148 public ExifReader(byte[] data)149 {150 _data = data;151 }152 153 /**154 * Performs the Exif data extraction, returning a new instance of <code>Metadata</code>.155 */156 public Metadata extract()157 {158 return extract(new Metadata());159 }160 85 161 86 /** 162 87 * Performs the Exif data extraction, adding found values to the specified 163 88 * instance of <code>Metadata</code>. 89 * 90 * @param reader The buffer reader from which Exif data should be read. 91 * @param metadata The Metadata object into which extracted values should be merged. 164 92 */ 165 public Metadata extract(Metadata metadata) 166 { 167 _metadata = metadata; 168 if (_data==null) 169 return _metadata; 170 171 // once we know there's some data, create the directory and start working on it 172 ExifDirectory directory = (ExifDirectory)_metadata.getDirectory(ExifDirectory.class); 93 public void extract(@NotNull final BufferReader reader, @NotNull Metadata metadata) 94 { 95 final ExifSubIFDDirectory directory = metadata.getOrCreateDirectory(ExifSubIFDDirectory.class); 173 96 174 97 // check for the header length 175 if ( _data.length<=14) {98 if (reader.getLength() <= 14) { 176 99 directory.addError("Exif data segment must contain at least 14 bytes"); 177 return _metadata;100 return; 178 101 } 179 102 180 103 // check for the header preamble 181 if (!"Exif\0\0".equals(new String(_data, 0, 6))) { 182 directory.addError("Exif data segment doesn't begin with 'Exif'"); 183 return _metadata; 184 } 185 104 try { 105 if (!reader.getString(0, 6).equals("Exif\0\0")) { 106 directory.addError("Exif data segment doesn't begin with 'Exif'"); 107 return; 108 } 109 110 extractIFD(metadata, metadata.getOrCreateDirectory(ExifIFD0Directory.class), TIFF_HEADER_START_OFFSET, reader); 111 } catch (BufferBoundsException e) { 112 directory.addError("Exif data segment ended prematurely"); 113 } 114 } 115 116 /** 117 * Performs the Exif data extraction on a TIFF/RAW, adding found values to the specified 118 * instance of <code>Metadata</code>. 119 * 120 * @param reader The BufferReader from which TIFF data should be read. 121 * @param metadata The Metadata object into which extracted values should be merged. 122 */ 123 public void extractTiff(@NotNull BufferReader reader, @NotNull Metadata metadata) 124 { 125 final ExifIFD0Directory directory = metadata.getOrCreateDirectory(ExifIFD0Directory.class); 126 127 try { 128 extractIFD(metadata, directory, 0, reader); 129 } catch (BufferBoundsException e) { 130 directory.addError("Exif data segment ended prematurely"); 131 } 132 } 133 134 private void extractIFD(@NotNull Metadata metadata, @NotNull final ExifIFD0Directory directory, int tiffHeaderOffset, @NotNull BufferReader reader) throws BufferBoundsException 135 { 186 136 // this should be either "MM" or "II" 187 String byteOrderIdentifier = new String(_data, 6, 2); 188 if (!setByteOrder(byteOrderIdentifier)) { 137 String byteOrderIdentifier = reader.getString(tiffHeaderOffset, 2); 138 139 if ("MM".equals(byteOrderIdentifier)) { 140 reader.setMotorolaByteOrder(true); 141 } else if ("II".equals(byteOrderIdentifier)) { 142 reader.setMotorolaByteOrder(false); 143 } else { 189 144 directory.addError("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier); 190 return _metadata;145 return; 191 146 } 192 147 193 148 // Check the next two values for correctness. 194 if (get16Bits(8)!=0x2a) { 195 directory.addError("Invalid Exif start - should have 0x2A at offset 8 in Exif header"); 196 return _metadata; 197 } 198 199 int firstDirectoryOffset = get32Bits(10) + TIFF_HEADER_START_OFFSET; 200 201 // David Ekholm sent an digital camera image that has this problem 202 if (firstDirectoryOffset>=_data.length - 1) { 149 final int tiffMarker = reader.getUInt16(2 + tiffHeaderOffset); 150 151 final int standardTiffMarker = 0x002A; 152 final int olympusRawTiffMarker = 0x4F52; // for ORF files 153 final int panasonicRawTiffMarker = 0x0055; // for RW2 files 154 155 if (tiffMarker != standardTiffMarker && tiffMarker != olympusRawTiffMarker && tiffMarker != panasonicRawTiffMarker) { 156 directory.addError("Unexpected TIFF marker after byte order identifier: 0x" + Integer.toHexString(tiffMarker)); 157 return; 158 } 159 160 int firstDirectoryOffset = reader.getInt32(4 + tiffHeaderOffset) + tiffHeaderOffset; 161 162 // David Ekholm sent a digital camera image that has this problem 163 if (firstDirectoryOffset >= reader.getLength() - 1) { 203 164 directory.addError("First exif directory offset is beyond end of Exif data segment"); 204 165 // First directory normally starts 14 bytes in -- try it here and catch another error in the worst case … … 206 167 } 207 168 208 HashMap processedDirectoryOffsets = new HashMap(); 209 210 // 0th IFD (we merge with Exif IFD) 211 processDirectory(directory, processedDirectoryOffsets, firstDirectoryOffset, TIFF_HEADER_START_OFFSET); 169 Set<Integer> processedDirectoryOffsets = new HashSet<Integer>(); 170 171 processDirectory(directory, processedDirectoryOffsets, firstDirectoryOffset, tiffHeaderOffset, metadata, reader); 212 172 213 173 // after the extraction process, if we have the correct tags, we may be able to store thumbnail information 214 storeThumbnailBytes(directory, TIFF_HEADER_START_OFFSET); 215 216 return _metadata; 217 } 218 219 private void storeThumbnailBytes(ExifDirectory exifDirectory, int tiffHeaderOffset) 220 { 221 if (!exifDirectory.containsTag(ExifDirectory.TAG_COMPRESSION)) 222 return; 223 224 if (!exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH) || 225 !exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET)) 226 return; 227 228 try { 229 int offset = exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET); 230 int length = exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH); 231 byte[] result = new byte[length]; 232 for (int i = 0; i<result.length; i++) { 233 result[i] = _data[tiffHeaderOffset + offset + i]; 234 } 235 exifDirectory.setByteArray(ExifDirectory.TAG_THUMBNAIL_DATA, result); 236 } catch (Throwable e) { 237 exifDirectory.addError("Unable to extract thumbnail: " + e.getMessage()); 238 } 239 } 240 241 private boolean setByteOrder(String byteOrderIdentifier) 242 { 243 if ("MM".equals(byteOrderIdentifier)) { 244 _isMotorollaByteOrder = true; 245 } else if ("II".equals(byteOrderIdentifier)) { 246 _isMotorollaByteOrder = false; 247 } else { 248 return false; 249 } 250 return true; 174 ExifThumbnailDirectory thumbnailDirectory = metadata.getDirectory(ExifThumbnailDirectory.class); 175 if (thumbnailDirectory!=null && thumbnailDirectory.containsTag(ExifThumbnailDirectory.TAG_THUMBNAIL_COMPRESSION)) { 176 Integer offset = thumbnailDirectory.getInteger(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET); 177 Integer length = thumbnailDirectory.getInteger(ExifThumbnailDirectory.TAG_THUMBNAIL_LENGTH); 178 if (offset != null && length != null) { 179 try { 180 byte[] thumbnailData = reader.getBytes(tiffHeaderOffset + offset, length); 181 thumbnailDirectory.setThumbnailData(thumbnailData); 182 } catch (BufferBoundsException ex) { 183 directory.addError("Invalid thumbnail data specification: " + ex.getMessage()); 184 } 185 } 186 } 251 187 } 252 188 253 189 /** 254 190 * Process one of the nested Tiff IFD directories. 191 * <p/> 192 * Header 255 193 * 2 bytes: number of tags 256 * for each tag 257 * 2 bytes: tag type 258 * 2 bytes: format code 259 * 4 bytes: component count 194 * <p/> 195 * Then for each tag 196 * 2 bytes: tag type 197 * 2 bytes: format code 198 * 4 bytes: component count 260 199 */ 261 private void processDirectory(Directory directory, HashMap processedDirectoryOffsets, int dirStartOffset, int tiffHeaderOffset)200 private void processDirectory(@NotNull Directory directory, @NotNull Set<Integer> processedDirectoryOffsets, int dirStartOffset, int tiffHeaderOffset, @NotNull final Metadata metadata, @NotNull final BufferReader reader) throws BufferBoundsException 262 201 { 263 202 // check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist 264 if (processedDirectoryOffsets.contains Key(newInteger(dirStartOffset)))203 if (processedDirectoryOffsets.contains(Integer.valueOf(dirStartOffset))) 265 204 return; 266 205 267 206 // remember that we've visited this directory so that we don't visit it again later 268 processedDirectoryOffsets.put(new Integer(dirStartOffset), "processed"); 269 270 if (dirStartOffset>=_data.length || dirStartOffset<0) { 271 directory.addError("Ignored directory marked to start outside data segement"); 272 return; 273 } 274 275 if (!isDirectoryLengthValid(dirStartOffset, tiffHeaderOffset)) { 207 processedDirectoryOffsets.add(dirStartOffset); 208 209 if (dirStartOffset >= reader.getLength() || dirStartOffset < 0) { 210 directory.addError("Ignored directory marked to start outside data segment"); 211 return; 212 } 213 214 // First two bytes in the IFD are the number of tags in this directory 215 int dirTagCount = reader.getUInt16(dirStartOffset); 216 217 int dirLength = (2 + (12 * dirTagCount) + 4); 218 if (dirLength + dirStartOffset > reader.getLength()) { 276 219 directory.addError("Illegally sized directory"); 277 220 return; 278 221 } 279 222 280 // First two bytes in the IFD are the number of tags in this directory281 int dirTagCount = get16Bits(dirStartOffset);282 283 223 // Handle each tag in this directory 284 for (int tagNumber = 0; tagNumber<dirTagCount; tagNumber++) 285 { 224 for (int tagNumber = 0; tagNumber < dirTagCount; tagNumber++) { 286 225 final int tagOffset = calculateTagOffset(dirStartOffset, tagNumber); 287 226 288 227 // 2 bytes for the tag type 289 final int tagType = get16Bits(tagOffset);228 final int tagType = reader.getUInt16(tagOffset); 290 229 291 230 // 2 bytes for the format code 292 final int formatCode = get16Bits(tagOffset + 2); 293 if (formatCode<1 || formatCode>MAX_FORMAT_CODE) { 294 directory.addError("Invalid format code: " + formatCode); 295 continue; 231 final int formatCode = reader.getUInt16(tagOffset + 2); 232 if (formatCode < 1 || formatCode > MAX_FORMAT_CODE) { 233 // This error suggests that we are processing at an incorrect index and will generate 234 // rubbish until we go out of bounds (which may be a while). Exit now. 235 directory.addError("Invalid TIFF tag format code: " + formatCode); 236 return; 296 237 } 297 238 298 239 // 4 bytes dictate the number of components in this tag's data 299 final int componentCount = get32Bits(tagOffset + 4);300 if (componentCount <0) {301 directory.addError("Negative component count in EXIF");240 final int componentCount = reader.getInt32(tagOffset + 4); 241 if (componentCount < 0) { 242 directory.addError("Negative TIFF tag component count"); 302 243 continue; 303 244 } 304 245 // each component may have more than one byte... calculate the total number of bytes 305 246 final int byteCount = componentCount * BYTES_PER_FORMAT[formatCode]; 306 final int tagValueOffset = calculateTagValueOffset(byteCount, tagOffset, tiffHeaderOffset); 307 if (tagValueOffset<0 || tagValueOffset > _data.length) { 308 directory.addError("Illegal pointer offset value in EXIF"); 247 final int tagValueOffset; 248 if (byteCount > 4) { 249 // If it's bigger than 4 bytes, the dir entry contains an offset. 250 // dirEntryOffset must be passed, as some makernote implementations (e.g. FujiFilm) incorrectly use an 251 // offset relative to the start of the makernote itself, not the TIFF segment. 252 final int offsetVal = reader.getInt32(tagOffset + 8); 253 if (offsetVal + byteCount > reader.getLength()) { 254 // Bogus pointer offset and / or byteCount value 255 directory.addError("Illegal TIFF tag pointer offset"); 256 continue; 257 } 258 tagValueOffset = tiffHeaderOffset + offsetVal; 259 } else { 260 // 4 bytes or less and value is in the dir entry itself 261 tagValueOffset = tagOffset + 8; 262 } 263 264 if (tagValueOffset < 0 || tagValueOffset > reader.getLength()) { 265 directory.addError("Illegal TIFF tag pointer offset"); 309 266 continue; 310 267 } … … 312 269 // Check that this tag isn't going to allocate outside the bounds of the data array. 313 270 // This addresses an uncommon OutOfMemoryError. 314 if (byteCount < 0 || tagValueOffset + byteCount > _data.length) 315 { 271 if (byteCount < 0 || tagValueOffset + byteCount > reader.getLength()) { 316 272 directory.addError("Illegal number of bytes: " + byteCount); 317 273 continue; 318 274 } 319 275 320 // Calculate the value as an offset for cases where the tag represents directory321 final int subdirOffset = tiffHeaderOffset + get32Bits(tagValueOffset);322 323 276 switch (tagType) { 324 case TAG_EXIF_OFFSET: 325 processDirectory(_metadata.getDirectory(ExifDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 277 case TAG_EXIF_SUB_IFD_OFFSET: { 278 final int subdirOffset = tiffHeaderOffset + reader.getInt32(tagValueOffset); 279 processDirectory(metadata.getOrCreateDirectory(ExifSubIFDDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 326 280 continue; 327 case TAG_INTEROP_OFFSET: 328 processDirectory(_metadata.getDirectory(ExifInteropDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 281 } 282 case TAG_INTEROP_OFFSET: { 283 final int subdirOffset = tiffHeaderOffset + reader.getInt32(tagValueOffset); 284 processDirectory(metadata.getOrCreateDirectory(ExifInteropDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 329 285 continue; 330 case TAG_GPS_INFO_OFFSET: 331 processDirectory(_metadata.getDirectory(GpsDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 286 } 287 case TAG_GPS_INFO_OFFSET: { 288 final int subdirOffset = tiffHeaderOffset + reader.getInt32(tagValueOffset); 289 processDirectory(metadata.getOrCreateDirectory(GpsDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 332 290 continue; 333 case TAG_MAKER_NOTE: 334 processMakerNote(tagValueOffset, processedDirectoryOffsets, tiffHeaderOffset); 291 } 292 case TAG_MAKER_NOTE_OFFSET: { 293 processMakerNote(tagValueOffset, processedDirectoryOffsets, tiffHeaderOffset, metadata, reader); 335 294 continue; 336 default: 337 processTag(directory, tagType, tagValueOffset, componentCount, formatCode); 295 } 296 default: { 297 processTag(directory, tagType, tagValueOffset, componentCount, formatCode, reader); 338 298 break; 299 } 339 300 } 340 301 } … … 342 303 // at the end of each IFD is an optional link to the next IFD 343 304 final int finalTagOffset = calculateTagOffset(dirStartOffset, dirTagCount); 344 int nextDirectoryOffset = get32Bits(finalTagOffset);345 if (nextDirectoryOffset !=0) {305 int nextDirectoryOffset = reader.getInt32(finalTagOffset); 306 if (nextDirectoryOffset != 0) { 346 307 nextDirectoryOffset += tiffHeaderOffset; 347 if (nextDirectoryOffset >=_data.length) {308 if (nextDirectoryOffset >= reader.getLength()) { 348 309 // Last 4 bytes of IFD reference another IFD with an address that is out of bounds 349 310 // Note this could have been caused by jhead 1.3 cropping too much … … 353 314 return; 354 315 } 355 // the next directory is of same type as this one 356 processDirectory(directory, processedDirectoryOffsets, nextDirectoryOffset, tiffHeaderOffset); 357 } 358 } 359 360 private void processMakerNote(int subdirOffset, HashMap processedDirectoryOffsets, int tiffHeaderOffset) 316 // TODO in Exif, the only known 'follower' IFD is the thumbnail one, however this may not be the case 317 final ExifThumbnailDirectory nextDirectory = metadata.getOrCreateDirectory(ExifThumbnailDirectory.class); 318 processDirectory(nextDirectory, processedDirectoryOffsets, nextDirectoryOffset, tiffHeaderOffset, metadata, reader); 319 } 320 } 321 322 private void processMakerNote(int subdirOffset, @NotNull Set<Integer> processedDirectoryOffsets, int tiffHeaderOffset, @NotNull final Metadata metadata, @NotNull BufferReader reader) throws BufferBoundsException 361 323 { 362 324 // Determine the camera model and makernote format 363 Directory exifDirectory = _metadata.getDirectory(ExifDirectory.class); 364 365 if (exifDirectory==null) 366 return; 367 368 String cameraModel = exifDirectory.getString(ExifDirectory.TAG_MAKE); 369 final String firstTwoChars = new String(_data, subdirOffset, 2); 370 final String firstThreeChars = new String(_data, subdirOffset, 3); 371 final String firstFourChars = new String(_data, subdirOffset, 4); 372 final String firstFiveChars = new String(_data, subdirOffset, 5); 373 final String firstSixChars = new String(_data, subdirOffset, 6); 374 final String firstSevenChars = new String(_data, subdirOffset, 7); 375 final String firstEightChars = new String(_data, subdirOffset, 8); 376 if ("OLYMP".equals(firstFiveChars) || "EPSON".equals(firstFiveChars) || "AGFA".equals(firstFourChars)) 377 { 325 Directory ifd0Directory = metadata.getDirectory(ExifIFD0Directory.class); 326 327 if (ifd0Directory==null) 328 return; 329 330 String cameraModel = ifd0Directory.getString(ExifIFD0Directory.TAG_MAKE); 331 332 //final String firstTwoChars = reader.getString(subdirOffset, 2); 333 final String firstThreeChars = reader.getString(subdirOffset, 3); 334 final String firstFourChars = reader.getString(subdirOffset, 4); 335 final String firstFiveChars = reader.getString(subdirOffset, 5); 336 final String firstSixChars = reader.getString(subdirOffset, 6); 337 final String firstSevenChars = reader.getString(subdirOffset, 7); 338 final String firstEightChars = reader.getString(subdirOffset, 8); 339 final String firstTwelveChars = reader.getString(subdirOffset, 12); 340 341 if ("OLYMP".equals(firstFiveChars) || "EPSON".equals(firstFiveChars) || "AGFA".equals(firstFourChars)) { 378 342 // Olympus Makernote 379 // Epson and Agfa use Olypus maker note standard, see: 380 // http://www.ozhiker.com/electronics/pjmt/jpeg_info/ 381 processDirectory(_metadata.getDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset); 382 } 383 else if (cameraModel!=null && cameraModel.trim().toUpperCase().startsWith("NIKON")) 384 { 385 if ("Nikon".equals(firstFiveChars)) 386 { 343 // Epson and Agfa use Olympus maker note standard: http://www.ozhiker.com/electronics/pjmt/jpeg_info/ 344 processDirectory(metadata.getOrCreateDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset, metadata, reader); 345 } else if (cameraModel != null && cameraModel.trim().toUpperCase().startsWith("NIKON")) { 346 if ("Nikon".equals(firstFiveChars)) { 387 347 /* There are two scenarios here: 388 348 * Type 1: ** … … 393 353 * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200 394 354 */ 395 if (_data[subdirOffset+6]==1) 396 processDirectory(_metadata.getDirectory(NikonType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset); 397 else if (_data[subdirOffset+6]==2) 398 processDirectory(_metadata.getDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 18, subdirOffset + 10); 399 else 400 exifDirectory.addError("Unsupported makernote data ignored."); 401 } 355 switch (reader.getUInt8(subdirOffset + 6)) { 356 case 1: 357 processDirectory(metadata.getOrCreateDirectory(NikonType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset, metadata, reader); 358 break; 359 case 2: 360 processDirectory(metadata.getOrCreateDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 18, subdirOffset + 10, metadata, reader); 361 break; 362 default: 363 ifd0Directory.addError("Unsupported Nikon makernote data ignored."); 364 break; 365 } 366 } else { 367 // The IFD begins with the first MakerNote byte (no ASCII name). This occurs with CoolPix 775, E990 and D1 models. 368 processDirectory(metadata.getOrCreateDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 369 } 370 } else if ("SONY CAM".equals(firstEightChars) || "SONY DSC".equals(firstEightChars)) { 371 processDirectory(metadata.getOrCreateDirectory(SonyType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset, metadata, reader); 372 } else if ("SIGMA\u0000\u0000\u0000".equals(firstEightChars) || "FOVEON\u0000\u0000".equals(firstEightChars)) { 373 processDirectory(metadata.getOrCreateDirectory(SigmaMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 10, tiffHeaderOffset, metadata, reader); 374 } else if ("SEMC MS\u0000\u0000\u0000\u0000\u0000".equals(firstTwelveChars)) { 375 // force MM for this directory 376 boolean isMotorola = reader.isMotorolaByteOrder(); 377 reader.setMotorolaByteOrder(true); 378 // skip 12 byte header + 2 for "MM" + 6 379 processDirectory(metadata.getOrCreateDirectory(SonyType6MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 20, tiffHeaderOffset, metadata, reader); 380 reader.setMotorolaByteOrder(isMotorola); 381 } else if ("KDK".equals(firstThreeChars)) { 382 processDirectory(metadata.getOrCreateDirectory(KodakMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 20, tiffHeaderOffset, metadata, reader); 383 } else if ("Canon".equalsIgnoreCase(cameraModel)) { 384 processDirectory(metadata.getOrCreateDirectory(CanonMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 385 } else if (cameraModel != null && cameraModel.toUpperCase().startsWith("CASIO")) { 386 if ("QVC\u0000\u0000\u0000".equals(firstSixChars)) 387 processDirectory(metadata.getOrCreateDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, tiffHeaderOffset, metadata, reader); 402 388 else 403 { 404 // The IFD begins with the first MakerNote byte (no ASCII name). This occurs with CoolPix 775, E990 and D1 models. 405 processDirectory(_metadata.getDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 406 } 407 } 408 else if ("SONY CAM".equals(firstEightChars) || "SONY DSC".equals(firstEightChars)) 409 { 410 processDirectory(_metadata.getDirectory(SonyMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset); 411 } 412 else if ("KDK".equals(firstThreeChars)) 413 { 414 processDirectory(_metadata.getDirectory(KodakMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 20, tiffHeaderOffset); 415 } 416 else if ("Canon".equalsIgnoreCase(cameraModel)) 417 { 418 processDirectory(_metadata.getDirectory(CanonMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 419 } 420 else if (cameraModel!=null && cameraModel.toUpperCase().startsWith("CASIO")) 421 { 422 if ("QVC\u0000\u0000\u0000".equals(firstSixChars)) 423 processDirectory(_metadata.getDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, tiffHeaderOffset); 424 else 425 processDirectory(_metadata.getDirectory(CasioType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 426 } 427 else if ("FUJIFILM".equals(firstEightChars) || "Fujifilm".equalsIgnoreCase(cameraModel)) 428 { 429 // TODO make this field a passed parameter, to avoid threading issues 430 boolean byteOrderBefore = _isMotorollaByteOrder; 389 processDirectory(metadata.getOrCreateDirectory(CasioType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 390 } else if ("FUJIFILM".equals(firstEightChars) || "Fujifilm".equalsIgnoreCase(cameraModel)) { 391 boolean byteOrderBefore = reader.isMotorolaByteOrder(); 431 392 // bug in fujifilm makernote ifd means we temporarily use Intel byte ordering 432 _isMotorollaByteOrder= false;393 reader.setMotorolaByteOrder(false); 433 394 // the 4 bytes after "FUJIFILM" in the makernote point to the start of the makernote 434 395 // IFD, though the offset is relative to the start of the makernote, not the TIFF 435 396 // header (like everywhere else) 436 int ifdStart = subdirOffset + get32Bits(subdirOffset + 8); 437 processDirectory(_metadata.getDirectory(FujifilmMakernoteDirectory.class), processedDirectoryOffsets, ifdStart, tiffHeaderOffset); 438 _isMotorollaByteOrder = byteOrderBefore; 439 } 440 else if (cameraModel!=null && cameraModel.toUpperCase().startsWith("MINOLTA")) 441 { 397 int ifdStart = subdirOffset + reader.getInt32(subdirOffset + 8); 398 processDirectory(metadata.getOrCreateDirectory(FujifilmMakernoteDirectory.class), processedDirectoryOffsets, ifdStart, tiffHeaderOffset, metadata, reader); 399 reader.setMotorolaByteOrder(byteOrderBefore); 400 } else if (cameraModel != null && cameraModel.toUpperCase().startsWith("MINOLTA")) { 442 401 // Cases seen with the model starting with MINOLTA in capitals seem to have a valid Olympus makernote 443 402 // area that commences immediately. 444 processDirectory(_metadata.getDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); 445 } 446 else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars)) 447 { 448 // This Konica data is not understood. Header identified in accordance with information at this site: 449 // http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html 450 // TODO determine how to process the information described at the above website 451 exifDirectory.addError("Unsupported Konica/Minolta data ignored."); 452 } 453 else if ("KYOCERA".equals(firstSevenChars)) 454 { 403 processDirectory(metadata.getOrCreateDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset, metadata, reader); 404 } else if ("KYOCERA".equals(firstSevenChars)) { 455 405 // http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html 456 processDirectory(_metadata.getDirectory(KyoceraMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 22, tiffHeaderOffset); 457 } 458 else if ("Panasonic\u0000\u0000\u0000".equals(new String(_data, subdirOffset, 12))) 459 { 406 processDirectory(metadata.getOrCreateDirectory(KyoceraMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 22, tiffHeaderOffset, metadata, reader); 407 } else if ("Panasonic\u0000\u0000\u0000".equals(reader.getString(subdirOffset, 12))) { 460 408 // NON-Standard TIFF IFD Data using Panasonic Tags. There is no Next-IFD pointer after the IFD 461 409 // Offsets are relative to the start of the TIFF header at the beginning of the EXIF segment 462 410 // more information here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html 463 processDirectory(_metadata.getDirectory(PanasonicMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset); 464 } 465 else if ("AOC\u0000".equals(firstFourChars)) 466 { 411 processDirectory(metadata.getOrCreateDirectory(PanasonicMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset, metadata, reader); 412 } else if ("AOC\u0000".equals(firstFourChars)) { 467 413 // NON-Standard TIFF IFD Data using Casio Type 2 Tags 468 414 // IFD has no Next-IFD pointer at end of IFD, and … … 470 416 // Observed for: 471 417 // - Pentax ist D 472 processDirectory(_metadata.getDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, subdirOffset); 473 } 474 else if (cameraModel!=null && (cameraModel.toUpperCase().startsWith("PENTAX") || cameraModel.toUpperCase().startsWith("ASAHI"))) 475 { 418 processDirectory(metadata.getOrCreateDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, subdirOffset, metadata, reader); 419 } else if (cameraModel != null && (cameraModel.toUpperCase().startsWith("PENTAX") || cameraModel.toUpperCase().startsWith("ASAHI"))) { 476 420 // NON-Standard TIFF IFD Data using Pentax Tags 477 421 // IFD has no Next-IFD pointer at end of IFD, and … … 480 424 // - PENTAX Optio 330 481 425 // - PENTAX Optio 430 482 processDirectory(_metadata.getDirectory(PentaxMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, subdirOffset); 483 } 484 else 485 { 426 processDirectory(metadata.getOrCreateDirectory(PentaxMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, subdirOffset, metadata, reader); 427 // } else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars)) { 428 // // This Konica data is not understood. Header identified in accordance with information at this site: 429 // // http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html 430 // // TODO add support for minolta/konica cameras 431 // exifDirectory.addError("Unsupported Konica/Minolta data ignored."); 432 } else { 486 433 // TODO how to store makernote data when it's not from a supported camera model? 487 434 // this is difficult as the starting offset is not known. we could look for it... 488 exifDirectory.addError("Unsupported makernote data ignored."); 489 } 490 } 491 492 private boolean isDirectoryLengthValid(int dirStartOffset, int tiffHeaderOffset) 493 { 494 int dirTagCount = get16Bits(dirStartOffset); 495 int dirLength = (2 + (12 * dirTagCount) + 4); 496 if (dirLength + dirStartOffset + tiffHeaderOffset>=_data.length) { 497 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier might trigger this 498 return false; 499 } 500 return true; 501 } 502 503 private void processTag(Directory directory, int tagType, int tagValueOffset, int componentCount, int formatCode) 435 } 436 } 437 438 private void processTag(@NotNull Directory directory, int tagType, int tagValueOffset, int componentCount, int formatCode, @NotNull final BufferReader reader) throws BufferBoundsException 504 439 { 505 440 // Directory simply stores raw values 506 441 // The display side uses a Descriptor class per directory to turn the raw values into 'pretty' descriptions 507 switch (formatCode) 508 { 442 switch (formatCode) { 509 443 case FMT_UNDEFINED: 510 444 // this includes exif user comments 511 final byte[] tagBytes = new byte[componentCount]; 512 final int byteCount = componentCount * BYTES_PER_FORMAT[formatCode]; 513 for (int i=0; i<byteCount; i++) 514 tagBytes[i] = _data[tagValueOffset + i]; 515 directory.setByteArray(tagType, tagBytes); 445 directory.setByteArray(tagType, reader.getBytes(tagValueOffset, componentCount)); 516 446 break; 517 447 case FMT_STRING: 518 directory.setString(tagType, readString(tagValueOffset, componentCount)); 448 String string = reader.getNullTerminatedString(tagValueOffset, componentCount); 449 directory.setString(tagType, string); 450 /* 451 // special handling for certain known tags, proposed by Yuri Binev but left out for now, 452 // as it gives the false impression that the image was captured in the same timezone 453 // in which the string is parsed 454 if (tagType==ExifSubIFDDirectory.TAG_DATETIME || 455 tagType==ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL || 456 tagType==ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED) { 457 String[] datePatterns = { 458 "yyyy:MM:dd HH:mm:ss", 459 "yyyy:MM:dd HH:mm", 460 "yyyy-MM-dd HH:mm:ss", 461 "yyyy-MM-dd HH:mm"}; 462 for (String datePattern : datePatterns) { 463 try { 464 DateFormat parser = new SimpleDateFormat(datePattern); 465 Date date = parser.parse(string); 466 directory.setDate(tagType, date); 467 break; 468 } catch (ParseException ex) { 469 // simply try the next pattern 470 } 471 } 472 } 473 */ 519 474 break; 520 475 case FMT_SRATIONAL: 476 if (componentCount == 1) { 477 directory.setRational(tagType, new Rational(reader.getInt32(tagValueOffset), reader.getInt32(tagValueOffset + 4))); 478 } else if (componentCount > 1) { 479 Rational[] rationals = new Rational[componentCount]; 480 for (int i = 0; i < componentCount; i++) 481 rationals[i] = new Rational(reader.getInt32(tagValueOffset + (8 * i)), reader.getInt32(tagValueOffset + 4 + (8 * i))); 482 directory.setRationalArray(tagType, rationals); 483 } 484 break; 521 485 case FMT_URATIONAL: 522 if (componentCount==1) { 523 Rational rational = new Rational(get32Bits(tagValueOffset), get32Bits(tagValueOffset + 4)); 524 directory.setRational(tagType, rational); 525 } else { 486 if (componentCount == 1) { 487 directory.setRational(tagType, new Rational(reader.getUInt32(tagValueOffset), reader.getUInt32(tagValueOffset + 4))); 488 } else if (componentCount > 1) { 526 489 Rational[] rationals = new Rational[componentCount]; 527 for (int i = 0; i <componentCount; i++)528 rationals[i] = new Rational( get32Bits(tagValueOffset + (8 * i)),get32Bits(tagValueOffset + 4 + (8 * i)));490 for (int i = 0; i < componentCount; i++) 491 rationals[i] = new Rational(reader.getUInt32(tagValueOffset + (8 * i)), reader.getUInt32(tagValueOffset + 4 + (8 * i))); 529 492 directory.setRationalArray(tagType, rationals); 530 493 } 531 494 break; 495 case FMT_SINGLE: 496 if (componentCount == 1) { 497 directory.setFloat(tagType, reader.getFloat32(tagValueOffset)); 498 } else { 499 float[] floats = new float[componentCount]; 500 for (int i = 0; i < componentCount; i++) 501 floats[i] = reader.getFloat32(tagValueOffset + (i * 4)); 502 directory.setFloatArray(tagType, floats); 503 } 504 break; 505 case FMT_DOUBLE: 506 if (componentCount == 1) { 507 directory.setDouble(tagType, reader.getDouble64(tagValueOffset)); 508 } else { 509 double[] doubles = new double[componentCount]; 510 for (int i = 0; i < componentCount; i++) 511 doubles[i] = reader.getDouble64(tagValueOffset + (i * 4)); 512 directory.setDoubleArray(tagType, doubles); 513 } 514 break; 515 516 // 517 // Note that all integral types are stored as int32 internally (the largest supported by TIFF) 518 // 519 532 520 case FMT_SBYTE: 521 if (componentCount == 1) { 522 directory.setInt(tagType, reader.getInt8(tagValueOffset)); 523 } else { 524 int[] bytes = new int[componentCount]; 525 for (int i = 0; i < componentCount; i++) 526 bytes[i] = reader.getInt8(tagValueOffset + i); 527 directory.setIntArray(tagType, bytes); 528 } 529 break; 533 530 case FMT_BYTE: 534 if (componentCount==1) { 535 // this may need to be a byte, but I think casting to int is fine 536 int b = _data[tagValueOffset]; 537 directory.setInt(tagType, b); 531 if (componentCount == 1) { 532 directory.setInt(tagType, reader.getUInt8(tagValueOffset)); 538 533 } else { 539 534 int[] bytes = new int[componentCount]; 540 for (int i = 0; i <componentCount; i++)541 bytes[i] = _data[tagValueOffset + i];535 for (int i = 0; i < componentCount; i++) 536 bytes[i] = reader.getUInt8(tagValueOffset + i); 542 537 directory.setIntArray(tagType, bytes); 543 538 } 544 539 break; 545 case FMT_SINGLE: 546 case FMT_DOUBLE: 547 if (componentCount==1) { 548 int i = _data[tagValueOffset]; 540 case FMT_USHORT: 541 if (componentCount == 1) { 542 int i = reader.getUInt16(tagValueOffset); 549 543 directory.setInt(tagType, i); 550 544 } else { 551 545 int[] ints = new int[componentCount]; 552 for (int i = 0; i <componentCount; i++)553 ints[i] = _data[tagValueOffset +i];546 for (int i = 0; i < componentCount; i++) 547 ints[i] = reader.getUInt16(tagValueOffset + (i * 2)); 554 548 directory.setIntArray(tagType, ints); 555 549 } 556 550 break; 557 case FMT_USHORT:558 551 case FMT_SSHORT: 559 if (componentCount ==1) {560 int i = get16Bits(tagValueOffset);552 if (componentCount == 1) { 553 int i = reader.getInt16(tagValueOffset); 561 554 directory.setInt(tagType, i); 562 555 } else { 563 556 int[] ints = new int[componentCount]; 564 for (int i = 0; i <componentCount; i++)565 ints[i] = get16Bits(tagValueOffset + (i * 2));557 for (int i = 0; i < componentCount; i++) 558 ints[i] = reader.getInt16(tagValueOffset + (i * 2)); 566 559 directory.setIntArray(tagType, ints); 567 560 } … … 569 562 case FMT_SLONG: 570 563 case FMT_ULONG: 571 if (componentCount==1) { 572 int i = get32Bits(tagValueOffset); 564 // NOTE 'long' in this case means 32 bit, not 64 565 if (componentCount == 1) { 566 int i = reader.getInt32(tagValueOffset); 573 567 directory.setInt(tagType, i); 574 568 } else { 575 569 int[] ints = new int[componentCount]; 576 for (int i = 0; i <componentCount; i++)577 ints[i] = get32Bits(tagValueOffset + (i * 4));570 for (int i = 0; i < componentCount; i++) 571 ints[i] = reader.getInt32(tagValueOffset + (i * 4)); 578 572 directory.setIntArray(tagType, ints); 579 573 } … … 584 578 } 585 579 586 private int calculateTagValueOffset(int byteCount, int dirEntryOffset, int tiffHeaderOffset)587 {588 if (byteCount>4) {589 // If its bigger than 4 bytes, the dir entry contains an offset.590 // dirEntryOffset must be passed, as some makernote implementations (e.g. FujiFilm) incorrectly use an591 // offset relative to the start of the makernote itself, not the TIFF segment.592 final int offsetVal = get32Bits(dirEntryOffset + 8);593 if (offsetVal + byteCount>_data.length) {594 // Bogus pointer offset and / or bytecount value595 return -1; // signal error596 }597 return tiffHeaderOffset + offsetVal;598 } else {599 // 4 bytes or less and value is in the dir entry itself600 return dirEntryOffset + 8;601 }602 }603 604 /**605 * Creates a String from the _data buffer starting at the specified offset,606 * and ending where byte=='\0' or where length==maxLength.607 */608 private String readString(int offset, int maxLength)609 {610 int length = 0;611 while ((offset + length)<_data.length && _data[offset + length]!='\0' && length<maxLength)612 length++;613 614 return new String(_data, offset, length);615 }616 617 580 /** 618 581 * Determine the offset at which a given InteropArray entry begins within the specified IFD. 582 * 619 583 * @param dirStartOffset the offset at which the IFD starts 620 * @param entryNumber the zero-based entry number 584 * @param entryNumber the zero-based entry number 621 585 */ 622 586 private int calculateTagOffset(int dirStartOffset, int entryNumber) … … 626 590 return dirStartOffset + 2 + (12 * entryNumber); 627 591 } 628 629 /**630 * Get a 16 bit value from file's native byte order. Between 0x0000 and 0xFFFF.631 */632 private int get16Bits(int offset)633 {634 if (offset<0 || offset+2>_data.length)635 throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")");636 637 if (_isMotorollaByteOrder) {638 // Motorola - MSB first639 return (_data[offset] << 8 & 0xFF00) | (_data[offset + 1] & 0xFF);640 } else {641 // Intel ordering - LSB first642 return (_data[offset + 1] << 8 & 0xFF00) | (_data[offset] & 0xFF);643 }644 }645 646 /**647 * Get a 32 bit value from file's native byte order.648 */649 private int get32Bits(int offset)650 {651 if (offset<0 || offset+4>_data.length)652 throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")");653 654 if (_isMotorollaByteOrder) {655 // Motorola - MSB first656 return (_data[offset] << 24 & 0xFF000000) |657 (_data[offset + 1] << 16 & 0xFF0000) |658 (_data[offset + 2] << 8 & 0xFF00) |659 (_data[offset + 3] & 0xFF);660 } else {661 // Intel ordering - LSB first662 return (_data[offset + 3] << 24 & 0xFF000000) |663 (_data[offset + 2] << 16 & 0xFF0000) |664 (_data[offset + 1] << 8 & 0xFF00) |665 (_data[offset] & 0xFF);666 }667 }668 592 } -
trunk/src/com/drew/metadata/exif/FujifilmMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 19 23 import com.drew.lang.Rational; 20 import com.drew. metadata.Directory;21 import com.drew. metadata.MetadataException;24 import com.drew.lang.annotations.NotNull; 25 import com.drew.lang.annotations.Nullable; 22 26 import com.drew.metadata.TagDescriptor; 23 27 24 28 /** 29 * Provides human-readable string representations of tag values stored in a <code>FujifilmMakernoteDirectory</code>. 30 * <p/> 25 31 * Fujifilm's digicam added the MakerNote tag from the Year2000's model (e.g.Finepix1400, 26 32 * Finepix4700). It uses IFD format and start from ASCII character 'FUJIFILM', and next 4 27 33 * bytes(value 0x000c) points the offset to first IFD entry. Example of actual data 28 34 * structure is shown below. 29 * 35 * <p/> 36 * <pre><code> 30 37 * :0000: 46 55 4A 49 46 49 4C 4D-0C 00 00 00 0F 00 00 00 :0000: FUJIFILM........ 31 38 * :0010: 07 00 04 00 00 00 30 31-33 30 00 10 02 00 08 00 :0010: ......0130...... 32 * 39 * </code></pre> 40 * <p/> 33 41 * There are two big differences to the other manufacturers. 34 42 * - Fujifilm's Exif data uses Motorola align, but MakerNote ignores it and uses Intel … … 37 45 * of TIFF header (same as the other IFD), but Fujifilm counts it from the first byte 38 46 * of MakerNote itself. 47 * 48 * @author Drew Noakes http://drewnoakes.com 39 49 */ 40 public class FujifilmMakernoteDescriptor extends TagDescriptor 50 public class FujifilmMakernoteDescriptor extends TagDescriptor<FujifilmMakernoteDirectory> 41 51 { 42 public FujifilmMakernoteDescriptor(Directory directory) 52 public FujifilmMakernoteDescriptor(@NotNull FujifilmMakernoteDirectory directory) 43 53 { 44 54 super(directory); 45 55 } 46 56 47 public String getDescription(int tagType) throws MetadataException 57 @Nullable 58 public String getDescription(int tagType) 48 59 { 49 60 switch (tagType) { … … 52 63 case FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE: 53 64 return getWhiteBalanceDescription(); 54 case FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR: 65 case FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR_SATURATION: 55 66 return getColorDescription(); 56 67 case FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE: … … 64 75 case FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE: 65 76 return getFocusModeDescription(); 66 case FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCH RO:77 case FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCH: 67 78 return getSlowSyncDescription(); 68 79 case FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE: … … 77 88 return getAutoExposureWarningDescription(); 78 89 default: 79 return _directory.getString(tagType); 80 } 81 } 82 83 public String getAutoExposureWarningDescription() throws MetadataException 84 { 85 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING)) return null; 86 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING); 87 switch (value) { 88 case 0: 89 return "AE good"; 90 case 1: 91 return "Over exposed (>1/1000s @ F11)"; 92 default: 93 return "Unknown (" + value + ")"; 94 } 95 } 96 97 public String getFocusWarningDescription() throws MetadataException 98 { 99 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING)) return null; 100 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING); 101 switch (value) { 102 case 0: 103 return "Auto focus good"; 104 case 1: 105 return "Out of focus"; 106 default: 107 return "Unknown (" + value + ")"; 108 } 109 } 110 111 public String getBlurWarningDescription() throws MetadataException 112 { 113 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING)) return null; 114 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING); 115 switch (value) { 116 case 0: 117 return "No blur warning"; 118 case 1: 119 return "Blur warning"; 120 default: 121 return "Unknown (" + value + ")"; 122 } 123 } 124 125 public String getContinuousTakingOrAutoBrackettingDescription() throws MetadataException 126 { 127 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING)) return null; 128 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING); 129 switch (value) { 130 case 0: 90 return super.getDescription(tagType); 91 } 92 } 93 94 @Nullable 95 public String getSharpnessDescription() 96 { 97 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS); 98 if (value==null) 99 return null; 100 switch (value) { 101 case 1: 102 return "Softest"; 103 case 2: 104 return "Soft"; 105 case 3: 106 return "Normal"; 107 case 4: 108 return "Hard"; 109 case 5: 110 return "Hardest"; 111 default: 112 return "Unknown (" + value + ")"; 113 } 114 } 115 116 @Nullable 117 public String getWhiteBalanceDescription() 118 { 119 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE); 120 if (value==null) 121 return null; 122 switch (value) { 123 case 0: 124 return "Auto"; 125 case 256: 126 return "Daylight"; 127 case 512: 128 return "Cloudy"; 129 case 768: 130 return "DaylightColor-fluorescence"; 131 case 769: 132 return "DaywhiteColor-fluorescence"; 133 case 770: 134 return "White-fluorescence"; 135 case 1024: 136 return "Incandescence"; 137 case 3840: 138 return "Custom white balance"; 139 default: 140 return "Unknown (" + value + ")"; 141 } 142 } 143 144 @Nullable 145 public String getColorDescription() 146 { 147 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR_SATURATION); 148 if (value==null) 149 return null; 150 switch (value) { 151 case 0: 152 return "Normal (STD)"; 153 case 256: 154 return "High (HARD)"; 155 case 512: 156 return "Low (ORG)"; 157 default: 158 return "Unknown (" + value + ")"; 159 } 160 } 161 162 @Nullable 163 public String getToneDescription() 164 { 165 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE); 166 if (value==null) 167 return null; 168 switch (value) { 169 case 0: 170 return "Normal (STD)"; 171 case 256: 172 return "High (HARD)"; 173 case 512: 174 return "Low (ORG)"; 175 default: 176 return "Unknown (" + value + ")"; 177 } 178 } 179 180 @Nullable 181 public String getFlashModeDescription() 182 { 183 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE); 184 if (value==null) 185 return null; 186 switch (value) { 187 case 0: 188 return "Auto"; 189 case 1: 190 return "On"; 191 case 2: 131 192 return "Off"; 132 case 1: 133 return "On"; 134 default: 135 return "Unknown (" + value + ")"; 136 } 137 } 138 139 public String getPictureModeDescription() throws MetadataException 140 { 141 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE)) return null; 142 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE); 193 case 3: 194 return "Red-eye reduction"; 195 default: 196 return "Unknown (" + value + ")"; 197 } 198 } 199 200 @Nullable 201 public String getFlashStrengthDescription() 202 { 203 Rational value = _directory.getRational(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH); 204 if (value==null) 205 return null; 206 return value.toSimpleString(false) + " EV (Apex)"; 207 } 208 209 @Nullable 210 public String getMacroDescription() 211 { 212 return getOnOffDescription(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO); 213 } 214 215 @Nullable 216 public String getFocusModeDescription() 217 { 218 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE); 219 if (value==null) 220 return null; 221 switch (value) { 222 case 0: 223 return "Auto focus"; 224 case 1: 225 return "Manual focus"; 226 default: 227 return "Unknown (" + value + ")"; 228 } 229 } 230 231 @Nullable 232 public String getSlowSyncDescription() 233 { 234 return getOnOffDescription(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCH); 235 } 236 237 @Nullable 238 public String getPictureModeDescription() 239 { 240 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE); 241 if (value==null) 242 return null; 143 243 switch (value) { 144 244 case 0: … … 165 265 } 166 266 167 public String getSlowSyncDescription() throws MetadataException 168 { 169 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO)) return null; 170 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO); 267 @Nullable 268 public String getContinuousTakingOrAutoBrackettingDescription() 269 { 270 return getOnOffDescription(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING); 271 } 272 273 @Nullable 274 public String getBlurWarningDescription() 275 { 276 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING); 277 if (value==null) 278 return null; 279 switch (value) { 280 case 0: 281 return "No blur warning"; 282 case 1: 283 return "Blur warning"; 284 default: 285 return "Unknown (" + value + ")"; 286 } 287 } 288 289 @Nullable 290 public String getFocusWarningDescription() 291 { 292 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING); 293 if (value==null) 294 return null; 295 switch (value) { 296 case 0: 297 return "Auto focus good"; 298 case 1: 299 return "Out of focus"; 300 default: 301 return "Unknown (" + value + ")"; 302 } 303 } 304 305 @Nullable 306 public String getAutoExposureWarningDescription() 307 { 308 final Integer value = _directory.getInteger(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING); 309 if (value==null) 310 return null; 311 switch (value) { 312 case 0: 313 return "AE good"; 314 case 1: 315 return "Over exposed (>1/1000s @ F11)"; 316 default: 317 return "Unknown (" + value + ")"; 318 } 319 } 320 321 322 @Nullable 323 private String getOnOffDescription(final int tagType) 324 { 325 final Integer value = _directory.getInteger(tagType); 326 if (value==null) 327 return null; 171 328 switch (value) { 172 329 case 0: … … 178 335 } 179 336 } 180 181 public String getFocusModeDescription() throws MetadataException182 {183 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE)) return null;184 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE);185 switch (value) {186 case 0:187 return "Auto focus";188 case 1:189 return "Manual focus";190 default:191 return "Unknown (" + value + ")";192 }193 }194 195 public String getMacroDescription() throws MetadataException196 {197 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO)) return null;198 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO);199 switch (value) {200 case 0:201 return "Off";202 case 1:203 return "On";204 default:205 return "Unknown (" + value + ")";206 }207 }208 209 public String getFlashStrengthDescription() throws MetadataException210 {211 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH)) return null;212 Rational value = _directory.getRational(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH);213 return value.toSimpleString(false) + " EV (Apex)";214 }215 216 public String getFlashModeDescription() throws MetadataException217 {218 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE)) return null;219 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE);220 switch (value) {221 case 0:222 return "Auto";223 case 1:224 return "On";225 case 2:226 return "Off";227 case 3:228 return "Red-eye reduction";229 default:230 return "Unknown (" + value + ")";231 }232 }233 234 public String getToneDescription() throws MetadataException235 {236 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE)) return null;237 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE);238 switch (value) {239 case 0:240 return "Normal (STD)";241 case 256:242 return "High (HARD)";243 case 512:244 return "Low (ORG)";245 default:246 return "Unknown (" + value + ")";247 }248 }249 250 public String getColorDescription() throws MetadataException251 {252 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR)) return null;253 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR);254 switch (value) {255 case 0:256 return "Normal (STD)";257 case 256:258 return "High";259 case 512:260 return "Low (ORG)";261 default:262 return "Unknown (" + value + ")";263 }264 }265 266 public String getWhiteBalanceDescription() throws MetadataException267 {268 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE)) return null;269 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE);270 switch (value) {271 case 0:272 return "Auto";273 case 256:274 return "Daylight";275 case 512:276 return "Cloudy";277 case 768:278 return "DaylightColor-fluorescence";279 case 769:280 return "DaywhiteColor-fluorescence";281 case 770:282 return "White-fluorescence";283 case 1024:284 return "Incandenscense";285 case 3840:286 return "Custom white balance";287 default:288 return "Unknown (" + value + ")";289 }290 }291 292 public String getSharpnessDescription() throws MetadataException293 {294 if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS)) return null;295 int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS);296 switch (value) {297 case 1:298 return "Softest";299 case 2:300 return "Soft";301 case 3:302 return "Normal";303 case 4:304 return "Hard";305 case 5:306 return "Hardest";307 default:308 return "Unknown (" + value + ")";309 }310 }311 337 } -
trunk/src/com/drew/metadata/exif/FujifilmMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 29 * Describes tags specific to Fujifilm cameras. 24 30 * 31 * @author Drew Noakes http://drewnoakes.com 25 32 */ 26 33 public class FujifilmMakernoteDirectory extends Directory 27 34 { 28 35 public static final int TAG_FUJIFILM_MAKERNOTE_VERSION = 0x0000; 29 public static final int TAG_FUJIFILM_QUALITY = 0x1000; 30 public static final int TAG_FUJIFILM_SHARPNESS = 0x1001; 31 public static final int TAG_FUJIFILM_WHITE_BALANCE = 0x1002; 32 public static final int TAG_FUJIFILM_COLOR = 0x1003; 33 public static final int TAG_FUJIFILM_TONE = 0x1004; 34 public static final int TAG_FUJIFILM_FLASH_MODE = 0x1010; 35 public static final int TAG_FUJIFILM_FLASH_STRENGTH = 0x1011; 36 public static final int TAG_FUJIFILM_MACRO = 0x1020; 37 public static final int TAG_FUJIFILM_FOCUS_MODE = 0x1021; 38 public static final int TAG_FUJIFILM_SLOW_SYNCH RO= 0x1030;39 public static final int TAG_FUJIFILM_PICTURE_MODE = 0x1031; 40 public static final int TAG_FUJIFILM_UNKNOWN_1 = 0x1032; 41 public static final int TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING = 0x1100; 42 public static final int TAG_FUJIFILM_UNKNOWN_2 = 0x1200; 43 public static final int TAG_FUJIFILM_BLUR_WARNING = 0x1300; 44 public static final int TAG_FUJIFILM_FOCUS_WARNING = 0x1301; 45 public static final int TAG_FUJIFILM_AE_WARNING = 0x1302; 36 public static final int TAG_FUJIFILM_QUALITY = 0x1000; // 4096 37 public static final int TAG_FUJIFILM_SHARPNESS = 0x1001; // 4097 38 public static final int TAG_FUJIFILM_WHITE_BALANCE = 0x1002; // 4098 39 public static final int TAG_FUJIFILM_COLOR_SATURATION = 0x1003; // 4099 40 public static final int TAG_FUJIFILM_TONE = 0x1004; // 4100 41 public static final int TAG_FUJIFILM_FLASH_MODE = 0x1010; // 4112 42 public static final int TAG_FUJIFILM_FLASH_STRENGTH = 0x1011; // 4113 43 public static final int TAG_FUJIFILM_MACRO = 0x1020; // 4128 44 public static final int TAG_FUJIFILM_FOCUS_MODE = 0x1021; // 4129 45 public static final int TAG_FUJIFILM_SLOW_SYNCH = 0x1030; // 4144 46 public static final int TAG_FUJIFILM_PICTURE_MODE = 0x1031; // 4145 47 public static final int TAG_FUJIFILM_UNKNOWN_1 = 0x1032; // 4146 48 public static final int TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING = 0x1100; // 4352 49 public static final int TAG_FUJIFILM_UNKNOWN_2 = 0x1200; // 4608 50 public static final int TAG_FUJIFILM_BLUR_WARNING = 0x1300; // 4864 51 public static final int TAG_FUJIFILM_FOCUS_WARNING = 0x1301; // 4865 52 public static final int TAG_FUJIFILM_AE_WARNING = 0x1302; // 4866 46 53 47 protected static final HashMap tagNameMap = new HashMap(); 54 @NotNull 55 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 48 56 49 57 static 50 58 { 51 tagNameMap.put( new Integer(TAG_FUJIFILM_AE_WARNING), "AE Warning");52 tagNameMap.put( new Integer(TAG_FUJIFILM_BLUR_WARNING), "Blur Warning");53 tagNameMap.put( new Integer(TAG_FUJIFILM_COLOR), "Color");54 tagNameMap.put( new Integer(TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING), "Continuous Taking Or Auto Bracketting");55 tagNameMap.put( new Integer(TAG_FUJIFILM_FLASH_MODE), "Flash Mode");56 tagNameMap.put( new Integer(TAG_FUJIFILM_FLASH_STRENGTH), "Flash Strength");57 tagNameMap.put( new Integer(TAG_FUJIFILM_FOCUS_MODE), "FocusMode");58 tagNameMap.put( new Integer(TAG_FUJIFILM_FOCUS_WARNING), "Focus Warning");59 tagNameMap.put (new Integer(TAG_FUJIFILM_MACRO), "Macro");60 tagNameMap.put( new Integer(TAG_FUJIFILM_MAKERNOTE_VERSION), "Makernote Version");61 tagNameMap.put( new Integer(TAG_FUJIFILM_PICTURE_MODE), "Picture Mode");62 tagNameMap.put( new Integer(TAG_FUJIFILM_QUALITY), "Quality");63 tagNameMap.put( new Integer(TAG_FUJIFILM_SHARPNESS), "Sharpness");64 tagNameMap.put( new Integer(TAG_FUJIFILM_SLOW_SYNCHRO), "Slow Synchro");65 tagNameMap.put( new Integer(TAG_FUJIFILM_TONE), "Tone");66 tagNameMap.put( new Integer(TAG_FUJIFILM_UNKNOWN_1), "Makernote Unknown 1");67 tagNameMap.put( new Integer(TAG_FUJIFILM_UNKNOWN_2), "Makernote Unknown 2");68 tagNameMap.put( new Integer(TAG_FUJIFILM_WHITE_BALANCE), "White Balance");59 _tagNameMap.put(TAG_FUJIFILM_MAKERNOTE_VERSION, "Makernote Version"); 60 _tagNameMap.put(TAG_FUJIFILM_QUALITY, "Quality"); 61 _tagNameMap.put(TAG_FUJIFILM_SHARPNESS, "Sharpness"); 62 _tagNameMap.put(TAG_FUJIFILM_WHITE_BALANCE, "White Balance"); 63 _tagNameMap.put(TAG_FUJIFILM_COLOR_SATURATION, "Color Saturation"); 64 _tagNameMap.put(TAG_FUJIFILM_TONE, "Tone (Contrast)"); 65 _tagNameMap.put(TAG_FUJIFILM_FLASH_MODE, "Flash Mode"); 66 _tagNameMap.put(TAG_FUJIFILM_FLASH_STRENGTH, "Flash Strength"); 67 _tagNameMap.put(TAG_FUJIFILM_MACRO, "Macro"); 68 _tagNameMap.put(TAG_FUJIFILM_FOCUS_MODE, "Focus Mode"); 69 _tagNameMap.put(TAG_FUJIFILM_SLOW_SYNCH, "Slow Synch"); 70 _tagNameMap.put(TAG_FUJIFILM_PICTURE_MODE, "Picture Mode"); 71 _tagNameMap.put(TAG_FUJIFILM_UNKNOWN_1, "Makernote Unknown 1"); 72 _tagNameMap.put(TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING, "Continuous Taking Or Auto Bracketting"); 73 _tagNameMap.put(TAG_FUJIFILM_UNKNOWN_2, "Makernote Unknown 2"); 74 _tagNameMap.put(TAG_FUJIFILM_BLUR_WARNING, "Blur Warning"); 75 _tagNameMap.put(TAG_FUJIFILM_FOCUS_WARNING, "Focus Warning"); 76 _tagNameMap.put(TAG_FUJIFILM_AE_WARNING, "AE Warning"); 69 77 } 70 78 … … 74 82 } 75 83 84 @NotNull 76 85 public String getName() 77 86 { … … 79 88 } 80 89 81 protected HashMap getTagNameMap() 90 @NotNull 91 protected HashMap<Integer, String> getTagNameMap() 82 92 { 83 return tagNameMap; 93 return _tagNameMap; 84 94 } 85 95 } -
trunk/src/com/drew/metadata/exif/GpsDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 12-Nov-2002 22:27:52 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.GeoLocation; 19 24 import com.drew.lang.Rational; 20 import com.drew. metadata.Directory;21 import com.drew. metadata.MetadataException;25 import com.drew.lang.annotations.NotNull; 26 import com.drew.lang.annotations.Nullable; 22 27 import com.drew.metadata.TagDescriptor; 23 28 29 import java.text.DecimalFormat; 30 24 31 /** 25 * 32 * Provides human-readable string representations of tag values stored in a <code>GpsDirectory</code>. 33 * 34 * @author Drew Noakes http://drewnoakes.com 26 35 */ 27 public class GpsDescriptor extends TagDescriptor 36 public class GpsDescriptor extends TagDescriptor<GpsDirectory> 28 37 { 29 public GpsDescriptor(Directory directory) 38 public GpsDescriptor(@NotNull GpsDirectory directory) 30 39 { 31 40 super(directory); 32 41 } 33 42 34 public String getDescription(int tagType) throws MetadataException 43 @Nullable 44 public String getDescription(int tagType) 35 45 { 36 46 switch (tagType) { 47 case GpsDirectory.TAG_GPS_VERSION_ID: 48 return getGpsVersionIdDescription(); 37 49 case GpsDirectory.TAG_GPS_ALTITUDE: 38 50 return getGpsAltitudeDescription(); … … 57 69 case GpsDirectory.TAG_GPS_TIME_STAMP: 58 70 return getGpsTimeStampDescription(); 71 case GpsDirectory.TAG_GPS_LONGITUDE: 59 72 // three rational numbers -- displayed in HH"MM"SS.ss 60 case GpsDirectory.TAG_GPS_LONGITUDE:61 73 return getGpsLongitudeDescription(); 62 74 case GpsDirectory.TAG_GPS_LATITUDE: 75 // three rational numbers -- displayed in HH"MM"SS.ss 63 76 return getGpsLatitudeDescription(); 77 case GpsDirectory.TAG_GPS_DIFFERENTIAL: 78 return getGpsDifferentialDescription(); 64 79 default: 65 return _directory.getString(tagType); 66 } 67 } 68 69 public String getGpsLatitudeDescription() throws MetadataException 70 { 71 if (!_directory.containsTag(GpsDirectory.TAG_GPS_LATITUDE)) return null; 72 return getHoursMinutesSecondsDescription(GpsDirectory.TAG_GPS_LATITUDE); 73 } 74 75 public String getGpsLongitudeDescription() throws MetadataException 76 { 77 if (!_directory.containsTag(GpsDirectory.TAG_GPS_LONGITUDE)) return null; 78 return getHoursMinutesSecondsDescription(GpsDirectory.TAG_GPS_LONGITUDE); 79 } 80 81 public String getHoursMinutesSecondsDescription(int tagType) throws MetadataException 82 { 83 Rational[] components = _directory.getRationalArray(tagType); 84 // TODO create an HoursMinutesSecods class ?? 85 int deg = components[0].intValue(); 86 float min = components[1].floatValue(); 87 float sec = components[2].floatValue(); 88 // carry fractions of minutes into seconds -- thanks Colin Briton 89 sec += (min % 1) * 60; 90 return String.valueOf(deg) + "\"" + String.valueOf((int)min) + "'" + String.valueOf(sec); 91 } 92 93 public String getGpsTimeStampDescription() throws MetadataException 80 return super.getDescription(tagType); 81 } 82 } 83 84 @Nullable 85 private String getGpsVersionIdDescription() 86 { 87 return convertBytesToVersionString(_directory.getIntArray(GpsDirectory.TAG_GPS_VERSION_ID), 1); 88 } 89 90 @Nullable 91 public String getGpsLatitudeDescription() 92 { 93 GeoLocation location = _directory.getGeoLocation(); 94 95 if (location == null) 96 return null; 97 98 return GeoLocation.decimalToDegreesMinutesSecondsString(location.getLatitude()); 99 } 100 101 @Nullable 102 public String getGpsLongitudeDescription() 103 { 104 GeoLocation location = _directory.getGeoLocation(); 105 106 if (location == null) 107 return null; 108 109 return GeoLocation.decimalToDegreesMinutesSecondsString(location.getLongitude()); 110 } 111 112 @Nullable 113 public String getGpsTimeStampDescription() 94 114 { 95 115 // time in hour, min, sec 96 if (!_directory.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP)) return null;97 116 int[] timeComponents = _directory.getIntArray(GpsDirectory.TAG_GPS_TIME_STAMP); 98 StringBuffer sbuffer = new StringBuffer(); 99 sbuffer.append(timeComponents[0]); 100 sbuffer.append(":"); 101 sbuffer.append(timeComponents[1]); 102 sbuffer.append(":"); 103 sbuffer.append(timeComponents[2]); 104 sbuffer.append(" UTC"); 105 return sbuffer.toString(); 106 } 107 117 if (timeComponents==null) 118 return null; 119 StringBuilder description = new StringBuilder(); 120 description.append(timeComponents[0]); 121 description.append(":"); 122 description.append(timeComponents[1]); 123 description.append(":"); 124 description.append(timeComponents[2]); 125 description.append(" UTC"); 126 return description.toString(); 127 } 128 129 @Nullable 108 130 public String getGpsDestinationReferenceDescription() 109 131 { 110 if (!_directory.containsTag(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF)) return null; 111 String destRef = _directory.getString(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF).trim(); 112 if ("K".equalsIgnoreCase(destRef)) { 132 final String value = _directory.getString(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF); 133 if (value==null) 134 return null; 135 String distanceRef = value.trim(); 136 if ("K".equalsIgnoreCase(distanceRef)) { 113 137 return "kilometers"; 114 } else if ("M".equalsIgnoreCase(d estRef)) {138 } else if ("M".equalsIgnoreCase(distanceRef)) { 115 139 return "miles"; 116 } else if ("N".equalsIgnoreCase(d estRef)) {140 } else if ("N".equalsIgnoreCase(distanceRef)) { 117 141 return "knots"; 118 142 } else { 119 return "Unknown (" + destRef + ")"; 120 } 121 } 122 143 return "Unknown (" + distanceRef + ")"; 144 } 145 } 146 147 @Nullable 123 148 public String getGpsDirectionDescription(int tagType) 124 149 { 125 if (!_directory.containsTag(tagType)) return null; 126 String gpsDirection = _directory.getString(tagType).trim(); 127 return gpsDirection + " degrees"; 128 } 129 150 Rational angle = _directory.getRational(tagType); 151 // provide a decimal version of rational numbers in the description, to avoid strings like "35334/199 degrees" 152 String value = angle != null 153 ? new DecimalFormat("0.##").format(angle.doubleValue()) 154 : _directory.getString(tagType); 155 if (value==null || value.trim().length()==0) 156 return null; 157 return value.trim() + " degrees"; 158 } 159 160 @Nullable 130 161 public String getGpsDirectionReferenceDescription(int tagType) 131 162 { 132 if (!_directory.containsTag(tagType)) return null; 133 String gpsDistRef = _directory.getString(tagType).trim(); 163 final String value = _directory.getString(tagType); 164 if (value==null) 165 return null; 166 String gpsDistRef = value.trim(); 134 167 if ("T".equalsIgnoreCase(gpsDistRef)) { 135 168 return "True direction"; … … 141 174 } 142 175 176 @Nullable 143 177 public String getGpsSpeedRefDescription() 144 178 { 145 if (!_directory.containsTag(GpsDirectory.TAG_GPS_SPEED_REF)) return null; 146 String gpsSpeedRef = _directory.getString(GpsDirectory.TAG_GPS_SPEED_REF).trim(); 179 final String value = _directory.getString(GpsDirectory.TAG_GPS_SPEED_REF); 180 if (value==null) 181 return null; 182 String gpsSpeedRef = value.trim(); 147 183 if ("K".equalsIgnoreCase(gpsSpeedRef)) { 148 184 return "kph"; … … 156 192 } 157 193 194 @Nullable 158 195 public String getGpsMeasureModeDescription() 159 196 { 160 if (!_directory.containsTag(GpsDirectory.TAG_GPS_MEASURE_MODE)) return null; 161 String gpsSpeedMeasureMode = _directory.getString(GpsDirectory.TAG_GPS_MEASURE_MODE).trim(); 197 final String value = _directory.getString(GpsDirectory.TAG_GPS_MEASURE_MODE); 198 if (value==null) 199 return null; 200 String gpsSpeedMeasureMode = value.trim(); 162 201 if ("2".equalsIgnoreCase(gpsSpeedMeasureMode)) { 163 202 return "2-dimensional measurement"; … … 169 208 } 170 209 210 @Nullable 171 211 public String getGpsStatusDescription() 172 212 { 173 if (!_directory.containsTag(GpsDirectory.TAG_GPS_STATUS)) return null; 174 String gpsStatus = _directory.getString(GpsDirectory.TAG_GPS_STATUS).trim(); 213 final String value = _directory.getString(GpsDirectory.TAG_GPS_STATUS); 214 if (value==null) 215 return null; 216 String gpsStatus = value.trim(); 175 217 if ("A".equalsIgnoreCase(gpsStatus)) { 176 return "Measurement in prog ess";218 return "Active (Measurement in progress)"; 177 219 } else if ("V".equalsIgnoreCase(gpsStatus)) { 178 return "Measurement Interoperability"; 220 return "Void (Measurement Interoperability)"; 179 221 } else { 180 222 return "Unknown (" + gpsStatus + ")"; … … 182 224 } 183 225 184 public String getGpsAltitudeRefDescription() throws MetadataException 185 { 186 if (!_directory.containsTag(GpsDirectory.TAG_GPS_ALTITUDE_REF)) return null; 187 int alititudeRef = _directory.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF); 188 if (alititudeRef == 0) { 226 @Nullable 227 public String getGpsAltitudeRefDescription() 228 { 229 Integer value = _directory.getInteger(GpsDirectory.TAG_GPS_ALTITUDE_REF); 230 if (value==null) 231 return null; 232 if (value == 0) 189 233 return "Sea level"; 190 } else { 191 return "Unknown (" + alititudeRef + ")"; 192 } 193 } 194 195 public String getGpsAltitudeDescription() throws MetadataException 196 { 197 if (!_directory.containsTag(GpsDirectory.TAG_GPS_ALTITUDE)) return null; 198 String alititude = _directory.getRational(GpsDirectory.TAG_GPS_ALTITUDE).toSimpleString(true); 199 return alititude + " metres"; 234 if (value == 1) 235 return "Below sea level"; 236 return "Unknown (" + value + ")"; 237 } 238 239 @Nullable 240 public String getGpsAltitudeDescription() 241 { 242 final Rational value = _directory.getRational(GpsDirectory.TAG_GPS_ALTITUDE); 243 if (value==null) 244 return null; 245 return value.intValue() + " metres"; 246 } 247 248 @Nullable 249 public String getGpsDifferentialDescription() 250 { 251 final Integer value = _directory.getInteger(GpsDirectory.TAG_GPS_DIFFERENTIAL); 252 if (value==null) 253 return null; 254 if (value == 0) 255 return "No Correction"; 256 if (value == 1) 257 return "Differential Corrected"; 258 return "Unknown (" + value + ")"; 259 } 260 261 @Nullable 262 public String getDegreesMinutesSecondsDescription() 263 { 264 GeoLocation location = _directory.getGeoLocation(); 265 266 if (location == null) 267 return null; 268 269 return location.toDMSString(); 200 270 } 201 271 } -
trunk/src/com/drew/metadata/exif/GpsDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 26-Nov-2002 11:00:52 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.GeoLocation; 24 import com.drew.lang.Rational; 25 import com.drew.lang.annotations.NotNull; 26 import com.drew.lang.annotations.Nullable; 19 27 import com.drew.metadata.Directory; 20 28 … … 22 30 23 31 /** 32 * Describes Exif tags that contain Global Positioning System (GPS) data. 24 33 * 34 * @author Drew Noakes http://drewnoakes.com 25 35 */ 26 36 public class GpsDirectory extends Directory … … 81 91 public static final int TAG_GPS_DEST_DISTANCE = 0x001A; 82 92 83 protected static final HashMap tagNameMap = new HashMap(); 93 /** Values of "GPS", "CELLID", "WLAN" or "MANUAL" by the EXIF spec. */ 94 public static final int TAG_GPS_PROCESSING_METHOD = 0x001B; 95 public static final int TAG_GPS_AREA_INFORMATION = 0x001C; 96 public static final int TAG_GPS_DATE_STAMP = 0x001D; 97 public static final int TAG_GPS_DIFFERENTIAL = 0x001E; 98 99 @NotNull 100 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 84 101 85 102 static 86 103 { 87 tagNameMap.put(new Integer(TAG_GPS_VERSION_ID), "GPS Version ID"); 88 tagNameMap.put(new Integer(TAG_GPS_LATITUDE_REF), "GPS Latitude Ref"); 89 tagNameMap.put(new Integer(TAG_GPS_LATITUDE), "GPS Latitude"); 90 tagNameMap.put(new Integer(TAG_GPS_LONGITUDE_REF), "GPS Longitude Ref"); 91 tagNameMap.put(new Integer(TAG_GPS_LONGITUDE), "GPS Longitude"); 92 tagNameMap.put(new Integer(TAG_GPS_ALTITUDE_REF), "GPS Altitude Ref"); 93 tagNameMap.put(new Integer(TAG_GPS_ALTITUDE), "GPS Altitude"); 94 tagNameMap.put(new Integer(TAG_GPS_TIME_STAMP), "GPS Time-Stamp"); 95 tagNameMap.put(new Integer(TAG_GPS_SATELLITES), "GPS Satellites"); 96 tagNameMap.put(new Integer(TAG_GPS_STATUS), "GPS Status"); 97 tagNameMap.put(new Integer(TAG_GPS_MEASURE_MODE), "GPS Measure Mode"); 98 tagNameMap.put(new Integer(TAG_GPS_DOP), "GPS DOP"); 99 tagNameMap.put(new Integer(TAG_GPS_SPEED_REF), "GPS Speed Ref"); 100 tagNameMap.put(new Integer(TAG_GPS_SPEED), "GPS Speed"); 101 tagNameMap.put(new Integer(TAG_GPS_TRACK_REF), "GPS Track Ref"); 102 tagNameMap.put(new Integer(TAG_GPS_TRACK), "GPS Track"); 103 tagNameMap.put(new Integer(TAG_GPS_IMG_DIRECTION_REF), "GPS Img Direction Ref"); 104 tagNameMap.put(new Integer(TAG_GPS_IMG_DIRECTION_REF), "GPS Img Direction"); 105 tagNameMap.put(new Integer(TAG_GPS_MAP_DATUM), "GPS Map Datum"); 106 tagNameMap.put(new Integer(TAG_GPS_DEST_LATITUDE_REF), "GPS Dest Latitude Ref"); 107 tagNameMap.put(new Integer(TAG_GPS_DEST_LATITUDE), "GPS Dest Latitude"); 108 tagNameMap.put(new Integer(TAG_GPS_DEST_LONGITUDE_REF), "GPS Dest Longitude Ref"); 109 tagNameMap.put(new Integer(TAG_GPS_DEST_LONGITUDE), "GPS Dest Longitude"); 110 tagNameMap.put(new Integer(TAG_GPS_DEST_BEARING_REF), "GPS Dest Bearing Ref"); 111 tagNameMap.put(new Integer(TAG_GPS_DEST_BEARING), "GPS Dest Bearing"); 112 tagNameMap.put(new Integer(TAG_GPS_DEST_DISTANCE_REF), "GPS Dest Distance Ref"); 113 tagNameMap.put(new Integer(TAG_GPS_DEST_DISTANCE), "GPS Dest Distance"); 104 _tagNameMap.put(TAG_GPS_VERSION_ID, "GPS Version ID"); 105 _tagNameMap.put(TAG_GPS_LATITUDE_REF, "GPS Latitude Ref"); 106 _tagNameMap.put(TAG_GPS_LATITUDE, "GPS Latitude"); 107 _tagNameMap.put(TAG_GPS_LONGITUDE_REF, "GPS Longitude Ref"); 108 _tagNameMap.put(TAG_GPS_LONGITUDE, "GPS Longitude"); 109 _tagNameMap.put(TAG_GPS_ALTITUDE_REF, "GPS Altitude Ref"); 110 _tagNameMap.put(TAG_GPS_ALTITUDE, "GPS Altitude"); 111 _tagNameMap.put(TAG_GPS_TIME_STAMP, "GPS Time-Stamp"); 112 _tagNameMap.put(TAG_GPS_SATELLITES, "GPS Satellites"); 113 _tagNameMap.put(TAG_GPS_STATUS, "GPS Status"); 114 _tagNameMap.put(TAG_GPS_MEASURE_MODE, "GPS Measure Mode"); 115 _tagNameMap.put(TAG_GPS_DOP, "GPS DOP"); 116 _tagNameMap.put(TAG_GPS_SPEED_REF, "GPS Speed Ref"); 117 _tagNameMap.put(TAG_GPS_SPEED, "GPS Speed"); 118 _tagNameMap.put(TAG_GPS_TRACK_REF, "GPS Track Ref"); 119 _tagNameMap.put(TAG_GPS_TRACK, "GPS Track"); 120 _tagNameMap.put(TAG_GPS_IMG_DIRECTION_REF, "GPS Img Direction Ref"); 121 _tagNameMap.put(TAG_GPS_IMG_DIRECTION, "GPS Img Direction"); 122 _tagNameMap.put(TAG_GPS_MAP_DATUM, "GPS Map Datum"); 123 _tagNameMap.put(TAG_GPS_DEST_LATITUDE_REF, "GPS Dest Latitude Ref"); 124 _tagNameMap.put(TAG_GPS_DEST_LATITUDE, "GPS Dest Latitude"); 125 _tagNameMap.put(TAG_GPS_DEST_LONGITUDE_REF, "GPS Dest Longitude Ref"); 126 _tagNameMap.put(TAG_GPS_DEST_LONGITUDE, "GPS Dest Longitude"); 127 _tagNameMap.put(TAG_GPS_DEST_BEARING_REF, "GPS Dest Bearing Ref"); 128 _tagNameMap.put(TAG_GPS_DEST_BEARING, "GPS Dest Bearing"); 129 _tagNameMap.put(TAG_GPS_DEST_DISTANCE_REF, "GPS Dest Distance Ref"); 130 _tagNameMap.put(TAG_GPS_DEST_DISTANCE, "GPS Dest Distance"); 131 _tagNameMap.put(TAG_GPS_PROCESSING_METHOD, "GPS Processing Method"); 132 _tagNameMap.put(TAG_GPS_AREA_INFORMATION, "GPS Area Information"); 133 _tagNameMap.put(TAG_GPS_DATE_STAMP, "GPS Date Stamp"); 134 _tagNameMap.put(TAG_GPS_DIFFERENTIAL, "GPS Differential"); 114 135 } 115 136 … … 119 140 } 120 141 142 @NotNull 121 143 public String getName() 122 144 { … … 124 146 } 125 147 126 protected HashMap getTagNameMap() 148 @NotNull 149 protected HashMap<Integer, String> getTagNameMap() 127 150 { 128 return tagNameMap; 151 return _tagNameMap; 152 } 153 154 /** 155 * Parses various tags in an attempt to obtain a single object representing the latitude and longitude 156 * at which this image was captured. 157 * 158 * @return The geographical location of this image, if possible, otherwise null 159 */ 160 @Nullable 161 public GeoLocation getGeoLocation() 162 { 163 Rational[] latitudes = getRationalArray(GpsDirectory.TAG_GPS_LATITUDE); 164 Rational[] longitudes = getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE); 165 String latitudeRef = getString(GpsDirectory.TAG_GPS_LATITUDE_REF); 166 String longitudeRef = getString(GpsDirectory.TAG_GPS_LONGITUDE_REF); 167 168 // Make sure we have the required values 169 if (latitudes == null || latitudes.length != 3) 170 return null; 171 if (longitudes == null || longitudes.length != 3) 172 return null; 173 if (latitudeRef == null || longitudeRef == null) 174 return null; 175 176 Double lat = GeoLocation.degreesMinutesSecondsToDecimal(latitudes[0], latitudes[1], latitudes[2], latitudeRef.equalsIgnoreCase("S")); 177 Double lon = GeoLocation.degreesMinutesSecondsToDecimal(longitudes[0], longitudes[1], longitudes[2], longitudeRef.equalsIgnoreCase("W")); 178 179 // This can return null, in cases where the conversion was not possible 180 if (lat == null || lon == null) 181 return null; 182 183 return new GeoLocation(lat, lon); 129 184 } 130 185 } -
trunk/src/com/drew/metadata/exif/KodakMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 import com.drew.metadata.Directory; 18 import com.drew.metadata.MetadataException; 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.TagDescriptor; 20 25 21 26 /** 22 * Provides human-readable string versions of the tags stored in a KodakMakernoteDirectory. 27 * Provides human-readable string representations of tag values stored in a <code>KodakMakernoteDirectory</code>. 28 * 23 29 * Thanks to David Carson for the initial version of this class. 30 * 31 * @author Drew Noakes http://drewnoakes.com 24 32 */ 25 public class KodakMakernoteDescriptor extends TagDescriptor 33 public class KodakMakernoteDescriptor extends TagDescriptor<KodakMakernoteDirectory> 26 34 { 27 public KodakMakernoteDescriptor(Directory directory) 28 { 29 super(directory); 30 } 31 32 public String getDescription(int tagType) throws MetadataException 35 public KodakMakernoteDescriptor(@NotNull KodakMakernoteDirectory directory) 33 36 { 34 return _directory.getString(tagType);35 37 super(directory); 38 } 36 39 } -
trunk/src/com/drew/metadata/exif/KodakMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 23 import com.drew.lang.annotations.NotNull; 17 24 import com.drew.metadata.Directory; 18 25 … … 21 28 /** 22 29 * Describes tags specific to Kodak cameras. 30 * 31 * @author Drew Noakes http://drewnoakes.com 23 32 */ 24 33 public class KodakMakernoteDirectory extends Directory 25 34 { 26 protected static final HashMap _tagNameMap = new HashMap(); 27 28 public String getName() 35 @NotNull 36 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 37 38 public KodakMakernoteDirectory() 29 39 { 30 return "KodakMakernote";31 40 this.setDescriptor(new KodakMakernoteDescriptor(this)); 41 } 32 42 33 protected HashMap getTagNameMap() 43 @NotNull 44 public String getName() 34 45 { 35 return _tagNameMap; 36 } 46 return "Kodak Makernote"; 47 } 48 49 @NotNull 50 protected HashMap<Integer, String> getTagNameMap() 51 { 52 return _tagNameMap; 53 } 37 54 } -
trunk/src/com/drew/metadata/exif/KyoceraMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 import com.drew. metadata.Directory;18 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 19 25 import com.drew.metadata.TagDescriptor; 20 26 21 27 /** 22 * Provides human-readable string versions of the tags stored in a KyoceraMakernoteDirectory.23 * 28 * Provides human-readable string representations of tag values stored in a <code>KyoceraMakernoteDirectory</code>. 29 * <p/> 24 30 * Some information about this makernote taken from here: 25 31 * http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html 26 * 32 * <p/> 27 33 * Most manufacturer's MakerNote counts the "offset to data" from the first byte 28 34 * of TIFF header (same as the other IFD), but Kyocera (along with Fujifilm) counts 29 35 * it from the first byte of MakerNote itself. 36 * 37 * @author Drew Noakes http://drewnoakes.com 30 38 */ 31 public class KyoceraMakernoteDescriptor extends TagDescriptor 39 public class KyoceraMakernoteDescriptor extends TagDescriptor<KyoceraMakernoteDirectory> 32 40 { 33 public KyoceraMakernoteDescriptor(Directory directory) 41 public KyoceraMakernoteDescriptor(@NotNull KyoceraMakernoteDirectory directory) 34 42 { 35 43 super(directory); 36 44 } 37 45 38 public String getDescription(int tagType) throws MetadataException 46 @Nullable 47 public String getDescription(int tagType) 39 48 { 40 49 switch (tagType) { … … 44 53 return getProprietaryThumbnailDataDescription(); 45 54 default: 46 return _directory.getString(tagType);55 return super.getDescription(tagType); 47 56 } 48 57 } 49 58 50 public String getPrintImageMatchingInfoDescription() throws MetadataException 59 @Nullable 60 public String getPrintImageMatchingInfoDescription() 51 61 { 52 if (!_directory.containsTag(KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO)) return null;53 62 byte[] bytes = _directory.getByteArray(KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO); 63 if (bytes==null) 64 return null; 54 65 return "(" + bytes.length + " bytes)"; 55 66 } 56 67 57 public String getProprietaryThumbnailDataDescription() throws MetadataException 68 @Nullable 69 public String getProprietaryThumbnailDataDescription() 58 70 { 59 if (!_directory.containsTag(KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL)) return null;60 71 byte[] bytes = _directory.getByteArray(KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL); 72 if (bytes==null) 73 return null; 61 74 return "(" + bytes.length + " bytes)"; 62 75 } -
trunk/src/com/drew/metadata/exif/KyoceraMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 29 * Describes tags specific to Kyocera and Contax cameras. 24 30 * 31 * @author Drew Noakes http://drewnoakes.com 25 32 */ 26 33 public class KyoceraMakernoteDirectory extends Directory … … 29 36 public static final int TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO = 0x0E00; 30 37 31 protected static final HashMap tagNameMap = new HashMap(); 38 @NotNull 39 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 32 40 33 41 static 34 42 { 35 tagNameMap.put (new Integer(TAG_KYOCERA_PROPRIETARY_THUMBNAIL), "Proprietary Thumbnail Format Data");36 tagNameMap.put (new Integer(TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");43 _tagNameMap.put(TAG_KYOCERA_PROPRIETARY_THUMBNAIL, "Proprietary Thumbnail Format Data"); 44 _tagNameMap.put(TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info"); 37 45 } 38 46 … … 42 50 } 43 51 52 @NotNull 44 53 public String getName() 45 54 { … … 47 56 } 48 57 49 protected HashMap getTagNameMap() 58 @NotNull 59 protected HashMap<Integer, String> getTagNameMap() 50 60 { 51 return tagNameMap; 61 return _tagNameMap; 52 62 } 53 63 } -
trunk/src/com/drew/metadata/exif/NikonType1MakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 23 import com.drew.lang.Rational; 18 import com.drew. metadata.Directory;19 import com.drew. metadata.MetadataException;24 import com.drew.lang.annotations.NotNull; 25 import com.drew.lang.annotations.Nullable; 20 26 import com.drew.metadata.TagDescriptor; 21 27 22 28 /** 23 * Provides human-readable string versions of the tags stored in a NikonType1MakernoteDirectory. 29 * Provides human-readable string representations of tag values stored in a <code>NikonType1MakernoteDirectory</code>. 30 * <p/> 24 31 * Type-1 is for E-Series cameras prior to (not including) E990. For example: E700, E800, E900, 25 32 * E900S, E910, E950. 26 * 33 * <p/> 27 34 * MakerNote starts from ASCII string "Nikon". Data format is the same as IFD, but it starts from 28 35 * offset 0x08. This is the same as Olympus except start string. Example of actual data … … 32 39 * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ 33 40 * </code></pre> 41 * 42 * @author Drew Noakes http://drewnoakes.com 34 43 */ 35 public class NikonType1MakernoteDescriptor extends TagDescriptor 44 public class NikonType1MakernoteDescriptor extends TagDescriptor<NikonType1MakernoteDirectory> 36 45 { 37 public NikonType1MakernoteDescriptor(Directory directory) 46 public NikonType1MakernoteDescriptor(@NotNull NikonType1MakernoteDirectory directory) 38 47 { 39 48 super(directory); 40 49 } 41 50 42 public String getDescription(int tagType) throws MetadataException 51 @Nullable 52 public String getDescription(int tagType) 43 53 { 44 54 switch (tagType) { … … 60 70 return getConverterDescription(); 61 71 default: 62 return _directory.getString(tagType); 63 } 64 } 65 66 public String getConverterDescription() throws MetadataException 67 { 68 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER)) return null; 69 int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER); 72 return super.getDescription(tagType); 73 } 74 } 75 76 @Nullable 77 public String getConverterDescription() 78 { 79 Integer value = _directory.getInteger(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER); 80 if (value == null) 81 return null; 70 82 switch (value) { 71 83 case 0: … … 78 90 } 79 91 80 public String getDigitalZoomDescription() throws MetadataException81 {82 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM)) return null;92 @Nullable 93 public String getDigitalZoomDescription() 94 { 83 95 Rational value = _directory.getRational(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM); 96 if (value == null) 97 return null; 84 98 if (value.getNumerator() == 0) { 85 99 return "No digital zoom"; … … 88 102 } 89 103 90 public String getFocusDescription() throws MetadataException91 {92 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS)) return null;104 @Nullable 105 public String getFocusDescription() 106 { 93 107 Rational value = _directory.getRational(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS); 108 if (value == null) 109 return null; 94 110 if (value.getNumerator() == 1 && value.getDenominator() == 0) { 95 111 return "Infinite"; … … 98 114 } 99 115 100 public String getWhiteBalanceDescription() throws MetadataException 101 { 102 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE)) return null; 103 int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE); 116 @Nullable 117 public String getWhiteBalanceDescription() 118 { 119 Integer value = _directory.getInteger(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE); 120 if (value == null) 121 return null; 104 122 switch (value) { 105 123 case 0: … … 110 128 return "Daylight"; 111 129 case 3: 112 return "Incandescen se";113 case 4: 114 return "Flo urescence";130 return "Incandescence"; 131 case 4: 132 return "Florescence"; 115 133 case 5: 116 134 return "Cloudy"; … … 122 140 } 123 141 124 public String getCcdSensitivityDescription() throws MetadataException 125 { 126 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY)) return null; 127 int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY); 142 @Nullable 143 public String getCcdSensitivityDescription() 144 { 145 Integer value = _directory.getInteger(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY); 146 if (value == null) 147 return null; 128 148 switch (value) { 129 149 case 0: … … 140 160 } 141 161 142 public String getImageAdjustmentDescription() throws MetadataException 143 { 144 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT)) return null; 145 int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT); 162 @Nullable 163 public String getImageAdjustmentDescription() 164 { 165 Integer value = _directory.getInteger(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT); 166 if (value == null) 167 return null; 146 168 switch (value) { 147 169 case 0: … … 160 182 } 161 183 162 public String getColorModeDescription() throws MetadataException 163 { 164 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE)) return null; 165 int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE); 184 @Nullable 185 public String getColorModeDescription() 186 { 187 Integer value = _directory.getInteger(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE); 188 if (value == null) 189 return null; 166 190 switch (value) { 167 191 case 1: … … 174 198 } 175 199 176 public String getQualityDescription() throws MetadataException 177 { 178 if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY)) return null; 179 int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY); 200 @Nullable 201 public String getQualityDescription() 202 { 203 Integer value = _directory.getInteger(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY); 204 if (value == null) 205 return null; 180 206 switch (value) { 181 207 case 1: -
trunk/src/com/drew/metadata/exif/NikonType1MakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 24 * Contains values specific to Nikon cameras. Type-1 is for E-Series cameras prior to (not including) E990.29 * Describes tags specific to Nikon (type 1) cameras. Type-1 is for E-Series cameras prior to (not including) E990. 25 30 * 26 31 * There are 3 formats of Nikon's MakerNote. MakerNote of E700/E800/E900/E900S/E910/E950 … … 32 37 * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ 33 38 * </code></pre> 39 * 40 * @author Drew Noakes http://drewnoakes.com 34 41 */ 35 42 public class NikonType1MakernoteDirectory extends Directory … … 47 54 public static final int TAG_NIKON_TYPE1_UNKNOWN_3 = 0x0F00; 48 55 49 protected static final HashMap _tagNameMap = new HashMap(); 56 @NotNull 57 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 50 58 51 59 static 52 60 { 53 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_CCD_SENSITIVITY), "CCD Sensitivity");54 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_COLOR_MODE), "Color Mode");55 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_DIGITAL_ZOOM), "Digital Zoom");56 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_CONVERTER), "Fisheye Converter");57 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_FOCUS), "Focus");58 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT), "Image Adjustment");59 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_QUALITY), "Quality");60 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_UNKNOWN_1), "Makernote Unknown 1");61 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_UNKNOWN_2), "Makernote Unknown 2");62 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_UNKNOWN_3), "Makernote Unknown 3");63 _tagNameMap.put( new Integer(TAG_NIKON_TYPE1_WHITE_BALANCE), "White Balance");61 _tagNameMap.put(TAG_NIKON_TYPE1_CCD_SENSITIVITY, "CCD Sensitivity"); 62 _tagNameMap.put(TAG_NIKON_TYPE1_COLOR_MODE, "Color Mode"); 63 _tagNameMap.put(TAG_NIKON_TYPE1_DIGITAL_ZOOM, "Digital Zoom"); 64 _tagNameMap.put(TAG_NIKON_TYPE1_CONVERTER, "Fisheye Converter"); 65 _tagNameMap.put(TAG_NIKON_TYPE1_FOCUS, "Focus"); 66 _tagNameMap.put(TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT, "Image Adjustment"); 67 _tagNameMap.put(TAG_NIKON_TYPE1_QUALITY, "Quality"); 68 _tagNameMap.put(TAG_NIKON_TYPE1_UNKNOWN_1, "Makernote Unknown 1"); 69 _tagNameMap.put(TAG_NIKON_TYPE1_UNKNOWN_2, "Makernote Unknown 2"); 70 _tagNameMap.put(TAG_NIKON_TYPE1_UNKNOWN_3, "Makernote Unknown 3"); 71 _tagNameMap.put(TAG_NIKON_TYPE1_WHITE_BALANCE, "White Balance"); 64 72 } 65 73 … … 69 77 } 70 78 79 @NotNull 71 80 public String getName() 72 81 { … … 74 83 } 75 84 76 protected HashMap getTagNameMap() 85 @NotNull 86 protected HashMap<Integer, String> getTagNameMap() 77 87 { 78 88 return _tagNameMap; -
trunk/src/com/drew/metadata/exif/NikonType2MakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 23 import com.drew.lang.Rational; 18 import com.drew.metadata.Directory; 19 import com.drew.metadata.MetadataException; 24 import com.drew.lang.StringUtil; 25 import com.drew.lang.annotations.NotNull; 26 import com.drew.lang.annotations.Nullable; 20 27 import com.drew.metadata.TagDescriptor; 21 28 22 29 import java.text.DecimalFormat; 30 import java.util.ArrayList; 31 import java.util.Collection; 32 import java.util.Date; 23 33 24 34 /** 25 * Provides human-readable string versions of the tags stored in a NikonType2MakernoteDirectory. 35 * Provides human-readable string representations of tag values stored in a <code>NikonType2MakernoteDirectory</code>. 36 * 26 37 * Type-2 applies to the E990 and D-series cameras such as the D1, D70 and D100. 38 * 39 * @author Drew Noakes http://drewnoakes.com 27 40 */ 28 public class NikonType2MakernoteDescriptor extends TagDescriptor 41 public class NikonType2MakernoteDescriptor extends TagDescriptor<NikonType2MakernoteDirectory> 29 42 { 30 public NikonType2MakernoteDescriptor(Directory directory) 43 public NikonType2MakernoteDescriptor(@NotNull NikonType2MakernoteDirectory directory) 31 44 { 32 45 super(directory); 33 46 } 34 47 35 private NikonType2MakernoteDirectory getMakernoteDirectory() 36 { 37 return (NikonType2MakernoteDirectory)_directory; 38 } 39 40 public String getDescription(int tagType) throws MetadataException 48 @Nullable 49 public String getDescription(int tagType) 41 50 { 42 51 switch (tagType) 43 52 { 53 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_PROGRAM_SHIFT: 54 return getProgramShiftDescription(); 55 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_DIFFERENCE: 56 return getExposureDifferenceDescription(); 44 57 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS: 45 58 return getLensDescription(); … … 50 63 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION: 51 64 return getAutoFlashCompensationDescription(); 65 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_EXPOSURE_COMPENSATION: 66 return getFlashExposureCompensationDescription(); 67 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_BRACKET_COMPENSATION: 68 return getFlashBracketCompensationDescription(); 69 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_TUNING: 70 return getExposureTuningDescription(); 71 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_STOPS: 72 return getLensStopsDescription(); 73 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_COLOR_SPACE: 74 return getColorSpaceDescription(); 75 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ACTIVE_D_LIGHTING: 76 return getActiveDLightingDescription(); 77 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_VIGNETTE_CONTROL: 78 return getVignetteControlDescription(); 52 79 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1: 53 80 return getIsoSettingDescription(); 54 81 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM: 55 82 return getDigitalZoomDescription(); 83 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_USED: 84 return getFlashUsedDescription(); 56 85 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION: 57 86 return getAutoFocusPositionDescription(); 58 87 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION: 59 return getAutoFirmwareVersionDescription(); 88 return getFirmwareVersionDescription(); 89 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_TYPE: 90 return getLensTypeDescription(); 91 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_SHOOTING_MODE: 92 return getShootingModeDescription(); 93 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_NEF_COMPRESSION: 94 return getNEFCompressionDescription(); 95 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_HIGH_ISO_NOISE_REDUCTION: 96 return getHighISONoiseReductionDescription(); 97 case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_POWER_UP_TIME: 98 return getPowerUpTimeDescription(); 60 99 default: 61 return _directory.getString(tagType); 62 } 63 } 64 65 public String getAutoFocusPositionDescription() throws MetadataException 66 { 67 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION)) return null; 100 return super.getDescription(tagType); 101 } 102 } 103 104 @Nullable 105 public String getPowerUpTimeDescription() 106 { 107 Long value = _directory.getLongObject(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_POWER_UP_TIME); 108 if (value==null) 109 return null; // TODO have observed a byte[8] here which is likely some kind of date (ticks as long?) 110 return new Date(value).toString(); 111 } 112 113 @Nullable 114 public String getHighISONoiseReductionDescription() 115 { 116 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_HIGH_ISO_NOISE_REDUCTION); 117 if (value==null) 118 return null; 119 switch (value) { 120 case 0: return "Off"; 121 case 1: return "Minimal"; 122 case 2: return "Low"; 123 case 4: return "Normal"; 124 case 6: return "High"; 125 default: return "Unknown (" + value + ")"; 126 } 127 } 128 129 @Nullable 130 public String getFlashUsedDescription() 131 { 132 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_USED); 133 if (value==null) 134 return null; 135 switch (value) { 136 case 0: return "Flash Not Used"; 137 case 1: return "Manual Flash"; 138 case 3: return "Flash Not Ready"; 139 case 7: return "External Flash"; 140 case 8: return "Fired, Commander Mode"; 141 case 9: return "Fired, TTL Mode"; 142 default: return "Unknown (" + value + ")"; 143 } 144 } 145 146 @Nullable 147 public String getNEFCompressionDescription() 148 { 149 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_NEF_COMPRESSION); 150 if (value==null) 151 return null; 152 switch (value) { 153 case 1: return "Lossy (Type 1)"; 154 case 3: return "Uncompressed"; 155 case 7: return "Lossless"; 156 case 8: return "Lossy (Type 2)"; 157 default: return "Unknown (" + value + ")"; 158 } 159 } 160 161 @Nullable 162 public String getShootingModeDescription() 163 { 164 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_SHOOTING_MODE); 165 if (value==null) 166 return null; 167 Collection<String> bits = new ArrayList<String>(); 168 169 if ((value&1)==1) 170 bits.add("Continuous"); 171 else 172 bits.add("Single Frame"); 173 174 if ((value&2)==2) 175 bits.add("Delay"); 176 // Don't know about 3 177 if ((value&8)==8) 178 bits.add("PC Control"); 179 if ((value&16)==16) 180 bits.add("Exposure Bracketing"); 181 if ((value&32)==32) 182 bits.add("Auto ISO"); 183 if ((value&64)==64) 184 bits.add("White-Balance Bracketing"); 185 if ((value&128)==128) 186 bits.add("IR Control"); 187 188 return StringUtil.join(bits, ", "); 189 } 190 191 @Nullable 192 public String getLensTypeDescription() 193 { 194 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_TYPE); 195 if (value==null) 196 return null; 197 198 Collection<String> bits = new ArrayList<String>(); 199 200 // TODO validate these values, as 14 is labelled as AF-C elsewhere but appears here as AF-D-G-VR 201 202 if ((value&1)==1) 203 bits.add("MF"); 204 else 205 bits.add("AF"); 206 207 if ((value&2)==2) 208 bits.add("D"); 209 210 if ((value&4)==4) 211 bits.add("G"); 212 213 if ((value&8)==8) 214 bits.add("VR"); 215 216 return StringUtil.join(bits, ", "); 217 } 218 219 @Nullable 220 public String getColorSpaceDescription() 221 { 222 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_COLOR_SPACE); 223 if (value==null) 224 return null; 225 switch (value) { 226 case 1: return "sRGB"; 227 case 2: return "Adobe RGB"; 228 default: return "Unknown (" + value + ")"; 229 } 230 } 231 232 @Nullable 233 public String getActiveDLightingDescription() 234 { 235 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ACTIVE_D_LIGHTING); 236 if (value==null) 237 return null; 238 switch (value) { 239 case 0: return "Off"; 240 case 1: return "Light"; 241 case 3: return "Normal"; 242 case 5: return "High"; 243 case 7: return "Extra High"; 244 case 65535: return "Auto"; 245 default: return "Unknown (" + value + ")"; 246 } 247 } 248 249 @Nullable 250 public String getVignetteControlDescription() 251 { 252 Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_VIGNETTE_CONTROL); 253 if (value==null) 254 return null; 255 switch (value) { 256 case 0: return "Off"; 257 case 1: return "Low"; 258 case 3: return "Normal"; 259 case 5: return "High"; 260 default: return "Unknown (" + value + ")"; 261 } 262 } 263 264 @Nullable 265 public String getAutoFocusPositionDescription() 266 { 68 267 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION); 268 if (values==null) 269 return null; 69 270 if (values.length != 4 || values[0] != 0 || values[2] != 0 || values[3] != 0) { 70 271 return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION) + ")"; … … 86 287 } 87 288 88 public String getDigitalZoomDescription() throws MetadataException 89 { 90 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM)) return null; 91 Rational rational = _directory.getRational(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM); 92 if (rational.intValue() == 1) { 93 return "No digital zoom"; 94 } 95 return rational.toSimpleString(true) + "x digital zoom"; 96 } 97 98 public String getIsoSettingDescription() throws MetadataException 99 { 100 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1)) return null; 289 @Nullable 290 public String getDigitalZoomDescription() 291 { 292 Rational value = _directory.getRational(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM); 293 if (value==null) 294 return null; 295 return value.intValue() == 1 296 ? "No digital zoom" 297 : value.toSimpleString(true) + "x digital zoom"; 298 } 299 300 @Nullable 301 public String getProgramShiftDescription() 302 { 303 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_PROGRAM_SHIFT); 304 return getEVDescription(values); 305 } 306 307 @Nullable 308 public String getExposureDifferenceDescription() 309 { 310 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_DIFFERENCE); 311 return getEVDescription(values); 312 } 313 314 @NotNull 315 public String getAutoFlashCompensationDescription() 316 { 317 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION); 318 return getEVDescription(values); 319 } 320 321 @NotNull 322 public String getFlashExposureCompensationDescription() 323 { 324 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_EXPOSURE_COMPENSATION); 325 return getEVDescription(values); 326 } 327 328 @NotNull 329 public String getFlashBracketCompensationDescription() 330 { 331 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_BRACKET_COMPENSATION); 332 return getEVDescription(values); 333 } 334 335 @NotNull 336 public String getExposureTuningDescription() 337 { 338 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_TUNING); 339 return getEVDescription(values); 340 } 341 342 @NotNull 343 public String getLensStopsDescription() 344 { 345 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_STOPS); 346 return getEVDescription(values); 347 } 348 349 @Nullable 350 private static String getEVDescription(@Nullable int[] values) 351 { 352 if (values==null) 353 return null; 354 if (values.length<3 || values[2]==0) 355 return null; 356 final DecimalFormat decimalFormat = new DecimalFormat("0.##"); 357 double ev = values[0] * values[1] / (double)values[2]; 358 return decimalFormat.format(ev) + " EV"; 359 } 360 361 @Nullable 362 public String getIsoSettingDescription() 363 { 101 364 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1); 102 if (values[0] != 0 || values[1] == 0) { 365 if (values==null) 366 return null; 367 if (values[0] != 0 || values[1] == 0) 103 368 return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1) + ")"; 104 }105 369 return "ISO " + values[1]; 106 370 } 107 371 108 public String getAutoFlashCompensationDescription() throws MetadataException 109 { 110 Rational ev = getMakernoteDirectory().getAutoFlashCompensation(); 111 112 if (ev==null) 113 return "Unknown"; 114 115 DecimalFormat decimalFormat = new DecimalFormat("0.##"); 116 return decimalFormat.format(ev.floatValue()) + " EV"; 117 } 118 119 public String getLensDescription() throws MetadataException 120 { 121 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS)) 122 return null; 123 124 Rational[] lensValues = _directory.getRationalArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS); 125 126 if (lensValues.length!=4) 372 @Nullable 373 public String getLensDescription() 374 { 375 Rational[] values = _directory.getRationalArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS); 376 377 if (values==null) 378 return null; 379 380 if (values.length<4) 127 381 return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS); 128 382 129 StringBu ffer description = new StringBuffer();130 description.append( lensValues[0].intValue());383 StringBuilder description = new StringBuilder(); 384 description.append(values[0].intValue()); 131 385 description.append('-'); 132 description.append( lensValues[1].intValue());386 description.append(values[1].intValue()); 133 387 description.append("mm f/"); 134 description.append( lensValues[2].floatValue());388 description.append(values[2].floatValue()); 135 389 description.append('-'); 136 description.append( lensValues[3].floatValue());390 description.append(values[3].floatValue()); 137 391 138 392 return description.toString(); 139 393 } 140 394 395 @Nullable 141 396 public String getHueAdjustmentDescription() 142 397 { 143 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT)) 144 return null; 145 146 return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT) + " degrees"; 147 } 148 398 final String value = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT); 399 if (value==null) 400 return null; 401 return value + " degrees"; 402 } 403 404 @Nullable 149 405 public String getColorModeDescription() 150 406 { 151 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE)) 152 return null; 153 154 String raw = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE); 155 if (raw.startsWith("MODE1")) 407 String value = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE); 408 if (value==null) 409 return null; 410 if (value.startsWith("MODE1")) 156 411 return "Mode I (sRGB)"; 157 158 return raw; 159 } 160 161 public String getAutoFirmwareVersionDescription() throws MetadataException 162 { 163 if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION)) 164 return null; 165 166 int[] ints = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION); 167 return ExifDescriptor.convertBytesToVersionString(ints); 412 return value; 413 } 414 415 @Nullable 416 public String getFirmwareVersionDescription() 417 { 418 int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION); 419 if (values==null) 420 return null; 421 return ExifSubIFDDescriptor.convertBytesToVersionString(values, 2); 168 422 } 169 423 } -
trunk/src/com/drew/metadata/exif/NikonType2MakernoteDirectory.java
r4258 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * metadata_extractor [at] drewnoakes [dot] com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 3-Oct-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 19 import com.drew.lang. Rational;23 import com.drew.lang.annotations.NotNull; 20 24 import com.drew.metadata.Directory; 21 import com.drew.metadata.MetadataException;22 25 23 26 import java.util.HashMap; … … 26 29 * Describes tags specific to Nikon (type 2) cameras. Type-2 applies to the E990 and D-series cameras such as the E990, D1, 27 30 * D70 and D100. 28 * 31 * <p/> 29 32 * Thanks to Fabrizio Giudici for publishing his reverse-engineering of the D100 makernote data. 30 33 * http://www.timelesswanderings.net/equipment/D100/NEF.html 31 * 34 * <p/> 32 35 * Note that the camera implements image protection (locking images) via the file's 'readonly' attribute. Similarly 33 36 * image hiding uses the 'hidden' attribute (observed on the D70). Consequently, these values are not available here. 34 * 37 * <p/> 35 38 * Additional sample images have been observed, and their tag values recorded in javadoc comments for each tag's field. 36 39 * New tags have subsequently been added since Fabrizio's observations. 37 * 40 * <p/> 38 41 * In earlier models (such as the E990 and D1), this directory begins at the first byte of the makernote IFD. In 39 42 * later models, the IFD was given the standard prefix to indicate the camera models (most other manufacturers also 40 43 * provide this prefix to aid in software decoding). 44 * 45 * @author Drew Noakes http://drewnoakes.com 41 46 */ 42 47 public class NikonType2MakernoteDirectory extends Directory … … 57 62 58 63 /** 59 * Values observed 60 * - COLOR (seen in the D1X) 64 * The camera's color mode, as an uppercase string. Examples include: 65 * <ul> 66 * <li><code>B & W</code></li> 67 * <li><code>COLOR</code></li> 68 * <li><code>COOL</code></li> 69 * <li><code>SEPIA</code></li> 70 * <li><code>VIVID</code></li> 71 * </ul> 61 72 */ 62 73 public static final int TAG_NIKON_TYPE2_COLOR_MODE = 0x0003; 63 74 64 75 /** 65 * Values observed 66 * - FILE 67 * - RAW 68 * - NORMAL 69 * - FINE 76 * The camera's quality setting, as an uppercase string. Examples include: 77 * <ul> 78 * <li><code>BASIC</code></li> 79 * <li><code>FINE</code></li> 80 * <li><code>NORMAL</code></li> 81 * <li><code>RAW</code></li> 82 * <li><code>RAW2.7M</code></li> 83 * </ul> 70 84 */ 71 85 public static final int TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT = 0x0004; 72 86 73 87 /** 74 * The white balance as set in the camera. 75 * 76 * Values observed 77 * - AUTO 78 * - SUNNY (D70) 79 * - FLASH (D1X) 80 * (presumably also SHADOW / INCANDESCENT / FLUORESCENT / CLOUDY) 88 * The camera's white balance setting, as an uppercase string. Examples include: 89 * 90 * <ul> 91 * <li><code>AUTO</code></li> 92 * <li><code>CLOUDY</code></li> 93 * <li><code>FLASH</code></li> 94 * <li><code>FLUORESCENT</code></li> 95 * <li><code>INCANDESCENT</code></li> 96 * <li><code>PRESET</code></li> 97 * <li><code>PRESET0</code></li> 98 * <li><code>PRESET1</code></li> 99 * <li><code>PRESET3</code></li> 100 * <li><code>SUNNY</code></li> 101 * <li><code>WHITE PRESET</code></li> 102 * <li><code>4350K</code></li> 103 * <li><code>5000K</code></li> 104 * <li><code>DAY WHITE FL</code></li> 105 * <li><code>SHADE</code></li> 106 * </ul> 81 107 */ 82 108 public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE = 0x0005; 83 109 84 110 /** 85 * The sharpening as set in the camera. 86 * 87 * Values observed 88 * - AUTO 89 * - NORMAL (D70) 90 * - NONE (D1X) 111 * The camera's sharpening setting, as an uppercase string. Examples include: 112 * 113 * <ul> 114 * <li><code>AUTO</code></li> 115 * <li><code>HIGH</code></li> 116 * <li><code>LOW</code></li> 117 * <li><code>NONE</code></li> 118 * <li><code>NORMAL</code></li> 119 * <li><code>MED.H</code></li> 120 * <li><code>MED.L</code></li> 121 * </ul> 91 122 */ 92 123 public static final int TAG_NIKON_TYPE2_CAMERA_SHARPENING = 0x0006; 93 124 94 125 /** 95 * The auto-focus type used by the camera. 96 * 97 * Values observed 98 * - AF-S 99 * - AF-C 100 * - MANUAL 126 * The camera's auto-focus mode, as an uppercase string. Examples include: 127 * 128 * <ul> 129 * <li><code>AF-C</code></li> 130 * <li><code>AF-S</code></li> 131 * <li><code>MANUAL</code></li> 132 * <li><code>AF-A</code></li> 133 * </ul> 101 134 */ 102 135 public static final int TAG_NIKON_TYPE2_AF_TYPE = 0x0007; 103 136 104 137 /** 105 * Values observed 106 * - NORMAL 107 * - RED-EYE 108 * 109 * Note: when TAG_NIKON_TYPE2_AUTO_FLASH_MODE is blank, Nikon Browser displays "Flash Sync Mode: Not Attached" 138 * The camera's flash setting, as an uppercase string. Examples include: 139 * 140 * <ul> 141 * <li><code></code></li> 142 * <li><code>NORMAL</code></li> 143 * <li><code>RED-EYE</code></li> 144 * <li><code>SLOW</code></li> 145 * <li><code>NEW_TTL</code></li> 146 * <li><code>REAR</code></li> 147 * <li><code>REAR SLOW</code></li> 148 * </ul> 149 * Note: when TAG_NIKON_TYPE2_AUTO_FLASH_MODE is blank (whitespace), Nikon Browser displays "Flash Sync Mode: Not Attached" 110 150 */ 111 151 public static final int TAG_NIKON_TYPE2_FLASH_SYNC_MODE = 0x0008; 112 152 113 153 /** 114 * Values observed 115 * - Built-in,TTL 116 * - Optional,TTL (with speedlight SB800, flash sync mode as NORMAL. NikonBrowser reports Auto Flash Comp: 0 EV -- which tag is that?) (D70) 117 * - NEW_TTL (Nikon Browser interprets as "D-TTL") 118 * - (blank -- accompanied FlashSyncMode of NORMAL) (D70) 154 * The type of flash used in the photograph, as a string. Examples include: 155 * 156 * <ul> 157 * <li><code></code></li> 158 * <li><code>Built-in,TTL</code></li> 159 * <li><code>NEW_TTL</code> Nikon Browser interprets as "D-TTL"</li> 160 * <li><code>Built-in,M</code></li> 161 * <li><code>Optional,TTL</code> with speedlight SB800, flash sync mode as "NORMAL"</li> 162 * </ul> 119 163 */ 120 164 public static final int TAG_NIKON_TYPE2_AUTO_FLASH_MODE = 0x0009; 121 165 122 166 /** 123 * Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. 167 * An unknown tag, as a rational. Several values given here: 168 * http://gvsoft.homedns.org/exif/makernote-nikon-type2.html#0x000b 124 169 */ 125 170 public static final int TAG_NIKON_TYPE2_UNKNOWN_34 = 0x000A; 126 171 127 172 /** 128 * Values observed 129 * - 0 173 * The camera's white balance bias setting, as an uint16 array having either one or two elements. 174 * 175 * <ul> 176 * <li><code>0</code></li> 177 * <li><code>1</code></li> 178 * <li><code>-3</code></li> 179 * <li><code>-2</code></li> 180 * <li><code>-1</code></li> 181 * <li><code>0,0</code></li> 182 * <li><code>1,0</code></li> 183 * <li><code>5,-5</code></li> 184 * </ul> 130 185 */ 131 186 public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE = 0x000B; … … 143 198 144 199 /** 145 * Values observed 146 * - 0,1,6,0 (hex) 147 */ 148 public static final int TAG_NIKON_TYPE2_UNKNOWN_1 = 0x000D; 149 150 /** 151 * Values observed 152 * - 0,1,c,0 (hex) 153 */ 154 public static final int TAG_NIKON_TYPE2_UNKNOWN_2 = 0x000E; 200 * The camera's program shift setting, as an array of four integers. 201 * The value, in EV, is calculated as <code>a*b/c</code>. 202 * 203 * <ul> 204 * <li><code>0,1,3,0</code> = 0 EV</li> 205 * <li><code>1,1,3,0</code> = 0.33 EV</li> 206 * <li><code>-3,1,3,0</code> = -1 EV</li> 207 * <li><code>1,1,2,0</code> = 0.5 EV</li> 208 * <li><code>2,1,6,0</code> = 0.33 EV</li> 209 * </ul> 210 */ 211 public static final int TAG_NIKON_TYPE2_PROGRAM_SHIFT = 0x000D; 212 213 /** 214 * The exposure difference, as an array of four integers. 215 * The value, in EV, is calculated as <code>a*b/c</code>. 216 * 217 * <ul> 218 * <li><code>-105,1,12,0</code> = -8.75 EV</li> 219 * <li><code>-72,1,12,0</code> = -6.00 EV</li> 220 * <li><code>-11,1,12,0</code> = -0.92 EV</li> 221 * </ul> 222 */ 223 public static final int TAG_NIKON_TYPE2_EXPOSURE_DIFFERENCE = 0x000E; 224 225 /** 226 * The camera's ISO mode, as an uppercase string. 227 * 228 * <ul> 229 * <li><code>AUTO</code></code></li> 230 * <li><code>MANUAL</code></li> 231 * </ul> 232 */ 233 public static final int TAG_NIKON_TYPE2_ISO_MODE = 0x000F; 155 234 156 235 /** 157 236 * Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. 158 237 */ 159 public static final int TAG_NIKON_TYPE2_ISO_SELECTION = 0x000F;160 161 /**162 * Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.163 */164 238 public static final int TAG_NIKON_TYPE2_DATA_DUMP = 0x0010; 165 239 166 240 /** 167 * Values observed 168 * - 914 169 * - 1379 (D70) 170 * - 2781 (D1X) 171 * - 6942 (D100) 172 */ 173 public static final int TAG_NIKON_TYPE2_UNKNOWN_3 = 0x0011; 174 175 /** 176 * Values observed 177 * - (no value -- blank) 241 * Preview to another IFD (?) 242 * <p/> 243 * Details here: http://gvsoft.homedns.org/exif/makernote-nikon-2-tag0x0011.html 244 * // TODO if this is another IFD, decode it 245 */ 246 public static final int TAG_NIKON_TYPE2_PREVIEW_IFD = 0x0011; 247 248 /** 249 * The flash compensation, as an array of four integers. 250 * The value, in EV, is calculated as <code>a*b/c</code>. 251 * 252 * <ul> 253 * <li><code>-18,1,6,0</code> = -3 EV</li> 254 * <li><code>4,1,6,0</code> = 0.67 EV</li> 255 * <li><code>6,1,6,0</code> = 1 EV</li> 256 * </ul> 178 257 */ 179 258 public static final int TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION = 0x0012; 180 259 181 260 /** 182 * Values observed 183 * - 0 250 184 * - 0 400 185 */ 186 public static final int TAG_NIKON_TYPE2_ISO_2 = 0x0013; 187 188 /** 189 * Values observed 261 * The requested ISO value, as an array of two integers. 262 * 263 * <ul> 264 * <li><code>0,0</code></li> 265 * <li><code>0,125</code></li> 266 * <li><code>1,2500</code></li> 267 * </ul> 268 */ 269 public static final int TAG_NIKON_TYPE2_ISO_REQUESTED = 0x0013; 270 271 /** 272 * Defines the photo corner coordinates, in 8 bytes. Treated as four 16-bit integers, they 273 * decode as: top-left (x,y); bot-right (x,y) 190 274 * - 0 0 49163 53255 191 275 * - 0 0 3008 2000 (the image dimensions were 3008x2000) (D70) 192 */ 193 public static final int TAG_NIKON_TYPE2_UNKNOWN_21 = 0x0016; 194 195 /** 196 * Values observed 197 * - (blank) 198 */ 199 public static final int TAG_NIKON_TYPE2_UNKNOWN_22 = 0x0017; 200 201 /** 202 * Values observed 203 * - (blank) 204 */ 205 public static final int TAG_NIKON_TYPE2_UNKNOWN_23 = 0x0018; 206 207 /** 208 * Values observed 209 * - 0 210 */ 211 public static final int TAG_NIKON_TYPE2_UNKNOWN_24 = 0x0019; 212 213 /** 214 * Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. 276 * <ul> 277 * <li><code>0,0,4288,2848</code> The max resolution of the D300 camera</li> 278 * <li><code>0,0,3008,2000</code> The max resolution of the D70 camera</li> 279 * <li><code>0,0,4256,2832</code> The max resolution of the D3 camera</li> 280 * </ul> 281 */ 282 public static final int TAG_NIKON_TYPE2_IMAGE_BOUNDARY = 0x0016; 283 284 /** 285 * The flash exposure compensation, as an array of four integers. 286 * The value, in EV, is calculated as <code>a*b/c</code>. 287 * 288 * <ul> 289 * <li><code>0,0,0,0</code> = 0 EV</li> 290 * <li><code>0,1,6,0</code> = 0 EV</li> 291 * <li><code>4,1,6,0</code> = 0.67 EV</li> 292 * </ul> 293 */ 294 public static final int TAG_NIKON_TYPE2_FLASH_EXPOSURE_COMPENSATION = 0x0017; 295 296 /** 297 * The flash bracket compensation, as an array of four integers. 298 * The value, in EV, is calculated as <code>a*b/c</code>. 299 * 300 * <ul> 301 * <li><code>0,0,0,0</code> = 0 EV</li> 302 * <li><code>0,1,6,0</code> = 0 EV</li> 303 * <li><code>4,1,6,0</code> = 0.67 EV</li> 304 * </ul> 305 */ 306 public static final int TAG_NIKON_TYPE2_FLASH_BRACKET_COMPENSATION = 0x0018; 307 308 /** 309 * The AE bracket compensation, as a rational number. 310 * 311 * <ul> 312 * <li><code>0/0</code></li> 313 * <li><code>0/1</code></li> 314 * <li><code>0/6</code></li> 315 * <li><code>4/6</code></li> 316 * <li><code>6/6</code></li> 317 * </ul> 318 */ 319 public static final int TAG_NIKON_TYPE2_AE_BRACKET_COMPENSATION = 0x0019; 320 321 /** 322 * Flash mode, as a string. 323 * 324 * <ul> 325 * <li><code></code></li> 326 * <li><code>Red Eye Reduction</code></li> 327 * <li><code>D-Lighting</code></li> 328 * <li><code>Distortion control</code></li> 329 * </ul> 330 */ 331 public static final int TAG_NIKON_TYPE2_FLASH_MODE = 0x001a; 332 333 public static final int TAG_NIKON_TYPE2_CROP_HIGH_SPEED = 0x001b; 334 public static final int TAG_NIKON_TYPE2_EXPOSURE_TUNING = 0x001c; 335 336 /** 337 * The camera's serial number, as a string. 338 * Note that D200 is always blank, and D50 is always <code>"D50"</code>. 339 */ 340 public static final int TAG_NIKON_TYPE2_CAMERA_SERIAL_NUMBER = 0x001d; 341 342 /** 343 * The camera's color space setting. 344 * 345 * <ul> 346 * <li><code>1</code> sRGB</li> 347 * <li><code>2</code> Adobe RGB</li> 348 * </ul> 349 */ 350 public static final int TAG_NIKON_TYPE2_COLOR_SPACE = 0x001e; 351 public static final int TAG_NIKON_TYPE2_VR_INFO = 0x001f; 352 public static final int TAG_NIKON_TYPE2_IMAGE_AUTHENTICATION = 0x0020; 353 public static final int TAG_NIKON_TYPE2_UNKNOWN_35 = 0x0021; 354 355 /** 356 * The active D-Lighting setting. 357 * 358 * <ul> 359 * <li><code>0</code> Off</li> 360 * <li><code>1</code> Low</li> 361 * <li><code>3</code> Normal</li> 362 * <li><code>5</code> High</li> 363 * <li><code>7</code> Extra High</li> 364 * <li><code>65535</code> Auto</li> 365 * </ul> 366 */ 367 public static final int TAG_NIKON_TYPE2_ACTIVE_D_LIGHTING = 0x0022; 368 public static final int TAG_NIKON_TYPE2_PICTURE_CONTROL = 0x0023; 369 public static final int TAG_NIKON_TYPE2_WORLD_TIME = 0x0024; 370 public static final int TAG_NIKON_TYPE2_ISO_INFO = 0x0025; 371 public static final int TAG_NIKON_TYPE2_UNKNOWN_36 = 0x0026; 372 public static final int TAG_NIKON_TYPE2_UNKNOWN_37 = 0x0027; 373 public static final int TAG_NIKON_TYPE2_UNKNOWN_38 = 0x0028; 374 public static final int TAG_NIKON_TYPE2_UNKNOWN_39 = 0x0029; 375 376 /** 377 * The camera's vignette control setting. 378 * 379 * <ul> 380 * <li><code>0</code> Off</li> 381 * <li><code>1</code> Low</li> 382 * <li><code>3</code> Normal</li> 383 * <li><code>5</code> High</li> 384 * </ul> 385 */ 386 public static final int TAG_NIKON_TYPE2_VIGNETTE_CONTROL = 0x002a; 387 public static final int TAG_NIKON_TYPE2_UNKNOWN_40 = 0x002b; 388 public static final int TAG_NIKON_TYPE2_UNKNOWN_41 = 0x002c; 389 public static final int TAG_NIKON_TYPE2_UNKNOWN_42 = 0x002d; 390 public static final int TAG_NIKON_TYPE2_UNKNOWN_43 = 0x002e; 391 public static final int TAG_NIKON_TYPE2_UNKNOWN_44 = 0x002f; 392 public static final int TAG_NIKON_TYPE2_UNKNOWN_45 = 0x0030; 393 public static final int TAG_NIKON_TYPE2_UNKNOWN_46 = 0x0031; 394 395 /** 396 * The camera's image adjustment setting, as a string. 397 * 398 * <ul> 399 * <li><code>AUTO</code></li> 400 * <li><code>CONTRAST(+)</code></li> 401 * <li><code>CONTRAST(-)</code></li> 402 * <li><code>NORMAL</code></li> 403 * <li><code>B & W</code></li> 404 * <li><code>BRIGHTNESS(+)</code></li> 405 * <li><code>BRIGHTNESS(-)</code></li> 406 * <li><code>SEPIA</code></li> 407 * </ul> 215 408 */ 216 409 public static final int TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT = 0x0080; 217 410 218 411 /** 219 * The tone compensation as set in the camera. 220 * 221 * Values observed 222 * - AUTO 223 * - NORMAL (D1X, D100) 412 * The camera's tone compensation setting, as a string. 413 * 414 * <ul> 415 * <li><code>NORMAL</code></li> 416 * <li><code>LOW</code></li> 417 * <li><code>MED.L</code></li> 418 * <li><code>MED.H</code></li> 419 * <li><code>HIGH</code></li> 420 * <li><code>AUTO</code></li> 421 * </ul> 224 422 */ 225 423 public static final int TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION = 0x0081; 226 424 227 425 /** 228 * Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. 426 * A description of any auxiliary lens, as a string. 427 * 428 * <ul> 429 * <li><code>OFF</code></li> 430 * <li><code>FISHEYE 1</code></li> 431 * <li><code>FISHEYE 2</code></li> 432 * <li><code>TELEPHOTO 2</code></li> 433 * <li><code>WIDE ADAPTER</code></li> 434 * </ul> 229 435 */ 230 436 public static final int TAG_NIKON_TYPE2_ADAPTER = 0x0082; 231 437 232 438 /** 233 * Values observed 234 * - 6 235 * - 6 (D70) 236 * - 2 (D1X) 237 */ 238 public static final int TAG_NIKON_TYPE2_UNKNOWN_4 = 0x0083; 439 * The type of lens used, as a byte. 440 * 441 * <ul> 442 * <li><code>0x00</code> AF</li> 443 * <li><code>0x01</code> MF</li> 444 * <li><code>0x02</code> D</li> 445 * <li><code>0x06</code> G, D</li> 446 * <li><code>0x08</code> VR</li> 447 * <li><code>0x0a</code> VR, D</li> 448 * <li><code>0x0e</code> VR, G, D</li> 449 * </ul> 450 */ 451 public static final int TAG_NIKON_TYPE2_LENS_TYPE = 0x0083; 239 452 240 453 /** … … 260 473 261 474 /** 262 * Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.475 * The amount of digital zoom used. 263 476 */ 264 477 public static final int TAG_NIKON_TYPE2_DIGITAL_ZOOM = 0x0086; 265 478 266 479 /** 480 * Whether the flash was used in this image. 481 * 482 * <ul> 483 * <li><code>0</code> Flash Not Used</li> 484 * <li><code>1</code> Manual Flash</li> 485 * <li><code>3</code> Flash Not Ready</li> 486 * <li><code>7</code> External Flash</li> 487 * <li><code>8</code> Fired, Commander Mode</li> 488 * <li><code>9</code> Fired, TTL Mode</li> 489 * </ul> 490 */ 491 public static final int TAG_NIKON_TYPE2_FLASH_USED = 0x0087; 492 493 /** 494 * The position of the autofocus target. 495 */ 496 public static final int TAG_NIKON_TYPE2_AF_FOCUS_POSITION = 0x0088; 497 498 /** 499 * The camera's shooting mode. 500 * <p/> 501 * A bit-array with: 502 * <ul> 503 * <li><code>0</code> Single Frame</li> 504 * <li><code>1</code> Continuous</li> 505 * <li><code>2</code> Delay</li> 506 * <li><code>8</code> PC Control</li> 507 * <li><code>16</code> Exposure Bracketing</li> 508 * <li><code>32</code> Auto ISO</li> 509 * <li><code>64</code> White-Balance Bracketing</li> 510 * <li><code>128</code> IR Control</li> 511 * </ul> 512 */ 513 public static final int TAG_NIKON_TYPE2_SHOOTING_MODE = 0x0089; 514 515 public static final int TAG_NIKON_TYPE2_UNKNOWN_20 = 0x008A; 516 517 /** 518 * Lens stops, as an array of four integers. 519 * The value, in EV, is calculated as <code>a*b/c</code>. 520 * 521 * <ul> 522 * <li><code>64,1,12,0</code> = 5.33 EV</li> 523 * <li><code>72,1,12,0</code> = 6 EV</li> 524 * </ul> 525 */ 526 public static final int TAG_NIKON_TYPE2_LENS_STOPS = 0x008B; 527 528 public static final int TAG_NIKON_TYPE2_CONTRAST_CURVE = 0x008C; 529 530 /** 531 * The color space as set in the camera, as a string. 532 * 533 * <ul> 534 * <li><code>MODE1</code> = Mode 1 (sRGB)</li> 535 * <li><code>MODE1a</code> = Mode 1 (sRGB)</li> 536 * <li><code>MODE2</code> = Mode 2 (Adobe RGB)</li> 537 * <li><code>MODE3</code> = Mode 2 (sRGB): Higher Saturation</li> 538 * <li><code>MODE3a</code> = Mode 2 (sRGB): Higher Saturation</li> 539 * <li><code>B & W</code> = B & W</li> 540 * </ul> 541 */ 542 public static final int TAG_NIKON_TYPE2_CAMERA_COLOR_MODE = 0x008D; 543 public static final int TAG_NIKON_TYPE2_UNKNOWN_47 = 0x008E; 544 545 /** 546 * The camera's scene mode, as a string. Examples include: 547 * <ul> 548 * <li><code>BEACH/SNOW</code></li> 549 * <li><code>CLOSE UP</code></li> 550 * <li><code>NIGHT PORTRAIT</code></li> 551 * <li><code>PORTRAIT</code></li> 552 * <li><code>ANTI-SHAKE</code></li> 553 * <li><code>BACK LIGHT</code></li> 554 * <li><code>BEST FACE</code></li> 555 * <li><code>BEST</code></li> 556 * <li><code>COPY</code></li> 557 * <li><code>DAWN/DUSK</code></li> 558 * <li><code>FACE-PRIORITY</code></li> 559 * <li><code>FIREWORKS</code></li> 560 * <li><code>FOOD</code></li> 561 * <li><code>HIGH SENS.</code></li> 562 * <li><code>LAND SCAPE</code></li> 563 * <li><code>MUSEUM</code></li> 564 * <li><code>PANORAMA ASSIST</code></li> 565 * <li><code>PARTY/INDOOR</code></li> 566 * <li><code>SCENE AUTO</code></li> 567 * <li><code>SMILE</code></li> 568 * <li><code>SPORT</code></li> 569 * <li><code>SPORT CONT.</code></li> 570 * <li><code>SUNSET</code></li> 571 * </ul> 572 */ 573 public static final int TAG_NIKON_TYPE2_SCENE_MODE = 0x008F; 574 575 /** 576 * The lighting type, as a string. Examples include: 577 * <ul> 578 * <li><code></code></li> 579 * <li><code>NATURAL</code></li> 580 * <li><code>SPEEDLIGHT</code></li> 581 * <li><code>COLORED</code></li> 582 * <li><code>MIXED</code></li> 583 * <li><code>NORMAL</code></li> 584 * </ul> 585 */ 586 public static final int TAG_NIKON_TYPE2_LIGHT_SOURCE = 0x0090; 587 588 /** 589 * Advertised as ASCII, but actually isn't. A variable number of bytes (eg. 18 to 533). Actual number of bytes 590 * appears fixed for a given camera model. 591 */ 592 public static final int TAG_NIKON_TYPE2_SHOT_INFO = 0x0091; 593 594 /** 595 * The hue adjustment as set in the camera. Values observed are either 0 or 3. 596 */ 597 public static final int TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT = 0x0092; 598 /** 599 * The NEF (RAW) compression. Examples include: 600 * <ul> 601 * <li><code>1</code> Lossy (Type 1)</li> 602 * <li><code>2</code> Uncompressed</li> 603 * <li><code>3</code> Lossless</li> 604 * <li><code>4</code> Lossy (Type 2)</li> 605 * </ul> 606 */ 607 public static final int TAG_NIKON_TYPE2_NEF_COMPRESSION = 0x0093; 608 609 /** 610 * The saturation level, as a signed integer. Examples include: 611 * <ul> 612 * <li><code>+3</code></li> 613 * <li><code>+2</code></li> 614 * <li><code>+1</code></li> 615 * <li><code>0</code> Normal</li> 616 * <li><code>-1</code></li> 617 * <li><code>-2</code></li> 618 * <li><code>-3</code> (B&W)</li> 619 * </ul> 620 */ 621 public static final int TAG_NIKON_TYPE2_SATURATION = 0x0094; 622 623 /** 624 * The type of noise reduction, as a string. Examples include: 625 * <ul> 626 * <li><code>OFF</code></li> 627 * <li><code>FPNR</code></li> 628 * </ul> 629 */ 630 public static final int TAG_NIKON_TYPE2_NOISE_REDUCTION = 0x0095; 631 public static final int TAG_NIKON_TYPE2_LINEARIZATION_TABLE = 0x0096; 632 public static final int TAG_NIKON_TYPE2_COLOR_BALANCE = 0x0097; 633 public static final int TAG_NIKON_TYPE2_LENS_DATA = 0x0098; 634 635 /** The NEF (RAW) thumbnail size, as an integer array with two items representing [width,height]. */ 636 public static final int TAG_NIKON_TYPE2_NEF_THUMBNAIL_SIZE = 0x0099; 637 638 /** The sensor pixel size, as a pair of rational numbers. */ 639 public static final int TAG_NIKON_TYPE2_SENSOR_PIXEL_SIZE = 0x009A; 640 public static final int TAG_NIKON_TYPE2_UNKNOWN_10 = 0x009B; 641 public static final int TAG_NIKON_TYPE2_SCENE_ASSIST = 0x009C; 642 public static final int TAG_NIKON_TYPE2_UNKNOWN_11 = 0x009D; 643 public static final int TAG_NIKON_TYPE2_RETOUCH_HISTORY = 0x009E; 644 public static final int TAG_NIKON_TYPE2_UNKNOWN_12 = 0x009F; 645 646 /** 647 * The camera serial number, as a string. 648 * <ul> 649 * <li><code>NO= 00002539</code></li> 650 * <li><code>NO= -1000d71</code></li> 651 * <li><code>PKG597230621263</code></li> 652 * <li><code>PKG5995671330625116</code></li> 653 * <li><code>PKG49981281631130677</code></li> 654 * <li><code>BU672230725063</code></li> 655 * <li><code>NO= 200332c7</code></li> 656 * <li><code>NO= 30045efe</code></li> 657 * </ul> 658 */ 659 public static final int TAG_NIKON_TYPE2_CAMERA_SERIAL_NUMBER_2 = 0x00A0; 660 661 public static final int TAG_NIKON_TYPE2_IMAGE_DATA_SIZE = 0x00A2; 662 663 public static final int TAG_NIKON_TYPE2_UNKNOWN_27 = 0x00A3; 664 public static final int TAG_NIKON_TYPE2_UNKNOWN_28 = 0x00A4; 665 public static final int TAG_NIKON_TYPE2_IMAGE_COUNT = 0x00A5; 666 public static final int TAG_NIKON_TYPE2_DELETED_IMAGE_COUNT = 0x00A6; 667 668 /** The number of total shutter releases. This value increments for each exposure (observed on D70). */ 669 public static final int TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER = 0x00A7; 670 671 public static final int TAG_NIKON_TYPE2_FLASH_INFO = 0x00A8; 672 /** 673 * The camera's image optimisation, as a string. 674 * <ul> 675 * <li><code></code></li> 676 * <li><code>NORMAL</code></li> 677 * <li><code>CUSTOM</code></li> 678 * <li><code>BLACK AND WHITE</code></li> 679 * <li><code>LAND SCAPE</code></li> 680 * <li><code>MORE VIVID</code></li> 681 * <li><code>PORTRAIT</code></li> 682 * <li><code>SOFT</code></li> 683 * <li><code>VIVID</code></li> 684 * </ul> 685 */ 686 public static final int TAG_NIKON_TYPE2_IMAGE_OPTIMISATION = 0x00A9; 687 688 /** 689 * The camera's saturation level, as a string. 690 * <ul> 691 * <li><code></code></li> 692 * <li><code>NORMAL</code></li> 693 * <li><code>AUTO</code></li> 694 * <li><code>ENHANCED</code></li> 695 * <li><code>MODERATE</code></li> 696 * </ul> 697 */ 698 public static final int TAG_NIKON_TYPE2_SATURATION_2 = 0x00AA; 699 700 /** 701 * The camera's digital vari-program setting, as a string. 702 * <ul> 703 * <li><code></code></li> 704 * <li><code>AUTO</code></li> 705 * <li><code>AUTO(FLASH OFF)</code></li> 706 * <li><code>CLOSE UP</code></li> 707 * <li><code>LANDSCAPE</code></li> 708 * <li><code>NIGHT PORTRAIT</code></li> 709 * <li><code>PORTRAIT</code></li> 710 * <li><code>SPORT</code></li> 711 * </ul> 712 */ 713 public static final int TAG_NIKON_TYPE2_DIGITAL_VARI_PROGRAM = 0x00AB; 714 715 /** 716 * The camera's digital vari-program setting, as a string. 717 * <ul> 718 * <li><code></code></li> 719 * <li><code>VR-ON</code></li> 720 * <li><code>VR-OFF</code></li> 721 * <li><code>VR-HYBRID</code></li> 722 * <li><code>VR-ACTIVE</code></li> 723 * </ul> 724 */ 725 public static final int TAG_NIKON_TYPE2_IMAGE_STABILISATION = 0x00AC; 726 727 /** 728 * The camera's digital vari-program setting, as a string. 729 * <ul> 730 * <li><code></code></li> 731 * <li><code>HYBRID</code></li> 732 * <li><code>STANDARD</code></li> 733 * </ul> 734 */ 735 public static final int TAG_NIKON_TYPE2_AF_RESPONSE = 0x00AD; 736 public static final int TAG_NIKON_TYPE2_UNKNOWN_29 = 0x00AE; 737 public static final int TAG_NIKON_TYPE2_UNKNOWN_30 = 0x00AF; 738 public static final int TAG_NIKON_TYPE2_MULTI_EXPOSURE = 0x00B0; 739 740 /** 741 * The camera's high ISO noise reduction setting, as an integer. 742 * <ul> 743 * <li><code>0</code> Off</li> 744 * <li><code>1</code> Minimal</li> 745 * <li><code>2</code> Low</li> 746 * <li><code>4</code> Normal</li> 747 * <li><code>6</code> High</li> 748 * </ul> 749 */ 750 public static final int TAG_NIKON_TYPE2_HIGH_ISO_NOISE_REDUCTION = 0x00B1; 751 public static final int TAG_NIKON_TYPE2_UNKNOWN_31 = 0x00B2; 752 public static final int TAG_NIKON_TYPE2_UNKNOWN_32 = 0x00B3; 753 public static final int TAG_NIKON_TYPE2_UNKNOWN_33 = 0x00B4; 754 public static final int TAG_NIKON_TYPE2_UNKNOWN_48 = 0x00B5; 755 public static final int TAG_NIKON_TYPE2_POWER_UP_TIME = 0x00B6; 756 public static final int TAG_NIKON_TYPE2_AF_INFO_2 = 0x00B7; 757 public static final int TAG_NIKON_TYPE2_FILE_INFO = 0x00B8; 758 public static final int TAG_NIKON_TYPE2_AF_TUNE = 0x00B9; 759 public static final int TAG_NIKON_TYPE2_UNKNOWN_49 = 0x00BB; 760 public static final int TAG_NIKON_TYPE2_UNKNOWN_50 = 0x00BD; 761 public static final int TAG_NIKON_TYPE2_UNKNOWN_51 = 0x0103; 762 public static final int TAG_NIKON_TYPE2_PRINT_IM = 0x0E00; 763 764 /** 765 * Data about changes set by Nikon Capture Editor. 766 * 267 767 * Values observed 268 * - 0 269 * - 9 270 * - 3 (D1X) 271 */ 272 public static final int TAG_NIKON_TYPE2_UNKNOWN_5 = 0x0087; 273 274 /** 275 * Values observed 276 * - 277 */ 278 public static final int TAG_NIKON_TYPE2_AF_FOCUS_POSITION = 0x0088; 279 280 /** 281 * Values observed 282 * - 0 283 * - 1 284 */ 285 public static final int TAG_NIKON_TYPE2_UNKNOWN_7 = 0x0089; 286 287 /** 288 * Values observed 289 * - 0 290 * - 0 291 */ 292 public static final int TAG_NIKON_TYPE2_UNKNOWN_20 = 0x008A; 293 294 /** 295 * Values observed 296 * - 48,1,c,0 (hex) (D100) 297 * - @ <hex> 298 */ 299 public static final int TAG_NIKON_TYPE2_UNKNOWN_8 = 0x008B; 300 301 /** 302 * Unknown. Fabrizio believes this may be a lookup table for the user-defined curve. 303 * 304 * Values observed 305 * - (blank) (D1X) 306 */ 307 public static final int TAG_NIKON_TYPE2_UNKNOWN_9 = 0x008C; 308 309 /** 310 * The color space as set in the camera. 311 * 312 * Values observed 313 * - MODE1 314 * - Mode I (sRGB) (D70) 315 * - MODE2 (D1X, D100) 316 */ 317 public static final int TAG_NIKON_TYPE2_CAMERA_COLOR_MODE = 0x008D; 318 319 /** 320 * Values observed 321 * - NATURAL 322 * - SPEEDLIGHT (D70, D1X) 323 */ 324 public static final int TAG_NIKON_TYPE2_LIGHT_SOURCE = 0x0090; 325 326 /** 327 * Values observed 328 * - 0100 <hex> 329 * - 0103 (D70) 330 * - 0100 (D1X) 331 */ 332 public static final int TAG_NIKON_TYPE2_UNKNOWN_11 = 0x0091; 333 334 /** 335 * The hue adjustment as set in the camera. 336 * 337 * Values observed 338 * - 0 339 */ 340 public static final int TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT = 0x0092; 341 342 /** 343 * Values observed 344 * - OFF 345 */ 346 public static final int TAG_NIKON_TYPE2_NOISE_REDUCTION = 0x0095; 347 348 /** 349 * Values observed 350 * - 0100 <hex> 351 * - 0103 <hex> 352 */ 353 public static final int TAG_NIKON_TYPE2_UNKNOWN_12 = 0x0097; 354 355 /** 356 * Values observed 357 * - 0100 <hex> 358 * - 0101 <hex> 359 * - 0100 <hex> (D1X) 360 * - 30,31,30,30,0,0,b,48,7c,7c,24,24,5,15,24,0,0,0,0,0 (hex) (D100) 361 */ 362 public static final int TAG_NIKON_TYPE2_UNKNOWN_13 = 0x0098; 363 364 /** 365 * Values observed 366 * - 2014 662 (D1X) 367 * - 1517,1012 (D100) 368 */ 369 public static final int TAG_NIKON_TYPE2_UNKNOWN_14 = 0x0099; 370 371 /** 372 * Values observed 373 * - 78/10 78/10 374 * - 78/10 78/10 (D70) 375 * - 59/10 59/5 (D1X) 376 * - 7.8,7.8 (D100) 377 */ 378 public static final int TAG_NIKON_TYPE2_UNKNOWN_15 = 0x009A; 379 380 /** 381 * Values observed 382 * - NO= 00002539 383 */ 384 public static final int TAG_NIKON_TYPE2_UNKNOWN_25 = 0x00A0; 385 386 /** 387 * Values observed 388 * - 1564851 389 */ 390 public static final int TAG_NIKON_TYPE2_UNKNOWN_26 = 0x00A2; 391 392 /** 393 * Values observed 394 * - 0 395 */ 396 public static final int TAG_NIKON_TYPE2_UNKNOWN_27 = 0x00A3; 397 398 /** 399 * This appears to be a sequence number to indentify the exposure. This value seems to increment 400 * for consecutive exposures (observed on D70). 401 * 402 * Values observed 403 * - 5062 404 */ 405 public static final int TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER = 0x00A7; 406 407 /** 408 * Values observed 409 * - 0100 (D70) 410 */ 411 public static final int TAG_NIKON_TYPE2_UNKNOWN_32 = 0x00A8; 412 413 /** 414 * Values observed 415 * - NORMAL (D70) 416 */ 417 public static final int TAG_NIKON_TYPE2_UNKNOWN_33 = 0x00A9; 418 419 /** 420 * Nikon Browser suggests this value represents Saturation... 421 * Values observed 422 * - NORMAL (D70) 423 */ 424 public static final int TAG_NIKON_TYPE2_UNKNOWN_29 = 0x00AA; 425 426 /** 427 * Values observed 428 * - AUTO (D70) 429 * - (blank) (D70) 430 */ 431 public static final int TAG_NIKON_TYPE2_UNKNOWN_30 = 0x00AB; 432 433 /** 434 * Data about changes set by Nikon Capture Editor. 435 * 436 * Values observed 437 */ 438 public static final int TAG_NIKON_TYPE2_CAPTURE_EDITOR_DATA = 0x0E01; 439 440 /** 441 * Values observed 442 * - 1473 443 * - 7036 (D100) 444 */ 445 public static final int TAG_NIKON_TYPE2_UNKNOWN_16 = 0x0E10; 446 447 protected static final HashMap _tagNameMap = new HashMap(); 768 */ 769 public static final int TAG_NIKON_TYPE2_NIKON_CAPTURE_DATA = 0x0E01; 770 public static final int TAG_NIKON_TYPE2_UNKNOWN_52 = 0x0E05; 771 public static final int TAG_NIKON_TYPE2_UNKNOWN_53 = 0x0E08; 772 public static final int TAG_NIKON_TYPE2_NIKON_CAPTURE_VERSION = 0x0E09; 773 public static final int TAG_NIKON_TYPE2_NIKON_CAPTURE_OFFSETS = 0x0E0E; 774 public static final int TAG_NIKON_TYPE2_NIKON_SCAN = 0x0E10; 775 public static final int TAG_NIKON_TYPE2_UNKNOWN_54 = 0x0E19; 776 public static final int TAG_NIKON_TYPE2_NEF_BIT_DEPTH = 0x0E22; 777 public static final int TAG_NIKON_TYPE2_UNKNOWN_55 = 0x0E23; 778 779 @NotNull 780 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 448 781 449 782 static 450 783 { 451 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_FIRMWARE_VERSION), "Firmware Version"); 452 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_1), "ISO"); 453 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT), "Quality & File Format"); 454 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE), "White Balance"); 455 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_SHARPENING), "Sharpening"); 456 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AF_TYPE), "AF Type"); 457 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE), "White Balance Fine"); 458 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_RB_COEFF), "White Balance RB Coefficients"); 459 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_2), "ISO"); 460 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_SELECTION), "ISO Selection"); 461 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_DATA_DUMP), "Data Dump"); 462 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT), "Image Adjustment"); 463 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION), "Tone Compensation"); 464 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ADAPTER), "Adapter"); 465 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_LENS), "Lens"); 466 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE), "Manual Focus Distance"); 467 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_DIGITAL_ZOOM), "Digital Zoom"); 468 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_COLOR_MODE), "Colour Mode"); 469 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT), "Camera Hue Adjustment"); 470 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_NOISE_REDUCTION), "Noise Reduction"); 471 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAPTURE_EDITOR_DATA), "Capture Editor Data"); 472 473 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_1), "Unknown 01"); 474 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_2), "Unknown 02"); 475 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_3), "Unknown 03"); 476 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_4), "Unknown 04"); 477 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_5), "Unknown 05"); 478 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AF_FOCUS_POSITION), "AF Focus Position"); 479 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_7), "Unknown 07"); 480 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_8), "Unknown 08"); 481 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_9), "Unknown 09"); 482 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_LIGHT_SOURCE), "Light source"); 483 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_11), "Unknown 11"); 484 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_12), "Unknown 12"); 485 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_13), "Unknown 13"); 486 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_14), "Unknown 14"); 487 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_15), "Unknown 15"); 488 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_16), "Unknown 16"); 489 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_FLASH_SYNC_MODE), "Flash Sync Mode"); 490 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AUTO_FLASH_MODE), "Auto Flash Mode"); 491 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION), "Auto Flash Compensation"); 492 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER), "Exposure Sequence Number"); 493 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_COLOR_MODE), "Color Mode"); 494 495 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_20), "Unknown 20"); 496 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_21), "Unknown 21"); 497 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_22), "Unknown 22"); 498 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_23), "Unknown 23"); 499 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_24), "Unknown 24"); 500 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_25), "Unknown 25"); 501 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_26), "Unknown 26"); 502 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_27), "Unknown 27"); 503 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_29), "Unknown 29"); 504 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_30), "Unknown 30"); 505 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_32), "Unknown 32"); 506 _tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_33), "Unknown 33"); 784 _tagNameMap.put(TAG_NIKON_TYPE2_FIRMWARE_VERSION, "Firmware Version"); 785 _tagNameMap.put(TAG_NIKON_TYPE2_ISO_1, "ISO"); 786 _tagNameMap.put(TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT, "Quality & File Format"); 787 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE, "White Balance"); 788 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_SHARPENING, "Sharpening"); 789 _tagNameMap.put(TAG_NIKON_TYPE2_AF_TYPE, "AF Type"); 790 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE, "White Balance Fine"); 791 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_RB_COEFF, "White Balance RB Coefficients"); 792 _tagNameMap.put(TAG_NIKON_TYPE2_ISO_REQUESTED, "ISO"); 793 _tagNameMap.put(TAG_NIKON_TYPE2_ISO_MODE, "ISO Mode"); 794 _tagNameMap.put(TAG_NIKON_TYPE2_DATA_DUMP, "Data Dump"); 795 796 _tagNameMap.put(TAG_NIKON_TYPE2_PROGRAM_SHIFT, "Program Shift"); 797 _tagNameMap.put(TAG_NIKON_TYPE2_EXPOSURE_DIFFERENCE, "Exposure Difference"); 798 _tagNameMap.put(TAG_NIKON_TYPE2_PREVIEW_IFD, "Preview IFD"); 799 _tagNameMap.put(TAG_NIKON_TYPE2_LENS_TYPE, "Lens Type"); 800 _tagNameMap.put(TAG_NIKON_TYPE2_FLASH_USED, "Flash Used"); 801 _tagNameMap.put(TAG_NIKON_TYPE2_AF_FOCUS_POSITION, "AF Focus Position"); 802 _tagNameMap.put(TAG_NIKON_TYPE2_SHOOTING_MODE, "Shooting Mode"); 803 _tagNameMap.put(TAG_NIKON_TYPE2_LENS_STOPS, "Lens Stops"); 804 _tagNameMap.put(TAG_NIKON_TYPE2_CONTRAST_CURVE, "Contrast Curve"); 805 _tagNameMap.put(TAG_NIKON_TYPE2_LIGHT_SOURCE, "Light source"); 806 _tagNameMap.put(TAG_NIKON_TYPE2_SHOT_INFO, "Shot Info"); 807 _tagNameMap.put(TAG_NIKON_TYPE2_COLOR_BALANCE, "Color Balance"); 808 _tagNameMap.put(TAG_NIKON_TYPE2_LENS_DATA, "Lens Data"); 809 _tagNameMap.put(TAG_NIKON_TYPE2_NEF_THUMBNAIL_SIZE, "NEF Thumbnail Size"); 810 _tagNameMap.put(TAG_NIKON_TYPE2_SENSOR_PIXEL_SIZE, "Sensor Pixel Size"); 811 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_10, "Unknown 10"); 812 _tagNameMap.put(TAG_NIKON_TYPE2_SCENE_ASSIST, "Scene Assist"); 813 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_11, "Unknown 11"); 814 _tagNameMap.put(TAG_NIKON_TYPE2_RETOUCH_HISTORY, "Retouch History"); 815 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_12, "Unknown 12"); 816 _tagNameMap.put(TAG_NIKON_TYPE2_FLASH_SYNC_MODE, "Flash Sync Mode"); 817 _tagNameMap.put(TAG_NIKON_TYPE2_AUTO_FLASH_MODE, "Auto Flash Mode"); 818 _tagNameMap.put(TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, "Auto Flash Compensation"); 819 _tagNameMap.put(TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER, "Exposure Sequence Number"); 820 _tagNameMap.put(TAG_NIKON_TYPE2_COLOR_MODE, "Color Mode"); 821 822 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_20, "Unknown 20"); 823 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_BOUNDARY, "Image Boundary"); 824 _tagNameMap.put(TAG_NIKON_TYPE2_FLASH_EXPOSURE_COMPENSATION, "Flash Exposure Compensation"); 825 _tagNameMap.put(TAG_NIKON_TYPE2_FLASH_BRACKET_COMPENSATION, "Flash Bracket Compensation"); 826 _tagNameMap.put(TAG_NIKON_TYPE2_AE_BRACKET_COMPENSATION, "AE Bracket Compensation"); 827 _tagNameMap.put(TAG_NIKON_TYPE2_FLASH_MODE, "Flash Mode"); 828 _tagNameMap.put(TAG_NIKON_TYPE2_CROP_HIGH_SPEED, "Crop High Speed"); 829 _tagNameMap.put(TAG_NIKON_TYPE2_EXPOSURE_TUNING, "Exposure Tuning"); 830 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_SERIAL_NUMBER, "Camera Serial Number"); 831 _tagNameMap.put(TAG_NIKON_TYPE2_COLOR_SPACE, "Color Space"); 832 _tagNameMap.put(TAG_NIKON_TYPE2_VR_INFO, "VR Info"); 833 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_AUTHENTICATION, "Image Authentication"); 834 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_35, "Unknown 35"); 835 _tagNameMap.put(TAG_NIKON_TYPE2_ACTIVE_D_LIGHTING, "Active D-Lighting"); 836 _tagNameMap.put(TAG_NIKON_TYPE2_PICTURE_CONTROL, "Picture Control"); 837 _tagNameMap.put(TAG_NIKON_TYPE2_WORLD_TIME, "World Time"); 838 _tagNameMap.put(TAG_NIKON_TYPE2_ISO_INFO, "ISO Info"); 839 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_36, "Unknown 36"); 840 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_37, "Unknown 37"); 841 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_38, "Unknown 38"); 842 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_39, "Unknown 39"); 843 _tagNameMap.put(TAG_NIKON_TYPE2_VIGNETTE_CONTROL, "Vignette Control"); 844 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_40, "Unknown 40"); 845 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_41, "Unknown 41"); 846 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_42, "Unknown 42"); 847 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_43, "Unknown 43"); 848 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_44, "Unknown 44"); 849 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_45, "Unknown 45"); 850 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_46, "Unknown 46"); 851 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_47, "Unknown 47"); 852 _tagNameMap.put(TAG_NIKON_TYPE2_SCENE_MODE, "Scene Mode"); 853 854 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_SERIAL_NUMBER_2, "Camera Serial Number"); 855 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_DATA_SIZE, "Image Data Size"); 856 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_27, "Unknown 27"); 857 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_28, "Unknown 28"); 858 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_COUNT, "Image Count"); 859 _tagNameMap.put(TAG_NIKON_TYPE2_DELETED_IMAGE_COUNT, "Deleted Image Count"); 860 _tagNameMap.put(TAG_NIKON_TYPE2_SATURATION_2, "Saturation"); 861 _tagNameMap.put(TAG_NIKON_TYPE2_DIGITAL_VARI_PROGRAM, "Digital Vari Program"); 862 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_STABILISATION, "Image Stabilisation"); 863 _tagNameMap.put(TAG_NIKON_TYPE2_AF_RESPONSE, "AF Response"); 864 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_29, "Unknown 29"); 865 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_30, "Unknown 30"); 866 _tagNameMap.put(TAG_NIKON_TYPE2_MULTI_EXPOSURE, "Multi Exposure"); 867 _tagNameMap.put(TAG_NIKON_TYPE2_HIGH_ISO_NOISE_REDUCTION, "High ISO Noise Reduction"); 868 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_31, "Unknown 31"); 869 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_32, "Unknown 32"); 870 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_33, "Unknown 33"); 871 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_48, "Unknown 48"); 872 _tagNameMap.put(TAG_NIKON_TYPE2_POWER_UP_TIME, "Power Up Time"); 873 _tagNameMap.put(TAG_NIKON_TYPE2_AF_INFO_2, "AF Info 2"); 874 _tagNameMap.put(TAG_NIKON_TYPE2_FILE_INFO, "File Info"); 875 _tagNameMap.put(TAG_NIKON_TYPE2_AF_TUNE, "AF Tune"); 876 _tagNameMap.put(TAG_NIKON_TYPE2_FLASH_INFO, "Flash Info"); 877 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_OPTIMISATION, "Image Optimisation"); 878 879 _tagNameMap.put(TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT, "Image Adjustment"); 880 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION, "Tone Compensation"); 881 _tagNameMap.put(TAG_NIKON_TYPE2_ADAPTER, "Adapter"); 882 _tagNameMap.put(TAG_NIKON_TYPE2_LENS, "Lens"); 883 _tagNameMap.put(TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE, "Manual Focus Distance"); 884 _tagNameMap.put(TAG_NIKON_TYPE2_DIGITAL_ZOOM, "Digital Zoom"); 885 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_COLOR_MODE, "Colour Mode"); 886 _tagNameMap.put(TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT, "Camera Hue Adjustment"); 887 _tagNameMap.put(TAG_NIKON_TYPE2_NEF_COMPRESSION, "NEF Compression"); 888 _tagNameMap.put(TAG_NIKON_TYPE2_SATURATION, "Saturation"); 889 _tagNameMap.put(TAG_NIKON_TYPE2_NOISE_REDUCTION, "Noise Reduction"); 890 _tagNameMap.put(TAG_NIKON_TYPE2_LINEARIZATION_TABLE, "Linearization Table"); 891 _tagNameMap.put(TAG_NIKON_TYPE2_NIKON_CAPTURE_DATA, "Nikon Capture Data"); 892 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_49, "Unknown 49"); 893 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_50, "Unknown 50"); 894 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_51, "Unknown 51"); 895 _tagNameMap.put(TAG_NIKON_TYPE2_PRINT_IM, "Print IM"); 896 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_52, "Unknown 52"); 897 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_53, "Unknown 53"); 898 _tagNameMap.put(TAG_NIKON_TYPE2_NIKON_CAPTURE_VERSION, "Nikon Capture Version"); 899 _tagNameMap.put(TAG_NIKON_TYPE2_NIKON_CAPTURE_OFFSETS, "Nikon Capture Offsets"); 900 _tagNameMap.put(TAG_NIKON_TYPE2_NIKON_SCAN, "Nikon Scan"); 901 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_54, "Unknown 54"); 902 _tagNameMap.put(TAG_NIKON_TYPE2_NEF_BIT_DEPTH, "NEF Bit Depth"); 903 _tagNameMap.put(TAG_NIKON_TYPE2_UNKNOWN_55, "Unknown 55"); 507 904 } 508 905 … … 512 909 } 513 910 514 public Rational getAutoFlashCompensation() throws MetadataException 515 { 516 if (!containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION)) 517 return null; 518 519 byte[] bytes = getByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION); 520 return CalculateFlashCompensationFromBytes(bytes); 521 } 522 523 public static Rational CalculateFlashCompensationFromBytes(byte[] bytes) 524 { 525 if (bytes.length==3) 526 { 527 byte denominator = bytes[2]; 528 int numerator = (int)bytes[0] * bytes[1]; 529 return new Rational(numerator, denominator); 530 } 531 return null; 532 } 533 911 @NotNull 534 912 public String getName() 535 913 { … … 537 915 } 538 916 539 protected HashMap getTagNameMap() 917 @NotNull 918 protected HashMap<Integer, String> getTagNameMap() 540 919 { 541 920 return _tagNameMap; -
trunk/src/com/drew/metadata/exif/OlympusMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 import com.drew. metadata.Directory;18 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 19 25 import com.drew.metadata.TagDescriptor; 20 26 21 27 /** 22 * Provides human-readable string versions of the tags stored in an OlympusMakernoteDirectory. 28 * Provides human-readable string representations of tag values stored in a <code>OlympusMakernoteDirectory</code>. 29 * 30 * @author Drew Noakes http://drewnoakes.com 23 31 */ 24 public class OlympusMakernoteDescriptor extends TagDescriptor 32 public class OlympusMakernoteDescriptor extends TagDescriptor<OlympusMakernoteDirectory> 25 33 { 26 public OlympusMakernoteDescriptor(Directory directory) 34 public OlympusMakernoteDescriptor(@NotNull OlympusMakernoteDirectory directory) 27 35 { 28 36 super(directory); 29 37 } 30 38 31 public String getDescription(int tagType) throws MetadataException 39 @Nullable 40 public String getDescription(int tagType) 32 41 { 33 42 switch (tagType) { … … 41 50 return getDigiZoomRatioDescription(); 42 51 default: 43 return _directory.getString(tagType);52 return super.getDescription(tagType); 44 53 } 45 54 } 46 55 47 public String getDigiZoomRatioDescription() throws MetadataException 56 @Nullable 57 public String getDigiZoomRatioDescription() 48 58 { 49 if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO)) return null; 50 int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO); 59 Integer value = _directory.getInteger(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO); 60 if (value==null) 61 return null; 51 62 switch (value) { 52 63 case 0: … … 59 70 } 60 71 61 public String getMacroModeDescription() throws MetadataException 72 @Nullable 73 public String getMacroModeDescription() 62 74 { 63 if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE)) return null; 64 int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE); 75 Integer value = _directory.getInteger(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE); 76 if (value==null) 77 return null; 65 78 switch (value) { 66 79 case 0: … … 73 86 } 74 87 75 public String getJpegQualityDescription() throws MetadataException 88 @Nullable 89 public String getJpegQualityDescription() 76 90 { 77 if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY)) return null; 78 int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY); 91 Integer value = _directory.getInteger(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY); 92 if (value==null) 93 return null; 79 94 switch (value) { 80 95 case 1: … … 89 104 } 90 105 91 public String getSpecialModeDescription() throws MetadataException 106 @Nullable 107 public String getSpecialModeDescription() 92 108 { 93 if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE)) return null;94 109 int[] values = _directory.getIntArray(OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE); 95 StringBuffer desc = new StringBuffer(); 110 if (values==null) 111 return null; 112 if (values.length < 1) 113 return ""; 114 StringBuilder desc = new StringBuilder(); 96 115 switch (values[0]) { 97 116 case 0: … … 111 130 break; 112 131 } 132 133 if (values.length < 2) 134 return desc.toString(); 113 135 desc.append(" - "); 114 136 switch (values[1]) { … … 117 139 break; 118 140 case 1: 119 desc.append("1st in a sequnce"); 141 desc.append("1st in a sequence"); 120 142 break; 121 143 case 2: … … 130 152 break; 131 153 } 154 if (values.length < 3) 155 return desc.toString(); 156 desc.append(" - "); 132 157 switch (values[2]) { 133 158 case 1: -
trunk/src/com/drew/metadata/exif/OlympusMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 24 * The Olympus makernote is used by many manufacturers, and as such contains some tags that appear specific to 25 * those manufacturers. Other users include Konica, Minolta and Epson. 29 * The Olympus makernote is used by many manufacturers (Konica, Minolta and Epson...), and as such contains some tags 30 * that appear specific to those manufacturers. 31 * 32 * @author Drew Noakes http://drewnoakes.com 26 33 */ 27 34 public class OlympusMakernoteDirectory extends Directory 28 35 { 29 /** 30 * Used by Konica / Minolta cameras. 31 */ 36 /** Used by Konica / Minolta cameras. */ 32 37 public static final int TAG_OLYMPUS_MAKERNOTE_VERSION = 0x0000; 33 34 /** 35 * Used by Konica / Minolta cameras. 36 */ 38 /** Used by Konica / Minolta cameras. */ 37 39 public static final int TAG_OLYMPUS_CAMERA_SETTINGS_1 = 0x0001; 38 39 /** 40 * Alternate Camera Settings Tag. Used by Konica / Minolta cameras. 41 */ 40 /** Alternate Camera Settings Tag. Used by Konica / Minolta cameras. */ 42 41 public static final int TAG_OLYMPUS_CAMERA_SETTINGS_2 = 0x0003; 43 44 /** 45 * Used by Konica / Minolta cameras. 46 */ 42 /** Used by Konica / Minolta cameras. */ 47 43 public static final int TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE = 0x0040; 48 49 /** 50 * Used by Konica / Minolta cameras. 51 */ 44 /** Used by Konica / Minolta cameras. */ 52 45 public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1 = 0x0081; 53 54 /** 55 * Alternate Thumbnail Offset. Used by Konica / Minolta cameras. 56 */ 46 /** Alternate Thumbnail Offset. Used by Konica / Minolta cameras. */ 57 47 public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2 = 0x0088; 58 59 /** 60 * Length of thumbnail in bytes. Used by Konica / Minolta cameras. 61 */ 48 /** Length of thumbnail in bytes. Used by Konica / Minolta cameras. */ 62 49 public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH = 0x0089; 63 50 … … 84 71 /** 85 72 * Not 100% sure about this tag. 86 * 73 * <p/> 87 74 * Used by Konica / Minolta cameras. 88 75 * 0 = Raw … … 119 106 public static final int TAG_OLYMPUS_MACRO_MODE = 0x0202; 120 107 121 /**122 *123 */124 108 public static final int TAG_OLYMPUS_UNKNOWN_1 = 0x0203; 125 109 126 /** 127 * Zoom Factor (0 or 1 = normal) 128 */ 110 /** Zoom Factor (0 or 1 = normal) */ 129 111 public static final int TAG_OLYMPUS_DIGI_ZOOM_RATIO = 0x0204; 130 131 /**132 *133 */134 112 public static final int TAG_OLYMPUS_UNKNOWN_2 = 0x0205; 135 136 /**137 *138 */139 113 public static final int TAG_OLYMPUS_UNKNOWN_3 = 0x0206; 140 141 /**142 *143 */144 114 public static final int TAG_OLYMPUS_FIRMWARE_VERSION = 0x0207; 145 146 /**147 *148 */149 115 public static final int TAG_OLYMPUS_PICT_INFO = 0x0208; 150 151 /**152 *153 */154 116 public static final int TAG_OLYMPUS_CAMERA_ID = 0x0209; 155 117 … … 166 128 public static final int TAG_OLYMPUS_IMAGE_HEIGHT = 0x020C; 167 129 168 /** 169 * A string. Used by Epson cameras. 170 */ 130 /** A string. Used by Epson cameras. */ 171 131 public static final int TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL = 0x020D; 172 132 … … 177 137 public static final int TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO = 0x0E00; 178 138 179 /**180 *181 */182 139 public static final int TAG_OLYMPUS_DATA_DUMP = 0x0F00; 183 184 /**185 *186 */187 140 public static final int TAG_OLYMPUS_FLASH_MODE = 0x1004; 188 189 /**190 *191 */192 141 public static final int TAG_OLYMPUS_BRACKET = 0x1006; 193 194 /**195 *196 */197 142 public static final int TAG_OLYMPUS_FOCUS_MODE = 0x100B; 198 199 /**200 *201 */202 143 public static final int TAG_OLYMPUS_FOCUS_DISTANCE = 0x100C; 203 204 /**205 *206 */207 144 public static final int TAG_OLYMPUS_ZOOM = 0x100D; 208 209 /**210 *211 */212 145 public static final int TAG_OLYMPUS_MACRO_FOCUS = 0x100E; 213 214 /**215 *216 */217 146 public static final int TAG_OLYMPUS_SHARPNESS = 0x100F; 218 219 /**220 *221 */222 147 public static final int TAG_OLYMPUS_COLOUR_MATRIX = 0x1011; 223 224 /**225 *226 */227 148 public static final int TAG_OLYMPUS_BLACK_LEVEL = 0x1012; 228 229 /**230 *231 */232 149 public static final int TAG_OLYMPUS_WHITE_BALANCE = 0x1015; 233 234 /**235 *236 */237 150 public static final int TAG_OLYMPUS_RED_BIAS = 0x1017; 238 239 /**240 *241 */242 151 public static final int TAG_OLYMPUS_BLUE_BIAS = 0x1018; 243 244 /**245 *246 */247 152 public static final int TAG_OLYMPUS_SERIAL_NUMBER = 0x101A; 248 249 /**250 *251 */252 153 public static final int TAG_OLYMPUS_FLASH_BIAS = 0x1023; 253 254 /**255 *256 */257 154 public static final int TAG_OLYMPUS_CONTRAST = 0x1029; 258 259 /**260 *261 */262 155 public static final int TAG_OLYMPUS_SHARPNESS_FACTOR = 0x102A; 263 264 /**265 *266 */267 156 public static final int TAG_OLYMPUS_COLOUR_CONTROL = 0x102B; 268 269 /**270 *271 */272 157 public static final int TAG_OLYMPUS_VALID_BITS = 0x102C; 273 274 /**275 *276 */277 158 public static final int TAG_OLYMPUS_CORING_FILTER = 0x102D; 278 279 /**280 *281 */282 159 public static final int TAG_OLYMPUS_FINAL_WIDTH = 0x102E; 283 284 /**285 *286 */287 160 public static final int TAG_OLYMPUS_FINAL_HEIGHT = 0x102F; 288 289 /**290 *291 */292 161 public static final int TAG_OLYMPUS_COMPRESSION_RATIO = 0x1034; 293 162 294 protected static final HashMap tagNameMap = new HashMap(); 295 296 static 297 { 298 tagNameMap.put(new Integer(TAG_OLYMPUS_SPECIAL_MODE), "Special Mode"); 299 tagNameMap.put(new Integer(TAG_OLYMPUS_JPEG_QUALITY), "Jpeg Quality"); 300 tagNameMap.put(new Integer(TAG_OLYMPUS_MACRO_MODE), "Macro"); 301 tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_1), "Makernote Unknown 1"); 302 tagNameMap.put(new Integer(TAG_OLYMPUS_DIGI_ZOOM_RATIO), "DigiZoom Ratio"); 303 tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_2), "Makernote Unknown 2"); 304 tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_3), "Makernote Unknown 3"); 305 tagNameMap.put(new Integer(TAG_OLYMPUS_FIRMWARE_VERSION), "Firmware Version"); 306 tagNameMap.put(new Integer(TAG_OLYMPUS_PICT_INFO), "Pict Info"); 307 tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_ID), "Camera Id"); 308 tagNameMap.put(new Integer(TAG_OLYMPUS_DATA_DUMP), "Data Dump"); 309 tagNameMap.put(new Integer(TAG_OLYMPUS_MAKERNOTE_VERSION), "Makernote Version"); 310 tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_SETTINGS_1), "Camera Settings"); 311 tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_SETTINGS_2), "Camera Settings"); 312 tagNameMap.put(new Integer(TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE), "Compressed Image Size"); 313 tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1), "Thumbnail Offset"); 314 tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2), "Thumbnail Offset"); 315 tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH), "Thumbnail Length"); 316 tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_MODE), "Colour Mode"); 317 tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_QUALITY_1), "Image Quality"); 318 tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_QUALITY_2), "Image Quality"); 319 tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_HEIGHT), "Image Height"); 320 tagNameMap.put(new Integer(TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL), "Original Manufacturer Model"); 321 tagNameMap.put(new Integer(TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); 322 tagNameMap.put(new Integer(TAG_OLYMPUS_FLASH_MODE), "Flash Mode"); 323 tagNameMap.put(new Integer(TAG_OLYMPUS_BRACKET), "Bracket"); 324 tagNameMap.put(new Integer(TAG_OLYMPUS_FOCUS_MODE), "Focus Mode"); 325 tagNameMap.put(new Integer(TAG_OLYMPUS_FOCUS_DISTANCE), "Focus Distance"); 326 tagNameMap.put(new Integer(TAG_OLYMPUS_ZOOM), "Zoom"); 327 tagNameMap.put(new Integer(TAG_OLYMPUS_MACRO_FOCUS), "Macro Focus"); 328 tagNameMap.put(new Integer(TAG_OLYMPUS_SHARPNESS), "Sharpness"); 329 tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_MATRIX), "Colour Matrix"); 330 tagNameMap.put(new Integer(TAG_OLYMPUS_BLACK_LEVEL), "Black Level"); 331 tagNameMap.put(new Integer(TAG_OLYMPUS_WHITE_BALANCE), "White Balance"); 332 tagNameMap.put(new Integer(TAG_OLYMPUS_RED_BIAS), "Red Bias"); 333 tagNameMap.put(new Integer(TAG_OLYMPUS_BLUE_BIAS), "Blue Bias"); 334 tagNameMap.put(new Integer(TAG_OLYMPUS_SERIAL_NUMBER), "Serial Number"); 335 tagNameMap.put(new Integer(TAG_OLYMPUS_FLASH_BIAS), "Flash Bias"); 336 tagNameMap.put(new Integer(TAG_OLYMPUS_CONTRAST), "Contrast"); 337 tagNameMap.put(new Integer(TAG_OLYMPUS_SHARPNESS_FACTOR), "Sharpness Factor"); 338 tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_CONTROL), "Colour Control"); 339 tagNameMap.put(new Integer(TAG_OLYMPUS_VALID_BITS), "Valid Bits"); 340 tagNameMap.put(new Integer(TAG_OLYMPUS_CORING_FILTER), "Coring Filter"); 341 tagNameMap.put(new Integer(TAG_OLYMPUS_FINAL_WIDTH), "Final Width"); 342 tagNameMap.put(new Integer(TAG_OLYMPUS_FINAL_HEIGHT), "Final Height"); 343 tagNameMap.put(new Integer(TAG_OLYMPUS_COMPRESSION_RATIO), "Compression Ratio"); 163 @NotNull 164 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 165 166 static { 167 _tagNameMap.put(TAG_OLYMPUS_SPECIAL_MODE, "Special Mode"); 168 _tagNameMap.put(TAG_OLYMPUS_JPEG_QUALITY, "Jpeg Quality"); 169 _tagNameMap.put(TAG_OLYMPUS_MACRO_MODE, "Macro"); 170 _tagNameMap.put(TAG_OLYMPUS_UNKNOWN_1, "Makernote Unknown 1"); 171 _tagNameMap.put(TAG_OLYMPUS_DIGI_ZOOM_RATIO, "DigiZoom Ratio"); 172 _tagNameMap.put(TAG_OLYMPUS_UNKNOWN_2, "Makernote Unknown 2"); 173 _tagNameMap.put(TAG_OLYMPUS_UNKNOWN_3, "Makernote Unknown 3"); 174 _tagNameMap.put(TAG_OLYMPUS_FIRMWARE_VERSION, "Firmware Version"); 175 _tagNameMap.put(TAG_OLYMPUS_PICT_INFO, "Pict Info"); 176 _tagNameMap.put(TAG_OLYMPUS_CAMERA_ID, "Camera Id"); 177 _tagNameMap.put(TAG_OLYMPUS_DATA_DUMP, "Data Dump"); 178 _tagNameMap.put(TAG_OLYMPUS_MAKERNOTE_VERSION, "Makernote Version"); 179 _tagNameMap.put(TAG_OLYMPUS_CAMERA_SETTINGS_1, "Camera Settings"); 180 _tagNameMap.put(TAG_OLYMPUS_CAMERA_SETTINGS_2, "Camera Settings"); 181 _tagNameMap.put(TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE, "Compressed Image Size"); 182 _tagNameMap.put(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1, "Thumbnail Offset"); 183 _tagNameMap.put(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2, "Thumbnail Offset"); 184 _tagNameMap.put(TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH, "Thumbnail Length"); 185 _tagNameMap.put(TAG_OLYMPUS_COLOUR_MODE, "Colour Mode"); 186 _tagNameMap.put(TAG_OLYMPUS_IMAGE_QUALITY_1, "Image Quality"); 187 _tagNameMap.put(TAG_OLYMPUS_IMAGE_QUALITY_2, "Image Quality"); 188 _tagNameMap.put(TAG_OLYMPUS_IMAGE_HEIGHT, "Image Height"); 189 _tagNameMap.put(TAG_OLYMPUS_IMAGE_WIDTH, "Image Width"); 190 _tagNameMap.put(TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL, "Original Manufacturer Model"); 191 _tagNameMap.put(TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info"); 192 _tagNameMap.put(TAG_OLYMPUS_FLASH_MODE, "Flash Mode"); 193 _tagNameMap.put(TAG_OLYMPUS_BRACKET, "Bracket"); 194 _tagNameMap.put(TAG_OLYMPUS_FOCUS_MODE, "Focus Mode"); 195 _tagNameMap.put(TAG_OLYMPUS_FOCUS_DISTANCE, "Focus Distance"); 196 _tagNameMap.put(TAG_OLYMPUS_ZOOM, "Zoom"); 197 _tagNameMap.put(TAG_OLYMPUS_MACRO_FOCUS, "Macro Focus"); 198 _tagNameMap.put(TAG_OLYMPUS_SHARPNESS, "Sharpness"); 199 _tagNameMap.put(TAG_OLYMPUS_COLOUR_MATRIX, "Colour Matrix"); 200 _tagNameMap.put(TAG_OLYMPUS_BLACK_LEVEL, "Black Level"); 201 _tagNameMap.put(TAG_OLYMPUS_WHITE_BALANCE, "White Balance"); 202 _tagNameMap.put(TAG_OLYMPUS_RED_BIAS, "Red Bias"); 203 _tagNameMap.put(TAG_OLYMPUS_BLUE_BIAS, "Blue Bias"); 204 _tagNameMap.put(TAG_OLYMPUS_SERIAL_NUMBER, "Serial Number"); 205 _tagNameMap.put(TAG_OLYMPUS_FLASH_BIAS, "Flash Bias"); 206 _tagNameMap.put(TAG_OLYMPUS_CONTRAST, "Contrast"); 207 _tagNameMap.put(TAG_OLYMPUS_SHARPNESS_FACTOR, "Sharpness Factor"); 208 _tagNameMap.put(TAG_OLYMPUS_COLOUR_CONTROL, "Colour Control"); 209 _tagNameMap.put(TAG_OLYMPUS_VALID_BITS, "Valid Bits"); 210 _tagNameMap.put(TAG_OLYMPUS_CORING_FILTER, "Coring Filter"); 211 _tagNameMap.put(TAG_OLYMPUS_FINAL_WIDTH, "Final Width"); 212 _tagNameMap.put(TAG_OLYMPUS_FINAL_HEIGHT, "Final Height"); 213 _tagNameMap.put(TAG_OLYMPUS_COMPRESSION_RATIO, "Compression Ratio"); 344 214 } 345 215 … … 349 219 } 350 220 221 @NotNull 351 222 public String getName() 352 223 { … … 354 225 } 355 226 356 protected HashMap getTagNameMap() 227 @NotNull 228 protected HashMap<Integer, String> getTagNameMap() 357 229 { 358 return tagNameMap; 230 return _tagNameMap; 359 231 } 360 232 } -
trunk/src/com/drew/metadata/exif/PanasonicMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 import com.drew.metadata.Directory; 18 import com.drew.metadata.MetadataException; 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 25 import com.drew.lang.ByteArrayReader; 26 import com.drew.lang.annotations.NotNull; 27 import com.drew.lang.annotations.Nullable; 28 import com.drew.metadata.Age; 29 import com.drew.metadata.Face; 19 30 import com.drew.metadata.TagDescriptor; 20 31 32 import java.io.UnsupportedEncodingException; 33 21 34 /** 22 * Provides human-readable string versions of the tags stored in a PanasonicMakernoteDirectory. 35 * Provides human-readable string representations of tag values stored in a <code>PanasonicMakernoteDirectory</code>. 36 * <p/> 37 * Some information about this makernote taken from here: 38 * <ul> 39 * <li><a href="http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html">http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html</a></li> 40 * <li><a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Panasonic.html">http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Panasonic.html</a></li> 41 * </ul> 23 42 * 24 * Some information about this makernote taken from here: 25 * http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html 43 * @author Drew Noakes http://drewnoakes.com, Philipp Sandhaus 26 44 */ 27 public class PanasonicMakernoteDescriptor extends TagDescriptor 45 public class PanasonicMakernoteDescriptor extends TagDescriptor<PanasonicMakernoteDirectory> 28 46 { 29 public PanasonicMakernoteDescriptor(Directory directory) 47 public PanasonicMakernoteDescriptor(@NotNull PanasonicMakernoteDirectory directory) 30 48 { 31 49 super(directory); 32 50 } 33 51 34 public String getDescription(int tagType) throws MetadataException 35 { 36 switch (tagType) 52 @Nullable 53 public String getDescription(int tagType) 54 { 55 switch (tagType) { 56 case PanasonicMakernoteDirectory.TAG_QUALITY_MODE: 57 return getQualityModeDescription(); 58 case PanasonicMakernoteDirectory.TAG_VERSION: 59 return getVersionDescription(); 60 case PanasonicMakernoteDirectory.TAG_WHITE_BALANCE: 61 return getWhiteBalanceDescription(); 62 case PanasonicMakernoteDirectory.TAG_FOCUS_MODE: 63 return getFocusModeDescription(); 64 case PanasonicMakernoteDirectory.TAG_AF_AREA_MODE: 65 return getAfAreaModeDescription(); 66 case PanasonicMakernoteDirectory.TAG_IMAGE_STABILIZATION: 67 return getImageStabilizationDescription(); 68 case PanasonicMakernoteDirectory.TAG_MACRO_MODE: 69 return getMacroModeDescription(); 70 case PanasonicMakernoteDirectory.TAG_RECORD_MODE: 71 return getRecordModeDescription(); 72 case PanasonicMakernoteDirectory.TAG_AUDIO: 73 return getAudioDescription(); 74 case PanasonicMakernoteDirectory.TAG_UNKNOWN_DATA_DUMP: 75 return getUnknownDataDumpDescription(); 76 case PanasonicMakernoteDirectory.TAG_COLOR_EFFECT: 77 return getColorEffectDescription(); 78 case PanasonicMakernoteDirectory.TAG_UPTIME: 79 return getUptimeDescription(); 80 case PanasonicMakernoteDirectory.TAG_BURST_MODE: 81 return getBurstModeDescription(); 82 case PanasonicMakernoteDirectory.TAG_CONTRAST_MODE: 83 return getContrastModeDescription(); 84 case PanasonicMakernoteDirectory.TAG_NOISE_REDUCTION: 85 return getNoiseReductionDescription(); 86 case PanasonicMakernoteDirectory.TAG_SELF_TIMER: 87 return getSelfTimerDescription(); 88 case PanasonicMakernoteDirectory.TAG_ROTATION: 89 return getRotationDescription(); 90 case PanasonicMakernoteDirectory.TAG_AF_ASSIST_LAMP: 91 return getAfAssistLampDescription(); 92 case PanasonicMakernoteDirectory.TAG_COLOR_MODE: 93 return getColorModeDescription(); 94 case PanasonicMakernoteDirectory.TAG_OPTICAL_ZOOM_MODE: 95 return getOpticalZoomModeDescription(); 96 case PanasonicMakernoteDirectory.TAG_CONVERSION_LENS: 97 return getConversionLensDescription(); 98 case PanasonicMakernoteDirectory.TAG_CONTRAST: 99 return getContrastDescription(); 100 case PanasonicMakernoteDirectory.TAG_WORLD_TIME_LOCATION: 101 return getWorldTimeLocationDescription(); 102 case PanasonicMakernoteDirectory.TAG_ADVANCED_SCENE_MODE: 103 return getAdvancedSceneModeDescription(); 104 case PanasonicMakernoteDirectory.TAG_FACE_DETECTION_INFO: 105 return getDetectedFacesDescription(); 106 case PanasonicMakernoteDirectory.TAG_TRANSFORM: 107 return getTransformDescription(); 108 case PanasonicMakernoteDirectory.TAG_TRANSFORM_1: 109 return getTransform1Description(); 110 case PanasonicMakernoteDirectory.TAG_INTELLIGENT_EXPOSURE: 111 return getIntelligentExposureDescription(); 112 case PanasonicMakernoteDirectory.TAG_FLASH_WARNING: 113 return getFlashWarningDescription(); 114 case PanasonicMakernoteDirectory.TAG_COUNTRY: 115 return getCountryDescription(); 116 case PanasonicMakernoteDirectory.TAG_STATE: 117 return getStateDescription(); 118 case PanasonicMakernoteDirectory.TAG_CITY: 119 return getCityDescription(); 120 case PanasonicMakernoteDirectory.TAG_LANDMARK: 121 return getLandmarkDescription(); 122 case PanasonicMakernoteDirectory.TAG_INTELLIGENT_RESOLUTION: 123 return getIntelligentResolutionDescription(); 124 case PanasonicMakernoteDirectory.TAG_FACE_RECOGNITION_INFO: 125 return getRecognizedFacesDescription(); 126 case PanasonicMakernoteDirectory.TAG_PRINT_IMAGE_MATCHING_INFO: 127 return getPrintImageMatchingInfoDescription(); 128 case PanasonicMakernoteDirectory.TAG_SCENE_MODE: 129 return getSceneModeDescription(); 130 case PanasonicMakernoteDirectory.TAG_FLASH_FIRED: 131 return getFlashFiredDescription(); 132 case PanasonicMakernoteDirectory.TAG_TEXT_STAMP: 133 return getTextStampDescription(); 134 case PanasonicMakernoteDirectory.TAG_TEXT_STAMP_1: 135 return getTextStamp1Description(); 136 case PanasonicMakernoteDirectory.TAG_TEXT_STAMP_2: 137 return getTextStamp2Description(); 138 case PanasonicMakernoteDirectory.TAG_TEXT_STAMP_3: 139 return getTextStamp3Description(); 140 case PanasonicMakernoteDirectory.TAG_MAKERNOTE_VERSION: 141 return getMakernoteVersionDescription(); 142 case PanasonicMakernoteDirectory.TAG_EXIF_VERSION: 143 return getExifVersionDescription(); 144 case PanasonicMakernoteDirectory.TAG_INTERNAL_SERIAL_NUMBER: 145 return getInternalSerialNumberDescription(); 146 case PanasonicMakernoteDirectory.TAG_TITLE: 147 return getTitleDescription(); 148 case PanasonicMakernoteDirectory.TAG_BABY_NAME: 149 return getBabyNameDescription(); 150 case PanasonicMakernoteDirectory.TAG_LOCATION: 151 return getLocationDescription(); 152 case PanasonicMakernoteDirectory.TAG_BABY_AGE: 153 return getBabyAgeDescription(); 154 case PanasonicMakernoteDirectory.TAG_BABY_AGE_1: 155 return getBabyAge1Description(); 156 default: 157 return super.getDescription(tagType); 158 } 159 } 160 161 @Nullable 162 public String getPrintImageMatchingInfoDescription() 163 { 164 byte[] values = _directory.getByteArray(PanasonicMakernoteDirectory.TAG_PRINT_IMAGE_MATCHING_INFO); 165 if (values == null) 166 return null; 167 return "(" + values.length + " bytes)"; 168 } 169 170 @Nullable 171 public String getTextStampDescription() 172 { 173 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_TEXT_STAMP); 174 } 175 176 @Nullable 177 public String getTextStamp1Description() 178 { 179 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_TEXT_STAMP_1); 180 } 181 182 @Nullable 183 public String getTextStamp2Description() 184 { 185 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_TEXT_STAMP_2); 186 } 187 188 @Nullable 189 public String getTextStamp3Description() 190 { 191 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_TEXT_STAMP_3); 192 } 193 194 @Nullable 195 public String getMacroModeDescription() 196 { 197 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_MACRO_MODE); 198 } 199 200 @Nullable 201 public String getFlashFiredDescription() 202 { 203 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_FLASH_FIRED); 204 } 205 206 @Nullable 207 public String getImageStabilizationDescription() 208 { 209 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_IMAGE_STABILIZATION); 210 if (value == null) 211 return null; 212 switch (value) { 213 case 2: 214 return "On, Mode 1"; 215 case 3: 216 return "Off"; 217 case 4: 218 return "On, Mode 2"; 219 default: 220 return "Unknown (" + value + ")"; 221 } 222 } 223 224 @Nullable 225 public String getAudioDescription() 226 { 227 return getOnOffDescription(PanasonicMakernoteDirectory.TAG_AUDIO); 228 } 229 230 @Nullable 231 public String getTransformDescription() 232 { 233 return getTransformDescription(PanasonicMakernoteDirectory.TAG_TRANSFORM); 234 } 235 236 @Nullable 237 public String getTransform1Description() 238 { 239 return getTransformDescription(PanasonicMakernoteDirectory.TAG_TRANSFORM_1); 240 } 241 242 @Nullable 243 private String getTransformDescription(int tag) 244 { 245 byte[] values = _directory.getByteArray(tag); 246 if (values == null) 247 return null; 248 249 BufferReader reader = new ByteArrayReader(values); 250 251 try 37 252 { 38 case PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE: 39 return getMacroModeDescription(); 40 case PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE: 41 return getRecordModeDescription(); 42 case PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO: 43 return getPrintImageMatchingInfoDescription(); 44 default: 45 return _directory.getString(tagType); 46 } 47 } 48 49 public String getPrintImageMatchingInfoDescription() throws MetadataException 50 { 51 if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO)) return null; 52 byte[] bytes = _directory.getByteArray(PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO); 53 return "(" + bytes.length + " bytes)"; 54 } 55 56 public String getMacroModeDescription() throws MetadataException 57 { 58 if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE)) return null; 59 int value = _directory.getInt(PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE); 60 switch (value) { 61 case 1: 253 int val1 = reader.getUInt16(0); 254 int val2 = reader.getUInt16(2); 255 256 if (val1 == -1 && val2 == 1) 257 return "Slim Low"; 258 if (val1 == -3 && val2 == 2) 259 return "Slim High"; 260 if (val1 == 0 && val2 == 0) 261 return "Off"; 262 if (val1 == 1 && val2 == 1) 263 return "Stretch Low"; 264 if (val1 == 3 && val2 == 2) 265 return "Stretch High"; 266 267 return "Unknown (" + val1 + " " + val2 + ")"; 268 } catch (BufferBoundsException e) { 269 return null ; 270 } 271 } 272 273 @Nullable 274 public String getIntelligentExposureDescription() 275 { 276 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_INTELLIGENT_EXPOSURE); 277 if (value == null) 278 return null; 279 switch (value) { 280 case 0: 281 return "Off"; 282 case 1: 283 return "Low"; 284 case 2: 285 return "Standard"; 286 case 3: 287 return "High"; 288 289 default: 290 return "Unknown (" + value + ")"; 291 } 292 } 293 294 @Nullable 295 public String getFlashWarningDescription() 296 { 297 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_FLASH_WARNING); 298 if (value == null) 299 return null; 300 switch (value) { 301 case 0: 302 return "No"; 303 case 1: 304 return "Yes (Flash required but disabled)"; 305 default: 306 return "Unknown (" + value + ")"; 307 } 308 } 309 310 @Nullable 311 public String getCountryDescription() 312 { 313 return getTextDescription(PanasonicMakernoteDirectory.TAG_COUNTRY); 314 } 315 316 @Nullable 317 public String getStateDescription() 318 { 319 return getTextDescription(PanasonicMakernoteDirectory.TAG_STATE); 320 } 321 322 @Nullable 323 public String getCityDescription() 324 { 325 return getTextDescription(PanasonicMakernoteDirectory.TAG_CITY); 326 } 327 328 @Nullable 329 public String getLandmarkDescription() 330 { 331 return getTextDescription(PanasonicMakernoteDirectory.TAG_LANDMARK); 332 } 333 334 @Nullable 335 public String getTitleDescription() 336 { 337 return getTextDescription(PanasonicMakernoteDirectory.TAG_TITLE); 338 } 339 340 @Nullable 341 public String getBabyNameDescription() 342 { 343 return getTextDescription(PanasonicMakernoteDirectory.TAG_BABY_NAME); 344 } 345 346 @Nullable 347 public String getLocationDescription() 348 { 349 return getTextDescription(PanasonicMakernoteDirectory.TAG_LOCATION); 350 } 351 352 @Nullable 353 public String getIntelligentResolutionDescription() 354 { 355 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_INTELLIGENT_RESOLUTION); 356 if (value == null) 357 return null; 358 switch (value) { 359 case 0: 360 return "Off"; 361 case 2: 362 return "Auto"; 363 case 3: 62 364 return "On"; 63 case 2: 365 default: 366 return "Unknown (" + value + ")"; 367 } 368 } 369 370 @Nullable 371 public String getContrastDescription() 372 { 373 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_CONTRAST); 374 if (value == null) 375 return null; 376 switch (value) { 377 case 0: 378 return "Normal"; 379 default: 380 return "Unknown (" + value + ")"; 381 } 382 } 383 384 @Nullable 385 public String getWorldTimeLocationDescription() 386 { 387 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_WORLD_TIME_LOCATION); 388 if (value == null) 389 return null; 390 switch (value) { 391 case 1: 392 return "Home"; 393 case 2: 394 return "Destination"; 395 default: 396 return "Unknown (" + value + ")"; 397 } 398 } 399 400 @Nullable 401 public String getAdvancedSceneModeDescription() 402 { 403 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_ADVANCED_SCENE_MODE); 404 if (value == null) 405 return null; 406 switch (value) { 407 case 1: 408 return "Normal"; 409 case 2: 410 return "Outdoor/Illuminations/Flower/HDR Art"; 411 case 3: 412 return "Indoor/Architecture/Objects/HDR B&W"; 413 case 4: 414 return "Creative"; 415 case 5: 416 return "Auto"; 417 case 7: 418 return "Expressive"; 419 case 8: 420 return "Retro"; 421 case 9: 422 return "Pure"; 423 case 10: 424 return "Elegant"; 425 case 12: 426 return "Monochrome"; 427 case 13: 428 return "Dynamic Art"; 429 case 14: 430 return "Silhouette"; 431 default: 432 return "Unknown (" + value + ")"; 433 } 434 } 435 436 @Nullable 437 public String getUnknownDataDumpDescription() 438 { 439 byte[] value = _directory.getByteArray(PanasonicMakernoteDirectory.TAG_UNKNOWN_DATA_DUMP); 440 if (value == null) 441 return null; 442 return "[" + value.length + " bytes]"; 443 } 444 445 @Nullable 446 public String getColorEffectDescription() 447 { 448 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_COLOR_EFFECT); 449 if (value == null) 450 return null; 451 switch (value) { 452 case 1: 64 453 return "Off"; 65 default: 66 return "Unknown (" + value + ")"; 67 } 68 } 69 70 public String getRecordModeDescription() throws MetadataException 71 { 72 if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE)) return null; 73 int value = _directory.getInt(PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE); 74 switch (value) { 75 case 1: 454 case 2: 455 return "Warm"; 456 case 3: 457 return "Cool"; 458 case 4: 459 return "Black & White"; 460 case 5: 461 return "Sepia"; 462 default: 463 return "Unknown (" + value + ")"; 464 } 465 } 466 467 @Nullable 468 public String getUptimeDescription() 469 { 470 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_UPTIME); 471 if (value == null) 472 return null; 473 return value / 100f + " s"; 474 } 475 476 @Nullable 477 public String getBurstModeDescription() 478 { 479 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_BURST_MODE); 480 if (value == null) 481 return null; 482 switch (value) { 483 case 0: 484 return "Off"; 485 case 1: 486 return "On"; 487 case 2: 488 return "Infinite"; 489 case 4: 490 return "Unlimited"; 491 default: 492 return "Unknown (" + value + ")"; 493 } 494 } 495 496 @Nullable 497 public String getContrastModeDescription() 498 { 499 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_CONTRAST_MODE); 500 if (value == null) 501 return null; 502 switch (value) { 503 case 0x0: 76 504 return "Normal"; 505 case 0x1: 506 return "Low"; 507 case 0x2: 508 return "High"; 509 case 0x6: 510 return "Medium Low"; 511 case 0x7: 512 return "Medium High"; 513 case 0x100: 514 return "Low"; 515 case 0x110: 516 return "Normal"; 517 case 0x120: 518 return "High"; 519 520 default: 521 return "Unknown (" + value + ")"; 522 } 523 } 524 525 @Nullable 526 public String getNoiseReductionDescription() 527 { 528 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_NOISE_REDUCTION); 529 if (value == null) 530 return null; 531 switch (value) { 532 case 0: 533 return "Standard (0)"; 534 case 1: 535 return "Low (-1)"; 536 case 2: 537 return "High (+1)"; 538 case 3: 539 return "Lowest (-2)"; 540 case 4: 541 return "Highest (+2)"; 542 default: 543 return "Unknown (" + value + ")"; 544 } 545 } 546 547 548 @Nullable 549 public String getSelfTimerDescription() 550 { 551 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_SELF_TIMER); 552 if (value == null) 553 return null; 554 switch (value) { 555 case 1: 556 return "Off"; 557 case 2: 558 return "10 s"; 559 case 3: 560 return "2 s"; 561 default: 562 return "Unknown (" + value + ")"; 563 } 564 } 565 566 @Nullable 567 public String getRotationDescription() 568 { 569 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_ROTATION); 570 if (value == null) 571 return null; 572 switch (value) { 573 case 1: 574 return "Horizontal"; 575 case 3: 576 return "Rotate 180"; 577 case 6: 578 return "Rotate 90 CW"; 579 case 8: 580 return "Rotate 270 CW"; 581 default: 582 return "Unknown (" + value + ")"; 583 } 584 } 585 586 @Nullable 587 public String getAfAssistLampDescription() 588 { 589 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_AF_ASSIST_LAMP); 590 if (value == null) 591 return null; 592 switch (value) { 593 case 1: 594 return "Fired"; 595 case 2: 596 return "Enabled but not used"; 597 case 3: 598 return "Disabled but required"; 599 case 4: 600 return "Disabled and not required"; 601 default: 602 return "Unknown (" + value + ")"; 603 } 604 } 605 606 @Nullable 607 public String getColorModeDescription() 608 { 609 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_COLOR_MODE); 610 if (value == null) 611 return null; 612 switch (value) { 613 case 0: 614 return "Normal"; 615 case 1: 616 return "Natural"; 617 case 2: 618 return "Vivid"; 619 default: 620 return "Unknown (" + value + ")"; 621 } 622 } 623 624 @Nullable 625 public String getOpticalZoomModeDescription() 626 { 627 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_OPTICAL_ZOOM_MODE); 628 if (value == null) 629 return null; 630 switch (value) { 631 case 1: 632 return "Standard"; 633 case 2: 634 return "Extended"; 635 default: 636 return "Unknown (" + value + ")"; 637 } 638 } 639 640 @Nullable 641 public String getConversionLensDescription() 642 { 643 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_CONVERSION_LENS); 644 if (value == null) 645 return null; 646 switch (value) { 647 case 1: 648 return "Off"; 649 case 2: 650 return "Wide"; 651 case 3: 652 return "Telephoto"; 653 case 4: 654 return "Macro"; 655 default: 656 return "Unknown (" + value + ")"; 657 } 658 } 659 660 @Nullable 661 public String getDetectedFacesDescription() 662 { 663 return buildFacesDescription(_directory.getDetectedFaces()); 664 } 665 666 @Nullable 667 public String getRecognizedFacesDescription() 668 { 669 return buildFacesDescription(_directory.getRecognizedFaces()); 670 } 671 672 @Nullable 673 private String buildFacesDescription(@Nullable Face[] faces) 674 { 675 if (faces == null) 676 return null; 677 678 StringBuilder result = new StringBuilder(); 679 680 for (int i = 0; i < faces.length; i++) 681 result.append("Face ").append(i + 1).append(": ").append(faces[i].toString()).append("\n"); 682 683 if (result.length() > 0) 684 return result.substring(0, result.length() - 1); 685 686 return null; 687 } 688 689 @Nullable 690 public String getRecordModeDescription() 691 { 692 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_RECORD_MODE); 693 if (value == null) 694 return null; 695 switch (value) { 696 case 1: 697 return "Normal"; 77 698 case 2: 78 699 return "Portrait"; 700 case 3: 701 return "Scenery"; 702 case 4: 703 return "Sports"; 704 case 5: 705 return "Night Portrait"; 706 case 6: 707 return "Program"; 708 case 7: 709 return "Aperture Priority"; 710 case 8: 711 return "Shutter Priority"; 79 712 case 9: 80 713 return "Macro"; 714 case 10: 715 return "Spot"; 716 case 11: 717 return "Manual"; 718 case 12: 719 return "Movie Preview"; 720 case 13: 721 return "Panning"; 722 case 14: 723 return "Simple"; 724 case 15: 725 return "Color Effects"; 726 case 16: 727 return "Self Portrait"; 728 case 17: 729 return "Economy"; 730 case 18: 731 return "Fireworks"; 732 case 19: 733 return "Party"; 734 case 20: 735 return "Snow"; 736 case 21: 737 return "Night Scenery"; 738 case 22: 739 return "Food"; 740 case 23: 741 return "Baby"; 742 case 24: 743 return "Soft Skin"; 744 case 25: 745 return "Candlelight"; 746 case 26: 747 return "Starry Night"; 748 case 27: 749 return "High Sensitivity"; 750 case 28: 751 return "Panorama Assist"; 752 case 29: 753 return "Underwater"; 754 case 30: 755 return "Beach"; 756 case 31: 757 return "Aerial Photo"; 758 case 32: 759 return "Sunset"; 760 case 33: 761 return "Pet"; 762 case 34: 763 return "Intelligent ISO"; 764 case 35: 765 return "Clipboard"; 766 case 36: 767 return "High Speed Continuous Shooting"; 768 case 37: 769 return "Intelligent Auto"; 770 case 39: 771 return "Multi-aspect"; 772 case 41: 773 return "Transform"; 774 case 42: 775 return "Flash Burst"; 776 case 43: 777 return "Pin Hole"; 778 case 44: 779 return "Film Grain"; 780 case 45: 781 return "My Color"; 782 case 46: 783 return "Photo Frame"; 784 case 51: 785 return "HDR"; 786 default: 787 return "Unknown (" + value + ")"; 788 } 789 } 790 791 @Nullable 792 public String getSceneModeDescription() 793 { 794 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_SCENE_MODE); 795 if (value == null) 796 return null; 797 switch (value) { 798 case 1: 799 return "Normal"; 800 case 2: 801 return "Portrait"; 802 case 3: 803 return "Scenery"; 804 case 4: 805 return "Sports"; 806 case 5: 807 return "Night Portrait"; 808 case 6: 809 return "Program"; 810 case 7: 811 return "Aperture Priority"; 812 case 8: 813 return "Shutter Priority"; 814 case 9: 815 return "Macro"; 816 case 10: 817 return "Spot"; 818 case 11: 819 return "Manual"; 820 case 12: 821 return "Movie Preview"; 822 case 13: 823 return "Panning"; 824 case 14: 825 return "Simple"; 826 case 15: 827 return "Color Effects"; 828 case 16: 829 return "Self Portrait"; 830 case 17: 831 return "Economy"; 832 case 18: 833 return "Fireworks"; 834 case 19: 835 return "Party"; 836 case 20: 837 return "Snow"; 838 case 21: 839 return "Night Scenery"; 840 case 22: 841 return "Food"; 842 case 23: 843 return "Baby"; 844 case 24: 845 return "Soft Skin"; 846 case 25: 847 return "Candlelight"; 848 case 26: 849 return "Starry Night"; 850 case 27: 851 return "High Sensitivity"; 852 case 28: 853 return "Panorama Assist"; 854 case 29: 855 return "Underwater"; 856 case 30: 857 return "Beach"; 858 case 31: 859 return "Aerial Photo"; 860 case 32: 861 return "Sunset"; 862 case 33: 863 return "Pet"; 864 case 34: 865 return "Intelligent ISO"; 866 case 35: 867 return "Clipboard"; 868 case 36: 869 return "High Speed Continuous Shooting"; 870 case 37: 871 return "Intelligent Auto"; 872 case 39: 873 return "Multi-aspect"; 874 case 41: 875 return "Transform"; 876 case 42: 877 return "Flash Burst"; 878 case 43: 879 return "Pin Hole"; 880 case 44: 881 return "Film Grain"; 882 case 45: 883 return "My Color"; 884 case 46: 885 return "Photo Frame"; 886 case 51: 887 return "HDR"; 888 default: 889 return "Unknown (" + value + ")"; 890 } 891 } 892 893 @Nullable 894 public String getFocusModeDescription() 895 { 896 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_FOCUS_MODE); 897 if (value == null) 898 return null; 899 switch (value) { 900 case 1: 901 return "Auto"; 902 case 2: 903 return "Manual"; 904 case 4: 905 return "Auto, Focus Button"; 906 case 5: 907 return "Auto, Continuous"; 908 default: 909 return "Unknown (" + value + ")"; 910 } 911 } 912 913 @Nullable 914 public String getAfAreaModeDescription() 915 { 916 int[] value = _directory.getIntArray(PanasonicMakernoteDirectory.TAG_AF_AREA_MODE); 917 if (value == null || value.length < 2) 918 return null; 919 switch (value[0]) { 920 case 0: 921 switch (value[1]) { 922 case 1: 923 return "Spot Mode On"; 924 case 16: 925 return "Spot Mode Off"; 926 default: 927 return "Unknown (" + value[0] + " " + value[1] + ")"; 928 } 929 case 1: 930 switch (value[1]) { 931 case 0: 932 return "Spot Focusing"; 933 case 1: 934 return "5-area"; 935 default: 936 return "Unknown (" + value[0] + " " + value[1] + ")"; 937 } 938 case 16: 939 switch (value[1]) { 940 case 0: 941 return "1-area"; 942 case 16: 943 return "1-area (high speed)"; 944 default: 945 return "Unknown (" + value[0] + " " + value[1] + ")"; 946 } 947 case 32: 948 switch (value[1]) { 949 case 0: 950 return "Auto or Face Detect"; 951 case 1: 952 return "3-area (left)"; 953 case 2: 954 return "3-area (center)"; 955 case 3: 956 return "3-area (right)"; 957 default: 958 return "Unknown (" + value[0] + " " + value[1] + ")"; 959 } 960 case 64: 961 return "Face Detect"; 962 default: 963 return "Unknown (" + value[0] + " " + value[1] + ")"; 964 } 965 } 966 967 @Nullable 968 public String getQualityModeDescription() 969 { 970 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_QUALITY_MODE); 971 if (value == null) 972 return null; 973 switch (value) { 974 case 2: 975 return "High"; 976 case 3: 977 return "Normal"; 978 case 6: 979 return "Very High"; 980 case 7: 981 return "Raw"; 982 case 9: 983 return "Motion Picture"; 984 default: 985 return "Unknown (" + value + ")"; 986 } 987 } 988 989 @Nullable 990 public String getVersionDescription() 991 { 992 return convertBytesToVersionString(_directory.getIntArray(PanasonicMakernoteDirectory.TAG_VERSION), 2); 993 } 994 995 @Nullable 996 public String getMakernoteVersionDescription() 997 { 998 return convertBytesToVersionString(_directory.getIntArray(PanasonicMakernoteDirectory.TAG_MAKERNOTE_VERSION), 2); 999 } 1000 1001 @Nullable 1002 public String getExifVersionDescription() 1003 { 1004 return convertBytesToVersionString(_directory.getIntArray(PanasonicMakernoteDirectory.TAG_EXIF_VERSION), 2); 1005 } 1006 1007 @Nullable 1008 public String getInternalSerialNumberDescription() 1009 { 1010 final byte[] bytes = _directory.getByteArray(PanasonicMakernoteDirectory.TAG_INTERNAL_SERIAL_NUMBER); 1011 1012 if (bytes==null) 1013 return null; 1014 1015 int length = bytes.length; 1016 for (int index = 0; index < bytes.length; index++) { 1017 int i = bytes[index] & 0xFF; 1018 if (i == 0 || i > 0x7F) { 1019 length = index; 1020 break; 1021 } 1022 } 1023 1024 return new String(bytes, 0, length); 1025 } 1026 1027 @Nullable 1028 public String getWhiteBalanceDescription() 1029 { 1030 Integer value = _directory.getInteger(PanasonicMakernoteDirectory.TAG_WHITE_BALANCE); 1031 if (value == null) 1032 return null; 1033 switch (value) { 1034 case 1: 1035 return "Auto"; 1036 case 2: 1037 return "Daylight"; 1038 case 3: 1039 return "Cloudy"; 1040 case 4: 1041 return "Incandescent"; 1042 case 5: 1043 return "Manual"; 1044 case 8: 1045 return "Flash"; 1046 case 10: 1047 return "Black & White"; 1048 case 11: 1049 return "Manual"; 1050 case 12: 1051 return "Shade"; 1052 default: 1053 return "Unknown (" + value + ")"; 1054 } 1055 } 1056 1057 @Nullable 1058 public String getBabyAgeDescription() 1059 { 1060 final Age age = _directory.getAge(PanasonicMakernoteDirectory.TAG_BABY_AGE); 1061 if (age==null) 1062 return null; 1063 return age.toFriendlyString(); 1064 } 1065 1066 @Nullable 1067 public String getBabyAge1Description() 1068 { 1069 final Age age = _directory.getAge(PanasonicMakernoteDirectory.TAG_BABY_AGE_1); 1070 if (age==null) 1071 return null; 1072 return age.toFriendlyString(); 1073 } 1074 1075 @Nullable 1076 private String getTextDescription(int tag) 1077 { 1078 byte[] values = _directory.getByteArray(tag); 1079 if (values == null) 1080 return null; 1081 try { 1082 return new String(values, "ASCII").trim(); 1083 } catch (UnsupportedEncodingException e) { 1084 return null; 1085 } 1086 } 1087 1088 @Nullable 1089 private String getOnOffDescription(int tag) 1090 { 1091 Integer value = _directory.getInteger(tag); 1092 if (value == null) 1093 return null; 1094 switch (value) { 1095 case 1: 1096 return "Off"; 1097 case 2: 1098 return "On"; 81 1099 default: 82 1100 return "Unknown (" + value + ")"; -
trunk/src/com/drew/metadata/exif/PanasonicMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 25 import com.drew.lang.ByteArrayReader; 26 import com.drew.lang.annotations.NotNull; 27 import com.drew.lang.annotations.Nullable; 28 import com.drew.metadata.Age; 19 29 import com.drew.metadata.Directory; 30 import com.drew.metadata.Face; 20 31 21 32 import java.util.HashMap; 22 33 23 34 /** 35 * Describes tags specific to Panasonic and Leica cameras. 24 36 * 37 * @author Drew Noakes http://drewnoakes.com, Philipp Sandhaus 25 38 */ 26 39 public class PanasonicMakernoteDirectory extends Directory 27 40 { 28 public static final int TAG_PANASONIC_QUALITY_MODE = 0x0001; 29 public static final int TAG_PANASONIC_VERSION = 0x0002; 30 /** 31 * 1 = On 32 * 2 = Off 33 */ 34 public static final int TAG_PANASONIC_MACRO_MODE = 0x001C; 35 /** 36 * 1 = Normal 37 * 2 = Portrait 38 * 9 = Macro 39 */ 40 public static final int TAG_PANASONIC_RECORD_MODE = 0x001F; 41 public static final int TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO = 0x0E00; 42 43 protected static final HashMap tagNameMap = new HashMap(); 41 42 /** 43 * <br> 44 * 2 = High <br> 45 * 3 = Normal <br> 46 * 6 = Very High <br> 47 * 7 = Raw <br> 48 * 9 = Motion Picture <br> 49 */ 50 public static final int TAG_QUALITY_MODE = 0x0001; 51 public static final int TAG_VERSION = 0x0002; 52 53 /** 54 * <br> 55 * 1 = Auto <br> 56 * 2 = Daylight <br> 57 * 3 = Cloudy <br> 58 * 4 = Incandescent <br> 59 * 5 = Manual <br> 60 * 8 = Flash <br> 61 * 10 = Black & White <br> 62 * 11 = Manual <br> 63 * 12 = Shade <br> 64 */ 65 public static final int TAG_WHITE_BALANCE = 0x0003; 66 67 68 /** 69 * <br> 70 * 1 = Auto <br> 71 * 2 = Manual <br> 72 * 4 = Auto, Focus Button <br> 73 * 5 = Auto, Continuous <br> 74 */ 75 public static final int TAG_FOCUS_MODE = 0x0007; 76 77 /** 78 * <br> 79 * 2 bytes <br> 80 * (DMC-FZ10) <br> 81 * '0 1' = Spot Mode On <br> 82 * '0 16' = Spot Mode Off <br> 83 * '(other models) <br> 84 * 16 = Normal? <br> 85 * '0 1' = 9-area <br> 86 * '0 16' = 3-area (high speed) <br> 87 * '1 0' = Spot Focusing <br> 88 * '1 1' = 5-area <br> 89 * '16 0' = 1-area <br> 90 * '16 16' = 1-area (high speed) <br> 91 * '32 0' = Auto or Face Detect <br> 92 * '32 1' = 3-area (left)? <br> 93 * '32 2' = 3-area (center)? <br> 94 * '32 3' = 3-area (right)? <br> 95 * '64 0' = Face Detect <br> 96 */ 97 public static final int TAG_AF_AREA_MODE = 0x000f; 98 99 /** 100 * <br> 101 * 2 = On, Mode 1 <br> 102 * 3 = Off <br> 103 * 4 = On, Mode 2 <br> 104 */ 105 public static final int TAG_IMAGE_STABILIZATION = 0x001a; 106 107 /** 108 * <br> 109 * 1 = On <br> 110 * 2 = Off <br> 111 */ 112 public static final int TAG_MACRO_MODE = 0x001C; 113 114 /** 115 * <br> 116 * 1 = Normal <br> 117 * 2 = Portrait <br> 118 * 3 = Scenery <br> 119 * 4 = Sports <br> 120 * 5 = Night Portrait <br> 121 * 6 = Program <br> 122 * 7 = Aperture Priority <br> 123 * 8 = Shutter Priority <br> 124 * 9 = Macro <br> 125 * 10= Spot <br> 126 * 11= Manual <br> 127 * 12= Movie Preview <br> 128 * 13= Panning <br> 129 * 14= Simple <br> 130 * 15= Color Effects <br> 131 * 16= Self Portrait <br> 132 * 17= Economy <br> 133 * 18= Fireworks <br> 134 * 19= Party <br> 135 * 20= Snow <br> 136 * 21= Night Scenery <br> 137 * 22= Food <br> 138 * 23= Baby <br> 139 * 24= Soft Skin <br> 140 * 25= Candlelight <br> 141 * 26= Starry Night <br> 142 * 27= High Sensitivity <br> 143 * 28= Panorama Assist <br> 144 * 29= Underwater <br> 145 * 30= Beach <br> 146 * 31= Aerial Photo <br> 147 * 32= Sunset <br> 148 * 33= Pet <br> 149 * 34= Intelligent ISO <br> 150 * 35= Clipboard <br> 151 * 36= High Speed Continuous Shooting <br> 152 * 37= Intelligent Auto <br> 153 * 39= Multi-aspect <br> 154 * 41= Transform <br> 155 * 42= Flash Burst <br> 156 * 43= Pin Hole <br> 157 * 44= Film Grain <br> 158 * 45= My Color <br> 159 * 46= Photo Frame <br> 160 * 51= HDR <br> 161 */ 162 public static final int TAG_RECORD_MODE = 0x001F; 163 164 /** 165 * 1 = Yes <br> 166 * 2 = No <br> 167 */ 168 public static final int TAG_AUDIO = 0x0020; 169 170 /** 171 * No idea, what this is 172 */ 173 public static final int TAG_UNKNOWN_DATA_DUMP = 0x0021; 174 175 public static final int TAG_WHITE_BALANCE_BIAS = 0x0023; 176 public static final int TAG_FLASH_BIAS = 0x0024; 177 178 /** 179 * this number is unique, and contains the date of manufacture, 180 * but is not the same as the number printed on the camera body 181 */ 182 public static final int TAG_INTERNAL_SERIAL_NUMBER = 0x0025; 183 184 /** 185 * Panasonic Exif Version 186 */ 187 public static final int TAG_EXIF_VERSION = 0x0026; 188 189 190 /** 191 * 1 = Off <br> 192 * 2 = Warm <br> 193 * 3 = Cool <br> 194 * 4 = Black & White <br> 195 * 5 = Sepia <br> 196 */ 197 public static final int TAG_COLOR_EFFECT = 0x0028; 198 199 /** 200 * 4 Bytes <br> 201 * Time in 1/100 s from when the camera was powered on to when the 202 * image is written to memory card 203 */ 204 public static final int TAG_UPTIME = 0x0029; 205 206 207 /** 208 * 0 = Off <br> 209 * 1 = On <br> 210 * 2 = Infinite <br> 211 * 4 = Unlimited <br> 212 */ 213 public static final int TAG_BURST_MODE = 0x002a; 214 215 public static final int TAG_SEQUENCE_NUMBER = 0x002b; 216 217 /** 218 * (this decoding seems to work for some models such as the LC1, LX2, FZ7, FZ8, FZ18 and FZ50, but may not be correct for other models such as the FX10, G1, L1, L10 and LC80) <br> 219 * 0x0 = Normal <br> 220 * 0x1 = Low <br> 221 * 0x2 = High <br> 222 * 0x6 = Medium Low <br> 223 * 0x7 = Medium High <br> 224 * 0x100 = Low <br> 225 * 0x110 = Normal <br> 226 * 0x120 = High <br> 227 * (these values are used by the GF1) <br> 228 * 0 = -2 <br> 229 * 1 = -1 <br> 230 * 2 = Normal <br> 231 * 3 = +1 <br> 232 * 4 = +2 <br> 233 * 7 = Nature (Color Film) <br> 234 * 12 = Smooth (Color Film) or Pure (My Color) <br> 235 * 17 = Dynamic (B&W Film) <br> 236 * 22 = Smooth (B&W Film) <br> 237 * 27 = Dynamic (Color Film) <br> 238 * 32 = Vibrant (Color Film) or Expressive (My Color) <br> 239 * 33 = Elegant (My Color) <br> 240 * 37 = Nostalgic (Color Film) <br> 241 * 41 = Dynamic Art (My Color) <br> 242 * 42 = Retro (My Color) <br> 243 */ 244 public static final int TAG_CONTRAST_MODE = 0x002c; 245 246 247 /** 248 * 0 = Standard <br> 249 * 1 = Low (-1) <br> 250 * 2 = High (+1) <br> 251 * 3 = Lowest (-2) <br> 252 * 4 = Highest (+2) <br> 253 */ 254 public static final int TAG_NOISE_REDUCTION = 0x002d; 255 256 /** 257 * 1 = Off <br> 258 * 2 = 10 s <br> 259 * 3 = 2 s <br> 260 */ 261 public static final int TAG_SELF_TIMER = 0x002e; 262 263 /** 264 * 1 = 0 DG <br> 265 * 3 = 180 DG <br> 266 * 6 = 90 DG <br> 267 * 8 = 270 DG <br> 268 */ 269 public static final int TAG_ROTATION = 0x0030; 270 271 /** 272 * 1 = Fired <br> 273 * 2 = Enabled nut not used <br> 274 * 3 = Disabled but required <br> 275 * 4 = Disabled and not required 276 */ 277 public static final int TAG_AF_ASSIST_LAMP = 0x0031; 278 279 /** 280 * 0 = Normal <br> 281 * 1 = Natural<br> 282 * 2 = Vivid 283 * 284 */ 285 public static final int TAG_COLOR_MODE = 0x0032; 286 287 public static final int TAG_BABY_AGE = 0x0033; 288 289 /** 290 * 1 = Standard <br> 291 * 2 = Extended 292 */ 293 public static final int TAG_OPTICAL_ZOOM_MODE = 0x0034; 294 295 /** 296 * 1 = Off <br> 297 * 2 = Wide <br> 298 * 3 = Telephoto <br> 299 * 4 = Macro 300 */ 301 public static final int TAG_CONVERSION_LENS = 0x0035; 302 303 public static final int TAG_TRAVEL_DAY = 0x0036; 304 305 /** 306 * 0 = Normal 307 */ 308 public static final int TAG_CONTRAST = 0x0039; 309 310 /** 311 * <br> 312 * 1 = Home <br> 313 * 2 = Destination 314 */ 315 public static final int TAG_WORLD_TIME_LOCATION = 0x003a; 316 317 /** 318 * 1 = Off <br> 319 * 2 = On 320 */ 321 public static final int TAG_TEXT_STAMP = 0x003b; 322 323 public static final int TAG_PROGRAM_ISO = 0x003c; 324 325 /** 326 * <br> 327 * 1 = Normal <br> 328 * 2 = Outdoor/Illuminations/Flower/HDR Art <br> 329 * 3 = Indoor/Architecture/Objects/HDR B&W <br> 330 * 4 = Creative <br> 331 * 5 = Auto <br> 332 * 7 = Expressive <br> 333 * 8 = Retro <br> 334 * 9 = Pure <br> 335 * 10 = Elegant <br> 336 * 12 = Monochrome <br> 337 * 13 = Dynamic Art <br> 338 * 14 = Silhouette <br> 339 */ 340 public static final int TAG_ADVANCED_SCENE_MODE = 0x003d; 341 342 /** 343 * 1 = Off <br> 344 * 2 = On 345 */ 346 public static final int TAG_TEXT_STAMP_1 = 0x003e; 347 348 public static final int TAG_FACES_DETECTED = 0x003f; 349 350 public static final int TAG_SATURATION = 0x0040; 351 public static final int TAG_SHARPNESS = 0x0041; 352 public static final int TAG_FILM_MODE = 0x0042; 353 354 /** 355 * WB adjust AB. Positive is a shift toward blue. 356 */ 357 public static final int TAG_WB_ADJUST_AB = 0x0046; 358 /** 359 * WB adjust GM. Positive is a shift toward green. 360 */ 361 public static final int TAG_WB_ADJUST_GM = 0x0047; 362 363 364 public static final int TAG_AF_POINT_POSITION = 0x004d; 365 366 367 /** 368 * <br> 369 * Integer (16Bit) Indexes: <br> 370 * 0 Number Face Positions (maybe less than Faces Detected) <br> 371 * 1-4 Face Position 1 <br> 372 * 5-8 Face Position 2 <br> 373 * and so on <br> 374 * <br> 375 * The four Integers are interpreted as follows: <br> 376 * (XYWH) X,Y Center of Face, (W,H) Width and Height <br> 377 * All values are in respect to double the size of the thumbnail image <br> 378 * 379 */ 380 public static final int TAG_FACE_DETECTION_INFO = 0x004e; 381 public static final int TAG_LENS_TYPE = 0x0051; 382 public static final int TAG_LENS_SERIAL_NUMBER = 0x0052; 383 public static final int TAG_ACCESSORY_TYPE = 0x0053; 384 385 /** 386 * (decoded as two 16-bit signed integers) 387 * '-1 1' = Slim Low 388 * '-3 2' = Slim High 389 * '0 0' = Off 390 * '1 1' = Stretch Low 391 * '3 2' = Stretch High 392 */ 393 public static final int TAG_TRANSFORM = 0x0059; 394 395 /** 396 * 0 = Off <br> 397 * 1 = Low <br> 398 * 2 = Standard <br> 399 * 3 = High 400 */ 401 public static final int TAG_INTELLIGENT_EXPOSURE = 0x005d; 402 403 /** 404 * Info at http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html 405 * 406 */ 407 public static final int TAG_PRINT_IMAGE_MATCHING_INFO = 0x0E00; 408 409 410 411 /** 412 * Byte Indexes: <br> 413 * 0 Int (2 Byte) Number of Recognized Faces <br> 414 * 4 String(20 Byte) Recognized Face 1 Name <br> 415 * 24 4 Int (8 Byte) Recognized Face 1 Position (Same Format as Face Detection) <br> 416 * 32 String(20 Byte) Recognized Face 1 Age <br> 417 * 52 String(20 Byte) Recognized Face 2 Name <br> 418 * 72 4 Int (8 Byte) Recognized Face 2 Position (Same Format as Face Detection) <br> 419 * 80 String(20 Byte) Recognized Face 2 Age <br> 420 * <br> 421 * And so on <br> 422 * <br> 423 * The four Integers are interpreted as follows: <br> 424 * (XYWH) X,Y Center of Face, (W,H) Width and Height <br> 425 * All values are in respect to double the size of the thumbnail image <br> 426 * 427 */ 428 public static final int TAG_FACE_RECOGNITION_INFO = 0x0061; 429 430 /** 431 * 0 = No <br> 432 * 1 = Yes 433 */ 434 public static final int TAG_FLASH_WARNING = 0x0062; 435 public static final int TAG_RECOGNIZED_FACE_FLAGS = 0x0063; 436 public static final int TAG_TITLE = 0x0065; 437 public static final int TAG_BABY_NAME = 0x0066; 438 public static final int TAG_LOCATION = 0x0067; 439 public static final int TAG_COUNTRY = 0x0069; 440 public static final int TAG_STATE = 0x006b; 441 public static final int TAG_CITY = 0x006d; 442 public static final int TAG_LANDMARK = 0x006f; 443 444 /** 445 * 0 = Off <br> 446 * 2 = Auto <br> 447 * 3 = On 448 */ 449 public static final int TAG_INTELLIGENT_RESOLUTION = 0x0070; 450 451 public static final int TAG_MAKERNOTE_VERSION = 0x8000; 452 public static final int TAG_SCENE_MODE = 0x8001; 453 public static final int TAG_WB_RED_LEVEL = 0x8004; 454 public static final int TAG_WB_GREEN_LEVEL = 0x8005; 455 public static final int TAG_WB_BLUE_LEVEL = 0x8006; 456 public static final int TAG_FLASH_FIRED = 0x8007; 457 public static final int TAG_TEXT_STAMP_2 = 0x8008; 458 public static final int TAG_TEXT_STAMP_3 = 0x8009; 459 public static final int TAG_BABY_AGE_1 = 0x8010; 460 461 /** 462 * (decoded as two 16-bit signed integers) 463 * '-1 1' = Slim Low 464 * '-3 2' = Slim High 465 * '0 0' = Off 466 * '1 1' = Stretch Low 467 * '3 2' = Stretch High 468 */ 469 public static final int TAG_TRANSFORM_1 = 0x8012; 470 471 @NotNull 472 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 44 473 45 474 static 46 475 { 47 tagNameMap.put(new Integer(TAG_PANASONIC_QUALITY_MODE), "Quality Mode"); 48 tagNameMap.put(new Integer(TAG_PANASONIC_VERSION), "Version"); 49 tagNameMap.put(new Integer(TAG_PANASONIC_MACRO_MODE), "Macro Mode"); 50 tagNameMap.put(new Integer(TAG_PANASONIC_RECORD_MODE), "Record Mode"); 51 tagNameMap.put(new Integer(TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); 476 _tagNameMap.put(TAG_QUALITY_MODE, "Quality Mode"); 477 _tagNameMap.put(TAG_VERSION, "Version"); 478 _tagNameMap.put(TAG_WHITE_BALANCE, "White Balance"); 479 _tagNameMap.put(TAG_FOCUS_MODE, "Focus Mode"); 480 _tagNameMap.put(TAG_AF_AREA_MODE, "AF Area Mode"); 481 _tagNameMap.put(TAG_IMAGE_STABILIZATION, "Image Stabilization"); 482 _tagNameMap.put(TAG_MACRO_MODE, "Macro Mode"); 483 _tagNameMap.put(TAG_RECORD_MODE, "Record Mode"); 484 _tagNameMap.put(TAG_AUDIO, "Audio"); 485 _tagNameMap.put(TAG_INTERNAL_SERIAL_NUMBER, "Internal Serial Number"); 486 _tagNameMap.put(TAG_UNKNOWN_DATA_DUMP, "Unknown Data Dump"); 487 _tagNameMap.put(TAG_WHITE_BALANCE_BIAS, "White Balance Bias"); 488 _tagNameMap.put(TAG_FLASH_BIAS, "Flash Bias"); 489 _tagNameMap.put(TAG_EXIF_VERSION, "Exif Version"); 490 _tagNameMap.put(TAG_COLOR_EFFECT, "Color Effect"); 491 _tagNameMap.put(TAG_UPTIME, "Camera Uptime"); 492 _tagNameMap.put(TAG_BURST_MODE, "Burst Mode"); 493 _tagNameMap.put(TAG_SEQUENCE_NUMBER, "Sequence Number"); 494 _tagNameMap.put(TAG_CONTRAST_MODE, "Contrast Mode"); 495 _tagNameMap.put(TAG_NOISE_REDUCTION, "Noise Reduction"); 496 _tagNameMap.put(TAG_SELF_TIMER, "Self Timer"); 497 _tagNameMap.put(TAG_ROTATION, "Rotation"); 498 _tagNameMap.put(TAG_AF_ASSIST_LAMP, "AF Assist Lamp"); 499 _tagNameMap.put(TAG_COLOR_MODE, "Color Mode"); 500 _tagNameMap.put(TAG_BABY_AGE, "Baby Age"); 501 _tagNameMap.put(TAG_OPTICAL_ZOOM_MODE, "Optical Zoom Mode"); 502 _tagNameMap.put(TAG_CONVERSION_LENS, "Conversion Lens"); 503 _tagNameMap.put(TAG_TRAVEL_DAY, "Travel Day"); 504 _tagNameMap.put(TAG_CONTRAST, "Contrast"); 505 _tagNameMap.put(TAG_WORLD_TIME_LOCATION, "World Time Location"); 506 _tagNameMap.put(TAG_TEXT_STAMP, "Text Stamp"); 507 _tagNameMap.put(TAG_PROGRAM_ISO, "Program ISO"); 508 _tagNameMap.put(TAG_ADVANCED_SCENE_MODE, "Advanced Scene Mode"); 509 _tagNameMap.put(TAG_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info"); 510 _tagNameMap.put(TAG_FACES_DETECTED, "Number of Detected Faces"); 511 _tagNameMap.put(TAG_SATURATION, "Saturation"); 512 _tagNameMap.put(TAG_SHARPNESS, "Sharpness"); 513 _tagNameMap.put(TAG_FILM_MODE, "Film Mode"); 514 _tagNameMap.put(TAG_WB_ADJUST_AB, "White Balance Adjust (AB)"); 515 _tagNameMap.put(TAG_WB_ADJUST_GM, "White Balance Adjust (GM)"); 516 _tagNameMap.put(TAG_AF_POINT_POSITION, "Af Point Position"); 517 _tagNameMap.put(TAG_FACE_DETECTION_INFO, "Face Detection Info"); 518 _tagNameMap.put(TAG_LENS_TYPE, "Lens Type"); 519 _tagNameMap.put(TAG_LENS_SERIAL_NUMBER, "Lens Serial Number"); 520 _tagNameMap.put(TAG_ACCESSORY_TYPE, "Accessory Type"); 521 _tagNameMap.put(TAG_TRANSFORM, "Transform"); 522 _tagNameMap.put(TAG_INTELLIGENT_EXPOSURE, "Intelligent Exposure"); 523 _tagNameMap.put(TAG_FACE_RECOGNITION_INFO, "Face Recognition Info"); 524 _tagNameMap.put(TAG_FLASH_WARNING, "Flash Warning"); 525 _tagNameMap.put(TAG_RECOGNIZED_FACE_FLAGS, "Recognized Face Flags"); 526 _tagNameMap.put(TAG_TITLE, "Title"); 527 _tagNameMap.put(TAG_BABY_NAME, "Baby Name"); 528 _tagNameMap.put(TAG_LOCATION, "Location"); 529 _tagNameMap.put(TAG_COUNTRY, "Country"); 530 _tagNameMap.put(TAG_STATE, "State"); 531 _tagNameMap.put(TAG_CITY, "City"); 532 _tagNameMap.put(TAG_LANDMARK, "Landmark"); 533 _tagNameMap.put(TAG_INTELLIGENT_RESOLUTION, "Intelligent Resolution"); 534 _tagNameMap.put(TAG_MAKERNOTE_VERSION, "Makernote Version"); 535 _tagNameMap.put(TAG_SCENE_MODE, "Scene Mode"); 536 _tagNameMap.put(TAG_WB_RED_LEVEL, "White Balance (Red)"); 537 _tagNameMap.put(TAG_WB_GREEN_LEVEL, "White Balance (Green)"); 538 _tagNameMap.put(TAG_WB_BLUE_LEVEL, "White Balance (Blue)"); 539 _tagNameMap.put(TAG_FLASH_FIRED, "Flash Fired"); 540 _tagNameMap.put(TAG_TEXT_STAMP_1, "Text Stamp 1"); 541 _tagNameMap.put(TAG_TEXT_STAMP_2, "Text Stamp 2"); 542 _tagNameMap.put(TAG_TEXT_STAMP_3, "Text Stamp 3"); 543 _tagNameMap.put(TAG_BABY_AGE_1, "Baby Age 1"); 544 _tagNameMap.put(TAG_TRANSFORM_1, "Transform 1"); 52 545 } 53 546 … … 57 550 } 58 551 552 @NotNull 59 553 public String getName() 60 554 { … … 62 556 } 63 557 64 protected HashMap getTagNameMap() 558 @NotNull 559 protected HashMap<Integer, String> getTagNameMap() 65 560 { 66 return tagNameMap; 561 return _tagNameMap; 67 562 } 563 564 @Nullable 565 public Face[] getDetectedFaces() 566 { 567 byte[] bytes = getByteArray(PanasonicMakernoteDirectory.TAG_FACE_DETECTION_INFO); 568 if (bytes==null) 569 return null; 570 571 BufferReader reader = new ByteArrayReader(bytes); 572 reader.setMotorolaByteOrder(false); 573 574 try { 575 int faceCount = reader.getUInt16(0); 576 if (faceCount==0) 577 return null; 578 Face[] faces = new Face[faceCount]; 579 580 for (int i = 0; i < faceCount; i++) { 581 int offset = 2 + i * 8; 582 faces[i] = new Face( 583 reader.getUInt16(offset), 584 reader.getUInt16(offset + 2), 585 reader.getUInt16(offset + 4), 586 reader.getUInt16(offset + 6) 587 , null, null); 588 } 589 return faces; 590 } catch (BufferBoundsException e) { 591 return null; 592 } 593 } 594 595 @Nullable 596 public Face[] getRecognizedFaces() 597 { 598 byte[] bytes = getByteArray(PanasonicMakernoteDirectory.TAG_FACE_RECOGNITION_INFO); 599 if (bytes == null) 600 return null; 601 602 BufferReader reader = new ByteArrayReader(bytes); 603 reader.setMotorolaByteOrder(false); 604 605 try { 606 int faceCount = reader.getUInt16(0); 607 if (faceCount==0) 608 return null; 609 Face[] faces = new Face[faceCount]; 610 611 for (int i = 0; i < faceCount; i++) { 612 int offset = 4 + i * 44; 613 String name = reader.getString(offset, 20, "ASCII").trim(); 614 String age = reader.getString(offset + 28, 20, "ASCII").trim(); 615 faces[i] = new Face( 616 reader.getUInt16(offset + 20), 617 reader.getUInt16(offset + 22), 618 reader.getUInt16(offset + 24), 619 reader.getUInt16(offset + 26), 620 name, 621 Age.fromPanasonicString(age)); 622 } 623 return faces; 624 } catch (BufferBoundsException e) { 625 return null; 626 } 627 } 628 629 /** 630 * Attempts to convert the underlying string value (as stored in the directory) into an Age object. 631 * @param tag The tag identifier. 632 * @return The parsed Age object, or null if the tag was empty of the value unable to be parsed. 633 */ 634 @Nullable 635 public Age getAge(int tag) 636 { 637 final String ageString = getString(tag); 638 if (ageString==null) 639 return null; 640 return Age.fromPanasonicString(ageString); 641 } 68 642 } -
trunk/src/com/drew/metadata/exif/PentaxMakernoteDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.exif; 16 22 17 import com.drew. metadata.Directory;18 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 19 25 import com.drew.metadata.TagDescriptor; 20 26 21 27 /** 22 * Provides human-readable string versions of the tags stored in PentaxMakernoteDirectory.23 * 28 * Provides human-readable string representations of tag values stored in a <code>PentaxMakernoteDirectory</code>. 29 * <p/> 24 30 * Some information about this makernote taken from here: 25 31 * http://www.ozhiker.com/electronics/pjmt/jpeg_info/pentax_mn.html 32 * 33 * @author Drew Noakes http://drewnoakes.com 26 34 */ 27 public class PentaxMakernoteDescriptor extends TagDescriptor 35 public class PentaxMakernoteDescriptor extends TagDescriptor<PentaxMakernoteDirectory> 28 36 { 29 public PentaxMakernoteDescriptor(Directory directory) 37 public PentaxMakernoteDescriptor(@NotNull PentaxMakernoteDirectory directory) 30 38 { 31 39 super(directory); 32 40 } 33 41 34 public String getDescription(int tagType) throws MetadataException 42 @Nullable 43 public String getDescription(int tagType) 35 44 { 36 45 switch (tagType) … … 59 68 return getColourDescription(); 60 69 default: 61 return _directory.getString(tagType); 62 } 63 } 64 65 public String getColourDescription() throws MetadataException 66 { 67 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR)) return null; 68 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR); 70 return super.getDescription(tagType); 71 } 72 } 73 74 @Nullable 75 public String getColourDescription() 76 { 77 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR); 78 if (value==null) 79 return null; 69 80 switch (value) 70 81 { … … 76 87 } 77 88 78 public String getIsoSpeedDescription() throws MetadataException 79 { 80 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED)) return null; 81 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED); 89 @Nullable 90 public String getIsoSpeedDescription() 91 { 92 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED); 93 if (value==null) 94 return null; 82 95 switch (value) 83 96 { … … 91 104 } 92 105 93 public String getSaturationDescription() throws MetadataException 94 { 95 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION)) return null; 96 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION); 106 @Nullable 107 public String getSaturationDescription() 108 { 109 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION); 110 if (value==null) 111 return null; 97 112 switch (value) 98 113 { … … 104 119 } 105 120 106 public String getContrastDescription() throws MetadataException 107 { 108 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST)) return null; 109 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST); 121 @Nullable 122 public String getContrastDescription() 123 { 124 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST); 125 if (value==null) 126 return null; 110 127 switch (value) 111 128 { … … 117 134 } 118 135 119 public String getSharpnessDescription() throws MetadataException 120 { 121 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS)) return null; 122 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS); 136 @Nullable 137 public String getSharpnessDescription() 138 { 139 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS); 140 if (value==null) 141 return null; 123 142 switch (value) 124 143 { … … 130 149 } 131 150 132 public String getDigitalZoomDescription() throws MetadataException 133 { 134 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM)) return null; 135 float value = _directory.getFloat(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM); 151 @Nullable 152 public String getDigitalZoomDescription() 153 { 154 Float value = _directory.getFloatObject(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM); 155 if (value==null) 156 return null; 136 157 if (value==0) 137 158 return "Off"; … … 139 160 } 140 161 141 public String getWhiteBalanceDescription() throws MetadataException 142 { 143 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE)) return null; 144 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE); 162 @Nullable 163 public String getWhiteBalanceDescription() 164 { 165 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE); 166 if (value==null) 167 return null; 145 168 switch (value) 146 169 { … … 155 178 } 156 179 157 public String getFlashModeDescription() throws MetadataException 158 { 159 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE)) return null; 160 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE); 180 @Nullable 181 public String getFlashModeDescription() 182 { 183 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE); 184 if (value==null) 185 return null; 161 186 switch (value) 162 187 { … … 169 194 } 170 195 171 public String getFocusModeDescription() throws MetadataException 172 { 173 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE)) return null; 174 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE); 196 @Nullable 197 public String getFocusModeDescription() 198 { 199 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE); 200 if (value==null) 201 return null; 175 202 switch (value) 176 203 { … … 181 208 } 182 209 183 public String getQualityLevelDescription() throws MetadataException 184 { 185 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL)) return null; 186 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL); 210 @Nullable 211 public String getQualityLevelDescription() 212 { 213 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL); 214 if (value==null) 215 return null; 187 216 switch (value) 188 217 { … … 194 223 } 195 224 196 public String getCaptureModeDescription() throws MetadataException 197 { 198 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE)) return null; 199 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE); 225 @Nullable 226 public String getCaptureModeDescription() 227 { 228 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE); 229 if (value==null) 230 return null; 200 231 switch (value) 201 232 { … … 209 240 210 241 /* 211 public String getPrintImageMatchingInfoDescription() throws MetadataException 212 { 213 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO)) return null; 242 public String getPrintImageMatchingInfoDescription() 243 { 214 244 byte[] bytes = _directory.getByteArray(PentaxMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO); 245 if (bytes==null) 246 return null; 215 247 return "(" + bytes.length + " bytes)"; 216 248 } 217 249 218 public String getMacroModeDescription() throws MetadataException 219 { 220 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE)) return null; 221 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE); 250 public String getMacroModeDescription() 251 { 252 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE); 253 if (value==null) 254 return null; 222 255 switch (value) { 223 256 case 1: … … 230 263 } 231 264 232 public String getRecordModeDescription() throws MetadataException 233 { 234 if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE)) return null; 235 int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE); 265 public String getRecordModeDescription() 266 { 267 Integer value = _directory.getInteger(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE); 268 if (value==null) 269 return null; 236 270 switch (value) { 237 271 case 1: -
trunk/src/com/drew/metadata/exif/PentaxMakernoteDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.exif; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 24 * Directory for metadata specific to Pentax and Asahi cameras. 29 * Describes tags specific to Pentax and Asahi cameras. 30 * 31 * @author Drew Noakes http://drewnoakes.com 25 32 */ 26 33 public class PentaxMakernoteDirectory extends Directory … … 122 129 public static final int TAG_PENTAX_DAYLIGHT_SAVINGS = 0x1001; 123 130 124 protected static final HashMap tagNameMap = new HashMap(); 131 @NotNull 132 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 125 133 126 134 static 127 135 { 128 tagNameMap.put (new Integer(TAG_PENTAX_CAPTURE_MODE), "Capture Mode");129 tagNameMap.put (new Integer(TAG_PENTAX_QUALITY_LEVEL), "Quality Level");130 tagNameMap.put (new Integer(TAG_PENTAX_FOCUS_MODE), "Focus Mode");131 tagNameMap.put (new Integer(TAG_PENTAX_FLASH_MODE), "Flash Mode");132 tagNameMap.put (new Integer(TAG_PENTAX_WHITE_BALANCE), "White Balance");133 tagNameMap.put (new Integer(TAG_PENTAX_DIGITAL_ZOOM), "Digital Zoom");134 tagNameMap.put (new Integer(TAG_PENTAX_SHARPNESS), "Sharpness");135 tagNameMap.put (new Integer(TAG_PENTAX_CONTRAST), "Contrast");136 tagNameMap.put (new Integer(TAG_PENTAX_SATURATION), "Saturation");137 tagNameMap.put (new Integer(TAG_PENTAX_ISO_SPEED), "ISO Speed");138 tagNameMap.put (new Integer(TAG_PENTAX_COLOUR), "Colour");139 tagNameMap.put (new Integer(TAG_PENTAX_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");140 tagNameMap.put (new Integer(TAG_PENTAX_TIME_ZONE), "Time Zone");141 tagNameMap.put (new Integer(TAG_PENTAX_DAYLIGHT_SAVINGS), "Daylight Savings");136 _tagNameMap.put(TAG_PENTAX_CAPTURE_MODE, "Capture Mode"); 137 _tagNameMap.put(TAG_PENTAX_QUALITY_LEVEL, "Quality Level"); 138 _tagNameMap.put(TAG_PENTAX_FOCUS_MODE, "Focus Mode"); 139 _tagNameMap.put(TAG_PENTAX_FLASH_MODE, "Flash Mode"); 140 _tagNameMap.put(TAG_PENTAX_WHITE_BALANCE, "White Balance"); 141 _tagNameMap.put(TAG_PENTAX_DIGITAL_ZOOM, "Digital Zoom"); 142 _tagNameMap.put(TAG_PENTAX_SHARPNESS, "Sharpness"); 143 _tagNameMap.put(TAG_PENTAX_CONTRAST, "Contrast"); 144 _tagNameMap.put(TAG_PENTAX_SATURATION, "Saturation"); 145 _tagNameMap.put(TAG_PENTAX_ISO_SPEED, "ISO Speed"); 146 _tagNameMap.put(TAG_PENTAX_COLOUR, "Colour"); 147 _tagNameMap.put(TAG_PENTAX_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info"); 148 _tagNameMap.put(TAG_PENTAX_TIME_ZONE, "Time Zone"); 149 _tagNameMap.put(TAG_PENTAX_DAYLIGHT_SAVINGS, "Daylight Savings"); 142 150 } 143 151 … … 147 155 } 148 156 157 @NotNull 149 158 public String getName() 150 159 { … … 152 161 } 153 162 154 protected HashMap getTagNameMap() 163 @NotNull 164 protected HashMap<Integer, String> getTagNameMap() 155 165 { 156 return tagNameMap; 166 return _tagNameMap; 157 167 } 158 168 } -
trunk/src/com/drew/metadata/iptc/IptcDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 21-Nov-2002 17:58:19 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.iptc; 18 22 19 import com.drew.metadata.Directory; 23 import com.drew.lang.StringUtil; 24 import com.drew.lang.annotations.NotNull; 25 import com.drew.lang.annotations.Nullable; 20 26 import com.drew.metadata.TagDescriptor; 21 27 22 28 /** 23 * 29 * Provides human-readable string representations of tag values stored in a <code>IptcDirectory</code>. 30 * <p/> 31 * As the IPTC directory already stores values as strings, this class simply returns the tag's value. 32 * 33 * @author Drew Noakes http://drewnoakes.com 24 34 */ 25 public class IptcDescriptor extends TagDescriptor 35 public class IptcDescriptor extends TagDescriptor<IptcDirectory> 26 36 { 27 public IptcDescriptor(Directory directory) 37 public IptcDescriptor(@NotNull IptcDirectory directory) 28 38 { 29 39 super(directory); 30 40 } 31 41 42 @Nullable 32 43 public String getDescription(int tagType) 33 44 { 34 return _directory.getString(tagType); 45 switch (tagType) { 46 case IptcDirectory.TAG_FILE_FORMAT: 47 return getFileFormatDescription(); 48 case IptcDirectory.TAG_KEYWORDS: 49 return getKeywordsDescription(); 50 default: 51 return super.getDescription(tagType); 52 } 53 } 54 55 @Nullable 56 public String getFileFormatDescription() 57 { 58 Integer value = _directory.getInteger(IptcDirectory.TAG_FILE_FORMAT); 59 if (value == null) 60 return null; 61 switch (value) { 62 case 0: return "No ObjectData"; 63 case 1: return "IPTC-NAA Digital Newsphoto Parameter Record"; 64 case 2: return "IPTC7901 Recommended Message Format"; 65 case 3: return "Tagged Image File Format (Adobe/Aldus Image data)"; 66 case 4: return "Illustrator (Adobe Graphics data)"; 67 case 5: return "AppleSingle (Apple Computer Inc)"; 68 case 6: return "NAA 89-3 (ANPA 1312)"; 69 case 7: return "MacBinary II"; 70 case 8: return "IPTC Unstructured Character Oriented File Format (UCOFF)"; 71 case 9: return "United Press International ANPA 1312 variant"; 72 case 10: return "United Press International Down-Load Message"; 73 case 11: return "JPEG File Interchange (JFIF)"; 74 case 12: return "Photo-CD Image-Pac (Eastman Kodak)"; 75 case 13: return "Bit Mapped Graphics File [.BMP] (Microsoft)"; 76 case 14: return "Digital Audio File [.WAV] (Microsoft & Creative Labs)"; 77 case 15: return "Audio plus Moving Video [.AVI] (Microsoft)"; 78 case 16: return "PC DOS/Windows Executable Files [.COM][.EXE]"; 79 case 17: return "Compressed Binary File [.ZIP] (PKWare Inc)"; 80 case 18: return "Audio Interchange File Format AIFF (Apple Computer Inc)"; 81 case 19: return "RIFF Wave (Microsoft Corporation)"; 82 case 20: return "Freehand (Macromedia/Aldus)"; 83 case 21: return "Hypertext Markup Language [.HTML] (The Internet Society)"; 84 case 22: return "MPEG 2 Audio Layer 2 (Musicom), ISO/IEC"; 85 case 23: return "MPEG 2 Audio Layer 3, ISO/IEC"; 86 case 24: return "Portable Document File [.PDF] Adobe"; 87 case 25: return "News Industry Text Format (NITF)"; 88 case 26: return "Tape Archive [.TAR]"; 89 case 27: return "Tidningarnas Telegrambyra NITF version (TTNITF DTD)"; 90 case 28: return "Ritzaus Bureau NITF version (RBNITF DTD)"; 91 case 29: return "Corel Draw [.CDR]"; 92 } 93 return String.format("Unknown (%d)", value); 94 } 95 96 @Nullable 97 public String getByLineDescription() 98 { 99 return _directory.getString(IptcDirectory.TAG_BY_LINE); 100 } 101 102 @Nullable 103 public String getByLineTitleDescription() 104 { 105 return _directory.getString(IptcDirectory.TAG_BY_LINE_TITLE); 106 } 107 108 @Nullable 109 public String getCaptionDescription() 110 { 111 return _directory.getString(IptcDirectory.TAG_CAPTION); 112 } 113 114 @Nullable 115 public String getCategoryDescription() 116 { 117 return _directory.getString(IptcDirectory.TAG_CATEGORY); 118 } 119 120 @Nullable 121 public String getCityDescription() 122 { 123 return _directory.getString(IptcDirectory.TAG_CITY); 124 } 125 126 @Nullable 127 public String getCopyrightNoticeDescription() 128 { 129 return _directory.getString(IptcDirectory.TAG_COPYRIGHT_NOTICE); 130 } 131 132 @Nullable 133 public String getCountryOrPrimaryLocationDescription() 134 { 135 return _directory.getString(IptcDirectory.TAG_COUNTRY_OR_PRIMARY_LOCATION_NAME); 136 } 137 138 @Nullable 139 public String getCreditDescription() 140 { 141 return _directory.getString(IptcDirectory.TAG_CREDIT); 142 } 143 144 @Nullable 145 public String getDateCreatedDescription() 146 { 147 return _directory.getString(IptcDirectory.TAG_DATE_CREATED); 148 } 149 150 @Nullable 151 public String getHeadlineDescription() 152 { 153 return _directory.getString(IptcDirectory.TAG_HEADLINE); 154 } 155 156 @Nullable 157 public String getKeywordsDescription() 158 { 159 final String[] keywords = _directory.getStringArray(IptcDirectory.TAG_KEYWORDS); 160 if (keywords==null) 161 return null; 162 return StringUtil.join(keywords, ";"); 163 } 164 165 @Nullable 166 public String getObjectNameDescription() 167 { 168 return _directory.getString(IptcDirectory.TAG_OBJECT_NAME); 169 } 170 171 @Nullable 172 public String getOriginalTransmissionReferenceDescription() 173 { 174 return _directory.getString(IptcDirectory.TAG_ORIGINAL_TRANSMISSION_REFERENCE); 175 } 176 177 @Nullable 178 public String getOriginatingProgramDescription() 179 { 180 return _directory.getString(IptcDirectory.TAG_ORIGINATING_PROGRAM); 181 } 182 183 @Nullable 184 public String getProvinceOrStateDescription() 185 { 186 return _directory.getString(IptcDirectory.TAG_PROVINCE_OR_STATE); 187 } 188 189 @Nullable 190 public String getRecordVersionDescription() 191 { 192 return _directory.getString(IptcDirectory.TAG_APPLICATION_RECORD_VERSION); 193 } 194 195 @Nullable 196 public String getReleaseDateDescription() 197 { 198 return _directory.getString(IptcDirectory.TAG_RELEASE_DATE); 199 } 200 201 @Nullable 202 public String getReleaseTimeDescription() 203 { 204 return _directory.getString(IptcDirectory.TAG_RELEASE_TIME); 205 } 206 207 @Nullable 208 public String getSourceDescription() 209 { 210 return _directory.getString(IptcDirectory.TAG_SOURCE); 211 } 212 213 @Nullable 214 public String getSpecialInstructionsDescription() 215 { 216 return _directory.getString(IptcDirectory.TAG_SPECIAL_INSTRUCTIONS); 217 } 218 219 @Nullable 220 public String getSupplementalCategoriesDescription() 221 { 222 return _directory.getString(IptcDirectory.TAG_SUPPLEMENTAL_CATEGORIES); 223 } 224 225 @Nullable 226 public String getTimeCreatedDescription() 227 { 228 return _directory.getString(IptcDirectory.TAG_TIME_CREATED); 229 } 230 231 @Nullable 232 public String getUrgencyDescription() 233 { 234 return _directory.getString(IptcDirectory.TAG_URGENCY); 235 } 236 237 @Nullable 238 public String getWriterDescription() 239 { 240 return _directory.getString(IptcDirectory.TAG_CAPTION_WRITER); 35 241 } 36 242 } -
trunk/src/com/drew/metadata/iptc/IptcDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 6 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 9 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 14 * 15 * Created by dnoakes on 26-Nov-2002 01:26:39 using IntelliJ IDEA. 2 * Copyright 2002-2012 Drew Noakes 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.iptc; 18 22 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 19 25 import com.drew.metadata.Directory; 20 26 27 import java.util.Arrays; 21 28 import java.util.HashMap; 29 import java.util.List; 22 30 23 31 /** 24 * 32 * Describes tags used by the International Press Telecommunications Council (IPTC) metadata format. 33 * 34 * @author Drew Noakes http://drewnoakes.com 25 35 */ 26 36 public class IptcDirectory extends Directory 27 37 { 28 public static final int TAG_RECORD_VERSION = 0x0200; 29 public static final int TAG_CAPTION = 0x0278; 30 public static final int TAG_WRITER = 0x027a; 31 public static final int TAG_HEADLINE = 0x0269; 32 public static final int TAG_SPECIAL_INSTRUCTIONS = 0x0228; 33 public static final int TAG_BY_LINE = 0x0250; 34 public static final int TAG_BY_LINE_TITLE = 0x0255; 35 public static final int TAG_CREDIT = 0x026e; 36 public static final int TAG_SOURCE = 0x0273; 37 public static final int TAG_OBJECT_NAME = 0x0205; 38 public static final int TAG_DATE_CREATED = 0x0237; 39 public static final int TAG_CITY = 0x025a; 40 public static final int TAG_PROVINCE_OR_STATE = 0x025f; 41 public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION = 0x0265; 42 public static final int TAG_ORIGINAL_TRANSMISSION_REFERENCE = 0x0267; 43 public static final int TAG_CATEGORY = 0x020f; 44 public static final int TAG_SUPPLEMENTAL_CATEGORIES = 0x0214; 45 public static final int TAG_URGENCY = 0x0200 | 10; 46 public static final int TAG_KEYWORDS = 0x0200 | 25; 47 public static final int TAG_COPYRIGHT_NOTICE = 0x0274; 48 public static final int TAG_RELEASE_DATE = 0x0200 | 30; 49 public static final int TAG_RELEASE_TIME = 0x0200 | 35; 50 public static final int TAG_TIME_CREATED = 0x0200 | 60; 51 public static final int TAG_ORIGINATING_PROGRAM = 0x0200 | 65; 52 53 protected static final HashMap tagNameMap = new HashMap(); 38 // IPTC EnvelopeRecord Tags 39 public static final int TAG_ENVELOPE_RECORD_VERSION = 0x0100; // 0 + 0x0100 40 public static final int TAG_DESTINATION = 0x0105; // 5 41 public static final int TAG_FILE_FORMAT = 0x0114; // 20 42 public static final int TAG_FILE_VERSION = 0x0116; // 22 43 public static final int TAG_SERVICE_ID = 0x011E; // 30 44 public static final int TAG_ENVELOPE_NUMBER = 0x0128; // 40 45 public static final int TAG_PRODUCT_ID = 0x0132; // 50 46 public static final int TAG_ENVELOPE_PRIORITY = 0x013C; // 60 47 public static final int TAG_DATE_SENT = 0x0146; // 70 48 public static final int TAG_TIME_SENT = 0x0150; // 80 49 public static final int TAG_CODED_CHARACTER_SET = 0x015A; // 90 50 public static final int TAG_UNIQUE_OBJECT_NAME = 0x0164; // 100 51 public static final int TAG_ARM_IDENTIFIER = 0x0178; // 120 52 public static final int TAG_ARM_VERSION = 0x017a; // 122 53 54 // IPTC ApplicationRecord Tags 55 public static final int TAG_APPLICATION_RECORD_VERSION = 0x0200; // 0 + 0x0200 56 public static final int TAG_OBJECT_TYPE_REFERENCE = 0x0203; // 3 57 public static final int TAG_OBJECT_ATTRIBUTE_REFERENCE = 0x0204; // 4 58 public static final int TAG_OBJECT_NAME = 0x0205; // 5 59 public static final int TAG_EDIT_STATUS = 0x0207; // 7 60 public static final int TAG_EDITORIAL_UPDATE = 0x0208; // 8 61 public static final int TAG_URGENCY = 0X020A; // 10 62 public static final int TAG_SUBJECT_REFERENCE = 0X020C; // 12 63 public static final int TAG_CATEGORY = 0x020F; // 15 64 public static final int TAG_SUPPLEMENTAL_CATEGORIES = 0x0214; // 20 65 public static final int TAG_FIXTURE_ID = 0x0216; // 22 66 public static final int TAG_KEYWORDS = 0x0219; // 25 67 public static final int TAG_CONTENT_LOCATION_CODE = 0x021A; // 26 68 public static final int TAG_CONTENT_LOCATION_NAME = 0x021B; // 27 69 public static final int TAG_RELEASE_DATE = 0X021E; // 30 70 public static final int TAG_RELEASE_TIME = 0x0223; // 35 71 public static final int TAG_EXPIRATION_DATE = 0x0225; // 37 72 public static final int TAG_EXPIRATION_TIME = 0x0226; // 38 73 public static final int TAG_SPECIAL_INSTRUCTIONS = 0x0228; // 40 74 public static final int TAG_ACTION_ADVISED = 0x022A; // 42 75 public static final int TAG_REFERENCE_SERVICE = 0x022D; // 45 76 public static final int TAG_REFERENCE_DATE = 0x022F; // 47 77 public static final int TAG_REFERENCE_NUMBER = 0x0232; // 50 78 public static final int TAG_DATE_CREATED = 0x0237; // 55 79 public static final int TAG_TIME_CREATED = 0X023C; // 60 80 public static final int TAG_DIGITAL_DATE_CREATED = 0x023E; // 62 81 public static final int TAG_DIGITAL_TIME_CREATED = 0x023F; // 63 82 public static final int TAG_ORIGINATING_PROGRAM = 0x0241; // 65 83 public static final int TAG_PROGRAM_VERSION = 0x0246; // 70 84 public static final int TAG_OBJECT_CYCLE = 0x024B; // 75 85 public static final int TAG_BY_LINE = 0x0250; // 80 86 public static final int TAG_BY_LINE_TITLE = 0x0255; // 85 87 public static final int TAG_CITY = 0x025A; // 90 88 public static final int TAG_SUB_LOCATION = 0x025C; // 92 89 public static final int TAG_PROVINCE_OR_STATE = 0x025F; // 95 90 public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION_CODE = 0x0264; // 100 91 public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION_NAME = 0x0265; // 101 92 public static final int TAG_ORIGINAL_TRANSMISSION_REFERENCE = 0x0267; // 103 93 public static final int TAG_HEADLINE = 0x0269; // 105 94 public static final int TAG_CREDIT = 0x026E; // 110 95 public static final int TAG_SOURCE = 0x0273; // 115 96 public static final int TAG_COPYRIGHT_NOTICE = 0x0274; // 116 97 public static final int TAG_CONTACT = 0x0276; // 118 98 public static final int TAG_CAPTION = 0x0278; // 120 99 public static final int TAG_LOCAL_CAPTION = 0x0279; // 121 100 public static final int TAG_CAPTION_WRITER = 0x027A; // 122 101 public static final int TAG_RASTERIZED_CAPTION = 0x027D; // 125 102 public static final int TAG_IMAGE_TYPE = 0x0282; // 130 103 public static final int TAG_IMAGE_ORIENTATION = 0x0283; // 131 104 public static final int TAG_LANGUAGE_IDENTIFIER = 0x0287; // 135 105 public static final int TAG_AUDIO_TYPE = 0x0296; // 150 106 public static final int TAG_AUDIO_SAMPLING_RATE = 0x0297; // 151 107 public static final int TAG_AUDIO_SAMPLING_RESOLUTION = 0x0298; // 152 108 public static final int TAG_AUDIO_DURATION = 0x0299; // 153 109 public static final int TAG_AUDIO_OUTCUE = 0x029A; // 154 110 111 public static final int TAG_JOB_ID = 0x02B8; // 184 112 public static final int TAG_MASTER_DOCUMENT_ID = 0x02B9; // 185 113 public static final int TAG_SHORT_DOCUMENT_ID = 0x02BA; // 186 114 public static final int TAG_UNIQUE_DOCUMENT_ID = 0x02BB; // 187 115 public static final int TAG_OWNER_ID = 0x02BC; // 188 116 117 public static final int TAG_OBJECT_PREVIEW_FILE_FORMAT = 0x02C8; // 200 118 public static final int TAG_OBJECT_PREVIEW_FILE_FORMAT_VERSION = 0x02C9; // 201 119 public static final int TAG_OBJECT_PREVIEW_DATA = 0x02CA; // 202 120 121 @NotNull 122 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 54 123 55 124 static 56 125 { 57 tagNameMap.put(new Integer(TAG_RECORD_VERSION), "Directory Version"); 58 tagNameMap.put(new Integer(TAG_CAPTION), "Caption/Abstract"); 59 tagNameMap.put(new Integer(TAG_WRITER), "Writer/Editor"); 60 tagNameMap.put(new Integer(TAG_HEADLINE), "Headline"); 61 tagNameMap.put(new Integer(TAG_SPECIAL_INSTRUCTIONS), "Special Instructions"); 62 tagNameMap.put(new Integer(TAG_BY_LINE), "By-line"); 63 tagNameMap.put(new Integer(TAG_BY_LINE_TITLE), "By-line Title"); 64 tagNameMap.put(new Integer(TAG_CREDIT), "Credit"); 65 tagNameMap.put(new Integer(TAG_SOURCE), "Source"); 66 tagNameMap.put(new Integer(TAG_OBJECT_NAME), "Object Name"); 67 tagNameMap.put(new Integer(TAG_DATE_CREATED), "Date Created"); 68 tagNameMap.put(new Integer(TAG_CITY), "City"); 69 tagNameMap.put(new Integer(TAG_PROVINCE_OR_STATE), "Province/State"); 70 tagNameMap.put(new Integer(TAG_COUNTRY_OR_PRIMARY_LOCATION), "Country/Primary Location"); 71 tagNameMap.put(new Integer(TAG_ORIGINAL_TRANSMISSION_REFERENCE), "Original Transmission Reference"); 72 tagNameMap.put(new Integer(TAG_CATEGORY), "Category"); 73 tagNameMap.put(new Integer(TAG_SUPPLEMENTAL_CATEGORIES), "Supplemental Category(s)"); 74 tagNameMap.put(new Integer(TAG_URGENCY), "Urgency"); 75 tagNameMap.put(new Integer(TAG_KEYWORDS), "Keywords"); 76 tagNameMap.put(new Integer(TAG_COPYRIGHT_NOTICE), "Copyright Notice"); 77 tagNameMap.put(new Integer(TAG_RELEASE_DATE), "Release Date"); 78 tagNameMap.put(new Integer(TAG_RELEASE_TIME), "Release Time"); 79 tagNameMap.put(new Integer(TAG_TIME_CREATED), "Time Created"); 80 tagNameMap.put(new Integer(TAG_ORIGINATING_PROGRAM), "Originating Program"); 126 _tagNameMap.put(TAG_ENVELOPE_RECORD_VERSION, "Enveloped Record Version"); 127 _tagNameMap.put(TAG_DESTINATION, "Destination"); 128 _tagNameMap.put(TAG_FILE_FORMAT, "File Format"); 129 _tagNameMap.put(TAG_FILE_VERSION, "File Version"); 130 _tagNameMap.put(TAG_SERVICE_ID, "Service Identifier"); 131 _tagNameMap.put(TAG_ENVELOPE_NUMBER, "Envelope Number"); 132 _tagNameMap.put(TAG_PRODUCT_ID, "Product Identifier"); 133 _tagNameMap.put(TAG_ENVELOPE_PRIORITY, "Envelope Priority"); 134 _tagNameMap.put(TAG_DATE_SENT, "Date Sent"); 135 _tagNameMap.put(TAG_TIME_SENT, "Time Sent"); 136 _tagNameMap.put(TAG_CODED_CHARACTER_SET, "Coded Character Set"); 137 _tagNameMap.put(TAG_UNIQUE_OBJECT_NAME, "Unique Object Name"); 138 _tagNameMap.put(TAG_ARM_IDENTIFIER, "ARM Identifier"); 139 _tagNameMap.put(TAG_ARM_VERSION, "ARM Version"); 140 141 _tagNameMap.put(TAG_APPLICATION_RECORD_VERSION, "Application Record Version"); 142 _tagNameMap.put(TAG_OBJECT_TYPE_REFERENCE, "Object Type Reference"); 143 _tagNameMap.put(TAG_OBJECT_ATTRIBUTE_REFERENCE, "Object Attribute Reference"); 144 _tagNameMap.put(TAG_OBJECT_NAME, "Object Name"); 145 _tagNameMap.put(TAG_EDIT_STATUS, "Edit Status"); 146 _tagNameMap.put(TAG_EDITORIAL_UPDATE, "Editorial Update"); 147 _tagNameMap.put(TAG_URGENCY, "Urgency"); 148 _tagNameMap.put(TAG_SUBJECT_REFERENCE, "Subject Reference"); 149 _tagNameMap.put(TAG_CATEGORY, "Category"); 150 _tagNameMap.put(TAG_SUPPLEMENTAL_CATEGORIES, "Supplemental Category(s)"); 151 _tagNameMap.put(TAG_FIXTURE_ID, "Fixture Identifier"); 152 _tagNameMap.put(TAG_KEYWORDS, "Keywords"); 153 _tagNameMap.put(TAG_CONTENT_LOCATION_CODE, "Content Location Code"); 154 _tagNameMap.put(TAG_CONTENT_LOCATION_NAME, "Content Location Name"); 155 _tagNameMap.put(TAG_RELEASE_DATE, "Release Date"); 156 _tagNameMap.put(TAG_RELEASE_TIME, "Release Time"); 157 _tagNameMap.put(TAG_EXPIRATION_DATE, "Expiration Date"); 158 _tagNameMap.put(TAG_EXPIRATION_TIME, "Expiration Time"); 159 _tagNameMap.put(TAG_SPECIAL_INSTRUCTIONS, "Special Instructions"); 160 _tagNameMap.put(TAG_ACTION_ADVISED, "Action Advised"); 161 _tagNameMap.put(TAG_REFERENCE_SERVICE, "Reference Service"); 162 _tagNameMap.put(TAG_REFERENCE_DATE, "Reference Date"); 163 _tagNameMap.put(TAG_REFERENCE_NUMBER, "Reference Number"); 164 _tagNameMap.put(TAG_DATE_CREATED, "Date Created"); 165 _tagNameMap.put(TAG_TIME_CREATED, "Time Created"); 166 _tagNameMap.put(TAG_DIGITAL_DATE_CREATED, "Digital Date Created"); 167 _tagNameMap.put(TAG_DIGITAL_TIME_CREATED, "Digital Time Created"); 168 _tagNameMap.put(TAG_ORIGINATING_PROGRAM, "Originating Program"); 169 _tagNameMap.put(TAG_PROGRAM_VERSION, "Program Version"); 170 _tagNameMap.put(TAG_OBJECT_CYCLE, "Object Cycle"); 171 _tagNameMap.put(TAG_BY_LINE, "By-line"); 172 _tagNameMap.put(TAG_BY_LINE_TITLE, "By-line Title"); 173 _tagNameMap.put(TAG_CITY, "City"); 174 _tagNameMap.put(TAG_SUB_LOCATION, "Sub-location"); 175 _tagNameMap.put(TAG_PROVINCE_OR_STATE, "Province/State"); 176 _tagNameMap.put(TAG_COUNTRY_OR_PRIMARY_LOCATION_CODE, "Country/Primary Location Code"); 177 _tagNameMap.put(TAG_COUNTRY_OR_PRIMARY_LOCATION_NAME, "Country/Primary Location Name"); 178 _tagNameMap.put(TAG_ORIGINAL_TRANSMISSION_REFERENCE, "Original Transmission Reference"); 179 _tagNameMap.put(TAG_HEADLINE, "Headline"); 180 _tagNameMap.put(TAG_CREDIT, "Credit"); 181 _tagNameMap.put(TAG_SOURCE, "Source"); 182 _tagNameMap.put(TAG_COPYRIGHT_NOTICE, "Copyright Notice"); 183 _tagNameMap.put(TAG_CONTACT, "Contact"); 184 _tagNameMap.put(TAG_CAPTION, "Caption/Abstract"); 185 _tagNameMap.put(TAG_LOCAL_CAPTION, "Local Caption"); 186 _tagNameMap.put(TAG_CAPTION_WRITER, "Caption Writer/Editor"); 187 _tagNameMap.put(TAG_RASTERIZED_CAPTION, "Rasterized Caption"); 188 _tagNameMap.put(TAG_IMAGE_TYPE, "Image Type"); 189 _tagNameMap.put(TAG_IMAGE_ORIENTATION, "Image Orientation"); 190 _tagNameMap.put(TAG_LANGUAGE_IDENTIFIER, "Language Identifier"); 191 _tagNameMap.put(TAG_AUDIO_TYPE, "Audio Type"); 192 _tagNameMap.put(TAG_AUDIO_SAMPLING_RATE, "Audio Sampling Rate"); 193 _tagNameMap.put(TAG_AUDIO_SAMPLING_RESOLUTION, "Audio Sampling Resolution"); 194 _tagNameMap.put(TAG_AUDIO_DURATION, "Audio Duration"); 195 _tagNameMap.put(TAG_AUDIO_OUTCUE, "Audio Outcue"); 196 197 _tagNameMap.put(TAG_JOB_ID, "Job Identifier"); 198 _tagNameMap.put(TAG_MASTER_DOCUMENT_ID, "Master Document Identifier"); 199 _tagNameMap.put(TAG_SHORT_DOCUMENT_ID, "Short Document Identifier"); 200 _tagNameMap.put(TAG_UNIQUE_DOCUMENT_ID, "Unique Document Identifier"); 201 _tagNameMap.put(TAG_OWNER_ID, "Owner Identifier"); 202 203 _tagNameMap.put(TAG_OBJECT_PREVIEW_FILE_FORMAT, "Object Data Preview File Format"); 204 _tagNameMap.put(TAG_OBJECT_PREVIEW_FILE_FORMAT_VERSION, "Object Data Preview File Format Version"); 205 _tagNameMap.put(TAG_OBJECT_PREVIEW_DATA, "Object Data Preview Data"); 81 206 } 82 207 … … 86 211 } 87 212 213 @NotNull 88 214 public String getName() 89 215 { … … 91 217 } 92 218 93 protected HashMap getTagNameMap() 94 { 95 return tagNameMap; 219 @NotNull 220 protected HashMap<Integer, String> getTagNameMap() 221 { 222 return _tagNameMap; 223 } 224 225 /** 226 * Returns any keywords contained in the IPTC data. This value may be <code>null</code>. 227 */ 228 @Nullable 229 public List<String> getKeywords() 230 { 231 final String[] array = getStringArray(IptcDirectory.TAG_KEYWORDS); 232 if (array==null) 233 return null; 234 return Arrays.asList(array); 96 235 } 97 236 } -
trunk/src/com/drew/metadata/iptc/IptcReader.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 12-Nov-2002 19:00:03 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.iptc; 18 22 19 import com.drew.imaging.jpeg.JpegProcessingException; 20 import com.drew.imaging.jpeg.JpegSegmentReader; 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 25 import com.drew.lang.annotations.NotNull; 21 26 import com.drew.metadata.Directory; 22 27 import com.drew.metadata.Metadata; 23 import com.drew.metadata.MetadataException;24 28 import com.drew.metadata.MetadataReader; 25 29 26 import java.io.File;27 import java.io.InputStream;28 30 import java.util.Date; 29 31 30 32 /** 33 * Decodes IPTC binary data, populating a <code>Metadata</code> object with tag values in an <code>IptcDirectory</code>. 31 34 * 35 * @author Drew Noakes http://drewnoakes.com 32 36 */ 33 37 public class IptcReader implements MetadataReader 34 38 { 39 // TODO consider breaking the IPTC section up into multiple directories and providing segregation of each IPTC directory 35 40 /* 36 41 public static final int DIRECTORY_IPTC = 2; … … 46 51 public static final int POST_DATA_RECORD = 9; 47 52 */ 48 /**49 * The Iptc data segment.50 */51 private final byte[] _data;52 53 53 /** 54 * Creates a new IptcReader for the specified Jpeg jpegFile. 55 */ 56 public IptcReader(File jpegFile) throws JpegProcessingException 54 /** Performs the IPTC data extraction, adding found values to the specified instance of <code>Metadata</code>. */ 55 public void extract(@NotNull final BufferReader reader, @NotNull final Metadata metadata) 57 56 { 58 this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_APPD)); 59 } 57 IptcDirectory directory = metadata.getOrCreateDirectory(IptcDirectory.class); 60 58 61 /** Creates an IptcReader for a JPEG stream. 62 * 63 * @param is JPEG stream. Stream will be closed. 64 */ 65 public IptcReader(InputStream is) throws JpegProcessingException 66 { 67 this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD)); 68 } 59 int offset = 0; 69 60 70 public IptcReader(byte[] data) 71 { 72 _data = data; 73 } 74 75 /** 76 * Performs the Exif data extraction, returning a new instance of <code>Metadata</code>. 77 */ 78 public Metadata extract() 79 { 80 return extract(new Metadata()); 81 } 82 83 /** 84 * Performs the Exif data extraction, adding found values to the specified 85 * instance of <code>Metadata</code>. 86 */ 87 public Metadata extract(Metadata metadata) 88 { 89 if (_data == null) { 90 return metadata; 61 /* 62 // find start-of-segment marker (potentially need to skip some ASCII photoshop header info) 63 try { 64 while (offset < data.length - 1 && reader.getUInt16(offset) != 0x1c01 && reader.getUInt16(offset) != 0x1c02) 65 offset++; 66 } catch (BufferBoundsException e) { 67 directory.addError("Couldn't find start of IPTC data (invalid segment)"); 68 return; 91 69 } 92 93 Directory directory = metadata.getDirectory(IptcDirectory.class); 94 95 // find start of data 96 int offset = 0; 97 try { 98 while (offset < _data.length - 1 && get32Bits(offset) != 0x1c02) { 99 offset++; 100 } 101 } catch (MetadataException e) { 102 directory.addError("Couldn't find start of Iptc data (invalid segment)"); 103 return metadata; 104 } 70 */ 105 71 106 72 // for each tag 107 while (offset < _data.length) { 73 while (offset < reader.getLength()) { 74 108 75 // identifies start of a tag 109 if (_data[offset] != 0x1c) { 76 short startByte; 77 try { 78 startByte = reader.getUInt8(offset); 79 } catch (BufferBoundsException e) { 80 directory.addError("Unable to read starting byte of IPTC tag"); 110 81 break; 111 82 } 83 84 if (startByte != 0x1c) { 85 directory.addError("Invalid start to IPTC tag"); 86 break; 87 } 88 112 89 // we need at least five bytes left to read a tag 113 if ((offset + 5) >= _data.length) { 90 if (offset + 5 >= reader.getLength()) { 91 directory.addError("Too few bytes remain for a valid IPTC tag"); 114 92 break; 115 93 } … … 121 99 int tagByteCount; 122 100 try { 123 directoryType = _data[offset++]; 124 tagType = _data[offset++]; 125 tagByteCount = get32Bits(offset); 126 } catch (MetadataException e) { 127 directory.addError("Iptc data segment ended mid-way through tag descriptor"); 128 return metadata; 101 directoryType = reader.getUInt8(offset++); 102 tagType = reader.getUInt8(offset++); 103 tagByteCount = reader.getUInt16(offset); 104 offset += 2; 105 } catch (BufferBoundsException e) { 106 directory.addError("IPTC data segment ended mid-way through tag descriptor"); 107 return; 129 108 } 130 offset += 2; 131 if ( (offset + tagByteCount) > _data.length) {132 directory.addError(" data for tag extends beyond end ofiptcsegment");109 110 if (offset + tagByteCount > reader.getLength()) { 111 directory.addError("Data for tag extends beyond end of IPTC segment"); 133 112 break; 134 113 } 135 114 136 processTag(directory, directoryType, tagType, offset, tagByteCount); 115 try { 116 processTag(reader, directory, directoryType, tagType, offset, tagByteCount); 117 } catch (BufferBoundsException e) { 118 directory.addError("Error processing IPTC tag"); 119 break; 120 } 121 137 122 offset += tagByteCount; 138 123 } 139 140 return metadata;141 124 } 142 125 143 /** 144 * Returns an int calculated from two bytes of data at the specified offset (MSB, LSB). 145 * @param offset position within the data buffer to read first byte 146 * @return the 32 bit int value, between 0x0000 and 0xFFFF 147 */ 148 private int get32Bits(int offset) throws MetadataException 149 { 150 if (offset >= _data.length) { 151 throw new MetadataException("Attempt to read bytes from outside Iptc data buffer"); 152 } 153 return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255); 154 } 155 156 /** 157 * This method serves as marsheller of objects for dataset. It converts from IPTC 158 * octets to relevant java object. 159 */ 160 private void processTag(Directory directory, int directoryType, int tagType, int offset, int tagByteCount) 126 private void processTag(@NotNull BufferReader reader, @NotNull Directory directory, int directoryType, int tagType, int offset, int tagByteCount) throws BufferBoundsException 161 127 { 162 128 int tagIdentifier = tagType | (directoryType << 8); 163 129 164 130 switch (tagIdentifier) { 165 case IptcDirectory.TAG_RECORD_VERSION: 131 case IptcDirectory.TAG_APPLICATION_RECORD_VERSION: 166 132 // short 167 short shortValue =(short)((_data[offset] << 8) | _data[offset + 1]);133 int shortValue = reader.getUInt16(offset); 168 134 directory.setInt(tagIdentifier, shortValue); 169 135 return; 170 136 case IptcDirectory.TAG_URGENCY: 171 137 // byte 172 directory.setInt(tagIdentifier, _data[offset]);138 directory.setInt(tagIdentifier, reader.getUInt8(offset)); 173 139 return; 174 140 case IptcDirectory.TAG_RELEASE_DATE: … … 176 142 // Date object 177 143 if (tagByteCount >= 8) { 178 String dateStr = newString(_data,offset, tagByteCount);144 String dateStr = reader.getString(offset, tagByteCount); 179 145 try { 180 146 int year = Integer.parseInt(dateStr.substring(0, 4)); 181 147 int month = Integer.parseInt(dateStr.substring(4, 6)) - 1; 182 148 int day = Integer.parseInt(dateStr.substring(6, 8)); 183 Date date = (new java.util.GregorianCalendar(year, month, day)).getTime();149 Date date = new java.util.GregorianCalendar(year, month, day).getTime(); 184 150 directory.setDate(tagIdentifier, date); 185 151 return; … … 194 160 // fall through 195 161 } 196 // If no special handling by now, treat it as a string 162 163 // If we haven't returned yet, treat it as a string 197 164 String str; 198 165 if (tagByteCount < 1) { 199 166 str = ""; 200 167 } else { 201 str = newString(_data,offset, tagByteCount);168 str = reader.getString(offset, tagByteCount, System.getProperty("file.encoding")); // "ISO-8859-1" 202 169 } 170 203 171 if (directory.containsTag(tagIdentifier)) { 204 String[] oldStrings; 172 // this fancy string[] business avoids using an ArrayList for performance reasons 173 String[] oldStrings = directory.getStringArray(tagIdentifier); 205 174 String[] newStrings; 206 try {207 oldStrings = directory.getStringArray(tagIdentifier);208 } catch (MetadataException e) {209 oldStrings = null;210 }211 175 if (oldStrings == null) { 212 176 newStrings = new String[1]; 213 177 } else { 214 178 newStrings = new String[oldStrings.length + 1]; 215 for (int i = 0; i < oldStrings.length; i++) { 216 newStrings[i] = oldStrings[i]; 217 } 179 System.arraycopy(oldStrings, 0, newStrings, 0, oldStrings.length); 218 180 } 219 181 newStrings[newStrings.length - 1] = str; -
trunk/src/com/drew/metadata/jpeg/JpegCommentDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.jpeg; 18 22 19 import com.drew.metadata.Directory; 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 20 25 import com.drew.metadata.TagDescriptor; 21 26 22 27 /** 28 * Provides human-readable string representations of tag values stored in a <code>JpegCommentDirectory</code>. 23 29 * 24 30 * @author Drew Noakes http://drewnoakes.com 25 31 */ 26 public class JpegCommentDescriptor extends TagDescriptor 32 public class JpegCommentDescriptor extends TagDescriptor<JpegCommentDirectory> 27 33 { 28 public JpegCommentDescriptor(Directory directory) 34 public JpegCommentDescriptor(@NotNull JpegCommentDirectory directory) 29 35 { 30 36 super(directory); 31 37 } 32 38 33 public String getDescription(int tagType) 39 @Nullable 40 public String getJpegCommentDescription() 34 41 { 35 return _directory.getString( tagType);42 return _directory.getString(JpegCommentDirectory.TAG_JPEG_COMMENT); 36 43 } 37 44 } -
trunk/src/com/drew/metadata/jpeg/JpegCommentDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.jpeg; 18 22 23 import com.drew.lang.annotations.NotNull; 19 24 import com.drew.metadata.Directory; 20 25 … … 22 27 23 28 /** 29 * Describes tags used by a JPEG file comment. 24 30 * 25 31 * @author Drew Noakes http://drewnoakes.com 26 32 */ 27 public class JpegCommentDirectory extends Directory { 33 public class JpegCommentDirectory extends Directory 34 { 35 /** 36 * This value does not apply to a particular standard. Rather, this value has been fabricated to maintain 37 * consistency with other directory types. 38 */ 39 public static final int TAG_JPEG_COMMENT = 0; 28 40 29 /** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */ 30 publicstatic finalint TAG_JPEG_COMMENT = 0;41 @NotNull 42 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 31 43 32 protected static final HashMap tagNameMap = new HashMap(); 44 static { 45 _tagNameMap.put(TAG_JPEG_COMMENT, "Jpeg Comment"); 46 } 33 47 34 static { 35 tagNameMap.put(new Integer(TAG_JPEG_COMMENT), "Jpeg Comment"); 36 } 48 public JpegCommentDirectory() 49 { 50 this.setDescriptor(new JpegCommentDescriptor(this)); 51 } 37 52 38 public JpegCommentDirectory() { 39 this.setDescriptor(new JpegCommentDescriptor(this)); 40 } 53 @NotNull 54 public String getName() 55 { 56 return "JpegComment"; 57 } 41 58 42 public String getName() { 43 return "JpegComment"; 44 } 45 46 protected HashMap getTagNameMap() { 47 return tagNameMap; 48 } 59 @NotNull 60 protected HashMap<Integer, String> getTagNameMap() 61 { 62 return _tagNameMap; 63 } 49 64 } -
trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.jpeg; 18 22 19 import com.drew.imaging.jpeg.JpegProcessingException; 20 import com.drew.imaging.jpeg.JpegSegmentReader; 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 25 import com.drew.lang.annotations.NotNull; 21 26 import com.drew.metadata.Metadata; 22 27 import com.drew.metadata.MetadataReader; 23 28 24 import java.io.File;25 import java.io.InputStream;26 27 29 /** 30 * Decodes the comment stored within Jpeg files, populating a <code>Metadata</code> object with tag values in a 31 * <code>JpegCommentDirectory</code>. 28 32 * 29 33 * @author Drew Noakes http://drewnoakes.com … … 32 36 { 33 37 /** 34 * The COM data segment.35 */36 private final byte[] _data;37 38 /**39 * Creates a new JpegReader for the specified Jpeg jpegFile.40 */41 public JpegCommentReader(File jpegFile) throws JpegProcessingException42 {43 this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_COM));44 }45 46 /** Creates a JpegCommentReader for a JPEG stream.47 *48 * @param is JPEG stream. Stream will be closed.49 */50 public JpegCommentReader(InputStream is) throws JpegProcessingException51 {52 this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));53 }54 55 public JpegCommentReader(byte[] data)56 {57 _data = data;58 }59 60 /**61 * Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>.62 */63 public Metadata extract()64 {65 return extract(new Metadata());66 }67 68 /**69 38 * Performs the Jpeg data extraction, adding found values to the specified 70 39 * instance of <code>Metadata</code>. 71 40 */ 72 public Metadataextract(Metadata metadata)41 public void extract(@NotNull final BufferReader reader, @NotNull Metadata metadata) 73 42 { 74 if (_data==null) { 75 return metadata; 43 JpegCommentDirectory directory = metadata.getOrCreateDirectory(JpegCommentDirectory.class); 44 45 try { 46 directory.setString(JpegCommentDirectory.TAG_JPEG_COMMENT, reader.getString(0, (int)reader.getLength())); 47 } catch (BufferBoundsException e) { 48 directory.addError("Exception reading JPEG comment string"); 76 49 } 77 78 JpegCommentDirectory directory = (JpegCommentDirectory)metadata.getDirectory(JpegCommentDirectory.class);79 80 directory.setString(JpegCommentDirectory.TAG_JPEG_COMMENT, new String(_data));81 82 return metadata;83 50 } 84 51 } -
trunk/src/com/drew/metadata/jpeg/JpegComponent.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on Oct 9, 17:04:07 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.jpeg; 18 22 19 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.Nullable; 20 24 21 25 import java.io.Serializable; 22 26 23 27 /** 24 * Created by IntelliJ IDEA. 25 * User: dnoakes 26 * Date: 09-Oct-2003 27 * Time: 17:04:07 28 * To change this template use Options | File Templates. 28 * Stores information about a Jpeg image component such as the component id, horiz/vert sampling factor and 29 * quantization table number. 30 * 31 * @author Drew Noakes http://drewnoakes.com 29 32 */ 30 33 public class JpegComponent implements Serializable 31 34 { 35 private static final long serialVersionUID = 61121257899091914L; 36 32 37 private final int _componentId; 33 38 private final int _samplingFactorByte; … … 46 51 } 47 52 48 public String getComponentName() throws MetadataException 53 /** 54 * Returns the component name (one of: Y, Cb, Cr, I, or Q) 55 * @return the component name 56 */ 57 @Nullable 58 public String getComponentName() 49 59 { 50 60 switch (_componentId) … … 61 71 return "Q"; 62 72 } 63 64 throw new MetadataException("Unsupported component id: " + _componentId); 73 return null; 65 74 } 66 75 -
trunk/src/com/drew/metadata/jpeg/JpegDescriptor.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 14 20 */ 15 21 package com.drew.metadata.jpeg; 16 22 17 import com.drew. metadata.Directory;18 import com.drew. metadata.MetadataException;23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 19 25 import com.drew.metadata.TagDescriptor; 20 26 … … 22 28 * Provides human-readable string versions of the tags stored in a JpegDirectory. 23 29 * Thanks to Darrell Silver (www.darrellsilver.com) for the initial version of this class. 30 * 31 * @author Drew Noakes http://drewnoakes.com 24 32 */ 25 public class JpegDescriptor extends TagDescriptor 33 public class JpegDescriptor extends TagDescriptor<JpegDirectory> 26 34 { 27 public JpegDescriptor(Directory directory) 35 public JpegDescriptor(@NotNull JpegDirectory directory) 28 36 { 29 37 super(directory); 30 38 } 31 39 32 public String getDescription(int tagType) throws MetadataException 40 @Nullable 41 public String getDescription(int tagType) 33 42 { 34 43 switch (tagType) 35 44 { 45 case JpegDirectory.TAG_JPEG_COMPRESSION_TYPE: 46 return getImageCompressionTypeDescription(); 36 47 case JpegDirectory.TAG_JPEG_COMPONENT_DATA_1: 37 48 return getComponentDataDescription(0); … … 48 59 case JpegDirectory.TAG_JPEG_IMAGE_WIDTH: 49 60 return getImageWidthDescription(); 61 default: 62 return super.getDescription(tagType); 50 63 } 51 52 return _directory.getString(tagType);53 64 } 54 65 66 @Nullable 67 public String getImageCompressionTypeDescription() 68 { 69 Integer value = _directory.getInteger(JpegDirectory.TAG_JPEG_COMPRESSION_TYPE); 70 if (value==null) 71 return null; 72 // Note there is no 2 or 12 73 switch (value) { 74 case 0: return "Baseline"; 75 case 1: return "Extended sequential, Huffman"; 76 case 2: return "Progressive, Huffman"; 77 case 3: return "Lossless, Huffman"; 78 case 5: return "Differential sequential, Huffman"; 79 case 6: return "Differential progressive, Huffman"; 80 case 7: return "Differential lossless, Huffman"; 81 case 8: return "Reserved for JPEG extensions"; 82 case 9: return "Extended sequential, arithmetic"; 83 case 10: return "Progressive, arithmetic"; 84 case 11: return "Lossless, arithmetic"; 85 case 13: return "Differential sequential, arithmetic"; 86 case 14: return "Differential progressive, arithmetic"; 87 case 15: return "Differential lossless, arithmetic"; 88 default: 89 return "Unknown type: "+ value; 90 } 91 } 92 @Nullable 55 93 public String getImageWidthDescription() 56 94 { 57 return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_WIDTH) + " pixels"; 95 final String value = _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_WIDTH); 96 if (value==null) 97 return null; 98 return value + " pixels"; 58 99 } 59 100 101 @Nullable 60 102 public String getImageHeightDescription() 61 103 { 62 return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT) + " pixels"; 104 final String value = _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT); 105 if (value==null) 106 return null; 107 return value + " pixels"; 63 108 } 64 109 110 @Nullable 65 111 public String getDataPrecisionDescription() 66 112 { 67 return _directory.getString(JpegDirectory.TAG_JPEG_DATA_PRECISION) + " bits"; 113 final String value = _directory.getString(JpegDirectory.TAG_JPEG_DATA_PRECISION); 114 if (value==null) 115 return null; 116 return value + " bits"; 68 117 } 69 118 70 public String getComponentDataDescription(int componentNumber) throws MetadataException 119 @Nullable 120 public String getComponentDataDescription(int componentNumber) 71 121 { 72 JpegComponent component = ((JpegDirectory)_directory).getComponent(componentNumber);122 JpegComponent value = _directory.getComponent(componentNumber); 73 123 74 if ( component==null)75 throw new MetadataException("No Jpeg component exists with number " + componentNumber);124 if (value==null) 125 return null; 76 126 77 StringBu ffer sb = new StringBuffer();78 sb.append( component.getComponentName());127 StringBuilder sb = new StringBuilder(); 128 sb.append(value.getComponentName()); 79 129 sb.append(" component: Quantization table "); 80 sb.append( component.getQuantizationTableNumber());130 sb.append(value.getQuantizationTableNumber()); 81 131 sb.append(", Sampling factors "); 82 sb.append( component.getHorizontalSamplingFactor());132 sb.append(value.getHorizontalSamplingFactor()); 83 133 sb.append(" horiz/"); 84 sb.append( component.getVerticalSamplingFactor());134 sb.append(value.getVerticalSamplingFactor()); 85 135 sb.append(" vert"); 86 136 return sb.toString(); -
trunk/src/com/drew/metadata/jpeg/JpegDirectory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created on Aug 2, 2003. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.jpeg; 18 22 23 import com.drew.lang.annotations.NotNull; 24 import com.drew.lang.annotations.Nullable; 19 25 import com.drew.metadata.Directory; 20 26 import com.drew.metadata.MetadataException; … … 24 30 /** 25 31 * Directory of tags and values for the SOF0 Jpeg segment. This segment holds basic metadata about the image. 26 * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes 32 * 33 * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes http://drewnoakes.com 27 34 */ 28 public class JpegDirectory extends Directory { 29 30 /** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */ 31 public static final int TAG_JPEG_DATA_PRECISION = 0; 32 /** The image's height. Necessary for decoding the image, so it should always be there. */ 33 public static final int TAG_JPEG_IMAGE_HEIGHT = 1; 34 /** The image's width. Necessary for decoding the image, so it should always be there. */ 35 public static final int TAG_JPEG_IMAGE_WIDTH = 3; 36 /** Usually 1 = grey scaled, 3 = color YcbCr or YIQ, 4 = color CMYK 37 * Each component TAG_COMPONENT_DATA_[1-4], has the following meaning: 38 * component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 39 * sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.), 40 * quantization table number (1 byte). 41 * <p> 42 * This info is from http://www.funducode.com/freec/Fileformats/format3/format3b.htm 43 */ 44 public static final int TAG_JPEG_NUMBER_OF_COMPONENTS = 5; 35 public class JpegDirectory extends Directory 36 { 37 public static final int TAG_JPEG_COMPRESSION_TYPE = -3; 38 /** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */ 39 public static final int TAG_JPEG_DATA_PRECISION = 0; 40 /** The image's height. Necessary for decoding the image, so it should always be there. */ 41 public static final int TAG_JPEG_IMAGE_HEIGHT = 1; 42 /** The image's width. Necessary for decoding the image, so it should always be there. */ 43 public static final int TAG_JPEG_IMAGE_WIDTH = 3; 44 /** 45 * Usually 1 = grey scaled, 3 = color YcbCr or YIQ, 4 = color CMYK 46 * Each component TAG_COMPONENT_DATA_[1-4], has the following meaning: 47 * component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 48 * sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.), 49 * quantization table number (1 byte). 50 * <p/> 51 * This info is from http://www.funducode.com/freec/Fileformats/format3/format3b.htm 52 */ 53 public static final int TAG_JPEG_NUMBER_OF_COMPONENTS = 5; 45 54 46 55 // NOTE! Component tag type int values must increment in steps of 1 47 56 48 49 50 51 52 53 54 55 57 /** the first of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */ 58 public static final int TAG_JPEG_COMPONENT_DATA_1 = 6; 59 /** the second of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */ 60 public static final int TAG_JPEG_COMPONENT_DATA_2 = 7; 61 /** the third of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */ 62 public static final int TAG_JPEG_COMPONENT_DATA_3 = 8; 63 /** the fourth of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */ 64 public static final int TAG_JPEG_COMPONENT_DATA_4 = 9; 56 65 57 protected static final HashMap tagNameMap = new HashMap(); 66 @NotNull 67 protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>(); 58 68 59 static { 60 tagNameMap.put(new Integer(TAG_JPEG_DATA_PRECISION), "Data Precision"); 61 tagNameMap.put(new Integer(TAG_JPEG_IMAGE_WIDTH), "Image Width"); 62 tagNameMap.put(new Integer(TAG_JPEG_IMAGE_HEIGHT), "Image Height"); 63 tagNameMap.put(new Integer(TAG_JPEG_NUMBER_OF_COMPONENTS), "Number of Components"); 64 tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_1), "Component 1"); 65 tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_2), "Component 2"); 66 tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_3), "Component 3"); 67 tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_4), "Component 4"); 68 } 69 static { 70 _tagNameMap.put(TAG_JPEG_COMPRESSION_TYPE, "Compression Type"); 71 _tagNameMap.put(TAG_JPEG_DATA_PRECISION, "Data Precision"); 72 _tagNameMap.put(TAG_JPEG_IMAGE_WIDTH, "Image Width"); 73 _tagNameMap.put(TAG_JPEG_IMAGE_HEIGHT, "Image Height"); 74 _tagNameMap.put(TAG_JPEG_NUMBER_OF_COMPONENTS, "Number of Components"); 75 _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_1, "Component 1"); 76 _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_2, "Component 2"); 77 _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_3, "Component 3"); 78 _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_4, "Component 4"); 79 } 69 80 70 public JpegDirectory() { 71 this.setDescriptor(new JpegDescriptor(this)); 72 } 81 public JpegDirectory() 82 { 83 this.setDescriptor(new JpegDescriptor(this)); 84 } 73 85 74 public String getName() { 75 return "Jpeg"; 76 } 86 @NotNull 87 public String getName() 88 { 89 return "Jpeg"; 90 } 77 91 78 protected HashMap getTagNameMap() { 79 return tagNameMap; 80 } 92 @NotNull 93 protected HashMap<Integer, String> getTagNameMap() 94 { 95 return _tagNameMap; 96 } 81 97 82 98 /** 83 *84 99 * @param componentNumber The zero-based index of the component. This number is normally between 0 and 3. 85 * Use getNumberOfComponents for bounds-checking. 86 * @return 100 * Use getNumberOfComponents for bounds-checking. 101 * @return the JpegComponent having the specified number. 87 102 */ 103 @Nullable 88 104 public JpegComponent getComponent(int componentNumber) 89 105 { 90 106 int tagType = JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + componentNumber; 91 92 JpegComponent component = (JpegComponent)getObject(tagType); 93 94 return component; 107 return (JpegComponent)getObject(tagType); 95 108 } 96 109 -
trunk/src/com/drew/metadata/jpeg/JpegReader.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on Aug 2, 2003 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.jpeg; 18 22 19 import com.drew.imaging.jpeg.JpegProcessingException; 20 import com.drew.imaging.jpeg.JpegSegmentReader; 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 25 import com.drew.lang.annotations.NotNull; 21 26 import com.drew.metadata.Metadata; 22 import com.drew.metadata.MetadataException;23 27 import com.drew.metadata.MetadataReader; 24 28 25 import java.io.File;26 import java.io.InputStream;27 28 29 /** 30 * Decodes Jpeg SOF0 data, populating a <code>Metadata</code> object with tag values in a <code>JpegDirectory</code>. 29 31 * 30 * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes 32 * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes http://drewnoakes.com 31 33 */ 32 34 public class JpegReader implements MetadataReader 33 35 { 34 36 /** 35 * The SOF0 data segment.36 */37 private final byte[] _data;38 39 /**40 * Creates a new JpegReader for the specified Jpeg jpegFile.41 */42 public JpegReader(File jpegFile) throws JpegProcessingException43 {44 this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_SOF0));45 }46 47 /** Creates a JpegReader for a JPEG stream.48 *49 * @param is JPEG stream. Stream will be closed.50 */51 public JpegReader(InputStream is) throws JpegProcessingException52 {53 this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));54 }55 56 public JpegReader(byte[] data)57 {58 _data = data;59 }60 61 /**62 * Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>.63 */64 public Metadata extract()65 {66 return extract(new Metadata());67 }68 69 /**70 37 * Performs the Jpeg data extraction, adding found values to the specified 71 38 * instance of <code>Metadata</code>. 72 39 */ 73 public Metadataextract(Metadata metadata)40 public void extract(@NotNull final BufferReader reader, @NotNull Metadata metadata) 74 41 { 75 if (_data==null) { 76 return metadata; 77 } 78 79 JpegDirectory directory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class); 42 JpegDirectory directory = metadata.getOrCreateDirectory(JpegDirectory.class); 80 43 81 44 try { 82 45 // data precision 83 int dataPrecision = get16Bits(JpegDirectory.TAG_JPEG_DATA_PRECISION);46 int dataPrecision = reader.getUInt8(JpegDirectory.TAG_JPEG_DATA_PRECISION); 84 47 directory.setInt(JpegDirectory.TAG_JPEG_DATA_PRECISION, dataPrecision); 85 48 86 49 // process height 87 int height = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);50 int height = reader.getUInt16(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT); 88 51 directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, height); 89 52 90 53 // process width 91 int width = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);54 int width = reader.getUInt16(JpegDirectory.TAG_JPEG_IMAGE_WIDTH); 92 55 directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, width); 93 56 94 57 // number of components 95 int numberOfComponents = get16Bits(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS);58 int numberOfComponents = reader.getUInt8(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS); 96 59 directory.setInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, numberOfComponents); 97 60 … … 101 64 // 3 - Quantization table number 102 65 int offset = 6; 103 for (int i=0; i<numberOfComponents; i++) 104 { 105 int componentId = get16Bits(offset++); 106 int samplingFactorByte = get16Bits(offset++); 107 int quantizationTableNumber = get16Bits(offset++); 66 for (int i = 0; i < numberOfComponents; i++) { 67 int componentId = reader.getUInt8(offset++); 68 int samplingFactorByte = reader.getUInt8(offset++); 69 int quantizationTableNumber = reader.getUInt8(offset++); 108 70 JpegComponent component = new JpegComponent(componentId, samplingFactorByte, quantizationTableNumber); 109 71 directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + i, component); 110 72 } 111 73 112 } catch ( MetadataExceptionme) {113 directory.addError( "MetadataException: " + me);74 } catch (BufferBoundsException ex) { 75 directory.addError(ex.getMessage()); 114 76 } 115 116 return metadata;117 }118 119 /**120 * Returns an int calculated from two bytes of data at the specified offset (MSB, LSB).121 * @param offset position within the data buffer to read first byte122 * @return the 32 bit int value, between 0x0000 and 0xFFFF123 */124 private int get32Bits(int offset) throws MetadataException125 {126 if (offset+1>=_data.length) {127 throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer");128 }129 130 return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255);131 }132 133 /**134 * Returns an int calculated from one byte of data at the specified offset.135 * @param offset position within the data buffer to read byte136 * @return the 16 bit int value, between 0x00 and 0xFF137 */138 private int get16Bits(int offset) throws MetadataException139 {140 if (offset>=_data.length) {141 throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer");142 }143 144 return (_data[offset] & 255);145 77 } 146 78 }
Note:
See TracChangeset
for help on using the changeset viewer.