我有一个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解决;见下面的代码。
答案 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);
}
它似乎有用(虽然我没有拍摄前后屏幕截图进行比较)。