Spolupráce s Direct2D

Win2D se implementuje jako vrstva nad Direct2D a podporuje interoperabilitu v obou směrech. Pokud máte objekt Win2D, můžete získat přístup k nativnímu objektu Direct2D, který se používá k jeho implementaci. Pokud máte objekt Direct2D, můžete najít objekt Win2D, který jej obaluje, nebo vytvořit nový, pokud takový objekt ještě neexistuje.

Interoperabilita umožňuje kombinovat a spárovat Win2D s nativními rozhraními API DirectX. Můžete napsat aplikaci, která většinou používá Win2D, ale v libovolném okamžiku přejděte do nativního rozhraní DirectX – třeba k volání některé jiné komponenty rozhraní API nebo třetí strany, která vyžaduje nativní rozhraní. Nebo vaše aplikace může být většinou nativní DirectX, ale můžete přepnout na Win2D na konkrétních místech, kde chcete získat další pohodlí nebo podporu jazyka C#.

API pro interoperabilitu

API pro interoperabilitu s C++/CX jsou definována v hlavičkovém souboru Microsoft.Graphics.Canvas.native.h:

#include <Microsoft.Graphics.Canvas.native.h>

using namespace Microsoft::Graphics::Canvas;

Získání nativního objektu Direct2D zabaleného objektem Win2D:

template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(U^ wrapper);

template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(CanvasDevice^ device, U^ wrapper);

template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(CanvasDevice^ device, U^ wrapper, float dpi);

Pro většinu typů GetWrappedResource lze volat pouze s objektem obálky Win2D jako parametr. U několika typů (viz níže uvedená tabulka) musí být předána také hodnota zařízení a/nebo DPI. Při použití GetWrappedResource s typy, které je nevyžadují, není chybou zadat zařízení nebo DPI.

Jak získat objekt Win2D, který obaluje nativní objekt Direct2D:

template<typename WRAPPER>
WRAPPER^ GetOrCreate(IUnknown* resource);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(CanvasDevice^ device, IUnknown* resource);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(ID2D1Device1* device, IUnknown* resource);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(CanvasDevice^ device, IUnknown* resource, float dpi);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(ID2D1Device1* device, IUnknown* resource, float dpi);

GetOrCreate vrátí existující instanci obálky, pokud již existuje, nebo vytvoří novou obálku, pokud neexistuje. Opakované volání na stejném nativním objektu vrátí pokaždé stejnou obálku, pokud instance obálky nadále existuje. Pokud jsou uvolněny všechny reference na wrapper, takže jeho počet referencí klesne na nulu a wrapper je zničen, každé pozdější volání GetOrCreate bude muset vytvořit nový wrapper.

U některých typů GetOrCreate lze jako parametr volat pouze objekt prostředku Direct2D, zatímco u jiných typů (viz následující tabulka) musí být předán také zařízení a hodnotu DPI. Při použití GetOrCreate s typy, které je nevyžadují, není chybou zadat zařízení nebo DPI. Pokud obálka Win2D již existuje, je v pořádku vynechat zařízení a DPI i pro typy, které by je normálně potřebovaly: tyto parametry se používají pouze při vytváření nových instancí obálky.

GetOrCreate rozumí hierarchii dědičnosti a vždy vytvoří nejvhodnější odvozený typ obálky. Pokud například zavoláte GetOrCreate<CanvasBitmap>(ID2D1Bitmap1*) s ID2D1Bitmap1, který má příznak D2D1_BITMAP_OPTIONS_TARGET, vrácená instance obálky bude ve skutečnosti CanvasRenderTarget (která je odvozena od CanvasBitmap). Naopak, pokud zavoláte GetOrCreate<CanvasRenderTarget>(ID2D1Bitmap1*) s ID2D1Bitmap1, které nemá D2D1_BITMAP_OPTIONS_TARGET, dojde k výjimce InvalidCastException.

Dovedeno do extrému je možné volat GetOrCreate<Object>(IUnknown*) a také GetWrappedResource<IUnknown>(Object^).

Typy podporující interoperabilitu

