How to get array of UIImage, from folder, in Swift? - ios

I have an ordinary Xcode project like this ...
notice there's a folder (it is an actual folder - not just a group) named "images". It contains 25 ".png" images.
All I want to do is make an array of UIimage with each of those images.
(Or even, an array of the image names or similar, that would be fine - then could load them UIImage(named:)
How do I get at that folder "images"?? What about a subfolder "images/cars"?
I tried something like this but it finds nothing...
override func viewDidLoad()
{
let imageArray = NSBundle.mainBundle().URLsForResourcesWithExtension(
"png", subdirectory: "images")
print("test...")
for n:NSURL in imageArray!
{ print("found ..." ,n) }
}

We we assume the images are in the app's resource bundle. If not you need to make sure that your images directory is listed in the "Copy Bundle Resources" in the "Build Phases" of the target.
EDIT
This is only going copy the images into the app bundle, if you require the folder to be copied to the app bundle per the code below then please use the follow StackOverflow question to set it up correctly.
This gives us an array of URL's that we can then use with UIImage(data:) and NSData(contentsOfURL:) to create the image when needed.
Get the bundle's resource path and append the image directory then get the contents of the directory.
if let path = NSBundle.mainBundle().resourcePath {
let imagePath = path + "/images"
let url = NSURL(fileURLWithPath: imagePath)
let fileManager = NSFileManager.defaultManager()
let properties = [NSURLLocalizedNameKey,
NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey]
do {
let imageURLs = try fileManager.contentsOfDirectoryAtURL(url, includingPropertiesForKeys: properties, options:NSDirectoryEnumerationOptions.SkipsHiddenFiles)
print("image URLs: \(imageURLs)")
// Create image from URL
var myImage = UIImage(data: NSData(contentsOfURL: imageURLs[0])!)
} catch let error1 as NSError {
print(error1.description)
}
}

You can follow these steps to download them:
Create a new folder in finder and add all images (or folder, ...
everything).
Change folder name + ".bundle" (for example: YourListImage ->
YourListImage.bundle).
Add folder to project.
Add FileManager extension:
extension FileManager {
func getListFileNameInBundle(bundlePath: String) -> [String] {
let fileManager = FileManager.default
let bundleURL = Bundle.main.bundleURL
let assetURL = bundleURL.appendingPathComponent(bundlePath)
do {
let contents = try fileManager.contentsOfDirectory(at: assetURL, includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.isDirectoryKey], options: .skipsHiddenFiles)
return contents.map{$0.lastPathComponent}
}
catch {
return []
}
}
func getImageInBundle(bundlePath: String) -> UIImage? {
let bundleURL = Bundle.main.bundleURL
let assetURL = bundleURL.appendingPathComponent(bundlePath)
return UIImage.init(contentsOfFile: assetURL.relativePath)
}
}
Use:
let fm = FileManager.default
let listImageName = fm.getListFileNameInBundle(bundlePath: "YourListImage.bundle")
for imgName in listImageName {
let image = fm.getImageInBundle(bundlePath: "YourListImage.bundle/\(imgName)")
}

Please try the following:
You have to register your images to "Copy Bundle Resources".
You have to add filter module in main Bundle.
enter image description here
It is working well on my side. Maybe you can change filter from "jpg" format into "png" one.
I've tested on iOS 10.x later, Swift 3.0 and xcode 8.1 version.

I would advise against loading all of your images into an array at once. Images tend to be large and it's easy to run out of memory and crash.
Unless you absolutely have to have all the images in memory at once it's better to keep an array of paths or URLs and load the images one at a time as needed.
Assuming the folder full of images is in your app bundle, you can use the NSBundle method URLsForResourcesWithExtension:subdirectory: to get an array of NSURLs to all the files in your images subdirectory, either with a specific filetype, or ALL files (if you pass nil for the extension.)
Once you have an array of file urls you can map it to an array of paths if needed, and then map that to an array of images.

Swift 4
if let path = Bundle.main.resourcePath {
let imagePath = path + "/images"
let url = NSURL(fileURLWithPath: imagePath)
let fileManager = FileManager.default
let properties = [URLResourceKey.localizedNameKey,
URLResourceKey.creationDateKey,
URLResourceKey.localizedTypeDescriptionKey]
do {
let imageURLs = try fileManager.contentsOfDirectory(at: url as URL, includingPropertiesForKeys: properties, options:FileManager.DirectoryEnumerationOptions.skipsHiddenFiles)
print("image URLs: \(imageURLs)")
// Create image from URL
let firstImageURL = imageURLs[0]
let firstImageData = try Data(contentsOf: firstImageURL)
let firstImage = UIImage(data: firstImageData)
// Do something with first image
} catch let error as NSError {
print(error.description)
}
}

Related

Unable to display Stickers from Documents directory in iMessage extension

