Microsoft .Net : rilevare da un file immagine dati gps e indirizzo

In questo articolo vedremo come realizzare programmi che possono tornare utile anche nell'ambito investigativo, come quelli che si vedono nei telefilm. Nell'articolo vedremo come rilevare informazioni geo localizzazione su una determinata foto scattata.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

Con le nuove tecnologie in cui sono presenti funzionalità come la geo localizzazione che permette di rilevare la posizione in cui ci si trova, è possibile sapere in quale posto è stata scattata  una foto tanto per fare unesempio.
In questo articolo, vedremo come realizzare un semplice programma, che data una foto scattata con uno SmartPhone, possiamo rilevare l’indirizzo del luogo in cui è avvenuto tale avvenimento ed informazioni sul dispositivo.
Tramite la tecnologia .Net rileveremo queste informazioni su un file Immagine, e tramite le API di google maps avremmo informazioni sulle coordinate riguardante il GPS.

Creazione del progetto per ottenere le coordinate GPS

Si crea un nuovo progetto di tipo Windows Application, selezionando il linguaggio di programmazione di proprio interesse.
Una volta aperto il progetto, inseriamo nella form 7 caselle di testo, sette controlli label, un controllo di tipo WebBrowser che avrà il compito di visualizzare la cartina ed un pulsante, il tutto come mostrato in figura 1.

Figura 1 – il programma in esecuzione

Una volta posizionati i controlli non ci resta che scrivere il codice.
Per eseguire il codice, dovremmo avere un file di tipo “jpg” nel quale sono presenti le proprietà “GPS” nel nostro caso, tramite lo smartphone Nokia Lumia 520 è stata effettuata la prova.


Stesura del codice

Passiamo in visualizzazione codice in modo che scriviamo il codice per estrapolare le informazioni dal file.
Inseriamo in alto, sopra ad ogni riga di codice, lo spazio dei nomi che ci permette di utilizzare determinate classi.
Qui di seguito si riporta i frammenti di codice per entrambi i linguaggi.

VB.Net 
Imports System.Drawing.Imaging
Imports System.Net
Imports System.Text
Imports System.IO
C#
using System.Drawing.Imaging;
using System.Net;
using System.IO;

Gli spazi di nomi ci permettono di gestire I file, richiamare il sito web di Google e la gestione delle immagini.

Si crea una funzione, la quale date le informazioni presenti nel file jpeg, ed in particolare le proprietà relative alle coordinate GPS, quali latitudine e longitudine, rileviamo il dato di tipo float che tramite le api di Google otteniamo l’indirizzo.

Qui di seguito si riporta la funzione che ci permette di ottenere la latitudine e longitudine.

VB.Net
Private Function GpsToFloat(propItemRef As PropertyItem, propItem As PropertyItem) As Single
Dim gradiNumeratore As UInteger = BitConverter.ToUInt32(propItem.Value, 0)
Dim gradiDenominatore As UInteger = BitConverter.ToUInt32(propItem.Value, 4)
Dim gradi As Single = gradiNumeratore / CSng(gradiDenominatore)
Dim minutiNumeratore As UInteger = BitConverter.ToUInt32(propItem.Value, 8)
Dim minutiDenominatore As UInteger = BitConverter.ToUInt32(propItem.Value, 12)
Dim minuti As Single = minutiNumeratore / CSng(minutiDenominatore)
Dim secondiNumeratore As UInteger = BitConverter.ToUInt32(propItem.Value, 16)
Dim secondiDenominatore As UInteger = BitConverter.ToUInt32(propItem.Value, 20)
Dim secondi As Single = secondiNumeratore / CSng(secondiDenominatore)
Dim coordinate As Single = gradi + (minuti / 60.0F) + (secondi / 3600.0F)
Dim gpsRef As String = System.Text.Encoding.ASCII.GetString(New Byte(0) {propItemRef.Value(0)})
'N, S, E, W
If gpsRef = "S" OrElse gpsRef = "W" Then
coordinate = 0 - coordinate
End If
Return coordinate
End Function
C#
private   float GpsToFloat(PropertyItem propItemRef, PropertyItem propItem)
{
uint gradiNumeratore = BitConverter.ToUInt32(propItem.Value, 0);
uint gradiDenominatore = BitConverter.ToUInt32(propItem.Value, 4);
float gradi = gradiNumeratore / (float)gradiDenominatore;
uint minutiNumeratore = BitConverter.ToUInt32(propItem.Value, 8);
uint minutiDenominatore = BitConverter.ToUInt32(propItem.Value, 12);
float minuti = minutiNumeratore / (float)minutiDenominatore;
uint secondiNumeratori = BitConverter.ToUInt32(propItem.Value, 16);
uint secondiDenominatori = BitConverter.ToUInt32(propItem.Value, 20);
float secondi = secondiNumeratori / (float) secondiDenominatori;
float coordinate = gradi + (minuti / 60f) + (secondi / 3600f);
string gpsRef = System.Text.Encoding.ASCII.GetString(new byte[1] { propItemRef.Value[0] }); //N, S, E, W
if (gpsRef == "S" || gpsRef == "W")
coordinate = 0 - coordinate;
return coordinate;
}

Nell’evento click, inseriamo il codice che permette di rilevare le informazioni dal file, ed in particolare ottenere la proprietà GPS, la proprietà del dispositivo con il quale abbiamo scattato la foto, la proprietà del sistema operativo del dispositivo ed infine data ed ora della foto.

Queste informazioni le otteniamo tramite il metodo “GEtPropertyItem” che tramite l’id otteniamo queste informazioni dall’oggetto di tipo Image che sarà il file jpeg posizionato nel nostro computer.
Mentre le classi di tipo webrequest e webresponse, otteniamo informazioni dalle api di Google sulle coordinate, e la mappa.
Qui di seguito si riporta il codice completo dell’evento click del pulsante per entrambi i linguaggi.

