I use the iOS Simulator to test.
When select photos from its own library and store the paths to a database backed by mongodb and nodejs, I then tried to read from the path and reload the image data:
NSString *photo1Path = photo1[0];
NSLog(#"!!!photo1Path: %#", photo1Path);
// Console: !!!photo1Path: /var/folders/x4/01z7j18d7vz8rxrgcxt2w9dm0000gn/T/6-vZsBlMzA1Lj_pkdVYRx-HI.png
NSData *data = [NSData dataWithContentsOfFile:photo1Path ];
NSLog(#"!!!photo1Data: %#", data);
// Console: !!!photo1Data: (null)
UIImage *photo1Image = [UIImage imageWithData:data];
[self.photo1Button setImage:photo1Image forState:UIControlStateNormal];
As you can see from the above, the path is correct but the data is read to be "null". I tried to search solutions online but still feel confused. Is it a problem of iOS simulator or do I need to use the main bundle or something?
Related
I'm trying to preload the image tags from an html string in order to load them when the device is offline. Basically, I strip the source url from all the <img>tags, clean the url to have a clean filename, then download the image.
__block NSString *imageName = [[NSString alloc]init];
//Get the string after HTTP://
NSArray *nohttp = [actualUrl componentsSeparatedByString:#"//"];
imageName = [nohttp objectAtIndex:1];
//Clean any /.:
imageName = [imageName stringByReplacingOccurrencesOfString:#"/" withString:#""];
imageName = [imageName stringByReplacingOccurrencesOfString:#"." withString:#""];
imageName = [imageName stringByReplacingOccurrencesOfString:#":" withString:#""];
//Add .png at the end as we will be saving it as a PNG
imageName = [NSString stringWithFormat:#"%#.png", imageName];
//change the source url to the new filename of the image so the WebView will load it from the main bundle
html = [html stringByReplacingOccurrencesOfString:actualUrl withString:imageName];
//save the image to the main bundle
NSString *pathString = [NSString stringWithFormat:#"%#/%#",[[NSBundle mainBundle]bundlePath], imageName];
//this just checks if the image already exists
BOOL test = [[NSFileManager defaultManager] fileExistsAtPath:pathString];
if (!test){
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:actualUrl]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
NSData *imageData2 = UIImagePNGRepresentation(image);
[imageData2 writeToFile:pathString atomically:YES];
});
}
Then after I load the html string into the UIWebView, it works perfectly on the simulator, but on the device the images just aren't loaded. Why?
NSURL *baseUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#",[[NSBundle mainBundle]bundlePath]]];
[self.webView loadHTMLString:self.htmlPage baseURL:baseUrl];
Any suggestions, thoughts? The images download fine on the iOS device/simulator but aren't loaded in the WebView of the real device. It works perfectly for the simulator.
That is correct.
On iOS an App's bundle is read-only. Any attempts to save changes into your bundle will fail on an iOS device.
On Mac OS the bundle is not read-only, but you should still treat it as read-only. Modifying your app's bundle is a bad idea. If the user updates their app from the app store, restores from a backup, etc, then changes you save to the bundle will be lost, even on Mac OS.
The simulator runs under Mac OS, and is built against Mac OS frameworks and the Mac file system.
There are a fair number of differences between the sim and running on a device. This is one.
Another example: The iOS file system is always case-senstive. The simulator, which runs on Mac OS, is not case-sensitive by default. (Mac OS can read from volumes running different file systems. The default file system is not case sensitive, but you can set it up to be case-sensitive.)
The file "Foo.txt" is a different file than the file "foo.txt". They can both exist in the same directory. If your file is called "Foo.txt" and you try to load it with the string "foo.txt" it will fail on an iOS device, but work on Mac OS.
As a result, you should always test your apps on an actual device. Don't assume that if something works correctly on the sim that it's correct for an iOS device. It may not be.
The only other information I could find on this error was here, which wasn't helpful.
I get the following error when I try to save images. This seems to only happen when I have several images (~6) at once. It also seems to be completely random as to when it occurs. Sometimes everything is fine, sometimes it'll fail on 1 image, sometimes 3, and sometimes the app will completely crash in a EXC_BAD_ACCESS error.
Error: ImageIO: CGImageReadGetBytesAtOffset : ^^^ ERROR ^^^ CGImageSource was created with data size: 1144891 - current size is only: 1003855
Here is the code that saves the image:
- (void)saveWithImage:(UIImage *)anImage andFileName:(NSString *)aFileName {
NSString *subDirectory = #"Images";
NSString *fileName = [aFileName stringByAppendingString:#".png"];
NSString *documentsPath = [[CMAStorageManager sharedManager] documentsSubDirectory:subDirectory].path;
NSString *imagePath = [subDirectory stringByAppendingPathComponent:fileName];
__block NSString *path = [documentsPath stringByAppendingPathComponent:fileName];
__block NSData *data = UIImagePNGRepresentation(anImage);
self.image = anImage;
self.tableCellImage = anImage;
self.galleryCellImage = anImage;
self.imagePath = imagePath; // stored path has to be relative, not absolute (iOS8 changes UUID every run)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
if (![data writeToFile:path atomically:YES])
NSLog(#"Error saving image to path: %#", path);
dispatch_async(dispatch_get_main_queue(), ^{
});
});
}
I get that error and as a result my images aren't saved (or only half of them are saved), which completely messes up the UI display, and any subsequent app launches. I've narrowed it down to the UIImagePNGRepresentation call.
On a related note, that code locks up the UI; I think because of the UIImagePNGRepresentation call; however, as far as I know UIImagePNGRepresentation is no thread safe, so I can't do it in the background. Does anyone know a way around this?
Thanks!
In case anyone comes across a similar issue, this is what fixed it for me.
iPhone iOS saving data obtained from UIImageJPEGRepresentation() fails second time: ImageIO: CGImageRead_mapData 'open' failed
and this is the solution I used to save UIImages in a background thread:
Convert UIImage to NSData without using UIImagePngrepresentation or UIImageJpegRepresentation
I was getting this error because the api I called was throwing a 500 and returning html error page in the tmp >> NSData file I was trying to convert to PNG.
You may wish to check the file your trying to open is a image at all before conversion.
If youre downloading the file with dowloadTask then check statusCode is 200 before moving tmp > /Document/.png
heres my answer in other SO
I'm trying to display a BLOB image (get from web server using Json) in my iOS app, but when I run my application I get an empty UIimageView, here is my code :
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:encodedUrl]];
NSData *profileImage1 = [[NSData alloc] initWithBytes:[dataURL bytes] length:[dataURL length]];
UIImage *profileImage2 = [UIImage imageWithData:profileImage1];
[profilImage setImage:profileImage2];
How can I fix this problem?
[UIImage imageWithData:data] only parses known image file formats like JPEG, PNG, etc. (Full info in the decomentation). Passing blobs isn't supported by UIImage. You need to do some decoding to be able to use the data for the UIImage. You can use GMTBase.64 for encoding and decoding of data. Read the docs and other posts and you'll find out how to change your code.
Hope this helps.
I am caching an NSData object containing image data retrieved from the web. The image displays correctly before caching. When I retrieve the data object from the cache, the data can no longer be used to create a UIImage, even though the data objects are identical.
Please see the relevant snippets of my code below
NSData *webData= [NSData dataWithContentsOfURL:webPath]; //retrieve from web
UIImage *webImage = [UIImage imageWithData:webData]; //works fine
[webData writeToURL:filePath atomically:YES]; //cache
NSData *cacheData = [NSData dataWithContentsOfURL:filePath]; //get from cache
if ([cacheData isEqualToData:webData]) NSLog(#"Equal"); //Data objects are equal
UIImage *cacheImage = [UIImage imageWithData:cacheData]; //cacheImage is nil
I can fix the problem by changing the way I store my data to the cache
NSData *temp = UIImageJPEGRepresentation(webImage, 1.0):
[temp writeToURL:filePath atomically:YES];
Now the webData and cacheData are no longer equal, but cacheImage is not nil and displays properly.
EDIT - After a bit more testing, I realized I get the same problem using UIImageJPEGRepresentation as well.
Anyone know why this would be?
Thanks.
Figure out the problem was that I was trying to do all this before my view controller was fully loaded.
How do I get image data out of JSON returned by a WCF Data Service?
I've got a WCF Data Service serving some objects that include some binary data that is an image (column type in SQL Server is image). It comes across as text gibberish in the JSON. In the iOS client I'm writing for this service, I want to display this data as an image ([UIImage imageWitData:myData]).
Here is what I'm doing:
NSData *networkData = nil; //assume this magically gets data from the service
NSError *err = nil;
//assume the returned JSON has one object and is not an array
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:networkData
options:NSJSONReadingAllowFragments error:&err];
//handle error if needed
NSString *imageString = [dict objectForKey:#"Image"];
NSData *imageData = [imageString dataUsingEncoding:NSUTF8StringEncoding];
///The service is using UTF-8.
UIImage *image = [UIImage imageWithData:imageData];
Putting that image in a UIImageView doesn't show anything. What am I doing wrong?
Turns out that binary data returned from WCF Data Services is base64 encoded. I'm using the NSData-Base64 category to parse it, and it's working great. So the solution looks like this:
NSData imageData = [NSData dataFromBase64String:imageString];
When I imported those files into my project ARC threw up some errors, but I was able to solve them by removing a couple of autorelease calls in the .m file.