使用 PixelWriter 在 JavaFX Canvas 上透明绘图
Drawing with transparency on JavaFX Canvas using PixelWriter
有谁知道为什么使用 drawImage() 在 Canvas 上绘制透明度效果很好,但使用 PixelWriter 时却根本不起作用?我最初认为它可能与 canvas/context 上的 Blend 或其他 mode/setting 有关,但还没有找到任何运气。
我需要每个像素变量透明度,而不是整个绘制操作的单一透明度值。我将渲染许多“层”(类似于 GIMP 层的工作方式,每个像素具有可选的透明度)。另一个悬而未决的问题是,出于性能原因,我是否最好先将 FINAL 预期输出绘制到 WritableImage,然后再绘制到 Canvas,但这似乎违背了使用 [=23= 的意义] 首先...
下面是一个示例,它显示了首先将部分透明的颜色绘制到图像,然后绘制到 Canvas,然后使用 setColor() 直接绘制到 Canvas。透明区域是Image draw,不透明区域是setColor部分。我们如何让 setColor() 尊重每个像素的颜色 alpha 透明度?
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
public class TransparencyTest extends Application {
private static final int width = 800;
private static final int height = 600;
private Scene scene;
private final Canvas canvas = new Canvas(width, height);
@Override
public void start(Stage stage) {
scene = new Scene(new Group(canvas));
stage.setScene(scene);
render();
stage.show();
exitOnEsc();
}
private void render() {
drawTransparentBg(canvas, 0, 0, width, height);
Color color = Color.web("#77000077");
WritableImage image = new WritableImage(200, 200);
for (int x = 0; x < 200; x++) {
for (int y = 0; y < 200; y++) {
image.getPixelWriter().setColor(x, y, color);
}
}
canvas.getGraphicsContext2D().drawImage(image, 50, 50);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
canvas.getGraphicsContext2D().getPixelWriter().setColor(x, y, color);
}
}
}
public void drawTransparentBg(Canvas canvas, int xPos, int yPos, int width, int height) {
int gridSize = 8;
boolean darkX = true;
String darkCol = "#111111";
String lightCol = "#222266";
for (int x = xPos; x < canvas.getWidth(); x += gridSize) {
boolean dark = darkX;
darkX = !darkX;
if (x > width) {
break;
}
for (int y = yPos; y < canvas.getHeight(); y += gridSize) {
if (y > height) {
break;
}
dark = !dark;
String color;
if (dark) {
color = darkCol;
} else {
color = lightCol;
}
canvas.getGraphicsContext2D().setFill(Paint.valueOf(color));
canvas.getGraphicsContext2D().fillRect(x, y, gridSize, gridSize);
}
}
}
private void exitOnEsc() {
scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode().equals(KeyCode.ESCAPE)) {
Platform.exit();
}
});
}
}
GraphicsContext
begins with the default BlendMode
, and all forms of drawImage()
use the current mode. In contrast, PixelWriter
方法替换值,忽略BlendMode
.
下面的示例让您可以使用支持的 BlendMode
值进行试验以查看效果。相关示例显示 and here.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ChoiceBox;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TransparencyTest extends Application {
private static final int S = 8;
private static final int W = S * 36;
private static final int H = W;
private final Canvas canvas = new Canvas(W, H);
private final GraphicsContext g = canvas.getGraphicsContext2D();
private BlendMode mode = g.getGlobalBlendMode();
@Override
public void start(Stage stage) {
render(mode);
BorderPane root = new BorderPane(new Pane(canvas));
ObservableList<BlendMode> modes
= FXCollections.observableArrayList(BlendMode.values());
ChoiceBox<BlendMode> cb = new ChoiceBox<>(modes);
cb.setValue(mode);
cb.valueProperty().addListener((o) -> {
render(cb.getValue());
});
root.setBottom(cb);
stage.setScene(new Scene(root));
stage.show();
}
private void render(BlendMode mode) {
drawBackground();
g.setGlobalBlendMode(mode);
Color color = Color.web("#7f00007f");
int s = 24 * 8;
WritableImage image = new WritableImage(s, s);
for (int x = 0; x < s; x++) {
for (int y = 0; y < s; y++) {
image.getPixelWriter().setColor(x, y, color);
}
}
s = 6 * 8;
g.drawImage(image, s, s);
for (int x = 0; x < s; x++) {
for (int y = 0; y < s; y++) {
g.getPixelWriter().setColor(x, y, color);
}
}
}
public void drawBackground() {
g.setGlobalBlendMode(BlendMode.SRC_OVER);
Color darkCol = Color.web("#333333");
Color lightCol = Color.web("#cccccc");
boolean dark = false;
for (int x = 0; x < W; x += S) {
dark = !dark;
for (int y = 0; y < H; y += S) {
dark = !dark;
g.setFill(dark ? darkCol : lightCol);
g.fillRect(x, y, S, S);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
有谁知道为什么使用 drawImage() 在 Canvas 上绘制透明度效果很好,但使用 PixelWriter 时却根本不起作用?我最初认为它可能与 canvas/context 上的 Blend 或其他 mode/setting 有关,但还没有找到任何运气。
我需要每个像素变量透明度,而不是整个绘制操作的单一透明度值。我将渲染许多“层”(类似于 GIMP 层的工作方式,每个像素具有可选的透明度)。另一个悬而未决的问题是,出于性能原因,我是否最好先将 FINAL 预期输出绘制到 WritableImage,然后再绘制到 Canvas,但这似乎违背了使用 [=23= 的意义] 首先...
下面是一个示例,它显示了首先将部分透明的颜色绘制到图像,然后绘制到 Canvas,然后使用 setColor() 直接绘制到 Canvas。透明区域是Image draw,不透明区域是setColor部分。我们如何让 setColor() 尊重每个像素的颜色 alpha 透明度?
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
public class TransparencyTest extends Application {
private static final int width = 800;
private static final int height = 600;
private Scene scene;
private final Canvas canvas = new Canvas(width, height);
@Override
public void start(Stage stage) {
scene = new Scene(new Group(canvas));
stage.setScene(scene);
render();
stage.show();
exitOnEsc();
}
private void render() {
drawTransparentBg(canvas, 0, 0, width, height);
Color color = Color.web("#77000077");
WritableImage image = new WritableImage(200, 200);
for (int x = 0; x < 200; x++) {
for (int y = 0; y < 200; y++) {
image.getPixelWriter().setColor(x, y, color);
}
}
canvas.getGraphicsContext2D().drawImage(image, 50, 50);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
canvas.getGraphicsContext2D().getPixelWriter().setColor(x, y, color);
}
}
}
public void drawTransparentBg(Canvas canvas, int xPos, int yPos, int width, int height) {
int gridSize = 8;
boolean darkX = true;
String darkCol = "#111111";
String lightCol = "#222266";
for (int x = xPos; x < canvas.getWidth(); x += gridSize) {
boolean dark = darkX;
darkX = !darkX;
if (x > width) {
break;
}
for (int y = yPos; y < canvas.getHeight(); y += gridSize) {
if (y > height) {
break;
}
dark = !dark;
String color;
if (dark) {
color = darkCol;
} else {
color = lightCol;
}
canvas.getGraphicsContext2D().setFill(Paint.valueOf(color));
canvas.getGraphicsContext2D().fillRect(x, y, gridSize, gridSize);
}
}
}
private void exitOnEsc() {
scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode().equals(KeyCode.ESCAPE)) {
Platform.exit();
}
});
}
}
GraphicsContext
begins with the default BlendMode
, and all forms of drawImage()
use the current mode. In contrast, PixelWriter
方法替换值,忽略BlendMode
.
下面的示例让您可以使用支持的 BlendMode
值进行试验以查看效果。相关示例显示
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ChoiceBox;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TransparencyTest extends Application {
private static final int S = 8;
private static final int W = S * 36;
private static final int H = W;
private final Canvas canvas = new Canvas(W, H);
private final GraphicsContext g = canvas.getGraphicsContext2D();
private BlendMode mode = g.getGlobalBlendMode();
@Override
public void start(Stage stage) {
render(mode);
BorderPane root = new BorderPane(new Pane(canvas));
ObservableList<BlendMode> modes
= FXCollections.observableArrayList(BlendMode.values());
ChoiceBox<BlendMode> cb = new ChoiceBox<>(modes);
cb.setValue(mode);
cb.valueProperty().addListener((o) -> {
render(cb.getValue());
});
root.setBottom(cb);
stage.setScene(new Scene(root));
stage.show();
}
private void render(BlendMode mode) {
drawBackground();
g.setGlobalBlendMode(mode);
Color color = Color.web("#7f00007f");
int s = 24 * 8;
WritableImage image = new WritableImage(s, s);
for (int x = 0; x < s; x++) {
for (int y = 0; y < s; y++) {
image.getPixelWriter().setColor(x, y, color);
}
}
s = 6 * 8;
g.drawImage(image, s, s);
for (int x = 0; x < s; x++) {
for (int y = 0; y < s; y++) {
g.getPixelWriter().setColor(x, y, color);
}
}
}
public void drawBackground() {
g.setGlobalBlendMode(BlendMode.SRC_OVER);
Color darkCol = Color.web("#333333");
Color lightCol = Color.web("#cccccc");
boolean dark = false;
for (int x = 0; x < W; x += S) {
dark = !dark;
for (int y = 0; y < H; y += S) {
dark = !dark;
g.setFill(dark ? darkCol : lightCol);
g.fillRect(x, y, S, S);
}
}
}
public static void main(String[] args) {
launch(args);
}
}