2012-10-13 8 views
6

SO 응답 + Google 결과를 무수히 시도하고 체증 한 결과, iOS에서 EXIF로 작업하는 것이 매우 실망 스럽습니다.수정 된 EXIF ​​데이터가 제대로 저장되지 않습니다.

아래는 결과 코드입니다.

2012-10-12 23:17:45.415 Waypointer[3120:907] original metadata Info: { 
ColorModel = RGB; 
DPIHeight = 72; 
DPIWidth = 72; 
Depth = 8; 
Orientation = 1; 
PixelHeight = 2448; 
PixelWidth = 3264; 
"{Exif}" =  { 
    ApertureValue = "2.526069"; 
    BrightnessValue = "-4.410617"; 
    ColorSpace = 1; 
    ComponentsConfiguration =   (
     1, 
     2, 
     3, 
     0 
    ); 
    ExifVersion =   (
     2, 
     2, 
     1 
    ); 
    ExposureMode = 0; 
    ExposureProgram = 2; 
    ExposureTime = "0.06666667"; 
    FNumber = "2.4"; 
    Flash = 16; 
    FlashPixVersion =   (
     1, 
     0 
    ); 
    FocalLenIn35mmFilm = 35; 
    FocalLength = "4.28"; 
    ISOSpeedRatings =   (
     800 
    ); 
    MeteringMode = 5; 
    PixelXDimension = 3264; 
    PixelYDimension = 2448; 
    SceneCaptureType = 0; 
    SensingMethod = 2; 
    ShutterSpeedValue = "3.906905"; 
    SubjectArea =   (
     1631, 
     1223, 
     881, 
     881 
    ); 
    WhiteBalance = 0; 
}; 
"{TIFF}" =  { 
    Orientation = 1; 
    ResolutionUnit = 2; 
    XResolution = 72; 
    YResolution = 72; 
    "_YCbCrPositioning" = 1; 
}; 
} 

그리고이 :

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
    completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) 
    { 
     NSData *imageNSData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 

     CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge_retained CFDataRef)imageNSData, NULL); 

     //get all the metadata in the image 
     NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imgSource, 0, NULL); 

     NSLog(@"original metadata Info: %@",metadata); 

     //make the metadata dictionary mutable so we can add properties to it 
     NSMutableDictionary *metadataAsMutable = [metadata mutableCopy]; 

     NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]; 
     NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]; 
     NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy]; 

     if(!EXIFDictionary) 
      EXIFDictionary = [[NSMutableDictionary dictionary] init]; 

     if(!GPSDictionary) 
      GPSDictionary = [[NSMutableDictionary dictionary] init]; 

     if(!RAWDictionary) 
      RAWDictionary = [[NSMutableDictionary dictionary] init]; 


     [GPSDictionary setObject:@"camera coord Latitude" 
         forKey:(NSString*)kCGImagePropertyGPSLatitude]; 
     [GPSDictionary setObject:@"camera coord Longitude" 
         forKey:(NSString*)kCGImagePropertyGPSLongitude]; 
     [GPSDictionary setObject:@"camera GPS Date Stamp" 
         forKey:(NSString*)kCGImagePropertyGPSDateStamp]; 
     [GPSDictionary setObject:@"camera direction (heading) in degrees" 
         forKey:(NSString*)kCGImagePropertyGPSImgDirection]; 

     [GPSDictionary setObject:@"subject coord Latitude" 
         forKey:(NSString*)kCGImagePropertyGPSDestLatitude]; 
     [GPSDictionary setObject:@"subject coord Longitude" 
         forKey:(NSString*)kCGImagePropertyGPSDestLongitude]; 

     [EXIFDictionary setObject:@"[S.D.] kCGImagePropertyExifUserComment" 
          forKey:(NSString *)kCGImagePropertyExifUserComment]; 

     [EXIFDictionary setValue:@"69 m" forKey:(NSString *)kCGImagePropertyExifSubjectDistance]; 


     //Add the modified Data back into the image’s metadata 
     [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; 
     [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; 
     [metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary]; 


     NSLog(@"metadataAsMutable Info: %@",metadataAsMutable); 

     CFStringRef UTI = CGImageSourceGetType(imgSource); //this is the type of image (e.g., public.jpeg) 

     //this will be the data CGImageDestinationRef will write into 
     NSMutableData *newImageData = [NSMutableData data]; 

     CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)newImageData, UTI, 1, NULL); 

     if(!destination) 
      NSLog(@"***Could not create image destination ***"); 

     //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata 
     CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge CFDictionaryRef) metadataAsMutable); 

     //tell the destination to write the image data and metadata into our data object. 
     //It will return false if something goes wrong 
     BOOL success = NO; 
     success = CGImageDestinationFinalize(destination); 

     if(!success) 
      NSLog(@"***Could not create data from image destination ***"); 

     CIImage *testImage = [CIImage imageWithData:newImageData]; 
     NSDictionary *propDict = [testImage properties]; 
     NSLog(@"Properties %@", propDict); 

    }]; 

