2013-03-04 26 views
12

La mia applicazione dovrebbe essere in grado di scrivere voci di metadati personalizzate in immagini PNG per l'esportazione su UIPasteboard.Come scrivere metadati personalizzati in immagini PNG su iOS

Mettendo insieme vari post sull'argomento, sono riuscito a trovare la classe indicata di seguito come sorgente.

Triggering il metodo copyPressed con un pulsante, sono in grado di impostare i metadati personalizzati con le immagini 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; 
    }; 
} 

Anche se sono in grado di leggere i metadati PNG bene, posso' t sembrano scrivere su di esso:

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

Tuttavia, nulla nella documentazione suggerisce che questo dovesse fallire e la presenza di molti PNG-specific metadata constants suggerisce che dovrebbe avere successo.

La mia applicazione dovrebbe utilizzare PNG per evitare JPG's lossy compression.

Perché non posso impostare i metadati personalizzati su un'immagine PNG in memoria in iOS?

Nota: ho visto this SO question, ma non risolve il problema qui, che è come scrivere metadati in immagini PNG in particolare.

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 

risposta

4

Se si cercherà di salvare l'immagine con metadati modificati

[data writeToFile:[NSTemporaryDirectory() stringByAppendingPathComponent:@"test.png"] 
     atomically:YES]; 

E di vederlo immobili a Finder. Vedrai che il campo kCGImagePropertyPNGDescription è stato impostato correttamente.

enter image description here

Ma se si cercherà di leggere i metadati di questo nuovo file, kCGImagePropertyPNGDescription andranno persi.

ColorModel = RGB; 
Depth = 8; 
PixelHeight = 1136; 
PixelWidth = 640; 
"{PNG}" =  { 
    InterlaceType = 0; 
}; 

Dopo alcune ricerche ho scoperto che PNG non contiene metadati. Ma può contenere XMP metadata. Tuttavia sembra che ImageIO non abbia funzionato con XMP.
Forse puoi provare a usare ImageMagic o libexif.

Link utili:
PNG Specification
Reading/Writing image XMP on iPhone/Objective-c
Does PNG support metadata fields like Author, Camera Model, etc?
Does PNG contain EXIF data like JPG?
libexif.sourceforge.net

+0

buono a sapersi. Apparentemente iOS non può leggere i metadati PNG dai file usando il mio metodo. Se avessi un modo per leggere i metadati PNG, potrei avere una soluzione. Dato che iOS ha costanti come kCGImagePropertyPNGDescription, preferirei non usare librerie esterne e preferirei sapere come farlo realmente solo con le librerie iOS. –

+0

Immagina di essere in grado di aggiungere metadati all'immagine, sei sicuro che altri software leggeranno queste informazioni? Per quale motivo vuoi aggiungere i metadati? –

+0

hai trovato una risposta? – Crashalot