none
如何在DrawingVisual中旋转图像?旋转以后如何为图像加上边框? RRS feed

  • 问题

  • 我在DrawingVisual中绘制了一幅图像,请问如何旋转图像?旋转动作开始以前我可以确定图像的边界,从而加上一个选中的边框,但是旋转以后,我如何确定图像边界,在加上一个边框呢?基本代码如下:

        public class ImageControl : Canvas

        {

            private VisualCollection _col;

            private DrawingVisual _dv;

            BitmapImage _image = new BitmapImage(new System.Uri("d:\\Cats_Baby.jpg"));

     

            protected override Visual GetVisualChild(int index)

            {

                return _col[index];

            }

            protected override int VisualChildrenCount

            {

                get

                {

                    return _col.Count;

                }

            }

            public ImageControl()

            {

                _col = new VisualCollection(this);

            }

     

            public void Draw()

            {

               Rect rect = new Rect(this.ActualWidth / 2, this.ActualHeight / 2, _image.Width, _image.Height); 

                DrawingContext dc = _dv.RenderOpen();

                dc.DrawImage(_image, rect); 

                dc.Close();

                _col.Add(_dv); 

            }

     

        }

     

     

     

     


    2011年8月17日 8:49

答案

  • 你好,

    把旋转计算入内就行了。

          rect = new Rect(rectangle.Right - 7.5, rectangle.Top - 7.5, 15, 15);
          rect.Transform(_rotateTrans.Value);
          if (rect.Contains(point)) { return 3; }
    

    旋转的代码改成如下就可以多次旋转。由于GetAngle方法的缘故单次旋转仍然只能是0-180度。其他旋转角度的计算你可以参考我之前帖子里那个Adorner的例子中的计算。

        private void InternalRotate(Point point)
        {
          double x = point.X - StartPoint.X;
          double y = point.Y - StartPoint.Y;
          double centerx = rect.X + rect.Width / 2;
          double centery = rect.Y + rect.Height / 2;
          double angle = GetAngle(StartPoint, point, new Point(centerx, centery));
          if (System.Double.IsNaN(angle)) { angle = 0; }
    
          double angleD = angle / System.Math.PI * 180;
          _rotateTrans.CenterX = centerx;
          _rotateTrans.CenterY = centery;
          _rotateTrans.Angle += angleD;
          RotateTransform rotateOffset = new RotateTransform(angleD, centerx, centery);
          StartPoint = rotateOffset.Transform(StartPoint);
        }
    

     


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 张柱敏 2011年8月23日 1:34
    2011年8月22日 7:22
    版主

