2015-12-14 22 views
2

我想我的手在編寫WP應用程序在c + +和模糊.png圖像有一個奇怪的問題。它有時起作用,有時不起作用。當它不起作用時,看起來像圖像是不可見的。只是爲了確保我在C#中實現了相同的功能,並且完美地工作。這是我的C#代碼Win2d的模糊並不總是工作在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(); 
    }); 
} 

方法被稱爲一個按下按鈕。任何想法可能是錯誤的?

回答

2

您需要關閉()/處置()繪圖會話。所以在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)); 

此頁面還有一些關於'delete'和IDisposable的信息。 https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh699870.aspx

你看到這個有時工作,有時不工作的原因是因爲當ds超出範圍時它也被關閉。有時這發生在SaveAsync調用抓取D2D鎖之前,有時發生在之後。這裏的最終結果是SaveAsync在繪製模糊之前保存rendertarget的內容,或者在繪製模糊之後保存內容。

+0

太棒了!我錯過了這一點。非常感謝你。 – Kegluneq