first and foremost, today is the Persian ancient new year (Nowruz), the first day of spring. Happy new year to all Persians.
but let me get back to our post title, oh Exif, a simple data structure which can reveal so many great information to intruders or investigators. needless to say, EXIF ( the exchangeable image file format ) normally contains some key information regarding the camera model, the place of taken picture and other precious data. with the advent of social medias and sharing the unlimited number of pictures on the internet, this is a good idea to investigate through countless of pictures to see What else can be taken except the content of the image. as our previous post's code was written in python, I follow the same programming language. you need to download and install Python Image library first at this URL: http://www.pythonware.com/products/pil/
Then you need to take to the second step, test whether your library is installed properly or not.
run this code in python interactive terminal or save it into a file and run it.
from PIL.EXIFTags import GPSTAGS gps ¼ GPSTAGS.items() gps.sort() print gps
taking a deeper look at what we got from the result is a dictionary of GPSTAGS. some of the key important items are GPSLONGITUDEREF and GPSLATITUDEREF which we need to take a look at it later on. Then, we need to know more about GPSTAGS, here is a brief introduction of what they are. the text below is quoted from Python Forensics Book:
"GPSLatitudeRef: Latitude is specified by either the North or South position in degrees from the equator. Those points that are north of the equator range from 0 to 90 degrees. Those points that are south of the equator range from 0 to -90 degrees. Thus this reference value is used to define where the latitude is in relationship to the equator. Since the value latitude is specified in EXIF as a positive integer, if the Latitude Reference is “S” or South, the integer value must be converted to a
negative value.
GPSLatitude: Indicates the latitude measured in degrees. The EXIF data specify these as whole degrees, followed by minutes and then followed by seconds. GPSLongitudeRef: Longitude is specified by either the east or west position in degrees. The convention is based on the Prime Meridian which runs through the Royal Observatory in Greenwich, England, which is defined as longitude zero degrees. Those points that are west of the Prime Meridian range from 0 to -180 degrees. Those points that are east of the Prime Meridian range from 0 to 180 degrees. Thus this reference value is used to define where the longitude value is in relationship to Greenwich. Since the value of longitude is specified in EXIF as a positive integer, if the Longitude Reference is west or “W,” the integer value must be converted to a negative value.
GPSLongitude: Indicates the longitude measured in degrees. The EXIF data specify these as whole degrees, followed by minutes and then followed by seconds. "
for making large advances, always you need to follow other works and then make some modification into it and avoid reinventing the wheel. the source code below is intended to scan a path and gives you some information on which picture contains EXIF data. when the for loop iterates, each of those pictures will be sent to a function of a class named _modEXIF which is responsible for the calculation of longitude and latitude and to see is there any EXIF tag or not to proceed the rest.
import os import _modEXIF TS = 0 MAKE = 1 MODEL = 2 # define a directory to scan scanDir = "C:\\pics\\" try: picts = os.listdir(scanDir) except: print "error invalid directory" exit(0) for aFile in picts: targetFile = scanDir + aFile if os.path.isfile(targetFile): gpsDictionary, EXIFList = _modEXIF.ExtractGPSDictionary(targetFile) if (gpsDictionary): # Converted to degrees dCoor = _modEXIF.ExtractLatLon(gpsDictionary) lat = dCoor.get("Lat") latRef = dCoor.get("LatRef") lon = dCoor.get("Lon") lonRef = dCoor.get("LonRef") if ( lat and lon and latRef and lonRef): print targetFile + ":" + EXIFList[TS] + ":" + EXIFList[MAKE]+ ":" + EXIFList[MODEL]+ ":" + str(lat)+','+str(lon) else: print "WARNING", "no GPS EXIF Data for " else: print "no dictionary found in " + targetFile
and the class goes like this
import os # Standard Library OS functions from PIL import Image from PIL.ExifTags import TAGS, GPSTAGS import sys def ExtractGPSDictionary(fileName): try: pilImage = Image.open(fileName) EXIFData = pilImage._getexif() except Exception: print sys.exc_info()[0] return None, None imageTimeStamp = "NA" CameraModel = "NA" CameraMake = "NA" gpsDictionary = {} if EXIFData: for tag, theValue in EXIFData.items(): tagValue = TAGS.get(tag, tag) if tagValue =='DateTimeOriginal': imageTimeStamp = EXIFData.get(tag) if tagValue == "Make": CameraMake = EXIFData.get(tag) if tagValue =='Model': CameraModel = EXIFData.get(tag) # check the tag for GPS if tagValue == "GPSInfo": # Found it ! # Now create a Dictionary to hold the GPS Data for curTag in theValue: gpsTag = GPSTAGS.get(curTag, curTag) gpsDictionary[gpsTag] = theValue[curTag] basicEXIFData = [imageTimeStamp, CameraMake,CameraModel] return gpsDictionary, basicEXIFData else: return None, None def ExtractLatLon(gps): # to perform the calculation at least lat, lon, latRef and lonRef are needed if (gps.has_key("GPSLatitude") and gps.has_key("GPSLongitude") and gps.has_key("GPSLatitudeRef") and gps.has_key ("GPSLatitudeRef")): latitude = gps["GPSLatitude"] latitudeRef = gps["GPSLatitudeRef"] longitude = gps["GPSLongitude"] longitudeRef = gps["GPSLongitudeRef"] lat = ConvertToDegrees(latitude) lon = ConvertToDegrees(longitude) if latitudeRef == "S": lat = 0 - lat # Check Longitude Reference # If West of the Prime Meridian in # Greenwich then the Longitude value is negative if longitudeRef == "W": lon = 0- lon gpsCoor = {"Lat": lat, "LatRef":latitudeRef, "Lon": lon, "LonRef": longitudeRef} return gpsCoor else: return None def ConvertToDegrees(gpsCoordinate): d0 = gpsCoordinate[0][0] d1 = gpsCoordinate[0][1] try: degrees = float(d0) / float(d1) except: degrees = 0.0 m0 = gpsCoordinate[1][0] m1 = gpsCoordinate[1][1] try: minutes = float(m0) / float(m1) except: minutes=0.0 s0 = gpsCoordinate[2][0] s1 = gpsCoordinate[2][1] try: seconds = float(s0) / float(s1) except: seconds = 0.0 floatCoordinate = float (degrees + (minutes / 60.0)+(seconds / 3600.0)) return floatCoordinate
to sum up, you can check out the below link to find out which location those numbers refer to.
http://www.latlong.net/Show-Latitude-Longitude.html