이 출력이 모두 끝났다 후,

2012-10-12 23:17:45.421 Waypointer[3120:907] metadataAsMutable Info: { 
ColorModel = RGB; 
DPIHeight = 72; 
DPIWidth = 72; 
Depth = 8; 
Orientation = 1; 
PixelHeight = 2448; 
PixelWidth = 3264; 
"{Exif}" =  { 
    ApertureValue = "2.526069"; 
    BrightnessValue = "-4.410617"; 
    ColorSpace = 1; 
    ComponentsConfiguration =   (
     1, 
     2, 
     3, 
     0 
    ); 
    ExifVersion =   (
     2, 
     2, 
     1 
    ); 
    ExposureMode = 0; 
    ExposureProgram = 2; 
    ExposureTime = "0.06666667"; 
    FNumber = "2.4"; 
    Flash = 16; 
    FlashPixVersion =   (
     1, 
     0 
    ); 
    FocalLenIn35mmFilm = 35; 
    FocalLength = "4.28"; 
    ISOSpeedRatings =   (
     800 
    ); 
    MeteringMode = 5; 
    PixelXDimension = 3264; 
    PixelYDimension = 2448; 
    SceneCaptureType = 0; 
    SensingMethod = 2; 
    ShutterSpeedValue = "3.906905"; 
    SubjectArea =   (
     1631, 
     1223, 
     881, 
     881 
    ); 
    SubjectDistance = "69 m"; 
    UserComment = "[S.D.] kCGImagePropertyExifUserComment"; 
    WhiteBalance = 0; 
}; 
"{GPS}" =  { 
    DateStamp = "camera GPS Date Stamp"; 
    DestLatitude = "subject coord Latitude"; 
    DestLongitude = "subject coord Longitude"; 
    ImgDirection = "camera direction (heading) in degrees"; 
    Latitude = "camera coord Latitude"; 
    Longitude = "camera coord Longitude"; 
}; 
"{Raw}" =  { 
}; 
"{TIFF}" =  { 
    Orientation = 1; 
    ResolutionUnit = 2; 
    XResolution = 72; 
    YResolution = 72; 
    "_YCbCrPositioning" = 1; 
}; 
} 

을 그리고, 이것은 다음 예제는 설명

2012-10-12 23:17:47.131 Waypointer[3120:907] Properties { 
ColorModel = RGB; 
DPIHeight = 72; 
DPIWidth = 72; 
Depth = 8; 
Orientation = 1; 
PixelHeight = 2448; 
PixelWidth = 3264; 
"{Exif}" =  { 
    ApertureValue = "2.526069"; 
    BrightnessValue = "-4.410617"; 
    ColorSpace = 1; 
    ComponentsConfiguration =   (
     0, 
     0, 
     0, 
     1 
    ); 
    ExifVersion =   (
     2, 
     2, 
     1 
    ); 
    ExposureMode = 0; 
    ExposureProgram = 2; 
    ExposureTime = "0.06666667"; 
    FNumber = "2.4"; 
    Flash = 16; 
    FlashPixVersion =   (
     1, 
     0 
    ); 
    FocalLenIn35mmFilm = 35; 
    FocalLength = "4.28"; 
    ISOSpeedRatings =   (
     800 
    ); 
    MeteringMode = 5; 
    PixelXDimension = 3264; 
    PixelYDimension = 2448; 
    SceneCaptureType = 0; 
    SensingMethod = 2; 
    ShutterSpeedValue = "3.906905"; 
    SubjectArea =   (
     1631, 
     1223, 
     881, 
     881 
    ); 
    UserComment = "[S.D.] kCGImagePropertyExifUserComment"; 
    WhiteBalance = 0; 
}; 
"{JFIF}" =  { 
    DensityUnit = 1; 
    JFIFVersion =   (
     1, 
     1 
    ); 
    XDensity = 72; 
    YDensity = 72; 
}; 
"{TIFF}" =  { 
    Orientation = 1; 
    ResolutionUnit = 2; 
    XResolution = 72; 
    YResolution = 72; 
    "_YCbCrPositioning" = 1; 
}; 
} 

