javafx가 반투명 커서를 망가 뜨리는 이유는 무엇입니까?
다음은 두 개의 PNG 이미지입니다.
시각적으로 정확히 동일합니다. 유일한 차이점은 일부 픽셀에 반투명 배경이 있다는 것입니다 (이미지를 다운로드하여 확인할 수 있음).
그러나 이러한 이미지를 JavaFX 노드에서 이미지 커서로 사용하면 다음과 같은 결과가 나타납니다.
첫 번째 커서 (부분적으로 투명한 픽셀 없음)는 여전히 선명하지만 두 번째 커서는 왜곡됩니다.
잠시 문제를 해결 한 후이 차이점을 설명하는 알고리즘 인 혼합 모드를 발견했습니다.
"예상"방법 (예 :이 브라우저에서 볼 수 있음)은 알파 값에 의해 가중치가 부여 된 채널당 값의 합계를 가져 오는 것
(1 - alpha) * background_color + alpha * foreground_color
입니다."JavaFX Cursor"는 다른 공식을 제공합니다 :
(1 - alpha) * background_color + alpha^2 * foreground_color
(정사각형에 유의하십시오).
왜곡을 발견했지만 내가 뭘 잘못했는지, 어떻게이 문제를 해결할 수 있는지 알 수 없습니다.
내 테스트 프로그램을위한 완전한 실행 가능한 소스 코드는 다음과 같습니다.
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();
}
}
이러한 반투명 커서를 올바르게 렌더링하려면 어떻게해야합니까?
문제를 해결하는 방법을 찾았습니다 (JDK 8 및 Linux & Windows에서 테스트 됨). 추악하고 반영이 필요하지만 작동하는 것 같습니다. 아래 코드 (Scala 구문이지만 Java에 쉽게 적용 할 수 있음) :
import com.sun.prism.PixelFormat
import javafx.scene.ImageCursor
import javafx.scene.image.{Image, WritableImage}
private def undoPremultipliedAlpha(image: Image): Image = {
// Fixes JavaFX bug with semi-transparent cursors -
// somewhere deep in JavaFX code they premultiply alpha
// on already premultiplied image, which screws up transparencies.
// This method attempts to counteract it by removing premultiplied alpha
// directly from bytes of internal JavaFX image.
def getPlatformImage(image: Image) = image.impl_getPlatformImage()
val platformImage = getPlatformImage(image)
val pixelFormat = platformImage.getClass.getDeclaredMethod("getPixelFormat").invoke(platformImage).asInstanceOf[PixelFormat]
if (pixelFormat != PixelFormat.BYTE_BGRA_PRE) {
println(s"wrong platform image pixel format (${pixelFormat}), unable to apply cursor transparency bug workaround")
} else {
val pixelBufferField = platformImage.getClass.getDeclaredField("pixelBuffer")
pixelBufferField.setAccessible(true)
val pixelBuffer = pixelBufferField.get(platformImage).asInstanceOf[java.nio.Buffer]
val pixelArray = pixelBuffer.array().asInstanceOf[Array[Byte]]
for (i <- 0 until pixelArray.length / 4) {
val alpha = (pixelArray(i * 4 + 3).toInt & 0xff) / 255.0
if (alpha != 0) {
pixelArray(i * 4) = math.min(255, math.max(0, ((pixelArray(i * 4).toInt & 0xff).toDouble / alpha))).toInt.toByte
pixelArray(i * 4 + 1) = math.min(255, math.max(0, ((pixelArray(i * 4 + 1).toInt & 0xff).toDouble / alpha))).toInt.toByte
pixelArray(i * 4 + 2) = math.min(255, math.max(0, ((pixelArray(i * 4 + 2).toInt & 0xff).toDouble / alpha))).toInt.toByte
}
}
}
image
}
def createImageCursor(resource: String, hotspotX: Int, hotspotY: Int): ImageCursor = {
new ImageCursor(
undoPremultipliedAlpha(
new Image(resource)),
hotspotX,
hotspotY
)
}
참고 URL : https://stackoverflow.com/questions/46426283/why-is-javafx-mangling-my-semi-transparent-cursors
'programing tip' 카테고리의 다른 글
Windows 용 최고의 C ++ IDE 또는 편집기 (0) | 2020.10.20 |
---|---|
Android 사용자 정의 ROM에서 통화 중 음성 재생 수정 (0) | 2020.10.20 |
CSS : transform : translate (-50 %, -50 %)는 텍스트를 흐리게 만듭니다. (0) | 2020.10.20 |
Django의 데이터베이스에서 외래 키에 대한 지원 부족을 해결하는 방법 (0) | 2020.10.20 |
bcp / BULK INSERT 대 테이블 반환 매개 변수의 성능 (0) | 2020.10.20 |