我尝试用c ++编写WP应用程序,并且模糊.png图像有一个奇怪的问题。它有时有效,有时也不行。当它不起作用时,看起来好像图像是不可见的。只是为了确保我在C#中实现了相同的功能,它运行得很好。这是我的C#代码
private async void blurDefaultAvatar() {
try {
var storageFile = await Package.Current.InstalledLocation.GetFileAsync("Assets\\menu_user.png");
using(var imgStream = await storageFile.OpenReadAsync()) {
using(var stream = await getBlurredImageStreamWithStream(imgStream, CanvasBitmapFileFormat.Png)) {
var bitmap = new BitmapImage();
bitmap.SetSource(stream);
blurredAvatar.Source = bitmap;
}
}
} catch(Exception e) {
System.Diagnostics.Debug.WriteLine("Avatar load fail: {0}", e.Message);
}
}
private async Task<IRandomAccessStream> getBlurredImageStreamWithStream(IRandomAccessStream stream, CanvasBitmapFileFormat format) {
try {
var device = new CanvasDevice();
var bitmap = await CanvasBitmap.LoadAsync(device, stream);
var renderer = new CanvasRenderTarget(device, bitmap.SizeInPixels.Width, bitmap.SizeInPixels.Height, bitmap.Dpi);
using(var ds = renderer.CreateDrawingSession()) {
var blur = new GaussianBlurEffect();
blur.BlurAmount = 30.0f;
blur.Source = bitmap;
ds.DrawImage(blur);
}
var imgStream = new InMemoryRandomAccessStream();
await renderer.SaveAsync(imgStream, format);
return imgStream;
} catch(Exception e) {
System.Diagnostics.Debug.WriteLine("Avatar blur fail: {0}", e.Message);
return null;
}
}
或多或少(我希望)等效于c ++
void MainPage::blurDefaultAvatar(){
concurrency::create_task(Package::Current->InstalledLocation->GetFileAsync(L"Assets\\menu_user.png")).then([](concurrency::task<StorageFile^> t){
try{
auto storageFile = t.get();
return concurrency::create_task(storageFile->OpenReadAsync());
} catch(Exception^ e){
std::wstringstream wss;
wss<<"\nAvatar not found: '"<<e->Message->Data()<<"'\n";
OutputDebugString(wss.str().c_str());
return concurrency::create_task(concurrency::create_async([]()->IRandomAccessStreamWithContentType^{ return nullptr; }));
}
}, concurrency::task_continuation_context::use_current()).then([this](concurrency::task<IRandomAccessStreamWithContentType^> t){
try{
auto imgStream = t.get();
concurrency::create_task(getBlurredImageStreamWithStream(imgStream, CanvasBitmapFileFormat::Png)).then([this](IRandomAccessStream^ stream){
if(stream!=nullptr && stream->Size>0){
auto bitmap = ref new BitmapImage();
bitmap->SetSource(stream);
blurredAvatar->Source = bitmap;
}
});
} catch(Exception^ e){
std::wstringstream wss;
wss<<"\nAvatar failed to read: '"<<e->Message->Data()<<"'\n";
OutputDebugString(wss.str().c_str());
}
});
}
IAsyncOperation<IRandomAccessStream^>^ MainPage::getBlurredImageStreamWithStream(IRandomAccessStream^ stream, CanvasBitmapFileFormat format){
return concurrency::create_async([stream, format]() -> IRandomAccessStream^{
auto imgStream = ref new InMemoryRandomAccessStream();
auto device = ref new CanvasDevice();
return concurrency::create_task(CanvasBitmap::LoadAsync(device, stream)).then([stream, device, format, imgStream](concurrency::task<CanvasBitmap^> t){
try {
auto bitmap = t.get();
auto renderer = ref new CanvasRenderTarget(device, bitmap->SizeInPixels.Width, bitmap->SizeInPixels.Height, bitmap->Dpi);
auto ds = renderer->CreateDrawingSession();
auto blur = ref new GaussianBlurEffect();
blur->BlurAmount = 30.0f;
blur->Source = bitmap;
ds->DrawImage(blur);
return concurrency::create_task(renderer->SaveAsync(imgStream, format));
} catch(Exception^ e){
std::wstringstream wss;
wss<<"\nBitmap load fail: '"<<e->Message->Data()<<"'\n";
OutputDebugString(wss.str().c_str());
return concurrency::create_task(concurrency::create_async([]()->void{}));
}
}, concurrency::task_continuation_context::use_current()).then([imgStream](concurrency::task<void> t){
try{
t.get();
return imgStream;
} catch(Exception^ e){
std::wstringstream wss;
wss<<"\nStream save fail: '"<<e->Message->Data()<<"'\n";
OutputDebugString(wss.str().c_str());
return (InMemoryRandomAccessStream^)nullptr;
}
}).get();
});
}
只需按一下按钮即可调出方法。知道什么可能是错的吗?
答案 0 :(得分:2)
您需要关闭()/ Dispose()绘图会话。所以在C#版本中你有:
using(var ds = renderer.CreateDrawingSession()) {
...
ds.DrawImage(blur);
}
退出使用范围会在绘图会话中调用Close()。在C ++ / CX中,使用“delete ds”调用Close()。所以:
auto ds = renderer->CreateDrawingSession();
auto blur = ref new GaussianBlurEffect();
blur->BlurAmount = 30.0f;
blur->Source = bitmap;
ds->DrawImage(blur);
delete ds; // <<<<<---- add this
return concurrency::create_task(renderer->SaveAsync(imgStream, format));
此页面提供了有关“删除”和IDisposable的更多信息。 https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh699870.aspx
您看到这种情况有时会起作用,有时无法正常工作的原因是因为当ds超出范围时它也会关闭。有时这会在SaveAsync调用获取D2D锁之前发生,有时它会在之后发生。这里的最终结果是SaveAsync在绘制模糊之前保存rendertarget的内容,或者在绘制模糊后保存内容。