In my app users are able to create images and then use them as stickers in iMessages.
My problem is that I can't display created images that are stored in the Documents Directory.
My issue is very similar to this question - SO Question but in my case the solution stated there didn't help.
Here's my code for fetching images:
func getImages(finished: () -> Void) {
imageData.removeAll()
let imageNames = keyboardUserDefaults!.stringArray(forKey: "Created stickers")
for imageName in imageNames! {
// let imagePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imageName)
// imageData.append(imagePath + "/" + imageName)
imageData.append(filePath)
}
print("Image Data - ", imageData)
finished()
}
And here is how I apply it to StickerView:
func configure(usingImageName imagePath: String) {
let urlToImage = URL(fileURLWithPath: imagePath)
do {
let description = NSLocalizedString("", comment: "")
let sticker = try MSSticker(contentsOfFileURL: urlToImage, localizedDescription: description)
print("Sicker is here - ", sticker)
stickerView.sticker = sticker
}
catch {
fatalError("Failed to create sticker: \(error)")
}
}
But I'm getting a blank view with no stickers.
Print inside cell shows:
Sicker is here - <MSSticker-<0x280393640> imageFileURL file:///var/mobile/Containers/Data/PluginKitPlugin/32AF9E44-F2F1-4FD1-80B5-E8E4B6C6E338/Documents/F54067B8-18DA-4737-8ED3-B716E368AF6E.png localizedDescription >
Images are showing when I set them from my folder inside Xcode project using Bundle.main.path, but not from the Documents Directory.
I have found source of my problem:
Application Extensions can't access default Documents Directory folder.
Solution:
Use App Groups and make path for image when saving and retrieving it like this:
let url = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "YOUR_APP_GROUP_NAME")?.appendingPathComponent("image.png")
After that you can easily access your images in Application Extensions.
Hope this helps someone in future!

Loading Images from Xcode Project Folder

I have a folder (untagged-data) in Xcode that consists of a lot of images (100). I am trying to load the images into my application but for some reason the path is not correct and I am not able to load. Here is the URL I get which I am trying to load.
file:///Users/johndoe/Library/Developer/CoreSimulator/Devices/66763907-9153-443A-BA0E-D5CB6CC9280C/data/Containers/Bundle/Application/D3C77C63-CA3D-4238-8EAD-97B1DA15F2C6/MyApp.app/untagged-data/vessey.jpg
Here is the code which populates an array with the paths:
guard let resourceURL = Bundle.main.resourceURL else {
fatalError("Bundle not found")
}
let resourcePath = resourceURL.appendingPathComponent("untagged-data")
let paths = try! FileManager.default.contentsOfDirectory(at: resourcePath, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for resourceURL in paths {
let path = resourceURL.absoluteString
self.images.append(path)
print(path)
}
When I try to create an image it simply throws an exception:
//let img = UIImage(named: images[index])
let img = UIImage(contentsOfFile: images[index])
Open the path below path in safari to check whether path exists or not
file:///Users/johndoe/Library/Developer/CoreSimulator/Devices/66763907-9153-443A-BA0E-D5CB6CC9280C/data/Containers/Bundle/Application/D3C77C63-CA3D-4238-8EAD-97B1DA15F2C6/MyApp.app/vessey.jpg
If path exists then comment the below line in code
//let resourcePath = resourceURL.appendingPathComponent("untagged-data")

Problems with loading image path from realm in Swift

In my app I am storing an image in local storage and I am saving the path of that image in my Realm database. And now i have problems with load this image from that path?
Thats how I save path to database:
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory,nsUserDomainMask, true)
let dirPath = paths.first
let imageURL1 = URL(fileURLWithPath: dirPath!).appendingPathComponent("refuge1.jpg")
let med1 = Meditation()
med1.name = "Refuge"
med1.count = 0
med1.targetAmount = 111111
med1.malasStep = 108
med1.imagePath = imageURL1.path
med1.id = 1
It's straightforward that am trying to get an image from this meditation.imagePath path. I double-checked the path, image is there still am not able to set the image using this path, is there is something that am missing?
In debug mode I see this:
Meditation {
name = Refuge;
count = 0;
targetAmount = 111111;
malasStep = 108;
imagePath = /Users/macbook/Library/Developer/CoreSimulator/Devices/2E25309F-D6A9-41C3-9EF4-67203142172C/data/Containers/Data/Application/F198640B-3C72-4F9C-8173-FB00D3ABEC15/Documents/refuge1.jpg;
id = 1;}
but my variable image still nil in debug mode
// Configure the cell...
cell.nameOfMeditation.text = meditation.name
cell.countOfMeditation.text = String(meditation.count)
let image = UIImage(contentsOfFile: meditation.imagePath)
cell.imageForMeditation.image = image
return cell
I see name of meditation and sound, bot no omg.
It's not advised to save the absolute file path of a file in an iOS app (ie, everything including /Users/macbook/Library/Developer/...), in Realm or anywhere else.
For security reasons, iOS devices rename the UUID folder name between launches. This means that while the folder path was valid at the time it was saved, it won't be at a later date.
Instead, it's recommended to save just the relative path of the file (eg, its location in relation to just the Documents folder. In this case, it would be just /refuge1.jpg) and to then dynamically build the absolute path by requesting the Documents directory path as you need it.
Try this:
// Use these convenience methods if you do a lot of saving and loading
func getDocumentsURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(_ filename: String) -> String {
let fileURL = getDocumentsURL().appendingPathComponent(filename)
return fileURL.path
}
func saveRefugeOne(image: UIImage) {
// Create a file name, and then save the path in your documents with that name
let imageFileName:String = "refuge1.jpg"
let imagePath = fileInDocumentsDirectory(imageFileName!)
saveImage(image, path: imagePath)
}
func loadRefugeOne() -> UIImage? {
// Get the image back
let imageName:String = "refuge1.jpg" // Or whatever name you saved
let imagePath = fileInDocumentsDirectory(imageName)
if let loadedImage = self.loadImageFromPath(imagePath) {
return loadedImage
} else {
print("Couldn't Load: \(imageName)")
return nil
}
}
// This will be your method to save image
func saveImage(_ image: UIImage, path: String ) {
//If you want PNG use this let pngImageData = UIImagePNGRepresentation(image)
// But since you mentioned JPEG:
if let jpgData = UIImageJPEGRepresentation(image, 1.0) {
try? jpgData.write(to: URL(fileURLWithPath: path), options: [.atomic])
}
}
// This will load image from saved path. Make sure to store the path
// somewhere. This makes it easier to save images locally. You can
// save the image in the documents directory, and then just save the
// path in CoreData or something similar.
func loadImageFromPath(_ path: String) -> UIImage? {
let image = UIImage(contentsOfFile: path)
if image == nil {
print("couldn't find image at path: \(path)")
}
return image
}
Hopefully this will help. It's the method I always use, and it works like a charm when I follow my own steps right ;-)

