trying to export a sequence of OBJ from GARAugmentedFaceSession
In the following project, I just added the following code snippet to export OBJs;
https://github.com/google-ar/arcore-ios-sdk/tree/master/Examples/AugmentedFacesExample
Into Ln 236 from FacesViewControllers.swift;
// Added
let mdlMesh = MDLMesh(scnGeometry: faceTextureNode.geometry!)
let asset = MDLAsset()
asset.add(mdlMesh)
do {
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let obj_url = directory!.appendingPathComponent("test_\(id).obj")
try asset.export(to: obj_url) // iOS14
self.id += 1
}
catch {
print("SCNSceneRendererDelegate:renderer :: Can't write mesh to url")
}
The weird thing is it works fine in iOS13, but crashes in iOS14.
I am using the latest version of ARCore,1.20.0
If I just use ARSCNFaceGeometry, it works fine.
But I want to use GARAugmentedFaceSession for better results.
Any idea why it crashes on iOS14?
On provided screenshot in comments your directory url is nil
Related
I am trying load SCNParticleSystem from download bundle which i am not able to load.
Path for the resource.
file:///var/mobile/Containers/Data/Application/A91E9970-CDE1-43D8-B822-4B61EFC6149B/Documents/so/solarsystem.bundle/Contents/Resources/
let objScene = SCNParticleSystem(named: "stars", inDirectory: directory)
This object is nil.
This is a legitimate problem since SceneKit does not provide an out-of-the-box solution for initializing particle systems from files that are outside of the main bundle (the only init method SCNParticleSystem.init(named:inDirectory:) implies that SCNParticleSystem.scnp files are in the main bundle).
Luckily for us .scnp files are just encoded/archived SCNParticleSystem instances that we can easily decode/unarchive using NSKeyedUnarchiver:
extension SCNParticleSystem {
static func make(fromFileAt url: URL) -> SCNParticleSystem? {
guard let data = try? Data(contentsOf: url),
let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
let system = object as? SCNParticleSystem else { return nil }
return system
}
}
If you do not need to support iOS 9 and iOS 10 you can use NSKeyedUnarchiver.unarchivedObject(ofClass: SCNParticleSystem.self, from: data) instead of NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(_:) and type casting, which was introduced in iOS 11.0.
Another issue that you're most likely to encounter is missing particle images. That is because by default SceneKit will look for them in the main bundle. As of current versions of iOS (which is iOS 12) and Xcode (Xcode 10) particle images in .scnp files (particleImage property) are String values which are texture filenames in the main bundle (that might change, but probably won't, however there's not much else we could use).
So my suggestion is to take that filename and look for the texture file with the same name in the same directory where the .scnp file is:
extension SCNParticleSystem {
static func make(fromFileAt url: URL) -> SCNParticleSystem? {
guard let data = try? Data(contentsOf: url),
let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
let system = object as? SCNParticleSystem else { return nil }
if let particleImageName = system.particleImage as? String {
let particleImageURL = url
.deletingLastPathComponent()
.appendingPathComponent(particleImageName)
if FileManager.default.fileExists(atPath: particleImageURL.path) {
system.particleImage = particleImageURL
}
}
return system
}
}
You can just set the URL of the image file and SceneKit will handle it from there.
As a little side-note, the recommended directory for downloadable content is Application Support directory, not Documents.
Application Support: Use this directory to store all app data files except those associated with the user’s documents. For example, you might use this directory to store app-created data files, configuration files, templates, or other fixed or modifiable resources that are managed by the app. An app might use this directory to store a modifiable copy of resources contained initially in the app’s bundle. A game might use this directory to store new levels purchased by the user and downloaded from a server.
(from File System Basics)
Don't have enough reps to add the comment so adding it as the answer.
The answer by Lësha Turkowski works for sure but was had issues with loading the particle images using only NSURL.
All particles were appearing square which meant,
If the value is nil (the default), SceneKit renders each particle as a
small white square (colorized by the particleColor property).
SCNParticleSystem particleImage
In the documentation it says You may specify an image using an
NSImage (in macOS) or UIImage (in iOS) instance, or an NSString or
NSURL instance containing the path or URL to an image file.
Instead of using the NSURL, ended up using the UIImage and it loaded up fine.
extension SCNParticleSystem {
static func make(fromFileAt url: URL) -> SCNParticleSystem? {
guard let data = try? Data(contentsOf: url),
let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
let system = object as? SCNParticleSystem else { return nil }
if let particleImageName = system.particleImage as? String {
let particleImageURL = url
.deletingLastPathComponent()
.appendingPathComponent(particleImageName)
if FileManager.default.fileExists(atPath: particleImageURL.path) {
// load up the NSURL contents in UIImage
let particleUIImage = UIImage(contentsOfFile: particleImageURL.path)
system.particleImage = particleUIImage
}
}
return system
}
}
I found out, that sometimes when dragging a SCNParticleSystem file into your project (probably form a different project) a silent error can happen due to some bugs in Xcode. As a result you can't get a reference to an instance of your SCNParticleSystem.
Solution: Check your BuildSettings in your target. The SCNPaticleSystem AND the associated ImageFile should be listed there and then you should get it right. (see screenShot below)
First of all I know this is a subjective question, not code based, How ever I need to find solution. Please provide any references
I am working on a task in which I saving the files in Device Document directory. Upto here all is working fine. However when I see these files from :
Files App -> App Folder and the files
I can see all those files.
Now I want to hide few of them, How can I achieve these....?
As per your requirement. You need to change some lines of code in saving file.
Firstly, The FileApp shows all the data that save in documentsDirectory of app whether you put code for hide or not. To hide few files you need to make separate path for them.
First, the file you want to show in documentDirectory:
let documentsDirectory = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
The file you don’t want to show with user, you need to create path here:
let libraryDirectory = (FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)).last! as URL
Once you set the library path for saving all your important files. All will be hidden and cannot be accessed by user.
To know more about files, please refer to this link:
https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
Xcode 9 • Swift 4 or Xcode 8 • Swift 3
extension URL {
var isHidden: Bool {
get {
return (try? resourceValues(forKeys: [.isHiddenKey]))?.isHidden == true
}
set {
var resourceValues = URLResourceValues()
resourceValues.isHidden = newValue
do {
try setResourceValues(resourceValues)
} catch {
print("isHidden error:", error)
}
}
}
}
for more reference see chain here Cocoa Swift, get/set hidden flag on files and directories
or
https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/ManagingFIlesandDirectories/ManagingFIlesandDirectories.html
How would one programmatically save an image generated from a playground to the resources folder?
I have generated some photos through filters in my playground that I would like to save somehow. The resources folder seems like a good fit. What if I wanted to save the image to the desktop?
I've seen this done with saving images for apps, but I just want to save it to my desktop (or a specified folder in a specified location.)
Create folder first in 'Documents' with name 'Shared Playground Data' otherwise app will give error.
SWIFT 5:
let image = // your UIImage
let filepath = playgroundSharedDataDirectory.appendingPathComponent("export.jpg")
let imagedata = image.jpegData(compressionQuality: 1.0)
try! imagedata?.write(to: URL.init(fileURLWithPath: filepath.path))
print("write to \(filepath)")
In Xcode 11, the folder is not in ~/Documents anymore for iOS playgrounds but buried deep in ~/Library/Developer/. You have to print the path and create the Shared Playground Data folder manually to save a file from a playground:
import PlaygroundSupport
// ...
let url = playgroundSharedDataDirectory.appendingPathComponent("example.png")
print(url)
try! image.pngData()!.write(to: url)
Here's how to save it to the shared data directory:
Create a path to the image:
let path = XCPlaygroundSharedDataDirectoryURL.appendingPathComponent("export.jpg")!
(you may need to create the directory ~/Documents/Shared Playground Data/)
Then to save your output (in this case a CIImage from a filter)
let temp:CGImage = context.createCGImage(output, from: output.extent)!
let image = UIImage(cgImage: temp)
let data = UIImageJPEGRepresentation(image, 1.0)
try! data?.write(to: path)
While the first answer helped point me in the right direction, the lack of ability to validate the required playgroundSharedDataDirectory path exists, the requirement to create that directory in order for the path to work, as well as force unwrapping (using !) the try can lead to frustration as well as drag out the process.
Here is a safer, more convenient solution that checks the name you provide for extra safety:
func writeImage(_ image: UIImage, name: String) {
if name.isEmpty || name.count < 3 {
print("Name cannot be empty or less than 3 characters.")
return
}
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
print("No documents directory found.")
return
}
let imagePath = documentsDirectory.appendingPathComponent("\(name).png")
let imagedata = image.jpegData(compressionQuality: 1.0)
do {
try imagedata?.write(to: imagePath)
print("Image successfully written to path:\n\n \(documentsDirectory) \n\n")
} catch {
print("Error writing image: \(error)")
}
}
Call using:
writeImage(image, name: "MyNewImage")
A break down of what is happening:
The method writeImage checks to see if the documents directory exists.
If the documents directory does not exist (unlikely), stop process.
If the documents directory exists, carry on and write the image to the path.
I'm testing my app on iPhone 5s, in this app I'm saving audio file using NSData.writeToURL(destinationUrl, atomically: true), but this line does not work.
How destinationUrl is beeing generated:
let documentsUrl = NSURL(fileURLWithPath: NSBundle.mainBundle().resourcePath!)
let fileName = remoteFileUrl.lastPathComponent
let destinationUrl = documentsUrl.URLByAppendingPathComponent(fileName)
While tested in iOS simulator - everythins was OK
How can I fix it?
You must not write anything at runtime into the application bundle.
That will break the code signature of the application.
I've been trying to create a Today extension that needs access to a .plist file in the documents directory. I have setup the App group for both the app and the extension.
While I have seen examples for NSUserDefaults, I couldn't find anything for accessing files.
I tried accessing the file like this (which works in the app itself)
let paths = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0] as String
let filePath = "\(documentsDirectory)/config.plist"
if NSFileManager.defaultManager().fileExistsAtPath(filePath) // false
{
…
}
But I get the following error messages in the console:
Warning: CFFIXED_USER_HOME is not set! It should be set to the simulated home directory.
Failed to inherit CoreMedia permissions from 59919: (null)
The documentation says something about using NSFileCoordinator and NSFilePresenter. I couldn't find out how to use them though. I'm sure I'll need to tell them the app group identifier somewhere but I don't where.
I got it to work. Since I don't need to write the file from the extension, I don't think I need to use NSFileCoordinator. Turns out NSFileManager has a method containerURLForSecurityApplicationGroupIdentifier() for retrieving the container URL.
let manager = NSFileManager()
let containerURL = manager.containerURLForSecurityApplicationGroupIdentifier("group.MyGroupIdentifier")
let filePath = "\(containerURL.path)/config.plist"
let settings = NSDictionary(contentsOfFile: filePath)