【问题标题】:Rotating graphics?旋转图形?
【发布时间】:2011-03-02 20:17:33
【问题描述】:

我有这段代码,它可以绘制图像。

private void timer1_Tick(object sender, EventArgs e)
{
    Invalidate();
}

protected override void OnPaint(PaintEventArgs e)
{
    var tempRocket = new Bitmap(Properties.Resources.rocket);

    using (var g = Graphics.FromImage(tempRocket))
    {
        e.Graphics.DrawImage(tempRocket, 150, 150);
    }
}

但我该怎么做才能旋转它?

【问题讨论】:

    标签: c#


    【解决方案1】:
    public static Bitmap RotateImage(Bitmap b, float angle)
    {
      //create a new empty bitmap to hold rotated image
      Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
      //make a graphics object from the empty bitmap
      using(Graphics g = Graphics.FromImage(returnBitmap)) 
      {
          //move rotation point to center of image
          g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
          //rotate
          g.RotateTransform(angle);
          //move image back
          g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
          //draw passed in image onto graphics object
          g.DrawImage(b, new Point(0, 0)); 
      }
      return returnBitmap;
    }
    

    【讨论】:

    • Graphics g 的创建应包含在 using 语句中。
    • 在创建 returnBitmap 之后,我发现了另外一件事:returnBitmap.SetResolution(b.Horizo​​ntalResolution, b.VerticalResolution);
    • 不像我预期的那样工作。旋转 30 度后 - X 和 Y 轴也旋转了。我需要用未旋转的轴绘制到新位置!类似于: g.DrawImage(b, new Point( UnrotatedNewX, UnrotatedNewY ) );旋转后的平移将在旋转轴上进行(低于 30 度角)。
    【解决方案2】:

    Graphics.DrawImage 有重载,它采用一个包含三个点的数组来定义目标的平行四边形,例如:

    Graphics.DrawImage Method (Image, Point[])

    备注

    destPoints 参数指定 平行四边形的三个点。这 三点结构代表 左上、右上和 的左下角 平行四边形。第四点是 从前三个外推到 形成一个平行四边形。

    图片所代表的图片 参数被缩放和剪切以适应 平行四边形的形状 由 destPoints 指定 参数。

    MSDN 上也有一篇文章描述了这种方法的使用:How to: Rotate, Reflect, and Skew Images,代码示例如下。不幸的是,该示例还会使图像倾斜,从而使问题复杂化。

    Point[] destinationPoints = {
              new Point(200, 20),   // destination for upper-left point of original
              new Point(110, 100),  // destination for upper-right point of original
              new Point(250, 30)};  // destination for lower-left point of original
    
    Image image = new Bitmap("Stripes.bmp");
    
    // Draw the image unaltered with its upper-left corner at (0, 0).
    e.Graphics.DrawImage(image, 0, 0);
    
    // Draw the image mapped to the parallelogram.
    e.Graphics.DrawImage(image, destinationPoints);
    

    与使用Graphics.Transform 属性相比的主要区别是:

    • 此方法不允许您以度为单位指定旋转角度——您必须使用一些简单的三角函数来导出点。
    • 此转换仅适用于特定图像。
      • 如果您只需要绘制一个旋转的图像并且其他所有图像都不会旋转,那么很好,因为您不必在之后重置Graphics.Transform
      • 如果您想同时旋转多个物体(即旋转“相机”),那就太糟糕了。

    【讨论】:

      【解决方案3】:

      没有剪辑的版本:

      private Bitmap RotateBitmap(Bitmap bitmap, float angle)
          {
              int w, h, x, y;
              var dW = (double)bitmap.Width;
              var dH = (double)bitmap.Height;
      
              double degrees = Math.Abs(angle);
              if (degrees <= 90)
              {
                  double radians = 0.0174532925 * degrees;
                  double dSin = Math.Sin(radians);
                  double dCos = Math.Cos(radians);
                  w = (int)(dH * dSin + dW * dCos);
                  h = (int)(dW * dSin + dH * dCos);
                  x = (w - bitmap.Width) / 2;
                  y = (h - bitmap.Height) / 2;
              }
              else
              {
                  degrees -= 90;
                  double radians = 0.0174532925 * degrees;
                  double dSin = Math.Sin(radians);
                  double dCos = Math.Cos(radians);
                  w = (int)(dW * dSin + dH * dCos);
                  h = (int)(dH * dSin + dW * dCos);
                  x = (w - bitmap.Width) / 2;
                  y = (h - bitmap.Height) / 2;
              }
      
              var rotateAtX = bitmap.Width / 2f;
              var rotateAtY = bitmap.Height / 2f;
      
              var bmpRet = new Bitmap(w, h);
              bmpRet.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
              using (var graphics = Graphics.FromImage(bmpRet))
              {
                  graphics.Clear(Color.White);
                  graphics.TranslateTransform(rotateAtX + x, rotateAtY + y);
                  graphics.RotateTransform(angle);
                  graphics.TranslateTransform(-rotateAtX - x, -rotateAtY - y);
                  graphics.DrawImage(bitmap, new PointF(0 + x, 0 + y));
              }
              return bmpRet;
          }
      

      Primary source

      【讨论】:

        【解决方案4】:

        使用Graphics.RotateTransform 旋转图像。

        protected override void OnPaint(PaintEventArgs e)
        {
            var tempRocket = new Bitmap(Properties.Resources.rocket);
        
            e.Graphics.RotateTransform(30.0F); 
        
            e.Graphics.DrawImage(tempRocket, 150, 150);
        }
        

        【讨论】:

        • 该代码看起来不正确 - 您应该在绘制火箭之前应用转换。为什么要创建g 但不使用它?
        • @Blorgbeard - 关于g,非常正确。这是从 OP 帖子中获取的,我现在已将其删除。
        【解决方案5】:

        您需要应用转换矩阵。 Here 你可以在 GDI+ 中找到关于转换的好例子

        【讨论】:

          猜你喜欢
          • 2013-05-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多