I want to make an app, where the user fills out some kind of form, and attaches an image to it. The user picks a picture form the gallery (using UIImagePickerController). I already know how to display the image on the screen with info[UIImagePickerControllerOriginalImage] as? UIImage.
I want to make a file which will be used next time the app is opened, so the same image can be displayed with the notes. So preferably I want to save the path to the file so the next time I simply open it with UIImage(contentsOfFile: path). How can I get this path?
Some not so interesting code I have so far:
#IBAction func chooseFromGallery(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum){
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum;
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
dismissViewControllerAnimated(true, completion: nil)
self.image.image = info[UIImagePickerControllerOriginalImage] as? UIImage // This works
self.imagePath = // What goes here?
println(self.imagePath)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
Edit
After some reading I found out that there is no way of getting the path to an image which is saved outside the applications sandbox. So everybody looking for the same thing, stop, and use Bluehounds answer.
For more information about how files are handled in iOS (and OS X) read: https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
A good place to store images is the documents directory. You can save to it and then retrieve images from it. I use these UIImage extensions for saving and retrieving images:
extension UIImage {
func save(fileName: String, type: String) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
if type.lowercaseString == "png" {
let path = "\(documentsPath)/\(fileName).\(type)"
UIImagePNGRepresentation(self).writeToFile(path, atomically: true)
} else if type.lowercaseString == "jpg" {
let path = "\(documentsPath)/\(fileName).\(type)"
UIImageJPEGRepresentation(self, 1.0).writeToFile(path, atomically: true)
} else {
}
}
convenience init?(fileName: String, type: String) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let path = "\(documentsPath)\(fileName).\(type)"
self.init(contentsOfFile: path)
}
}
Using this, I can store a file name rather than the entire path of an image using some data storing method such as Core Data.
Use:
someImage.save("SomeName" , type: "png")
if let image = UIImage(fileName: "SomeName", type: "png") {
}
Here is How you can save your image
- (IBAction)saveImage {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *image = imageView.image; // imageView is where you are displaying image after selecting one from UIImagePicker
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
You may fetch back this image like this
- (IBAction)getImage {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
}
Update :
I believe that you title for question implies a bit differently. Coming back to your question, If you are planning to use only one image all the time, you can have a single image name and use it. This will override the earlier saved image at all times.
Else another option could be creating a simple plist or db and use the image along with timestamp to uniquely identify each image.
Swift Code to Save Image:
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
let image = ***YOUR IMAGE***
let writePath = dirPath.stringByAppendingPathComponent("Image2.png")
UIImagePNGRepresentation(image).writeToFile(writePath, atomically: true)
}
}
}
To get the image can be very easliy relate from the same
Related
My goal (besides learning how to write an iOS app extension) is to allow a user to share an image using the share button from a variety of apps including Photos and automatically rename them. Lastly then I want to save the image to the "documents" folder of the app for further use.
I'm having some problems trying to get the actual didSelectPost portion working since it seems that, unlike Objective-C examples I've seen, the loadItem operation returns a NSURL instead of an UIImage. When attempting to copy the NSUrl to my apps documents folder I get an error:
Error Domain=NSCocoaErrorDomain Code=260 "The file “IMG_0941.JPG”
couldn’t be opened because there is no such file."
UserInfo={NSFilePath=file:///var/mobile/Media/PhotoData/OutgoingTemp/B79263E5-9512-4317-9C5D-817D7EBEFA9A/RenderedPhoto/IMG_0941.JPG,
NSUnderlyingError=0x283f89080 {Error Domain=NSPOSIXErrorDomain Code=2
"No such file or directory"}}
This happens when I push the share button on a photo in the "photos" app, tap my extension and then press the "post" button.
I get the same error regardless if it's running in a simulator or real device.
Here's my hacked together progress so far:
override func didSelectPost() {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
let inputItem = extensionContext?.inputItems.first as! NSExtensionItem
let attachment = inputItem.attachments!.first!
if attachment.hasItemConformingToTypeIdentifier(kUTTypeJPEG as String) {
attachment.loadItem(forTypeIdentifier: kUTTypeJPEG as String, options: nil) { data, error in
var image: UIImage?
if let someUrl = data as? NSURL {
do {
// a ends up being nil in both of these cases
let a = NSData(contentsOfFile: someUrl.absoluteString!)
image = UIImage(data: a as! Data)
// let a = try Data(contentsOf: someUrl)
// image = UIImage(contentsOfFile: someUrl.absoluteString)
} catch {
print(error)
}
} else if let someImage = data as? UIImage {
image = someImage
}
if let someImage = image {
guard let compressedImagePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("theimage.jpg", isDirectory: false) else {
return
}
let compressedImageData = someImage.jpegData(compressionQuality: 1)
guard (try? compressedImageData?.write(to: compressedImagePath)) != nil else {
return
}
} else {
print("Bad share data")
}
}
}
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
Notice I'm casting the img variable as an NSURL. I've tried to cast it as a UIImage but that throws an exception.
I have some other things I'd like to do to the image, like read it's EXIF data but for now this is what I have. Any suggestions would be great as I'm really struggling to wrap my head around and learn this environment.
Similar but unsuccessful posts I've tried, notice they are all Objective-C:
iOS Share Extension issue when sharing images from Photo library
Share image using share extension in ios8
How to add my app to the share sheet action
[edit] Matched the layout of one of the better answers, still with no luck.
I have review your code and there is some mistake in the code. I have fixed it .
Replace your code with it
func share() {
let inputItem = extensionContext!.inputItems.first! as! NSExtensionItem
let attachment = inputItem.attachments!.first as! NSItemProvider
if attachment.hasItemConformingToTypeIdentifier( kUTTypeImage as String) {
attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: [:]) { (data, error) in
var image: UIImage?
if let someURl = data as? URL {
image = UIImage(contentsOfFile: someURl.path)
}else if let someImage = data as? UIImage {
image = someImage
}
if let someImage = image {
guard let compressedImagePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("shareImage.jpg", isDirectory: false) else {
return
}
let compressedImageData = UIImageJPEGRepresentation(someImage, 1)
guard (try? compressedImageData?.write(to: compressedImagePath)) != nil else {
return
}
}else{
print("bad share data")
}
}
}
}
I have the same issue. The solution I was able to implement:
Get URL to image. This URL is useless because I got 260 error when try to load image using this URL. Interesting that this comes after some recent updates because it works before
Get file name with extension from this URL
Iterate over all images in user's photo library and find the image name == name from ULR
Extract the image data
- (void)didSelectPost {
for (NSItemProvider* itemProvider in ((NSExtensionItem*)self.extensionContext.inputItems[0]).attachments ) {
// get type of file extention (jpeg, file, url, png ...)
NSArray *registeredTypeIdentifiers = itemProvider.registeredTypeIdentifiers;
if ([itemProvider hasItemConformingToTypeIdentifier:registeredTypeIdentifiers.firstObject]) {
[itemProvider loadItemForTypeIdentifier:registeredTypeIdentifiers.firstObject options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSData *imgData;
NSString* imgPath = ((NSURL*) item).absoluteString;
if(imgPath == nil)
imgPath = [NSString stringWithFormat:#"%#", item];
NSCharacterSet* set = [NSCharacterSet URLHostAllowedCharacterSet];
NSString* imgPathEscaped = [imgPath stringByAddingPercentEncodingWithAllowedCharacters:set];
NSString* fileName = [imgPath lastPathComponent];
NSError* error2 = nil;
//try load from file path
__block NSData* data2 = [NSData dataWithContentsOfFile:imgPath options: NSDataReadingUncached error:&error2];
if(data2 == nil) //try load as URL
data2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgPath] options: NSDataReadingUncached error:&error2];
if(data2 == nil) //all failed so try hacky way
{
NSString* searchFilename = [fileName lowercaseString];
PHFetchResult *results = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
[results enumerateObjectsUsingBlock:^(PHAsset *obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray* resources = [PHAssetResource assetResourcesForAsset:obj];
NSString* fileName2 = [NSString stringWithFormat:#"%#", ((PHAssetResource*)resources[0]).originalFilename].lowercaseString;
if ([fileName2 isEqual:searchFilename])
{
NSLog(#"found %#", fileName2);
PHImageManager* mgr = [PHImageManager defaultManager];
PHImageRequestOptions * options = [PHImageRequestOptions alloc];
options.synchronous = YES;
[mgr requestImageDataForAsset:obj options:options resultHandler:^(NSData * _Nullable imageData33, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info)
{
//imageData33 is your image
data2 = imageData33;
}];
}
}];
}
}];
}
}
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
[self.extensionContext completeRequestReturningItems:#[] completionHandler:nil];
}
func getPhotofolder() -> String{
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("hsafetyPhoto")
if !fileManager.fileExists(atPath: paths){
try! fileManager.createDirectory(atPath: paths, withIntermediateDirectories: true, attributes: nil)
}else{
print("Already dictionary created.")
}
return paths
}
func saveImageDocumentDirectory(photo : UIImage, photoUrl : String) -> Bool{
let fileManager = FileManager.default
let paths = Utility.getPhotofolder().stringByAppendingPathComponent(pathComponent: photoUrl)
print("image's path \(paths)")
if !fileManager.fileExists(atPath: paths){
print("file already exits \(paths)")
let imageData = UIImageJPEGRepresentation(photo, 0.5)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
if !fileManager.fileExists(atPath: paths){
return false
}else{
return true
}
}else{
print(paths)
let imageData = UIImageJPEGRepresentation(photo, 0.5)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
if !fileManager.fileExists(atPath: paths){
return false
}else{
return true
}
}
}
func showimage(image_name : String) {
let documentsUrl = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let imgUrl = documentsUrl.appendingPathComponent(image_name)
if(FileManager.default.fileExists(atPath:imgUrl.path))
{
do {
let data = try Data(contentsOf:imgUrl)
self.imageView.image = UIImage(data:data)
}catch {
print(error)
} } else{
self.imageView.image = UIImage(named:"default.jpg") //Display any default image
}
}
I am getting a photo's URL using requestContentEditingInput using the PHLibrary
asset.requestContentEditingInput(with: PHContentEditingInputRequestOptions()) { (input, _) in
let url = input?.fullSizeImageURL
}
This URL prints: file:///Users/josh/Library/Developer/CoreSimulator/Devices/EE65D986-55E7-414C-A73E-D1C96FF17004/data/Media/DCIM/100APPLE/IMG_0005.JPG.
How do I retrieve this image? I've tried the following but it does not return anything:
var fileLocation = "file:///Users/josh/Library/Developer/CoreSimulator/Devices/EE65D986-55E7-414C-A73E-D1C96FF17004/data/Media/DCIM/100APPLE/IMG_0005.JPG"
let url = URL(string: fileLocation)
let asset = PHAsset.fetchAssets(withALAssetURLs: [url!], options: nil)
if let result = asset.firstObject {
//asset.firstObject does not exist
}
apparently apple will not allow the developer to access any and every photo in the user's photo library even after they have accepted photos usage. If you are using an image that hasnt been picked from the imagePicker, (i.e. choosing last image in library), you have to store the image in the document directory before you can use the document directory URL. I guess this prevents people hacking into others photo library
//Storing the image (in my case, when selecting last photo NOT via imagePicker)
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("image01.jpg")
let imageData = UIImageJPEGRepresentation(image!, 1.0)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
//Retrieving the image
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first {
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("image01.jpg")
if let imageRetrieved = UIImage(contentsOfFile: imageURL.path) {
//do whatever you want with this image
print(imageRetrieved)
}
}
I have this image:
I am trying to recognize those letters with Tesseract but I always get some random text like _u_i.i_1, L_n_.t. Here is my code:
let tesseract = G8Tesseract.init(language: "eng")
if let tes = tesseract{
tes.image = img.g8_blackAndWhite()
tes.engineMode = .cubeOnly
tes.pageSegmentationMode = .auto
tes.maximumRecognitionTime = 60
tes.recognize()
//...
}
I've found this code at here and it works fine for them. Of course I was prepared for having worse results because I'm not using a perfectly lighted image but I don't know why I don't get any good results at all.
Any idea?
You can try this link https://github.com/BradLarson/GPUImage . After that add below code for tessdata langauges store. I think it will help you.
func storeLanguageFile() throws{
var fileManager: FileManager = FileManager.default
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let docDirectory = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)[0] as NSString
let path: String = docDirectory.appendingPathComponent("/tessdata/eng.traineddata")
if fileManager.fileExists(atPath: path){
var data: NSData = NSData.dataWithContentsOfMappedFile((Bundle.main.resourcePath?.appending("/tessdata/eng.traineddata"))!)! as! NSData
var error: NSError
try FileManager.default.createDirectory(atPath: docDirectory.appendingPathComponent("/tessdata"), withIntermediateDirectories: true, attributes: nil)
data.write(toFile: path, atomically: true)
}
}
I am using the documents directory of my application to cache images locally, but when I go to access them, they are not updated until I close the app and reopen.
Here is my save:
var readPath = ""
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
readPath = dirPath.stringByAppendingPathComponent("\(user).png")
UIImagePNGRepresentation(imageView.image).writeToFile(readPath, atomically: true)
}
}
}
Here is my retrieval:
var readPath = ""
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
readPath = dirPath.stringByAppendingPathComponent("\(user).png")
//UIImagePNGRepresentation(imageView.image).writeToFile(readPath, atomically: true)
}
}
}
let cachedImage = UIImage(named: readPath)
if (cachedImage != nil)
{
println("cached")
self.userPictures.append(cachedImage!)
}
For some reason though, it is not until I have reset the application that these resources become available.
Can anyone shed some light on why this could be?
The image that gets returned to cachedImage is an image that I had previously saved into that specific path btw
This may helps you....
let fileManager = NSFileManager.defaultManager()
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
var getImagePath = paths.stringByAppendingPathComponent("\(fileName).png")
if (fileManager.fileExistsAtPath(getImagePath))
{
println("FILE AVAILABLE");
//Pick Image and Use accordingly
var imageis: UIImage = UIImage(contentsOfFile: getImagePath)!
self.image = imageis // UIImageView Class
let datas: NSData = UIImagePNGRepresentation(imageis)
}
else
{
println("FILE NOT AVAILABLE");
let getImage = UIImage(data: self.data)
self.image = getImage
var filePathToWrite = "\(paths)/\(fileName).png"
var imageData: NSData = UIImagePNGRepresentation(self.image)
fileManager.createFileAtPath(filePathToWrite, contents: imageData, attributes: nil)
}
Check the Project in Github
I am coding as below for UIImagePickerController to get image from the photo library.
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
// Code here
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary;
imagePicker.mediaTypes = [kUTTypeImage]
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
After selecting an image, I can show it on UIImageView, but I cannot get it's URL.
This is code I wrote to get it.
let url: NSString = info[UIImagePickerControllerReferenceURL] as NSString
var imageName:String = url.lastPathComponent
println("URL is \(imageName)")
let image = info[UIImagePickerControllerOriginalImage] as UIImage
profileImage.image = image
self.dismissViewControllerAnimated(true, completion: nil)
Here it gives nil and if I use UIImagePickerControllerEditedImage, it also crashes.
Can't we access URL directly, if not what is UIImagePickerControllerReferenceURL supposed to return?
How can I get the URL of the image so it could be sent to the server.
Thanks
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
let readPath = dirPath.stringByAppendingPathComponent("yourNameImg.png")
var pickedimage = UIImage(CGImage: UIImage(contentsOfFile: readPath)!.CGImage, scale: 1.0, orientation: .Up)
UploadImagePreview.image = pickedimage
}
}
}
Note: We can set the image from url if the complete address is known. Here we are searching for the given image name in nsDocumentDirectory , finds out the complete image path and then set to image view.