C# 在C档旋转仪表指针#

C# 在C档旋转仪表指针#,c#,wpf,graphics,.net-4.5,C#,Wpf,Graphics,.net 4.5,我无法在不进行剪裁的情况下围绕其中心正确旋转针。我找到的旋转代码不会导致剪切,它会以错误的方式旋转针。我在stackoverflow的某个地方找到了代码示例 图1:指向南方的正确位置 Pic2:RotateBitmap4(),旋转位置错误,无剪裁 图3:RotateBitmap5(),纠正旋转点,但剪切 图4:RotateBitmap5(),纠正旋转点,但剪切 使用系统; 使用系统图; 使用System.Drawing.Drawing2D; 使用System.Windows; 使用Syste

我无法在不进行剪裁的情况下围绕其中心正确旋转针。我找到的旋转代码不会导致剪切,它会以错误的方式旋转针。我在stackoverflow的某个地方找到了代码示例

图1:指向南方的正确位置

Pic2:RotateBitmap4(),旋转位置错误,无剪裁

图3:RotateBitmap5(),纠正旋转点,但剪切

图4:RotateBitmap5(),纠正旋转点,但剪切

使用系统;
使用系统图;
使用System.Drawing.Drawing2D;
使用System.Windows;
使用System.Windows.Media.Imaging;
使用点=System.Drawing.Point;
命名空间堆栈溢出
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
专用浮动_角度=0;
公共主窗口()
{
初始化组件();
}
private void Button估计值单击(对象发送方,RoutedEventArgs e)
{
var backgroundImage=新位图(@“”);//指南针圆
var foregroundImage=新位图(@“”);//指南针
foregroundImage=ResizeBitmap(foregroundImage,13,65);
//旋转错误,没有剪辑
//前地面图像=旋转ITMAP4(前地面图像,_角度);
//正确的旋转,剪辑!
前地面图像=旋转ITMAP5(前地面图像,_角度);
var finalImage=新位图(320240);
使用(var graphics=graphics.FromImage(finalImage))
{
//设置背景色
图形。清晰(系统。绘图。颜色。黑色);
graphics.DrawImage(backgroundImage,新系统.绘图.矩形(0,0,backgroundImage.Width,backgroundImage.Height));
//graphics.DrawImage(foregroundImage,新系统.Drawing.Rectangle(int.Parse(TextBoxXOffset.Text),int.Parse(TextBoxYOffset.Text),foregroundImage.Width,foregroundImage.Height));
graphics.DrawImage(foregroundImage,新系统.绘图.矩形(44,18,foregroundImage.Width,foregroundImage.Height));
}
var image=System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(finalImage.GetHbitmap(),IntPtr.Zero,System.Windows.Int32Rect.Empty,BitmapSizeOptions.FromWidthAndHeight(320,240));
ImageTest.Source=图像;
_角度+=20;
如果(_角度>=360)
{
_角度=0;
}
}
专用静态位图ResizeBitmap(位图源位图、整型宽度、整型高度)
{
var结果=新位图(宽度、高度);
使用(var graphics=graphics.FromImage(结果))
{
graphics.DrawImage(源位图,0,0,宽度,高度);
}
返回结果;
}
专用位图RotateBitmap5(位图b,浮动角度)
{
//创建新的空位图以保存旋转的图像。
//位图返回位图=新位图(b.宽度,b.高度);
位图返回位图=新位图(b.高度+500,b.高度+500);
//从空位图创建图形对象。
Graphics g=Graphics.FromImage(返回位图);
//将旋转点移动到图像的中心。
g、 插值模式=插值模式。高质量双三次;
g、 平移变换((浮动)b.宽度/2,(浮动)b.高度/2);
//轮换。
g、 旋转变换(角度);
//向后移动图像。
g、 平移变换(-(浮动)b.宽度/2,-(浮动)b.高度/2);
//将传入的图像绘制到图形对象上。
g、 DrawImage(b,新点(0,0));
返回位图;
}
公共位图旋转位图4(位图b,浮动角度)
{
如果(角度>0)
{
int l=b.宽度;
int h=b.高度;
双安=角度*Math.PI/180;
double cos=Math.Abs(Math.cos(an));
double sin=Math.Abs(Math.sin(an));
int nl=(int)(l*cos+h*sin);
int nh=(int)(l*sin+h*cos);
位图返回位图=新位图(nl,nh);
Graphics g=Graphics.FromImage(返回位图);
g、 翻译形式((浮动)(nl-l)/2,(浮动)(nh-h)/2);
g、 平移变换((浮动)b.宽度/2,(浮动)b.高度/2);
g、 旋转变换(角度);
g、 平移变换(-(浮动)b.宽度/2,-(浮动)b.高度/2);
g、 DrawImage(b,新点(0,0));
返回位图;
}
否则返回b;
}
}
}
XAML是:

