Load UIImage from documents directory - ios

I'm trying to load a UIImage from the documents directory and set it to a UIImageView as per below:
NSString *pngfile = [[MyUtil getLocalDirectory] stringByAppendingPathComponent:#"school.png"];
NSLog(#"%#", pngfile);
if ([[NSFileManager defaultManager] fileExistsAtPath:pngfile]) {
NSData *imageData = [NSData dataWithContentsOfFile:pngfile];
UIImage *img = [UIImage imageWithData:imageData];
[schoolImage setImage:img];
}
However, whenever I try the above, the image never loads. The image is in Documents/MyAppCustomDirectory/school.png. Is the above correct to load from that directory?
I also tried a few others: UIImage imageWithContentsOfFile, among other ways based on SO responses.

To get the documents directory you should use:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *pngfile = [documentsDir stringByAppendingPathComponent:#"school.png"];
I'm not quite sure if you also need to append the 'MyAppCustomDirectory', but I don't think so.

Swift 4 Solution:
guard let documentsDirectory = try? FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor:nil,
create:false)
else {
// May never happen
print ("No Document directory Error")
return nil
}
// Construct your Path from device Documents Directory
var imagesDirectory = documentsDirectory
// Only if your images are un a subdirectory named 'images'
imagesDirectory.appendPathComponent("images", isDirectory: true)
// Add your file name to path
imagesDirectory.appendPathComponent("school.png")
// Create your UIImage?
let result = UIImage(contentsOfFile: imagesDirectory.path)

Related

How to convert video data to NSURL

I have a video I'm fetching from my server and receiving as data. I'm trying to cover the raw data into a URL so that I can use it to instantiate an AVPlayerItem and play the video on the phone. However, this code returns nil when I print "videoDataString". If I print "videoData" there is a result though. Here is my code where I try to convert, is my mistake the encoding part?
let videoDataString = NSString(data: videoData, encoding: NSUTF8StringEncoding)
let videoURL = NSURL(string: String(videoDataString))
First Save your Video data to a file then try to access that as a file URL.
Here is an example.
NSString *filePath = [self documentsPathForFileName:#"video.mp4"];
NSData *videoAsData; // your data here
[videoAsData writeToFile:filePath atomically:YES];
// access video as URL
NSURL *videoFileURL = [NSURL fileURLWithPath:filePath];
- (NSString *)documentsPathForFileName:(NSString *)name
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
return [documentsPath stringByAppendingPathComponent:name];
}
For Swift 3.0:
let filePath = self.documentsPathForFileName("video.mp4")
let videoAsData = NSData()
videoAsData.write(toFile: filePath, atomically: true)
let videoFileURL = NSURL(fileURLWithPath: filePath)
func documentsPathForFileName(name: String) -> String {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
return documentsPath.appending(name)
}
You cannot convert all strings to URL. URL is Uniform Resource Locator. That means it is a string containing the path to the file or resource in remote or local destination. If you want to keep your video data and instantiate video player with that video, first save the video data to a file, then instantiate video player with path to that file.
Use following code for this
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let videoURL = documentsURL.URLByAppendingPathComponent("video.mp4")//what ever your filename and extention
videoData.writeToURL(videoURL, atomically: true)
//uese videoURL to instantiate video player

How to save and retrieve an image in iOS(for profile picture) [duplicate]

I have a UIImageView that allows a user to place and hold an image until it can be saved. The problem is, I can't figure out how to actually save and retrieve the image I've placed in the view.
I have retrieved and placed the image in the UIImageView like this:
//Get Image
- (void) getPicture:(id)sender {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = (sender == myPic) ? UIImagePickerControllerSourceTypeCamera : UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage (UIImage *)image editingInfo:(NSDictionary *)editingInfo {
myPic.image = image;
[picker dismissModalViewControllerAnimated:YES];
}
It displays the selected image in my UIImageView just fine, but I have no idea how to save it. I'm saving all the other pieces of the view (mostly UITextfield) in Core Data. I've searched and searched, and tried many bits of code that people have suggested, but either I'm not entering the code correctly, or those suggestions don't work with the way I have my code set up. It's likely the former. I'd like to save the image in the UIImageView using the same action (a save button) I'm using to save the text in the UITextFields. Here's how I'm saving my UITextField info:
// Handle Save Button
- (void)save {
// Get Info From UI
[self.referringObject setValue:self.myInfo.text forKey:#"myInfo"];
Like I said earlier, I have tried several methods to get this to work, but can't get a grasp on it. For the first time in my life I've wanted to cause physical harm to an inanimate object, but I've managed to restrain myself.
I'd like to be able to save the image the user places into the UIImageView in the application's documents folder, and then be able to retrieve it and place it in another UIImageView for display when the user pushes that view onto the stack. Any help is greatly appreciated!
It's all good, man. Don't harm yourself or others.
You probably don't want to store these images in Core Data, since that can impact performance if the data set grows too large. Better to write the images to files.
NSData *pngData = UIImagePNGRepresentation(image);
This pulls out PNG data of the image you've captured. From here, you can write it to a file:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"image.png"]; //Add the file name
[pngData writeToFile:filePath atomically:YES]; //Write the file
Reading it later works the same way. Build the path like we just did above, then:
NSData *pngData = [NSData dataWithContentsOfFile:filePath];
UIImage *image = [UIImage imageWithData:pngData];
What you'll probably want to do is make a method that creates path strings for you, since you don't want that code littered everywhere. It might look like this:
- (NSString *)documentsPathForFileName:(NSString *)name
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
return [documentsPath stringByAppendingPathComponent:name];
}
Hope that's helpful.
Swift 3.0 version
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let img = UIImage(named: "1.jpg")!// Or use whatever way to get the UIImage object
let imgPath = URL(fileURLWithPath: documentDirectoryPath.appendingPathComponent("1.jpg"))// Change extension if you want to save as PNG
do{
try UIImageJPEGRepresentation(img, 1.0)?.write(to: imgPath, options: .atomic)//Use UIImagePNGRepresentation if you want to save as PNG
}catch let error{
print(error.localizedDescription)
}
Swift 4 with extension
extension UIImage{
func saveImage(inDir:FileManager.SearchPathDirectory,name:String){
guard let documentDirectoryPath = FileManager.default.urls(for: inDir, in: .userDomainMask).first else {
return
}
let img = UIImage(named: "\(name).jpg")!
// Change extension if you want to save as PNG.
let imgPath = URL(fileURLWithPath: documentDirectoryPath.appendingPathComponent("\(name).jpg").absoluteString)
do {
try UIImageJPEGRepresentation(img, 0.5)?.write(to: imgPath, options: .atomic)
} catch {
print(error.localizedDescription)
}
}
}
Usage example
image.saveImage(inDir: .documentDirectory, name: "pic")
This is Fangming Ning's answer for Swift 4.2, updated with a recommended and more Swifty method for retrieving the document directory path and with better documentation. Credits to Fangming Ning for the new method as well.
guard let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return
}
//Using force unwrapping here because we're sure "1.jpg" exists. Remember, this is just an example.
let img = UIImage(named: "1.jpg")!
// Change extension if you want to save as PNG.
let imgPath = documentDirectoryPath.appendingPathComponent("1.jpg")
do {
//Use .pngData() if you want to save as PNG.
//.atomic is just an example here, check out other writing options as well. (see the link under this example)
//(atomic writes data to a temporary file first and sending that file to its final destination)
try img.jpegData(compressionQuality: 1)?.write(to: imgPath, options: .atomic)
} catch {
print(error.localizedDescription)
}
Check out all the possible Data writing options here.
#pragma mark - Save Image To Local Directory
- (void)saveImageToDocumentDirectoryWithImage:(UIImage *)capturedImage {
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"/images"];
//Create a folder inside Document Directory
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder
NSString *imageName = [NSString stringWithFormat:#"%#/img_%#.png", dataPath, [self getRandomNumber]] ;
// save the file
if ([[NSFileManager defaultManager] fileExistsAtPath:imageName]) {
// delete if exist
[[NSFileManager defaultManager] removeItemAtPath:imageName error:nil];
}
NSData *imageDate = [NSData dataWithData:UIImagePNGRepresentation(capturedImage)];
[imageDate writeToFile: imageName atomically: YES];
}
#pragma mark - Generate Random Number
- (NSString *)getRandomNumber {
NSTimeInterval time = ([[NSDate date] timeIntervalSince1970]); // returned as a double
long digits = (long)time; // this is the first 10 digits
int decimalDigits = (int)(fmod(time, 1) * 1000); // this will get the 3 missing digits
//long timestamp = (digits * 1000) + decimalDigits;
NSString *timestampString = [NSString stringWithFormat:#"%ld%d",digits ,decimalDigits];
return timestampString;
}
In Swift:
let paths: [NSString?] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .LocalDomainMask, true)
if let path = paths[0]?.stringByAppendingPathComponent(imageName) {
do {
try UIImagePNGRepresentation(image)?.writeToFile(path, options: .DataWritingAtomic)
} catch {
return
}
}

Send UIImage to LocalwebServer using GCDWebServer

My app using GCDWebServer I get a photo from my iPhone album by using AssetsLibrary and I store them in NSDocumentDirectory. I just want to get access Url to this photo to show them in a web page.
There is my code :
[_webServer addHandlerForMethod:#"POST"
path:#"/"
requestClass:[GCDWebServerURLEncodedFormRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
ALAsset *asset = [self.arrayPictures objectAtIndex:0];
ALAssetRepresentation *rep = [asset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
UIImage *thumbnail = [UIImage imageWithCGImage:iref];
NSString* path ;
if (thumbnail != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [[NSString alloc] initWithString:[documentsDirectory stringByAppendingPathComponent:#"test.png"]];
NSData* data = UIImagePNGRepresentation(thumbnail);
[data writeToFile:path atomically:YES];
}
NSURL *url = [NSURL fileURLWithPath:path];
NSString* html = [NSString stringWithFormat:#"<html><body><img src=\"%#\" width=\"400\" height=\"500\"/></body></html>", url];
return [GCDWebServerDataResponse responseWithHTML:html];
}];
For DocumentDirectory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath = [[NSString alloc] initWithString:[documentsDirectory stringByAppendingPathComponent:#"test.jpg"]];
NSURL *baseURL2 = [NSURL fileURLWithPath:documentsDirectory];
NSString* html2 = [NSString stringWithFormat:#"<html><body><img src=\"%#\" width=\"400\" height=\"500\"/></body></html>", imagePath];
[_webView loadHTMLString:html2 baseURL:baseURL2];
For Bundled resource
NSString *path = [[NSBundle mainBundle] pathForResource:#"ahsan" ofType:#"jpg"]; // path to your image source.
NSURL *baseURL = [NSURL fileURLWithPath:path];
NSString* html = [NSString stringWithFormat:#"<html><body><img src=\"%#\" width=\"400\" height=\"500\"/></body></html>", path];
Try this code.
GCDWebServer* webServer = [[GCDWebServer alloc] init];
[webServer addGETHandlerForBasePath:#"/" directoryPath:[[NSBundle mainBundle] bundlePath] indexFilename:nil cacheAge:3600 allowRangeRequests:YES];
[webServer runWithPort:8080];
Looks like nobody is answering the actual question here: this is not about uploading a photo from iOS to a web server or viewing it in a local UIWebView, but about serving that photo using GCDWebServer so that users can view it by connecting to the device using a web browser e.g. by going to http://my-device.local/photo-1234.jpg.
The sample code you provided has 2 major issues:
You are creating a handler for POST requests while you need to handle GET requests (POST is when submitting forms from web browsers, while GET is for regular web browsing and getting web pages).
Instead of returning the image data, you are returning an HTML webpage, which contains a URL to the image file locally (e.g. file:///some/path/photo-1234.jpg) instead of HTTP URL handled by GCDWebServer (e.g. http://my-device.local/photo-1234.jpg). File URLs do not make sense outside of the device itself and will not work.
If you have all the photos as files in your documents folder, you can simply add a GET handler to GCDWebServer to serve the contents of the entire documents folder:
[webServer addGETHandlerForBasePath:#"/"
directoryPath:<PATH_TO_DOCUMENTS_DIRECTORY>
indexFilename:nil
cacheAge:3600
allowRangeRequests:YES];
This is not a very good solution though, as it requires copying photos from the assets library into the documents folder, which is wasteful. Instead, consider dynamically serving the photo assets as I explain in my answer to a related question here: https://stackoverflow.com/a/31778726/463432.
You can create one GET request which will return all custom URLs of the photo assets.
After that create one handler of that custom URLs which will return requested URL image Data.
In a custom URL handler use below code
//Get PHAsset image name with extionsion.
let filename = NSURL(string: (asset as! PHAsset).originalFilename!)
// Retrive image data from PHAsset object
PHImageManager.default().requestImageData(for: asset as! PHAsset, options: nil, resultHandler: { (imageData, str, nil, info) in
//Check imageData is nil or not.
if (imageData) {
//Return image Data with contentType
let imageDatas = UIImagePNGRepresentation(imageData)
completionBlock!(GCDWebServerDataResponse(data: imageDatas, contentType: "image/\((filename?.pathExtension)!)"))
} else {
// Image retrive error message return.
let jsonResponse = ["type":"failed","Message":"Image not avilable."] as [String : Any]
completionBlock!(GCDWebServerDataResponse(jsonObject: jsonResponse))
}
})
// MARK:- Get File name from PHAsset.
extension PHAsset {
var originalFilename: String? {
var fname:String?
if #available(iOS 9.0, *) {
let resources = PHAssetResource.assetResources(for: self)
if let resource = resources.first {
fname = resource.originalFilename
}
}
if fname == nil {
// this is an undocumented workaround that works as of iOS 9.1
fname = self.value(forKey: "filename") as? String
}
return fname
}
}

How can I get the file path from a UIImage?

Usually it's the other way around, you use the path to display the image. I was wondering if you can get the path if you already have the image.
if you already have the image i.e. have added the file to your resources, you can use this to get the file path;
NSString *string = [[NSBundle mainBundle] pathForResource:#"IMAGE_FILE_NAME" ofType:#"jpg"]; // or ofType:#"png", etc.
I don't believe it is possible to get it directly from UIImage.
Best way is to save the image in a directory, then you will have the file path.
//image is your UIImage;
if (image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
#"test.png" ];
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
}
path will be your filepath.
Once a UIImage is created, the image data is loaded into memory and no longer connected to the file on disk. As such, the file can be deleted or modified without consequence to the UIImage and there is no way of getting the source path from a UIImage.

iOS - Saving multiple images to Documents folder

I have this code this code to save an image to the Documents folder.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *image = imageView.image; // imageView is my image from camera
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
I am looking for a way to be able to save multiple images as this one keeps over writing the savedImage.png name.
I do not mind looking for it on google or whatever, but I need to know what it is called, since looking with the wrong keywords really delays the world:-)
Cheers
You need to change the file name that you are appending to the image documentsDirectory path on line three. Each time you'll need to use a different name that isn't already used. NSFileManager has methods to see if a file exists so you can construct a file name and then test if it exists in that location and if so, increment your duplicate count and try the next one.
if num is an integer you define somewhere and keep around so you know the last one you thought you used (and that you've initialized to 1 somewhere).
// your code to get the directory here, as above
NSFileManager *fm = [NSFileManager ...]
do {
savedImagePath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat: #"%#-%d.png", #"savedImage", num]];
num += 1; // for next time
if ( ![fm fileExistsAtPath: savedImagePath] )
{
// save your image here using savedImagePath
exit;
}
} while ( //some kind of test for maximum tries/time or whatever )
you'll have to look up the syntax to get an NSFileManager instance and the exact file exists method signature, but that's the gist of it.
If you save file with current dateTime you don't need to worry about same name override problem
-(NSString*)getCurrentDateTimeAsNSString
{
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"yyyyMMddHHmmss"];
NSDate *now = [NSDate date];
NSString *retStr = [format stringFromDate:now];
[format release];
return retStr;
}
you can create a new file each time to do that.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"YOURiMAGEfILE.IMAGEeXTENSION"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat: #"YOURiMAGEfILE.IMAGEeXTENSION] ];
}
and then you can perform your above operations on the created file.
Hope it help You Working For me!!
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage
{
let i = Int(arc4random())
let str = String(i).appending(".png")
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(str)
print(paths)
let imageData = UIImagePNGRepresentation(image)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
}
else{
print("error")
}

Resources