如何绘制在JavaFX画布上旋转的图像?

时间:2021-12-18 17:04:15

I want to draw image on canvas rotated. with drawImage(image, 0, 0) I can draw image but how can I rotate that image for example 45 degrees and draw it and then draw other image with -50 degrees rotation after previous image on the same canvas?

我想在画布上旋转。使用drawImage(图像,0,0),我可以画出图像,但是我怎样才能将图像旋转45度并绘制出来,然后在相同画布上的前一个图像旋转50度后绘制其他图像?

graphicContext2D does not work for me because it rotate all canvas content.

graphicContext2D不适合我,因为它会旋转所有画布内容。

So how can I do that?

我该怎么做呢?

3 个解决方案

#1


15  

Here is a sample, following similar principles to Katona's answer, only difference is that it rotates images about arbitrary pivot points by applying a custom transform.

这里有一个样本,遵循了卡托纳的答案,唯一的区别是,它通过应用自定义转换来旋转任意主点的图像。

如何绘制在JavaFX画布上旋转的图像?

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

/** Rotates images round pivot points and places them in a canvas */
public class RotatedImageInCanvas extends Application {
    /**
     * Sets the transform for the GraphicsContext to rotate around a pivot point.
     *
     * @param gc the graphics context the transform to applied to.
     * @param angle the angle of rotation.
     * @param px the x pivot co-ordinate for the rotation (in canvas co-ordinates).
     * @param py the y pivot co-ordinate for the rotation (in canvas co-ordinates).
     */
    private void rotate(GraphicsContext gc, double angle, double px, double py) {
        Rotate r = new Rotate(angle, px, py);
        gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
    }

    /**
     * Draws an image on a graphics context.
     *
     * The image is drawn at (tlpx, tlpy) rotated by angle pivoted around the point:
     *   (tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2)
     *
     * @param gc the graphics context the image is to be drawn on.
     * @param angle the angle of rotation.
     * @param tlpx the top left x co-ordinate where the image will be plotted (in canvas co-ordinates).
     * @param tlpy the top left y co-ordinate where the image will be plotted (in canvas co-ordinates).
     */
    private void drawRotatedImage(GraphicsContext gc, Image image, double angle, double tlpx, double tlpy) {
        gc.save(); // saves the current state on stack, including the current transform
        rotate(gc, angle, tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2);
        gc.drawImage(image, tlpx, tlpy);
        gc.restore(); // back to original state (before rotation)
    }

    @Override public void start(Stage stage) {
        Image image = new Image(
            "http://worldpress.org/images/maps/world_600w.jpg", 350, 0, true, true
        );

        // creates a canvas on which rotated images are rendered.
        Canvas canvas = new Canvas(600, 400);
        GraphicsContext gc = canvas.getGraphicsContext2D();

        drawRotatedImage(gc, image,  40,   0,   0);
        drawRotatedImage(gc, image, -50, 400, 200);

        // supplies a tiled background image on which the canvas is drawn.
        StackPane stack = new StackPane();
        stack.setMaxSize(canvas.getWidth(), canvas.getHeight());
        stack.setStyle("-fx-background-image: url('http://1.bp.blogspot.com/_wV5JMD1OISg/TDYTYxuxR4I/AAAAAAAAvSo/a0zT8nwPV8U/s400/louis-vuitton-nice-beautiful.jpg');");
        stack.getChildren().add(
                canvas
        );

        // places a resizable padded frame around the canvas.
        StackPane frame = new StackPane();
        frame.setPadding(new Insets(20));
        frame.getChildren().add(stack);

        stage.setScene(new Scene(frame, Color.BURLYWOOD));
        stage.show();
    }

    public static void main(String[] args) { launch(RotatedImageInCanvas.class); }
}

#2


3  

Well I have never used JavaFX, but browsing it's API documentation, I came up with this solution (I have not actually tried it so it may be wrong):

我从来没有使用过JavaFX,但是浏览它的API文档,我找到了这个解决方案(实际上我没有尝试过它可能是错误的):

Canvas canvas = ...
Image img = ...
GraphicsContext gc = canvas.getGraphicsContext2D();

gc.save(); // saves the current state on stack, including the current transform
gc.rotate(45);
gc.drawImage(img);
gc.restore(); // back to original state (before rotation)

gc.save();
gc.rotate(-50);
gc.drawImage(img);
gc.restore();

I don't know if it works here, but the idea (transformation stack) is borrowed from other drawing API (like OpenGL).

我不知道它是否在这里工作,但是这个想法(转换堆栈)是从其他绘图API(如OpenGL)借鉴的。

#3


2  

The above issue can also be solved by creating different layers of canvas.

上面的问题也可以通过创建不同层次的画布来解决。

private void createLayers(){
        // Layers 1&2 are the same size
        layer1 = new Canvas(300,250);
        layer2 = new Canvas(300,250);

        // Obtain Graphics Contexts
        gc1 = layer1.getGraphicsContext2D();
        gc1.setFill(Color.GREEN);
        gc1.fillOval(50,50,20,20);
        gc1.getCanvas().setRotate(45);
        gc2 = layer2.getGraphicsContext2D();
        gc2.setFill(Color.BLUE);
        gc2.fillOval(100,100,20,20);
        gc.getCanvas().setRotate(135);
    }
        ...

 private void addLayers(){
        // Add Layers
        borderPane.setTop(cb);        
        Pane pane = new Pane();
        pane.getChildren().add(layer1);
        pane.getChildren().add(layer2);
        layer1.toFront();
        borderPane.setCenter(pane);    
        root.getChildren().add(borderPane);
    }

