Rotation of images stored in documents directory - ios

I have written an app that allows the user to take photos which are stored in an NSArray and which are then saved in the Documents directory. When they are reloaded the pictures are stored in an UITableView - note only one photo is currently loaded due to problem 1.
I have two problems:
1 - This works but only for one photo as I need to be able work out how many photos have been stored.
2 - When I reload the data and put into an UIImageView the rotation of the photos is incorrect. Landscape photos are upside down and portrait photos are landscape.
Any help with either of these issues greatly appreciated.
Saving the photos
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
for (int i=0;i<photoCount;i++)
{
UIImage *image = [photos objectAtIndex:i];
NSString *savePicturePath = [saveFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:#"image_%d",i]];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savePicturePath atomically:NO];
}
Retrieving the photos
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getPicPath = [documentsDirectory stringByAppendingPathComponent:#"image_0"];
NSData *picData = [[NSFileManager defaultManager] contentsAtPath:getPicPath];
UIImage *loadedImage = [UIImage imageWithData:picData];
[photos addObject:loadedImage];
[self.tableView reloadData];
Adding image to table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"photoCell"];
UIImage *currentImage = [self.photos objectAtIndex:indexPath.row];
cell.imageView.image = currentImage;
return cell;
}

You could solve the first issue by creating your own directory and storing all images to that directory. Then when you read use NSFileManager's contentsOfDirectoryAtPath to get an array of all the images in that directory. Or you could read the content of the documents folder and use NSPredicate to filter out only images by file extension (using filteredArrayUsingPredicate).
As for the rotation issue, the answer is available here.

The rotation issue ... simple:
Change
NSData *imageData = UIImagePNGRepresentation(image);
to
NSData *imageData = UIImageJPGRepresentation(image, 1.0);
And everything is perfect. Thanks to Joel for pointing me in the right direction.

Related

Convert a downloaded image to in-memory static image -IOS

