novità - ios 12 su iphone 6s




Lettura dei dati GPS dall'immagine restituita dalla fotocamera nell'iPhone iOS (6)

Devo ottenere le coordinate GPS di un'immagine scattata con la fotocamera del dispositivo iOS. Non mi interessa le immagini del Rullino fotografico, solo l'immagine scattata con UIImagePickerControllerSourceTypeCamera.

Ho letto molte risposte StackOverflow, come Get Exif data da UIImage - UIImagePickerController , che presume che tu stia utilizzando la struttura AssetsLibrary, che non sembra funzionare con le immagini delle telecamere, o usi CoreLocaiton per ottenere la latitudine / longitudine dall'app stesso, non dall'immagine.

L'uso di CoreLocation non è un'opzione . Questo non mi darà le coordinate quando è stato premuto il pulsante dell'otturatore. (Con le soluzioni basate su CoreLocation, è necessario registrare le coords prima di visualizzare la telecamera o dopo e, naturalmente, se il dispositivo si muove, le coordinate saranno errate. Questo metodo dovrebbe funzionare con un dispositivo stazionario.)

Sono solo iOS5, quindi non ho bisogno di supportare i dispositivi più vecchi. Questo è anche per un prodotto commerciale, quindi non posso utilizzare http://code.google.com/p/iphone-exif/ .

Quindi, quali sono le mie opzioni per leggere i dati GPS dall'immagine restituita dalla fotocamera in iOS5? Tutto quello che riesco a pensare adesso è di salvare l'immagine su Rullino fotografico e quindi utilizzare AssetsLibrary, ma sembra un hokey.

Grazie!

Ecco il codice che ho scritto sulla base della risposta di Caleb.

    UIImage *image =  [info objectForKey:UIImagePickerControllerOriginalImage];

    NSData *jpeg = UIImageJPEGRepresentation(image,1.0);
    CGImageSourceRef  source ;
    source = CGImageSourceCreateWithData((__bridge CFDataRef)jpeg, NULL);

    NSDictionary *metadataNew = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL);  

    NSLog(@"%@",metadataNew);

e la mia console mostra:

    2012-04-26 14:15:37:137 ferret[2060:1799] {
        ColorModel = RGB;
        Depth = 8;
        Orientation = 6;
        PixelHeight = 1936;
        PixelWidth = 2592;
        "{Exif}" =     {
            ColorSpace = 1;
            PixelXDimension = 2592;
            PixelYDimension = 1936;
        };
        "{JFIF}" =     {
            DensityUnit = 0;
            JFIFVersion =         (
                1,
                1
            );
            XDensity = 1;
            YDensity = 1;
        };
        "{TIFF}" =     {
            Orientation = 6;
        };
    }

Nessuna latitudine / longitudine.


Abbiamo lavorato molto con la fotocamera e con UIImagePickerController e, almeno fino a iOS 5.1.1 incluso, non restituisce i dati sulla posizione nei metadati delle foto o dei video girati con UIImagePickerController .

Non importa se i servizi di localizzazione sono abilitati per l'app Fotocamera o no; controlla l'utilizzo dell'app dei servizi di localizzazione da parte dell'app Camera, non la funzione della videocamera all'interno di UIImagePickerController .

L'app dovrà utilizzare la classe CLLocation per ottenere la posizione e quindi aggiungerla all'immagine o al video restituito dalla videocamera. Se la tua app può ottenere la posizione dipende dal fatto che l'utente autorizzi l'accesso ai servizi di localizzazione per la tua app. E nota che l'utente può disabilitare i servizi di localizzazione per la tua app (o interamente per il dispositivo) in qualsiasi momento tramite Settings > Location Servizi di Settings > Location .


Come sottolinea Chris Markle , Apple elimina i dati GPS da EXIF. Ma puoi aprire i dati RAW dell'immagine e analizzare i dati da solo o usare una lib di terze parti per farlo, per example .

Ecco un codice di esempio:

