iOS 用前置摄像头闪光灯的新值覆盖 EXIF 闪光灯 属性

iOS overwrite EXIF flash property with new value for front camera flash

我正在尝试更改 Exif 词典的 kCGImagePropertyExifFlash 属性。我的应用程序提供前置闪光灯模式,因此我正在尝试更改此 Exif 值。当我使用 ALAssetsLibrarywriteImageDataToSavedPhotosAlbum 方法保存 newImageData 时,无论我做什么,它都会删除我设置的值。

如果能提供任何帮助,我将不胜感激。

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:
[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] 
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
    if (imageSampleBuffer && !error)
    {
        CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);

        NSDictionary *metadata = [NSDictionary dictionaryWithDictionary:(__bridge NSDictionary *)metadataDict];

        CFRelease(metadataDict);

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

        if (metadata && imageData)
        {
            NSMutableDictionary *newMetaData = [NSMutableDictionary dictionaryWithDictionary:metadata];

            NSMutableDictionary *exifMetadata = [NSMutableDictionary dictionaryWithDictionary:
            [metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]];

            if (self.isUsingFrontCamera && exifMetadata)
            {
                if (self.flashButton.flashMode == On)
                {
                    [exifMetadata setObject:@"On, Fired" forKey:(NSString *)kCGImagePropertyExifFlash];
                }
                else if (self.flashButton.flashMode == Off)
                {
                    [exifMetadata setObject:@"Off, did not fire" forKey:(NSString *)kCGImagePropertyExifFlash];
                }
                else if (self.frontFlashAutoDidFire)
                {
                    [exifMetadata setObject:@"Auto, Fired" forKey:(NSString *)kCGImagePropertyExifFlash];
                }
             }

             [newMetaData setObject:exifMetadata forKey:(NSString *)kCGImagePropertyExifDictionary];

             NSData *newImageData = [self writeMetadataIntoImageData:imageData metadata:newMetaData];

             [ALAssetsLibrary.new writeImageDataToSavedPhotosAlbum:newImageData metadata:nil completionBlock:nil];
         }
     }
}

- (NSData *)writeMetadataIntoImageData:(NSData *)imageData metadata:(NSDictionary *)metadata
{
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);

    CFStringRef UTI = CGImageSourceGetType(source);

    NSMutableData *data = [NSMutableData data];

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

    CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef) metadata);

    CGImageDestinationFinalize(destination);

    CFRelease(destination);
    CFRelease(source);

    return data;
}

我明白了;结果 kCGImagePropertyExifFlashNSCFNumber,而不是 NSCFString,这是我的问题。我能够记录闪光灯模式的默认整数值:

  • On, Fired 值为 9
  • 关,没火是16的值
  • 自动,不开火是24的值
  • Auto, Fired 的值为 25
  • 如果硬件设备不支持闪存,则值为 32
  • 不确定任何其他可能的值,可能与闪光灯太热时无法使用有关。

代码:

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:
[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] 
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
    if (imageSampleBuffer && !error)
    {
        CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);

        NSDictionary *metadata = [NSDictionary dictionaryWithDictionary:(__bridge NSDictionary *)metadataDict];

        CFRelease(metadataDict);

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

        if (metadata && imageData)
        {
            NSMutableDictionary *newMetaData = [NSMutableDictionary dictionaryWithDictionary:metadata];

            NSMutableDictionary *exifMetadata = [NSMutableDictionary dictionaryWithDictionary:
            [metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]];

            if (self.isUsingFrontCamera && exifMetadata)
            {
                if (self.flashButton.flashMode == On)
                {
                    [exifMetadata setObject:@(9) forKey:(NSString *)kCGImagePropertyExifFlash];
                }
                else if (self.flashButton.flashMode == Off)
                {
                    [exifMetadata setObject:@(16) forKey:(NSString *)kCGImagePropertyExifFlash];
                }
                else if (self.flashButton.flashMode == Auto)
                {
                    [exifMetadata setObject:@(24) forKey:(NSString *)kCGImagePropertyExifFlash];

                    if (self.frontFlashAutoDidFire)
                    {
                        [exifMetadata setObject:@(25) forKey:(NSString *)kCGImagePropertyExifFlash];
                    }
                }
            }

            [newMetaData setObject:exifMetadata forKey:(NSString *)kCGImagePropertyExifDictionary];

            [ALAssetsLibrary.new writeImageDataToSavedPhotosAlbum:imageData metadata:newMetaData completionBlock:nil];
        }
    }
}

