Corrupted Images in document directory - iphone

I am fetching URL of the images from the server and converting this images into png format using:
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(img)];
[data1 writeToFile:pngFilePath atomically:YES];
but some of the images are corrupted when i check them after completing the process on simulator.
Hence these images are not displaying on the app wherever needed.
Please see the attached image as some images are corrupted.
Update
I am calling a method in a loop which fetches the images from the server parallel and didFinishLoading I am performing this:
UIImage *img = [UIImage imageWithData:self.data];
NSArray *split = [self.strImageName componentsSeparatedByString:#"/"];
int arrCount=[split count];
NSString *imageName=[split objectAtIndex:arrCount-1];
NSString *docDirec = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pngFilePath=nil
pngFilePath = [NSString stringWithFormat:#"%#/Thumbs/%#",docDirec,imageName];
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(img)];
[data1 writeToFile:pngFilePath atomically:YES];
[self.data release]; //don't need this any more, its in the UIImageView now
self.data=nil;

i have the similar problem
i solved it using the below code
- (void)viewWillDisappear:(BOOL)animated
{
if (self.m_objWebManager != nil)//Webmanager is class for downloading the images as a background thread
{
[self.m_objWebManager cancelCommunication];
[self.m_objWebManager release];
self.m_objWebManager = nil;
}
}

Related

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;
}

Storing and retrieving images on iPhone efficiently

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

Saving in NSDocumentDirectory

Having weird problem with my NSDocumenDirectory saving.
Here is a sneak preview:
First I pick images ( in my imagePickerViewController):
in my PreviewController:
So at first try, it was okay.
Then I revisit the imagePickerViewController to add another image:
in my PreviewController:
This is where the problem occurs. At the image above, it recopies the last image from the old preview (like a duplicate). I dunno what Im doing wrong in my codes. But Im saving it when a file exist. Kindly see:
for (int i = 0; i < info.count; i++) {
NSLog(#"%#", [info objectAtIndex:i]);
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask ,YES );
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"firstSlotImages%d.png", i]];
if ([[NSFileManager defaultManager] fileExistsAtPath:savedImagePath]) {
NSLog(#"file doesnt exist");
} else {
ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullResolutionImage]];
//----resize the images
image = [self imageByScalingAndCroppingForSize:image toSize:CGSizeMake(256,256*image.size.height/image.size.width)];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:YES];
NSLog(#"saving at:%#",savedImagePath);
}
}
What I need is to just reAdd AGAIN the same image with the new one.
Same as, like the last preview.
The four images are passed in the sequence that they show in the preview, so in the first example the orange cat is third, and in the second example, the orange cat is fourth. The new image isn't saving because it is third, and you already have a file named "firstSlotImages2.png". If you re-save each image without checking if the file exists, you should get the result you are looking for.
There's a key in the media info: UIImagePickerControllerMediaURL which returns an NSURL, convert it to a string and get the the lastPathComponent. Use this as the file name to save to the directory you are saving it to. You can then save the reference to these images by saving this same file name either in an NSMutableArray, or an NSMutableDictionary

Image storage as byte code locally from XML parsing & display if it is stored Otherwise go for parsing.

I am having an app in which at the time of launcing the app XML parsing is giving Main category from URL like hp, dell, etc...I am displaying it in the Tableview.
Then on click of particular cell i can get the detail of main category means its subcategory like http://www.dealsbell.com/findcoupon.php?store=hp
Here also i am getting data properly after parsing.
But my concern over here is, in ( http://www.dealsbell.com/findcoupon.php?store=hp ) this link i am getting images.
Each particular subcategory will have a same image. So i want to do something like that the image if first time loaded from the URL then it will display image from parsing otherwise i would like to store that image as its byte code in folder / file / in any way in my device on first parsing.
If once the image is stored to the particular way in my device next time when i will go to see the subcategory it will first check this image is stored locally to my device or not.
If yes then it should go to the particular location to fetch this local image & display it to each cell otherwise will parse & display image.
I hope you are getting, what i want to ask.
Please guide me, how can this be possible & what is the way to get result.
If any example or link you can suggest, then it will be more efficient to me.
Thanks in advance.
There are probably two ways to achive this.
Get NSData out of Image and hold that in UserDefaults or database.
Dump image in application folder and pick image from that place.
So whenever you try to load image for subcatogory check at one of place and if present use that. IF in case you have stored image and if any updated image comes,then remove previous copy and store new one.
-(void) SaveImageinDocumentWithName:(UIImage*) aUIImage Name:(NSString*) aName
{
if(aUIImage)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSMutableString* str = [[NSMutableString alloc] initWithCapacity:300];
[str appendString:documentsDirectory];
[str appendString:#"/"];
[str appendString:aName];
NSFileManager *fileManager = [NSFileManager defaultManager];
[UIImagePNGRepresentation(aUIImage) writeToFile:str atomically:YES];
if(str)
{
[str release];
str = nil;
}
if(fileManager)
{
[fileManager release];
fileManager = nil;
}
[pool release];
}
}
-- Getting saved image
-(UIImage*)GetSavedImageWithName:(NSString*) aFileName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSMutableString* str = [[NSMutableString alloc] initWithCapacity:300];
[str appendString:documentsDirectory];
[str appendString:#"/"];
[str appendString:aFileName];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:str];
NSData *dataToWrite = nil;
UIImage* image = nil;
if(!success)
{
}
else
{
image = [[UIImage alloc] initWithContentsOfFile:str];
}
if(dataToWrite)
{
[dataToWrite release];
dataToWrite = nil;
}
if(str)
{
[str release];
str = nil;
}
if(fileManager)
{
[fileManager release];
fileManager = nil;
}
return image;
}
Parse dealsbell.com/wp-content/uploads/mobile/hp.gif and take only hp.gif
NSString *strImage = [NSString stringWithFormat:#"%#",aBook.image];
UIImage* image = [self GetSavedImageWithName:strImage];
if(image) // This means Image exists
{
// Do what you want
}
else
{
NSURL *url4Image = [NSURL URLWithString:strImage];
NSData *data = [NSData dataWithContentsOfURL:url4Image];
if(data != NULL)
{
image =[[UIImage alloc] initWithData:data];
[self SaveImageinDocumentWithName:image Name:strImage]; // save for future ref.
}
else
{
image =[UIImage imageNamed:#"icon.png"];
}
}

Race Condition (?) In iPhone Temp File Writing

I'm creating some temporary files in the iPad simulator. To test my file creation, I create the file and then read it back. Here's some code to show this:
-(NSString *) writeToTempFile:(UIImage*) image{
NSString *path = [self createTemporaryFile];
NSLog(#"path: %#", path);
NSData *data = UIImageJPEGRepresentation(image, 1);
[data writeToFile:path atomically:YES];
free(data);
return path;
}
-(UIImage *) readTempFile:(NSString *) path{
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:data];
return image;
}
I call these methods one after another, before a final function writes out the UIImage to the photo album.
UIImageWriteToSavedPhotosAlbum(image2, self, nil, nil);
The problem is, this always crashes my app on the third time it is executed. First and second time it successfully does all of this and stores to the album. Third time it crashes to Home. Any ideas?
NSData *data = UIImageJPEGRepresentation(image, 1);
[data writeToFile:path atomically:YES];
free(data);
The NSData returned from UIImageJPEGRepresentation is -autoreleased. There is no need to free() it. And it is wrong to free() any Objective-C objects — send a -release message instead.
Please read through the Memory Management Programming Guide.