My scenario goes in this way. At the start of application a list of images will be downloaded from server & once downloaded all images will be converted into the static images and onwards will be using those static images everywhere in application. I think in android this thing can be achieved using BITMAP. (Not confirm).
Currently i'm using SDWEBIMAGE library for downloading and caching images. But i don't want to use this library anymore. I just want to download all images once and then everywhere i want to add below code snippet for displaying downloaded images.
[ImageView setImage:[UIImage imageNamed:#"DownloadedImageName"]];
Is there any way to get this thing done in ios?
You have to download each Image and save it into "Documents" Directory, and then whenever you need them use that.
For saving image into documents directory, use code like this:
- (IBAction)saveImage:(UIImage*)img {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
NSData *imageData = UIImagePNGRepresentation(img);
[imageData writeToFile:savedImagePath atomically:NO];
}
And for getting and show image on imageview, use this code:
- (UIImage*)getImage
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
return img;
}
[UIImage imageNamed:] method is only for getting images that already exist in your app bundle. So if you have dynamic content that is downloaded from internet, you cannot use this method. Rather, create your own method to load the images from sandbox Documents folder.

Image written through WriteToFile command is missing after app rerun

I am writing an app which downloads image from my server and stores them locally for offline viewing. The codes I use to store the image locally are shown below. Apart from storing the image, I am also able to read the image from the path (which I stored separately).
However when I re-run my code from Xcode to the iPhone (without uninstalling the app from the phone), the stored image file would be missing. Is this expected? Would I face similar issue when my app has been released on App Store and when the user updates the app? Is there a way to keep the file persistent when I re-run them when I update some codes in Xcode?
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"file.jpeg",]];
if (![imageData writeToFile:imagePath atomically:YES])
{
// Handling when there is an error
NSLog(#"Failed to store file at path %#",imagePath);
stored.text = #"";
}
else
{ // Handling when write is successful
NSLog(#"Imaged stored path is %#",imagePath);
stored.text = imagePath;
}
[imageView setImage:image];
The code to read the image is shown below:
NSString *imagePathToRead = stored.text;
NSLog(#"Retrieve image from %#",imagePathToRead);
UIImage *image = [UIImage imageWithContentsOfFile:imagePathToRead];
[imageView setImage:image];
I am posting the answer here from rmaddy which solved the issue I was facing. I am posting here so that others can benefit if they are facing similar issue.
For the storing portion:
The stored.text should never store the full path:
stored.text = imagePath;
Instead I should store #"file.jpeg" only.
For the Read portion:
I should always regenerate the full path below when I wanted to read the path instead of the code below:
NSString *imagePathToRead = stored.text;
The corrected codes are:
NSString *imagePathToRead = stored.text;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:imagePathToRead]];
NSLog(#"Retrieve image from %#",imagePath);
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
This solved the issue and the image is able to be read even though the app is re-installed through Xcode.

Image not showing in my UICollectionView

So I've been looking for a solution to this issue, but can't seem to find anything. I have an array that I load with image paths using the below method
- (IBAction)btnPictures:(id)sender {
// Create the next view controller.
ImageGalleryViewController *galleryViewController = [[ImageGalleryViewController alloc] initWithNibName:#"ImageGalleryViewController" bundle:nil];
// Search for paths and get users home directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
// get path at first index (in case multiple returned
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSArray *files = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"pathExtension IN %#", #"png"]];
// Pass the selected object to the new view controller.
[galleryViewController setImageArray:files];
// Push the view controller.
[self.navigationController pushViewController:galleryViewController animated:YES];
}
That image array is then sent to the below method in my UICollectionViewController
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
ImageGalleryViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ImageGalleryViewCell" forIndexPath:indexPath];
NSLog(#"Image at index %#", [imageArray objectAtIndex:indexPath.row]);
[cell.galleryImage setImage:[UIImage imageWithContentsOfFile:[imageArray objectAtIndex:indexPath.row]]];
[cell setBackgroundColor:[UIColor whiteColor]];
return cell;
}
I verified the objectAtIndex is returning a valid image name through my NSLog, but for some reason the cell is not displaying it.
Any help is greatly appreciated, thanks in advance.
The array returned by -contentsOfDirectoryAtPath: of NSFileManager doesn't provide the full file path but just the name of files and directories. You have to append each values in the array to the path to your Document Directory.
Something like this:
NSString *documentsDirectoryPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *imagePath = [documentsDirectoryPath stringByAppendingPathComponent:[imageArray objectAtIndex:indexPath.row]];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
I suspect, you are not initialising any cells before using (dequequing) one. Initialise your cell, and try again. Good Luck!
PS: by initialising I mean, alloc init your cell.

Loading from file not working.

I'm taking screenshots and writing them to file with this code:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
NSArray *directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [directories objectAtIndex:0];
NSString *key = [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
NSMutableArray *storageArray = [NSMutableArray arrayWithContentsOfFile:key];
if(!storageArray)
storageArray = [NSMutableArray arrayWithObject:data];
else
[storageArray addObject:data];
[storageArray writeToFile:key atomically:YES];
When i load the images again i do this:
pics = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];
ScreenshotViewController *scv = [[ScreenshotViewController alloc]init];
[[self navigationController]pushViewController:scv animated:YES];
NSInteger row = indexPath.row;
[scv setImage:[pics objectAtIndex:row]];
dataFilePath method:
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
}
The problem is that that the UIImageView, in the ScreenshotViewController remains blank. I have tested all kinds of things, and it is something about the way the images get saved/loaded into the array, but i'm not sure. I have also tested that the actual screenshot part is working by putting it into a UIImageView right away and adding it to the view.
NOTE:
If i change this
[scv setImage:[pics objectAtIndex:row]];
to this
[scv.myUIImageView setImage:[pics objectAtIndex:row]];
i get this exception: [__NSCFData _isResizable]: unrecognized selector sent to instance 0x847a280.
Whats the correct way of setting the image by?
Wow it got abit messy, hope its readable.
At first glance, and assuming your read/write code is correct, you are saving the image with PNG representation.
Thus, when reading, you will need to create a UIImage like this:
UIImage * myPic = [UIImage imageWithData:[pics objectAtIndex:row]];
Then try showing that image

Creating image thumbnails to be loaded into tableview from files in app directory

I need some help for a problem which I can't solve but I think I am close to the solution. Here is it:
In a version of my app, I was able to populate a tableview (in CellforRowAtIndexPath) with images taken from the Assetlibrary using the following 2 lines:
ALAsset someAsset = [theAssets objectAtIndex:indexPath.row];
[cell.imageView setImage:[UIImage imageWithCGImage:[someAsset thumbnail]]];
Now, I am trying to read image files from the directory and stored in an NSMutableArray. I can see the filenames when I NSLog the NSMutableArray. But how do I now cause the files to be converted into images and displayed in my tableview in the same way I did why using the Assetlibrary? I have tried several times, but the app either crashes or it does not show the image thumbnails in the table view. For example, this statement does not display the image but the app does not crash:
UIImage *anImage = [UIImage imageWithContentsOfFile:[self.listTable objectAtIndex:0]];
When I setImage in the next line, it doesn't work. Someone please help!
UPDATED: The contents of self.listable when I NSLog it is something like this: "19-10-25 276-10-12.jpg",
"19-10-37 276-10-12.jpg",
"19-10-54 276-10-12.jpg",
"19-10-65 276-10-12.mov", etc.
When I NSLog my documents directory, it is: /var/mobile/Applications/8CB1368A-AAE2-4815-BD26-A7B7C8536193/Documents.
Apps can only imageWithContentsOfFile for files located within the app's sandbox (e.g. in Documents, the bundle, etc.) If these files are located in your Documents folder, you get the full path via:
NSString *documentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *imageFullPath = [documentsFolder stringByAppendingPathComponent:imageFilename];
You can then use that in imageWithContentsOfFile.
Update:
You asked:
my directoryContents is an NSArray; how do I convert it to NSString and then [documentsFolder stringByAppendingPathComponent ...] and store each fullpath in the NSMutableArray?
You might do something like:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSArray *filenames = [fileManager contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSMutableArray *paths = [[NSMutableArray alloc] initWithCapacity:[filenames count]];
for (NSString *filename in filenames)
{
[paths addObject:[documentsDirectory stringByAppendingPathComponent:filename]];
}
NSLog(#"%s filenames = %#", __FUNCTION__, filenames);
NSLog(#"%s paths = %#", __FUNCTION__, paths);

Resources