I have a SplitviewController that displays a list of images. When one is clicked it will be shown on the main screen and I want to display the metadata of this image below it.
My images are managed by a self written class that stores them as UIImages.
I got 4 example pictures that are just embedded as Ressource files and loaded via
NSString* pathToImageFile = [[NSBundle mainBundle] pathForResource:imageName
ofType:#"jpg"];
UIImage* img = [UIImage imageWithContentsOfFile:pathToImageFile];
The User has the option to add pictures to this list via imagePicker either out of the library or the camera.
Now I need a way to access the metadata of the images when the user chooses a row in the table. I know that UIImages don't carry any metadata, but is there a way to access the underlying jpg and retrieve metadata from there? The main problem hereby would be that I have three different sources for the images (app directoy, photo album, camera).
Or do I need to rewrite my image store class that it has to keep track of my metadata or my URLs as well as the images?
The following is my didSelectRow method where I want to add a method to retrieve metadata of the selected image.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIImage *img = [[[ImageStore sharedStore] getAllImages] objectAtIndex:[indexPath row]];
self.detailViewController.detailItem = img;
}
Thanks for your help!
If it's in the app directory you can read the file directly. There is code here which will get the metadata using CGImageSource.
http://blog.depicus.com/index.php/2011/05/07/getting-exif-data-from-images-on-ios/
The photo library you get using ALAssetLibrary. Eventually you will drill down to an ALAssetRepresentation, which has a metadata property.
For a camera picture, to be honest I'm not entirely sure how you can do that without writing it to disk (photo library or application directory) first.
Related
I am displaying images in UITableview from document directory folder but it's getting so much loading, how can I make it smooth. See below my code:
cell.imageView.image = [UIImage imageWithContentsOfFile:path];
If I convert the path into NSData then it also get so much load to display image in UITableview.
Any suggestion or any other way to display the image from document directory or any suggestion for smoothly loading images from document directory?
Try LazyTableImages sample code from Apple like Phil Kulak answered to a similar question.
I'm using XCode 6.
Let's say I have a Food model containing a (UIImage *)image property. I would like to display all my foods displaying images for my interface.
I have already the pictures for the foods (they are not in the Photo Library of the device but on my computer).
1) Where to put these image files (beet.png, banana.png etc... for example) in Xcode ? (is there a dedicated folder ?)
2) How to refere to this image file ? Example in my Food class, self.image = ?
Thanks a lot !
You can just drag and drop image files to your project while xcode is open.
make sure you use copy items if needed option, it is less hassle.
once you clikc finish for your files, you will see your files on bundle.
then all you need to do is call
[UIImage imageNamed:#"imageInBundle.png"];
imageNamed: will search your main bundle
or long way
NSBundle* bundle = [NSBundle bundleWithURL:[[NSBundle mainBundle]URLForResource:#"YourBundle" withExtension:#"bundle"]];
NSString *imagePath = [bundle pathForResource:#"imageInBundle" ofType:#"png"];
UIImage* image = [UIImage imageWithContentsOfFile:imagePath];
1) you can create new group inside your project in XCode and drag images to it. Check in build phases, in Copy Bundle Resources to make sure they'll be copyed in final app. 2) you refer image using imageWithName. You can use UIImageView for easier management and set this image your imageWithName. Otherwise you can implement directly images in your xib. Anyway how do you want to use images? In a table, in a collection, in a detail view? Depends on you how you want to display them and how you manage to make things work.
In my app, user can make a profile pic by uploading it from phone or taking one from the phone.
Everything works fine, and the user is able to do any of these operations smoothly and the profile pic looks great, at the time of setting it up.
But, when the user starts the app again, I fetch the path of the image and try to show it.
And it is shown, but it is, for some reason, rotated for 90 or 180 degrees!
So, once again, at the moment when the user takes or uploads a pic from the phone, it is not rotated strangely like this, only on the next app life cycle.
Here is some code:
-(void)setAvatar
{
NSMutableArray* imagePathArray = [[Model shared] loadDataForKey:#"avatar"];
NSString *imagePath = [imagePathArray objectAtIndex:0];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
if (image!=nil)
_avatar.image = image;
}
I suppose the problem is because of skipping embedded metadata information. When you use Media Library to get an image (?) it includes orientation transformation info. After that you start to UIImage, but this class truncates all image metadata. That's why you see your image rotated after you save and reload it.
Accessing Image Metadata in iOS
I have an app where it pulls urls of images from a database and stores it in coredata. Then in my app view, there's a scrollview of imageviews, basically I'm trying to do an image slider. These images tend to get updated so it needs to load from the server. I load the image urls from the coredata, download them to uiimages and load them in my view. Problem is, it's really slow as I'm doing it at runtime.
I was wondering what's the best way to go about this. I was thinking of loading all the images to the phone first when the app launches? I tried looking for some sample code to point me to the right direction but I can only find code that saves images to the phone's camera roll and not to the app itself. Anyone could help pls? Thanks!
Here's a method that takes a UIImage, a target path (the directory you want to save the image to) and the filename for the image, and saves the image as a PNG file:
-(BOOL) saveImage:(UIImage *)image savePath:(NSString *)savePath filename:(NSString *)filename{
savePath = [savePath stringByAppendingPathComponent:filename];
NSData *sourceData = UIImagePNGRepresentation(image);
return [sourceData writeToFile:savePath atomically:YES];
}
You will need to store the image in the right location within the app's sandbox. For example, don't put them in the Documents folder as it may be rejected by Apple since you can recreate (or re-download) the images. You likely want to put them in the Library/Caches folder, and be prepared to re-download them if they are removed. See the iOS File System Programming Guide for details on this.
I would be concerned about downloading all the files at app start, since it will look like the app has frozen if it non-responsive while download a number of image files. You can download the images in the background and update the UI as the images finish downloading.
One method to do this would be to check if the image has already been downloaded (e.g., is it in the Library/Caches folder). If it is, then use it, otherwise use a placeholder image until the image is downloaded. For example:
if (isImageAvailable) {
displayedImageView.image = cachedImage;
} else {
displayedImageView.image = placeholderImage;
[self getImageAtURL:imageURL andThenDo:^(UIImage *image) {
// Replace placeholder image with downloaded image
displayedImageView.image = image;
}];
}
Replace isImageAvailable with a method that checks for the existence of the image file in the Library/Caches folder. displayedImageView is the UIImageView you are displaying the image with.
The getImageAtURL method would look something like:
-(void)getImageAtURL:(NSURL *)url andThenDo:(void(^)(UIImage *image))completionBlock{
// Run on background thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image;
// Insert code to download image...
// Switch to main (UI) thread to allow updating the UI
dispatch_sync(dispatch_get_main_queue(), ^{
completionBlock(image);
});
});
}
You might not need to download images to your application, I can suggest better you use image url it self to load images from server it self.
To load images from server u may use following:
UIImage* yourImageview = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:your.image_url]]];
Downloading all images will also slow down your app.
I have an UImageView and on click of an button i want to change the UImage in the UImageView. App has 22 UImages with each image exceeding 5 mb size , so the UImageView takes some time to load an image when the button is clicked , is there a way by which we can load these images into the memory so that image view takes lesser time to show the image?
I use the following code to set the image :
[ImageView setImage:[UIImage imageNamed:#"ImageName.jpg"]];
basically i want on swipe the images to be changed , e.g. if a user swipes from right to left the app must show the next image and on left to right click the back image be loaded . please suggest .
like #Gobot mentioned it is the best way du reduce the size of your pictures. For the swipe there is no need to use big pictures like this. You could just create two folders, one with small sized pictures and another with bigger one. If you swipe through, you just use the small pictures. If a user taps a picture you could get the name of the selected UIImage and load just this single picture. That way you also can provide high quality pictures for zooming in. And keep in mind, that your app package gets also bigger the more pictures you have included.
There is a good explanation in a WWDC Stream: iOS App Performance: Graphics and Animations
I also created a method inside a NSMutableArray category for loading all my UIImages once. You could use this method inside viewDidLoad:
- (NSMutableArray *)getImagesWithStartSuffix:(NSString *)start
andEndSuffix:(NSString *)end{
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for (int i = 1; i < 100 + 2; i++) {
NSString *fileName = [NSString stringWithFormat:#"%#%d%#.jpg",
start, i, end];
if([self fileExistsInProject:fileName]){
[imageArray addObject:[UIImage imageNamed:fileName]];
} else {
break;
}
}
return imageArray;
}
There is also a very easy way to change the size of your pictures by writing an Apple Script. You could run a loop over all pictures and resize them all this way. This is the easiest way and you don't have to use any tools like Gimp or PS:
do shell script "sips [path_to_file]/picture1.jpg -z 666 1000 --out [path]/changedSize/picture1_small.jpg"
From the Documentation:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
if it takes too long, you may want to add a progress indicator in your app till the full view is generated/loaded then display it on your screen.
The first and simplest option would be to reduce your images under 5MB. Do they really need to be that big? Are they thumbnails? The more complex option would be to load/cache images in a background thread (asynchronously) using dispatch queues.