首页 文章

WPF WriteableBitmap用鼠标绘制已加载的图片并保存 . 奇怪的光标移位

提问于
浏览
1

我正在尝试实现一些WPF绘图示例以了解它是如何工作的 . 我可以很快用C解决这个任务,但我想了解WPF的意思 .

在执行任务期间,我面临一些奇怪的问题:鼠标光标的坐标移位负责到我可以在画布上看到的像素 .

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

这是我的代码:

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>

窗口类的实现:

class 成员:

Point currentPoint = new Point();

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

    WriteableBitmap imageWriteableBitmap;

构造函数和初始化(init白色画布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);
            }               
        }
    }

好 . 这很简单 .

现在,两个用例:

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

usecase 1

  • 我装了图片(大小是700x600)并遇到问题,光标有不同的地方(可以看到一个班次):

usecase 2

我认为问题是画布(图像)与实际画面的侧面不同 . 我不确定 .

你能帮我解决一下是什么问题以及如何解决这个问题吗?

谢谢 .

1 回答

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

相关问题