can anyone tell me how to extract images from a video? what i ve tried till now is i ve follow these:
Getting iPhone video thumbnails
Getting a thumbnail from a video url or data in iPhone SDK
How do I extract a screenshot from a video in the iPhone SDK?
iPhone Read UIimage (frames) from video with AVFoundation , iphone sdk > 3.0 . Video Thumbnail?
etc. and after that i ve done this:
Source Code:
- (void)viewDidLoad
{
videoPicker = [[UIImagePickerController alloc] init];
[videoPicker setDelegate:self];
videoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
NSArray *mediaTypesAllowed = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
videoPicker.mediaTypes = mediaTypesAllowed;
videoPicker.view.hidden = YES;
}
-(IBAction)imgPickerController
{
[self presentModalViewController:videoPicker animated:YES];
videoPicker.view.hidden = NO;
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// e.g.
NSString *tempFilePath = [(NSURL *)[info valueForKey:UIImagePickerControllerMediaURL] absoluteString];
NSLog(#"didFinishPickingMediaWithInfo: %#",tempFilePath);
// e.g. /private/var/mobile/Applications/D1E784A4-EC1A-402B-81BF-F36D3A08A332/tmp/capture/capturedvideo.MOV
tempFilePath = [tempFilePath substringFromIndex:16];
NSLog(#"didFinishPickingMediaWithInfo: %#",tempFilePath);
NSLog(#"===Try to save video to camera roll.===");
NSLog(#"UIVideoAtPathIsCompatibleWithSavedPhotosAlbum: %#",UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(tempFilePath)? #"YES":#"NO");
// Check if the video file can be saved to camera roll.
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(tempFilePath))
{
// YES. Copy it to the camera roll.
UISaveVideoAtPathToSavedPhotosAlbum(tempFilePath, self, #selector(video:didFinishSavingWithError:contextInfo:),(__bridge_retained void *)tempFilePath );
}
[self dismissModalViewControllerAnimated:YES];
}
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(NSString *)contextInfo
{
NSLog(#"didFinishSavingWithError--videoPath in camera roll:%#",videoPath);
NSLog(#"didFinishSavingWithError--videoPath in temp directory:%#",contextInfo);
// The thumbnail jpg should located in this directory.
NSString *thumbnailDirectory = [[contextInfo stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
// Debug info. list all files in the directory of the video file.
// e.g. /private/var/mobile/Applications/D1E784A4-EC1A-402B-81BF-F36D3A08A332/tmp/capture
NSLog(#"%#",[contextInfo stringByDeletingLastPathComponent]);
NSLog(#"%#",[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[contextInfo stringByDeletingLastPathComponent] error:nil] description]);
// Debug info. list all files in the parent directory of the video file, i.e. the "~/tmp" directory.
// e.g. /private/var/mobile/Applications/D1E784A4-EC1A-402B-81BF-F36D3A08A332/tmp
NSLog(#"%#",thumbnailDirectory);
NSLog(#"%#",[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:thumbnailDirectory error:nil] description]);
///////////////////
// Find the thumbnail for the video just recorded.
NSString *file,*latestFile;
NSDate *latestDate = [NSDate distantPast];
NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:[[contextInfo stringByDeletingLastPathComponent]stringByDeletingLastPathComponent]];
// Enumerate all files in the ~/tmp directory
while (file = [dirEnum nextObject])
{
// Only check files with jpg extension.
if ([[file pathExtension] isEqualToString: #"jpg"])
{
NSLog(#"***latestDate:%#",latestDate);
NSLog(#"***file name:%#",file);
NSLog(#"***NSFileSize:%#", [[dirEnum fileAttributes] valueForKey:#"NSFileSize"]);
NSLog(#"***NSFileModificationDate:%#", [[dirEnum fileAttributes] valueForKey:#"NSFileModificationDate"]);
// Check if current jpg file is the latest one.
if ([(NSDate *)[[dirEnum fileAttributes] valueForKey:#"NSFileModificationDate"] compare:latestDate] == NSOrderedDescending)
{
latestDate = [[dirEnum fileAttributes] valueForKey:#"NSFileModificationDate"];
latestFile = file;
NSLog(#"***latestFile changed:%#",latestFile);
}
}
}
// The thumbnail path.
latestFile = [NSTemporaryDirectory() stringByAppendingPathComponent:latestFile];
NSLog(#"****** The thumbnail file should be this one:%#",latestFile);
UIImage *img = [[UIImage alloc] initWithContentsOfFile:latestFile];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(150, 150, 100, 100)];
[imgView setImage:img];
imgView.layer.borderWidth = 2.0;
[self.view addSubview:imgView];
// Your code ...
// Your code ...
// Your code ...
}
After doing all this still i dint reached where i want to reach.i dint get images still.I'm stuck now.Pls anyone help me out!!!Thanks :)
Simple way to extract thumbnails from a movie is to use MPMoviePlayerController class and its - thumbnailImageAtTime:timeOption: method.
For example you've got a filepath url:
NSURL *tempFilePathURL = ...;
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL: tempFilePathURL];
UIImage *thumbnail = [player thumbnailImageAtTime:THUMBNAIL_TIME timeOption:MPMovieTimeOptionExact];
[player release];
I used it in my code and it worked.
thumbnailImageAtTime:timeOption is depricated since iOS 7.0.
Here is an alternative
+ (UIImage *)extractFirstFrameFromFilepath:(NSString *)filepath
{
AVURLAsset *movieAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:filepath] options:nil];
AVAssetImageGenerator *assetImageGemerator = [[AVAssetImageGenerator alloc] initWithAsset:movieAsset];
assetImageGemerator.appliesPreferredTrackTransform = YES;
CGImageRef frameRef = [assetImageGemerator copyCGImageAtTime:CMTimeMake(1, 2) actualTime:nil error:nil];
return [[UIImage alloc] initWithCGImage:frameRef];
}
Swift Version
func getThumbOfVideo(fileURL: URL) -> UIImage? {
let movieAsset = AVURLAsset(url: fileURL)
let assetImageGenerator = AVAssetImageGenerator(asset: movieAsset)
assetImageGenerator.appliesPreferredTrackTransform = true
var thumbnail: UIImage?
do {
let cgImage = try assetImageGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1000), actualTime: nil)
thumbnail = UIImage(cgImage: cgImage)
} catch {
print(error)
}
return thumbnail
}
If you need thumbnail array throughout the video then use the following API of AVAssetImageGenerator class
func generateCGImagesAsynchronously(forTimes requestedTimes: [NSValue],
completionHandler handler: #escaping AVAssetImageGeneratorCompletionHandler)
For required thumbnail image resolution set the following property
assetImageGenerator.maximumSize
Related
I am trying to play a video in a loop on a AVSampleBufferDisplayLayer. I can get it to play though once with no problem. But, when I try to loop it, it doesn't keep playing.
Per the answer to AVFoundation to reproduce a video loop there isn't a way to rewind the AVAssetReader so I re-create it. (I did see the answer for Looping a video with AVFoundation AVPlayer? but AVPlayer is more full-features. I am reading for a file, but want the AVSampleBufferDisplayLayer still.)
One hypothesis is that I need to stop some of the H264 headers, but I have no idea if that'll help (and how). Another is that it has something to do with the CMTimebase, but I've tried several things to no avail.
Code below, based on Apple's WWDC talk on Direct Access to Video Encoding:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"sample-mp4" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
UIView *view = self.view;
self.videoLayer = [[AVSampleBufferDisplayLayer alloc] init];
self.videoLayer.bounds = view.bounds;
self.videoLayer.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds));
self.videoLayer.videoGravity = AVLayerVideoGravityResizeAspect;
self.videoLayer.backgroundColor = [[UIColor greenColor] CGColor];
CMTimebaseRef controlTimebase;
CMTimebaseCreateWithMasterClock( CFAllocatorGetDefault(), CMClockGetHostTimeClock(), &controlTimebase );
self.videoLayer.controlTimebase = controlTimebase;
CMTimebaseSetTime(self.videoLayer.controlTimebase, CMTimeMake(5, 1));
CMTimebaseSetRate(self.videoLayer.controlTimebase, 1.0);
[[view layer] addSublayer:_videoLayer];
dispatch_queue_t assetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //??? right queue?
__block AVAssetReader *assetReaderVideo = [self createAssetReader:asset];
__block AVAssetReaderTrackOutput *outVideo = [assetReaderVideo outputs][0];
if( [assetReaderVideo startReading] )
{
[_videoLayer requestMediaDataWhenReadyOnQueue: assetQueue usingBlock: ^{
while( [_videoLayer isReadyForMoreMediaData] )
{
CMSampleBufferRef sampleVideo;
if ( ([assetReaderVideo status] == AVAssetReaderStatusReading) && ( sampleVideo = [outVideo copyNextSampleBuffer]) ) {
[_videoLayer enqueueSampleBuffer:sampleVideo];
CFRelease(sampleVideo);
CMTimeShow(CMTimebaseGetTime(_videoLayer.controlTimebase));
}
else {
[_videoLayer stopRequestingMediaData];
//CMTimebaseSetTime(_videoLayer.controlTimebase, CMTimeMake(5, 1));
//CMTimebaseSetRate(self.videoLayer.controlTimebase, 1.0);
//CMTimeShow(CMTimebaseGetTime(_videoLayer.controlTimebase));
assetReaderVideo = [self createAssetReader:asset];
outVideo = [assetReaderVideo outputs][0];
[assetReaderVideo startReading];
//sampleVideo = [outVideo copyNextSampleBuffer];
//[_videoLayer enqueueSampleBuffer:sampleVideo];
}
}
}];
}
}
-(AVAssetReader *)createAssetReader:(AVAsset*)asset {
NSError *error=nil;
AVAssetReader *assetReaderVideo = [[AVAssetReader alloc] initWithAsset:asset error:&error];
NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
AVAssetReaderTrackOutput *outVideo = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTracks[0] outputSettings:nil]; //dic];
[outVideo res]
[assetReaderVideo addOutput:outVideo];
return assetReaderVideo;
}
Thanks so much.
Try Making a loop with swift, then bridge the objective-c files with the swift files. google has many answers to bridging and looping, so just google it with swift.
I've got a gif in my documents folder I would like users of the app to be able to access and email to use on other platforms that support gif animation.
I generated the gif file using information from this post...
Create and and export an animated gif via iOS?
The gif file generated and animates correctly (opened directly from simulator's documents folder in safari)
Unfortunately when trying to move the file to the camera roll (for easy email by user) using either UIImageWriteToSavedPhotosAlbum or writeImageDataToSavedPhotosAlbum from ALAssetsLibrary the image seems to be converted to a jpg file and loses all animation.
Checked this by emailing file from camera roll and opening on different platform (the functionality I would like users to have).
I have read every post I could find and from what I've seen it seems possible to save gif files directly from a browser to camera roll and even if they do not animate there they do retain that property when opened in another program so I am hoping what I am trying to do is at least possible : )
Thank for any help, have included my gif creation and failed copying attempts below..
- (void) makeGifFile {
////////////////////
NSDictionary *fileProperties = #{
(__bridge id)kCGImagePropertyGIFDictionary: #{
(__bridge id)kCGImagePropertyGIFLoopCount: #0, // 0 means loop forever
}
};
///////////////////
NSDictionary *frameProperties = #{
(__bridge id)kCGImagePropertyGIFDictionary: #{
(__bridge id)kCGImagePropertyGIFDelayTime: #0.06f, // a float (not double!) in seconds, rounded to centiseconds in the GIF data
}
};
///////////////////////
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:#"animated.gif"];
////////////////////////
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeGIF, self.screenshotnumber, NULL);
CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties);
/////////////////////////////////
for (NSUInteger i = 1; i < self.screenshotnumber+1; i++) {
#autoreleasepool {
////
NSString *name = [NSString stringWithFormat: #"Screenshot%d", i];
NSString *pathstring = [NSString stringWithFormat: #"Documents/%#.png", name];
NSString *gifPath = [NSHomeDirectory() stringByAppendingPathComponent:pathstring];
/////
UIImage *image = [UIImage imageWithContentsOfFile:gifPath];
CGImageDestinationAddImage(destination, image.CGImage, (__bridge CFDictionaryRef)frameProperties); }
}
///////////////////////////////////////
if (!CGImageDestinationFinalize(destination)) {
NSLog(#"failed to finalize image destination");
}
CFRelease(destination);
NSLog(#"url=%#", fileURL);
//////////////////////////////
///
/// saved in documents directory
/////////////////////////////
//////////////////////////
//////
///// now move to camera roll
///////////////////////
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSString *documentDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *gifImagePath = [NSString stringWithFormat:#"%#/%#", documentDirectory, #"animated.gif"];
UIImage *gifImage = [UIImage imageWithContentsOfFile:gifImagePath];
UIImageWriteToSavedPhotosAlbum(gifImage, nil, nil, nil);
CCLOG(#"wrote to camera roll");
//////////////////////// gets saved as JPG not gif
//////// next try...
NSData *data = [NSData dataWithContentsOfFile:gifImagePath]; // Your GIF file path which you might have saved in NSDocumentDir or NSTempDir
[library writeImageDataToSavedPhotosAlbum:data metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
NSLog(#"Error Saving GIF to Photo Album: %#", error);
} else {
// TODO: success handling
NSLog(#"GIF Saved to %#", assetURL);
// success(gifImagePath);
}
}];
/////////// also gets saved as jpg
}
My methods for creating screenshots for those interested... I have lost track of the post I found this on... if anyone can provide me with the link I will give due credit here ...
Included to have all relevant functions together in case it helps anyone else :)
-(UIImage*) screenshotWithStartNode:(CCNode*)startNode
{
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize viewSize = [[CCDirector sharedDirector] viewSize];
CCRenderTexture* rtx =
[CCRenderTexture renderTextureWithWidth:viewSize.width
height:viewSize.height];
[rtx begin];
[startNode visit];
[rtx end];
return [rtx getUIImage];
}
- (void) saveScreenShotWithName: (NSString*) name
{
CCScene *scene = [[CCDirector sharedDirector] runningScene];
CCNode *n = [scene.children objectAtIndex:0];
UIImage *tempimage = [self screenshotWithStartNode:n];
NSString *pathstring = [NSString stringWithFormat: #"Documents/%#.png", name];
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:pathstring];
// Write image to PNG
[UIImagePNGRepresentation(tempimage) writeToFile:savePath atomically:YES];
}
Simple loop creates files and then another deletes files from documents directory after gif creation
Sadly this can't be solved. The reason for this is that Photos app can't (at the present) display animated GIFs and it only displays one frame from the GIF as a static image. That doesn't mean though that the gif wasn't saved properly. I haven't tried your code but everything seems Ok.
There's a way of testing this. In Messages app (for example) GIFs are being played correctly, so if you share the GIF image from Photos app via ActivityController, select Message and then send it to yourself, you should see animated GIF image in Messages app.
I am working on an iOS app and I recently implemented a imagePicker in a popover that allows a user to record photos and videos. I would like to store these in the iPad's photo roll so that the user can sync them in iTunes later. I've been able to do this successfully, but I would like to give each photo and video a unique name that contains useful information about the photo and video so I can load them later. Specifically, I would like to store the photo using a property of the class, live_trial_id, as the filename. Below is the code that I am currently using to store my photos and videos to the photo roll. I understand that I could do this with metadata for pictures, but for the videos I am lost. Thanks in advance for any help with this issue!
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
UIImage *originalImage, *editedImage, *imageToSave;
// Handle a still image capture
if( [mediaType isEqualToString:#"public.image"]){
editedImage = (UIImage *) [info objectForKey:
UIImagePickerControllerEditedImage];
originalImage = (UIImage *) [info objectForKey:
UIImagePickerControllerOriginalImage];
if (editedImage) {
imageToSave = editedImage;
} else {
imageToSave = originalImage;
}
// Get the image metadata
UIImagePickerControllerSourceType pickerType = picker.sourceType;
if(pickerType == UIImagePickerControllerSourceTypeCamera)
{
NSDictionary *imageMetadata = [info objectForKey:
UIImagePickerControllerMediaMetadata];
// Get the assets library
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteImageCompletionBlock imageWriteCompletionBlock =
^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
} else {
NSLog( #"Wrote image with metadata to Photo Library");
}
};
// Save the new image (original or edited) to the Camera Roll
[library writeImageToSavedPhotosAlbum:[imageToSave CGImage]
metadata:imageMetadata
completionBlock:imageWriteCompletionBlock];
}
}
if ([mediaType isEqualToString:#"public.movie"]) {
UIImagePickerControllerSourceType pickerType = picker.sourceType;
if(pickerType == UIImagePickerControllerSourceTypeCamera)
{
NSURL *mediaURL = [info objectForKey:UIImagePickerControllerMediaURL];
// Get the assets library
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteVideoCompletionBlock videoWriteCompletionBlock =
^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
} else {
NSLog( #"Wrote image with metadata to Photo Library");
}
};
// Save the new image (original or edited) to the Camera Roll
[library writeVideoAtPathToSavedPhotosAlbum:mediaURL
completionBlock:videoWriteCompletionBlock];
}
}
I would also like to avoid creating a custom library or custom metadata if at all possible. I really just wanted to change the filename on the way to the photo roll
I ended up answering my own question. What I wanted to do was to save to the application's documents directory instead of the photo roll. This allowed me to access the files that I had saved and also to sync them to the computer when attached later.
I am trying to save video with custom metadata relevant for my app and trying to retrieve it when the user selects that video from the library. I am not sure if I am saving the meta data right as I am not able to see anything when I try to retrieve the metadata. I am also not sure if I am retrieving the meta data correctly. I am new to iOS, any help is appreciated. I have searched many threads and developer library but could not get this to work.
I am trying to save metadata in the recordingDidFinishToOutputFileURL delegate function. Video is getting saved in the library.
NSMutableArray *metadata = [NSMutableArray array];
AVMutableMetadataItem *mi = [AVMutableMetadataItem metadataItem];
mi.key = AVMetadataCommonKeyTitle;
mi.keySpace = AVMetadataKeySpaceCommon;
mi.value = #"title";
[metadata addObject:mi];
NSLog(#"Output saving:%#",outputFileURL);
AVAsset *video = [AVAsset assetWithURL:outputFileURL];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetPassthrough];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.metadata = metadata;
exportSession.outputURL = outputFileURL;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog(#"done processing video!");
UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, self, #selector(video:didFinishSavingWithError: contextInfo:), nil);
}];
I am trying to retrieve the video in didFinishPickingMediaWithInfo delegate function to check the metadata but not able to see anything in the completionhandler function
if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
video_selected = TRUE;
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSLog(#"video has %#", videoURL.path);
AVAsset *videoAsset = [AVAsset assetWithURL:videoURL];
NSLog(#"Loading metadata...");
NSArray *keys = [[NSArray alloc] initWithObjects:#"commonMetadata", nil];
NSMutableArray *metadata = [[NSMutableArray alloc] init];
[videoAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
[metadata removeAllObjects];
for (NSString *format in [videoAsset availableMetadataFormats])
{
[metadata addObjectsFromArray:[videoAsset metadataForFormat:format]];
NSLog(#"Printing metadata-%#",metadata);
}
}];
check your errors. You're exporting to where the file already exists so it's exporting into itself which won't work. Just export to a different location
These keys work fine:
AVMetadataCommonKeyAuthor
AVMetadataCommonKeyDescription
AVMetadataCommonKeyCopyrights
MP4 files support the ISO userdata keyspace and the iTunes metadata keyspace. The above keys don't have an ISO userdata mapping, so that's why they're not working. Likewise, you can't put AVMetadataQuickTimeMetadataKey* in an MP4 file because it doesn't support that keyspace.
var metadata: [AVMetadataItem] = []
let mi = AVMutableMetadataItem()
mi.identifier = AVMetadataIdentifier.commonIdentifierDescription
mi.keySpace = .common
mi.value = "Milan Description" as (NSCopying & NSObjectProtocol)?
metadata.append(mi)
let mi1 = AVMutableMetadataItem()
mi1.identifier = AVMetadataIdentifier.commonIdentifierCopyrights
mi1.keySpace = .common
mi1.value = "Milan copy" as (NSCopying & NSObjectProtocol)?
metadata.append(mi1)
print("Output saving:\(trackObj.getTrackUrl())")
let video = AVAsset(url: trackObj.getTrackUrl())
let exportSession = AVAssetExportSession(asset: video, presetName: AVAssetExportPresetPassthrough)
exportSession?.metadata = metadata
exportSession?.outputURL = volumeBoosterViewModel.audioResultRootFolderURL.appendingPathComponent(trackObj.filePathName)
exportSession?.outputFileType = AVFileType.mp3
exportSession?.exportAsynchronously(completionHandler: {[weak self]
() -> Void in
if exportSession!.status == AVAssetExportSession.Status.completed {
// All is working fine!!
print("success")
//get metadata
let asset = AVAsset(url: Your url)
if asset.commonMetadata.count > 0 {
for item in asset.metadata {
//get metadata
print(item.value)
}
}
}
})
With this code below, I can extract metadata from an image (pre-added to my project), and render the info as text. This is exactly what I want to do. The SYMetadata is created by pointing to an image via URL. initWithAbsolutePathURL. I want to do the same thing with a UIImage or maybe the image that is being loaded to the UIImage. How do I get the URL to the image that the picker selects? Or how do I create an "asset" from this incoming image?
The documentation describes initWithAsset. Have not figured out how to use it yet though, or if this is the right way to go for my purpose. Any help greatly appreciated.
NSURL *imageURL = [[NSBundle mainBundle] URLForResource:#"someImage" withExtension:#"jpg"];
SYMetadata *metadata = [[SYMetadata alloc] initWithAbsolutePathURL:imageURL];
[textView setText:[[metadata allMetadatas] description]];
Note: I tried adding an NSURL like this imageURL = [info valueForKey:#"UIImagePickerControllerReferenceURL"];, in the "pickerDidFinish" method but the metadata is null after I add this URL to the above code.
If you are using the imagePickerController, the delegate method will give you what you need
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
if ([[info allKeys] containsObject:UIImagePickerControllerReferenceURL]){
// you will get this key if your image comes from a library
[self setMetaDataFromAssetLibrary:info];
} else if ([[info allKeys] containsObject:UIImagePickerControllerMediaMetadata]){
// if the image comes from the camera you get the metadata in it's own key
self.rawMetaData = [self metaDataFromCamera:info];
}
}
From Asset Library - bear in mind that it takes time to complete and has an asynchronous completion block, so you might want to add a completion flag to ensure you don't access the property before it has been updated.
- (void) setMetaDataFromAssetLibrary:(NSDictionary*)info
{
NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
self.rawMetaData = asset.defaultRepresentation.metadata;
}
failureBlock:^(NSError *error) {
NSLog (#"error %#",error);
}];
}
From Camera:
- (NSDictionary*)metaDataFromCamera:(NSDictionary*)info
{
NSMutableDictionary *imageMetadata = [info objectForKey:UIImagePickerControllerMediaMetadata];
return imageMetadata;
}
Here is how to get metadata from a UIImage
- (NSDictionary*)metaDataFromImage:(UIImage*)image
{
NSData *jpegData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0)];
return [self metaDataFromData:jpegData];
}
But take care - a UIImage can already stripped of much of the metadata from the original.. you will be better off getting the metadata from the NSData that was used to create the UIImage...
- (NSDictionary*)metaDataFromData:(NSData*)data
{
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
CFDictionaryRef imageMetaData = CGImageSourceCopyPropertiesAtIndex(source,0,NULL);
return (__bridge NSDictionary *)(imageMetaData);
}
If you've an ALAsset (in my sample _detailItem), you can have metadata in this way:
NSDictionary *myMetadata = [[_detailItem defaultRepresentation] metadata];