全部回复

  • 你好,

    你可以将_dv的RenderTransform属性设为一个RotateTransform, 这样你就可以旋转这个元素。

    边框也可以进行同样的处理。

     


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月18日 9:09
    版主
  • 非常感谢回答!

    我想实现的效果是插入的图像有选中状态,类似IDE设计界面的Button选中的效果,还可以取消这种状态,目前我的实现思路是命中图像以后,先绘制图像,然后在绘制边界,但是旋转以后再这样走,就有问题了。问题是旋转以后的边界不会是一个Rect,所以旋转以后如何确定Visual的精确边界呢?



    2011年8月19日 1:51
  • 你好,

    我觉得简单的解决方案可以这样:先根据旋转前的图像绘制边界,然后把边界和图像一起旋转。

     

    或者也可以通过Adorner来绘制边界,这样可以自动跟随图像一起旋转。

    这里有一个用Adorner的例子,你可以参考一下。

    https://skydrive.live.com/#cid=14362542B2FD72F8&id=14362542B2FD72F8%21210


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月19日 2:31
    版主
  • 您好!Adorner是针对UIElement的,我不知道如何才能转化到DrawingVisual上。因为我不光针对图像操作,还需要在同一面板上对手写笔画进行类似操作。我的问题是旋转以后的处理:旋转完成以后,图像可能会失去焦点,不显示其边界。然后可能会再次命中该图像,再为其加上边框。我不是在inkcanvas上实现的,从Canvas继承的,在其上建立Drawingvisual集合,然后分别实现不同的DrawingVisual(负责自由书写的visual,负责规则图形的visual,负责图片的visual等等)。
    2011年8月19日 3:33
  • 你好,

    可能我之前没有理解正确。是不是边框本身是不需要旋转的,而是用来标示上下左右4个方向的边界?


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月19日 3:41
    版主
  • 前一个是非选中状态,后一个是选中状态。边框上的几个点是为了标识在这个点上可以向左,向右拉伸或缩小或者旋转的动作。里面的内容,可以是图片,视频,笔迹等等。问题是我把drawingvisual旋转45以后,取消选中状态,然后在选中,如何加上边框。我要的效果是边框也需要旋转。而再次选中的时候,边界框和旋转后的内容吻合,这就可能不会是一个矩形了。
    2011年8月19日 4:14
  • 你好,

    那你原来的边框是怎么绘制的呢?不能对边框应用一个RotateTransform吗?


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月19日 5:28
    版主
  • 移动和缩放的时候,我是先绘制内容,然后在依据是否选中来绘制边框,并没有对drawingvisual整体应用变换,是使用DrawingContext的方法手动绘制的(先调用DrawingContext的DrawingImage方法绘制图像,然后再调用我自己写的DrawingBounds方法获得图像的Rect来绘制边界)。因为移动和缩放的时候,获得的边界是Rect,所以能够满足要求。但是旋转就适应不了了。因为旋转后的Rect出来的选中效果不理想(假设旋转以后的图像是菱形,我想要选中边框的形状与其吻合,也是菱形)。

    对整体使用RotateTransform开始旋转的时候,是可以实现边框跟随图像一起旋转。但是旋转完成以后,失去焦点的时候,我需要把边框去掉,只显示内容,按照原来的写法是不行的。这里就不知道如何处理了。



    2011年8月19日 5:50
  • 你好,

    一个思路是用一个自定义的UIElement来包装Visual,为Visual提供旋转、添加边框的功能。这样所有需要这些功能的Visual都可以用这个类来包装。

    你也可以把你现在的代码包括边界的部分贴出来,这样讨论得更清楚一些。如果有一个简单的可以运行的代码就更好了。


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月19日 8:06
    版主
  • https://skydrive.live.com/redir.aspx?cid=8f125a6da8d15aee&resid=8F125A6DA8D15AEE!103

    简单的代码在上面。如果使用UIElement来封装的话,我就担心会不会影响性能,因为我实现的是一个类似电子白板的应用。目前我所有的实现都是自己手动绘制的,包括以后可能引入的视频,其他的几何图形什么的.


    2011年8月19日 9:02
  • 你好,

    下面的代码只对ImageVisual的旋转部分做了少量修改。由于没有改动其他代码,只能对ImageVisual的进行0-180度的一次旋转。

    希望可以用这个思路帮助你解决这个问题。

     

      private void InternalRotate(Point point)
      {
       double x = point.X - StartPoint.X;
       double y = point.Y - StartPoint.Y;
       double centerx = rect.X + rect.Width / 2;
       double centery = rect.Y + rect.Height / 2;
       double angle = GetAngle(StartPoint, point, new Point(centerx, centery));
       if (System.Double.IsNaN(angle)) { angle = 0; }
    
       double angleD = angle / System.Math.PI * 180;
       _rotateTrans.CenterX = centerx;
       _rotateTrans.CenterY = centery;
       _rotateTrans.Angle = angleD;
       //matr.RotateAt(angle, centerx, centery);
       //rect.Transform(matr); 
      }
      /// <summary>
      /// 旋转
      /// </summary>
      /// <param name="point"></param>
      public override void Rotate(Point point)
      {
       if (this.IsLocked) { return; }
       InternalRotate(point);
       this.Draw();
      }
    
    
      RotateTransform _rotateTrans = new RotateTransform();
    
      /// <summary>
      /// 绘制图形
      /// </summary>
      public override void Draw()
      {
       DrawingContext dc = this.RenderOpen();
       dc.PushTransform(_rotateTrans);
       Draw(dc);
       this.DrawBounds(dc);
       dc.Pop();
       dc.Close();
      }
    

    Best regards,

     


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    2011年8月22日 4:12
    版主
  • 非常感谢!

    旋转完成以后,我应该如何对这个图形进行精确的命中操作,比如我再次选中该图形进行移动,缩放等操作?我应该如何确定一个点或Rect和旋转后区域的关系?

    2011年8月22日 6:33
  • 你好,

    把旋转计算入内就行了。

          rect = new Rect(rectangle.Right - 7.5, rectangle.Top - 7.5, 15, 15);
          rect.Transform(_rotateTrans.Value);
          if (rect.Contains(point)) { return 3; }
    

    旋转的代码改成如下就可以多次旋转。由于GetAngle方法的缘故单次旋转仍然只能是0-180度。其他旋转角度的计算你可以参考我之前帖子里那个Adorner的例子中的计算。

        private void InternalRotate(Point point)
        {
          double x = point.X - StartPoint.X;
          double y = point.Y - StartPoint.Y;
          double centerx = rect.X + rect.Width / 2;
          double centery = rect.Y + rect.Height / 2;
          double angle = GetAngle(StartPoint, point, new Point(centerx, centery));
          if (System.Double.IsNaN(angle)) { angle = 0; }
    
          double angleD = angle / System.Math.PI * 180;
          _rotateTrans.CenterX = centerx;
          _rotateTrans.CenterY = centery;
          _rotateTrans.Angle += angleD;
          RotateTransform rotateOffset = new RotateTransform(angleD, centerx, centery);
          StartPoint = rotateOffset.Transform(StartPoint);
        }
    

     


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 张柱敏 2011年8月23日 1:34
    2011年8月22日 7:22
    版主
  • 谢谢了!
    2011年8月23日 1:34