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.
Related
I am trying to make a simple application using XCode 4.5 which would allow the user to chose any particular image via accessing his photo library, then submit that image for recognition with the help of the Tesseract library.
The problem is that I do not know how to further save the selected user picture, In other words, I can provide the user with an option for going in the picture library and let him chose a picture, but I do not how to then save that selected picture so that it can be further processed.
I hope i made it clear, Appreciate your help.
Try this,
Save image:
NSString *imgName=[#"imgname.png"];
[[NSUserDefaults standardUserDefaults]setValue:imgName forKey:#"imageName"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:imgName];
UIImage *image = imageView.image; // imageView is my image from camera
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
Retrive image:
NSString *imgName= [[NSUserDefaults standardUserDefaults]valueForKey:#"imageName"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *filePath=[NSString stringWithFormat:#"%#/%#",documentsDir,imageName];
[imageview setImage:[UIImage imageWithContentsOfFile:filePath]];
What you need to do is save the image data after selection inside the following delegate - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { You can get the image via the key UIImagePickerControllerOriginalImage in the info dictionary and possibly assign it to an imageview or save it as mentioned by #Kalpesh. Check out apple's documentation for more info. Also check out this good tutorial that shows how to pick photos from the photo album or the camera.
I am still not clear about what exactly you want.
You can always Save Image in or Retrieve Image from Photo Library.
I have an application which donwloads several images and stores them on the phone. In total it will probably required around 20 images tops. I need to be able to retrieve any of these images at will depending on what screen the user is on. These images will be stored indefinitely, so I don't want to use temp directory.
At present I have a class named Images with these methods
- (void) cacheImage: (NSString *) ImageURLString : (NSString *)imageName
{
NSURL *ImageURL = [NSURL URLWithString: ImageURLString];
// Generate a unique path to a resource representing the image you want
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString *docFile = [docDir stringByAppendingPathComponent: imageName];
// Check for file existence
if(![[NSFileManager defaultManager] fileExistsAtPath: docFile])
{
// The file doesn't exist, we should get a copy of it
// Fetch image
NSData *data = [[NSData alloc] initWithContentsOfURL: ImageURL];
UIImage *image = [[UIImage alloc] initWithData: data];
// Is it PNG or JPG/JPEG?
// Running the image representation function writes the data from the image to a file
if([ImageURLString rangeOfString: #".png" options: NSCaseInsensitiveSearch].location != NSNotFound)
{
[UIImagePNGRepresentation(image) writeToFile: docFile atomically: YES];
}
else if([ImageURLString rangeOfString: #".jpg" options: NSCaseInsensitiveSearch].location != NSNotFound ||
[ImageURLString rangeOfString: #".jpeg" options: NSCaseInsensitiveSearch].location != NSNotFound)
{
[UIImageJPEGRepresentation(image, 100) writeToFile: docFile atomically: YES];
}
}
}
- (UIImage *) getCachedImage : (NSString *)imageName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* cachedPath = [documentsDirectory stringByAppendingPathComponent:imageName];
UIImage *image;
// Check for a cached version
if([[NSFileManager defaultManager] fileExistsAtPath: cachedPath])
{
image = [UIImage imageWithContentsOfFile: cachedPath]; // this is the cached image
}
else
{
NSLog(#"Error getting image %#", imageName);
}
return image;
}
-(void)getImages
{
//example
NSString *image1URL = #"http://test/image1.png";
NSString *image2URL = #"http://test/image2.png";
NSString *image3URL = #"http://test/image3.png";
[self cacheImage:sLogo: #"Image1"];
[self cacheImage:sBlankNav: #"Image2"];
[self cacheImage:buttonLarge :#"Image3"];
}
-(void) storeImages
{
image1 = [self getCachedImage:#"Image1"];
image2 = [self getCachedImage:#"Image2"];
image3 = [self getCachedImage:#"Image3"];
}
So I use the code like this
Images *cache = [[Images alloc]init];
[cache storeImages];
The get images method is called once when the app first starts to get the images, it isn't called again after that, unless the images on the server are updated and I need to retrieve the updated ones.
The code works, but the problem is when I navigate to a screen that uses it, there is a very slight delay before the screen loads as it is loading the images.
My application is a tabbed application, so it begins on tab 1, I click tab 2 which implements the code, there will be a slight pause the first time it loads. It doesn't last very long, but it is noticeable and is very annoying. After that it is fine, as it is already loaded. However with navigation controller, every time you move from the first VC to the second VC, the method will be called again, so each time you navigate the delay will be there.
The images are not very big, biggest one is 68kb, others are much smaller than that. At present I am just testing with 5 images. Is there a more efficient way of storing and retrieving images, or am I doing something wrong with my code? I need to be able to retrieve these images without any noticeable delay in order for my application to remain fluid and not jerky or clunky.
Thanks in advance!!
You have two options to do the image loading work on a background thread - use Grand Central Dispatch or NSInvocationOperation. GCD might be considered the cleaner of the two:
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_async(q, ^{
//load images here
dispatch_async(main, ^{
// show on main thread here
});
});
you have delay because you're downloading data synchronously
// NSData *data = [[NSData alloc] initWithContentsOfURL: ImageURL];
Try some smart library like SDWebImage:
it lets you download image asynchronously while you still can display a local image (a proxy image). By the way, you still get cache image for free. So even if u are on local, you can still catch previously downloaded images
https://github.com/rs/SDWebImage
A must have
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..
I'm using a UITableView to show 2 to 3 images as thumbnail in each table view cell. The images which I'm showing it in the tableview are huge in size. If I'm using those images directly without any size reduction then the tableview may lose some images if I move back and forth between TableView and other view controllers.
So, I thought of size reduction code which reduces the size of the images. The code given below works great and the previous issue was fixed. But the tableview looses its smooth scrolling because the size reduction code uses a lot of memory. Every time when a new tableview cell is shown, it processes (reduces the size) the images in the particular tableview cell.
There may be a simple solution for this. Thanks in Advance.
//Size Reduction Code
CGSize newSize=CGSizeMake(_new_width, _new_height);
UIGraphicsBeginImageContext( newSize );
[sd._image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
scene_image_preview.image =newImage;
On top of reducing the image you can store the resulting newImage as a file in the documents folder of your app.
NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:newImage]);
CGImageRelease(newImage);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [NSString stringWithFormat:#"%#/%#%d_%d.png",documentsDirectory, prefix, x, y];
[imageData writeToFile:path atomically:NO];
Depending on how many images you have, you can just keep all the reduced-size images in an NSMutableDictionary that's a property of your class.
In other words:
In your header
#property (nonatomic, retain) NSMutableDictionary *sizedImages;
Then in your cellForRowAtIndexPath: code
UIImage *sizedImage = [sizedImages objectForKey:[NSNumber numberWithInt:indexPath.row]];
//Or you could use the filename as the key
if (!sizedImage) {
sizedImage = [self sizeImage];(your sizing method)
[sizedImages setObject:sizedImage forKey:[NSNumber numberWithInt:indexPath.row]];
}
A few possible options
Perform the resizing in the background so it doesn't hold up the main thread.
Cache the resized image after doing it so there is only a delay the first time (this could be used in conjunction with doing it in the background so there is no delay on the scrolling)
Are you downloading the images? If so, download a thumbnail first and display that. Then if the image is selected, display the thumbnail scaled up to full screen which will look blocky, but then download the full-size image in the background and display that when it has loaded.
If you aren't downloading the images, but they are included in the app, just include thumbnails as well and display them instead
drawing images usually takes time.i think you can try to place the images in imageView by giving the frame sizes as desired.i doesn't make difference in look of the images.
add the imageviews to the cell and add the images to the imageView
These two links are very useful
http://www.fieryrobot.com/blog/2008/10/01/glassy-scrolling-with-uitableview/
and his follow up post
http://www.fieryrobot.com/blog/2008/10/08/more-glassy-scrolling-with-uitableview/
The first link is a few best practices. The second link will eb more useful to you; render your whole table view cell to an image and use that instead - this can be cached to disk to free memory & can be used between runs of the app.
- (void)saveImage:(UIImage *)image withName:(NSString *)name {
[myArray addObject:name];
//save image
NSData *data = UIImageJPEGRepresentation(image, 1.0);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}
- (UIImage *)loadImage:(NSString *)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
UIImage *res = [UIImage imageWithContentsOfFile:fullPath];
return res;
}
Finally, I got a solution to load number of large sized images simultaneously. First, I reduced the size of the image using the size reduction code above and I saved those sized images to documents directory for the first time and then I loaded the saved images from the documents directory using these saveImage and loadImage functions.
Thanks for all the comments and suggestions to solve this.
I'm trying to save a selected image to a directory. My code is as follows:
-(IBAction)attachPhotosButton
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:imagePicker animated:YES];
// If image is selected, then save
//[self saveImage];
// else do nothing
}
-(void)saveImage
{
// This creates a string with the path to the app's Documents Directory.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// Here we are calling the method we created before to provide us with a unique file name.
NSString *imagePath = [NSString stringWithFormat:#"%#/iPhoneImage.png", documentsDirectory];
// This creates PNG NSData for the UIImageView imageView's image.
UIImageView *imageView;
NSData *imageData = UIImagePNGRepresentation(imageView.image);
// Uncomment the line below to view the image's file path in the Debugger Console. (Command+Shift+R)
NSLog(#"Image Directory: %#", imagePath);
// This actually creates the image at the file path specified, with the image's NSData.
[[NSFileManager defaultManager] createFileAtPath:imagePath contents:imageData attributes:nil];
}
How do I detect that the user selected an image when the imagePicker view controller is presented ?
If they select an image I want to call the saveImage method.
Regards,
Stephen
You need to access the UIImagePickerControllerDelegate methods. The link brings you to the one you want. Make sure that you set the picker delegate!
Inside the method you just need to check if the UIImagePickerControllerMediaType key of the info dictionary is set to a kUTTypeImage. Then call your function.
in the
-(void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
delegate method of UIImagePickerControllerDelegate.
Edit: reread your question and realized you want to save to your temp path or somewhere, not the phone's photo album.