CGImageDestinationCopyImageSource converts or truncates floats to integers

Some EXIF entries require float content as a string. For example FNumber often looks like that: "2.8" or "1.4". When I edit EXIF data using CGImageDestinationCopyImageSource most of the EXIF entries that require that float-like content are truncated to their first character. To stay in the example above the EXIF dict will be written with a "2" or "1". The dot and the rest of the string are truncated. 🤯

Shall: "2.8" Is: "2"

All EXIF data is written correctly (I use about 40 fields), but only the following keys are reduced to some kind of integer style:

  • kCGImagePropertyExifFNumber
  • kCGImagePropertyExifFocalLength
  • kCGImagePropertyGPSAltitude
  • kCGImagePropertyGPSImgDirection
  • kCGImagePropertyGPSSpeed

I am using this code to set the entries:

let metaData = CGImageMetadataCreateMutable()

if !CGImageMetadataSetValueMatchingImageProperty(metaData, kCGImagePropertyExifDictionary, kCGImagePropertyExifFNumber, 2.8 as CFTypeRef) {
  print("kCGImagePropertyExifFNumber EXIF not written")
}

let destOptions: [String: AnyObject] = [
  kCGImageDestinationMergeMetadata as String: NSNumber(value: 1),
  kCGImageDestinationMetadata as String: metaData
]

if !CGImageDestinationCopyImageSource(destination, cgImgSource, destOptions as CFDictionary, nil)  {
  print("Error making CGImageDestinationCopyImageSource")
}

The dictionary being created shows me the correct values, but when I open the updated JPG, I only see the truncated floating point numbers.

I tried it with

  • 2.8 as CFString
  • "2.8" as CFString
  • 2.8 as CFTypeRef
  • "2.8" as CFTypeRef
  • 2.8 as CFNumber
  • 2.8 as NSNumber
  • 2.8 as NSString

Only in kCGImagePropertyGPSLongitude & kCGImagePropertyGPSLatitude this behavior doesn't occur.

if !CGImageMetadataSetValueMatchingImageProperty(metaData, kCGImagePropertyGPSDictionary, kCGImagePropertyGPSLatitude, 53.997853 as CFTypeRef ) {
  print("kCGImagePropertyGPSLatitude GPS not written")
}

Using CGImageDestinationCreateWithData does not do this and writes the data correctly.

I think that’s strange, because most photos aren’t taken with int-values. So either I found a bug or I am doing something wrong. What’s the point here? Is there some kind of round-rule?

CGImageDestinationCopyImageSource converts or truncates floats to integers
 
 
Q