- (void) imagePickerController: (UIImagePickerController *) picker
 didFinishPickingMediaWithInfo: (NSDictionary *) info {

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
             resultBlock:^(ALAsset *asset) {

                 ALAssetRepresentation *image_representation = [asset defaultRepresentation];
                 NSUInteger size = (NSUInteger)image_representation.size;
                 // create a buffer to hold image data
                 uint8_t *buffer = (Byte*)malloc(size);
                 NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0  length:size error:nil];

                 if (length != 0)  {

                     // buffer -> NSData object; free buffer afterwards
                     NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:size freeWhenDone:YES];

                     EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
                     [jpegScanner scanImageData: adata];
                     EXFMetaData* exifData = jpegScanner.exifMetaData;

                     id latitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];
                     id longitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];
                     id datetime = [exifData tagValue:[NSNumber numberWithInt:EXIF_DateTime]];
                     id t = [exifData tagValue:[NSNumber numberWithInt:EXIF_Model]];

                     self.locationLabel.text = [NSString stringWithFormat:@"Local: %@ - %@",latitudeValue,longitudeValue];
                     self.dateLavel.text = [NSString stringWithFormat:@"Data: %@", datetime];

                 }
                 else {
                     NSLog(@"image_representation buffer length == 0");
                 }
             }
            failureBlock:^(NSError *error) {
                NSLog(@"couldn't get asset: %@", error);
            }
     ];
}

Nel delegato UIImagePickerController, effettuare le seguenti operazioni:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
  NSDictionary *metadata = [info valueForKey:UIImagePickerControllerMediaMetadata];

  // metadata now contains all the image metadata.  Extract GPS data from here.
}

Non posso dire di aver avuto bisogno di fare esattamente questo nella mia roba, ma dai documenti sembra abbastanza chiaro che se stai usando UIImagePickerController puoi ottenere l'immagine che l'utente ha appena preso da -imagePicker:didFinishPickingMediaWithInfo: delegate metodo. Utilizzare il tasto UIImagePickerControllerOriginalImage per ottenere l'immagine.

Una volta ottenuta l'immagine, dovresti essere in grado di accedere alle sue proprietà, compresi i dati EXIF, come descritto in QA1654 Accesso alle proprietà dell'immagine con ImageIO . Per creare CGImageSource, vorrei esaminare CGImageSourceCreateWithData() e utilizzare i dati ottenuti dal metodo CGImage di CGImage . Una volta ottenuta l'origine dell'immagine, è possibile accedere ai vari attributi tramite CGImageSourceCopyProperties() .


Questo è testato su iOS 8 e funziona per i video, quindi dovrebbe funzionare in modo simile per le foto con alcune modifiche.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    NSURL *videoUrl = (NSURL *)[info objectForKey:UIImagePickerControllerMediaURL];
    NSString *moviePath = [videoUrl path];

    if ( UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath) ) {

        ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];

        [assetLibrary assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {

            CLLocation *location = [asset valueForProperty:ALAssetPropertyLocation];
            NSLog(@"Location Meta: %@", location);

        } failureBlock:^(NSError *error) {
            NSLog(@"Video Date Error: %@", error);
        }];

    }

}

Risposta rapida :

import AssetsLibrary
import CoreLocation


// MARK: - UIImagePickerControllerDelegate
extension ViewController: UIImagePickerControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        defer {
            dismiss(animated: true, completion: nil)
        }
        guard picker.sourceType == .photoLibrary else {
            return
        }
        guard let url = info[UIImagePickerControllerReferenceURL] as? URL else {
            return
        }

        let library = ALAssetsLibrary()
        library.asset(for: url, resultBlock: { (asset) in
            guard let coordinate = asset?.value(forProperty: ALAssetPropertyLocation) as? CLLocation else {
                return
            }
            print("\(coordinate)")

            // Getting human-readable address.
            let geocoder = CLGeocoder()
            geocoder.reverseGeocodeLocation(coordinate, completionHandler: { (placemarks, error) in
                guard let placemark = placemarks?.first else {
                    return
                }
                print("\(placemark.addressDictionary)")
            })
        }, failureBlock: { (error: Error?) in
            print("Unable to read metadata: \(error)")
        })
    }
}






camera