Szövegmegjelenítés Direct2D és DirectWrite használatával
Más API-któl( például GDI, GDI+ vagy WPF) eltérően Direct2D együttműködik egy másik API-val, DirectWrite, hogy manipulálja és renderelje a szöveget. Ez a témakör a különálló összetevők előnyeit és együttműködését ismerteti.
Ez a témakör a következő szakaszokat tartalmazza.
- Direct2D lehetővé teszi a növekményes bevezetést
- Szövegszolgáltatások és szövegmegjelenítési
- Karakterjelek és Szöveg
- DirectWrite és Direct2D
- Glyph Rendering
- Következtetés
A Direct2D lehetővé teszi a növekményes bevezetést
Az alkalmazások áthelyezése az egyik grafikus API-ból a másikba nehéz lehet, vagy nem az, amit szeretne, különböző okokból. Ennek az lehet az oka, hogy támogatnia kell azokat a beépülő modulokat, amelyek továbbra is a régebbi felületeket használják, mivel maga az alkalmazás túl nagy ahhoz, hogy egy kiadásban egy új API-t portoljon át, vagy azért, mert az újabb API egy része kívánatos, de a régebbi API elég jól működik az alkalmazás más részeihez.
Mivel Direct2D és DirectWrite különálló összetevőkként vannak implementálva, frissítheti a teljes 2D grafikus rendszert, vagy csak a szövegrészét. Például frissíthet egy alkalmazást úgy, hogy a szöveghez DirectWrite-ot használjon, de a rendereléshez továbbra is GDI- vagy GDI+-t alkalmazzon.
Szövegszolgáltatások és szövegmegjelenítés
Az alkalmazások fejlődésével a szövegfeldolgozási követelményeik egyre összetettebbek lettek. Először a szöveg általában statikusan lefektetett felhasználói felületre korlátozódott, a szöveg pedig egy jól definiált dobozban, például egy gombban jelenik meg. Mivel az alkalmazások egyre több nyelven váltak elérhetővé, ez a megközelítés egyre nehezebbé vált, mivel a lefordított szöveg szélessége és magassága is jelentősen változhat a nyelvek között. Az alkalmazkodáshoz az alkalmazások dinamikusan kezdtek el elhelyezni felhasználói felületüket, hogy a szöveg tényleges renderelt méretétől függjenek, nem pedig fordítva.
A feladat végrehajtásához DirectWrite biztosítja az IDWriteTextLayout felületet. Ez az API lehetővé teszi az alkalmazás számára, hogy összetett jellemzőkkel rendelkező szövegrészeket adjon meg, például különböző betűtípusokat és betűméreteket, aláhúzásokat, áthúzásokat, kétirányú szöveget, effektusokat, három pontot és még beágyazott nem karakterjeleket (például bitkép hangulatjelet vagy ikont). Az alkalmazás ezután módosíthatja a szöveg különböző jellemzőit, mivel iteratív módon határozza meg a felhasználói felület elrendezését. A DirectWrite Hello World Minta, amely az alábbi ábrán és a oktatóanyagban látható: A DirectWrite használatának első lépései témakör számos ilyen effektust mutat be.
Az elrendezés a szélességük alapján ideálisan helyezheti el a karakterjeleket (ahogy a WPF is teszi), vagy a karakterjeleket a legközelebbi képpontpozíciókhoz illesztheti (ahogy GDI teszi).
A szövegmérések beszerzése mellett az alkalmazás a szöveg különböző részeinek tesztelésére is képes. Előfordulhat például, hogy tudni szeretné, hogy a szövegben lévő hivatkozásra kattint. (A találattesztelésről további információt a Találattesztelés végrehajtása szövegelrendezésen témakörben talál.)
A szövegelrendezési felület leválasztva van az alkalmazás által használt renderelési API-ról, ahogyan az alábbi ábrán látható:
Ez az elkülönítés azért lehetséges, mert a DirectWrite egy renderelő felületet (IDWriteTextRenderer) biztosít, amelyet az alkalmazások bármilyen grafikus API használatával implementálhatnak. Az alkalmazás IDWriteTextRenderer::DrawGlyphRun visszahívási metódust a DirectWrite hívja meg a szövegelrendezés megjelenítésekor. Ennek a módszernek a feladata a rajzműveletek végrehajtása vagy továbbítása.
A karakterjelek rajzolásához a Direct2D biztosítja az ID2D1RenderTarget::DrawGlyphRun funkciót a Direct2D felületre való rajzoláshoz, és a DirectWrite biztosítja az IDWriteBitmapRenderTarget::DrawGlyphRun funkciót a GDI felületre való rajzoláshoz, amelyet aztán a GDI használatával továbbíthatunk egy ablakba. A Direct2D és a DirectWrite DrawGlyphRun metódusai kényelmesen pontosan kompatibilis paraméterekkel rendelkeznek a DrawGlyphRun metódussal, amelyet az alkalmazás implementál a IDWriteTextRendererfelületen.
Hasonló elkülönítést követően a szövegspecifikus funkciókat (például a betűtípusok számbavételét és kezelését, a gliph-elemzést stb.) DirectWrite kezeli ahelyett, hogy Direct2D. A DirectWrite-objektumokat közvetlenül a Direct2D fogadja el. Annak érdekében, hogy a meglévő GDI-alkalmazások kihasználhassák a DirectWrite előnyeit, az IDWriteGdiInterop metódusfelületet biztosít a következő módszerekkel:
- DirectWrite betűtípus létrehozása a GDI logikai betűtípusból (CreateFontFromLOGFONT).
- Konvertálás DirectWrite betűtípuslapról GDI logikai betűtípussá (ConvertFontFaceToLOGFONT).
- Kérje le a DirectWrite betűtípus-arcot a HDC-be kiválasztotttól. (CreateFontFaceFromHdc)
- Hozzon létre egy DirectWritebitkép kirajzolási célpont a rendszermemóriában (CreateBitmapRenderTarget).
Karakterjelek és szöveg
A szöveg Unicode kódpontok (karakterek) készlete, amelyek különböző stílusmódosítókkal (betűtípusok, súlyok, aláhúzások, áthúzások stb.) állnak egy téglalapban. A karakterjel ezzel szemben egy adott betűtípusfájl adott indexe. A karakterjelek olyan görbéket határoznak meg, amelyek megjeleníthetők, de nem rendelkeznek szöveges jelentéssel. Lehetséges, hogy többszörös-többszörös kapcsolat van a glifák és a karakterek között. Az azonos betűtípus betűképéből származó és az alapvonalon egymás után elrendezett karaktersorozatot GlyphRunnevezik. A DirectWrite és a Direct2D a legpontosabb karaktermegjelenítési API-jukat, a DrawGlyphRun-t hívják meg, és nagyon hasonló függvényaláírásokkal rendelkeznek. A következő a Direct2D ID2D1RenderTarget-ből származik:
STDMETHOD_(void, DrawGlyphRun)(
D2D1_POINT_2F baselineOrigin,
__in CONST DWRITE_GLYPH_RUN *glyphRun,
__in ID2D1Brush *foregroundBrush,
DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL
) PURE;
Ez a módszer pedig IDWriteBitmapRenderTargetDirectWrite:
STDMETHOD(DrawGlyphRun)(
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
IDWriteRenderingParams* renderingParams,
COLORREF textColor,
__out_opt RECT* blackBoxRect = NULL
) PURE;
A DirectWrite verziója megőrzi az alapkonfiguráció forrását, a mérési módot és a gliph-futtatási paramétereket, és további paramétereket is tartalmaz.
DirectWrite lehetővé teszi egyéni renderelő használatát a karakterjelekhez az IDWriteTextRenderer felület implementálásával. Ez az interfész egy DrawGlyphRun metódussal is rendelkezik, ahogyan az alábbi kódpéldában látható.
STDMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
__maybenull IUnknown* clientDrawingEffect
) PURE;
Ez a verzió további paramétereket tartalmaz, amelyek egyéni szövegmegjelenítőimplementálásakor hasznosak. A végső paraméter az alkalmazás által implementált egyéni rajzeffektusokhoz használatos. (Az ügyfél rajzeffektusairól további információt az Ügyfélrajzeffektusok hozzáadása szövegelrendezéshezcímű témakörben talál.
Minden gliph-futtatás egy forrásnál kezdődik, és egy vonalat helyez el ebből a forrásból. A karakterjeleket a jelenlegi világátalakítás és a kijelölt szövegmegjelenítési beállítások módosítják a társított renderelési célon. Ezt az API-t általában csak azok az alkalmazások hívják közvetlenül, amelyek saját elrendezéssel rendelkeznek (például egy Word Processor), vagy egy olyan alkalmazás, amely implementálta az IDWriteTextRenderer felületet.
DirectWrite és Direct2D
Direct2D glyph szintű renderelési szolgáltatásokat nyújt DrawGlyphRunkeresztül. Ehhez azonban az alkalmazásnak implementálnia kell a renderelés részleteit, amely alapvetően a GDI-ből származó DrawText API funkcióit reprodukálja.
Ezért Direct2D olyan API-kat biztosít, amelyek szövegeket fogadnak el a karakterjelek helyett: ID2D1RenderTarget::DrawTextLayout és ID2D1RenderTarget::DrawText. Mindkét módszer egy Direct2D felületre rajzol. GDI-felületre való rendereléshez IDWriteBitmapRenderTarget::D rawGlyphRun van megadva. Ehhez a módszerhez azonban egyéni szöveg renderelőt kell implementálnia az alkalmazásnak. (További információkért lásd a GDI-felületre történő renderelés című témakört.)
Az alkalmazás szöveghasználata általában egyszerű: például OK vagy Mégse szöveget egy fix elrendezésű gombra helyezni. Idővel azonban egyre összetettebbé válik a nemzetközivé válás és más funkciók hozzáadása. Végül sok alkalmazásnak használnia kell DirectWrite szövegelrendezési objektumait, és implementálnia kell a szövegmegjelenítőt.
Ezért Direct2D rétegzett API-kat biztosít, amelyek lehetővé teszik az alkalmazások számára, hogy egyszerűen elinduljanak, és kifinomultabbak legyenek anélkül, hogy vissza kellene követniük vagy fel kellene hagyniuk a munkakódot. Az alábbi ábrán egy egyszerűsített nézet látható:
Rajzszöveg
DrawText a legegyszerűbben használható API-k. Unicode-karakterláncot, előtérecsetet, egyetlen formázó objektumot és cél téglalapot fogad. Az elrendezési téglalapon belül elhelyezi és rendereli a teljes karakterláncot, és igény szerint levágja. Ez akkor hasznos, ha egy egyszerű szöveget egy rögzített elrendezésű felhasználói felületbe helyez.
Szövegelrendezés rajzolása
Egy IDWriteTextLayout objektum létrehozásával egy alkalmazás megkezdheti a szöveg és más felhasználói felületi elemek mérését és rendezését, és több betűtípust, stílust, aláhúzást és áthúzást támogat. Direct2D biztosítja a DrawTextLayout API-t, amely közvetlenül elfogadja ezt az objektumot, és egy adott ponton jeleníti meg a szöveget. (A szélességet és a magasságot az elrendezési objektum biztosítja). Az összes várt szövegelrendezési funkció implementálása mellett a Direct2D minden effektusobjektumot ecsetként értelmez, és alkalmazza az ecsetet a kijelölt karakterjeltartományra. Emellett meghívja a beágyazott objektumokat is. Az alkalmazás ezután tetszés szerint beszúrhat nem karakterjeleket (ikonokat) a szövegbe. A szövegelrendezési objektumok használatának másik előnye, hogy a rendszer gyorsítótárazza a karakterjelek pozícióit. Ezért nagy teljesítménynövekedést érhet el, ha ugyanazt az elrendezési objektumot újrahasználja több híváshoz, és elkerüli az egyes hívásokhoz tartozó karakterjelpozíciók újraszámítását. Ez a funkció nem áll rendelkezésre a GDI DrawText.
DrawGlyphRun
Végül az alkalmazás implementálhatja az IDWriteTextRenderer felületet, és meghívhatja DrawGlyphRun és FillRectangle magát, vagy bármely más renderelő API-t. A Szövegelrendezés objektummal folytatott összes meglévő interakció változatlan marad.
Az egyéni szövegmegjelenítők implementálásához lásd a Renderelés egyéni szövegmegjelenítővel témakört.
Glyph Rendering
Ha DirectWrite ad hozzá egy meglévő GDI-alkalmazáshoz, az alkalmazás az IDWriteBitmapRenderTarget API-t használhatja a karakterjelek megjelenítéséhez. A IDWriteBitmapRenderTarget::DrawGlyphRun metódus, amelyet a DirectWrite biztosít, egyszínűen rajzol a memória DC-be anélkül, hogy további API-kat, például a Direct2D, igényelne.
Ez lehetővé teszi, hogy az alkalmazás speciális szövegmegjelenítési funkciókat szerezzen be, például a következőket:
- Az alpixel ClearType lehetővé teszi, hogy az alkalmazások a glifákat subpixelek pozícióiba helyezzék, ami éles glifa megjelenítést és glifa elrendezést biztosít.
- Az Y-irányú antialiasing lehetővé teszi a görbék simább renderelését nagyobb karakterjeleken.
A Direct2D áttérő alkalmazások a következő funkciókat is megkapják:
- Hardveres gyorsítás.
- A szöveg tetszőleges Direct2D ecsettel való kitöltése, például radiális színátmenetekkel, lineáris színátmenetekkel és bittérképekkel.
- További támogatás a PushAxisAlignedClip, PushLayer és CreateCompatibleRenderTarget API-k használatával történő rétegzéshez és kivágáshoz.
- A szürkeárnyalatos szöveg renderelésének támogatása. Ez helyesen tölti ki a cél alfa csatornát a szöveges ecset átlátszósága és a szöveg antialiasingja alapján.
A hardveres gyorsítás hatékony támogatása érdekében a Direct2D a gammakorrekció kissé eltérő megközelítését használja: az úgynevezett alfakorrekció. Ehhez nem szükséges, hogy a Direct2D megvizsgálja a renderelési célszín képpontot a szöveg renderelésekor.
Következtetés
Ez a témakör ismerteti Direct2D és DirectWrite közötti különbségeket és hasonlóságokat, valamint azokat az architekturális motivációkat, amelyek különálló, együttműködési API-kként biztosítják őket.