Get "Timestamp"from image - objective-c

I just wondered whether there is a way of getting a timestamp of a picture, or if that info even gets written to an image file, in example from when it was taken.
Thanks in advance

Import the imageIO framework and try with an image with a timestamp. Here is one, add it to your project.
#import <ImageIO/ImageIO.h>
NSString *path = [[NSBundle mainBundle] pathForResource:#"gg_gps" ofType:#"jpg"];
NSURL *imageFileURL = [NSURL fileURLWithPath:path];
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)CFBridgingRetain(imageFileURL), NULL);
// or you can get your imageSource this other way:
// NSData *data = [NSData dataWithContentsOfFile:path];
// CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], (NSString *)kCGImageSourceShouldCache, nil];
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (CFDictionaryRef)CFBridgingRetain(options));
CFDictionaryRef exifDic = CFDictionaryGetValue(imageProperties, kCGImagePropertyExifDictionary);
if (exifDic){
NSString *timestamp = (NSString *)CFBridgingRelease(CFDictionaryGetValue(exifDic, kCGImagePropertyExifDateTimeOriginal));
if (timestamp){
NSLog(#"timestamp: %#", timestamp);
} else {
NSLog(#"timestamp not found in the exif dic %#", exifDic);
}
} else {
NSLog(#"exifDic nil for imageProperties %#",imageProperties);
}
CFRelease(imageProperties);

Related

Xcode desktop directory and writeToFile: always with different name COCOA APPLICATION

I am creating a application that screenshot the mac desktop...
But I am having 2 problems:
what is the "global" directory of desktop?
In my computer is /Users/miguelcosta/Desktop/ but i want a directory that works for all macs..
My second problem is:
When you screenshot he creates a image on your desktop with the name Result.jpg. However when you take another screenshot he replace the previous screenshot... So I was thinking how can I save this images always with a different name...
Here is my code:
NSString *targetPath =#"/Users/miguelcosta/Desktop/Result.jpg";
NSData *imageData = [newImage TIFFRepresentation];
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
[imageData writeToFile:targetPath atomically:NO];
Thanks for your help!
Here is a code snippet... Refer also to this topic: Getting desktop path for current user on OS X
#import "ViewController.h"
#interface ViewController()
{
NSInteger _count;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_count = 1;
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES );
NSString* desktopPath = [paths objectAtIndex:0];
NSString *fileName = #"Result.jpg";
NSString *filePath = [NSString stringWithFormat:#"%#/%#", desktopPath, fileName];
filePath = [self filePathWithPath:filePath];
// write to file now using filePath ...
}
// generate new name ...
- (NSString*)filePathWithPath:(NSString*)filePath
{
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSArray *parts = [[filePath lastPathComponent] componentsSeparatedByString:#"."];
NSString *name = parts[0];
NSString *ext = parts[1];
filePath = [self filePathWithPath:[NSString stringWithFormat:#"%#/%#%ld.%#", filePath, name, _count++, ext]];
}
return filePath;
}
#end

Loading image from url ios 8 objective c

i´m trying to obtain the imagen from this url[#"file:///var/mobile/Media/DCIM/100APPLE/IMG_0158.JPG"], but i can´t.
Always is nil.
this is my code:
NSData *data = [NSData dataWithContentsOfURL: #"file:///var/mobile/Media/DCIM/100APPLE/IMG_0158.JPG"];
UIImage *image = [UIImage imageWithData:data];
self.pruebaTmp.image = image;
i obtain the url with this code:
if (asset) {
// get photo info from this asset
PHImageRequestOptions * imageRequestOptions = [[PHImageRequestOptions alloc] init];
imageRequestOptions.synchronous = YES;
[[PHImageManager defaultManager]
requestImageDataForAsset:asset
options:imageRequestOptions
resultHandler:^(NSData *imageData, NSString *dataUTI,
UIImageOrientation orientation,
NSDictionary *info)
{
NSURL *path = [info objectForKey:#"PHImageFileURLKey"];
//asignamos el path de la imágen seleccionada en galeria
self.pathImagen = path;
}];
}
if someone could help i would be very grateful, because i can´t load the image with the url obtained.
you can`t not get UIimage or metadata from that url.
you can get UIImage from local Identifier of access
PHFetchResult *savedAssets = [PHAsset fetchAssetsWithLocalIdentifiers:#[localIdentifier] options:nil];
[savedAssets enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
//this gets called for every asset from its localIdentifier you saved
//PHImageRequestOptionsDeliveryModeHighQualityFormat
PHImageRequestOptions * imageRequestOptions = [[PHImageRequestOptions alloc] init];
imageRequestOptions.synchronous = NO;
imageRequestOptions.deliveryMode = PHImageRequestOptionsResizeModeFast;
imageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
[[PHImageManager defaultManager]requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:imageRequestOptions resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
NSLog(#"get image from result");
if (result) {
}
}];
imageRequestOptions = nil;
}];

How to trim Music Library file and save it document directry

-(BOOL)trimAudioFileAtPath:(NSString *)inputFilename
start:(float)start
end:(float) stop{
NSString *outputFilename = #"File Path";
NSError *error = nil; NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:outputFilename]) {
if (![fileManager removeItemAtPath:outputFilename error:&error]) {
DebugLog(#"error file remove:%#",error); } else {
DebugLog(#"sucess remove file");
} }
NSURL *audioFileInput = [NSURL fileURLWithPath:inputFilename];
NSURL *audioFileOutput = [NSURL fileURLWithPath:outputFilename];
if (!audioFileInput || !audioFileOutput){ return NO; }
[[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
AVMutableComposition *mutableComposition = [AVMutableComposition composition]; // Create the video composition track.
AVMutableCompositionTrack *mutableCompositionAudioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSLog(#"audioFileInput %#",audioFileInput); AVURLAsset *assetUrl = [AVURLAsset assetWithURL:audioFileInput];
if ([[assetUrl tracksWithMediaType:AVMediaTypeAudio] count]==0) { return NO; }
// Get the first music track from each asset. AVAssetTrack *audioAssetTrack = [[assetUrl tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; [mutableCompositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,audioAssetTrack.timeRange.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];
// we need the audio asset to be at least 50 seconds long for this snippet
CMTime startTime = CMTimeMake(start, 1);
CMTime stopTime = CMTimeMake(stop, 1);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime,stopTime);
Float64 duration = CMTimeGetSeconds(exportTimeRange.duration);
// Create the export session with the composition and set the preset to the highest quality.
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetAppleM4A];
if (duration > 6.0){
AVMutableAudioMix *mutableAudioMix = [AVMutableAudioMix audioMix];
// Create the audio mix input parameters object.
AVMutableAudioMixInputParameters *mixParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:mutableCompositionAudioTrack];
// float totalDutaion=mutableComposition.duration.value;
float totalDutaion=duration;
float lenth=totalDutaion/3;
CMTime startCM = CMTimeMake(totalDutaion-lenth-1,mutableComposition.duration.timescale);
CMTime endCM = CMTimeMake(lenth, mutableComposition.duration.timescale);
// Set the volume ramp to slowly fade the audio out over the duration of the composition.
[mixParameters setVolumeRampFromStartVolume:0.f toEndVolume:1.f timeRange:CMTimeRangeMake(startTime, endCM)];
[mixParameters setVolumeRampFromStartVolume:1.f toEndVolume:0.f timeRange:CMTimeRangeMake(startCM,endCM)];
// Attach the input parameters to the audio mix.
mutableAudioMix.inputParameters = #[mixParameters];
exportSession.audioMix=mutableAudioMix; }
if (exportSession == nil){
return NO; }
exportSession.outputURL = audioFileOutput; exportSession.outputFileType = AVFileTypeAppleM4A; exportSession.timeRange = exportTimeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^ {
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
// It worked!
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
// It failed...
} }]; return YES; }
I am using this function to trim the music file from music libaray. The Above code is working file when I try to trim a file which is located in bundle. But When I try to use the same function with input file from iTune music Library it is give no Tracks i.e. if ([[assetUrl tracksWithMediaType:AVMediaTypeAudio] count]==0) {
return NO;
} return No. Can anyone help to trim music from iTunes Libaray
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection
{
if (mediaItemCollection) {
NSLog(#"%#",[mediaItemCollection items]);
// [musicPlayer setQueueWithItemCollection: mediaItemCollection];
// [musicPlayer play];
}
[KVNProgress showWithStatus:#"Processing"];
MPMediaItem *item =mediaItemCollection.representativeItem;
NSURL* assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
// set up an AVAssetReader to read from the iPod Library
AVURLAsset *songAsset =
[AVURLAsset URLAssetWithURL:assetURL options:nil];
NSError *assetError = nil;
AVAssetReader *assetReader =[AVAssetReader assetReaderWithAsset:songAsset error:&assetError];
if (assetError) {
NSLog (#"error: %#", assetError);
return;
}
AVAssetReaderOutput *assetReaderOutput =[AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
audioSettings: nil];
if (! [assetReader canAddOutput: assetReaderOutput]) {
NSLog (#"can't add reader output... die!");
return;
}
[assetReader addOutput: assetReaderOutput];
// NSArray *dirs = NSSearchPathForDirectoriesInDomains
// (NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *documentsDirectoryPath = [dirs objectAtIndex:0];
// NSString *exportPath = [documentsDirectoryPath stringByAppendingPathComponent:#"out.m4a"];
NSString * exportPath =[NSString stringWithFormat:#"%#%#", NSTemporaryDirectory(), #"out.m4a"];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
[[NSFileManager defaultManager] removeItemAtPath:exportPath
error:nil];
}
NSURL *exportURL = [NSURL fileURLWithPath:exportPath];
AVAssetWriter *assetWriter =[AVAssetWriter assetWriterWithURL:exportURL
fileType:AVFileTypeCoreAudioFormat
error:&assetError];
if (assetError) {
NSLog (#"error: %#", assetError);
return;
}
AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
NSDictionary *outputSettings =[NSDictionary dictionaryWithObjectsAndKeys:
#(kAudioFormatLinearPCM), AVFormatIDKey,
#44100.0, AVSampleRateKey,
#2, AVNumberOfChannelsKey,
[NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)],AVChannelLayoutKey,
#16, AVLinearPCMBitDepthKey,
#NO, AVLinearPCMIsNonInterleaved,
#NO,AVLinearPCMIsFloatKey,
#NO, AVLinearPCMIsBigEndianKey,
nil];
AVAssetWriterInput *assetWriterInput =[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:outputSettings];
if ([assetWriter canAddInput:assetWriterInput]) {
[assetWriter addInput:assetWriterInput];
} else {
NSLog (#"can't add asset writer input... die!");
return;
}
assetWriterInput.expectsMediaDataInRealTime = NO;
[assetWriter startWriting];
[assetReader startReading];
AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
[assetWriter startSessionAtSourceTime: startTime];
__block UInt64 convertedByteCount = 0;
dispatch_queue_t mediaInputQueue =
dispatch_queue_create("mediaInputQueue", NULL);
[assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue
usingBlock: ^
{
while (assetWriterInput.readyForMoreMediaData) {
CMSampleBufferRef nextBuffer =
[assetReaderOutput copyNextSampleBuffer];
if (nextBuffer) {
// append buffer
[assetWriterInput appendSampleBuffer: nextBuffer];
// update ui
convertedByteCount +=
CMSampleBufferGetTotalSampleSize (nextBuffer);
} else {
// done!
[assetWriterInput markAsFinished];
[assetWriter finishWritingWithCompletionHandler:^{
[assetReader cancelReading];
[self performSelectorOnMainThread:#selector(updateCompletedAtMusicPath:)
withObject:exportPath
waitUntilDone:NO];
// NSLog (#"done. file size is %llu",[outputFileAttributes fileSize]);
}];
break;
}}}];
[self dismissViewControllerAnimated:NO completion:^{
}];
}
This is code used for geting the URL form iTune Library and story in document directry
First i just want to point out that you can just read segments of the audio from the library by setting the timeRange property of your assetReader. This way instead of copying over the whole file first you can just copy the segments you need. That being said, if you are going to stick with your original implementation, i think you just need to change AVURLAsset *assetUrl = [AVURLAsset assetWithURL:audioFileInput]; to AVURLAsset *assetUrl = [[AVURLAsset URLAssetWithURL:audioFileInput options:nil];
I Got sucess to save itune music in document libray by using following Method
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
self.fullPathToFileForAudio = [documentsDirectory stringByAppendingPathComponent:#"auto-old.m4a"];
NSFileManager *fileMgr = [NSFileManager defaultManager];
// get rid of existing mp4 if exists...
if ([fileMgr removeItemAtPath:self.fullPathToFileForAudio error:&error] != YES)
NSLog(#"Unable to delete file: %#", [error localizedDescription]);
[self convertVideoToLowQuailtyWithInputURL:self.musicUrl outputURL:[NSURL fileURLWithPath:self.fullPathToFileForAudio] handler:^(AVAssetExportSession *exportSession)
{
if (exportSession.status == AVAssetExportSessionStatusCompleted)
{
NSLog(#"completed %#",exportSession.error);
printf("completed\n");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"%# PATH",self.fullPathToFileForAudio);
[self exporterCompleted:[NSURL fileURLWithPath:self.fullPathToFileForAudio]];
});
}
else
{
// NSLog(#"%#",exportSession.error);
printf("error\n");
dispatch_sync(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
}
}];
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL
outputURL:(NSURL*)outputURL
handler:(void (^)(AVAssetExportSession*))handler
{
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetAppleM4A];
CMTime startTime = CMTimeMake(minValue, 1);
CMTime stopTime = CMTimeMake(maxValue, 1);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.outputURL = outputURL;
exportSession.outputFileType = #"com.apple.m4a-audio";
exportSession.timeRange = exportTimeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
handler(exportSession);
}];
}

Image not displayed on UICollectionViewCell

I am trying to get images on contacts,here i used UICollectionViewCell but in the collection view i didn't get image for the contact,i get only name and number.Here my code is
- (IBAction)ContactDisplay:(id)sender {
_addressBookController = [[ABPeoplePickerNavigationController alloc] init];
[_addressBookController setPeoplePickerDelegate:self];
[self presentViewController:_addressBookController animated:YES completion:nil];
}
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person
{
[self displayPerson:person];
}
- (void)displayPerson:(ABRecordRef)person
{
NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
kABPersonFirstNameProperty);
NSLog(#"%#",name);
NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
kABPersonPhoneProperty);
if (ABMultiValueGetCount(phoneNumbers) > 0) {
phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
} else {
phone = #"[None]";
}
NSLog(#"%#",phone);
UIImage *img ;
if (person != nil && ABPersonHasImageData(person)) {
if ((&ABPersonCopyImageDataWithFormat) != nil ) {
img= [UIImage imageWithData:(__bridge NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail)];
}
} else {
NSString *imageUrlString = #"http://www.google.co.in/intl/en_com/images/srpr/logo1w.png";
NSURL *url = [NSURL URLWithString:imageUrlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
img= [UIImage imageWithData:data];
}
NSString *string ;//
string =[NSString stringWithFormat:#"%#",img];
NSLog(#"%#",img);
self.name.text=name;
self.number.text=phone;
[self.nameArray addObject:name];
[self.imageArray addObject:string];
NSLog(#"%#",self.nameArray);
NSLog(#"%#",self.imageArray);
[self.collectionView reloadData];
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:nil];
}
finally an image array i got like this
(
"add-button.png",
"<UIImage: 0x17e56c80>, {148, 148}"
)
On image array every image like display .PNG format it will display fine ,then how can modify it.
Can you please suggest me how can you solve this,thank you.
I don't fully agree with everything you're doing there but I think you're getting your data wrong. Try using this instead when you're fetching the ABPerson image data.
if (person != nil) {
CFDataRef imageData = ABPersonCopyImageData(person);
NSData *data = CFBridgingRelease(imageData);
if (data != nil && data.length > 10){ //arbitrary length to make sure our data object isnt' really empty
img = [UIImage imageWithData:data];
} else {
NSString *imageUrlString = #"http://www.google.co.in/intl/en_com/images/srpr/logo1w.png";
NSURL *url = [NSURL URLWithString:imageUrlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
img= [UIImage imageWithData:data];
}
Then don't store your images as Strings in your array. Store them either as NSData or UIImage, but NOT STRINGS.
so
[myArray addObject:img]; //not the string.
And when you fetch it later, make sure you treat is as an image and not as a string
on your storyboard, select the image and look at the properties panel.
there are "Installed" options at the bottom. check the topmost "Installed" box.
I think there might be issue with conversion of image to string
NSString *string ;//
string =[NSString stringWithFormat:#"%#",img];
Add image to image array without converting to string
[self.imageArray addObject:img];
I do it like this in my app. Assuming 'person' is an ABRecordRef.
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
initWithObjects:#[#"", #"", #"", #""]
forKeys:#[#"firstName", #"lastName", #"birthday", #"picture"]];
CFTypeRef generalCFObject;
// Firtname
generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"firstName"];
CFRelease(generalCFObject);
}
// Lastname
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"lastName"];
CFRelease(generalCFObject);
}
// Birthday
generalCFObject = ABRecordCopyValue(person, kABPersonBirthdayProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"birthday"];
NSLog(#"Date : %#", [contactInfoDict objectForKey:#"birthday"]);
CFRelease(generalCFObject);
}
// User image
CFDataRef photo = ABPersonCopyImageData(person);
if (photo) {
CFRelease(photo);
UIImage *image = [UIImage imageWithData:(__bridge NSData*)photo];
[contactInfoDict setObject:image forKey:#"picture"];
}

iOS AVFoundation: How do I fetch artwork from an mp3 file?

My code:
- (void)metadata {
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:self.fileURL options:nil];
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtwork keySpace:AVMetadataKeySpaceCommon];
NSArray *titles = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
NSArray *artists = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtist keySpace:AVMetadataKeySpaceCommon];
NSArray *albumNames = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyAlbumName keySpace:AVMetadataKeySpaceCommon];
AVMetadataItem *artwork = [artworks objectAtIndex:0];
AVMetadataItem *title = [titles objectAtIndex:0];
AVMetadataItem *artist = [artists objectAtIndex:0];
AVMetadataItem *albumName = [albumNames objectAtIndex:0];
if ([artwork.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSDictionary *dictionary = [artwork.value copyWithZone:nil];
self.currentSongArtwork = [UIImage imageWithData:[dictionary objectForKey:#"data"]];
}
else if ([artwork.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
self.currentSongArtwork = [UIImage imageWithData:[artwork.value copyWithZone:nil]];
}
self.currentSongTitle = [title.value copyWithZone:nil];
self.currentSongArtist = [artist.value copyWithZone:nil];
self.currentSongAlbumName = [albumName.value copyWithZone:nil];
self.currentSongDuration = self.audioPlayer.duration;
}
This works for fetching artwork from m4a files, but doesn’t work for mp3 files. If the asset points to an mp3 file, artworks is empty. What am I doing wrong and how do I fix it?
I found that the artworks were being loaded asynchronously while the image was being set synchronously. I solved it this way:
- (void)metadata {
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:self.fileURL options:nil];
NSArray *titles = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
NSArray *artists = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtist keySpace:AVMetadataKeySpaceCommon];
NSArray *albumNames = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyAlbumName keySpace:AVMetadataKeySpaceCommon];
AVMetadataItem *title = [titles objectAtIndex:0];
AVMetadataItem *artist = [artists objectAtIndex:0];
AVMetadataItem *albumName = [albumNames objectAtIndex:0];
NSArray *keys = [NSArray arrayWithObjects:#"commonMetadata", nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
withKey:AVMetadataCommonKeyArtwork
keySpace:AVMetadataKeySpaceCommon];
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSDictionary *d = [item.value copyWithZone:nil];
self.currentSongArtwork = [UIImage imageWithData:[d objectForKey:#"data"]];
} else if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
self.currentSongArtwork = [UIImage imageWithData:[item.value copyWithZone:nil]];
}
}
}];
self.currentSongTitle = [title.value copyWithZone:nil];
self.currentSongArtist = [artist.value copyWithZone:nil];
self.currentSongAlbumName = [albumName.value copyWithZone:nil];
self.currentSongDuration = self.audioPlayer.duration;
}
I just found the answer to that here: How can I extract metadata from mp3 file in ios development and was now looking to see why that code doesn't work on an m4a file.
I took a little bit from your code and present the following which seems to work for both m4a and mp3. Note that I left the code which works for mp3 as an open else clause without the qualifier - if anybody gains more experience with this they are welcome to refine!
- (void)getMetaDataForSong:(MusicItem *)musicItem {
AVAsset *assest;
// filePath looks something like this: /var/mobile/Applications/741647B1-1341-4203-8CFA-9D0C555D670A/Library/Caches/All Summer Long.m4a
NSURL *fileURL = [NSURL fileURLWithPath:musicItem.filePath];
NSLog(#"%#", fileURL);
assest = [AVURLAsset URLAssetWithURL:fileURL options:nil];
NSLog(#"%#", assest);
for (NSString *format in [assest availableMetadataFormats]) {
for (AVMetadataItem *item in [assest metadataForFormat:format]) {
if ([[item commonKey] isEqualToString:#"title"]) {
musicItem.strSongTitle = (NSString *)[item value];
}
if ([[item commonKey] isEqualToString:#"artist"]) {
musicItem.strArtistName = (NSString *)[item value];
}
if ([[item commonKey] isEqualToString:#"albumName"]) {
musicItem.strAlbumName = (NSString *)[item value];
}
if ([[item commonKey] isEqualToString:#"artwork"]) {
UIImage *img = nil;
if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
img = [UIImage imageWithData:[item.value copyWithZone:nil]];
}
else { // if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSData *data = [(NSDictionary *)[item value] objectForKey:#"data"];
img = [UIImage imageWithData:data] ;
}
musicItem.imgArtwork = img;
}
}
}
}
As Ryan Heitner pointed out in a comment to Andy Weinstein, the way to retrieve the binary artwork data from the AVMetadataKeySpaceID3 has changed somewhere from IOS7 to IOS8. Casting blindly item to NSDictionary will crash in the ID3 case nowadays. To make code bullet proof just check dataValue, otherwise the Classes. In fact today item.value points to item.dataValue and has the NSData class.
- (UIImage*)imageFromItem:(AVMetadataItem*)item
{
NSData* data=nil;
if (item.dataValue!=nil) {
data=item.dataValue;
} else if ([item.value isKindOfClass:NSData.class]) { //never arrive here nowadays
data=(NSData*)item.value;
} else if ([item.value isKindOfClass:NSDictionary.class]) { //never arrive here nowadays...
NSDictionary* dict=(NSDictionary*)item.value;
data=dict[#"data"];
}
if (data==nil) {
return nil;
}
return [UIImage imageWithData:data];
}