/* * This is public domain software - that is, you can do whatever you want * with it, and include it software that is licensed under the GNU or the * BSD license, or whatever other licence you choose, including proprietary * closed source licenses. I do ask that you leave this header in tact. * * If you make modifications to this code that you think would benefit the * wider community, please send me a copy and I'll post it on my site. * * If you make use of this code, I'd appreciate hearing about it. * metadata_extractor [at] drewnoakes [dot] com * Latest version of this software kept at * http://drewnoakes.com/ * * Created by Darren Salomons & Drew Noakes. */ package com.drew.imaging; import com.drew.imaging.jpeg.JpegMetadataReader; import com.drew.imaging.tiff.TiffMetadataReader; import com.drew.metadata.Metadata; import com.drew.metadata.MetadataException; import com.drew.metadata.Directory; import com.drew.metadata.Tag; import com.drew.metadata.exif.ExifDirectory; import java.io.*; import java.util.Iterator; /** * Obtains metadata from all supported file formats, including JPEG, RAW (NEF/CRw/CR2) and TIFF. * If the caller knows their file to be of a particular type, they may prefer to use the dedicated MetadataReader * directly (<code>JpegMetadataReader</code> for Jpeg files, or <code>TiffMetadataReader</code> for TIFF and RAW files). * The dedicated readers offer a very slight performance improvement, though for most scenarios it is simpler, * more convenient and more robust to use this class. */ public class ImageMetadataReader { private static final int JPEG_FILE_MAGIC_NUMBER = 0xFFD8; private static final int MOTOROLLA_TIFF_MAGIC_NUMBER = 0x4D4D; // "MM" private static final int INTEL_TIFF_MAGIC_NUMBER = 0x4949; // "II" /** * Reads metadata from an input stream. The file inputStream examined to determine its type and consequently the * appropriate method to extract the data, though this inputStream transparent to the caller. * @param inputStream a stream from which the image data may be read. The stream must be positioned at the * beginning of the image data. * @return a populated Metadata error containing directories of tags with values and any processing errors. * @throws ImageProcessingException for general processing errors. */ public static Metadata readMetadata(BufferedInputStream inputStream) throws ImageProcessingException { int magicNumber = readMagicNumber(inputStream); return readMetadata(inputStream, null, magicNumber); } /** * Reads metadata from a file. The file is examined to determine its type and consequently the appropriate * method to extract the data, though this is transparent to the caller. * @param file a file from which the image data may be read. * @return a populated Metadata error containing directories of tags with values and any processing errors. * @throws ImageProcessingException for general processing errors. */ public static Metadata readMetadata(File file) throws ImageProcessingException { BufferedInputStream inputStream; try { inputStream = new BufferedInputStream(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new ImageProcessingException("File not found: " + file.getPath(), e); } int magicNumber = readMagicNumber(inputStream); try { inputStream.close(); } catch (IOException e) { throw new ImageProcessingException("Error closing file: " + file.getPath(), e); } return readMetadata(null, file, magicNumber); } private static Metadata readMetadata(BufferedInputStream inputStream, File file, int magicNumber) throws ImageProcessingException { if ((magicNumber & JPEG_FILE_MAGIC_NUMBER)==JPEG_FILE_MAGIC_NUMBER) { if (inputStream!=null) return JpegMetadataReader.readMetadata(inputStream); else return JpegMetadataReader.readMetadata(file); } else if (magicNumber==INTEL_TIFF_MAGIC_NUMBER || magicNumber==MOTOROLLA_TIFF_MAGIC_NUMBER) { if (inputStream!=null) return TiffMetadataReader.readMetadata(inputStream); else return TiffMetadataReader.readMetadata(file); } else { throw new ImageProcessingException("File is not the correct format"); } } private static int readMagicNumber(BufferedInputStream inputStream) throws ImageProcessingException { int magicNumber; try { inputStream.mark(2); magicNumber = inputStream.read() << 8; magicNumber |= inputStream.read(); inputStream.reset(); } catch (IOException e) { throw new ImageProcessingException("Error reading image data", e); } return magicNumber; } private ImageMetadataReader() throws Exception { throw new Exception("Not intended for instantiation"); } /** * An application entry point. Takes the name of a file as an argument and prints the contents of all metadata * directories to System.out. If the second parameter is '/thumb' then any thumbnail data will be written to * a file with name of the input file having '.thumb.jpg' appended. * @param args the command line arguments * @throws MetadataException * @throws IOException */ public static void main(String[] args) throws MetadataException, IOException { if (args.length<1 || args.length>2) { System.out.println("Usage: java -jar metadata-extractor-a.b.c.jar <filename> [/thumb]"); System.exit(1); } Metadata metadata = null; try { metadata = ImageMetadataReader.readMetadata(new File(args[0])); } catch (Exception e) { e.printStackTrace(System.err); System.exit(1); } // iterate over the exif data and print to System.out Iterator directories = metadata.getDirectoryIterator(); while (directories.hasNext()) { Directory directory = (Directory)directories.next(); Iterator tags = directory.getTagIterator(); while (tags.hasNext()) { Tag tag = (Tag)tags.next(); try { System.out.println("[" + directory.getName() + "] " + tag.getTagName() + " = " + tag.getDescription()); } catch (MetadataException e) { System.err.println(e.getMessage()); System.err.println(tag.getDirectoryName() + " " + tag.getTagName() + " (error)"); } } if (directory.hasErrors()) { Iterator errors = directory.getErrors(); while (errors.hasNext()) { System.out.println("ERROR: " + errors.next()); } } } if (args.length>1 && args[1].trim().equals("/thumb")) { ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); if (directory.containsThumbnail()) { System.out.println("Writing thumbnail..."); directory.writeThumbnail(args[0].trim() + ".thumb.jpg"); } else { System.out.println("No thumbnail data exists in this image"); } } } }