imagegwtcanvasspriteclientbundle

gwt ClientBundle context.drawImage doesn't show image? my 2D engine


My code has not errors but I don't see the image. The image is located at the same place as the ClientBundle file is. Sorry for a chunk of code. In fact I am newbie in GWT (and in Java as well). And I teach myself. I made debugging and I saw the image was loaded, all classes was initialized, but the canvas was empty so far. I use NetBeans IDE 7.3. I will be happy if somebody could give me any advice how to launch this code. Thanks you upfront!

______ResourseInspector (nothing special)______________ The image is located at the same folder.

package info.alexpi.client.engine2D;

import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;

public interface ResourseInspector extends ClientBundle {
  public static final ResourseInspector INSTANCE = GWT.create(ResourseInspector.class); 

  @ClientBundle.Source("image1.png") 
  //GWT.getHostPageBaseURL() or GWT.getModuleBaseURL() - By the way, why it's not allowed to use here?
  ImageResource Img();

}

_____Point2D____

 package info.alexpi.client.engine2D;

   public class Point2D {
   public int x = 0;
   public int y = 0;   
}

___Rect2D____

package info.alexpi.client.engine2D;

public class Rect2D {
   public int x;
   public int y;
   public int w;
   public int h;

   public Rect2D(){
      x = 0;
      y = 0;
      w = 100;
      h = 100;
   }

   public Rect2D(int x, int y, int w, int h){
      this.x = x;
      this.y = y;
      this.w = w;
      this.h = h;
   }
}

______ImgElement2D_______ I need this class to keep width and high of the original image

package info.alexpi.client.engine2D;

import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;

