google-ar / sceneform-android-sdk

Sceneform SDK for Android
https://developers.google.com/sceneform/develop/
Apache License 2.0
1.23k stars 604 forks source link

Texture file loading #79

Closed michaelvogt closed 6 years ago

michaelvogt commented 6 years ago

I try to load a texture from external storage, but can't get it to work. I used both FileProvider and regular file:/// style URI.

Texture builder looks like this:

Texture.builder() .setSource(getContext(), photoURI) .setUsage(Texture.Usage.DATA) .build();

Effectively, I create the file URI like this: Uri photoURI = Uri.fromFile(new File(getExternalStorageDirectory(), path)); file:///storage/emulated/0/Touristar/Hidaka/hidakabreads.jpg

Which leads to a file not found exception java.lang.IllegalStateException: java.io.FileNotFoundException: /storage/emulated/0/Touristar/Hidaka/hidakabreads.jpg at com.google.ar.sceneform.rendering.Texture$LoadTextureTask.loadData(Texture.java:311) at com.google.ar.sceneform.rendering.AssetLoader.lambda$runLoadTask$0(AssetLoader.java:81) at com.google.ar.sceneform.rendering.-$$Lambda$AssetLoader$Jdb8M1vmtZpNIxZABL9oLMUs3g0.run(lambda) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:761) Caused by: java.io.FileNotFoundException: /storage/emulated/0/Touristar/Hidaka/hidakabreads.jpg at android.content.res.AssetManager.openAsset(Native Method) at android.content.res.AssetManager.open(AssetManager.java:347) at android.content.res.AssetManager.open(AssetManager.java:321) at com.google.ar.sceneform.utilities.LoadHelper.lambda$fileUriToInputStreamCreator$0$LoadHelper(Unknown Source) at com.google.ar.sceneform.utilities.a.call(Unknown Source) at com.google.ar.sceneform.rendering.Texture$LoadTextureTask.loadData(Texture.java:308) at com.google.ar.sceneform.rendering.AssetLoader.lambda$runLoadTask$0(AssetLoader.java:81)  at com.google.ar.sceneform.rendering.-$$Lambda$AssetLoader$Jdb8M1vmtZpNIxZABL9oLMUs3g0.run(lambda)  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)  at java.lang.Thread.run(Thread.java:761) 

Using a FilePorvider with the File create like above it looks like this Uri photoURI = FileProvider.getUriForFile(getContext(), "com.example.fileprovider", new File(getExternalStorageDirectory(), path));

The resulting exception says, the content scheme is not supported. java.lang.IllegalArgumentException: Unable to parse url: 'content://eu.michaelvogt.ar.author.fileprovider/hidaka_data/hidakabreads.jpg' at com.google.ar.sceneform.utilities.LoadHelper.remoteUriToInputStreamCreator(Unknown Source) at com.google.ar.sceneform.utilities.LoadHelper.fromUri(Unknown Source) at com.google.ar.sceneform.rendering.Texture$Builder.setSource(Texture.java:383) at eu.michaelvogt.ar.author.PreviewFragment.lambda$makeUserPanel$7(PreviewFragment.java:158) at eu.michaelvogt.ar.author.-$$Lambda$PreviewFragment$uoU9MkgipiyRm_Wzg9yaV0SVyf0.onClick(lambda) at android.view.View.performClick(View.java:5610) at android.view.View$PerformClick.run(View.java:22277) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:159) at android.app.ActivityThread.main(ActivityThread.java:6097) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) Caused by: java.net.MalformedURLException: unknown protocol: content at java.net.URL.(URL.java:596) at java.net.URL.(URL.java:486) at java.net.URL.(URL.java:435) at com.google.ar.sceneform.utilities.LoadHelper.remoteUriToInputStreamCreator(Unknown Source)  at com.google.ar.sceneform.utilities.LoadHelper.fromUri(Unknown Source)  at com.google.ar.sceneform.rendering.Texture$Builder.setSource(Texture.java:383)  at eu.michaelvogt.ar.author.PreviewFragment.lambda$makeUserPanel$7(PreviewFragment.java:158)  at eu.michaelvogt.ar.author.-$$Lambda$PreviewFragment$uoU9MkgipiyRm_Wzg9yaV0SVyf0.onClick(lambda)  at android.view.View.performClick(View.java:5610)  at android.view.View$PerformClick.run(View.java:22277)  at android.os.Handler.handleCallback(Handler.java:751)  at android.os.Handler.dispatchMessage(Handler.java:95)  at android.os.Looper.loop(Looper.java:159)  at android.app.ActivityThread.main(ActivityThread.java:6097)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

Should this work that way or am I doing something stupid?

tpsiaki commented 6 years ago

@michaelvogt - in 1.0 we interpret all file:// uris as being relative to the assets folder which is why we fail to load from external storage. Consequently, in order to load a Texture from a Uri, you'll need to either put in in the assets folder (i.e. bundled into your apk), or host it online where it's available via an http:// scheme.

terezo commented 6 years ago

Hi @tpsiaki ,

do you have any idea when this could be fixed? It's quite essential functionality when you need to use plenty of models and do not want to have giant APK, or just simply need runtime model loading with sort of control and models preloading.

dyavil commented 6 years ago

Hi, Like @terezo said, loading a texture file from external storage seems essential to me. And likewise I'd like to know if it will be fixed in an upcoming release.

malik-at-work commented 6 years ago

Yes this is on our plate. There is a workaround for this so you'd don't have to wait for our fix. You can pass in an InputStream and load the texture from any source.

    Callable<InputStream> loadTextureFromFile =
        () -> {
          try {
            File filename = ....;
            return new FileInputStream(filename);
          } catch (IOException ex) {
            throw new CompletionException(ex);
          }
        };

    Texture.builder()
        .setSource(loadTextureFromFile)
        .build();
dyavil commented 6 years ago

Thanks ! As that might be of use for others, updating the documentation here may limit duplicates on this issue.

malik-at-work commented 6 years ago

Fixed in Sceneform 1.4, Closing.

basitsaleemmb commented 6 years ago

@malik-at-work got this issue in sceneform 1.4.0 minSdK = 17 supportLibrary = 27.1.1 phone samsung s7 galaxy OS = 8.0.0

Fatal Exception: java.lang.IllegalStateException: Texture must use ARGB8 format. at com.google.ar.sceneform.rendering.Texture$LoadTextureTask.loadData(Texture.java:299) at com.google.ar.sceneform.rendering.AssetLoader.lambda$runLoadTask$0$AssetLoader(AssetLoader.java:81) at com.google.ar.sceneform.rendering.AssetLoader$$Lambda$0.run(Unknown Source:8) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764)

dsternfeld7 commented 6 years ago

Can you check to make sure the bitmap you created is in the ARGB8 format?

malik-at-work commented 6 years ago

@basitsaleemmb I've opened a new issue to discuss the new issue, check out https://github.com/google-ar/sceneform-android-sdk/issues/254

chnouman commented 5 years ago

@tpsiaki can you explain how can I load a texture from URL? I want to apply different textures and want to place textures on server.