Swift: can't get array of images from url of folder?

Alright, Im fairly new to the url locating process (I always just use explicit names) and everyone is new to MSMessageStickers. However. I need to pull in an array of image urls to use as MSStickers from a folder of images I have copied into my MessagesExtension target in my project here (it is starterPack):
It may the Swift 3 syntax screwing this up or something else, but I CANT find any way to just get the right url of this folder and get all the images inside of it. The following is successful in making stickers out of PNGS with specific names:
for i in (1..<2) {
if let url = Bundle.main.url(forResource: "test\(i)", withExtension: "png") {
do {
//let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "")
let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "")
//print("SUCCESS", url)
stickers.append(sticker)
} catch {
print(error)
}
}
}
And I have adapted the following to Swift 3 from similar question How to get array of UIImage, from folder, in Swift? :
if let path = NSBundle.mainBundle().resourcePath {
let imagePath = path + "/images"
let url = NSURL(fileURLWithPath: imagePath)
let fileManager = NSFileManager.defaultManager()
let properties = [NSURLLocalizedNameKey,
NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey]
do {
let imageURLs = try fileManager.contentsOfDirectoryAtURL(url, includingPropertiesForKeys: properties, options:NSDirectoryEnumerationOptions.SkipsHiddenFiles)
print("image URLs: \(imageURLs)")
// Create image from URL
var myImage = UIImage(data: NSData(contentsOfURL: imageURLs[0])!)
} catch let error1 as NSError {
print(error1.description)
}
}
But because the folder is not technically in my project folder but rather in the messagesExtension folder as you can see, I think that is why it cant find it.
I need to bring in and get the url of all the images contained in my stickers folder. What am I doing wrong?

How to get Assets.xcassets file names in an Array (or some data structure?)

I'm trying to use Swift to iterate over the images I have put into my Assets folder. I'd like to iterate over them and insert them into a .nib file later, but so far I cannot find how to get something like:
let assetArray = ["image1.gif", "image2.gif", ...]
Is this possible? I've been playing with NSBundle.mainBundle() but couldn't find anything on this. Please let me know. Thanks!
Assets.xcassets is not a folder but an archive containing all the images using Assets.car as its filename.
If you really want to read the assets file then you need to use some library that can extract the contents of the file like this one.
Or you can create a bundle in your project and drag all the images you have there. In my case, I have Images.bundle in my project. To get the filenames you can do the following:
let fileManager = NSFileManager.defaultManager()
let bundleURL = NSBundle.mainBundle().bundleURL
let assetURL = bundleURL.URLByAppendingPathComponent("Images.bundle")
let contents = try! fileManager.contentsOfDirectoryAtURL(assetURL, includingPropertiesForKeys: [NSURLNameKey, NSURLIsDirectoryKey], options: .SkipsHiddenFiles)
for item in contents
{
print(item.lastPathComponent)
}
SWIFT 3/4 Version:
let fileManager = FileManager.default
let bundleURL = Bundle.main.bundleURL
let assetURL = bundleURL.appendingPathComponent("Images.bundle")
do {
let contents = try fileManager.contentsOfDirectory(at: assetURL, includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.isDirectoryKey], options: .skipsHiddenFiles)
for item in contents
{
print(item.lastPathComponent)
}
}
catch let error as NSError {
print(error)
}

Resources