I am working on application in which I store data of image into database like
NSString *query = [NSString stringWithFormat:#"INSERT INTO Friends_user (f_id,f_name,f_image,f_mobile) VALUES('%ld','%#','%#','%#')",(long)id_, self.txt_name.text,[UIImagePNGRepresentation(self.img_userprofile.image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength], self.txt_mobile_no.text ];
It stores Successfully but when I retrieve that data to display image, Memory Increases with every image. Here is my code to retrieve data
NSData *data = [[NSData alloc]initWithBase64EncodedString:[[arr_friendList objectAtIndex:indexPath.row] objectAtIndex:2] options:NSDataBase64DecodingIgnoreUnknownCharacters];
img_friend_profile.image= [UIImage imageWithData:data];
[theAppDelegate.dbManager executeQuery:query];
My Datatype in database is BLOB.
Memory increases Upto 10-20 MB per image. Please Help me with it
Thank you
Related
I am working in project in which I store string of image data to database by using this library https://github.com/bborbe/base64-ios/tree/master/Base64.
So when I get that image field I decode that data and shows image
My code to encode Image data
imageData = UIImageJPEGRepresentation(self.img_user_profile.image, 0.4);;
NSString *strEncodeImg = [Base64 encode:imageData];
My code to decode image data
NSData *str = [Base64 decode:[[arr_user_info valueForKey:#"image"] objectAtIndex:0]];
_img_user.image =[UIImage imageWithData:str];
My problem is When I get data string from database and load image in imageview, Memory increases with every image.
Please help me with it
Instead of declaring the attribute as NSString you can declared that as NSData. Now you can directly store the imageData into core data. When fetching you can use imageData directly to load the image
I am saving a UIImage to NSMutableArray. After saving, i am talking the object from array and not getting previous memory.
[self.arrselectedPhotos addObject:[UIImage imageWithData:imageData]];
Currently the size is 191565 (192KB). But when i am taking it from array, the size shows 768786 (750KB+).
UIImage *img=[self.arrselectedPhotos lastObject];
NSLog(#"image size: %lu", (unsigned long)[UIImageJPEGRepresentation(img , 1.0) length]);
What is the problem ?
After 3 days of random R&D, i find out the issue of increasing memory size. I was saving the NSData into array after converting it another image. This is the reason. If i save the NSData directly then everything is ok.
This line is wrong:
[self.arrselectedPhotos addObject:[UIImage imageWithData:imageData]];
And the correct line is:
[self.arrselectedPhotos addObject:imageData];
So i can save it furthur easily.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.arrselectedPhotos];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:self.course_name];
[[NSUserDefaults standardUserDefaults] synchronize];
I have a big table in SQLite where photos are stored with good resolution so they have a big sizeā¦ so I am trying to resize these images and updating the DB table in the same process. I am using FMDB wrapper for working with SQLite DB.
Well, with instruments I can see NSData and UIImage is not being released and memory grows quickly so it makes my app close.
What could I do?
Here it is the code:
FMResultSet *aFMResultSet = [database executeQuery:#"SELECT id, image FROM Images WHERE LENGTH(image)> 1000000;" ];
while([aFMResultSet next]){
int aId = [aFMResultSet intForColumn:#"id"];
NSData *aDataImage = [aFMResultSet dataForColumn:#"image"];
UIImage* aImage = [UIImage imageWithData:aDataImage];
UIImage *aResizedImage = [Utils resizedImage:aImage withRect:CGRectMake(0, 0, 324, 242)]; //(2592x1936)/16
NSData *aDataResizedThumbnail = UIImageJPEGRepresentation(aResizedImage,0.5f);
[database executeUpdate:#"UPDATE Images SET image = ? WHERE id = ?;", aDataResizedThumbnail, [NSNumber numberWithInt:aId],nil];
}
Due to the loop, the system might never get a chance to free the memory not needed anymore.
To force the system to do so, wrap the inside of your loop in an autoreleasepool, like this:
FMResultSet *aFMResultSet = [database executeQuery:#"SELECT id, image FROM Images WHERE LENGTH(image)> 1000000;" ];
while([aFMResultSet next]){
int aId = [aFMResultSet intForColumn:#"id"];
#autoreleasepool {
NSData *aDataImage = [aFMResultSet dataForColumn:#"image"];
UIImage* aImage = [UIImage imageWithData:aDataImage];
UIImage *aResizedImage = [Utils resizedImage:aImage withRect:CGRectMake(0, 0, 324, 242)]; //(2592x1936)/16
NSData *aDataResizedThumbnail = UIImageJPEGRepresentation(aResizedImage,0.5f);
[database executeUpdate:#"UPDATE Images SET image = ? WHERE id = ?;", aDataResizedThumbnail, [NSNumber numberWithInt:aId],nil];
}
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I need to store and retrieve images in my app, I first thought of doing it like so:
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];
NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];
But I read this isn't the recommended way. What is the best approach for this?
(I know there are duplicates of this question, but I haven't understood how to do it yet)
The best way to store images depends on what your app does.
If you have 100k+ images you probably want to save it manually to the iphone's hard disk over coredata since it will load images faster this way.
However, if you have less than that, then storing images as binary data in core data is what I would recommend.
The benefits of using coredata vs the file system:
Better iCloud Sync Support
No need to manage images on the hard disk as well as what ever you use as a 'persistence store' (coredata/nsuserdefaults/custom)
You can tie images to other data such as name, created date, ect.
Some interesting performance info with filesystem vs coredata: http://biasedbit.com/filesystem-vs-coredata-image-cache/
You'd have to take the data from UIImageJPEGRepresentation() and store it in an NSData object or some such in order for it to be "plist-serializable" to store in NSUserDefaults, but as others have said, you're much better off storing the image as an image file on the file system somewhere and storing the file path or file URL in NSUserDefaults.
Save the image in the Documents directory, then save the file name in a database (Core Data perhaps), another file format or NSUserDefaults.
NSUserDefaults is not really a great way to store app data.
From a UIImage instance get the data with
UIImagePNGRepresentation() or UIImageJPEGRepresentation(). Then save the data to a file. Use imageWithContentsOfFile: to recover the UIImage.
To obtain the path to the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
The easiest way for you is to directly save the content to your iOS Device and store the path in the NSUserDefaults.
First convert the image to a file and save it to the phone.
UIImage *image = // your image
NSData *pngImageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
NSString *fileName = [NSString stringWithFormat:#"%#/imageName.png",
documentsDirectory];
[pngImageData writeToFile:fileName atomically:YES];
Some are against storing filePaths in NSUserDefaults because, you're not suppose to store anything in NSUserDefaults that is super dynamic, you're suppose to store things like session keys, or token values, user names even, things that don't change often or are very strict.
The suggestion is, if you absolutely refuse CoreData, to make a property list and store the string name there.
To store your imagePath in a plist you would do the following:
NSString *textPath = [[NSBundle mainBundle] pathForResource:#"propertyListName" ofType:#"plist"];
NSDictionary *thisDict = [NSDictionary dictionaryWithContentsOfFile:textPath];
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:thisDict];
mutableDictionary[#"key"] = fileName;
[mutableDictionary writeToFile:resultsPath atomically:YES];
To retrieve your image from a plist you would do the following
NSString *textPath = [[NSBundle mainBundle] pathForResource:#"propertyListName" ofType:#"plist"];
NSDictionary *thisDict = [NSDictionary dictionaryWithContentsOfFile:textPath];
NSString *imagePath = thisDict[#"key"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
UIImage *myImage = [UIImage imageWithData:imageData];
Do not use this NSUserDefaults option for it is wrong, but if you wanted to, this is how you would do it.
[[NSUserDefaults standardUserDefaults] setObject:fileName forKey:#"key"];
[[NSUserDefaults standardUserDefaults] synchronize];
now it's saved easily for you to retrieve. When you want to retrieve the image.
NSString *filePath = [[NSUserDefaults standardUserDefaults] objectForKey:#"key"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
UIImage *myImage = [UIImage imageWithData:imageData];
then use myImage as the image. Remember the key must be the same when setting and retrieving.
The best way to store images depends on what your app does.
If you have 100k+ images you probably want to save it manually to the iphone's hard disk over coredata since it will load images faster this way.
However, if you have less than that, then storing images as binary data in core data is what I would recommend.
The benefits of using coredata vs the file system:
Better iCloud Sync Support
No need to manage images on the hard disk as well as what ever you use as a 'persistence store' (coredata/nsuserdefaults/custom)
You can tie images to other data such as name, created date, ect.
Some interesting performance info with filesystem vs coredata: http://biasedbit.com/filesystem-vs-coredata-image-cache/
I'm trying to display an image from my Database.
This part works nicely.
I save the image in the DB like this :
UIImage *resizedImg = [Generics scaleImage:self.photo.image toResolution:self.photo.frame.size.width and:self.photo.frame.size.height];
NSData *imgData = UIImageJPEGRepresentation(resizedImg, 0.9);
NSString *stringDataImage = [NSString stringWithFormat:#"%#",imgData];
[dict setObject:stringDataImage for key#"image"];
// POST Request to save the image in DB ...
Now when I try to load the image and set it into my UIImageView I do this way :
NSData *data = [[[MyUser sharedUser] picture] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:data]];
Or
NSData *data = [[[MyUser sharedUser] picture] dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
self.imageView.image = [UIImage withData:data];
But this doesn't work.
data is not equal to imgData, I think it's the encoding but I can find the good one.
And [UIImage withData:data] return nil;
Can you help me?
EDIT :
Convert and save
UIImage *resizedImg = [Generics scaleImage:self.photo.image toResolution:self.photo.frame.size.width and:self.photo.frame.size.height];
NSData *imgData = UIImageJPEGRepresentation(resizedImg, 0.9);
[dict setObject:[imgData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength] forKey:#"image"];
Load the image
NSData *data = [[NSData alloc] initWithBase64EncodedData:[[MyUser sharedUser] picture] options:kNilOptions];
NSLog(#"%#", data);
self.image.image = [UIImage imageWithData:data];
You are converting the NSData to a string and saving that to your database. Two issues:
Your choice of using the stringWithFormat construct is an inefficient string representation of your data (resulting in string representation that is roughly twice the size). You probably want to use base64 (for which the string representation is only 33% larger).
You are saving your string representation, but never converting it back to binary format after retrieving it. You could write a routine to do this, but it's better to just use established base64 formats.
If you want to save the image as a string in your database, you should use base64. Historically we would have directed you to one of the many third party libraries (see How do I do base64 encoding on iphone-sdk?) for converting from binary data to base64 string (and back), or, iOS 7 now has native base 64 encoding (and exposes the private iOS 4 method, in case you need to support earlier versions of iOS).
Thus to convert NSData to NSString base64 representation:
NSString *string;
if ([data respondsToSelector:#selector(base64EncodedStringWithOptions:)]) {
string = [data base64EncodedStringWithOptions:kNilOptions]; // iOS 7+
} else {
string = [data base64Encoding]; // pre iOS7
}
And to convert base64 string back to NSData:
NSData *data;
if ([NSData instancesRespondToSelector:#selector(initWithBase64EncodedString:options:)]) {
data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions]; // iOS 7+
} else {
data = [[NSData alloc] initWithBase64Encoding:string]; // pre iOS7
}
If you really want to turn binary data into a string you should be using base64 encoding. Luckily for you, NSData now supports Base64 natively
So you could get your string from data with:
NSString *stringDataImage = [imgData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
And you could turn this back into NSData with:
NSData *imgData = [[NSData alloc] initWithBase64EncodedString:stringDataImage options:kNilOptions];