当我 运行 在使用相机开发 iOS 应用程序时遇到同样的问题,我查找了一些典型的 EXIF 密钥及其标准 t运行 格式。

这是 EXIF flash 属性 描述:

IFD Exif

Code        37385 (hex 0x9209)
Name        Flash

描述

Indicates the status of flash when the image was shot.

Bit 0 indicates the flash firing status, bits 1 and 2 indicate the flash return status, bits 3 and 4 indicate the flash mode, bit 5 indicates whether the flash function is present, and bit 6 indicates "red eye" mode.

Values for bit 0 indicating whether the flash fired.
0 = Flash did not fire
1 = Flash fired

Values for bits 1 and 2 indicating the status of returned light.
00 = No strobe return detection function
01 = reserved
10 = Strobe return light not detected
11 = Strobe return light detected

Values for bits 3 and 4 indicating the camera's flash mode.
00 = unknown
01 = Compulsory flash firing
10 = Compulsory flash suppression
11 = Auto mode

Values for bit 5 indicating the presence of a flash function.
0 = Flash function present
1 = No flash function

Values for bit 6 indicating the camera's red-eye mode.
0 = No red-eye reduction mode or unknown
1 = Red-eye reduction supported

Not all combinations make sense though. The specification defines these combined values:

hex 0000 = Flash did not fire
hex 0001 = Flash fired
hex 0005 = Strobe return light not detected
hex 0007 = Strobe return light detected
hex 0009 = Flash fired, compulsory flash mode
hex 000D = Flash fired, compulsory flash mode, return light not detected
hex 000F = Flash fired, compulsory flash mode, return light detected
hex 0010 = Flash did not fire, compulsory flash mode
hex 0018 = Flash did not fire, auto mode
hex 0019 = Flash fired, auto mode
hex 001D = Flash fired, auto mode, return light not detected
hex 001F = Flash fired, auto mode, return light detected
hex 0020 = No flash function
hex 0041 = Flash fired, red-eye reduction mode
hex 0045 = Flash fired, red-eye reduction mode, return light not detected
hex 0047 = Flash fired, red-eye reduction mode, return light detected
hex 0049 = Flash fired, compulsory flash mode, red-eye reduction mode
hex 004D = Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected
hex 004F = Flash fired, compulsory flash mode, red-eye reduction mode, return light detected
hex 0059 = Flash fired, auto mode, red-eye reduction mode
hex 005D = Flash fired, auto mode, return light not detected, red-eye reduction mode
hex 005F = Flash fired, auto mode, return light detected, red-eye reduction mode

使用十六进制到十进制的转换和 objective-C,这里有一个方法来 t运行slate 调用 :

给出的枚举
[[exifDictionary objectForKey : @"Flash"] integerValue]

进入NSString描述

-(NSString *) translateFlashEnumToNSString: (long) flash
{
    switch (flash) {
        case 0:
            return @"Flash did not fire";
        case 1:
            return @"Flash did fire";
        case 5:
            return @"Strobe return light not detected";
        case 7:
            return @"Strobe return light detected";
        case 9:
            return @"Flash fired, compulsory flash mode";
        case 13:
            return @"Flash fired, compulsory flash mode, return light not detected";
        case 15:
            return @"Flash fired, compulsory flash mode, return light detected";
        case 16:
            return @"Flash did not fire, compulsory flash mode";
        case 24:
            return @"Flash did not fire, auto mode";
        case 25:
            return @"Flash fired, auto mode";
        case 29:
            return @"Flash fired, auto mode, return light not detected";
        case 31:
            return @"Flash fired, auto mode, return light detected";
        case 32:
            return @"No flash function";
        case 65:
            return @"Flash fired, red-eye reduction mode";
        case 69:
            return @"Flash fired, red-eye reduction mode, return light not detected";
        case 71:
            return @"Flash fired, red-eye reduction mode, return light detected";
        case 73:
            return @"Flash fired, compulsory flash mode, red-eye reduction mode";
        case 77:
            return @"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected";
        case 79:
            return @"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected";
        case 89:
            return @"Flash fired, auto mode, red-eye reduction mode";
        case 93:
            return @"Flash fired, auto mode, return light not detected, red-eye reduction mode";
        case 95:
            return @"Flash fired, auto mode, return light detected, red-eye reduction mode";
        default:
            return @"Flash mode unsupported";
    }
}

调用方法:

NSLog(@"Flash EXIF : %@", [self translateFlashEnumToNSString: [[exifDictionary objectForKey:@"Flash"] integerValue]];

希望对您有所帮助。 对于其他 EXIF 密钥及其描述:http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/flash.html