Oftentimes I need the GPS coordinates from where a picture was taken. In the past I was using exiftool (see this blog posting ), but that is cumbersome: right click the image in Dolphin, click “Copy location”, open a terminal, search in the history (Ctrl*r) the last line with exiftool, jump to the end, remove the previous picture filename, paste the filename, and then select and copy the coordinates. Too many steps. There must be a better way.
KDE has a feature where one can create custom context menus, called “service menus”. Awesome. All I need is two files:
A .desktop file in the servicemenus folder A small script which extracts the coordinates And while I’m at it, also transform the EXIF specialized GPSLatitude, GPSLatitudeRef, GPSLongitude and GPSLongitudeRef into a more readable Decimal Degrees format. And also copy the result directly into the clipboard, saving a couple of steps.
.desktop file The folder for the servicemenus is: ~/.local/share/kio/servicemenus/. Create a new file in this folder, the name doesn’t really matter as long as it ends with .desktop. In my case I’m using: ~/.local/share/kio/servicemenus/extract_gps_coordinates.desktop. The content of the file:
1
2
3
4
5
6
7
8
9
10
[Desktop Entry]
Type = Service
MimeType = image/jpeg;
Actions = copyGpsPosition;
X-KDE-Priority = TopLevel
[Desktop Action copyGpsPosition]
Name = Extract GPS Coordinates
Icon = mark-location
Exec = /usr/bin/python3 ~/bin/extract_gps_coordinates_from_jpeg_image.py %f
MimeType defines that this is only for JPEG images. The Name field defines the name this is shown under in the right click context menu.
Right click context menu
And the Exec field defines what action is taken, in my case a Python script. See the next chapter.
The Python script This script has several tasks:
Check if the image is really a JPEG image (someone could call it manually with a different file, or without file) Extract the GPS coordinates Transform the coordinates into the Decimal Degrees format Copy the coordinates into the clipboard I have a “personal” ~/bin/ folder where I place scripts I’m using regularly. That’s the right place for extract_gps_coordinates_from_jpeg_image.py.
The script source code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python3
import sys
import os
import subprocess
from PIL import Image
from PIL.ExifTags import GPSTAGS
def notify ( text, title= "GPS Coordinates Extractor" , is_error= False ):
if is_error:
icon = "dialog-error"
else :
icon = "mark-location"
# notify-send is used to send desktop notifications
subprocess. run([ 'notify-send' , '-i' , icon, title, text])
def copy_to_clipboard ( text):
# try KDE Klipper native DBus interface
try :
subprocess. run([ 'qdbus' , 'org.kde.klipper' , '/klipper' , 'setClipboardContents' , text], check= True )
return True
except Exception:
pass
# fallback for Wayland (wl-copy)
# sudo pacman -S wl-clipboard
try :
subprocess. run([ 'wl-copy' ], input = text. encode(), check= True )
return True
except Exception:
pass
# fallback for X11 (xclip)
try :
subprocess. run([ 'xclip' , '-selection' , 'clipboard' ], input = text. encode(), check= True )
return True
except Exception:
pass
return False
def convert_to_degrees ( value):
# convert DMS (Degrees, Minutes, Seconds) tuple to float degrees
d = float ( value[ 0 ])
m = float ( value[ 1 ])
s = float ( value[ 2 ])
return d + ( m / 60.0 ) + ( s / 3600.0 )
def main ():
if len ( sys. argv) < 2 :
notify( "No file provided!" , is_error= True )
return
image_path = sys. argv[ 1 ]
try :
img = Image. open( image_path)
exif = img. getexif()
# 34853 is the EXIF GPS IFD tag block
gps_ifd = exif. get_ifd( 34853 )
if not gps_ifd:
notify( "No GPS metadata found in this image!" , is_error= True )
return
gps_data = { GPSTAGS. get( key, key): value for key, value in gps_ifd. items()}
required_tags = [ 'GPSLatitude' , 'GPSLatitudeRef' , 'GPSLongitude' , 'GPSLongitudeRef' ]
if not all ( tag in gps_data for tag in required_tags):
notify( "Incomplete GPS metadata!" , is_error= True )
return
lat = convert_to_degrees( gps_data[ 'GPSLatitude' ])
if gps_data[ 'GPSLatitudeRef' ] != 'N' :
lat = - lat
lon = convert_to_degrees( gps_data[ 'GPSLongitude' ])
if gps_data[ 'GPSLongitudeRef' ] != 'E' :
lon = - lon
coordinates_str = f " { lat: .6f } , { lon: .6f } "
print ( f "Coordinates: { coordinates_str} " )
if copy_to_clipboard( coordinates_str):
notify( f "Copied to clipboard: \n { coordinates_str} " )
else :
notify( "Failed to access system clipboard!" , is_error= True )
except Exception as e:
notify( f "Error processing image: { str ( e) } " , is_error= True )
if __name__ == "__main__" :
main()
It tries to populate the clipboard in three different ways:
native qdbus wl-copy for Waylandxclip for X11Notification with GPS coordinates
Summary A simple KDE service menu entry and a small Python script save me quite some time and effort when dealing with coordinates in JPEG images.