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

611 views Asked by At

I'm trying to change the kCGImagePropertyExifFlash property of the Exif dictionary. My app offers front facing flash modes, so I'm trying to change this Exif value. No matter what I do when I go to save the newImageData using writeImageDataToSavedPhotosAlbum method of ALAssetsLibrary, it removes the value I set.

I'd appreciate any help offered.

[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;
}
2

There are 2 answers

0
klcjr89 On BEST ANSWER

I figured this out; it turns out the kCGImagePropertyExifFlash is an NSCFNumber, not an NSCFString, which was my problem. I was able to log the default integer values for the flash modes:

  • On, Fired is a value of 9
  • Off, did not fire is a value of 16
  • Auto, did not fire is a value of 24
  • Auto, Fired is a value of 25
  • If the hardware device doesn't have flash support, the value is 32
  • Unsure of any other possible values, perhaps related to when the flash isn't available if it's too warm.

Code:

[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];
        }
    }
}
0
Neimsz On

As i ran into the same sort of question while developing an iOS app using the camera, I looked up some typical EXIF keys, and their standard translations.

Here is the EXIF flash property description :

IFD Exif

Code        37385 (hex 0x9209)
Name        Flash

Description

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

Using hex to decimal conversion and objective-C, here is a method to translate the enum given by a call to :

[[exifDictionary objectForKey : @"Flash"] integerValue]

into a NSString description

-(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";
    }
}

calling the method :

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

Hope it will help. And for other EXIF key and their description : http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/flash.html