复制带有Alpha通道的Java SWT图像部分

5
我正在使用Java SWT Images,包含完整的32位颜色和alpha通道(org.eclipse.swt.graphics.Image)。我需要提取图像的矩形区域作为新图像,包括完整的alpha通道信息。
例如,我可能有一个大小为100×100的图像,我需要创建一个新的图像,其中只包含左上角50×50像素的内容,与100×100图像完全相同。(我是在裁剪,而不是重新缩放。)
我最初的尝试是创建一个所需大小的空白图像(在此示例中为50×50),然后获取新图像的GC,然后在新图像上绘制旧图像的正确部分。问题是透明度没有被保留。如果我的新图像开始是不透明的,那么绘制后的结果将完全不透明。如果我的新图像开始是透明的,那么绘制后的结果将完全透明(所有RGB颜色都正确,但因为所有像素的alpha值为零而不可见)。
我的当前解决方案很笨重:我使用GC来绘制图像,然后逐行手动复制alpha通道。
/**
 * Returns a sub-rectangle from the image, preserving alpha transparency.
 * @param source The image from which to copy a portion
 * @param sourceData The ImageData of the source image
 * @param xInSource The x-coordinate in the source image from which to start copying
 * @param yInSource The y-coordinate in the source image from which to start copying
 * @param widthInSource The width (in pixels) of the copied image portion
 * @param heightInSource The height (in pixels) of the copied image portion
 * @param disp The display to use for the new image, or null for the current display
 * @return New image copied from a portion of the source.
 */
private static Image getRectHelper(final Image source, final ImageData sourceData,
        final int xInSource, final int yInSource, final int widthInSource, final int heightInSource, final Display disp)
{
    // In cases like extracting multiple frames at once, we need both the Image and its ImageData without
    // having to extract the ImageData over and over. That’s why this helper takes both parameters.

    // New up an image of the appropriate size
    final Display d = disp==null ? Display.getDefault() : disp;
    final Image dest = new Image(d, widthInSource, heightInSource);

    // This draws the colors from the original image, but does not set the destination alphas
    // (For the  Image class, alpha transparency doesn’t work well – it seems to have been tacked on as an afterthought.)
    final GC g = new GC(dest);
    g.drawImage(source, xInSource, yInSource, widthInSource, heightInSource, 0, 0, widthInSource, heightInSource);
    g.dispose();

    // Get a copy of the dest image data, then sets the destination alphas from the source image
    final ImageData destData = dest.getImageData();
    copyAlpha(sourceData, destData, xInSource, yInSource, widthInSource, heightInSource, 0, 0);

    // Construct a new image with the modified image data
    final Image ret = new Image(d, destData);
    dest.dispose();

    return ret;
}

/**
 * Copies a block of alpha channel information from the sourceData to the destaData. 
 * 
 * @param sourceData The source image data from which to copy alpha information
 * @param destData The destination image data to modify with new alpha information
 * @param xInSource The x-coordinate from which the alpha information should be copied
 * @param yInSource The y-coordinate from which the alpha information should be copied
 * @param width The width (in pixels) of the alpha information to copy
 * @param height The height (in pixels) of the alpha information to copy
 * @param xInDest The x-coordinate to which the alpha information should be copied 
 * @param yInDest The y-coordinate to which the alpha information should be copied
 */
private static void copyAlpha(final ImageData sourceData, final ImageData destData,
        final int xInSource, final int yInSource, final int width, final int height,
        final int xInDest, final int yInDest)
{
    final byte[] alphas = new byte[width];
    for (int ySrc = yInSource, yDst = yInDest; ySrc < yInSource+height; ++ySrc, ++yDst) {
        sourceData.getAlphas(xInSource, ySrc, width, alphas, 0);
        destData.setAlphas(xInDest, yDst, width, alphas, 0);
    }
}

我是否遗漏了什么?我是Java的新手,可能做错了什么。alpha通道对于swt Image类来说真的只是一个附带的考虑吗?肯定有一种更简单和更快速的方法来完成这个任务。我很想直接使用ImageData对象,并完全绕过GC的使用。

1个回答

0

你可能忽略了一个问题,那就是图像有多种透明度类型。http://help.eclipse.org/kepler/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/ImageData.html#getTransparencyType()

在我们用于 SWT 图像的调整大小代码中,我们首先创建一个新的 Image 并获取其 ImageData。然后根据原始图像的 ImageData 的透明度类型,我们执行以下操作之一:

  • 如果 SWT.TRANSPARENCY_ALPHA,则像你的示例一样应用 alpha 即可。
  • 如果 SWT.TRANSPARENCY_PIXEL,则将 ImageData 的 transparentPixel 属性设置为与原始图像的 ImageData 匹配。
  • 如果 SWT.TRANSPARENCY_MASK,则将新 ImageData 的 maskData 和 maskPad 属性设置为与原始图像的 ImageData 匹配。

然后,我们使用 ImageData 创建一个新的 Image(丢弃第一个),并使用 GC 在其上绘制。

希望以上内容能帮助您更接近解决问题。


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