Has*_*tor 2 c# image-processing threadpool windows-phone-8
我需要在WP8上创建一个图像的缩略图,目前我正面临困难.简而言之,我知道这样做的唯一方法就是使用类System.Windows.Controls.Image,System.Windows.Media.Imaging.BitmapImage而且System.Windows.Media.Imaging.WritableBitmap.我也试图在线程池上执行缩略图创建,因为它是在线程池上运行的其他更大操作的一部分.
正如您可能已经理解的那样,即使我正在尝试创建上述类的实例,我也无法使用无效的跨线程访问.真的很遗憾,因为这个缩略图甚至不会在UI中使用,只保存到文件中,稍后会从文件中显示.我的工作与UI线程无关,我仍然面临着这种局限.
那么有没有其他方法从图像流创建缩略图(我从PhotoChooser任务获得它)?也许一些其他API,不需要那些UI绑定类?试图把它搞定,甚至谷歌它,但没有运气.
好吧,我想我也会在这里提出自己的答案,因为它从一些不同的角度展示了一些东西.贾斯汀·安吉尔的回答是可以的,但是有一些问题:
考虑到这些要求,这是我的解决方案:
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;
}
Run Code Online (Sandbox Code Playgroud)
我正在捕获UI线程的SynchronizationContext,而我仍处于UI线程(在View Model中),并进一步传递,然后我使用闭包来捕获局部变量,以便它们可用于运行的回调在UI线程上.我也使用锁和监视器来同步这两个线程并等待映像准备好.
如果有的话,我会根据投票接受我或Justin Angel的回答.:)
编辑:你可以得到分派器的实例SynchronizationContext通过System.Threading.SynchronizationContext.Current,而你在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);
}
Run Code Online (Sandbox Code Playgroud)