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

Posted

技术标签:

【中文标题】iOS 用前置摄像头闪光灯的新值覆盖 EXIF 闪光灯属性【英文标题】:iOS overwrite EXIF flash property with new value for front camera flash 【发布时间】:2015-06-20 23:51:23 【问题描述】:

我正在尝试更改 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;

【问题讨论】:

【参考方案1】:

当我在使用相机开发 ios 应用程序时遇到相同类型的问题时,我查找了一些典型的 EXIF 键,以及它们的标准翻译。

这是 EXIF flash 属性说明:

IFD Exif

代码 37385(十六进制 0x9209) 名字闪光

说明

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,这里有一个方法来翻译通过调用给出的枚举:

[[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

【讨论】:

【参考方案2】:

我想通了;原来kCGImagePropertyExifFlashNSCFNumber,而不是NSCFString,这是我的问题。我能够记录 Flash 模式的默认整数值:

开,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 闪光灯属性的主要内容,如果未能解决你的问题,请参考以下文章

Flutter小记3Android打开前置或广角摄像头的同时打开闪光灯方案

如何检查设备是不是有分别用于前置和后置摄像头的闪光灯?

为自定义相机转动闪光灯时前置相机崩溃?

有没有办法打开和关闭前置摄像头的手电筒? [复制]

android Camera如何判断当前使用的摄像头是前置还是后置

android Camera 如何判断当前使用的摄像头是前置还是后置