으로 이미지의 원래 메타 데이터 인 mo를 볼 수 있습니다. 차별화, 그리고 최종 출력.

최종 결과물은 내가하는 일에 상관없이 수정 된 값을 고수 할 수 없기 때문에 나를 귀찮게합니다!

매우 구체적인 형식이 있습니까? iOS가 내 수정 사항을 삭제하는 이유는 무엇입니까? 이러한 추가 값을 추가하려면 어떻게해야합니까? 그들은 .header에 나열되어 있으며 쉽게 받아 들여 져야한다고 생각했습니다.

+0

'메타 데이터'에서 ARC가 '__bridge'가 아닌'__bridge_transfer '(또는'CFBridgingRelease')가 필요합니다. 당신. –

+0

좋습니다. 그러나 나는 여전히 같은 결과를 얻는다. –

+0

내가 가지고있는 유일한 또 다른 일은 사전을 잘못 작성하고 있다는 것입니다. 'dictionary'와 같은 편의 생성자는 이미 초기화 된 객체를 반환하므로 init 객체를 보낼 필요가 없으며 그렇게해서는 안됩니다. '[[... alloc] init]','[... new]'또는'[NSMutableDictionary dictionary]'를 사용하십시오. 나는 출력이 올바르게 보이기 때문에 이것이 문제를 해결할 것이라고 생각하지 않지만, 나는 볼 수있는 유일한 나머지 버그이다. –

답변

9

스콧, 애플의 개발자가, 내 사고 보고서와 함께 반환하고 문제 해결 :

문자열을 쓰고 앞의 코드는 GPS 값에 대한 값을 - 작동하지 않습니다 은 NS/CFNumbers이어야합니다 ( EXIF에 대한 float 값을 추출합니다).

나는 그들의 문서에 대해 Apple에 버그 보고서를 제출할 것입니다.

이 응답을받는 데 1 주일이 걸렸지 만, Apple이 개발자에게 제공하는 지원에 정말 감사드립니다.

Final properties info { 
    ColorModel = RGB; 
    DPIHeight = 72; 
    DPIWidth = 72; 
    Depth = 8; 
    Orientation = 6; 
    PixelHeight = 2448; 
    PixelWidth = 3264; 
    "{Exif}" =  { 
     ApertureValue = "2.526069"; 
     BrightnessValue = "0.547474"; 
     ColorSpace = 1; 
     ComponentsConfiguration =   (
      0, 
      0, 
      0, 
      1 
     ); 
     ExifVersion =   (
      2, 
      2, 
      1 
     ); 
     ExposureMode = 0; 
     ExposureProgram = 2; 
     ExposureTime = "0.05"; 
     FNumber = "2.4"; 
     Flash = 16; 
     FlashPixVersion =   (
      1, 
      0 
     ); 
     FocalLenIn35mmFilm = 35; 
     FocalLength = "4.28"; 
     ISOSpeedRatings =   (
      320 
     ); 
     MeteringMode = 5; 
     PixelXDimension = 3264; 
     PixelYDimension = 2448; 
     SceneCaptureType = 0; 
     SensingMethod = 2; 
     ShutterSpeedValue = "4.321929"; 
     SubjectArea =   (
      1631, 
      1223, 
      881, 
      881 
     ); 
     SubjectDistance = "69.999"; 
     UserComment = "[S.D.] kCGImagePropertyExifUserComment"; 
     WhiteBalance = 0; 
    }; 
    "{GPS}" =  { 
     DateStamp = "2012:10:18"; 
     DestLatitude = "37.795"; 
     DestLatitudeRef = N; 
     DestLongitude = "122.41"; 
     DestLongitudeRef = W; 
     ImgDirection = 300; 
     Latitude = "37.795"; 
     LatitudeRef = N; 
     Longitude = "122.41"; 
     LongitudeRef = W; 
    }; 
    "{JFIF}" =  { 
     DensityUnit = 1; 
     JFIFVersion =   (
      1, 
      1 
     ); 
     XDensity = 72; 
     YDensity = 72; 
    }; 
    "{TIFF}" =  { 
     Orientation = 6; 
     ResolutionUnit = 2; 
     XResolution = 72; 
     YResolution = 72; 
     "_YCbCrPositioning" = 1; 
    }; 
} 

