I have an UIImage that is getting captured using the device camera, After the image is captured I am saving the UIImage like this,
-(void)onCapture:(UIImage *)image {
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
NSFileManager *filemanager = [NSFileManager defaultManager];
NSString *pathToImage = [NSTemporaryDirectory() stringByAppendingPathComponent:#"my_photo_001.jpg"];
[filemanager createFileAtPath:pathToImage contents:imageData attributes:nil];
NSURL *imageFileUrl = [NSURL fileURLWithPath:pathToImage];
[self.delegate onDone:imageFileUrl];
}
After the NSURL is passed to the delegate the delegate then passes this NSURL to an image editing view controller, I am passing the UIImage as well as the NSURL to the editing view controller, Once someone is done editing I want to override the UIImage stored at the NSURL with the edited UIImage so I am doing this,
NSData *imageData = UIImageJPEGRepresentation(self.editImage.image, 1.0);
NSString *pathToImage = [pathOfCapturedImage absoluteString];
[imageData writeToFile:pathToImage atomically:YES];
NSURL *imageFileUrl = [NSURL URLWithString:pathToImage];
Where pathOfCapturedImage is the variable I am passing to my edit view controller.
However when I am opening the image after saving it opens up the unedited image, Where am I going wrong?
You can try delete the old file first, and the write the new one;
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
First delete old exist image then write on the same path.
NSString* imagePath = #"image path"; // get path of old image.
NSData *imgData = UIImageJPEGRepresentation(self.editImage.image, 1.0); // get data of edited image. please make sure if edited image is not nil.
if ([[NSFileManager defaultManager] fileExistsAtPath:imagePath]) // check existence of old image, If yes then delete it.
{
[[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil];
}
if (imgData)
[imgData writeToFile:imagePath atomically:YES];
Related
So i have already gone through almost all questions on SO, and I have put them all together to create a method that accepts two paramaters, first is the URL of the image to download and display in UIImageView and second is the placeholder image for that UIImageView. I want to save the image so that it won't be downloaded every time. I have used SDWebImage to download the image, however i had some confusion when it came to saving the image in documents directory using SDWebImage, so i decided not to use it. I used dispatch_sync(dispatch_get_main_queue() and my method now looks like :
- (void)saveImageFromURL:(UIImage*)image:(NSURL*)imageURL {
NSString *url = [imageURL absoluteString];
NSArray *parts = [url componentsSeparatedByString:#"/"];
NSString *filename = [parts lastObject];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", filename]];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath];
if (fileExists) {
NSLog(#"File already exists");
_myUIImage.image = [UIImage imageNamed:fullPath];
return;
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self.myUIImage sd_setImageWithURL:imageURL placeholderImage:image];
UIImage *imageFromURL = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
NSData *imageDataNew = UIImagePNGRepresentation(imageFromURL);
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:fullPath contents:imageDataNew attributes:nil];
});
}
}
I have a couple of questions, is this implementation good enough since i am working on a app that will be on app store ? Will the downloading of the image from URL be done asynchronously ? (i know i am using dispatch_async but just need to confirm). If yes, then this wont block my UI, right ?
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
// *** Load Image from URL Asynchronously without blocking Main thread ***
UIImage *imageFromURL = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
dispatch_async(dispatch_get_main_queue(), ^(void){
// *** Create file path to DocumentDirectory ***
NSString * docDirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *filePath = [docDirPath stringByAppendingPathComponent:#"myImage.jpg"]
// *** Write Image to disk ***
BOOL isSaved = [UIImageJPEGRepresentation(image, 1.0f) writeToFile:dirPath atomically:YES];
if(isSaved)
{
NSLog(#"Image write to disc successfully.");
}
});
});
I'm downloading an image and then displaying it with UIImageView. Using this approach the image is downloaded every time the view is loaded. How would I go about storing it locally to avoid an unnecessary server request?
[self requestData ] ;
UIImage *userImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:userProfileImageUrl ]]] ;
[self.profileImageView setImage:userImage ] ;
I would suggest using a library like SDWebImage that handles caching and asynchronous download.
Very first time, you have to save the image into NSDocumentsDirectory. For that you have to take the path of directory and append imageName like this
NSString * documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString * documentsPathAppend = [documentsPath stringByAppendingFormat:#"/%#",[userProfileImageUrl lastPathComponent]];
And you have to write image with folowing condition
if(![[NSFileManager defaultManager]fileExistsAtPath:documentsPathAppend])
{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:userProfileImageUrl]]];
[data writeToFile:documentsPathAppend atomically:YES];
}
After that you have to add this path into your local storage like core data. From next time you have to check whether image is there or not for particular URL in your core data.If it is there, then fetch the path from your core data and show like this
[self.profileImageView setImage:[UIImage imageWithContentsOfFile:imageEntity.imagePath]];
try this method to store UIImage in Local Directory..
- (void)addImage:(UIImage *)image toCacheWithIdentifier:(NSString *)identifier {
NSString *folderPath = #"LOCAL DIRECTORY PATH ";
if(![[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:nil])
{
[[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *fileName = [NSString stringWithFormat:#"%#.png",identifier];
fileName = [folderPath stringByAppendingPathComponent:fileName];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:fileName atomically:YES];
}
to retrieve image from Local Directory try this method...
- (UIImage *)imageFromCacheWithIdentifier:(NSString *)identifier
{
NSString *folderPath = #"LOCAL DIRECTORY PATH ";
NSString *fileName = [NSString stringWithFormat:#"%#.png",identifier];
fileName = [folderPath stringByAppendingPathComponent:fileName];
if([UIImage imageWithContentsOfFile:fileName])
{
return [UIImage imageWithContentsOfFile:fileName];
}
return nil;
}
One other viable approach is to utilize NSURLCache (see also: Understanding Cache Access) in the official documentation.
The HTTP Cache was invented exactly for this requirement: Caching in HTTP in RFC 2616.
Unfortunately, HTTP Caching is an advanced topic, and the exact behavior of NSURLCache is quite obscure.
I'm trying to load images using the following method.
I first check if I already have the images on the disk, if I do then I will just get the image data from the disk and load it otherwise I will get the image from the server and write to disk so that the second time that I need the image I won't have to access the server.
The problem is it doesn't seem to write or read from the disk. Everytime that I want to load images for the second time it's still reads them from the server and the NSLog(#"disk"); never gets called.
I don't know what I'm doing wrong if anyone has any idea?
-(UIImage *)imageWith:(NSString *)imageName isPreview:(BOOL)preview
{
//imageName is something like "56.jpg"
NSString *mainOrPreview = #"Preview";
if (!preview) {
mainOrPreview = #"Main";
}
NSString *pathSuffix = [[#"Images" stringByAppendingPathComponent:mainOrPreview] stringByAppendingPathComponent:imageName];
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:pathSuffix];
NSData *imageData = [NSData dataWithContentsOfFile:path];
if (imageData) {
NSLog(#"disk");
}
if (!imageData && [self connected]) {
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[serverURL stringByAppendingPathComponent: pathSuffix]]];
if (imageData) {
[imageData writeToFile:path atomically:YES];
}
NSLog(#"server");
}
return [UIImage imageWithData:imageData];
}
The problem is that the directories don't exist beyond Documents. Therefore the attempts to write the files are failing. It's always a good idea to use the file methods that have the NSError parameters so you can check the result.
You need to update only the code that actually writes the image from the server.
if (!imageData && [self connected]) {
// This needs to be done in on a background thread!
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[serverURL stringByAppendingPathComponent: pathSuffix]]];
if (imageData) {
[[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
[imageData writeToFile:path atomically:YES];
}
NSLog(#"server");
}
I've been trying to use NSFileManager to cache images to the Cache directory of my sandboxed app. Unfortunately, my code doesn't seem to work.
- (BOOL)saveImageToCacheFolder
{
NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *cachePath = [[[filemgr URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject] absoluteString];
NSString *fullpath = [cachePath stringByAppendingPathComponent:#"test.jpg"];
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.photoData format:FlickrPhotoFormatLarge];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
BOOL success = false;
if (imageData != nil) {
success = [imageData writeToURL:[NSURL URLWithString:fullpath] atomically:true];
if (!success) NSLog(#"Did Not Managed to save the image");
}
return success;
}
Here is what I am trying to do. First, get the default NSFileManager. Second, get the relative path to the cache directory of my app. Third, append the name of my file (here i just wrote test for now). Fourth, convert my image to NSData. Fourth, write the NSData object to the specified path.
edit: added if statement for checking if the imageData is nil
Try this:
NSArray *myPathList = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [myPathList objectAtIndex:0];
NSString *fullpath = [cachePath stringByAppendingPathComponent:#"test.jpg"];
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.photoData format:FlickrPhotoFormatLarge];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
if (imageData != nil) {
success = [imageData writeToURL:[NSURL fileURLWithPath:fullpath] atomically:YES];
if (!success) NSLog(#"Did Not Managed to save the image");
}
I'm using a simple implementation of UIImagePickerController to take a picture and save it to my app directory. I"m running into problems with didFinishPickingMediaWithInfo, where I retrieve the image from the info, convert it into NSData using UIImageJPEGRepresentation, and then save it to a file. Problem is, the NSData object appears never to be overwritten, so the first time I take a picture it saves the picture just fine, but any subsequent pictures are not saved, because when I redisplay the image located at the filePath I'm saving it to, it's always the very first picture I took.
I have NSLog statements right now printing out the hash of the UIImage and of the NSData object I'm saving the image to. The UIImage hash changes each time, but the NSData hash is exactly the same all the time...shouldn't that change too?
My code is below. Note that everything not declared in the delegate method below is a global var that isn't causing me any trouble (at least they don't seem to be).
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, fileNameString];
NSData *imageData = UIImageJPEGRepresentation(image, 0.5f);
// imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 0.5f)];
[imageData writeToFile:filePath atomically:YES];
[self dismissModalViewControllerAnimated:YES];
}
When I get rid of the NSData object entirely and replace all instances of
imageData
with
UIImageJPEGRepresentation(image, 0.5f)
I still have the same problem, namely that the hash of UIImageJPEGRepresentation(image, 0.5f) is always the same, even though the hash of the UIImage it takes as a parameter always changes.
Try this:
NSData *imageData = UIImageJPEGRepresentation(image, 0.5f);
imageData = [NSKeyedArchiver archivedDataWithRootObject:imageData];
//imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 0.5f)];
NSError *error= nil;
[imageData writeToFile:filePath options:NSDataWritingAtomic error:&error];
Also take a look at this link
Are you creating the directory? Use this code to create the directory:
NSArray* dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* docsDir = [dirPaths objectAtIndex:0];
pathString = [docsDir stringByAppendingPathComponent:#"%#",filePath];
NSFileManager* filemgr = [NSFileManager defaultManager];
//Creates Directory
if ([filemgr createDirectoryAtPath:pathString
withIntermediateDirectories:YES
attributes:nil
error: NULL] == YES){