VB.Net
Private Sub btnRileva_Click(sender As System.Object, e As System.EventArgs) Handles btnRileva.Click
Dim image As Image = New Bitmap("E:\TestGPS.jpg")
'Latitudine
Dim propItemRef As PropertyItem = image.GetPropertyItem(1)
Dim propItemLat As PropertyItem = image.GetPropertyItem(2)
Dim datiLatitudine As System.Nullable(Of Single) = GpsToFloat(propItemRef, propItemLat)
TxtLatitudine.Text = datiLatitudine.ToString()
'logitudine
propItemRef = image.GetPropertyItem(3)
Dim propItemLong As PropertyItem = image.GetPropertyItem(4)
Dim datiLogitudine As System.Nullable(Of Single) = GpsToFloat(propItemRef, propItemLong)
txtLogitudine.Text = datiLogitudine.ToString()
'Rilevo da google le informazioni
Dim url As String = "http://maps.google.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false"
url = String.Format(url, TxtLatitudine.Text.Trim().Replace(",", "."), txtLogitudine.Text.Trim().Replace(",", "."))
Dim request As WebRequest = WebRequest.Create(url)
Using response As WebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
Using reader As New StreamReader(response.GetResponseStream(), Encoding.UTF8)
Dim dsResult As New DataSet()
dsResult.ReadXml(reader)
txtIndirizzo.Text = dsResult.Tables("result").Rows(0)("formatted_address").ToString()
End Using
End Using
Dim ascii As Encoding = Encoding.ASCII
TxtNomeDispositovo.Text = ascii.GetString(image.GetPropertyItem(272).Value, 0, image.GetPropertyItem(272).Len - 1)
TxtSistema.Text = ascii.GetString(image.GetPropertyItem(305).Value, 0, image.GetPropertyItem(305).Len - 1)
Dim DataFoto As String = ascii.GetString(image.GetPropertyItem(36867).Value, 0, image.GetPropertyItem(36867).Len - 1)
Dim Data As String() = DataFoto.Split(" "c)
Dim DataDellaFoto As String = DateTime.Parse(Data(0).Replace(":", "/")).ToString("dd/MM/yyyy") + " " + Data(1)
webBrowser1.Navigate("http://maps.googleapis.com/maps/api/staticmap?center=" + TxtLatitudine.Text.Trim().Replace(",", ".") + "," + txtLogitudine.Text.Trim().Replace(",", ".") + "&zoom=15&size=200x200")
TxtTelecamera.Text = ascii.GetString(image.GetPropertyItem(271).Value, 0, image.GetPropertyItem(271).Len - 1)
TxtDataFoto.Text = DataDellaFoto
End Sub
C#
private void btnRileva_Click(object sender, EventArgs e)
{
Image image = new Bitmap(@"E:\TestGPS2.jpg");
//Latitudine
PropertyItem propItemRef = image.GetPropertyItem(1);
PropertyItem propItemLat = image.GetPropertyItem(2);
float? datiLatitudine = GpsToFloat(propItemRef, propItemLat);
TxtLatitudine.Text = datiLatitudine.ToString();
//logitudine
propItemRef = image.GetPropertyItem(3);
PropertyItem propItemLong = image.GetPropertyItem(4);
float? datiLogitudine = GpsToFloat(propItemRef, propItemLong);
txtLogitudine.Text = datiLogitudine.ToString();
//Rilevo da google le informazioni
string url = "http://maps.google.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false";
url = string.Format(url, TxtLatitudine.Text.Trim().Replace(",", "."), txtLogitudine.Text.Trim().Replace(",", "."));
WebRequest request = WebRequest.Create(url);
using (WebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
DataSet dsResult = new DataSet();
dsResult.ReadXml(reader);
txtIndirizzo.Text = dsResult.Tables["result"].Rows[0]["formatted_address"].ToString();
}
}
Encoding ascii = Encoding.ASCII;
TxtNomeDispositovo.Text =  ascii.GetString(image.GetPropertyItem(272).Value, 0, image.GetPropertyItem(272).Len - 1);
TxtSistema.Text = ascii.GetString(image.GetPropertyItem(305).Value, 0, image.GetPropertyItem(305).Len - 1);
string DataFoto = ascii.GetString(image.GetPropertyItem(36867).Value, 0, image.GetPropertyItem(36867).Len - 1);
string[]Data = DataFoto.Split(' ');
string DataDellaFoto = DateTime.Parse(Data[0].Replace(":", "/")).ToString("dd/MM/yyyy") + " " + Data[1];
webBrowser1.Navigate("http://maps.googleapis.com/maps/api/staticmap?center=" + TxtLatitudine.Text.Trim().Replace(",", ".") + "," + txtLogitudine.Text.Trim().Replace(",", ".") + "&zoom=15&size=200x200");
TxtTelecamera.Text = ascii.GetString(image.GetPropertyItem(271).Value, 0, image.GetPropertyItem(271).Len - 1);
TxtDataFoto.Text = DataDellaFoto;
}

Ora non ci resta che eseguire il programma per rilevare i dati dalla nostra immagine.


Conclusioni

In questo articolo abbiamo visto come realizzare un semplice programma, che può tornare utile soprattutto in ambito di investigazione, per rilevare informazioni su una determinata immagine. Con poche righe di codice, possiamo rilevare  dati dai file carpendo molte cose sulle persone ed in particolare gli spostamenti o luoghi che hanno visitato, un articolo che introduce il lettore alla realizzazione di un programma più complesso per rilevamento dei dati importanti.