Metadata lost when saving photo using PHPhotoLibrary - ios

I used to save a photo to the camera roll using ALAssetLibrary's writeImageToSavedPhotosAlbum:metadata:completionBlock, but that is now deprecated in iOS 9.0, so I switched to PHPhotoLibrary's version which looks like
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
}completionHandler:^(BOOL success, NSError *error) {
if (success){
NSLog(#"Image Saved!");
} else {
NSLog(#"Error: %#", error);
}
}];
This saves the image itself, but loses the metadata (exif ect) and I can't find any fixes of how to preserve this data when I save the photo. Any help would be appreciated. TYIA

I think the method
creationRequestForAssetFromImage:(UIImage *)image;
saves only image data. It doesn't include metadata.
If you want to save a image with metadata, you can do it by the following step.
First Save your image in temporary folder and get its path as NSURL.
Then Call the method
creationRequestForAssetFromImageAtFileURL:(NSURL *)fileURL;
with the NSURL you get in First step.

Related

Memory leak when using placeholderForCreatedAsset property in PHAssetChangeRequest

In iOS 10 I start to replace asset-library to PhotoKit to manage image picker. But there is an issue.
The specific step is that app needs system camera and user shot a photo after that the delegate method imagePickerController:didFinishPickingMediaWithInfo: will be called.
Then, here is my code:
UIImage *pickerImage = [[info objectForKey:UIImagePickerControllerOriginalImage] fixOrientation];
PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary];
__block NSString *localId;
[photoLibrary performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:pickerImage];
localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
// to get localIdentifier and reload collectionView
}
}];
line 1 that fixOrientation is a custom category that return UIImage instance.
Only call [PHAssetChangeRequest creationRequestForAssetFromImage:] method performs fine. However, when I want to fetch newly created photo to use [assetChangeRequest placeholderForCreatedAsset] , it shows memory leak and app crash.
Above all, any solution to fetch created photo just moment or other methods to solve that by using Photos Framework?

In PHPhotoLibrary, how to know whether video file can save on iPhone or not

I'm changing over from ALAssetsLibrary to PHPhotoLibrary and want to know whether or not video file can save or not.
In ALAssetsLibray, you know, we could know it before start saving video file with the API
- (BOOL)videoAtPathIsCompatibleWithSavedPhotosAlbum:(NSURL *)videoPathURL;
Does anyone knows the substitute API for videoAtPathIsCompatibleWIthSavedPhotoAlbum in PHPhotoLibrary ?
Or do you know the exact error code which means that a video file cannot save on the iOS device ?
My code for saving video file is like below,
- (void)saveVideoFile:(NSURL *)videoURL completion:(savePhotoFileCompletion)completion
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest;
assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:videoURL];
PHAssetCollectionChangeRequest *assetCollectionChangeRequest =
[PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
[assetCollectionChangeRequest addAssets:#[ [assetChangeRequest placeholderForCreatedAsset] ]];
}
completionHandler:^(BOOL success, NSError *_Nullable error) {
DBGLog(#"success=%#, error=%#", (success ? #"YES" : #"NO"), error);
completion(success, error);
}];
}
I found the question talking about the same issue.
How to use PHPhotoLibrary like ALAssetsLibrary
But it doesn't refer to the exact answer.
I asked my question to Apple with TSI.
And their answer is to use the following API
AVAsset *avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:videoPath]];
BOOL canSaveVideo = [avAsset isCompatibleWithSavedPhotosAlbum];
It seemed that I could get the correct compatibility.
One important point it that PHPhotoLibrary can save the video even if the value of canSaveVideo is NO.
Thank you.

PHPhotoLibrary error while saving image at url

