为什么javafx会弄乱我的半透明游标?
以下是两幅PNG图像: 从视觉上看,它们完全相同——唯一的区别是其中一些像素的背景是半透明的(您可以下载图像进行检查) 但当我将这些图像用作JavaFX节点上的图像光标时,会得到以下结果: 第一个光标(没有部分透明的像素)仍然清晰,但第二个光标会变形 在与这个问题斗争了一段时间后,我发现了解释这种差异混合模式的算法:为什么javafx会弄乱我的半透明游标?,java,javafx,Java,Javafx,以下是两幅PNG图像: 从视觉上看,它们完全相同——唯一的区别是其中一些像素的背景是半透明的(您可以下载图像进行检查) 但当我将这些图像用作JavaFX节点上的图像光标时,会得到以下结果: 第一个光标(没有部分透明的像素)仍然清晰,但第二个光标会变形 在与这个问题斗争了一段时间后,我发现了解释这种差异混合模式的算法: “预期”方式(例如,您可以在本浏览器中看到)是采用每个通道的值之和,通过alpha值进行加权:(1-alpha)*背景色+alpha*前景色 “JavaFX Cursor
- “预期”方式(例如,您可以在本浏览器中看到)是采用每个通道的值之和,通过alpha值进行加权:
(1-alpha)*背景色+alpha*前景色
- “JavaFX Cursor”给出了不同的公式:
(注意正方形)(1-alpha)*背景色+alpha^2*前景色
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.ImageCursor;
import javafx.scene.image.Image;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
System.out.println(ImageCursor.getBestSize(32, 32));
primaryStage.setTitle("Hello World!");
StackPane root = new StackPane();
root.setCursor(new ImageCursor(new Image("/test-cursor.png"), 0, 0));
primaryStage.setScene(new Scene(root, 100, 100));
primaryStage.show();
}
}
如何正确呈现此类半透明光标?更新:经过深入检查,JavaFX似乎没有问题——问题似乎出在视频驱动程序实现中。下面的代码确实适用于硬件、驱动程序和操作系统的某些组合,但并非所有组合都适用 不幸的是,目前最好的解决方案似乎是避免使用部分透明的白色或灰色像素的光标。不过,部分透明的黑色像素也不错
我找到了解决这个问题的方法(在JDK 8和Linux&Windows上进行了测试)。这很难看,需要反思,但似乎有效。下面的代码(使用Scala语法,但很容易适应Java):
导入com.sun.prism.PixelFormat
导入javafx.scene.ImageCursor
导入javafx.scene.image.{image,writeableimage}
专用预乘Alpha(图像:图像):图像={
//修复了带有半透明游标的JavaFX错误-
//在JavaFX代码的深处,它们预乘alpha
//在已经预乘的图像上,这会破坏透明度。
//此方法试图通过移除预乘alpha来抵消它
//直接从内部JavaFX图像的字节。
def getPlatformImage(image:image)=image.impl_getPlatformImage()
val platformImage=getPlatformImage(图像)
val pixelFormat=platformage.getClass.getDeclaredMethod(“getPixelFormat”).invoke(platformImage.asInstanceOf[pixelFormat]
if(pixelFormat!=pixelFormat.BYTE\u BGRA\u PRE){
println(s“错误的平台图像像素格式(${pixelFormat}),无法应用光标透明度错误解决方法”)
}否则{
val pixelBufferField=platformImage.getClass.getDeclaredField(“pixelBuffer”)
pixelBufferField.setAccessible(真)
val pixelBuffer=pixelBufferField.get(platformImage.asInstanceOf[java.nio.Buffer]
val pixelArray=pixelBuffer.array().asInstanceOf[array[Byte]]
例如(我已经看过@Tschallacka了-是的,我看过了。JFXCustom cursor在性能方面不是很好(它会在应用程序中出现口吃,而本机cursor工作得很顺利),而您链接的问题中的示例也遇到了同样的问题-半透明时白色被渲染为黑色。下面是该问题中的一段稍微重写的代码,它突出了问题:光栅图形不应在光标等图形元素中使用。您使用的图像会放大,从而扭曲。请重试添加多个不同尺寸的图像并使用ImageCursor.chooseBestCursor()
函数。对我来说,尺寸为240 x 240 px的图像效果很好。@Rogach你能帮我做一个,让JavaFX团队看看吗?