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];
Related
I'm going to show avatar image of users within a conversation. I used JSQMessageViewController, so the function below should be used to achieve this goal. However, observeeventtype seems like get out this function and not being called, and there is a nil(MyuserImage or OtheruserImage) in return. So crash will appear. So how can I get photo url of different users in firebase and then return the expected avatar image? Thank you!
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessage *message = [self.msgArray objectAtIndex:indexPath.item];
if([message.senderId isEqualToString:self.senderId]){
NSString *MyuserId = [FIRAuth auth].currentUser.uid;
__block NSString *MyuserImage;
NSLog(#"uid is : %#",MyuserId);
[[_photoRef child:#"users"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSLog(#"My key is : %#",snapshot.key);
if([snapshot.key isEqualToString:MyuserId]){
NSLog(#"snapshot value is : %#", snapshot.value);
MyuserImage = snapshot.value[#"photo"];
}
}];
NSURL *url = [NSURL URLWithString:MyuserImage];
NSData *data = [NSData dataWithContentsOfURL:url];
self.myuserImage= [[UIImage alloc] initWithData:data];
return [JSQMessagesAvatarImageFactory avatarImageWithImage:self.myuserImage diameter:15];
}
else{
NSString *OtheruserId = message.senderId;
__block NSString *OtheruserImage;
NSLog(#"other userId is: %#",OtheruserId);
[[_photoRef child:#"users"]observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSLog(#"other user's key is: %#", snapshot.key);
if([snapshot.key isEqualToString:OtheruserId]){
NSLog(#"snapshot value is: %#", snapshot.value);
OtheruserImage = snapshot.value[#"photo"];
}
}];
NSURL *url = [NSURL URLWithString:OtheruserImage];
NSData *data = [NSData dataWithContentsOfURL:url];
self.otheruserImage= [[UIImage alloc] initWithData:data];
return [JSQMessagesAvatarImageFactory avatarImageWithImage:self.otheruserImage diameter:15];
}
}
From best I can tell it looks like you need to be pulling this data from firebase before this method gets called. Something like creating a struct that matches your data structure and then being able to pull this information from your datasource which presumably would be an array of these structs you've created.
An implementation I'd also recommend exploring is to use a library like SDWebImage which will manage the async call for you and let you set a default avatar while the network request and image rendering happen. But still you will need that url fetched from your database before this method gets called.
I'm doing a pick a images from iPhone photo library or in other way from camera roll. I've done that without any problem. But I need to retrieve the picking the image name from the library. but I cant able to pick the image name from gallery. My requirement is I want to pick the image and image name from photo gallery and send the chat wall.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *image =[[UIImage alloc] init];
image =[info objectForKey:#"UIImagePickerControllerOriginalImage"];
NSURL *imagePath = [info objectForKey:#"UIImagePickerControllerReferenceURL"];
//Here I am able to get the image path like this: assets-library://asset/asset.JPG?id=9F983DBA-EC35-42B8-8773-B597CF782EDD&ext=JPG
imageName = [imagePath lastPathComponent];
NSData *imageData;
NSString *extensionOFImage =[imageName substringFromIndex:[imageName rangeOfString:#"."].location+1 ];
if ([extensionOFImage isEqualToString:#"jpg"])
{
imageData =UIImagePNGRepresentation(image);
}
else
{
imageData = UIImageJPEGRepresentation(image, 1.0);
}
int imageSize=imageData.length/1024;
NSLog(#"imageSize--->%d", imageSize);
if (imageName!=nil) {
NSLog(#"imageName--->%#",imageName);
//here the imageName is showing like this “asset.jpg”..
}
else
{
NSLog(#"no image name found");
}
}
-(void)sendMessage:(NSString *)messageTxt {
str=#"Ryan";
mesText=messageTxt;
senderImgName=[UIImage imageNamed:imageName];
//here the imageName is showing like this = asset.jpg
//but senderImgName= null.
NSString *str1=imageName;
NSLog(#"sender image name is:%#",senderImgName);
imgData=[NSData dataWithData:UIImageJPEGRepresentation(senderImgName, 0)];
finalImagePath=[imgData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSLog(#"Final image path is:%#", finalImagePath);
}
Use the Photos framework and import Photos/Photos.h
#import "Photos/Photos.h"
In your imagePickerController function add the following to get the filename of the selected image from the Photo library:
NSURL *imagePath = [editingInfo objectForKey:UIImagePickerControllerReferenceURL];
PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:#[imagePath] options:nil];
NSString *filename = [[result firstObject] filename];
NSLog(#"[filename ] %#", filename );
The result is like this: [filename ] IMG_0012.JPG
I am generating image from view using following functions
-(void)preparePhotos
{
[assetGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop)
{
if(result == nil)
{
return;
}
NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
UIImage *img = [[UIImage imageWithCGImage:[[result defaultRepresentation] fullResolutionImage]] resizedImageToSize:CGSizeMake(600, 600)];
[workingDictionary setObject:img forKey:#"UIImagePickerControllerOriginalImage"];
[appdelegate.arrImageData addObject:workingDictionary];
}];
}
But as the number of times this function is called is get increased , app get crashed. How can I optimize this function or any alternative function to get image from device gallery which will not result into crash.function call like this.
[self performSelectorInBackground:#selector(preparePhotos) withObject:nil];
If you want to fetch all the images from photo library than you should only store their Assets urls only not the images themselves. Lets say you are storing the Assets url in an array named photoAssets than you can call this method by passing just the index:
- (UIImage *)photoAtIndex:(NSUInteger)index
{
ALAsset *photoAsset = self.photoAssets[index];
ALAssetRepresentation *assetRepresentation = [photoAsset defaultRepresentation];
UIImage *fullScreenImage = [UIImage imageWithCGImage:[assetRepresentation fullScreenImage]
scale:[assetRepresentation scale]
orientation:UIImageOrientationUp];
return fullScreenImage;
}
and for more information or reference you should refer PhotoScroller and MyImagePicker
I am trying to get the image filename from the camera. I have seen many, many posts about retrieving the filename using UIImagePickerControllerReferenceURL or UIImagePickerControllerMediaURL, but that only gets you a filename similar to: //asset/asset.JPG?id=D1D715A8-6956-49FF-AF07-CE60FE93AE32&ext=JPG. I believe this is because the image is not saved yet, thus a name like img0001.jpg in not available.
Does anyone know how to get the filename? I am as suing I need to do this after UIImageWriteToSavedPhotosAlbum, but I cannot seem to figure it out.
I have seen the question asked many times, but none seem to 'really' answer it, they just always give the filename from an image chosen from the picker not from the camera.
Thanks for any help
** UPDATE:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self.popoverController dismissPopoverAnimated:true];
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage])
{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
imageView.image = image;
if (newMedia)
{
UIImageWriteToSavedPhotosAlbum(image,
self,
#selector(image:finishedSavingWithError:contextInfo:),
nil);
NSURL *refURL = [info valueForKey:UIImagePickerControllerMediaURL];
// define the block to call when we get the asset based on the url (below)
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
NSLog(#"[imageRep filename] : %#", [imageRep filename]);
};
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:refURL resultBlock:resultblock failureBlock:nil];
}
}
}
My code above, but when imageRep filename is logged it is null.
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.