WPF WriteableBitmap用鼠标绘制并加载加载的图片。奇怪的光标移动

时间:2018-12-09 11:23:00

标签: c# wpf canvas

我正在尝试实现一些WPF绘图示例,以了解其工作原理。我可以使用C ++很快解决此类任务,但是我想了解WPF的含义。

在执行任务期间,我遇到了一个奇怪的问题:鼠标光标坐标移动到我在画布上可以看到的像素。

首先,我的任务是:从文件中加载一些图片;在图像组件上显示;允许用鼠标绘制图像(如铅笔工具);将更改保存到新文件。任务很容易实现。

这是我的代码:

XAML:

<Window x:Class="MyPaint.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MyPaint"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    Background="#FF000000" 
    mc:Ignorable="d"
    Title="Strange Paint" Height="503.542" Width="766.281" Icon="icons/paint.png">

<Grid >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="50"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="20"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid Grid.Column="0" Grid.Row="1" Width="Auto">
        <StackPanel HorizontalAlignment="Left" Width="Auto" Background="{x:Null}">
            <Button x:Name="arrowButton" Width="25" Height="25" HorizontalAlignment="Left" Click="ArrowButton_Click">
                <Image Source="icons/arrow.png"/>
            </Button>
            <Button x:Name="selectorButton" Width="25" Height="25" Click="SelectorButton_Click" HorizontalAlignment="Left">
                <Image Source="icons/select_selection_tool-128.png"/>
            </Button>
            <Button x:Name="clearButton" Width="25" Height="25" Click="ClearButton_Click" HorizontalAlignment="Left">
                <Image Source="icons/clear.png"/>
            </Button>
            <Button x:Name="pencilButton" Width="25" Height="25" Click="PencilButton_Click" HorizontalAlignment="Left">
                <Image Source="icons/pencil.png"/>
            </Button>
            <Button x:Name="fillButton" Width="25" Height="25" Click="FillButton_Click" HorizontalAlignment="Left">
                <Image Source="icons/fill.png"/>
            </Button>
            <xctk:ColorPicker Width="50"  Name="ClrPcker_Foreground" SelectedColorChanged="ClrPcker_Foreground_SelectedColorChanged">

            </xctk:ColorPicker>
        </StackPanel>
    </Grid>
    <Grid x:Name="drawingCanvas" Grid.Column="1" Grid.Row="1" MouseMove="paintImageCanvas_MouseMove"  MouseLeave="PaintImageCanvas_MouseLeave" MouseLeftButtonUp="PaintImageCanvas_MouseLeftButtonUp">
        <ScrollViewer Grid.Column="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Canvas x:Name="scrCanvas" Width="{Binding ActualWidth, ElementName=paintImageCanvas}" Height="{Binding ActualHeight, ElementName=paintImageCanvas}" >
                <Image x:Name="paintImageCanvas" HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="UniformToFill" MouseDown="paintImageCanvas_MouseDown" MouseMove="paintImageCanvas_MouseMove">

                </Image>
                <Rectangle x:Name="Rect" Stroke="DarkOrange" Visibility="Collapsed" Fill="#77EEEEEE"></Rectangle>
            </Canvas>
        </ScrollViewer>
    </Grid>

    <StackPanel Grid.Row="0">
        <Menu IsMainMenu="True" DockPanel.Dock="Top" Background="#FF000000">
            <MenuItem Header="_File" Foreground="White"  Background="#FF000000">
                <MenuItem x:Name="newMenuItem" Header="_New"  Background="#FF000000" Click="NewMenuItem_Click"/>
                <MenuItem x:Name="openMenuItem" Header="_Open" Click="openMenuItem_Click"  Background="#FF000000"/>
                <MenuItem Header="_Close"  Background="#FF000000"/>
                <MenuItem Header="_Save"  Background="#FF000000" Click="MenuItem_Click"/>
                <MenuItem x:Name="exitMenuItem" Header="_Exit" Click="exitMenuItem_Click"  Background="#FF000000"/>
            </MenuItem>
        </Menu>
        <StackPanel></StackPanel>
    </StackPanel>


</Grid>

窗口类的实现

班级成员:

Point currentPoint = new Point();

    ToolBoxTypes currentSelectedTool = ToolBoxTypes.Unknown;
    Color foregroundColor = Brushes.Black.Color;

    WriteableBitmap imageWriteableBitmap;

构造函数和初始化(初始化白色画布1024x768):

        public MainWindow()
    {
        InitializeComponent();
        ClrPcker_Foreground.SelectedColor = foregroundColor;

        imageWriteableBitmap = BitmapFactory.New(1024, 768);
        paintImageCanvas.Source = imageWriteableBitmap;

        imageWriteableBitmap.Clear(Colors.White);
        int i = 0;

    }

鼠标按下事件(这里我要说的是第一点):

private void paintImageCanvas_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ButtonState == MouseButtonState.Pressed)
        {
            currentPoint = e.GetPosition(paintImageCanvas);
        }
        if (currentSelectedTool == ToolBoxTypes.PencilTool)
        {

        }
    }

鼠标移动事件(如果按下,则在画布上绘制):

        private void paintImageCanvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if(currentSelectedTool == ToolBoxTypes.PencilTool)
            {
                int x1 = Convert.ToInt32(currentPoint.X);
                int y1 = Convert.ToInt32(currentPoint.Y);

                int x2 = Convert.ToInt32(e.GetPosition(paintImageCanvas).X);
                int y2 = Convert.ToInt32(e.GetPosition(paintImageCanvas).Y);

                Console.WriteLine("Mouse X: " + x2 + " Mouse Y: " + y2);
                imageWriteableBitmap.DrawLine(  x1, y1, x2, y2, foregroundColor );



                currentPoint = e.GetPosition(paintImageCanvas);
            }               
        }
    }

好的。那是简单的代码。

现在有两个用例:

  1. 在启动和初始化时,我可以看到白色画布,并且可以用鼠标绘制而没有任何问题(光标跟随像素移动):

usecase 1

  1. 我加载了图片(尺寸为700x600)并遇到问题,光标位于不同的位置(可以看到一个偏移):

usecase 2

我认为问题在于画布(图像)的一面与实际图片的一面不同。我不确定。

您能帮我了解什么是错误的以及如何解决吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

感谢德米特里(查看我的问题的评论),发现了问题的原因:源图片的DPI。

我更改了图片加载代码,并且效果很好:

private void openMenuItem_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Filter = "JPEG files (*.jpg)|*.jpg|PNG files (*.png)|*.png";
        if (openFileDialog.ShowDialog() == true)
        {
            BitmapImage image = new BitmapImage(new Uri(openFileDialog.FileName));                
            imageWriteableBitmap = new WriteableBitmap(image);
            double dpi = 96;
            int width = imageWriteableBitmap.PixelWidth;
            int height = imageWriteableBitmap.PixelHeight;

            int stride = width * 4; 
            byte[] pixelData = new byte[stride * height];
            imageWriteableBitmap.CopyPixels(pixelData, stride, 0);

            BitmapSource bmpSource = BitmapSource.Create(width, height, dpi, dpi, PixelFormats.Bgra32, null, pixelData, stride);

            imageWriteableBitmap = new WriteableBitmap(
                                        bmpSource.PixelWidth,
                                        bmpSource.PixelHeight,
                                        bmpSource.DpiX, bmpSource.DpiY,
                                        bmpSource.Format, null);
            imageWriteableBitmap.WritePixels(
              new Int32Rect(0, 0, bmpSource.PixelWidth, bmpSource.PixelHeight), pixelData, stride, 0);

            paintImageCanvas.Source = imageWriteableBitmap;


        }
    }