2013-03-04 13 views
12

Moja aplikacja powinna być w stanie pisać niestandardowe wpisy metadanych do obrazów PNG w celu eksportu do UIPasteboard.Jak pisać niestandardowe metadane do obrazów PNG w iOS

Łącząc różne posty na ten temat, udało mi się wymyślić klasę podaną poniżej jako źródło.

Wyzwalanie copyPressed metody z przyciskiem, jestem w stanie ustawić niestandardowe metadane z 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ż jestem w stanie odczytać metadane PNG dobrze, mogę” t wydają się napisać do niego:

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 sugeruje to powinno zakończyć się niepowodzeniem i obecność wielu PNG-specific metadata constants sugeruje powinien odnieść sukces.

Moja aplikacja powinna używać PNG, aby uniknąć JPG's lossy compression.

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

Uwaga: Widziałem this SO question, ale nie rozwiązuje problemu tutaj, czyli w jaki sposób zapisywać metadane 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 

Odpowiedz

4

Jeśli będziesz próbować zapisać obraz ze zmodyfikowanego metadanych

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

I niż go zobaczyć właściwości w Finderze. Zobaczysz, że pole kCGImagePropertyPNGDescription zostało skonfigurowane pomyślnie.

enter image description here

Ale jeśli będzie próbować odczytać metadane tego nowego pliku, kCGImagePropertyPNGDescription zostaną utracone.

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

Po kilku badaniach stwierdziłem, że PNG nie zawiera metadanych. Ale może zawierać XMP metadata. Wygląda jednak na to, że ImageIO nie działa z XMP.
Może możesz spróbować użyć ImageMagic lub libexif.

Przydatne linki:
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

Dobrze wiedzieć. Najwyraźniej iOS nie może odczytać metadanych PNG z plików przy użyciu mojej metody. Gdybym miał sposób na odczytanie metadanych PNG, mógłbym mieć rozwiązanie. Biorąc pod uwagę, że iOS ma stałe takie jak kCGImagePropertyPNGDescription, wolałbym nie używać zewnętrznych bibliotek i wolałbym wiedzieć, jak to zrobić tylko z bibliotekami iOS. –

+0

Wyobraź sobie, że jesteś w stanie dodać metadane do obrazu, czy na pewno inne oprogramowanie odczyta te informacje? Z jakiego powodu chcesz dodać metadane? –

+0

znalazłeś odpowiedź? – Crashalot

Powiązane problemy