使用JavaFX,我试图将文本绘制到画布上,并将阴影和反射效果链接在一起。
以下代码将显示反射的红色文本,然后将阴影应用于原始文本和反射文本。
Canvas canvas = new Canvas(400,400);
GraphicsContext context = canvas.getGraphicsContext2D();
context.setFont( new Font("Arial Bold", 48) );
context.setFill(Color.RED);
DropShadow shadow = new DropShadow(6, 2, 2, Color.BLACK);
Reflection reflect = new Reflection(10, 1.0, 1.0, 0.0);
shadow.setInput(reflect);
context.setEffect(shadow);
context.fillText("Hello, world!", 100,100);
但是,阴影在反射中显示为“向后”,因为需要首先应用阴影才能获得逼真的效果。我尝试通过更改效果的应用顺序来完成此操作,方法是更改上面的setInput
和setEffect
代码行,如下所示:
reflect.setInput(shadow);
context.setEffect(reflect);
然而,结果是只应用了反射;我根本看不到任何投影。
为什么不应用/不显示投影?
如何重写此代码以达到预期效果(如果可能,仅使用效果组合)?
答案 0 :(得分:1)
我不知道使用标准API使用GraphicsContext
是否可以实现您所说的内容,因此欢迎其他答案。但是,这可能是一个临时的解决方法,只要它实际上是您需要的。首先应用阴影,然后逐个像素地复制图像以模仿反射效果。请看下面的截图:(原件 - 左侧,新的 - 右侧)。
下面附有完整的工作示例。它需要一些调整来获得一般解决方案,但应该有足够的开始。
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class FXApp extends Application {
private Parent createContent() {
Canvas canvas = new Canvas(400,400);
Font font = new Font("Arial Bold", 48);
Color fill = Color.RED;
DropShadow shadow = new DropShadow(6, 2, 2, Color.BLACK);
fillTextWithReflection(canvas.getGraphicsContext2D(), "Hello, world!", 100, 100, font, fill, shadow);
return new Pane(canvas);
}
private void fillTextWithReflection(GraphicsContext g, String text, double textX, double textY, Font font, Color fill, Effect effect) {
Text t = new Text(text);
t.setFont(font);
// 5 px margin
Canvas tmpCanvas = new Canvas(t.getLayoutBounds().getWidth() + 5, t.getLayoutBounds().getHeight() + 5);
// set configuration
GraphicsContext tmpContext = tmpCanvas.getGraphicsContext2D();
tmpContext.setFont(font);
tmpContext.setFill(fill);
tmpContext.setEffect(effect);
// draw on temporary context
tmpContext.fillText(text, 0, font.getSize());
// take a snapshot of the text
WritableImage snapshot = tmpCanvas.snapshot(null, null);
int w = (int)snapshot.getWidth();
int h = (int)snapshot.getHeight();
WritableImage reflected = new WritableImage(w, h);
// make an 'inverted' copy
for (int y = 0; y < h; y++) {
// imitate fading out of reflection
double alpha = y / (h - 1.0);
for (int x = 0; x < w; x++) {
Color oldColor = snapshot.getPixelReader().getColor(x, y);
Color newColor = Color.color(oldColor.getRed(), oldColor.getGreen(), oldColor.getBlue(), alpha);
reflected.getPixelWriter().setColor(x, h - 1 - y, newColor);
}
}
// draw on the actual context
// images are drawn from x, y top-left but text is filled from x, y + h
// hence corrections
// this can be replaced with actual fillText() call if required
g.drawImage(snapshot, textX, textY - font.getSize());
g.drawImage(reflected, textX, textY + h - font.getSize());
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.show();
}
}