Search code examples
iosswiftmacoscore-graphicscgimage

CGImage has no properties / metadata (CGImageProperties)


Say I have a CGImage that was loaded from some URL, and I want to extract its properties via CGImageSourceCopyPropertiesAtIndex:

// Playground

import SwiftUI

func printPropertiesOf(_ image: CGImage) {
    guard let dataProvider = image.dataProvider else {
        print("Couldn't get the data provider.")
        return
    }
    guard let data = dataProvider.data else {
        print("Couldn't get the data.")
        return
    }
    guard let source = CGImageSourceCreateWithData(data, nil) else {
        print("Couldn't get the source.")
        return
    }
    guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) else {
        print("Couldn't get the properties.")
        return
    }
    print(properties)
}

let url = Bundle.main.url(forResource: "Landscape/Landscape_0", withExtension: "jpg")!
let source = CGImageSourceCreateWithURL(url as CFURL, nil)!
let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil)!

printPropertiesOf(cgImage)

Output:

Couldn't get the properties.


But if I use the URL where the image resides, instead of the CGImage:

// Playground

import SwiftUI

func printPropertiesOfImageIn(_ url: URL) {
    guard let data = try? Data(contentsOf: url) else {
        print("Couldn't get the data.")
        return
    }
    guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
        print("Couldn't get the source.")
        return
    }
    guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) else {
        print("Couldn't get the properties.")
        return
    }
    print(properties)
}

let url = Bundle.main.url(forResource: "Landscape/Landscape_0", withExtension: "jpg")!
let source = CGImageSourceCreateWithURL(url as CFURL, nil)!
let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil)!

printPropertiesOfImageIn(url)

Output:

{
    ColorModel = RGB;
    DPIHeight = 72;
    DPIWidth = 72;
    Depth = 8;
    PixelHeight = 1200;
    PixelWidth = 1800;
    "{JFIF}" =     {
        DensityUnit = 1;
        JFIFVersion =         (
            1,
            0,
            1
        );
        XDensity = 72;
        YDensity = 72;
    };
    "{TIFF}" =     {
        Orientation = 0;
        ResolutionUnit = 2;
        XResolution = 72;
        YResolution = 72;
    };
}


Is there a way to retrieve the metadata from a CGImage itself, without having to rely on its source URL?

If not, is there a way to find out the source URL of a given CGImage?

(Note: the image used in the above examples can be found here.)


Solution

  • The CGImage should be completely raw bitmap data. A minimum set of uncompressed data to visually present an image even. From docs "A bitmap image or image mask".

    I am actually surprised that you were able to construct a source using CGImageSourceCreateWithData in two such different ways:

    • In first case you are creating it directly from raw uncompressed data which is your CGImage. It is expected that it has absolutely no headers or additional information on how it should be shown.

    • In second case you are creating it from JPEG data which is compressed data with headers that may contain a lot of different information. Some of the info may be completely unrelated such as coordinates of where image was taken or date it was taken on for instance.

    So the additional information that you are showing in second case could potentially be used by the system to construct a CGImage object (encoding for instance). But it is not the information that needs to be appended to CGImage in order to display it since it is already prepared (decoded) for presentation.

    In your title you are saying "CGImage has no properties / metadata (CGImageProperties)". There is no such thing as "CGImageProperties", there is "CGImageSourceProperties". So it is the source that has the properties.

    So I believe these properties are not copied and there is no way to get them from CGImage alone. There are other properties you can get directly from CGImage though:

    • cgImage.width
    • cgImage.height
    • cgImage.alphaInfo
    • cgImage.bitmapInfo
    • cgImage.bitsPerComponent
    • cgImage.colorSpace
    • ...

    You can check a bit more here.