WPF 之上的 C# async/await Task<BitmaptImage> 问题

标签 c# bitmap async-await

微型 WPF 应用程序使用灰度输入参数以异步/等待方式转换图像(BitmapImage)。

我读了很多实现,但没能成功:/

按钮方法:

private async void btnConvertImage_ClickAsync(object sender, RoutedEventArgs e)
{
    try
    {
        var cts = new CancellationTokenSource();
        BitmapImage result = await ImageProcessing.GreyscaleAsync(orginalImage, cts.Token).ConfigureAwait(false);
        imgPhotoConverted.Source = result;
    }
}

灰度任务定义:

public static async Task<BitmapImage> GreyscaleAsync(BitmapImage inputBitmapImage, CancellationToken cancellationToken)
{
    return await Task.Run(() =>
    {
        Bitmap inputBitmap = ToBitmap(inputBitmapImage);
        Bitmap outputImage = new Bitmap(inputBitmap.Width, inputBitmap.Height);
        for (int i = 0; i < inputBitmap.Width; i++)
        {
            for (int x = 0; x < inputBitmap.Height; x++)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Color imageColor = inputBitmap.GetPixel(i, x);
                int grayScale = (int)((imageColor.R * 0.21) + (imageColor.G * 0.72) + (imageColor.B * 0.07));
                Color newColor = Color.FromArgb(imageColor.A, grayScale, grayScale, grayScale);
                outputImage.SetPixel(i, x, newColor);
            }
        }

        return ToBitmapImage(outputImage);
    }, cancellationToken);
}

上线:

imgPhotoConverted.Source = result;

抛出错误:

System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'

最佳答案

您应该阅读有关 async/await 的更多信息 Stephen Clearys Blog .

遵循那里的建议将引导您找到一个非常明智的解决方案

private async void btnConvertImage_ClickAsync(object sender, RoutedEventArgs e)
{
    var originalImage = ( imgPhotoOriginal.Source as BitmapImage );
    BitmapImage result = await Task.Run( () => originalImage.ToBitmap().ToGrayscale().ToBitmapImage() );
    imgPhotoConverted.Source = result;
}

它正在使用这个扩展类

public static class BitmapExtensions
{
    public static Bitmap ToGrayscale( this Bitmap source, CancellationToken cancellationToken = default )
    {
        Bitmap output = new Bitmap( source.Width, source.Height );
        for ( int i = 0; i < source.Width; i++ )
        {
            for ( int x = 0; x < source.Height; x++ )
            {
                cancellationToken.ThrowIfCancellationRequested();
                var imageColor = source.GetPixel( i, x );
                int grayScale = (int)( ( imageColor.R * 0.21 ) + ( imageColor.G * 0.72 ) + ( imageColor.B * 0.07 ) );
                var newColor = System.Drawing.Color.FromArgb( imageColor.A, grayScale, grayScale, grayScale );
                output.SetPixel( i, x, newColor );
            }
        }
        return output;
    }

    public static Bitmap ToBitmap( this BitmapImage source )
    {
        using ( MemoryStream outStream = new MemoryStream() )
        {
            BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add( BitmapFrame.Create( source ) );
            enc.Save( outStream );
            System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap( outStream );

            return new Bitmap( bitmap );
        }
    }

    public static BitmapImage ToBitmapImage( this Bitmap source )
    {
        using ( var memory = new MemoryStream() )
        {
            source.Save( memory, ImageFormat.Png );
            memory.Position = 0;

            var bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = memory;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();
            bitmapImage.Freeze();

            return bitmapImage;
        }
    }
}

关于WPF 之上的 C# async/await Task<BitmaptImage> 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57718242/

相关文章:

c# - 文本框更改时传递隐藏 ID

c# - C# 二进制 PowerShell 模块中的 ValidateScript ParameterAttribute

c# - 如何在以拉伸(stretch)模式显示图像的 pictureBox 中裁剪原始图像?

c# - 如果 "await"已经被 .Start()-ed 过,是否会重生一个任务?

mysql - 如何让提交等到 if 语句运行完毕?

c# - 从 C# AsyncCTP 使用 ExecuteReaderAsync 的任何缺点

c# - 在运行时发送长进程的当前状态

c# - 使用 foreach 循环两个以上的 list<string>

java - 通过触摸检测位图中的颜色

c# - .Net 使用 Lockbits 从位图中获取 RGB 值