Retrieving a remote image

25 views
Skip to first unread message

guille.r...@gmail.com

unread,
Nov 10, 2017, 5:05:33 AM11/10/17
to PlayN
Hi all,

Two questions related to retrieving an image from a remote HTTP server.

First I tried using Assets.getRemoteImage(String url). This seems to fail on the Java target:

  [java] onFailure: javax.imageio.IIOException: Can't get input stream from URL!

Is this expected or am I doing something wrong ?

Second. I need to setup some custom HTTP headers and getRemoteImage won't let me do this. Is there any way to create an Image object out of a byte array? Then I could retrieve the raw bytes using Net.Builder (which lets me play with the request headers) and create the image once the data is ready.

Best,

Guillermo


guille.r...@gmail.com

unread,
Nov 10, 2017, 5:20:10 AM11/10/17
to PlayN
Please forget about the first question. It was a mistake on my side.

The second one still remains, though.

Guillermo

Andres Q

unread,
Nov 10, 2017, 10:18:51 AM11/10/17
to pl...@googlegroups.com
what's the use case for #2?

Guillermo Rodriguez Garcia

unread,
Nov 10, 2017, 10:27:40 AM11/10/17
to pl...@googlegroups.com
Hi,

Authorization header (for bearer token), User agent string, caching headers (If-None-Match).

Guillermo 
--

---
You received this message because you are subscribed to a topic in the Google Groups "PlayN" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/playn/_NLF3Rxj9-s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to playn+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Guillermo Rodriguez Garcia
guille.r...@gmail.com

Michael Bayne

unread,
Nov 10, 2017, 12:37:37 PM11/10/17
to pl...@googlegroups.com
It would be pretty easy to add support for this to the Java backend, but much more difficult to do it for all four backends. Unfortunately due to the fact that every platform does things a little differently, we can't easily expose composable APIs like "API A gives me a 'stream' and API B turns a 'stream' into an image". That may be how the JDK does it, but then the web backend has to use XmlHttpRequest and everything has to be done specially. Android and iOS handle images via their own platform-specific APIs as well.

So this is probably something you'll have to implement yourself. If you're only targeting one or two platforms, this will be easy, and if you're targeting all the platforms, then feel free to package up all of your hard work as a pull request that adds support for this to the platform. :)


On Fri, Nov 10, 2017 at 2:05 AM <guille.r...@gmail.com> wrote:

Second. I need to setup some custom HTTP headers and getRemoteImage won't let me do this. Is there any way to create an Image object out of a byte array? Then I could retrieve the raw bytes using Net.Builder (which lets me play with the request headers) and create the image once the data is ready.
--

guille.r...@gmail.com

unread,
Nov 14, 2017, 11:31:32 AM11/14/17
to PlayN
I was indeed looking for a way to "retrieve a stream of bytes" and then "turn the bytes into an image" but perhaps there are other ways.

At the end I just need to have some more control over the HTTP headers of the request. Perhaps another way to achieve this would be to implement a variant of Assets.getRemoteImage taking a Net.Builder object as a parameter, instead of a String? This would make it possible to add headers to the request and hopefully would be a more portable approach.

Does this sound better?

Guillermo

Michael Bayne

unread,
Nov 14, 2017, 11:40:28 AM11/14/17
to pl...@googlegroups.com
Doesn’t help. The problem is that for the html backend one has zero control over the http request to get an image. So playn can’t provide an api for all platforms that allows headers to be set.

There are new ways to load images in html5 that do provide more control, but they’re massively inefficient so we could not use them by default. Plus they don’t work on all browsers. So that would mean having some whole separate code path to support when headers were set versus not, and it would have to come with a bunch of caveats about how it doesn’t work on certain browsers when you use the html backend. I try to avoid adding apis which come with a pile of warnings.

What backends are you targeting?


--

---
You received this message because you are subscribed to the Google Groups "PlayN" group.
To unsubscribe from this group and stop receiving emails from it, send an email to playn+un...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--

guille.r...@gmail.com

unread,
Nov 14, 2017, 11:59:53 AM11/14/17
to PlayN
Ah; I thought that images in the HTML backend were already being loaded over XHR but I see this is not the case.

