iPhone - UIImagePickerController -> save the image to app folder - iphone

I have an iPhone application using a UIImagePickerController. As sourceType I have
UIImagePickerControllerSourceTypePhotoLibrary
UIImagePickerControllerSourceTypeCamera
UIImagePickerControllerSourceTypeSavedPhotosAlbum
so the user can make a photo or select one from the photo library from the photos or camera photos.
The image will be displayed in a UIImageView. The image should be saved if the user closes the app. So for text fields, I use NSUserDefaults. I know, it is not a good way to save the image inside the NSUSerDefaults with NSData, so I want to save / copy the image to a folder which is controlled by my application similar to the NSUserDefaults.
How can I do this? I want to save it, and then I can write the path to the file into my NSUserDefaults and read it on startup of the application.
Thank you in advance & Best Regards.

You can use the following code in UIImagePickerControllerDelegate delegate implementation
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
//obtaining saving path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:#"latest_photo.png"];
//extracting image from the picker and saving it
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:#"public.image"]){
UIImage *editedImage = [info objectForKey:UIImagePickerControllerEditedImage];
NSData *webData = UIImagePNGRepresentation(editedImage);
[webData writeToFile:imagePath atomically:YES];
}
}
UPD
Swift 3.0 code by XueYu
here the image is saved as jpeg but you can also save it as png. the
0.0 parameter stands for compression and it's the lowest quality, if you want to get the best use 1.0.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//obtaining saving path
let fileManager = FileManager.default
let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
let imagePath = documentsPath?.appendingPathComponent("image.jpg")
// extract image from the picker and save it
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
try! UIImageJPEGRepresentation(pickedImage, 0.0)?.write(to: imagePath!)
}
self.dismiss(animated: true, completion: nil)
}

Depending on the file format you want to save, you can use
[UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
OR
[UIImageJPEGRepresentation(image) writeToFile:path atomically:YES];

This is the code to save the UIImage into the document directory. You can use this code in didFinishPickingImage delegate method:
// Create paths to output images
NSString *pngPath = [NSHomeDirectory();
stringByAppendingPathComponent:#"Documents/Test.png"];
NSString *jpgPath = [NSHomeDirectory();
stringByAppendingPathComponent:#"Documents/Test.jpg"];
// Write a UIImage to JPEG with minimum compression (best quality)
// The value 'image' must be a UIImage object
// The value '1.0' represents image compression quality as value from 0.0 to 1.0
[UIImageJPEGRepresentation(image, 1.0) writeToFile:jpgPath atomically:YES];
// Write image to PNG
[UIImagePNGRepresentation(image) writeToFile:pngPath atomically:YES];
// Let's check to see if files were successfully written...
// Create file manager
NSError *error;
NSFileManager *fileMgr = [NSFileManager defaultManager];
// Point to Document directory
NSString *documentsDirectory = [NSHomeDirectory();
stringByAppendingPathComponent:#"Documents"];
// Write out the contents of home directory to console
NSLog(#"Documents directory: %#", [fileMgr contentsOfDirectoryAtPath:documentsDirectory error:&error]);
EDIT
You can also use:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
to find the path to your application document directory, instead of NSHomeDierctory.

Update knuku's answer for Swift 3.0
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//obtaining saving path
let fileManager = FileManager.default
let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
let imagePath = documentsPath?.appendingPathComponent("image.jpg")
// extract image from the picker and save it
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
try! UIImageJPEGRepresentation(pickedImage, 0.0)?.write(to: imagePath!)
}
self.dismiss(animated: true, completion: nil)
}
here the image is saved as jpeg but you can also save it as png. the 0.0 parameter stands for compression and it's the lowest quality, if you want to get the best use 1.0.

Related

Select image to use as UIViewController background throughout my app

When my iPhone app runs for the first time it asks you to select an image from your iPhone library to use as the background throughout your app. Here is the relevant code:
/*
* Responds when an image is selected (from browsing)
*/
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
[self dismissModalViewControllerAnimated:YES];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage])
{
//Not really sure what to do here
UIImage *image = [[UIImage alloc] initWithData:UIImageJPEGRepresentation([info objectForKey:UIImagePickerController], .2)];
}
}
I now what to save this image (or a reference to this image) so that I can use it throughout my app as the background for some (60%) of my UIViewController
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
What is the best/most efficient/easiest way to do this. I thought about saving the image into NSUserDefaults but this didn't seem right because NSUserDefaults is only supposed to be for small objects. Should I save it to disk? But then won't my app be really slow having to read from disk every time I segue? (If this is the proper way, how would I do this?)
Store your Image in Documents Directory
To save Image
- (void)saveImage:(UIImage *)image {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
// Convert to Data
NSData *imageData = UIImagePNGRepresentation(image);
// write to file
[imageData writeToFile:savedImagePath atomically:NO];
}
To read Image use following
- (UIImage *)getImage {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
return img;
}
Use a subclassed UIViewController where the background is always this selected background image, which you could have saved off using #Dipen's suggestions below (and +1 to him).
Literally the only thing that needs to exists in your new view controller is that in it's "viewDidLoad:" method, you add a subview that is a "UIImageView", set to your background image which you saved off as some preference.
You can then subclass further view controllers off your new "NosetrapViewController", which will automatically pick up the selected background image.

