2

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

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

我要解决的问题是阴影看起来太透明了。因此,在明亮、繁忙的背景下,它并没有给白色文本提供足够的分离度。

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

我使用的代码基于Romain Guy 的DropShadowDemo。我使用他的 createDropShadow() 和 gaussianBlurFilter()。但不是在 期间分别paintComponent()绘制阴影和文本,而是提前将它们都绘制到 BufferedImage 上;我在paintComponent(). 也许这是我的问题?但我不明白这会如何降低阴影的不透明度。g2.setComposite()期间我不使用paintComponent()

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

代码的详细信息可以在这里看到:

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

更新

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

最终更新

使用 LookupOp 解决;请参阅下面的代码。

4

1 回答 1

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

它似乎有效(尽管我没有截取前后的屏幕截图进行比较)。

于 2012-04-11T07:07:51.873 回答