如何增加高斯模糊的不透明度

时间:2012-04-10 11:51:13

标签: java image-processing alpha

我有一个Java应用程序,我需要在图像上绘制文本。文本,字体和图像都是在运行时确定的。文本需要看起来不错,但在图像上可读(足够对比)。

为了满足这些要求,我创建了一个投影。这是通过在空白/透明BufferedImage上绘制不透明黑色文本,然后应用高斯模糊滤镜来完成的。然后,我再次以不透明的白色在阴影顶部绘制文本。所以我有不透明的白色文字,周围有黑色模糊的阴影,很快就会变得完全透明。然后,我可以在背景图像上绘制此图像。

我想解决的问题是投影看起来太透明了。因此,对于明亮,繁忙的背景,它不会给白色文本足够的分离。

那么如何增加阴影的不透明度?我已经尝试增加高斯模糊的半径,这使阴影更宽,但不会使它更不透明。

我正在使用的代码基于Romain Guy的this DropShadowDemo。我使用他的createDropShadow()和gaussianBlurFilter()。但是,不是在paintComponent()期间单独绘制投影和文本,而是将它们预先绘制到BufferedImage上;我在paintComponent()期间在背景上绘制了这个单独的BufferedImage。也许那是我的问题?但我不知道这会如何降低阴影的不透明度。我在g2.setComposite()期间没有使用paintComponent()

我已经考虑使用某种BufferedImageOp来调整投影的不透明度,例如LookupOp。但是对于一个简单的调整来说似乎需要做很多工作(我猜是创建四个数组)。我不认为RescaleOp会起作用,因为我希望结果alpha与源alpha相同的范围(0到1)。如果我可以指定一个设置新alpha = sqrt(旧alpha)的BufferedImageOp,或类似的东西,那将是理想的。但我不知道一个简单的方法。

这里可以看到代码的细节:

我会在这里包含相关的代码块,但似乎相关的代码量太大(代码墙)......也许只是提供源文件的链接。

更新

看起来Change the alpha value of a BufferedImage?会改变投影的不透明度......基本上是逐个重新计算每个像素的alpha值。 TBD:它是否可移植(例如64位机器),以及它是否足够快。如果我对每个像素a = sqrt(a)a = sin(a * pi * 0.5)(在0到1范围内考虑a),那会慢吗?我很高兴知道是否有一种更简单的方法可以利用可用的优化,例如内置的BufferedImageOps。也许答案是为LookupOp构建数组。有人知道一些示例代码吗?

最终更新

使用LookupOp解决;见下面的代码。

1 个答案:

答案 0 :(得分:0)

下面是我最终得到的代码,使BufferedImage更加不透明。我决定继续使用LookupOp,而不是在每个像素上使用getRGB / setRGB进行可能不可移植且缓慢的循环。设置Lookup数组的工作并不是那么糟糕。

/* Make alpha channel more opaque.
 * Modify the alpha (opacity) channel so that values are higher, but still
 * continuous and monotonically increasing.
 */
private static void adjustOpacity(BufferedImage shadowImage) {
    // Use a lookup table with four arrays;
    // the three for RGB are identity arrays (no change).
    byte identityArray[] = new byte[256];
    for (int i=0; i < 256; i++)
        identityArray[i] = (byte)i;

    byte alphaArray[] = new byte[256];
    // map the range (0..256] to (0..pi/2]
    double mapTo90Deg = Math.PI / 2.0 / 256.0;
    for (int i=0; i < 256; i++) {
        alphaArray[i] = (byte)(Math.sin(i * mapTo90Deg) * 256);
    }

    byte[][] tables = {
            identityArray,
            identityArray,
            identityArray,
            alphaArray
    };
    ByteLookupTable blut = new ByteLookupTable(0, tables);
    LookupOp op = new LookupOp(blut, null);

    // With LookupOp, it's ok for src and dest to be the same image.
    op.filter(shadowImage,  shadowImage);
}

它似乎有用(虽然我没有拍摄前后屏幕截图进行比较)。