Estrarre le coordinate geografiche dai TAG GPS eventualmente presenti in un file immagine JPEG

Da Gambas-it.org - Wikipedia.

I file immagine di formato JPEG (.jpg) possono contenere TAG che rappresentano varie informazioni relative all'immagine.
Essi possono contenere anche informazioni GPS ed in particolare i dati relativi alle coordinate geografiche (Latitudine e Longitudine), nonché all'Altitudine del punto ove si trovava colui che ha scattato la foto.

Qui dunque prenderemo in considerazione i seguenti TAG GPS:
- GPSLatitudeRef
- GPSLatitude
- GPSLongitudeRef
- GPSLongitude

Per interpretare i dati presenti nel file immagine JPEG relativi ai TAG GPS, sopra elencati, bisogna innanzitutto individuare i dati che si riferiscono alla direzione della Latitudine e della Longitudineove è stata scattata la foto-immagine. In particolare la direzione della Latitudine può essere "Nord" o "Sud", mentre quella della Longitudine può essere "Est" oppure "Ovest".
In particolare - per quello che a noi interessa - il TAG relativo alla Latitudine Nord è indicato nel file con il valore ASCII del carattere "N" espresso all'interno del codice con un valore a 16-bit che in esadecimale è rappresentato dal valore &h004E. L'altro valore a 16-bit, rappresentato dal valore &h0045 e corrispondente al carattere ASCII "E", si trova esattamente dopo 24 byte dopo il byte &h4E. Pertanto, per essere sicuri che effettivamente si tratta del valore riferito alla Latitudine Nord, si dovrà verificare la presenta dopo 24 byte del valore &h45 corrispondente al carattere ASCII "E".

Dopo ciò, si individueranno e interpreteranno i dati afferenti ai valori delle Coordinate geografiche, dei quali sarà presente prima quello della Latitudine seguito da quello della Longitudine.
Al 12° byte dopo il valore del carattere ASCII "N" è presente il valore di 4 byte che rappresenta il numero d'indice (offset) all'interno del file ove inizia il blocco relativo ai dati della Latitudine e della Longitudine. A tale valore vanno sommate 12 unità. Tale somma indica il numero d'indice ove incominciano precisamente i valori della Latitudine.
In particolare i valori delle due coordinate geografiche sono espressi nel formato Gradi-Minuti-Secondi (DMS). Ogni singolo valore di detto formato è un numero in virgola mobile, espresso nel tipo di dato "rational64u", che è sostanzialmente formato da due interi di 4 byte ciascuno: un numeratore e un denominatore.
Il primo intero di 4 byte (numeratore) è quello che si riferisce dunque al valore dei Gradi della Latitudine.
Per ottenere il numero effettivo di ogni valore delle due coordinate geografiche, si dividerà il numeratore per il denominatore.
Così in astratto:

Gradi = numeratore / denominatore

Immediatamente dopo l'ultimo valore/denominatore dei secondi della Latitudine iniziano i valori sono presenti i valori della Longitudine, anch'essi espressi nel tipo "rational64u".

Più in particolare la sequenza dei valori è la seguente:
- individuazione del valore di un solo byte &h4E relativo al carattere ASCII "N" e alla direzione "Nord" della Latitudine;
- salto di 24 byte per verificare se è presente il valore di un solo byte &h45 relativo al carattere ASCII "E" e alla direzione "Est" della Longitudine;
- in caso affermativo, salto di 12 byte, a cominciare dal byte successivo a quello della lettera "N", per leggere 4 byte e individuare l'offset ove leggere le coordinate geografiche;
- salto quindi al byte di numero d'indice sopra individuato per conoscere i dati relativi alle due coordinate geografiche;
- LAT. Gradi (4 byte: Numeratore);
- LAT. Gradi (4 byte: Denominatore);
- LAT. Minuti (4 byte: Numeratore);
- LAT. Minuti (4 byte: Denominatore);
- LAT. Secondi (4 byte: Numeratore);
- LAT. Secondi (4 byte: Denominatore);
- LONG. Gradi (4 byte: Numeratore);
- LONG. Gradi (4 byte: Denominatore);
- LONG. Minuti (4 byte: Numeratore);
- LONG. Minuti (4 byte: Denominatore);
- LONG. Secondi (4 byte: Numeratore);
- LONG. Secondi (4 byte: Denominatore).

Mostriamo di seguito un semplice codice per leggere i dati sopra descritti:

Public Sub Main()
 
 Dim filejpg, jpg As String
 Dim i, n, e As Integer
 Dim g, m, s As Single
 Dim fl As File

 filejpg = "/percorso/del/file.jpg"
 jpg = File.Load(filejpg)
 
' Verifica la presenza del valore &4E (caratterre ASCII "N") e del valore &45 (caratterre ASCII "E"):
 Repeat 
   n = InStr(jpg, MkShort(&4e), e)   ' oppure: Chr(&4E) & Chr(&00) & Chr(&00) & Chr(&00), e)
   e = n + 23
 Until (jpg[e, 2] = MkShort(&45)) Or (n == 0)

 If n == 0 Then Error.Raise("Non ci sono TAG GPS !")

 fl = Open filejpg For Read 

' Il numero d'indice (offset) del byte iniziale del primo Intero afferente ai dati della Latitudine è indicato dal valore di tipo Integer posto 12 byte più avanti rispetto al già visto valore &4E. Tale valore dell'offset deve essere aumentato di 12 unità.
 Seek #fl, (n - 1) + 12
 Read #fl, i

' Legge il 1° valore del formato "rational64u" relativo ai "Gradi" della Latitudine:
 Seek #fl, i + 12
 Read #fl, n
' Legge il 2° valore del formato "rational64u" relativo ai "Gradi" della Latitudine:
 Read #fl, e
 g = CSingle(n / e)
' Legge il 1° valore del formato "rational64u" relativo ai "Minuti" della Latitudine:
 Read #fl, n
' Legge il 2° valore del formato "rational64u" relativo ai "Minuti" della Latitudine:
 Read #fl, e
 m = CSingle(n / e)
' Legge il 1° valore del formato "rational64u" relativo ai "Secondi" della Latitudine:
 Read #fl, n
' Legge il 2° valore del formato "rational64u" relativo ai "Secondi" della Latitudine:
 Read #fl, e
 s = CSingle(n / e)
 Print "Latitudine:  "; g; "°"; m; "'"; s; "\"", g + m / 60 + s / 3600 ' (gradi decimali = Gradi + Minuti/60 + Secondi/3600)

' Legge il 1° valore del formato "rational64u" relativo ai "Gradi" della Longitudine:
 Read #fl, n
' Legge il 2° valore del formato "rational64u" relativo ai "Gradi" della Longitudine:
 Read #fl, e
 g = CSingle(n / e)
' Legge il 1° valore del formato "rational64u" relativo ai "Minuti" della Longitudine:
 Read #fl, n
' Legge il 2° valore del formato "rational64u" relativo ai "Minuti" della Longitudine:
 Read #fl, e
 m = CSingle(n / e)
' Legge il 1° valore del formato "rational64u" relativo ai "Secondi" della Longitudine:
 Read #fl, n
' Legge il 2° valore del formato "rational64u" relativo ai "Secondi" della Longitudine:
 Read #fl, e
 s = CSingle(n / e)
 Print "Longitudine: "; g; "°"; m; "'"; s; "\"", g + m / 60 + s / 3600 ' (gradi decimali = Gradi + Minuti/60 + Secondi/3600)

 fl.Close

End


Riferimenti