我有一个 org.eclipse.swt.graphics.Image,从 PNG 加载,并且想要以高质量缩放它(抗锯齿、插值)。但我不想失去透明度并只得到白色背景。 (我需要这个图像将其放在 org.eclipse.swt.widgets.Label 上。)
有人知道该怎么做吗? 谢谢!
基于Mark的回答我找到了一个更好的解决方案,没有“hacky bit”:首先从原点复制
alphaData
,然后使用GC
缩放图像。
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;
}
这样我们就不必对底层 ImageData 做出假设。
使用 Sean Bright 在这里描述的方法:https://stackoverflow.com/a/15685473/6245535,我们可以从图像中提取 alpha 信息,并用它来填充
ImageData.alphaData
数组,该数组负责透明度:
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;
}
请注意,此方法假设您正在使用 32 位颜色深度;否则将无法工作。
所以,我真的不明白为什么会这样。
我想对正确像素上的 alpha 数据进行平均,因为 Loris 给出的答案在缩小时给了我奇怪的结果。我认为它只是为了扩大规模。
我已经对此进行了测试,将 240 x 240(像素)图像缩放到各种尺寸:
(280 x 50)、(40 x 40)、(50 x 50)、(40 x 60)、(280 x 280)和(250 x 300)。
我选择这个主要是为了尝试涵盖所有不同的情况,包括缩放到倍数(40 x 40)和缩放到非倍数的东西,例如(50 x 50)和(280 x 280)。
坦率地说,如果有人能告诉我为什么在除以比例差之前将一个区域中的字节相乘是有效的,我很想知道。我首先尝试将它们相加并除以,但这也给出了不稳定的结果。
public static Image scaleImage(Display display, Point size, Image orig)
{
final Rectangle origBounds = orig.getBounds();
if (origBounds.width == size.x && origBounds.height == size.y)
{
return orig;
}
final ImageData origData = orig.getImageData();
final ImageData destData = new ImageData(size.x, size.y, origData.depth, origData.palette);
boolean scaleUpX = origBounds.width <= size.x;
boolean scaleUpY = origBounds.height <= size.y;
if (origData.alphaData != null)
{
destData.alphaData = new byte[destData.width * destData.height];
int xScale = scaleUpX ? size.x / origBounds.width:origBounds.width / size.x;
int yScale = scaleUpY ? size.x / origBounds.width:origBounds.height / size.y;
for (int destRow = 0; destRow < destData.height; destRow++)
{
for (int destCol = 0; destCol < destData.width; destCol++)
{
byte pixAvg = (byte) 0;
for (int avgRow = destRow * yScale; avgRow < (destRow + 1) * yScale; avgRow++)
{
for (int avgCol = destCol * xScale; avgCol < (destCol + 1) * xScale; avgCol++)
{
int ind = avgRow * origData.width + avgCol;
pixAvg *= ind < origData.alphaData.length ? origData.alphaData[avgRow * origData.width + avgCol] : 0;
}
}
pixAvg = (byte) ((byte) pixAvg / ((byte) ((double) xScale * (double) yScale)));
final int d = destRow * destData.width + destCol;
destData.alphaData[d] = pixAvg;
}
}
}
final Image dest = new Image(display, 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, size.x, size.y);
gc.dispose();
return dest;
}```