I want to create and save a UIImage in iOS 10. I can create it either by taking a UIView snapshot or using UIGraphicsImageRenderer (shown below).
- (UIView *)createIcon
{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(200, 200)];
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) {
[[UIColor darkGrayColor] setStroke];
[context strokeRect:renderer.format.bounds];
[[UIColor colorWithRed:158/255.0 green:215/255.0 blue:245/255.0 alpha:0.5] setFill];
[context fillRect:CGRectMake(30, 30, 140, 140)];
[[UIColor colorWithRed:243/255.0 green:122/255.0 blue:216/255.0 alpha:0.3] setFill];
CGContextFillEllipseInRect(context.CGContext, CGRectMake(30, 30, 120, 120));
}];
UIImageView *showImage = [[UIImageView alloc] initWithImage:image];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
return showImage;
}
However, when I try to save using UIImageWriteToSavedPhotosAlbum by including the second last statement, Xcode goes into Debug with the following error report
(lldb) bt
* thread #5, queue = 'com.apple.root.default-qos', stop reason = signal SIGABRT
* frame #0: 0x00000001101611a6 libsystem_kernel.dylib`__abort_with_payload + 10
frame #1: 0x000000011015b86e libsystem_kernel.dylib`abort_with_payload_wrapper_internal + 89
frame #2: 0x000000011015b89b libsystem_kernel.dylib`abort_with_payload + 9
frame #3: 0x0000000108ab3af7 TCC`__CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 182
frame #4: 0x0000000108ab3a41 TCC`__TCCAccessRequest_block_invoke.77 + 665
frame #5: 0x0000000108ab7273 TCC`__tccd_send_block_invoke + 274
So even though I didn’t use a camera to create the image, saving it to the photo album is a violation of privacy (hiss, boo)! I know it is possible to set up privacy keys in the plist but is there a more sensible alternative?
CLARIFICATION
I hope to use rendered images (or view snapshots) as assets in the app. So instead of is there a more sensible alternative ?
perhaps I should have asked
is there an alternative place to save images (i.e. as PNG or JPG files) so privacy is not an issue?
You can save any UIImage to the photo album but first you must ask the user for permission to do as this as it is indeed a privacy issue. If they don't give you access then you can't save the image at all.
The most sensible approach is to add the required privacy key to the info.plist.
This is the info.plist xml definition although it's easier to add the keys in the property list:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Message requesting the ability to add to the photo library</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Message requestion the ability to access the photo library</string>
If you add these then when you first try to access or add to the photo library a popup will display with your message allowing the user to decide if they want your app to have access.
One good reason to put it in the info.plist file is that all the requests for access are then in a single easily visible place instead of somewhere random in your project.
EDIT
Here is how to save the image in documents which does not raise and privacy issues:
NSData *imageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"image.png"]; //Add the file name
[imageData writeToFile:filePath atomically:YES]; //Write the file
If you want a jpg instead of a png use this instead:
NSData *imageData = UIImageJPEGRepresentation(image, 0.9); // Use whatever compression ratio you want instead of 0.9
Follow this code:
#import <Photos/Photos.h>
pragma mark - Save Image in photo album
- (void)addImageToCameraRoll:(UIImage *)image {
NSString *albumName = #"Your app name";
void (^saveBlock)(PHAssetCollection *assetCollection) = ^void(PHAssetCollection *assetCollection) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
[assetCollectionChangeRequest addAssets:#[[assetChangeRequest placeholderForCreatedAsset]]];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error creating asset: %#", error);
}
}];
};
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:#"localizedTitle = %#", albumName];
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:fetchOptions];
if (fetchResult.count > 0) {
saveBlock(fetchResult.firstObject);
} else {
__block PHObjectPlaceholder *albumPlaceholder;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *changeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumName];
albumPlaceholder = changeRequest.placeholderForCreatedAssetCollection;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:#[albumPlaceholder.localIdentifier] options:nil];
if (fetchResult.count > 0) {
saveBlock(fetchResult.firstObject);
}
} else {
NSLog(#"Error creating album: %#", error);
}
}];
}
}
Related
my company is having a big problem with getting correct size metadata by fetching PHAssets.
We have developed an iOS applications that lets customers choose pictures from library, get the size (in pixel) for each of them, calculate coordinates for adjusting to gadgets we sell, then upload high quality version of picture to our server to print gadgets.
For some of our customers, the problem is that the size in pixel of some of the high-quality versions of pictures sent, does not match pixelWidth and pixelHeight given by the PHAsset object.
To make an example, we have a picture that:
is reported to be 2096x3724 by PHAsset object
but, when full size image is requested, a 1536x2730 picture is generated
The picture is not in iCloud, and is sent by an iPhone 6 SE running iOS 10.2.
This is the code to get full size image version:
PHImageRequestOptions *imgOpts = [[PHImageRequestOptions alloc] init];
imgOpts.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
imgOpts.networkAccessAllowed = YES;
imgOpts.resizeMode = PHImageRequestOptionsResizeModeExact;
imgOpts.version = PHImageRequestOptionsVersionCurrent;
PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];
[imageManager requestImageForAsset:imageAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:imgOpts resultHandler:^(UIImage * result, NSDictionary * info) {
NSData * imageData = UIImageJPEGRepresentation(result, 0.92f);
//UPLOAD OF imageData TO SERVER HERE
}]
Also tried with requestImageDataForAsset method, but with no luck:
PHImageRequestOptions *imgOpts = [[PHImageRequestOptions alloc] init];
imgOpts.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
imgOpts.networkAccessAllowed = YES;
imgOpts.resizeMode = PHImageRequestOptionsResizeModeExact;
imgOpts.version = PHImageRequestOptionsVersionCurrent;
PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];
[imageManager requestImageDataForAsset:imageAsset options:imgOpts resultHandler:^(NSData * imageData, NSString * dataUTI, UIImageOrientation orientation, NSDictionary * info) {
//UPLOAD OF imageData TO SERVER HERE
}]
Getting exact size from high-resolution version of every picture, before doing upload, is not an option for us, 'cause it would degrade a lot performance when selecting a large amount of assets from the library.
Are we missing or doing something wrong?
Is there a way to get asset size in pixel without loading full-resolution image into memory?
Thanks for helping
This is due to a bug in Photos framework. Details about the bug can be found here.
Sometimes, after a photo is edited, a smaller version is created. This only occurs for some larger photos.
Calling either requestImageForAsset: (with PHImageManagerMaximumSize) or requestImageDataForAsset: (with PHImageRequestOptionsDeliveryModeHighQualityFormat) will read the data from the smaller file version, when trying to retrieve the edited version (PHImageRequestOptionsVersionCurrent).
The info in the callback of the above methods will point the path to the image. As an example:
PHImageFileURLKey = "file:///[...]DCIM/100APPLE/IMG_0006/Adjustments/IMG_0006.JPG";
Inspecting that folder, I was able to find another image, FullSizeRender.jpg - this one has the full size and contains the latest edits. Thus, one way would be to try and read from the FullSizeRender.jpg, when such a file is present.
Starting with iOS 9, it's also possible to fetch the latest edit, at highest resolution, using the PHAssetResourceManager:
// if (#available(iOS 9.0, *)) {
// check if a high quality edit is available
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:_asset];
PHAssetResource *hqResource = nil;
for (PHAssetResource *res in resources) {
if (res.type == PHAssetResourceTypeFullSizePhoto) {
// from my tests so far, this is only present for edited photos
hqResource = res;
break;
}
}
if (hqResource) {
PHAssetResourceRequestOptions *options = [[PHAssetResourceRequestOptions alloc] init];
options.networkAccessAllowed = YES;
long long fileSize = [[hqResource valueForKey:#"fileSize"] longLongValue];
NSMutableData *fullData = [[NSMutableData alloc] initWithCapacity:fileSize];
[[PHAssetResourceManager defaultManager] requestDataForAssetResource:hqResource options:options dataReceivedHandler:^(NSData * _Nonnull data) {
// append the data that we're receiving
[fullData appendData:data];
} completionHandler:^(NSError * _Nullable error) {
// handle completion, using `fullData` or `error`
// uti == hqResource.uniformTypeIdentifier
// orientation == UIImageOrientationUp
}];
}
else {
// use `requestImageDataForAsset:`, `requestImageForAsset:` or `requestDataForAssetResource:` with a different `PHAssetResource`
}
can you try this to fetch camera Roll pics:
__weak __typeof(self) weakSelf = self;
PHFetchResult<PHAssetCollection *> *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumSelfPortraits options:nil];
[albums enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull album, NSUInteger idx, BOOL * _Nonnull stop) {
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.wantsIncrementalChangeDetails = YES;
options.predicate = [NSPredicate predicateWithFormat:#"mediaType == %d",PHAssetMediaTypeImage];
options.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:album options:options];
if(assets.count>0)
{
[assets enumerateObjectsUsingBlock:^(PHAsset * _Nonnull asset, NSUInteger idx, BOOL * _Nonnull stop) {
if(asset!=nil)
{
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage *result, NSDictionary *info)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf addlocalNotificationForFilters:result];
// [weakSelf.buttonGalery setImage:result forState:UIControlStateNormal];
});
}];
*stop = YES;
}
else{
[weakSelf getlatestAferSelfie];
}
}];
}
When I take a video using UIImagePickerController and save it to SavedPhotosAlbum using
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:(NSURL *)movieURL
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
NSLog(#"Save video fail:%#",error);
} else {
NSLog(#"Save video succeed.");
[self getsavedvideo];
}}];
the saved file contains a name and creation date but not the GPS info. I am surprised by this since I am using the built in camera and the imagePicker. Why wouldn't Apple just include the GPS coordinates (even if I had to ask users permission to use location services).
anyway I digress
I have not found anyway to add the GPS coordinates to the video as it is being saved and I haven't been able to find anyway to add the this information in the completionBlock.
If someone knows how please let me know.
So I wrote a bit of code that is called after the video is saved [self getsavedvideo]; above which gets the saved video and I can get the movie name and creation date and it shows there is no location info.
-(void) getsavedvideo;{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Within the group enumeration block, filter to enumerate just photos.
[group setAssetsFilter:[ALAssetsFilter allVideos]];
// Chooses the photo at the last index
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
// The end of the enumeration is signaled by asset == nil.
if (alAsset) {
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
// Stop the enumerations
*stop = YES; *innerStop = YES;
// Do something interesting with the AV asset.
NSString *fileName = [representation filename];
NSDate *myDate = [alAsset valueForProperty:ALAssetPropertyDate];
CLLocation *location = [alAsset valueForProperty:ALAssetPropertyLocation];
NSLog(#"fileName!!!!,%#",fileName);
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:mad:"dd-MM-yyyy 'at' HH:mm"];
NSLog( #"date for this file is %# %#", [[[alAsset defaultRepresentation] url] absoluteString], [dateFormatter stringFromDate: myDate] );
NSLog (#"locate!!!!%#",location);
} }];
} failureBlock: ^(NSError *error) {
NSLog(#"No groups");}];}
so does anyone know how to append this with the GPS information and save it back to the video's metadata.
I have been wracking my brains out on this for a few days and haven't really found anything helpful.
Plz help
So I figured this out for a device running ios8 or newer anyway.
add this code in the -(void) getsavedvideo that was in the completionBlock above.
Make sure you have
import
if ([PHAsset class]) { // If this class is available, we're running iOS 8
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
fetchOptions.fetchLimit = 1;
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:fetchOptions];
PHAsset *lastImageAsset = [fetchResult lastObject];
[[PHImageManager defaultManager]requestImageForAsset:lastImageAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *result, NSDictionary *info){
if ([info objectForKey:PHImageErrorKey] == nil && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]) {
NSArray *resources = [PHAssetResource assetResourcesForAsset:lastImageAsset];
NSString *orgFilename = ((PHAssetResource*)resources[0]).originalFilename;
[lastImageAsset requestContentEditingInputWithOptions:nil
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSURL *imageURL = contentEditingInput.fullSizeImageURL;
NSString *urlstring = [imageURL absoluteString];
NSLog(#"urlstring%#",urlstring);
}];
CLLocationCoordinate2D locationNew = CLLocationCoordinate2DMake( currentLocation.coordinate.latitude, currentLocation.coordinate.longitude) ;
NSDate *nowDate = [NSDate date];
CLLocation *myLocation = [[CLLocation alloc ]initWithCoordinate:locationNew altitude:0.0 horizontalAccuracy:1.0 verticalAccuracy:1.0 timestamp:nowDate];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// Create a change request from the asset to be modified.
PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:lastImageAsset];
// Set a property of the request to change the asset itself.
request.location = myLocation;
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished updating asset. %#", (success ? #"Success." : error));
}];
}
}];
}
else {
//if you aren't running ios8 or newer I haven't found a way to add/change metadata but I will keep looking.So if you leave this blank no new metadata is added.
}
You can add other metadata just create the data in the form needed and then use request.(what you want to change) = new data.
you can check to see if the data already exist and if there is a metadata for it by putting in something like
lastImageAsset (which was the PHAsset fetch result above) and then the property like
NSDate *originalFileDate = [lastImageAsset creationDate]; etc.
there is a list at
https://developer.apple.com/reference/photos/phasset
I am creating an Application that fetches Images from the photo library of the phone and remove duplicate images from it.I searched a lot but did not find any way to delete the image from the photo library.
i create on demo for that
here is the code
i used UIImageJPEGRepresentation to convert image into data.and compare them it gives me result.is there any other image property that we can compare?
UIImage *img1 = [UIImage imageNamed:#"1.jpg"];
UIImage *img2 = [UIImage imageNamed:#"2.jpg"];
NSData *data1 = UIImageJPEGRepresentation(img1, 1.0);
NSLog(#"%#",data1);
NSData *data2 = UIImageJPEGRepresentation(img2, 1.0);
NSLog(#"%#",data2);
if ([data1 isEqualToData:data2])
{
NSLog(#"yes");
}
else
{
NSLog(#"no");
}
As you know we dont have access to modify anything out side the sandbox.So before ios 8 it was not possible to delete photos from photo library.But in ios 8 and later versions are supported to delete photos from library but before removing it will ask user that you want to delete photos.If user allow then photos will be deleted.
I providing you the CODE which I have used in my app to delete photo from photo library.
if (check system version >= 8.0)
{
PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
[library performChanges:^{
PHFetchResult *assetsToBeDeleted = [PHAsset fetchAssetsWithALAssetURLs:delet
options:nil];
[PHAssetChangeRequest deleteAssets:assetsToBeDeleted];
} completionHandler:^(BOOL success, NSError *error) {
//do something here when error
}];
}
Where delet is the array of asset url of images you get from library with help of AssetLibrary framework.
PHFetchResult *moments = [PHAssetCollection fetchMomentsWithOptions:nil];
for (PHAssetCollection *moment in moments)
{
PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsInAssetCollection:moment options:nil];
for (PHAsset *asset in assetsFetchResults)
{
// Do something with assets, for example add them to array.
}
}
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 trying to create GIF animated images, for which i pass an array of images.
Lets say I have a 4 seconds video and i extract about 120 frames from it. Regardless of the created GIF size, i create a GIF from all those 120 frames. The problem is, when i open the GIF in iPhone (by attaching it to MailViewComposer or iMessage) it runs fine, but if i email it, or import it to computer, it runs too fast. Can anyone suggest what is wrong here?
I am using HJImagesToGIF for GIF creation. The dictionary for GIF properties is as below:
NSDictionary *prep = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.03f]
forKey:(NSString *) kCGImagePropertyGIFDelayTime]
forKey:(NSString *) kCGImagePropertyGIFDictionary];
NSDictionary *fileProperties = #{
(__bridge id)kCGImagePropertyGIFDictionary: #{
(__bridge id)kCGImagePropertyGIFLoopCount: #0, // 0 means loop forever
}
};
creation of GIF:
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:path];
CGImageDestinationRef dst = CGImageDestinationCreateWithURL(url, kUTTypeGIF, [images count], nil);
CGImageDestinationSetProperties(dst, (__bridge CFDictionaryRef)fileProperties);
for (int i=0;i<[images count];i++)
{
//load anImage from array
UIImage * anImage = [images objectAtIndex:i];
CGImageDestinationAddImage(dst, anImage.CGImage,(__bridge CFDictionaryRef)(prep));
}
bool fileSave = CGImageDestinationFinalize(dst);
CFRelease(dst);
if(fileSave) {
NSLog(#"animated GIF file created at %#", path);
}else{
NSLog(#"error: no animated GIF file created at %#", path);
}
To save the GIF, I’m using:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:tempPath]];
data = [NSData dataWithContentsOfFile:tempPath];
[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);
}
}];
Thanks everyone.