使用 MTKTextureLoader 加载远程图像
Load a remote image using MTKTextureLoader
我正在尝试使用此代码将远程图像加载到 MTLTexture 中,
let textureLoader = MTKTextureLoader(device: device)
textureLoader.newTexture(withContentsOf: url, options: options) { [weak self] (texture, error) in
if let t = texture {
completion(t)
} else {
if let desc = error?.localizedDescription {
NSLog(desc)
}
completion(nil)
}
}
如果 URL 来自 Bundle 资源,那么它可以工作,例如
let url = Bundle.main.url(forResource: name, withExtension: ext)
但是,如果我通过这样的东西,它会失败,
let url = URL(string: "http://example.com/images/bla_bla.jpg")
出现这个错误,
Could not find resource bla_bla.jpg at specified location.
如果我将 url 复制粘贴到浏览器中,则图像显示没有问题(另外我在 Android 中使用 OpenGL 实现了同样的事情并且图像渲染正常)。
我已将我的域添加到 Info.plist,我可以从该位置加载 Json 之类的内容。只是纹理加载器很有趣... Info.plist 看起来像这样,
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
MTKTextureLoader documentation没有提到任何关于外部URL的东西,难道它只处理内部资源吗?
下面是一个示例,说明如何扩展 MTKTextureLoader
以加载默认实现不支持的远程 URL。
extension MTKTextureLoader {
enum RemoteTextureLoaderError: Error {
case noCachesDirectory
case downloadFailed(URLResponse?)
}
func newTexture(withContentsOfRemote url: URL, options: [String : NSObject]? = nil, completionHandler: @escaping MTKTextureLoaderCallback) {
let downloadTask = URLSession.shared.downloadTask(with: URLRequest(url: url)) { (maybeFileURL, maybeResponse, maybeError) in
var anError: Error? = maybeError
if let tempURL = maybeFileURL, let response = maybeResponse {
if let cachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first {
let cachesURL = URL(fileURLWithPath: cachePath, isDirectory: true)
let cachedFileURL = cachesURL.appendingPathComponent(response.suggestedFilename ?? NSUUID().uuidString)
try? FileManager.default.moveItem(at: tempURL, to: cachedFileURL)
return self.newTexture(withContentsOf: cachedFileURL, options: options, completionHandler: completionHandler)
} else {
anError = RemoteTextureLoaderError.noCachesDirectory
}
} else {
anError = RemoteTextureLoaderError.downloadFailed(maybeResponse)
}
completionHandler(nil, anError)
}
downloadTask.resume()
}
}
理想情况下,您应该实施自己的缓存机制以避免重复下载相同的图像,但这应该能让您入门。
我正在尝试使用此代码将远程图像加载到 MTLTexture 中,
let textureLoader = MTKTextureLoader(device: device)
textureLoader.newTexture(withContentsOf: url, options: options) { [weak self] (texture, error) in
if let t = texture {
completion(t)
} else {
if let desc = error?.localizedDescription {
NSLog(desc)
}
completion(nil)
}
}
如果 URL 来自 Bundle 资源,那么它可以工作,例如
let url = Bundle.main.url(forResource: name, withExtension: ext)
但是,如果我通过这样的东西,它会失败,
let url = URL(string: "http://example.com/images/bla_bla.jpg")
出现这个错误,
Could not find resource bla_bla.jpg at specified location.
如果我将 url 复制粘贴到浏览器中,则图像显示没有问题(另外我在 Android 中使用 OpenGL 实现了同样的事情并且图像渲染正常)。
我已将我的域添加到 Info.plist,我可以从该位置加载 Json 之类的内容。只是纹理加载器很有趣... Info.plist 看起来像这样,
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
MTKTextureLoader documentation没有提到任何关于外部URL的东西,难道它只处理内部资源吗?
下面是一个示例,说明如何扩展 MTKTextureLoader
以加载默认实现不支持的远程 URL。
extension MTKTextureLoader {
enum RemoteTextureLoaderError: Error {
case noCachesDirectory
case downloadFailed(URLResponse?)
}
func newTexture(withContentsOfRemote url: URL, options: [String : NSObject]? = nil, completionHandler: @escaping MTKTextureLoaderCallback) {
let downloadTask = URLSession.shared.downloadTask(with: URLRequest(url: url)) { (maybeFileURL, maybeResponse, maybeError) in
var anError: Error? = maybeError
if let tempURL = maybeFileURL, let response = maybeResponse {
if let cachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first {
let cachesURL = URL(fileURLWithPath: cachePath, isDirectory: true)
let cachedFileURL = cachesURL.appendingPathComponent(response.suggestedFilename ?? NSUUID().uuidString)
try? FileManager.default.moveItem(at: tempURL, to: cachedFileURL)
return self.newTexture(withContentsOf: cachedFileURL, options: options, completionHandler: completionHandler)
} else {
anError = RemoteTextureLoaderError.noCachesDirectory
}
} else {
anError = RemoteTextureLoaderError.downloadFailed(maybeResponse)
}
completionHandler(nil, anError)
}
downloadTask.resume()
}
}
理想情况下,您应该实施自己的缓存机制以避免重复下载相同的图像,但这应该能让您入门。