java - मेरे अर्ध-पारदर्शी श्रापों से मैनफोर्स क्यों होता है?



javafx (1)

मुझे समस्या के आसपास काम करने का एक तरीका मिला (JDK 8 और लिनक्स और विंडोज पर परीक्षण किया गया)। यह बदसूरत है और प्रतिबिंब की आवश्यकता है, लेकिन काम करने लगता है। नीचे कोड (स्काला सिंटैक्स में, लेकिन आसानी से जावा के लिए अनुकूलित किया जा सकता है):

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

नीचे दो पीएनजी चित्र हैं:

नेत्रहीन वे बिल्कुल समान हैं - केवल अंतर यह है कि किसी में कुछ पिक्सेल में अर्ध-पारदर्शी पृष्ठभूमि है (आप इसे जांचने के लिए चित्र डाउनलोड कर सकते हैं)।

लेकिन जब मैं उन चित्रों को JavaFX नोड्स पर छवि कर्सर के रूप में उपयोग करता हूं, तो मुझे निम्न परिणाम मिलते हैं:

पहला कर्सर (आंशिक रूप से पारदर्शी पिक्सल के बिना) अभी भी कुरकुरा है, लेकिन दूसरा विकृत हो जाता है।

थोड़ी देर के लिए समस्या से लड़ने के बाद, मैंने एल्गोरिथ्म की खोज की जो इस अंतर के लिए जिम्मेदार है - सम्मिश्रण मोड:

  • "अपेक्षित" तरीका (जो आप इस ब्राउज़र में देख सकते हैं, उदाहरण के लिए) प्रति चैनल मानों का योग लेना है, जो अल्फा मानों से भारित है: (1 - alpha) * background_color + alpha * foreground_color

  • "JavaFX कर्सर" अलग सूत्र देता है: (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();
    }
}

मैं ऐसे अर्ध-पारदर्शी अभिशापों का उचित प्रतिपादन कैसे प्राप्त कर सकता हूं?





javafx