Typ Win2D Typ Direct2D GetOrCreate parametry GetWrappedResource parametry
CanvasBitmap ID2D1Bitmap1 bez D2D1_BITMAP_OPTIONS_TARGET Device -
CanvasCachedGeometry ID2D1GeometryRealization Device -
CanvasCommandList ID2D1CommandList Device -
CanvasDevice ID2D1Device1 - -
CanvasDrawingSession ID2D1DeviceContext1 - -
CanvasFontFace IDWriteFontFaceReference - -
CanvasFontSet IDWriteFontSet - -
CanvasGeometry ID2D1Geometry nebo jedno z jeho odvozených rozhraní ID2D1PathGeometry, ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry, ID2D1EllipseGeometry, ID2D1TransformedGeometry nebo ID2D1GeometryGroup Device -
CanvasGradientMesh ID2D1GradientMesh Device -
CanvasImageBrush ID2D1BitmapBrush1 (pokud je obrázek CanvasBitmap a SourceRectangle je null) nebo ID2D1ImageBrush (pokud je to jakýkoli jiný typ ICanvasImage nebo pokud SourceRectangle is set) Device Volitelné DPI^1
CanvasLinearGradientBrush ID2D1LinearGradientBrush Device -
CanvasNumberSubstitution IDWriteNumberSubstitution - -
CanvasRadialGradientBrush ID2D1RadialGradientBrush Device -
CanvasRenderTarget ID2D1Bitmap1 s D2D1_BITMAP_OPTIONS_TARGET Device -
CanvasSolidColorBrush ID2D1SolidColorBrush Device -
CanvasStrokeStyle ID2D1StrokeStyle1 - Device
CanvasSvgDocument ID2D1SvgDocument^2 Device -
CanvasSwapChain IDXGISwapChain1 Zařízení, DPI -
CanvasTextFormat IDWriteTextFormat1 - -
CanvasTextLayout IDWriteTextLayout3 Device -
CanvasTextRenderingParameters IDWriteRenderingParams3 - -
CanvasTypography IDWriteTypography - -
CanvasVirtualBitmap ID2D1ImageSource nebo ID2D1TransformedImageSource Device -
ColorManagementProfile ID2D1ColorContext Device Device
EffectTransferTable3D ID2D1LookupTable3D Device -
Microsoft.Graphics.Canvas.Effects.* (více tříd Win2D mapovaných na stejný typ D2D) ID2D1Effect s odpovídajícím D2D1_PROPERTY_TYPE_CLSID Device Zařízení, volitelné DPI^1

Note

^1: Volitelné DPI znamená, že je platné volat GetWrappedResource pro tento typ bez zadání hodnoty DPI, ale pokud zadáte DPI, může být Win2D schopen efektivněji konfigurovat grafy efektů tím, že vynechá redundantní uzly kompenzace DPI. To platí při volání GetWrappedResource u efektu nebo u CanvasImageBrush, který má jako zdrojový obrázek efekt.

Note

^2: když je CanvasSvgDocument vytvořen z ID2D1SvgDocument pomocí nativní interoperability jazyka C++, velikost výřezu prvku ID2D1SvgDocument je ignorována.

Interoperabilita s využitím C++/CX

Tady je příklad spolupráce Win2D s Direct2D pomocí jazyka C++:

#include <Microsoft.Graphics.Canvas.native.h>
#include <d2d1_2.h>

using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::WRL;

// Interop Win2D -> Direct2D.
CanvasDevice^ canvasDevice = ...;
CanvasBitmap^ canvasBitmap = ...;

ComPtr<ID2D1Device> nativeDevice = GetWrappedResource<ID2D1Device>(canvasDevice);
ComPtr<ID2D1Bitmap1> nativeBitmap = GetWrappedResource<ID2D1Bitmap1>(canvasBitmap);

// Interop Direct2D -> Win2D.
canvasDevice = GetOrCreate<CanvasDevice>(nativeDevice.Get());
bitmap = GetOrCreate<CanvasBitmap>(canvasDevice, nativeBitmap.Get());

Note

Interop je také možný prostřednictvím jazyka C#, prostřednictvím různých prostředků (např. pomocí integrovaného zprostředkovatele komunikace COM/WinRT, prostřednictvím rozhraní API csWinRT nebo pomocí blittable bindings). Další informace o ruční interoperabilitě v jazyce C# najdete v dokumentaci k nástroji CsWinRT.