<Window x:Class="Stackoverflow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="432" Width="782">
<Grid>
    <Image Name="ImageTest" HorizontalAlignment="Left" Height="260" Margin="22,170,0,0" VerticalAlignment="Top" Width="348"/>
    <Button Name="ButtonTestImage" Content="Test Image" HorizontalAlignment="Left" Margin="490,132,0,0" VerticalAlignment="Top" Width="75" Click="ButtonTestImage_OnClick"/>
</Grid>
</Window>


感谢您提供了非常有用的代码示例。这让理解你的问题变得容易多了

那么,答案是什么

嗯,我有几个建议。首先,使用
System.Drawing
名称空间(主要是为了支持Winforms而设计的)来处理整个位图实际上是错误的。因此,调用
CreateBitmapSourceFromHBitmap()
,将所有Winforms代码的结果映射到与WPF兼容的位图

其次,现有代码中的基本问题是,如果要创建一个新位图,其中覆盖已旋转,则必须确保在该位图中定位旋转的图像,使其完全适合

在您发布的代码中,您只是在旋转后将箭头位图重新定位回其原始位置,而不是将其移动到足够远的位置,以使其具有足够的裕度来解释新的旋转后示意图,当然,当它没有垂直方向时,向左绘制超过其原始宽度一半的任何部分都会偏离位图的边缘。这就是导致剪辑的原因

现在,您可以修复代码以解决该问题,同时仍然保留基本思想。但是,我认为,这种实现完全是浪费。如果要绘制旋转的箭头图像,最好在将其与原始图像合成的同时绘制。不需要创建另一个中间位图,只需
<Window x:Class="Stackoverflow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="432" Width="782">
<Grid>
    <Image Name="ImageTest" HorizontalAlignment="Left" Height="260" Margin="22,170,0,0" VerticalAlignment="Top" Width="348"/>
    <Button Name="ButtonTestImage" Content="Test Image" HorizontalAlignment="Left" Margin="490,132,0,0" VerticalAlignment="Top" Width="75" Click="ButtonTestImage_OnClick"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
    private float _angle = 0;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void ButtonTestImage_OnClick(object sender, RoutedEventArgs e)
    {
        var backgroundImage = new Bitmap(@"Assets\dial.png");//Compass circle
        System.Drawing.Size finalSize = backgroundImage.Size;
        var foregroundImage = new Bitmap(@"Assets\arrow.png");//Compass needle

        foregroundImage = new Bitmap(foregroundImage, 13, 65);

        var finalImage = new Bitmap(finalSize.Width, finalSize.Height);
        using (var graphics = Graphics.FromImage(finalImage))
        {
            graphics.DrawImage(backgroundImage, 0, 0, backgroundImage.Width, backgroundImage.Height);

            graphics.TranslateTransform(backgroundImage.Width / 2f, backgroundImage.Height / 2f);
            graphics.RotateTransform(_angle);
            graphics.TranslateTransform(foregroundImage.Width / -2f, foregroundImage.Height / -2f);

            graphics.DrawImage(foregroundImage, Point.Empty);
        }
        var image = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(finalImage.GetHbitmap(), IntPtr.Zero, System.Windows.Int32Rect.Empty,
            BitmapSizeOptions.FromWidthAndHeight(finalSize.Width, finalSize.Height));
        ImageTest.Source = image;

        _angle += 20;
        if (_angle >= 360)
        {
            _angle = 0;
        }
    }
}
<Window x:Class="TestSO30142795RotateBitmapWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <BitmapImage x:Key="backgroundImage" UriSource="Assets\dial.png"/>
    <BitmapImage x:Key="foregroundImage" UriSource="Assets\arrow.png"/>
  </Window.Resources>
  <Grid>
    <Grid Margin="22,170,0,0" HorizontalAlignment="Left" VerticalAlignment="Top">
      <Image Name="ImageTestBackground" Source="{StaticResource backgroundImage}"
           HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="None"/>
      <Image Name="ImageTestForeground" Source="{StaticResource foregroundImage}"
           HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None"
           RenderTransformOrigin="0.5,0.5">
        <Image.RenderTransform>
          <TransformGroup>
            <ScaleTransform ScaleX="1" ScaleY=".8"/>
            <RotateTransform Angle="{Binding Angle}"/>
          </TransformGroup>
        </Image.RenderTransform>
      </Image>
    </Grid>
    <Button Name="ButtonTestImage" Content="Test Image"
            HorizontalAlignment="Left" VerticalAlignment="Top"
            Margin="490,132,0,0" Width="75"
            Click="ButtonTestImage_OnClick"/>
  </Grid>
</Window>
public partial class MainWindow : Window
{
    public static readonly DependencyProperty AngleProperty =
        DependencyProperty.Register("Angle", typeof(double), typeof(MainWindow));

    public double Angle
    {
        get { return (double)GetValue(AngleProperty); }
        set { SetValue(AngleProperty, value); }
    }

    public MainWindow()
    {
        InitializeComponent();

        DataContext = this;
    }

    private void ButtonTestImage_OnClick(object sender, RoutedEventArgs e)
    {
        double angle = Angle;

        angle += 20;
        if (angle >= 360)
        {
            angle = 0;
        }

        Angle = angle;
    }
}