【问题标题】:How to draw image rotated on JavaFX Canvas?如何在 JavaFX Canvas 上绘制旋转的图像?
【发布时间】:2013-08-18 02:22:35
【问题描述】:

我想在旋转的画布上绘制图像。使用drawImage(image, 0, 0) 我可以绘制图像,但我如何将该图像旋转 45 度并绘制它,然后在同一画布上绘制另一个旋转 -50 度的图像?

graphicContext2D 对我不起作用,因为它会旋转所有画布内容。

【问题讨论】:

    标签: javafx-2 javafx-8


    【解决方案1】:

    嗯,我从来没有使用过 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();
    

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

    【讨论】:

      【解决方案2】:

      这是一个示例,遵循与 Katona 的答案类似的原则,唯一的区别是它通过应用自定义变换来围绕任意枢轴点旋转图像。

      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); }
      }
      

      【讨论】:

      • 这个解决方案更适合我的情况。
      【解决方案3】:

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

      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);
          }
      

      【讨论】:

        【解决方案4】:

        我在使用 ImageViews 时遇到了类似的问题,在旋转和缩放图像后,父容器的布局管理器没有正确调整它的大小。

        根据这里提出的想法,我创建了一个 ImageCanvas,它反映了渲染图像的尺寸,无论是旋转还是缩放。

        https://github.com/treimers/JfxImageCanvas

        享受 托尔斯滕

        【讨论】:

          猜你喜欢
          • 2017-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-21
          • 2018-10-07
          • 1970-01-01
          • 2017-06-05
          • 1970-01-01
          相关资源
          最近更新 更多