Interoperabilita s využitím C++/WinRT

Interoperabilitu můžete také provádět pomocí C++/WinRT s některými úpravami výše uvedených možností. Všimněte si, že hlavičky C++/WinRT pro součásti prostředí Windows Runtime Win2D by se měly generovat automaticky při přidání balíčku NuGet Win2D do projektu C++/WinRT. Pro zajištění interoperability však budete muset i nadále používat hlavičkový soubor Microsoft.Graphics.Canvas.native.h, který obsahuje nízkoúrovňové rozhraní ABI ICanvasFactoryNative v oboru názvů ABI::Microsoft::Graphics::Canvas. Rozhraní má následující funkce, které můžete použít k provádění vzájemné spolupráce.

HRESULT GetOrCreate(ICanvasDevice* device, IUnknown* resource, float dpi, IInspectable** wrapper);
HRESULT GetNativeResource(ICanvasDevice* device, float dpi, REFIID iid, void** resource);

Zde je příklad ukazující, jak vytvořit CanvasVirtualBitmap z IWICBitmapSource, počínaje IWICBitmapSource a sdíleným CanvasDevice.

#include "pch.h"
#include <wincodec.h>
#include <wincodecsdk.h>
#include <winrt/Microsoft.Graphics.Canvas.h> //This defines the C++/WinRT interfaces for the Win2D Windows Runtime Components
#include <Microsoft.Graphics.Canvas.h> //This defines the low-level ABI interfaces for the Win2D Windows Runtime Components
#include <Microsoft.Graphics.Canvas.native.h> //This is for interop
#include <d2d1_3.h>

using namespace winrt::Microsoft::Graphics::Canvas;
namespace abi {
  using namespace ABI::Microsoft::Graphics::Canvas;
}

namespace winrt::Win2DInteropTest::implementation {
  CanvasVirtualBitmap CreateVirtualBitmapFromBitmapSource(com_ptr<IWICBitmapSource> const& pBitmapSource){
    CanvasDevice sharedDevice = CanvasDevice::GetSharedDevice();

    //First we need to get an ID2D1Device1 pointer from the shared CanvasDevice
    com_ptr<abi::ICanvasResourceWrapperNative> nativeDeviceWrapper = sharedDevice.as<abi::ICanvasResourceWrapperNative>();
    com_ptr<ID2D1Device1> pDevice{ nullptr };
    check_hresult(nativeDeviceWrapper->GetNativeResource(nullptr, 0.0f, guid_of<ID2D1Device1>(), pDevice.put_void()));

    //Next we need to call some Direct2D functions to create the ID2D1ImageSourceFromWic object
    com_ptr<ID2D1DeviceContext1> pContext{ nullptr };
    check_hresult(pDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, pContext.put()));
    com_ptr<ID2D1DeviceContext2> pContext2 = pContext.as<ID2D1DeviceContext2>();
    com_ptr<ID2D1ImageSourceFromWic> pImage{ nullptr };
    check_hresult(pContext2->CreateImageSourceFromWic(pBitmapSource.get(), D2D1_IMAGE_SOURCE_LOADING_OPTIONS_RELEASE_SOURCE, pImage.put()));

    //Finally we need to wrap the ID2D1ImageSourceFromWic object inside 
    com_ptr<::IInspectable> pInspectable{ nullptr };
    auto factory = winrt::get_activation_factory<CanvasDevice, abi::ICanvasFactoryNative>(); //abi::ICanvasFactoryNative is the activation factory for the CanvasDevice class
    check_hresult(factory->GetOrCreate(sharedDevice.as<abi::ICanvasDevice>().get(), pImage.as<::IUnknown>().get(), 0.0f, pInspectable.put())); //Note abi::ICanvasDevice is defined in the header Microsoft.Graphics.Canvas.h
    CanvasVirtualBitmap cvb = pInspectable.as<CanvasVirtualBitmap>();
    return cvb;
  }
}

Nezapomeňte zahrnout hlavičku <unknwn.h> do souboru pch.h před všechny hlavičky WinRT (povinné v sadě SDK 17763 a novější).