How to draw image rotated on JavaFX Canvas?
Asked Answered
U

4

5

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, then draw another image with -50 degrees rotation on the same canvas?

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

Uni answered 15/8, 2013 at 19:39 Comment(0)
S
19

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.

rotatedimages

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); }
}
Suomi answered 15/8, 2013 at 22:28 Comment(1)
This solution fits better in my case.Uni
I
4

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

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

Inclination answered 15/8, 2013 at 20:13 Comment(0)
M
3

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);
    }
Manipulator answered 7/11, 2014 at 9:48 Comment(0)
R
0

I was running into similar problems with ImageViews, after rotating and scaling an image it was not sized correctly by the layout managers of parent containers.

According to the ideas presented here I created an ImageCanvas that reflects the dimension of the rendered image whether it is rotated or scaled.

See https://github.com/treimers/JfxImageCanvas

Enjoy Thorsten

Ratable answered 29/3, 2020 at 20:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.