Jak napisać niestandardowe metadane do obrazów PNG w systemie iOS

Moja aplikacja powinna być w stanie zapisywać niestandardowe wpisy metadanych do obrazów PNG w celu ich eksportu do UIPasteboard.

Łącząc różne posty na ten temat, byłem w stanie wymyślić poniższą klasę jako źródło.

Wyzwalanie metody copyPressed przyciskiem, jestem w stanie ustawić niestandardowe metadane za pomocą obrazów JPG (EXIF):

Image[6101:907] found jpg exif dictionary
Image[6101:907] checking image metadata on clipboard
Image[6101:907] {
    ColorModel = RGB;
    Depth = 8;
    Orientation = 1;
    PixelHeight = 224;
    PixelWidth = 240;
    "{Exif}" =     {
        ColorSpace = 1;
        PixelXDimension = 240;
        PixelYDimension = 224;
        UserComment = "Here is a comment";
    };
    "{JFIF}" =     {
        DensityUnit = 0;
        JFIFVersion =         (
            1,
            1
        );
        XDensity = 1;
        YDensity = 1;
    };
    "{TIFF}" =     {
        Orientation = 1;
    };
}

Chociaż mogę dobrze odczytać metadane PNG, nie mogę do tego napisać:

Image[6116:907] found png property dictionary
Image[6116:907] checking image metadata on clipboard
Image[6116:907] {
    ColorModel = RGB;
    Depth = 8;
    PixelHeight = 224;
    PixelWidth = 240;
    "{PNG}" =     {
        InterlaceType = 0;
    };
}

Jednak nic w dokumentacji nie sugeruje, że powinno to zawieść i obecność wieluStałe metadanych specyficzne dla PNG sugeruje, że powinno się to udać.

Moja aplikacja powinna używać PNG, aby tego uniknąćKompresja stratna JPG.

Dlaczego nie mogę ustawić niestandardowych metadanych na obrazie PNG w pamięci w systemie iOS?

Uwaga: widziałemto pytanie TAK, ale nie rozwiązuje problemu tutaj, czyli w jaki sposób napisać metadane specjalnie do obrazów PNG.

IMViewController.m

#import "IMViewController.h"
#import <ImageIO/ImageIO.h>

@interface IMViewController ()

@end

@implementation IMViewController

- (IBAction)copyPressed:(id)sender
{
//    [self copyJPG];
    [self copyPNG];
}

-(void)copyPNG
{
    NSData *pngData = UIImagePNGRepresentation([UIImage imageNamed:@"wow.png"]);
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)pngData, NULL);
    NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
    NSMutableDictionary *mutableMetadata = [metadata mutableCopy];
    NSMutableDictionary *dict = [[mutableMetadata objectForKey:(NSString *) kCGImagePropertyPNGDictionary] mutableCopy];

    if (dict) {
        NSLog(@"found png property dictionary");
    } else {
        NSLog(@"creating png property dictionary");
        dict = [NSMutableDictionary dictionary];
    }

    // set values on the root dictionary
    [mutableMetadata setObject:@"Name of Software" forKey:(NSString *)kCGImagePropertyPNGDescription];
    [mutableMetadata setObject:dict forKey:(NSString *)kCGImagePropertyPNGDictionary];

    // set values on the internal dictionary
    [dict setObject:@"works" forKey:(NSString *)kCGImagePropertyPNGDescription];

    CFStringRef UTI = CGImageSourceGetType(source);
    NSMutableData *data = [NSMutableData data];
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) data, UTI, 1, NULL);

    if (!destination) {
        NSLog(@">>> Could not create image destination <<<");

        return;
    }

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

    BOOL success = CGImageDestinationFinalize(destination);

    if (!success) {
        NSLog(@">>> Error Writing Data <<<");
    }

    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];

    [pasteboard setData:data forPasteboardType:@"public.png"];
    [self showPNGMetadata];
}

-(void)copyJPG
{
    NSData *jpgData = UIImageJPEGRepresentation([UIImage imageNamed:@"wow.jpg"], 1);
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) jpgData, NULL);
    NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
    NSMutableDictionary *mutableMetadata = [metadata mutableCopy];
    NSMutableDictionary *exif = [[mutableMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];

    if (exif) {
        NSLog(@"found jpg exif dictionary");
    } else {
        NSLog(@"creating jpg exif dictionary");
    }

    // set values on the exif dictionary
    [exif setObject:@"Here is a comment" forKey:(NSString *)kCGImagePropertyExifUserComment];
    [mutableMetadata setObject:exif forKey:(NSString *)kCGImagePropertyExifDictionary];

    CFStringRef UTI = CGImageSourceGetType(source);
    NSMutableData *data = [NSMutableData data];
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) data, UTI, 1, NULL);

    if(!destination) {
        NSLog(@">>> Could not create image destination <<<");

        return;
    }

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

    BOOL success = CGImageDestinationFinalize(destination);

    if (!success) {
        NSLog(@">>> Could not create data from image destination <<<");
    }

    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];

    [pasteboard setData:data forPasteboardType:@"public.jpeg"];
    [self showJPGMetadata];
}

-(void)showJPGMetadata
{
    NSLog(@"checking image metadata on clipboard");

    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    NSData *data = [pasteboard dataForPasteboardType:@"public.jpeg"];

    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL);

    NSLog(@"%@", metadata);
}

-(void)showPNGMetadata
{
    NSLog(@"checking image metadata on clipboard");

    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    NSData *data = [pasteboard dataForPasteboardType:@"public.png"];

    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL);

    NSLog(@"%@", metadata);
}

@end

questionAnswers(1)

yourAnswerToTheQuestion