greatwar93 / gwt-g2d

Automatically exported from code.google.com/p/gwt-g2d
0 stars 0 forks source link

Can't do image bundling #13

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I need to use ClientBundle feature of combining several images into one large 
image file to make the download faster/more efficient.

However, doing this business:

((ExternalImageResource) myImageResource).getImage(myCallback);

And the GWT compiler outputs separate images - no bundling.  There is also the 
problem that ResourceCallback can only grab one thing at a time - so to ensure 
all images are loaded I have to do successive chaining of these callbacks 
(seems inefficient).

If I try to cast to CanvasElement (shown below, which by the way is a little 
weird because the GWT compiler doesn't let me put the first two lines into a 
one-line operation even though it is functionally the same thing):

Element myElement = myImage.getElement();
CanvasElement myCanvasElement = (CanvasElement) myElement;
surface.drawImage(myCanvasElement, x, y);

.. then no drawing happens.

One possibility is that if I could pass in Image instead of ImageElement to the 
drawImage methods, then I could preload the Image objects using ClientBundle 
and then render them.

Of course, it could be that I'm just missing something obvious here.  Are there 
any examples of ClientBundle'ing images with g2d?

Original issue reported on code.google.com by joeh...@gmail.com on 27 Jul 2010 at 6:21

GoogleCodeExporter commented 8 years ago
You can declare your image resources as followed:
{{{
interface Resources extends ClientBundle {
  static final Resources INSTANCE = GWT.create(Resources.class);

  @Source({"image1.png", "image2.png", "image3.png"})
  ExternalImageResource imageResource();
}
}}}

Using multiple images is similar to using one image. Like what you have above, 
you provide getImage() with a callback:
{{{
Resources.INSTANCE.imageResource().getImage(new 
ResourceCallback<ImageElementResource>() {
  @Override
  public void onSuccess(ImageElementResource resource) {
    // This method will be called once for each image provided (assuming that they all load correctly),
    // you can identify the image passed in using either resource.getIndex(), which will return you
    // the zero-based index in the order that you declare the images, or resource.getBaseUrl(), which
    // will return you the original name of the image (in this case, it will be "image1.png", "image2.png", etc.
  }

  @Override
  public void onError(ResourceException e) {
    // Handles image error here.
  }
});
}}}

Let me know if this works for you.

PS: I believe you can call
{{{
CanvasElement myCanvasElement = myImage.getElement().cast();
}}}
to squeeze your statement into one line.

Original comment by hao1...@gmail.com on 28 Jul 2010 at 3:13

GoogleCodeExporter commented 8 years ago
When I do this..

@Source({"image1.png", "image2.png", "image3.png"})
  ExternalImageResource 

.. it does not create a single "sprites" image, in other words -  when I 
compile the app with the GWT compiler it does not combine multiple images into 
one physical file as it does when I use Image/ImageResource.  So - it would 
seem that the two are mutually exclusive.  

It would seem I can either:

1) use G2D and ImageElement (which seems to be more lightweight and efficient 
than using the more baggage-carrying "Image extends Widget" class), or

2) I can use the more bloated Image class but get the advantages of the 
composite file.

.. but not both.  So is it possible to get the image combining/spriting feature 
with g2d?  The image-combining thing is a lifesaver for loading mobile apps 
over not-so-snappy networks (AT&T), and also is much nicer for scalability on 
the HTTP server side.

By the way, keep up the great work - maybe I will have a chance to try out G3D 
sometime.

Original comment by joeh...@gmail.com on 30 Jul 2010 at 3:46

GoogleCodeExporter commented 8 years ago
You can also use ClientBundle + ImageElement this way:

public interface MyImageBundle extends ClientBundle {
  @Source("sample.png")
  public ImageResource sample();

  // Other resources ...
}

And in your codes:

{
// Prefetches the image. This steps seems unavoidable as the 
loadHandler/loadListener in 
// GWT doesn't seem to work, so we have no way of telling if the image is 
loaded otherwise
Image.prefetch(myImageBundle.sample().getURL());

// Creates the <img> with the src to the image resource.
ImageElement imgElement = DOM.createImg().cast();
ImageResource imgRes = myImageBundle.sample();
imgElement.setSrc(imgRes.getURL());

// Draws the clipped image. It should still be correct if there is only one 
image.
surface.drawImage(imgElement, 
    imgRes.getLeft(), imgRes.getTop(), imgRes.getWidth(), imgRes.getHeight(), 
    destX, destY, imgRes.getWidth(), imgRes.getHeight());
}

Let me know if this works for your app and if it speeds up the loading time :)

Original comment by hao1...@gmail.com on 1 Aug 2010 at 4:09

GoogleCodeExporter commented 8 years ago
THANKS Hao, that seems to work perfectly.  And as far as I can tell, 
Image.prefetch isn't really needed - all it does is put the image into a 
HashMap anyway.  Just needed to store a reference to the ImageElement either 
statically or in the module instance to keep it from getting GC'ed.  At that 
point the same ImageElement can be reused to draw the same image over and over 
again if needed, so the "only one image" isn't a problem either (imgRes.getLeft 
and getTop describe the relative position within the composite, not position on 
the screen).

ImageResource imgRes = Resources.INSTANCE.myImage();
// declare imgElement as either module-level instance variable or static
imgElement = Document.get().createImageElement();
imgElement.setSrc(imgRes.getURL());

Original comment by joeh...@gmail.com on 1 Aug 2010 at 5:30

GoogleCodeExporter commented 8 years ago
Great! I will mark this issue as fixed. Feel free to reopen it if you run into 
similar issues.

Original comment by hao1...@gmail.com on 1 Aug 2010 at 7:48

GoogleCodeExporter commented 8 years ago
Note however as a caviat, it only works because I have an animation loop.  The 
line:

image.prefetch(myImageBundle.sample().getURL());

.. does not wait for the image to load (it just prevents GC).  So in my case 
the image shows only because I keep repainting it onto the canvas.  Eventually, 
after it loads - it gets painted.  Firefox doesn't have that problem I think 
because it happens to load  differently or maybe just faster.  But it can be 
reproduced in desktop Chrome (at least on Linux).  Maybe something to do with 
Gecko vs Webkit(?)  I see now what you meant about not having a way to tell 
when ImageResource is loaded.

But in my case (doing animations) its not really an issue.

Thanks again for the help.

Original comment by joeh...@gmail.com on 1 Aug 2010 at 8:10