Win2d模糊并不总是在c ++中工作

时间:2015-12-14 15:08:58

标签: c# visual-c++ windows-phone-8.1 win2d

我尝试用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();
    });
}

只需按一下按钮即可调出方法。知道什么可能是错的吗?

1 个答案:

答案 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的内容,或者在绘制模糊后保存内容。