Granini
Granini

Reputation: 33

How to scale a transparent org.eclipse.swt.graphics.Image, loaded from a PNG; Java

I have an org.eclipse.swt.graphics.Image, loaded from a PNG, and want to scale it in high quality (antialiasing, interpolation). But I do not want to lose transparency and get just a white background. (I need this Image to put it on an org.eclipse.swt.widgets.Label .)

Does anybody know how to do that? Thank you!

Upvotes: 0

Views: 697

Answers (2)

Fernando Silveira
Fernando Silveira

Reputation: 784

Based on Mark's answer I found a better solution without the "hacky bit": first copy the alphaData from the origin then use GC to scale the image.

public static Image scaleImage(final Device device, final Image orig, final int scaledWidth, final int scaledHeight) {     
    final Rectangle origBounds = orig.getBounds();     
    if (origBounds.width == scaledWidth && origBounds.height == scaledHeight) {     
        return orig;     
    }     

    final ImageData origData = orig.getImageData();     
    final ImageData destData = new ImageData(scaledWidth, scaledHeight, origData.depth, origData.palette);     
    if (origData.alphaData != null) {     
        destData.alphaData = new byte[destData.width * destData.height];     
        for (int destRow = 0; destRow < destData.height; destRow++) {     
            for (int destCol = 0; destCol < destData.width; destCol++) {     
                final int origRow = destRow * origData.height / destData.height;     
                final int origCol = destCol * origData.width / destData.width;     
                final int o = origRow * origData.width + origCol;     
                final int d = destRow * destData.width + destCol;     
                destData.alphaData[d] = origData.alphaData[o];     
            }     
        }     
    }     

    final Image dest = new Image(device, destData);     

    final GC gc = new GC(dest);     
    gc.setAntialias(SWT.ON);     
    gc.setInterpolation(SWT.HIGH);     
    gc.drawImage(orig, 0, 0, origBounds.width, origBounds.height, 0, 0, scaledWidth, scaledHeight);     
    gc.dispose();

    return dest;
}

This way we don't have to make assumptions about the underlying ImageData.

Upvotes: 2

Loris Securo
Loris Securo

Reputation: 7638

Using a method described by Sean Bright here: https://stackoverflow.com/a/15685473/6245535, we can extract the alpha information from the image and use it to fill the ImageData.alphaData array which is responsible for the transparency:

public static Image resizeImage(Display display, Image image, int width, int height) {

    Image scaled = new Image(display, width, height);
    GC gc = new GC(scaled);
    gc.setAntialias(SWT.ON);
    gc.setInterpolation(SWT.HIGH);
    gc.drawImage(image, 0, 0, image.getBounds().width, image.getBounds().height, 0, 0, width, height);
    gc.dispose();

    ImageData canvasData = scaled.getImageData();
    canvasData.alphaData = new byte[width * height];

    // This is the hacky bit that is making assumptions about
    // the underlying ImageData. In my case it is 32 bit data
    // so every 4th byte in the data array is the alpha for that
    // pixel...
    for (int idx = 0; idx < (width * height); idx++) {
        int coord = (idx * 4) + 3;
        canvasData.alphaData[idx] = canvasData.data[coord];
    }

    // Now that we've set the alphaData, we can create our
    // final image
    Image finalImage = new Image(display, canvasData);

    scaled.dispose();

    return finalImage;
}

Note that this method assumes that you are working with 32 bit depth of color; it won't work otherwise.

Upvotes: 2

Related Questions