Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.mycompany.jpegrenamer; import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.lang.GeoLocation; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.Tag; import com.drew.metadata.exif.ExifSubIFDDirectory; import com.drew.metadata.exif.GpsDirectory; import com.drew.metadata.exif.makernotes.PanasonicMakernoteDirectory; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.ImageWriteException; import org.apache.commons.imaging.Imaging; import org.apache.commons.imaging.common.ImageMetadata; import org.apache.commons.imaging.common.RationalNumber; import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata; import org.apache.commons.imaging.formats.tiff.TiffField; import org.apache.commons.imaging.formats.tiff.TiffImageMetadata; import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants; import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants; import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants; import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author eperson */ public class MetaDataReader { private static final Logger logger = LoggerFactory.getLogger(MetaDataReader.class); private static void printTagValue(final JpegImageMetadata jpegMetadata, final TagInfo tagInfo) { final TiffField field = jpegMetadata.findEXIFValueWithExactMatch(tagInfo); if (field == null) { logger.info(tagInfo.name + ": " + "Not Found."); } else { logger.info(tagInfo.name + ": " + field.getValueDescription()); } } private static Date getDateTagValue(final JpegImageMetadata jpegMetadata, final TagInfo tagInfo) throws ImageReadException { final TiffField field = jpegMetadata.findEXIFValueWithExactMatch(tagInfo); if (field == null) { return null; } else { Date d = (Date) field.getValue(); return d; } } private static String getTagValue(final JpegImageMetadata jpegMetadata, final TagInfo tagInfo) { final TiffField field = jpegMetadata.findEXIFValueWithExactMatch(tagInfo); if (field == null) { return ""; } else { return field.getValueDescription(); } } public Map<String, String> readMetaData2(String f) { logger.info("**************************************************"); logger.info("Parsing file " + f); Map<String, String> s = new HashMap(); ; try { s = getExifMetadata(new File(f)); } catch (ImageReadException ex) { logger.error("", ex); } catch (IOException ex) { logger.error("", ex); } catch (ImageWriteException ex) { logger.error("", ex); } return s; } private Map<String, String> getAddressByGpsCoordinates(String lat, String lng) throws MalformedURLException, IOException, org.json.simple.parser.ParseException { Map<String, String> res = new HashMap(); URL url = new URL( "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + lat + "," + lng + "&sensor=true"); logger.info(url.toString()); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); String formattedAddress = null; PrintStream out = new PrintStream(System.out, true, "UTF-8"); try { InputStream in = url.openStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); String result; String line = reader.readLine(); result = line; while ((line = reader.readLine()) != null) { result += line; } JSONParser parser = new JSONParser(); JSONObject rsp = (JSONObject) parser.parse(result); logger.debug("JSON " + rsp.toString()); if (rsp.containsKey("error_message")) { JSONObject msg = (JSONObject) rsp.get("error_message"); logger.error("Error response from Google Maps: " + msg); res.put("formatted_address", msg.toString()); } else if (rsp.containsKey("results")) { JSONArray matches = (JSONArray) rsp.get("results"); String premise = null; String administrative_area_level_1 = null; String administrative_area_level_2 = null; String sublocality_level_1 = null; String locality = null; String postal_town = null; String country = null; List<String> types = null; String short_name = null; String long_name = null; for (int i = 0; i < matches.size(); i++) { JSONObject data = (JSONObject) matches.get(i); //TODO: check if idx=0 exists if (formattedAddress == null) { formattedAddress = (String) data.get("formatted_address"); res.put("formatted_address", formattedAddress); } JSONObject comp = (JSONObject) ((JSONArray) data.get("address_components")).get(0); logger.debug("JSON " + comp.toString()); types = (List<String>) ((JSONArray) comp.get("types")); short_name = (String) comp.get("short_name"); long_name = (String) comp.get("long_name"); logger.debug("JSON types" + types); logger.debug("JSON short_name" + short_name); logger.debug("JSON long_name" + long_name); if (types.contains("premise")) { premise = long_name; res.put("premise", premise); } else if (types.contains("sublocality_level_1")) { sublocality_level_1 = long_name; res.put("sublocality_level_1", sublocality_level_1); } else if (types.contains("postal_town")) { postal_town = long_name; res.put("postal_town", postal_town); } else if (types.contains("country")) { logger.debug("Setting country to " + long_name); country = long_name; res.put("country", country); } else if (types.contains("locality") && locality == null) { logger.debug("Setting locality to " + long_name); locality = long_name; res.put("locality", locality); } else if (types.contains("administrative_area_level_1")) { logger.debug("Setting administrative_area_level_1 to " + long_name); administrative_area_level_1 = long_name; res.put("administrative_area_level_1", administrative_area_level_1); } } } } finally { urlConnection.disconnect(); logger.debug("Reverse geocode returns " + res); logger.debug("Reverse geocode returns formatted_address = " + formattedAddress); return res; } } Map<String, String> readMetaData(String f) { logger.info("**************************************************"); logger.info("Parsing file " + f); Map<String, String> s = new HashMap(); ; try { s = getMetaData(new File(f)); } catch (IOException ex) { logger.error("", ex); } catch (ImageProcessingException ex) { logger.error("", ex); } return s; } public Map<String, String> getExifMetadata(final File jpegImageFile) throws ImageReadException, IOException, ImageWriteException { Map<String, String> res = new HashMap<>(); Map<String, String> location = new HashMap(); ; // note that metadata might be null if no metadata is found. final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile); boolean isClassOk = metadata instanceof JpegImageMetadata; if (!isClassOk || (null == metadata)) { return res; } final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata; if (jpegMetadata == null) { logger.info("File does not contain metadata - " + jpegImageFile.getCanonicalPath()); return res; } String dateOfCaptureString = getTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_DATE_TIME); SimpleDateFormat sdf = new SimpleDateFormat("''yyyy:MM:dd hh:mm:ss''"); Date dateOfCapture = null; try { dateOfCapture = sdf.parse(dateOfCaptureString); final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss", Locale.ENGLISH); res.put("date", df.format(dateOfCapture)); } catch (ParseException ex) { logger.error("", ex); } // s = getTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_DATE_TIME); printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_DATE_TIME); printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL); printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_DATE_TIME_DIGITIZED); printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF); printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LATITUDE); printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF); printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LONGITUDE); if (null != jpegMetadata) { // note that exif might be null if no Exif metadata is found. final TiffImageMetadata exif = jpegMetadata.getExif(); //logger.info(jpegMetadata.toString()); if (null != exif) { //logger.info(exif.toString()); final TiffImageMetadata.GPSInfo gpsInfo = exif.getGPS(); if (null != gpsInfo) { final String gpsDescription = gpsInfo.toString(); final double longitude = gpsInfo.getLongitudeAsDegreesEast(); final double latitude = gpsInfo.getLatitudeAsDegreesNorth(); logger.info(" " + "GPS Description: " + gpsDescription); logger.info(" " + "GPS Longitude (Degrees East): " + longitude); logger.info(" " + "GPS Latitude (Degrees North): " + latitude); try { Locale fmtLocale = Locale.US; NumberFormat formatter = NumberFormat.getNumberInstance(fmtLocale); formatter.setGroupingUsed(false); location = getAddressByGpsCoordinates(formatter.format(latitude), formatter.format(longitude)); if (location != null) { res.putAll(location); } } catch (MalformedURLException ex) { logger.error("", ex); } catch (org.json.simple.parser.ParseException ex) { logger.error("", ex); } logger.info(" " + location); } // more specific example of how to manually access GPS values final TiffField gpsLatitudeRefField = jpegMetadata .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF); final TiffField gpsLatitudeField = jpegMetadata .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE); final TiffField gpsLongitudeRefField = jpegMetadata .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF); final TiffField gpsLongitudeField = jpegMetadata .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE); if (gpsLatitudeRefField != null && gpsLatitudeField != null && gpsLongitudeRefField != null && gpsLongitudeField != null) { // all of these values are strings. final String gpsLatitudeRef = (String) gpsLatitudeRefField.getValue(); final RationalNumber[] gpsLatitude = (RationalNumber[]) (gpsLatitudeField.getValue()); final String gpsLongitudeRef = (String) gpsLongitudeRefField.getValue(); final RationalNumber[] gpsLongitude = (RationalNumber[]) gpsLongitudeField.getValue(); final RationalNumber gpsLatitudeDegrees = gpsLatitude[0]; final RationalNumber gpsLatitudeMinutes = gpsLatitude[1]; final RationalNumber gpsLatitudeSeconds = gpsLatitude[2]; final RationalNumber gpsLongitudeDegrees = gpsLongitude[0]; final RationalNumber gpsLongitudeMinutes = gpsLongitude[1]; final RationalNumber gpsLongitudeSeconds = gpsLongitude[2]; // This will format the gps info like so: // // gpsLatitude: 8 degrees, 40 minutes, 42.2 seconds S // gpsLongitude: 115 degrees, 26 minutes, 21.8 seconds E logger.info(" " + "GPS Latitude: " + gpsLatitudeDegrees.toDisplayString() + " degrees, " + gpsLatitudeMinutes.toDisplayString() + " minutes, " + gpsLatitudeSeconds.toDisplayString() + " seconds " + gpsLatitudeRef); logger.info(" " + "GPS Longitude: " + gpsLongitudeDegrees.toDisplayString() + " degrees, " + gpsLongitudeMinutes.toDisplayString() + " minutes, " + gpsLongitudeSeconds.toDisplayString() + " seconds " + gpsLongitudeRef); } logger.info(""); final List<ImageMetadata.ImageMetadataItem> items = jpegMetadata.getItems(); for (int i = 0; i < items.size(); i++) { final ImageMetadata.ImageMetadataItem item = items.get(i); // logger.info(" " + "item: " + item); } logger.info(""); } } return res; } public Map<String, String> getMetaData(final File jpegImageFile) throws ImageProcessingException, IOException { Metadata metadata = ImageMetadataReader.readMetadata(jpegImageFile); Map<String, String> res = new HashMap<>(); res.put("date", "Pinding"); for (Directory directory : metadata.getDirectories()) { for (Tag tag : directory.getTags()) { logger.debug("{} - {} = {}", directory.getName(), tag.getTagName(), tag.getDescription()); } if (directory.hasErrors()) { for (String error : directory.getErrors()) { logger.debug("ERROR: {}", error); } } } // obtain the Exif directory ExifSubIFDDirectory directory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class); // query the tag's value if (directory == null) { return res; } PanasonicMakernoteDirectory pmd = metadata.getFirstDirectoryOfType(PanasonicMakernoteDirectory.class); if (pmd != null) { String country = ""; String city = ""; String landmark = ""; for (Tag tag : pmd.getTags()) { if (tag.getTagType() == PanasonicMakernoteDirectory.TAG_COUNTRY) { country = tag.getDescription(); if (!country.equals("---")) { res.put("country", country); } } else if (tag.getTagType() == PanasonicMakernoteDirectory.TAG_CITY) { city = tag.getDescription(); if (!city.equals("---")) { res.put("locality", city); } } else if (tag.getTagType() == PanasonicMakernoteDirectory.TAG_LANDMARK) { landmark = tag.getDescription(); if (!landmark.equals("---")) { res.put("premise", landmark); } } } logger.info("Panasonic fafa " + country + " x " + city + " x " + landmark); } Date dateOfCapture = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL); final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss", Locale.ENGLISH); String s = null; if (dateOfCapture != null) { s = df.format(dateOfCapture); } else { return res; } logger.info("Date " + dateOfCapture.toString()); logger.info("Date f " + s); res.put("date", s); // if (res.get("country") != null) { // // We have some data from Panasonic Makernotes, so no need to lookup GPS // return res; // } // See whether it has GPS data Collection<GpsDirectory> gpsDirectories = metadata.getDirectoriesOfType(GpsDirectory.class); if (gpsDirectories == null) { return res; } for (GpsDirectory gpsDirectory : gpsDirectories) { // Try to read out the location, making sure it's non-zero GeoLocation geoLocation = gpsDirectory.getGeoLocation(); if (geoLocation != null && !geoLocation.isZero()) { // Add to our collection for use below logger.info("Geo " + geoLocation.toString()); double lat = geoLocation.getLatitude(); double lon = geoLocation.getLongitude(); Locale fmtLocale = Locale.US; NumberFormat formatter = NumberFormat.getNumberInstance(fmtLocale); formatter.setGroupingUsed(false); Map<String, String> location = new HashMap(); ; try { location = getAddressByGpsCoordinates(formatter.format(lat), formatter.format(lon)); logger.info("Location " + location); res.putAll(location); } catch (MalformedURLException ex) { logger.error("", ex); } catch (org.json.simple.parser.ParseException ex) { logger.error("", ex); } break; } } return res; } }