How to get author of image in cocoa

2019-05-07 05:05发布

问题:

I can not understand why metaDic is always null. There is a code.

    CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(img.CGImage)); //(UIImage *img)
    CGImageSourceRef mySourceRef =  CGImageSourceCreateWithData(dataRef, NULL);
    NSDictionary *metaDic = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(mySourceRef,0,NULL);
    NSDictionary *tiffDic = (NSDictionary *)[metaDic objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];
    NSString *AuthorName  =  [tiffDic objectForKey:(NSString *)kCGImagePropertyTIFFArtist];

I did some variants of getting picture. And here what I have discovered:

One way of getting picture with its info - I need to get it from site and there what I've got:

              //  NSURL *UrlPath  - path of picture    image.jpg   from web site
            NSData *dataImg = [NSData dataWithContentsOfURL:UrlPath];

            CGImageSourceRef mySource =  CGImageSourceCreateWithData((CFDataRef)dataImg, NULL); 
            NSDictionary *metaDic = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(mySource,0,NULL);
            NSDictionary *tiffDic = [metaDic objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];

            /// Log of tiffDic    
tiffDic = {
Artist =(
  "mr. Smith"
  );
}

another way - read picture from NSBoudle mainBundle:

           // NSURL *NSBundleUrl  -  - path of the same  picture    image.jpg   from [[NSBundle mainBundle] 
            CGImageSourceRef mySource = CGImageSourceCreateWithURL( (CFURLRef) NSBundleUrl, NULL);
            NSDictionary *metaDic = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(mySource,0,NULL);
            NSDictionary *tiffDic = [metaDic objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];

/// Log of tiffDic
tiffDic = {
    Artist = "mr. Smith"; 
}

why it get braces as array for name of artist when the picture data come from web site?

回答1:

Your data path looks something like this:

UIImage -> CGImage -> CGDataProvider -> CGImageSource

It's that third step that is cleansing your image of metadata. CGDataProviders are an "older" mechanism for getting data into Quartz with "limited functionality" - meaning - amongst other things - they do not support metadata.

Try something like this instead:

NSData* jpegData = UIImageJPEGRepresentation(image,1.0);
CFDataRef dataRef = (__bridge CFDataRef)jpegData;
CGImageSourceRef source = CGImageSourceCreateWithData(dataRef, NULL);

Data path:

UIImage -> NS/CFData -> CGImageSource

That will preserve the metadata.

You may not have much luck getting the authorName this way if you use the UIImage as your starting point. UIImage strips out a lot of the metadata that may accompany the original image source (the TiffDict seems to get stripped down to just the orientation tag). You really want to be reading the 'uninterpreted' data from it's source and extracting metadata without reading the image data (that is one of the benefits of using a CGImageSourceRef).

I have a little test project up on github that compares methods of extracting image metadata from various sources - filesystem, network URL, asset library, camera, maybe you should take a look.

update As Peter points out (and my project shows) - you shouldn't be using the UIImage, but the original data source. As in your case it is a filesystem source, something like this:

 NSString* path = @"/path/to/resource";
 NSData *data = [NSData dataWithContentsOfFile:path];
 CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

Or better still (as Peter points out again!) you can use CGImageSourceCreateWithURL and skip that NSData step altogether.



回答2:

The data provider of a CGImage provides raw pixels, not PNG or TIFF or other external-format data with metadata included. Consequently, there are no properties to get.

I wouldn't be surprised if that source can't even give you an image, since it has no way of knowing what pixel format to interpret the data in.

You need to create the image source with the URL or data you got the original image from, not the pixel data of that image. Ideally, you should create the image source first, and then create the image and its properties from the image source.