#1


15  

Here is a sample, following similar principles to Katona's answer, only difference is that it rotates images about arbitrary pivot points by applying a custom transform.

这里有一个样本,遵循了卡托纳的答案,唯一的区别是,它通过应用自定义转换来旋转任意主点的图像。

如何绘制在JavaFX画布上旋转的图像?

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

/** Rotates images round pivot points and places them in a canvas */
public class RotatedImageInCanvas extends Application {
    /**
     * Sets the transform for the GraphicsContext to rotate around a pivot point.
     *
     * @param gc the graphics context the transform to applied to.
     * @param angle the angle of rotation.
     * @param px the x pivot co-ordinate for the rotation (in canvas co-ordinates).
     * @param py the y pivot co-ordinate for the rotation (in canvas co-ordinates).
     */
    private void rotate(GraphicsContext gc, double angle, double px, double py) {
        Rotate r = new Rotate(angle, px, py);
        gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
    }

    /**
     * Draws an image on a graphics context.
     *
     * The image is drawn at (tlpx, tlpy) rotated by angle pivoted around the point:
     *   (tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2)
     *
     * @param gc the graphics context the image is to be drawn on.
     * @param angle the angle of rotation.
     * @param tlpx the top left x co-ordinate where the image will be plotted (in canvas co-ordinates).
     * @param tlpy the top left y co-ordinate where the image will be plotted (in canvas co-ordinates).
     */
    private void drawRotatedImage(GraphicsContext gc, Image image, double angle, double tlpx, double tlpy) {
        gc.save(); // saves the current state on stack, including the current transform
        rotate(gc, angle, tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2);
        gc.drawImage(image, tlpx, tlpy);
        gc.restore(); // back to original state (before rotation)
    }

    @Override public void start(Stage stage) {
        Image image = new Image(
            "http://worldpress.org/images/maps/world_600w.jpg", 350, 0, true, true
        );

        // creates a canvas on which rotated images are rendered.
        Canvas canvas = new Canvas(600, 400);
        GraphicsContext gc = canvas.getGraphicsContext2D();

        drawRotatedImage(gc, image,  40,   0,   0);
        drawRotatedImage(gc, image, -50, 400, 200);

        // supplies a tiled background image on which the canvas is drawn.
        StackPane stack = new StackPane();
        stack.setMaxSize(canvas.getWidth(), canvas.getHeight());
        stack.setStyle("-fx-background-image: url('http://1.bp.blogspot.com/_wV5JMD1OISg/TDYTYxuxR4I/AAAAAAAAvSo/a0zT8nwPV8U/s400/louis-vuitton-nice-beautiful.jpg');");
        stack.getChildren().add(
                canvas
        );

        // places a resizable padded frame around the canvas.
        StackPane frame = new StackPane();
        frame.setPadding(new Insets(20));
        frame.getChildren().add(stack);

        stage.setScene(new Scene(frame, Color.BURLYWOOD));
        stage.show();
    }

    public static void main(String[] args) { launch(RotatedImageInCanvas.class); }
}

#2


3  

Well I have never used JavaFX, but browsing it's API documentation, I came up with this solution (I have not actually tried it so it may be wrong):

我从来没有使用过JavaFX,但是浏览它的API文档,我找到了这个解决方案(实际上我没有尝试过它可能是错误的):

Canvas canvas = ...
Image img = ...
GraphicsContext gc = canvas.getGraphicsContext2D();

gc.save(); // saves the current state on stack, including the current transform
gc.rotate(45);
gc.drawImage(img);
gc.restore(); // back to original state (before rotation)

gc.save();
gc.rotate(-50);
gc.drawImage(img);
gc.restore();

I don't know if it works here, but the idea (transformation stack) is borrowed from other drawing API (like OpenGL).

我不知道它是否在这里工作,但是这个想法(转换堆栈)是从其他绘图API(如OpenGL)借鉴的。

#3


2  

The above issue can also be solved by creating different layers of canvas.

上面的问题也可以通过创建不同层次的画布来解决。

private void createLayers(){
        // Layers 1&2 are the same size
        layer1 = new Canvas(300,250);
        layer2 = new Canvas(300,250);

        // Obtain Graphics Contexts
        gc1 = layer1.getGraphicsContext2D();
        gc1.setFill(Color.GREEN);
        gc1.fillOval(50,50,20,20);
        gc1.getCanvas().setRotate(45);
        gc2 = layer2.getGraphicsContext2D();
        gc2.setFill(Color.BLUE);
        gc2.fillOval(100,100,20,20);
        gc.getCanvas().setRotate(135);
    }
        ...

 private void addLayers(){
        // Add Layers
        borderPane.setTop(cb);        
        Pane pane = new Pane();
        pane.getChildren().add(layer1);
        pane.getChildren().add(layer2);
        layer1.toFront();
        borderPane.setCenter(pane);    
        root.getChildren().add(borderPane);
    }