开发者

Scaling an Image in GWT

Changing the size of an Image Widget in GWT changes the size of the image element, but does not rescale the image on the screen. Therefore, the following will not work:

Image image = new Image(myImageResource);
image.setHeight(newHeight);
image.setWidth(newWidth);
image.setPixelSize(newWidth, newHeight);

This is because GWT implements its Image widget by setting the backg开发者_运维知识库round-image of the HTML <img... /> element as the image, using CSS.

How does one get the actual image to resize?


I saw this blog entry, which solves the problem by using a GWT DataResource instead of ImageResource. It turns out that the same technique will actually work with ImageResource, if you use it as follows:

Image image = new Image(myImageResource.getURL());
image.setPixelSize(getLength(), getHeight());

To keep aspect ratio calculate it like:

Image image = new Image(myImageResource.getURL());
image.setPixelSize(newWidth, myImageResource.getHeight() * newWidth / myImageResource.getWidth());

As of GWT 2.4, use (see here):

Image image = new Image(myImageResource.getSafeUri());
image.setPixelSize(newWidth, myImageResource.getHeight() * newWidth / myImageResource.getWidth());


If we want to do the same in UIbinder. From an external resource then :

For example we have in recource

@Source("images/logo.png")
ImageResource getLogo();

In UiBinder template declare the <ui:with> element:

<ui:with field='res' type='com.myapp.client.Resources'/>

and below:

<g:Image url='{res.getLogo.getSafeUri.asString}'  pixelSize="Width, Height" />

in older GWT version:

<g:Image url='{res.getLogo.getURL}'  pixelSize="Width, Height" />

but now - Deprecated.

Do not use:

<g:Image resource='{res.getLogo}' pixelSize="Width, Height" />

becouse it doesn't scale images


Try the image loader widget http://code.google.com/p/gwt-image-loader The FitImage class provides what you are looking for.

PS: apply also patches from issues, as there are some minor bugs which I have fixed

  • http://code.google.com/p/gwt-image-loader/issues/detail?id=1
  • http://code.google.com/p/gwt-image-loader/issues/detail?id=3


my final solution was to add a load handler on the image to resize it according to the dimensions of the loaded image (i.e. respectnig the ratio).

image.addLoadHandler(new LoadHandler() {
        @Override
        public void onLoad(LoadEvent event) {
            Element element = event.getRelativeElement();
            if (element == image.getElement()) {
                int originalHeight = image.getOffsetHeight();
                int originalWidth = image.getOffsetWidth();
                if (originalHeight > originalWidth) {
                    image.setHeight(MAX_IMAGE_HEIGHT + "px");
                } else {
                    image.setWidth(MAX_IMAGE_WIDTH + "px");
                }
            }
        }
    });

where MAX_IMAGE_WIDTH and MAX_IMAGE_HEIGHT are constants that determine the maximum allowed size of the image.


I wrote a class which accepts a ImageResource object, and you can set the wanted Pixel size of the Image. It uses CSS background-Position and CSS background-size to achive the aim:

The source code of the class ScalableImage is:

package de.tu_freiberg.informatik.vonwenckstern.client;
// class is written by Michael von Wenckstern, and is also used in ist diploma Thesis
// (this is only for my super visor, that he does not think I copied it from stackoverflow
// without mention the source) - this class is free to use for every body

import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Image;

public class ScalableImage extends Image {
    private int width;
    private int height;
    private ImageResource res;

    public ScalableImage(ImageResource res, int width, int height) {
        this.setUrl(res.getSafeUri());
        this.res = res;
        this.width = width;
        this.height = height;
    }

    @Override
    public void onLoad() {
        int widthOfBigImage = this.getOffsetWidth();
        int heightOfBigImage = this.getOffsetHeight();
        double scaleX = width / res.getWidth();
        double scaleY = height / res.getHeight();
        this.setResource(res);
        DOM.setStyleAttribute(getElement(), "backgroundPosition", Integer.toString((int) (res.getLeft() * -1 * scaleX))+"px "+
                Integer.toString((int) (res.getTop() * -1 * scaleY))+"px ");
        DOM.setStyleAttribute(getElement(), "backgroundSize", Integer.toString((int) (widthOfBigImage * scaleX))+"px "+
                Integer.toString((int) (heightOfBigImage * scaleY))+"px ");
        this.setPixelSize((int) (res.getWidth()* scaleX), (int) (res.getHeight() * scaleY));
    }
}

You can use this class as followed:

rootPanel.add(new ScalableImage(Images.Util.getImages().img0(), 60, 60));

If you use this class together with a PushButton, than you have to add the PushButton to the RootPanel, because otherwise the onLoad() function is not called. An example source code would look like:

for(ImageResource imRes: latexIconsClientBundle) {
            ScalableImage im = new ScalableImage(imRes, 60, 60);
            RootPanel.get().add(im); // PushButton class does not fire onAttach event, so we need to attach the image to the RootPanel
            PushButton btn = new PushButton(im);
            btn.setPixelSize(60, 60);
            if(++col > 9) {
                row++;
                col = 0;
            }
            this.setWidget(row, col, btn);
        }


Here is how I use the canvas element to scale images using HTML5.

http://code.google.com/p/gwt-examples/wiki/gwt_hmtl5

Brandon Donnelson http://gwt-examples.googlecode.com http://c.gawkat.com


From all my test, safeURI work only if you have ONE image in your bundle...So useless to use it because you have one cache.png by Bundle, so it is optimize nothing !

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