I create an image at url provided by PHContentEditingOutput. When I load data to UIImage and save it like this - it works.
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
NSData *data = [NSData dataWithContentsOfURL:contentEditingOutput.renderedContentURL]
UIImage *image = [UIImage imageWithData:data];
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:^(BOOL success, NSError *error) {
...
}];
But when I try approach with url it fails:
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:contentEditingOutput.renderedContentURL];
} completionHandler:^(BOOL success, NSError *error) {
...
}];
Error:
Error Domain=NSCocoaErrorDomain Code=-1 "The operation couldn’t be completed. (Cocoa error -1.)"
UPDATE:
The same error when I try to save a modification.
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset];
request.contentEditingOutput = contentEditingOutput;
} completionHandler:^(BOOL success, NSError *error) {
...
}];
The method works for a video (creationRequestForAssetFromVideoAtFileURL:), but not for an image. What went wrong?
The problem is in the file format. I was trying to edit PNG screenshot, but renderingContentURL was always tmp/filename.JPG. At first I thought it was a bug, but according to the documentation this is correct behaviour.
renderedContentURL
Read this property to find a URL for writing edited asset content. Then, if editing a photo asset, write the altered photo image to a file in JPEG format at this URL. If editing a video asset, export the video to a QuickTime (.mov) file at this URL.
The solution is to convert the image with function
NSData *UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality);
When passing the metadata, I also had the issue consistently showing whenever the Orientation (inside the image metadata) was anything other than CGImagePropertyOrientationUp.
This is also stated inside the renderedContentURL documentation:
Edited asset content must incorporate (or “bake in”) the intended
orientation of the asset. That is, the orientation metadata (if any)
that you write in the output image or video file must declare the “up”
orientation, and the image or video data must appear right-side up
when presented without orientation metadata.
For images, the following metadata keys need to be updated (while the image data is also rotated):
• kCGImagePropertyTIFFDictionary \ kCGImagePropertyTIFFOrientation
• kCGImagePropertyOrientation
• possibly, kCGImagePropertyIPTCImageOrientation

Setting the location property of PHAssetChangeRequest doesn't create a GPS section in image metatdata

When a picture is taken (iOS 8.1) and didFinishPickingMediaWithInfo is called, I'm trying to use PhotoKit to add the GPS data back into the metadata.
This is the code I'm using:
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *newAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
newAssetRequest.creationDate = [NSDate date];
newAssetRequest.location = [self deviceLocation];
NSLog(#"didFinishPickingMediaWithInfo: location:%#", newAssetRequest.location);
PHObjectPlaceholder *placeholderAsset = newAssetRequest.placeholderForCreatedAsset;
PHAssetCollectionChangeRequest *addAssetRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.myResults[0]];
[addAssetRequest addAssets:#[placeholderAsset]];
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"didFinishPickingMediaWithInfo: Success saving picture to album");
} else {
NSLog(#"didFinishPickingMediaWithInfo: error saving picture to album %#", error);
}
}];
[picker dismissViewControllerAnimated:YES completion:nil];
The code takes the image and moves it to an album. This part works. The photo ends up in the correct album.
The problem is the GPS data is not present in the metadata even though the location property is properly set. I know the location data is valid.
Shouldn't this work? Is there an alternate approach to get the desired result? I don't really care about all the other metadata, just the GPS coordinates.

iOS - Is it possible to rename image file name before saving it into iPhone device gallery from app?

Hey I'm new to iPhone and I have been trying to make an gallery kind of app. Basically, what I want to do is that i need to save all the captured images into a specific folder like a new album "My_App Images" related to our app name in iPhone device gallery, it's working for me, but I am having trouble to change the image file name, i don't know that Is it possible to specify a file name? Using iPhoto, currently i am getting image file name as "IMG_0094.jpg", can we change it with any other file name like "Anyfilename.png" format programmatically?
here is my code for saving images to the specific album :
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
[self.library saveImage:image toAlbum:#"My_App Images" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Image saving error: %#", [error description]);
}
}];
[picker dismissViewControllerAnimated:NO completion:nil];
}
Any source or link for reference is appreciated. Thanks for the help!
There is a way to kinda do that, by setting the image IPTC metadata field "Object Name". If you later import the image to iPhoto, then this name will be used as its title.
See details (and code) at http://ootips.org/yonat/how-to-set-the-image-name-when-saving-to-the-camera-roll/ .
Do you meant,
// Build NSData in memory from the btnImage...
NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
// Save to the default Apple (Camera Roll) folder.
[imageData writeToFile:#"/private/var/mobile/Media/DCIM/100APPLE/customImageFilename.jpg" atomically:NO];
Now adjust the path of folder as per your folder name...
Sorry to disappoint you, but it seems that you can not change the name of the photos, before or after saving, in the photo album, custom or not. Here is a post to explain it:
iOS rename/delete albums of photos
Edit
So, to clarify my comment, use the following override:
Download the NSMutableDictionary category for metadata of image here.
Also download the sample project CustomAlbumDemo from here and modify the NSMutableDictionary+ImageMetadata.m file in the CustomAlbumDemo project as:
-(void)saveImage:(UIImage*)image toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
//write the image data to the assets library (camera roll)
NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
[metadata setDescription:#"This is my special image"];
[self writeImageDataToSavedPhotosAlbum:imageData metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error) {
//error handling
if (error!=nil) {
completionBlock(error);
return;
}
//add the asset to the custom photo album
[self addAssetURL: assetURL
toAlbum:albumName
withCompletionBlock:completionBlock];
}];
}

Resources