public class ImgElement2D {
   private Rect2D rect = new Rect2D();
   private ImageElement imgElement;
   private Image tempImg;

public ImgElement2D(String imgAddress){
      try {
      Image.prefetch(imgAddress);
      tempImg = new Image(imgAddress);

     // SafeUri fromString = UriUtils.fromString(imgAddress);           
     // tempImg.setUrl(fromString); //SafeUri url

     // this method doesn't trigger
      tempImg.addLoadHandler(new LoadHandler(){
         @Override
         public void onLoad(LoadEvent event) {
            imgElement = (ImageElement) tempImg.getElement().cast();
            rect.x = 0;
            rect.y = 0;
            rect.h = tempImg.getHeight();
            rect.w = tempImg.getWidth();

            //RootPanel.get().remove(image);
         }
      });

   public ImgElement2D(ImageResource resource){
      tempImg = new Image(resource);
      rect.x = 0;
      rect.y = 0;
      rect.h = tempImg.getHeight();
      rect.w = tempImg.getWidth(); 
      imgElement = (ImageElement) tempImg.getElement().cast();

   }

______Sprite2D_______

package info.alexpi.client.engine2D;

import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.dom.client.ImageElement;

public class Sprite2D {
   private Point2D pos = new Point2D();
   private ImgElement2D img;
   private double scale;
   private Rect2D rect = new Rect2D();

   public Sprite2D(ImgElement2D image2D){
      this.img = image2D;
      this.rect = image2D.getRect();
      this.scale = 1.0;
      this.pos.x = 0;
      this.pos.y = 0;
   }

   public void setImage(ImgElement2D image2D){
      this.img = image2D;
   }

   public ImgElement2D getImgElement(){
      return this.img;
   }
________________DRAWING ______________________
   public void draw(Context2d context){
      ImageElement el = this.img.getImg();
      if( el != null) {
      context.drawImage(el, rect.x, rect.y, 
          rect.w, rect.h, pos.x, pos.y, rect.w*scale, rect.h*scale);
      }
   }

_____________Main entry point_________________

package info.alexpi.client;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.CssColor;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import info.alexpi.client.engine2D.ImgElement2D;
import info.alexpi.client.engine2D.Point2D;
import info.alexpi.client.engine2D.Rect2D;
import info.alexpi.client.engine2D.ResourseInspector;
import info.alexpi.client.engine2D.Sprite2D;
import java.util.ArrayList;
import java.util.List;

public class gwtEntryPoint implements EntryPoint {
  static final String holderId = "canvasholder";
  static final String upgradeMessage = "Your browser does not support the HTML5 Canvas. "
                      + "Please upgrade your browser to view this demo.";
  Canvas canvas;
  Canvas backBuffer;
  Context2d context;
  Context2d backBufferContext;
  final CssColor redrawColor = CssColor.make("rgba(255,255,255,0.0)");

  // canvas size, in px
  static final int height = 712;
  static final int width = 800;
  boolean isFirstLoading = true;

  // mouse positions relative to canvas
  int mouseX, mouseY;

  //timer refresh rate, in milliseconds
  static final int refreshRate = 25;
  String imgAddress = GWT.getHostPageBaseURL() + "resources/images/Anthony-Catwalk-Dress.png";

  //String imgAddress = "resources/images/image1.png"; //Second place of image
  String cssAddress = GWT.getHostPageBaseURL() + "resources/myStyle.css";
  double scale = 0.7;
  List<Sprite2D> spriteList = new ArrayList<Sprite2D>();
  ImgElement2D im;

  public gwtEntryPoint() {
  }

 // init the canvases-------------------------------------------------------------------------
  void initCanvas(){
    canvas = Canvas.createIfSupported();
    backBuffer = Canvas.createIfSupported();
    if (canvas == null) {
      RootPanel.get(holderId).add(new Label(upgradeMessage));
      return;
    }

    canvas.setWidth(width + "px");
    canvas.setHeight(height + "px");
    canvas.setCoordinateSpaceWidth(width);
    canvas.setCoordinateSpaceHeight(height);
    backBuffer.setCoordinateSpaceWidth(width);
    backBuffer.setCoordinateSpaceHeight(height);
    canvas.setStyleName(cssAddress); //apply css style
    canvas.getElement().getStyle().setProperty("border", "3px solid #00F");
    RootPanel.get(holderId).add(canvas);
    context = canvas.getContext2d();
    backBufferContext = backBuffer.getContext2d();
  }

  // draw backBuffer ----------------------------------------------------------------------------
  public void drawBuffer(Context2d back, Context2d front){
      front.drawImage(back.getCanvas(), 0, 0);
   }

  void initElements(){

      im = new ImgElement2D(ResourseInspector.INSTANCE.Img()); //ImageResource loading
      Sprite2D sprite = new Sprite2D(im);
      Rect2D r = new Rect2D(0,0, 228, 720); //man
      sprite.setRect(r);
      spriteList.add(sprite);

      //im = new ImgElement2D(imgAddress); //another way of image loading (doesn't trigger)
      sprite = new Sprite2D(im);
      r = new Rect2D(226,12, 230, 283); //white T-shirt
      sprite.setRect(r);
      spriteList.add(sprite);
  }

  void doUpdate(){
      // update the back canvas
      backBufferContext.setFillStyle(redrawColor);
      backBufferContext.fillRect(0, 0, width, height);
      for(int x = 0; x < spriteList.size(); ++x){
         spriteList.get(x).draw(backBufferContext);
        // spriteList.get(x).draw(context);
      }

      drawBuffer(backBufferContext, context);
   }

   // init Assets & Timer -----------------------------------------------------------------------
   void initAssets(){
      initElements();

      final Timer timer = new Timer() {          
         @Override
         public void run() {
            doUpdate();
         }
      };
      timer.scheduleRepeating(refreshRate); 
   }

   @Override
   public void onModuleLoad() {
      initCanvas();
      initAssets();
   }
}

Solution

  • See https://code.google.com/p/google-web-toolkit/issues/detail?id=8180

    This is because, currently, new Image(imageResource) uses a blank GIF and puts the ImageResource as a background image. This is fixed in master and will ship in GWT 2.6 later this year.
    The workaround is to use new Image(imageResource.getSafeUri()). It's not safe to do it in IE6/7 where a sprited image is used, but canvas is not supported there so it's not really an issue in this case (note that you could configure any permutation to use a sprited image rather than a data: URL, so technically it's not safe to use getSafeUri() in any browser; GWT 2.6 will add an isStandalone() method to tell you when it's safe to use it, and this is how new Image(imageResource) will be fixed)