IOS Comparing UIImage Data [duplicate] - ios

This question already has answers here:
Comparing UIImage
(4 answers)
Closed 8 years ago.
I have a UIImageView that holds a cover photo for a user. Through the xcode IDE I added a placeholder image that acts as a stock cover photo. When the user clicks on the cover photo I need a way to tell if the image inside the UIImageView is the stock cover photo or another photo that the user has added. The image is never nil. Currently I am doing it by comparing the image data of the current cover photo to the image data generated buy creating an image from the stock cover photo image file.
This is what I have:
if ([UIImagePNGRepresentation(_coverPhoto.image) isEqualToData:UIImagePNGRepresentation([UIImage imageNamed:#"stockCoverPhoto.png"])])
{
[self loadPhoto:1];
}
Comparing the _coverPhoto.image to UIImage imageNamed:#"stockCoverPhoto.png" produced buggy results when the app was closed and reopened within the same session. There must be a better way to do this, I need my code to be as efficient as possible and comparing two NSData structures to one another seems unnecessary.

try with this
UIImage *img = [UIImage imageNamed:#"some.png"];
UIImage *img1 = [UIImage imageNamed:#"some1.png"];
NSData *dataObj1 = UIImagePNGRepresentation(img);
NSData *dataObj2 = UIImagePNGRepresentation(img2);
BOOL test = [dataObj1 isEqualToData:dataObj2];
if(test)
//is Equal
and other answer is
NSData compare to NSData in percents
NSData isEqualtoData

I suppose user will not add this picture every time he start the app. I don't see the problem at all. Just use some property for this, handle it after loading user picture and save it to NSUSerDefaults, cloud or somewhere...
// your class interface
#property (nonatomic) BOOL isUserPictureLoaded;
// first time run save isUserPictureLoaded = NO to NSUserDefaults
// if user saves own picture, set isUserPictureLoaded = YES and save to NSUserDefaults

Related

Strange Image rotation after loading

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

Saving images from web server to phone for image slider

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.

Strange issue with loading an UIImage from core dara directly using KVC

I am in the middle of an app project with core data where I stricty use KVC only with regard to the NSManagedObjects. The purpose of consequentally doing that is simply to get an understanding of advantages and disadvanages. I may have discovered a disadvangate. However, I cannot explain why.
I came across this when I used some very well established principle (used that in other apps already) of saving a scetch that the user drew with his fingers (a signature to a document) in core data and fetch and display or print to PDF respectively it later.
It turned out that I was able to get the UIImage from the view, store it in core data and instanly receive it from core data again using KVC (no save/fetch in between) and display it in another view for testing purposes. But I was unable to actually save it, fetch the data from persistant storage and re-display it on the screen.
So I did a lot of debugging, analysed the sqlite file etc. Eventually I nailed it down to the following strange behaviour:
Situation:
The image was stored into core data successfully by doing this:
[self.detailItem setValue:UIImagePNGRepresentation(image) forKey:kSignatureImage];
with image being an UIImage object and self.detailItem is the NSManagedOBject. Keys and references and everything is fine.
Then it comes to displaying the view again. The following is independent from whether the context was saved in between or even the app was closed and restartet or not:
self.signatureCanvas.image = [UIImage imageWithData:[self.detailTextLabel valueForKey:kSignatureImage]];
with self.signatureCanvas beeing an UIImageView subclass object. The image is not shown on screen.
NSData *data = [self.detailItem valueForKey:kSignatureImage];
NSLog(#"UIImage a: %#", [UIImage imageWithData:[self.detailTextLabel valueForKey:kSignatureImage]]);
NSLog(#"UIImage b: %#", [UIImage imageWithData:data]);
self.testImage.image = [UIImage imageWithData:[self.detailTextLabel valueForKey:kSignatureImage]];
self.signatureCanvas.image = [UIImage imageWithData:data];
self.testImage is a second plain UIImageView withn the same view (but smaller). Now the image is visible in signatureCanvas but not in testImage. (could be vice versa, tried that)
The output give a hint on what was happening but no actual explanation:
2013-03-22 12:43:37.746 MyApp[1595:c07] UIImage a: (null)
2013-03-22 12:43:37.769 MyApp[1595:c07] UIImage b: <UIImage: 0x7c973a0>
Until now I would have thought that the lines of code were kinda equivalent and that the compiler may even optimize the data object away. But why is the image (null) in one case and not in the other.
So I found the problem root cause and a workaround. Therefore this is not urgent any more. But I do not understand it. Any clues?
Environment is: SDK 6.1, xcode 4.6, ARC, core data on sqlite, iPad only so far. All this happens in a UITableViewCell subclass (prototype cell within storyboard) naturally in a UITableViewController subclass.
I assume that self.detailTextLabel in
self.testImage.image = [UIImage imageWithData:[self.detailTextLabel valueForKey:kSignatureImage]];
should be self.detailItem.

iOS Metadata from images loaded by Splitview Controller

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.

Loading images into memory in iPhone 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.

Resources