How to edit Image metadata in iOS? - ios

I am using following code to modify the metadata of Gallery Image.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)mediaInfo
{
ALAssetsLibrary *library =nil;
void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *) = ^(ALAsset *asset)
{
NSDictionary *metadata = asset.defaultRepresentation.metadata;
NSLog(#"Image Meta Data: %#",metadata);
NSMutableDictionary* dict=[[NSMutableDictionary alloc] initWithDictionary:metadata];
[dict setValue:#"sdfdfsfsfsfdsfsf" forKey:(NSString*)kCGImagePropertyIPTCKeywords];
UIImage *anImage = [mediaInfo valueForKey:UIImagePickerControllerOriginalImage];
NSData *imageData = UIImageJPEGRepresentation(anImage, 1.0);
[asset writeModifiedImageDataToSavedPhotosAlbum:imageData metadata:dict completionBlock:^(NSURL *assetURL, NSError *error) {
}];
};
NSURL *assetURL = [mediaInfo objectForKey:UIImagePickerControllerReferenceURL];
library = [[ALAssetsLibrary alloc] init];
[library assetForURL:assetURL
resultBlock:ALAssetsLibraryAssetForURLResultBlock
failureBlock:^(NSError *error) {
}];
}
But it is not working. Please help.

Here is a minimal example to do it:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *imageToSave = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage];
/* modify metadata dict */
NSMutableDictionary *imageMetadata = [[info objectForKey: UIImagePickerControllerMediaMetadata] mutableCopy];
NSLog(#"Inspect current metadata: %#", imageMetadata);
NSDictionary *iptc = #{(id)kCGImagePropertyIPTCKeywords: #"awesome photo"};
[imageMetadata setObject:iptc forKey:(id)kCGImagePropertyIPTCDictionary];
/* Save to the Camera Roll with modified medatadata */
[[ALAssetsLibrary new] writeImageToSavedPhotosAlbum:imageToSave.CGImage
metadata:imageMetadata
completionBlock:NULL];
[self performDismiss];
}
If you use a metadata viewer (OS X's Preview is good enough) you'll see something like this:
But, as pawan suggests, use an existing library to do it more easily. Google around, there are quite a few options out there.

Related

Understanding Old ALAsset Code

I am trying to go through and clean up some deprecation warnings by updating ALAsset with PHPhoto. I am getting confused by this code and need some help to make sure I am not missing something. I added in some comments about what is confusing me.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSURL *assetsURL = [info objectForKey:UIImagePickerControllerReferenceURL];
UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
NSMutableDictionary *metadata = [NSMutableDictionary dictionary];
// This is where I am getting confused.
// What is the difference between the meta data of the else statement
// and the if statement.
if (assetsURL) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[library assetForURL:assetsURL
resultBlock:^(ALAsset *asset) {
[metadata addEntriesFromDictionary:asset.defaultRepresentation.metadata];
dispatch_semaphore_signal(sema);
}
failureBlock:^(NSError *error) {
dispatch_semaphore_signal(sema);
}];
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
} else {
[metadata addEntriesFromDictionary:[info objectForKey:UIImagePickerControllerMediaMetadata]];
}
// Undocumented method guessing it rotates image to Portrait
pickedImage = [pickedImage IN_rotateToPortraitOrientation];
[metadata setImageOrientation:UIImageOrientationUp];
if (!assetsURL) {
[library writeImageToSavedPhotosAlbum:pickedImage.CGImage
metadata:metadata
completionBlock:^(NSURL *assetURL, NSError *error) {
$l(#"Saved to photo album");
}];
}
...
}
If you could help me understand the difference in meta data. If there is a difference how could I accomplish the same thing with PHPhotos.

how can i get url after take photo

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *assetURL;
if( [picker sourceType] == UIImagePickerControllerSourceTypeCamera )
{
assetURL = [info objectForKey:UIImagePickerControllerReferenceURL]; // always return nil !!
}
else if( [picker sourceType] == UIImagePickerControllerSourceTypePhotoLibrary)
{
assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
}
how can i get assetURL when i selected UIImagePickerControllerSourceTypeCamera.
UIImagePickerControllerSourceTypePhotoLibrary is work.
When you take an image using UIImagePickerControllerSourceTypeCamera, the image is not saved into photo library automatically. You have to write it manually. After writing, you can get the URL.
Sample code:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
UIImage* cameraImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary writeImageToSavedPhotosAlbum:cameraImage.CGImage
metadata:[info objectForKey:UIImagePickerControllerMediaMetadata]
completionBlock:^(NSURL *assetURL, NSError *error) {
if (!error) {
//use assetURL as you need.
}
}];
}
}
A warning though, writing is a time consuming operation.

Get EXIF data of a particular image/photo in cameraroll

