2013-03-04 34 views
12

Ứng dụng của tôi sẽ có thể viết các mục tùy chỉnh siêu dữ liệu để hình ảnh PNG để xuất khẩu sang UIPasteboard.Làm thế nào để viết tùy chỉnh siêu dữ liệu để hình ảnh PNG trong iOS

Bằng việc vẽ bài viết cùng đa dạng về đề tài này, tôi đã có thể đưa ra các lớp đưa ra dưới đây như là nguồn.

Triggering phương pháp copyPressed với một nút, tôi có thể thiết lập siêu dữ liệu tùy chỉnh với hình ảnh 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; 
    }; 
} 

Mặc dù tôi có thể đọc metadata PNG tốt, tôi có thể' t dường như viết thư cho nó:

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

Tuy nhiên, không có gì trong tài liệu gợi ý này nên thất bại và sự hiện diện của nhiều PNG-specific metadata constants gợi ý nó nên thành công.

Ứng dụng của tôi nên sử dụng PNG để tránh JPG's lossy compression.

Tại sao tôi không thể thiết lập siêu dữ liệu tùy chỉnh trên một trong bộ nhớ PNG hình ảnh trong iOS?

Lưu ý: Tôi đã xem this SO question nhưng không giải quyết được sự cố ở đây, đó là cách ghi siêu dữ liệu vào hình ảnh PNG cụ thể.

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 

Trả lời

4

Nếu bạn sẽ cố gắng để lưu hình ảnh của bạn với siêu dữ liệu sửa đổi

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

Và hơn xem nó thuộc tính trong Finder. Bạn sẽ thấy rằng trường kCGImagePropertyPNGDescription đã được thiết lập thành công.

enter image description here

Nhưng nếu bạn sẽ cố gắng đọc siêu dữ liệu của tập tin mới này, kCGImagePropertyPNGDescription sẽ bị mất.

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

Sau một số nghiên cứu tôi thấy rằng PNG không chứa siêu dữ liệu. Nhưng nó có thể chứa XMP metadata. Tuy nhiên, có vẻ như ImageIO không hoạt động với XMP.
lẽ bạn có thể cố gắng sử dụng ImageMagic hoặc libexif.

Liên kết hữu ích:
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

Thông tin cần biết. Rõ ràng iOS không thể đọc siêu dữ liệu PNG từ các tệp bằng phương thức của tôi. Nếu tôi đã có một cách để đọc siêu dữ liệu PNG, tôi có thể có một giải pháp. Với iOS có hằng số như kCGImagePropertyPNGDescription, tôi không muốn sử dụng thư viện bên ngoài và thà biết làm thế nào để thực sự làm được điều này chỉ với iOS libs. –

+0

Hãy tưởng tượng rằng bạn có thể thêm siêu dữ liệu vào hình ảnh, bạn có chắc chắn rằng phần mềm khác sẽ đọc thông tin này không? Vì lý do nào bạn muốn thêm siêu dữ liệu? –

+0

bạn có tìm thấy câu trả lời không? – Crashalot