당신이 볼 수 있듯이, 모든 값은 다음과 같습니다이 출력

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
    completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) 
    { 
     NSData *imageNSData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 

     CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge_retained CFDataRef)imageNSData, NULL); 

     //get all the metadata in the image 
     NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imgSource, 0, NULL); 

     //make the metadata dictionary mutable so we can add properties to it 
     NSMutableDictionary *metadataAsMutable = [metadata mutableCopy]; 

     NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]; 
     NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]; 
     NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy]; 

     if(!EXIFDictionary) 
      EXIFDictionary = [[NSMutableDictionary dictionary] init]; 

     if(!GPSDictionary) 
      GPSDictionary = [[NSMutableDictionary dictionary] init]; 

     if(!RAWDictionary) 
      RAWDictionary = [[NSMutableDictionary dictionary] init]; 


     [GPSDictionary setObject:[NSNumber numberWithFloat:37.795] 
          forKey:(NSString*)kCGImagePropertyGPSLatitude]; 

     [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; 

     [GPSDictionary setObject:[NSNumber numberWithFloat:122.410] 
          forKey:(NSString*)kCGImagePropertyGPSLongitude]; 

     [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; 

     [GPSDictionary setObject:@"2012:10:18" 
          forKey:(NSString*)kCGImagePropertyGPSDateStamp]; 

     [GPSDictionary setObject:[NSNumber numberWithFloat:300] 
          forKey:(NSString*)kCGImagePropertyGPSImgDirection]; 

     [GPSDictionary setObject:[NSNumber numberWithFloat:37.795] 
          forKey:(NSString*)kCGImagePropertyGPSDestLatitude]; 

     [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSDestLatitudeRef]; 

     [GPSDictionary setObject:[NSNumber numberWithFloat:122.410] 
          forKey:(NSString*)kCGImagePropertyGPSDestLongitude]; 

     [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSDestLongitudeRef]; 

     [EXIFDictionary setObject:@"[S.D.] kCGImagePropertyExifUserComment" 
          forKey:(NSString *)kCGImagePropertyExifUserComment]; 

     [EXIFDictionary setObject:[NSNumber numberWithFloat:69.999] 
          forKey:(NSString*)kCGImagePropertyExifSubjectDistance]; 


     //Add the modified Data back into the image’s metadata 
     [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; 
     [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; 
     [metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary]; 


     CFStringRef UTI = CGImageSourceGetType(imgSource); //this is the type of image (e.g., public.jpeg) 

     //this will be the data CGImageDestinationRef will write into 
     NSMutableData *newImageData = [NSMutableData data]; 

     CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)newImageData, UTI, 1, NULL); 

     if(!destination) 
      NSLog(@"***Could not create image destination ***"); 

     //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata 
     CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge CFDictionaryRef) metadataAsMutable); 

     //tell the destination to write the image data and metadata into our data object. 
     //It will return false if something goes wrong 
     BOOL success = NO; 
     success = CGImageDestinationFinalize(destination); 

     if(!success) 
      NSLog(@"***Could not create data from image destination ***"); 

     CIImage *testImage = [CIImage imageWithData:newImageData]; 
     NSDictionary *propDict = [testImage properties]; 
     NSLog(@"Final properties %@", propDict); 

    }]; 

: (감사합니다 스콧!) ;-)

아래는 개선 된 코드가 및 올바른 출력 이제 제대로 EXIF ​​헤더에 포함되어 있고 이것이 제대로 JPG로 카메라 롤에 기록되었는지 테스트했습니다.

즐기십시오! :)

+1

제 입력은 UIImage이므로 출력도 같아야합니다. 데이터는 내가하는대로 수정되지 않은 채로 남아 있습니다 ... 그것은 CIImage에서도 작동합니다. 어떤 생각? – Mercurial

+2

데이터를 저장할 때까지 코드가 제대로 작동합니다. 파일에서 데이터를 읽을 때 원본 메타 데이터 만 포함됩니다. 어떤 생각? – Amnysia

+0

@Sebastian 감사합니다. 현지 이미지를 읽고 저장하는 데 도움이되었지만 Google 드라이브에 업로드 한 다음 Google 드라이브에서 다운로드하면 내게 GPS 좌표가 표시되지 않습니다. –

관련 문제