Остановить непрозрачность в JavaFX LinearGradient

У меня есть следующий документ SVG:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg id="svg602"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   width="324.02335" height="689.724"
   space="preserve" version="1.0">

  <defs id="defs604">
    <linearGradient id="linearGradient3034">
      <stop id="stop3035" offset="0"
            style="stop-color:#0000ff;stop-opacity:1" />
      <stop id="stop3036" offset="1"
            style="stop-color:#ffffff;stop-opacity:0;" />
    </linearGradient>
    <linearGradient id="linearGradient3542"
       xlink:href="#linearGradient3034"
       x1="10" y1="10"
       x2="210" y2="210"
       gradientUnits="userSpaceOnUse" />
  </defs>

  <rect id="r1" x="10" y="10" width="200" height="200"
        style="fill:url(#linearGradient3542);stroke:none" />
</svg>

Я пытаюсь добиться того же в JavaFX с помощью следующего кода:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class GradientSample extends Application {
    public static void main(String[] args) { launch(args); }

    @Override
    public void start(Stage primaryStage) {

        Group mainGroup = new Group();
        Rectangle r = new Rectangle(10, 10, 200, 200);

        Stop[] stops = new Stop[] { new Stop(0, new Color(0.0, 0.0, 1.0, 1.0)), 
                                    new Stop(1, new Color(1.0, 1.0, 1.0, 0.0)) };
        LinearGradient lg = new LinearGradient(10, 10, 210, 210, false, CycleMethod.NO_CYCLE,
                                               stops);
        r.setFill(lg);

        mainGroup.getChildren().add(r);
        Scene scene = new Scene(mainGroup, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Однако SVG отображается (в Inkscape) следующим образом:

введите здесь описание изображения

в то время как сцена JavaFX отображается следующим образом:

введите здесь описание изображения

Очевидно, что непрозрачность (0,0) второй остановки не учитывается JavaFX (если я установил непрозрачность на 1,0 в файле SVG, она будет отображаться как сцена JavaFX).

Я что-то пропустил или мне следует считать это ошибкой?

Есть ли другое решение, как достичь непрозрачности Stop, кроме 1.0 в JavaFX?


person Andreas Fester    schedule 08.01.2016    source источник


Ответы (1)


Вы действительно нашли ошибку, но не в непрозрачности!

Сначала я проверил, работает ли непрозрачность. Например, вы можете разместить метку под прямоугольником, и вы увидите ее, так что проблема не в этом.

Затем я экспортировал изображение как png и отредактировал его. Я обнаружил, что непрозрачность хорошо интерполировалась от 1 до 0, от верхнего левого угла к правому нижнему.

К моему удивлению, красный и зеленый были равны нулю на каждом пикселе !!

Пытаясь найти обнаруженную ошибку, я ничего не нашел, но у меня возникла идея использовать разные конвейеры рендеринга.

Использование -Dprism.order с параметрами d3d (Windows), es2 (Mac) и sw дало один и тот же неверный результат. Но старый и устаревший j2d отлично работал в Windows!

Чтобы проверить это, я немного изменил ваш код:

public void start(Stage primaryStage) {
    Group mainGroup = new Group();
    Rectangle r = new Rectangle(0, 0, 200, 200);

    Stop[] stops = new Stop[] { new Stop(0, new Color(0.0, 0.0, 1.0, 1.0)), 
                                new Stop(1, new Color(1.0, 1.0, 1.0, 0.0)) };
    LinearGradient lg = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, stops);
    r.setFill(lg);

    mainGroup.getChildren().add(r);
    Scene scene = new Scene(mainGroup, 200, 200);
    scene.setFill(Color.TRANSPARENT);
    primaryStage.setScene(scene);
    primaryStage.show();

    WritableImage image = scene.snapshot(null);
    PixelReader pixelReader = image.getPixelReader();

    System.out.println("Color: " + pixelReader.getColor((int)image.getWidth()/2, (int)image.getHeight()/2));
}

Запустив обычные конвейеры, вы увидите такой результат:

Color: 0x0000ff7f

и только с -Dprism.order=j2d вы получите:

Color: 0x7e7eff7f

Как я упоминал ранее, интерполируется непрозрачность, но не цвет RGB: в этом случае кажется, что RGB - это тот, который был от первой остановки.

Так что в какой-то момент мы можем подумать о регрессе, о котором следует сообщить.

person José Pereda    schedule 08.01.2016
comment
Спасибо, что сообщили об этом - person José Pereda; 11.01.2016