3

我正在使用 AvFoundation 拍摄静止图像并将 gps 信息添加到元数据并使用资产库保存到相册,但 gps 信息根本没有保存。

这是我的代码...

[self.stillImageTaker captureStillImageAsynchronouslyFromConnection:videoConnection
                    completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) 
    {

if (imageDataSampleBuffer != NULL) 

    {

            CFDictionaryRef exifAttachments = CMGetAttachment(imageDataSampleBuffer,kCGImagePropertyExifDictionary, NULL);
            CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);


        NSDictionary *gpsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"1",kCGImagePropertyGPSVersion,
                                 @"78.4852",kCGImagePropertyGPSLatitude,@"32.1456",kCGImagePropertyGPSLongitude, nil];

        CMSetAttachment(imageDataSampleBuffer,kCGImagePropertyGPSDictionary,gpsDict,kCMAttachmentMode_ShouldPropagate);

        CFDictionaryRef newMetadata = CMCopyDictionaryOfAttachments(NULL, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
        CFDictionaryRef gpsAttachments = CMGetAttachment(imageDataSampleBuffer,kCGImagePropertyGPSDictionary, NULL);

        if (exifAttachments) 
        { // Attachments may be read or additional ones written

        }

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];  

        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        /


        NSDictionary *newDict = (NSDictionary *)newMetadata;

        [library writeImageToSavedPhotosAlbum:[image CGImage] 
                                     metadata:newDict completionBlock:^(NSURL *assetURL, NSError *error)
         {
             if (error) 
             {

             }                                                                                               
         }];

        [library release];
        [image release];
        CFRelease(metadataDict);
        CFRelease(newMetadata);

    } 
    else if (error) 
    {

    }

}];
4

3 回答 3

9

我有完全相同的问题。我认为关于这个主题的文档不是很好,所以我最终通过查看相机应用程序拍摄的照片的元数据并尝试复制它来解决它。

以下是相机应用程序保存的属性的简要说明:

  • kCGImagePropertyGPSLatitude (NSNumber) (十进制格式的纬度)
  • kCGImagePropertyGPSLongitude (NSNumber) (十进制格式的经度)
  • kCGImagePropertyGPSLatitudeRef (NSString) (N 或 S)
  • kCGImagePropertyGPSLongitudeRef (NSString) (E 或 W)
  • kCGImagePropertyGPSTimeStamp (NSString) (格式为 04:30:51.71 (UTC 时间戳))

如果你坚持这些,你应该没问题。这是一个示例:

CFDictionaryRef metaDict = CMCopyDictionaryOfAttachments(NULL, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
CFMutableDictionaryRef mutable = CFDictionaryCreateMutableCopy(NULL, 0, metaDict);

NSDictionary *gpsDict = [NSDictionary 
  dictionaryWithObjectsAndKeys:
  [NSNumber numberWithFloat:self.currentLocation.coordinate.latitude], kCGImagePropertyGPSLatitude,
  @"N", kCGImagePropertyGPSLatitudeRef,
  [NSNumber numberWithFloat:self.currentLocation.coordinate.longitude], kCGImagePropertyGPSLongitude,
  @"E", kCGImagePropertyGPSLongitudeRef,
  @"04:30:51.71", kCGImagePropertyGPSTimeStamp,
  nil];

CFDictionarySetValue(mutable, kCGImagePropertyGPSDictionary, gpsDict);

//  Get the image
NSData *imageData = [AVCaptureStillImageOutput  jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];

//  Get the assets library
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[image CGImage] metadata:mutable completionBlock:captureComplete];

这一切都在你的 AVCaptureConnection 对象的 captureStillImageAsynchronouslyFromConnection 方法的 completionHandler 中,而 self.currentLocation 只是一个 CLLocation。为了简单起见,我对示例的时间戳和纬度/经度参考进行了硬编码。

希望这可以帮助!

于 2011-02-21T05:45:40.427 回答
2

梅森的回答真的帮助了我。您需要进行一些修改,例如设置经度和纬度的绝对值。这是使用 CoreLocation + Image I/O 将带有 GPS 信息的 UIImage 写入磁盘的代码片段:

- (BOOL)writeCGImage:(CGImageRef)theImage toURL:(NSURL*)url withType:(CFStringRef)imageType andOptions:(CFDictionaryRef)options {
    CGImageDestinationRef myImageDest   = CGImageDestinationCreateWithURL((CFURLRef)url, imageType, 1, nil);
    CGImageDestinationAddImage(myImageDest, theImage, options);
    BOOL success                        = CGImageDestinationFinalize(myImageDest);

    // Memory Mangement
    CFRelease(myImageDest);
    if (options)
        CFRelease(options);

    return success;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    if (newLocation) {
        [manager stopUpdatingLocation];

        // Create formatted date
        NSTimeZone      *timeZone   = [NSTimeZone timeZoneWithName:@"UTC"];
        NSDateFormatter *formatter  = [[NSDateFormatter alloc] init]; 
        [formatter setTimeZone:timeZone];
        [formatter setDateFormat:@"HH:mm:ss.SS"];

        // Create GPS Dictionary
        NSDictionary *gpsDict   = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithFloat:fabs(newLocation.coordinate.latitude)], kCGImagePropertyGPSLatitude
                                   , ((newLocation.coordinate.latitude >= 0) ? @"N" : @"S"), kCGImagePropertyGPSLatitudeRef
                                   , [NSNumber numberWithFloat:fabs(newLocation.coordinate.longitude)], kCGImagePropertyGPSLongitude
                                   , ((newLocation.coordinate.longitude >= 0) ? @"E" : @"W"), kCGImagePropertyGPSLongitudeRef
                                   , [formatter stringFromDate:[newLocation timestamp]], kCGImagePropertyGPSTimeStamp
                                   , nil];

        // Memory Management
        [formatter release];

        // Set GPS Dictionary to be part of media Metadata
        // NOTE: mediaInfo in this sample is dictionary object returned in UIImagePickerController delegate:
        // imagePickerController:didFinishPickingMediaWithInfo
        if (mediaInfo && [mediaInfo objectForKey:UIImagePickerControllerMediaMetadata] && gpsDict) {
            [[mediaInfo objectForKey:UIImagePickerControllerMediaMetadata] setValue:gpsDict forKey:@"{GPS}"];
        }

        // Save Image
        if([self writeCGImage:[image CGImage] toURL:imageSaveURL withType:kUTTypeJPEG andOptions:(CFDictionaryRef)[mediaInfo objectForKey:UIImagePickerControllerMediaMetadata]]) {
            // Image is written to device
        }
    } 
}
于 2011-09-15T01:08:19.347 回答
0