Iphone-saving full size image to document directory hangs my app

I am working on an app similar to photo app in iPhone. The flow is I get images through UIImagePickerController. When I use Actual image and further save that image to documents,
My app hangs. I saw on profile tool that allocation goes to 19 to 20 mb. If there is any solution to that.
Getting image from UIImagepicker controller
Saving it to documents.
-(NSString *)saveImageInDocumentsAtPath:(NSNumber *)number
{
NSString *fileName=[NSString stringWithFormat:#"image%#.png",number];
NSString *imagePath= [[NSString alloc] initWithFormat:#"%#/%#", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0],fileName];
UIImage *image = self.selectedImage.image;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:imagePath atomically:YES];
return imagePath;
}
A typical image is going to be around 3Megabytes, if I am not mistaken (depending on the iPhone and its camera). So going from 19 to 20 is not unreasonable. Why you are at 19 to begin with ay be another question. See if you're loading in too many other images, large files etc.
If you use AV Foundation instead of ImagePicker, you have some other options for handling the images.
And you can write the image to the filesystem asynchronously.
This looks like a great opportunity for some error checking in your code.
Why not try this?
-(NSString *)saveImageInDocumentsAtPath:(NSNumber *)number
{
NSString *fileName=[NSString stringWithFormat:#"image%#.png",number];
NSArray * docDirectoryArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if(docDirectoryArray)
{
NSString *imagePath= [[NSString alloc] initWithFormat:#"%#/%#", [docDirectoryArray objectAtIndex:0],fileName];
UIImage *image = self.selectedImage.image;
if(image)
{
NSData *imageData = UIImagePNGRepresentation(image);
if(imageData)
{
BOOL success = [imageData writeToFile:imagePath atomically:YES];
if(success)
{
// only return the image path in the success == YES case
return imagePath;
} else {
NSLog( #"did not save file to %#", imagePath);
}
} else {
NSLog( #"could not get image data out of the image");
}
} else {
NSLog( #"no image selected");
}
}
// you might want to check in the caller to make certain the imagePath is NULL
return NULL;
}

How do I save a UIImage to a file?

If I have a UIImage from an imagePicker, how can I save it to a subfolder in the documents directory?
Of course you can create subfolders in the documents folder of your app. You use NSFileManager to do that.
You use UIImagePNGRepresentation to convert your image to NSData and save that to disk.
// Create path.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Image.png"];
// Save image.
[UIImagePNGRepresentation(image) writeToFile:filePath atomically:YES];
Core Data has nothing to do with saving images to disk by the way.
In Swift 3:
// Create path.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let filePath = "\(paths[0])/MyImageName.png"
// Save image.
UIImagePNGRepresentation(image)?.writeToFile(filePath, atomically: true)
You have to construct a representation of your image as a particular format (say, JPEG or PNG), and then call writeToFile:atomically: on the representation:
UIImage *image = ...;
NSString *path = ...;
[UIImageJPEGRepresentation(image, 1.0) writeToFile:path atomically:YES];
The above are useful, but they don't answer your question of how to save in a subdirectory or get the image from a UIImagePicker.
First, you must specify that your controller implements image picker's delegate, in either .m or .h code file, such as:
#interface CameraViewController () <UIImagePickerControllerDelegate>
#end
Then you implement the delegate's imagePickerController:didFinishPickingMediaWithInfo: method, which is where you can get the photograph from the image picker and save it (of course, you may have another class/object that handles the saving, but I'll just show the code inside the method):
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// get the captured image
UIImage *image = (UIImage *)info[UIImagePickerControllerOriginalImage];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *imageSubdirectory = [documentsDirectory stringByAppendingPathComponent:#"MySubfolderName"];
NSString *filePath = [imageSubdirectory stringByAppendingPathComponent:#"MyImageName.png"];
// Convert UIImage object into NSData (a wrapper for a stream of bytes) formatted according to PNG spec
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:filePath atomically:YES];
}
If you want to save as JPEG image, the last 3 lines would be:
NSString *filePath = [imageSubdirectory stringByAppendingPathComponent:#"MyImageName.jpg"];
// Convert UIImage object into NSData (a wrapper for a stream of bytes) formatted according to JPG spec
NSData *imageData = UIImageJPEGRepresentation(image, 0.85f); // quality level 85%
[imageData writeToFile:filePath atomically:YES];
extension UIImage {
/// Save PNG in the Documents directory
func save(_ name: String) {
let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let url = URL(fileURLWithPath: path).appendingPathComponent(name)
try! UIImagePNGRepresentation(self)?.write(to: url)
print("saved image at \(url)")
}
}
// Usage: Saves file in the Documents directory
image.save("climate_model_2017.png")
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:path atomically:YES];
where path is the name of the file you want to write it to.
First you should get the Documents directory
/* create path to cache directory inside the application's Documents directory */
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"fileName"];
Then you should save the photo to the file
NSData *photoData = UIImageJPEGRepresentation(photoImage, 1);
[photoData writeToFile:filePath atomically:YES];
In Swift 4.2:
// Create path.
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let filePath = paths.first?.appendingPathComponent("MyImageName.png") {
// Save image.
do {
try image.pngData()?.write(to: filePath, options: .atomic)
} catch {
// Handle the error
}
}
In Swift 4:
// Create path.
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let filePath = paths.first?.appendingPathComponent("MyImageName.png") {
// Save image.
do {
try UIImagePNGRepresentation(image)?.write(to: filePath, options: .atomic)
}
catch {
// Handle the error
}
}

Save images for later use in iPhone

I want to save images that user selects from the camera roll, when app exits and restart i want to show those images to user. I have searched over internet and not found much useful resource. I know I can write the image in database as blob but I dont want to do it as increases the database size. Is it possible to save the image path and then later use that path to access that image.
Save the Image into the DocumentDirectory
NSString *imageName = "myImage.png";
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsDirectoryPath = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectoryPath stringByAppendingPathComponent:imageName];
NSData* settingsData = UIImagePNGRepresentation(imageData);
[settingsData writeToFile:dataPath atomically:YES];
EDIT:
If you want to see your saved images on the iPhone/iPad (or share them) in iTunes->Apps->Documents
jut add in Info.plist "Application supports iTunes file sharing" : "YES"
You have to use UIImagePickerController
to get the media from the Camera roll
You will get the image in the delegate method
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
Here you can get the image and save is as NSData .. in a file and then retrieve back it next time
Edit :
to Save
Data = UIImageJPEGRepresentation(theImage,1.0);
NSString *imagePath = [ContentFolder stringByAppendingPathComponent:[NSString stringWithFormat:#" %d.plist",Counter]];
NSLog(#" iamge path %#",imagePath);
NSMutableDictionary *objectDictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:data,#"data", nil];
[objectDictionary writeToFile:imagePath atomically:YES];
you should be able to change these according to your needs..

Save videos using uiimagepickercontroller without changings its created date

I am using uiimagepicker to save video to my application bundle. But after saving that, the created date of the video is changed. My requirement is just to copy that video to my folder without changing its created date.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
NSData *imageData = [NSData dataWithContentsOfURL:url];
NSString *path = NSHomeDirectory();
NSString *img_temp_name=[[NSString stringWithFormat:#"test"] stringByAppendingString:#".mov"];
NSString *full_path=[path stringByAppendingPathComponent:img_temp_name];
if([imageData writeToFile:full_path atomically:YES]) {
}
Can you use NSFileManager to help you?
I assume that you're not going to be allowed just to move the movie but if you copy it, does it preserve some file information?
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
NSString *path = NSHomeDirectory();
NSString *img_temp_name=[[NSString stringWithFormat:#"test"] stringByAppendingString:#".mov"];
NSString *full_path=[path stringByAppendingPathComponent:img_temp_name];
NSURL *dst = [NSURL fileURLWithString:full_path];
NSError *error = nil;
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
BOOL success = [manager copyItemAtURL:url toURL:dst error:&error];
if (NO == success || error) {
NSLog(#"Could not copy : %#", error);
}
Your issue is that as part of the picking process the video is reencoded. This changes the creation date. I would also like to know if it is possible to getbthis info.
Here is a way to get videos as NSData.
It uses the Photos framework as ALAssetLibrary is deprecated as of iOS9:
IMPORTANT
The Assets Library framework is deprecated as of iOS 9.0. Instead, use the Photos framework instead, which in iOS 8.0 and later provides more features and better performance for working with a user’s photo library. For more information, see Photos Framework Reference.
import Photos
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
self.dismissViewControllerAnimated(true, completion: nil)
if let referenceURL = info[UIImagePickerControllerReferenceURL] as? NSURL {
let fetchResult = PHAsset.fetchAssetsWithALAssetURLs([referenceURL], options: nil)
if let phAsset = fetchResult.firstObject as? PHAsset {
PHImageManager.defaultManager().requestAVAssetForVideo(phAsset, options: PHVideoRequestOptions(), resultHandler: { (asset, audioMix, info) -> Void in
if let asset = asset as? AVURLAsset {
let videoData = NSData(contentsOfURL: asset.URL)
// optionally, write the video to the temp directory
let videoPath = NSTemporaryDirectory() + "tmpMovie.MOV"
let videoURL = NSURL(fileURLWithPath: videoPath)
let writeResult = videoData?.writeToURL(videoURL, atomically: true)
if let writeResult = writeResult where writeResult {
print("success")
}
else {
print("failure")
}
}
})
}
}
}