c# - 在线程池中的 Windows Phone 8 上创建图像缩略图

标签 c# image-processing windows-phone-8 threadpool

我需要在 WP8 上创建图像的缩略图,目前我遇到了困难。简而言之,我知道执行此操作的唯一方法,即使用类 System.Windows.Controls.ImageSystem.Windows.Media.Imaging.BitmapImageSystem.Windows.Media.Imaging.WritableBitmap。我还尝试在线程池上执行缩略图创建,因为它是其他更大操作的一部分,它在线程池上运行。

正如您可能已经了解的那样,即使我尝试创建上述类的实例,我也会因无效的跨线程访问而失败。真的很遗憾,因为这个缩略图甚至不会在 UI 中使用,只会保存到文件中,稍后从文件中显示。我的工作与 UI 线程无关,我仍然面临这个限制。

那么有没有其他方法可以从图像流中创建缩略图(我是从 PhotoChooser 任务中获取的)?也许其他一些不需要那些 UI 绑定(bind)类的 API?尝试搜索它,甚至用谷歌搜索它,但都没有成功。

最佳答案

好吧,我想我也会把我自己的答案放在这里,因为它从不同的角度展示了一些东西。 Justin Angel 的回答没问题,但有几个问题:

  1. 当代码深入模型层并在后台线程上运行时,不可能引用 Dispatcher。
  2. 我需要从该方法返回缩略图图像,稍后在相同的同步上下文中使用它。否则,我将不得不围绕这种创建缩略图的方法更改大量代码。

考虑到这个要求,这是我的解决方案:

private WriteableBitmap CreateThumbnail(Stream stream, int width, int height, SynchronizationContext uiThread)
        {
            // This hack comes from the problem that classes like BitmapImage, WritableBitmap, Image used here could 
            // only be created or accessed from the UI thread. And now this code called from the threadpool. To avoid
            // cross-thread access exceptions, I dispatch the code back to the UI thread, waiting for it to complete
            // using the Monitor and a lock object, and then return the value from the method. Quite hacky, but the only
            // way to make this work currently. It's quite stupid that MS didn't provide any classes to do image 
            // processing on the non-UI threads.
            WriteableBitmap result = null;
            var waitHandle = new object();
            lock (waitHandle)
            {
                uiThread.Post(_ => 
                {
                    lock (waitHandle)
                    {
                        var bi = new BitmapImage();
                        bi.SetSource(stream);

                        int w, h;
                        double ws = (double)width / bi.PixelWidth;
                        double hs = (double)height / bi.PixelHeight;
                        double scale = (ws > hs) ? ws : hs;
                        w = (int)(bi.PixelWidth * scale);
                        h = (int)(bi.PixelHeight * scale);

                        var im = new Image();
                        im.Stretch = Stretch.UniformToFill;
                        im.Source = bi;

                        result = new WriteableBitmap(width, height);
                        var tr = new CompositeTransform();
                        tr.CenterX = (ws > hs) ? 0 : (width - w) / 2;
                        tr.CenterY = (ws < hs) ? 0 : (height - h) / 2;
                        tr.ScaleX = scale;
                        tr.ScaleY = scale;
                        result.Render(im, tr);
                        result.Invalidate();
                        Monitor.Pulse(waitHandle);
                    }

                }, null);

                Monitor.Wait(waitHandle);
            }
            return result;
        }

当我仍在 UI 线程中(在 View 模型中)时,我正在捕获 UI 线程的 SynchronizationContext,并进一步传递它,然后我使用闭包来捕获局部变量,以便它们可用于在 UI 线程上运行的回调。我还使用 lock 和 Monitor 来同步这两个线程并等待图像准备就绪。

我会根据投票接受我或 Justin Angel 的回答(如果有的话)。 :)

编辑:当您在 UI 线程(例如,在按钮单击处理程序中)。像这样:

private async void CreateThumbnailButton_Clicked(object sender, EventArgs args)
    {
        SynchronizationContext uiThread = SynchronizationContext.Current;
        var result = await Task.Factory.StartNew<WriteableBitmap>(() =>
            {
                Stream img = GetOriginalImage();// get the original image through a long synchronous operation
                return CreateThumbnail(img, 163, 163, uiThread);
            });
        await SaveThumbnailAsync(result);
    }

关于c# - 在线程池中的 Windows Phone 8 上创建图像缩略图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14852897/

相关文章:

silverlight - 在 Silverlight 3 中使用 WriteableBitmap 调整图像大小

c# - Azure 移动服务查询不返回所有行

windows-phone-8 - WP8中如何使用AudioVideoCptureDevice录制视频

c# - 在 web api Controller (.net 核心)中使用异步/等待或任务

c# - 基本 LINQ 语法

python - 当没有数据像素时对图像应用滤镜

c# - 使用XNA接入GPGPU进行图像处理

c# - ASP.NET 捕获并替换 Global.asax 中的输出

c# - 从外部配置文件中读取部分 appSettings

c# - Windows Phone 8 Geolocator 缓存位置