I am using ALAssetsLibrary to list details of photos present in cameraroll. But how to get details of a particular selected photo from cameraroll using ALAssetsLibrary?
Assume i selected ABC.jpeg from cameraroll. I want to display the exif details of only ABC.jpeg. Not exif details of other photos present in cameraroll.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
self.imageView.image = image;
NSLog(#"image %#\ninfo: %#",image, info);
[picker dismissViewControllerAnimated:YES completion:NULL];
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
NSDictionary *data = [[asset defaultRepresentation] metadata];
NSLog(#"%#",data);
}
}];
}
} failureBlock:^(NSError *error) {
NSLog(#"error enumerating AssetLibrary groups %#\n", error);
}];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissViewControllerAnimated:YES completion:NULL];
}
ok here is the code how to get the asset of a media picker with the image picker:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
self.imageView.image = image;
NSLog(#"media image info: %#", info);
//use assetLib
NSURL *imageURL = [info objectForKey:UIImagePickerControllerReferenceURL];
if(imageURL) {
[self getPictureInfoFromAssetURL:imageURL
success:^(NSDictionary*)alInfo {
NSLog(#"asset lib image info: %#", alInfo);
} failure:^(NSError *error) {
NSLog(#"error reading asset lib image info: %#", error);
}];
}
[picker dismissViewControllerAnimated:YES completion:NULL];
}
- (void)getPictureInfoFromAssetURL:(NSURL *)url
success:(void (^)(NSDictionary *alInfo))success
failure:(void (^)(NSError *error))failure {
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:url
resultBlock: ^(ALAsset *myasset) {
ALAssetRepresentation *rep = [myasset defaultRepresentation];
if(success {
success([rep metadata]);
}
failureBlock: ^(NSError *err) {
if (failure) {
failure(err);
}
}];
}

Saving image to Photo Library and get the URL of the saved image

I'm trying to save an image from camera to Photo Library and then store the URL of the saved image. My code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
[library writeImageToSavedPhotosAlbum:(__bridge CGImageRef)([info objectForKey:UIImagePickerControllerOriginalImage])
orientation:ALAssetOrientationUp completionBlock:^(NSURL *assetURL, NSError *error) {
if(error == nil) {
_myImageUrl = [NSString stringWithFormat:#"%#",assetURL];
NSLog(#"%#",assetURL);
} else NSLog(#"%#",error);
}];
[picker dismissViewControllerAnimated:YES completion:nil];}
My problem is that assetUrl is always NULL. Any ideas?
Thank you!
Finally, after reading more, I found out the answer: the first parameter of the function is of CGImageRef type and (__bridge CGImageRef) doesn't do what I expected; but if I call the CGImage method of UIImage object, it works. The correct way to do this is:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
CGImageRef image = [[info objectForKey:UIImagePickerControllerOriginalImage] CGImage];
[library writeImageToSavedPhotosAlbum:image
orientation:ALAssetOrientationUp
completionBlock:^(NSURL *assetURL, NSError *error) {
if(error == nil) {
_myImageUrl = [NSString stringWithFormat:#"%#",assetURL];
NSLog(#"%#",assetURL);
} else NSLog(#"%#",error);
}];
self.toDoImage.image = [info objectForKey:UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:nil];
}

How to capture still image and save with its city name with AV Foundation camera?

I capture still image and save to camera roll with AV Foundation like this:
- (void) captureStillImage
{
AVCaptureConnection *stillImageConnection =
[self.stillImageOutput.connections objectAtIndex:0];
if ([stillImageConnection isVideoOrientationSupported])
[stillImageConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
[self.stillImageOutput
captureStillImageAsynchronouslyFromConnection:stillImageConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
{
if (imageDataSampleBuffer != NULL)
{
NSData *imageData = [AVCaptureStillImageOutput
jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[library writeImageToSavedPhotosAlbum:[image CGImage]
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
}];
}
else
{
NSLog(#"Error capturing still image: %#", error);
}
}
];
}
These images from my App when check again in Photos App don't have info about city name.
How to capture still image and save with its location name which can be display in photos app?
Thanks for help!
From the Docs : captureStillImageAsynchronouslyFromConnection
handler
A block to invoke after the image has been captured. The block
parameters are as follows: imageDataSampleBuffer The data that was
captured. The buffer attachments may contain metadata appropriate to
the image data format. For example, a buffer containing JPEG data may
carry a kCGImagePropertyExifDictionary as an attachment. See
ImageIO/CGImageProperties.h for a list of keys and value types.
So using that you can get the meta data.
CFDictionaryRef metaDict = CMCopyDictionaryOfAttachments(NULL, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
CFMutableDictionaryRef mutable = CFDictionaryCreateMutableCopy(NULL, 0, metaDict);
NSDictionary *metaDict = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:self.currentLocation.coordinate.latitude], kCGImagePropertyGPSLatitude,
#"N", kCGImagePropertyGPSLatitudeRef,
[NSNumber numberWithFloat:self.currentLocation.coordinate.longitude], kCGImagePropertyGPSLongitude,
#"E", kCGImagePropertyGPSLongitudeRef,
#"04:30:51.71", kCGImagePropertyGPSTimeStamp,
nil];
NSLog(#"%#",metaDict);
CFDictionarySetValue(mutable, kCGImagePropertyGPSDictionary, (__bridge const void *)(metaDict));
and when saving to Asset Library use this method to add the meta data
[library writeImageToSavedPhotosAlbum:[image CGImage] metadata:mutable completionBlock: nil];

Resources