Backends: I am targetting Android and iOS so certainly I can just roll my own implementation for this supporting only these two platforms (plus the Java backend for development / testing). I just thought this could be a useful thing to have in PlayN.

Re. avoiding adding APIs with a pile of warnings: I guess that also includes that you are not happy adding APIs that are only supported on a subset of the platforms, right?

Guillermo

Michael Bayne

unread,
Nov 15, 2017, 7:21:50 PM11/15/17
to pl...@googlegroups.com
I definitely try to avoid APIs that can't be implemented on all platforms, though there are a few in there.

Indeed, given that Net.Response.payload() (which returns byte[]) isn't supported on HTML5, maybe I should just add payloadImage() which can also be not supported on HTML5. I'll take a look into it.

Michael Bayne

unread,
Nov 17, 2017, 2:11:05 PM11/17/17
to pl...@googlegroups.com
I went ahead and added 'responseImage' to Net.Response, so you can build a request and then get the response back as an image.


There's some test code that shows an example of the call:

    game.net.req("https://www.samskivert.com/images/2012/12/spellwood-app-icon.png").execute().

      onSuccess(new Slot<Net.Response>() {

        public void onEmit (Net.Response rsp) {

          try {

            Image icon = rsp.payloadImage(new Scale(2));

            ImageLayer l4 = new ImageLayer(icon);

            game.rootLayer.addAt(l4.setRotation(FloatMath.PI/4), 150, 150);

            l4.events().connect(new Mover(l4).listener(game.input));

          } catch (Exception e) {

            game.log.warn("Failed to decode image: " + e);

          }

        }

      }).

      onFailure(new Slot<Throwable>() {

        public void onEmit (Throwable t) {

          game.log.warn("Failed to load image: " + t);

        }

      });


In this case I'm testing loading a HiDPI image, normally you'd probably pass Scale.ONE into the call to indicate that the image is "normal" scale.

Michael Bayne

unread,
Nov 17, 2017, 2:12:49 PM11/17/17
to pl...@googlegroups.com
That code incidentally is a great example of how nice it would be to have lambdas. :)

    game.net.req("https://www.samskivert.com/images/2012/12/spellwood-app-icon.png").execute().

      onSuccess(rsp -> {

        try {

          Image icon = rsp.payloadImage(new Scale(2));

          ImageLayer l4 = new ImageLayer(icon);

          game.rootLayer.addAt(l4.setRotation(FloatMath.PI/4), 150, 150);

          l4.events().connect(new Mover(l4).listener(game.input));

        } catch (Exception e) {

          game.log.warn("Failed to decode image: " + e);

        }

      }).

      onFailure(t -> game.log.warn("Failed to load image: " + t));


--

Andres Q

unread,
Nov 17, 2017, 2:14:36 PM11/17/17
to pl...@googlegroups.com
I think that you can still use lambdas even if React is not written in
Java8 and doesn't have @FunctionalInterface annotations

Michael Bayne

unread,
Nov 17, 2017, 2:19:08 PM11/17/17
to pl...@googlegroups.com
Yeah, it mostly works. I was using them two years ago when I was working on a random game prototype.

    media.onReady.onSuccess(media -> {

      // lay out our header view and wire it up

      GoldenAge game = GoldenAge.this;

      IDimension vs = game.plat.graphics().viewSize;

      // ...

    });


but I was doing it with Retrolambda for Android. I wouldn't want to force everyone to have to wire that up, unless they were already enthusiastic enough to have done it.

Michael Bayne

unread,
Nov 17, 2017, 2:20:04 PM11/17/17
to pl...@googlegroups.com
I guess that's a good point. I could wire up Retrolambda for the PlayN tests and use it there and that would provide an example for anyone who wanted to do so themselves.
--

Andres Q

unread,
Nov 17, 2017, 2:20:57 PM11/17/17
to pl...@googlegroups.com
+1!

guille.r...@gmail.com

unread,
Nov 20, 2017, 2:22:44 PM11/20/17
to PlayN
That's great :-)

Guillermo
Reply all
Reply to author
Forward
0 new messages