在GWT中缩放图像

22

在 GWT 中改变 Image 小部件的大小会改变图像元素的大小,但不会重新缩放屏幕上的图像。因此,以下内容将无法正常工作:

Image image = new Image(myImageResource);
image.setHeight(newHeight);
image.setWidth(newWidth);
image.setPixelSize(newWidth, newHeight);
这是因为GWT通过使用CSS将HTML <img... />元素的background-image设置为图像来实现其Image小部件。

那么如何获取实际图像并调整大小?

7个回答

34

我看到了这篇博客文章,它通过使用GWT DataResource而非ImageResource解决了问题。结果发现,如果按照以下方式使用ImageResource,则相同的技术实际上也能够奏效:

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

保持宽高比的计算方法如下:

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

从 GWT 2.4 开始使用(请参见这里):

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

1
这将调整图像大小,但不会保持其纵横比。 - adranale
2
@adranale:你总是可以计算出正确的比率(添加此内容是因为这是社区维基)。 - Hurda
我无法使用此方法调整图像大小。对我来说毫无作用 :/ - Jacek Kwiecień
只需要使用ImageResource.getURL(),然后可以通过CSS设置图像大小。 - djjeck
2
我对此的问题在于,我认为这有点违背了ImageResource的目的,不是吗?这是否意味着每次调用此方法时都要从服务器加载图像? - Marconius
确保将比率转换为double类型,然后将结果高度转换为int类型。image.setPixelSize(newWidth, (int) (myImageResource.getHeight() * ((double) newWidth / myImageResource.getWidth()))); - jazz

11
如果我们想在UIbinder中实现同样的功能,从外部资源获取内容,那么:

例如,我们在资源中有

@Source("images/logo.png")
ImageResource getLogo();
在 UiBinder 模板中声明 <ui:with> 元素:
<ui:with field='res' type='com.myapp.client.Resources'/>

以下是:

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

在旧版 GWT 中:

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

但现在已被弃用。

不要使用:

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

因为它不能缩放图片


2
仅供参考,您可以用数字值替换“Width”和“Height”,例如:<g:Image url='{res.getLogo.getSafeUri.asString}' pixelSize="32, 32" />。 - MeatFlavourDev

3

3

我的最终解决方案是在图像上添加一个加载处理程序,根据加载的图像尺寸进行调整大小(即保持比例)。

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");
                }
            }
        }
    });

其中MAX_IMAGE_WIDTHMAX_IMAGE_HEIGHT是常量,用于确定图像允许的最大尺寸。


解决方案也在这里提到:http://code.google.com/p/google-web-toolkit/issues/detail?id=3999 - zpon
我喜欢你的“if”,因为它可以防止事件被重复处理。 - Daniel De León

1
我写了一个类,可以接受一个ImageResource对象,并且你可以设置图像的期望像素大小。它使用CSS background-Position和CSS background-size来实现这个目标:
类ScalableImage的源代码如下:
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));
    }
}

您可以按照以下方式使用这个类:
rootPanel.add(new ScalableImage(Images.Util.getImages().img0(), 60, 60));

如果您与PushButton一起使用此类,则必须将PushButton添加到RootPanel中,否则不会调用onLoad()函数。示例源代码如下:
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);
        }

如果必须传递一个ImageResource,例如为带有图标的某个Tree组件使用一些com.sencha.gxt.data.shared.IconProvider,则此方法无效。 - Andreas Covidiot

0

0

从我的所有测试来看,只有在您的捆绑包中有一个图像时,safeURI 才有效...因此使用它是无用的,因为您的每个捆绑包都有一个 cache.png,所以它并没有优化任何内容!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接