SO上面和其他地方有几个答案可以提供您想要的大部分内容。这是我从所有这些来源生成的工作代码,它似乎工作得很好。

这一切都在 captureStillImageAsynchronouslyFromConnection 块中完成。我感谢所有不同的贡献者:

    [stillCapture
 captureStillImageAsynchronouslyFromConnection: stillConnection
 completionHandler:
 ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
     if (error) {
         NSLog(@"snap capture error %@", [error localizedDescription]);
         return;
     }

     NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

     CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);
     CFMutableDictionaryRef mutableAttachments = CFDictionaryCreateMutableCopy(NULL, 0, attachments);

     // Create GPS Dictionary
     NSMutableDictionary *gps = [NSMutableDictionary dictionary];

     CLLocation *location = <your location source here>;

     // GPS tag version
     [gps setObject:@"2.2.0.0" forKey:(NSString *)kCGImagePropertyGPSVersion];

     // Time and date must be provided as strings, not as an NSDate object
     NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
     [formatter setDateFormat:@"HH:mm:ss.SSSSSS"];
     [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
     [gps setObject:[formatter stringFromDate:location.timestamp] forKey:(NSString *)kCGImagePropertyGPSTimeStamp];

     // Latitude
     [gps setObject: (location.coordinate.latitude < 0) ? @"S" : @"N"
             forKey:(NSString *)kCGImagePropertyGPSLatitudeRef];
     [gps setObject:[NSNumber numberWithDouble:fabs(location.coordinate.latitude)]
             forKey:(NSString *)kCGImagePropertyGPSLatitude];

     // Longitude
     [gps setObject: (location.coordinate.longitude < 0) ? @"W" : @"E"
             forKey:(NSString *)kCGImagePropertyGPSLongitudeRef];
     [gps setObject:[NSNumber numberWithDouble:fabs(location.coordinate.longitude)]
             forKey:(NSString *)kCGImagePropertyGPSLongitude];

     // Altitude
     if (!isnan(location.altitude)){
         // NB: many get this wrong, it is an int, not a string:
         [gps setObject:[NSNumber numberWithInt: location.altitude >= 0 ? 0 : 1]
                 forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
         [gps setObject:[NSNumber numberWithDouble:fabs(location.altitude)]
                 forKey:(NSString *)kCGImagePropertyGPSAltitude];
     }

     // Speed, must be converted from m/s to km/h
     if (location.speed >= 0){
         [gps setObject:@"K" forKey:(NSString *)kCGImagePropertyGPSSpeedRef];
         [gps setObject:[NSNumber numberWithDouble:location.speed*3.6] forKey:(NSString *)kCGImagePropertyGPSSpeed];
     }

     // Heading
     if (location.course >= 0){
         [gps setObject:@"T" forKey:(NSString *)kCGImagePropertyGPSTrackRef];
         [gps setObject:[NSNumber numberWithDouble:location.course] forKey:(NSString *)kCGImagePropertyGPSTrack];
     }

     CFDictionarySetValue(mutableAttachments, kCGImagePropertyGPSDictionary, CFBridgingRetain(gps));

//         NSDictionary *ma = (__bridge NSDictionary *)(mutableAttachments);
//         NSLog(@"photo attachments: %@", ma);

     [ROOTVC.library
      writeImageDataToSavedPhotosAlbum:jpegData
      metadata:(__bridge id)mutableAttachments
      completionBlock:^(NSURL *assetURL, NSError *error) {
          if (error) {
              NSLog(@"XXX save to assets failed: %@", [error localizedDescription]);
          } else {
              [self processAsset:assetURL inGroup:ROOTVC.venue forMessage:savingMessage];
          }
      }];

     if (mutableAttachments)
         CFRelease(mutableAttachments);
     if (attachments)
         CFRelease(attachments);
 }];

和往常一样,我担心我的发布是否正确。这是结果的 jhead(1):

File name    : 20131001_082119/photo.jpeg
File size    : 82876 bytes
File date    : 2013:10:01 08:21:19
Resolution   : 480 x 360
Orientation  : rotate 90
Flash used   : No
Focal length :  4.1mm  (35mm equivalent: 30mm)
Exposure time: 0.0083 s  (1/120)
Aperture     : f/2.2
ISO equiv.   : 6400
Whitebalance : Auto
Metering Mode: pattern
Exposure     : program (auto)
GPS Latitude : N 40d 43m 22.32s
GPS Longitude: W 74d 34m 39.15s
GPS Altitude :  117.92m
于 2013-10-01T15:24:17.380 回答