Cocoa touch 将元数据写入图像时出现问题
我正在使用AvFoundation拍摄静止图像,将gps信息添加到元数据中,并使用资产库保存到相册中,但gps信息根本不保存 这是我的密码Cocoa touch 将元数据写入图像时出现问题,cocoa-touch,metadata,avfoundation,Cocoa Touch,Metadata,Avfoundation,我正在使用AvFoundation拍摄静止图像,将gps信息添加到元数据中,并使用资产库保存到相册中,但gps信息根本不保存 这是我的密码 [self.stillImageTaker captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
[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)
{
}
}];
我也有同样的问题。我认为关于这个主题的文档不是很好,所以我最终解决了这个问题,通过查看摄像头应用程序拍摄的照片的元数据并尝试复制它 以下是Camera应用程序保存的属性摘要:
- KCGIMAGEPropertyGPS纬度 (NSNumber)(十进制格式的纬度)
- KCgimagePropertyGPS经度 (NSNumber)(十进制格式的经度)
- KCGIMAGEPROPERTYGPSTATITUREF (NSString)(N或S)
- kCGImagePropertyGPSLongitudeRef (NSString)(E或W)
- KCgimagePropertyGPTimeStamp (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。我对示例的时间戳和Lat/Lng引用进行了硬编码,以保持简单
希望这有帮助 梅森的回答确实帮助了我。您需要进行一些修改,例如设置经度和纬度的绝对值。以下是使用CoreLocation+Image I/O将UIImage写入包含GPS信息的磁盘的代码片段:
- (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
}
}
}
上面和其他地方都有一些答案,可以满足你的大部分需求。这是我从所有这些源代码中生成的工作代码,它似乎工作得很好 这一切都是在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);
}];
我和你有同样的问题。您是否找到了将exif元数据写入照片的解决方案?附件中似乎还有其他exig标签,但它们从未写入照片。
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