Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln förklarar skillnaden mellan fysiska pixlar och enhetsoberoende pixlar (DIP:er) och hur DPI (punkter per tum) hanteras i Win2D.
Win2D är utformat på ett sådant sätt att många appar kan ignorera den här skillnaden, eftersom det ger förnuftiga standardbeteenden som gör det rätta när de körs på både låg och hög DPI-enheter. Om din app har mer specifika behov, eller om du har en annan uppfattning om vad ”rimligt standardval” betyder, läs vidare för alla detaljer...
Vad är DPI?
DPI står för "punkter per tum". Det här är ett ungefärligt mått på pixeldensiteten för en utdatavisning, till exempel en datorskärm eller telefonskärm. Ju högre DPI, desto fler, mindre punkter utgör skärmen.
DPI är bara ett ungefärligt mått eftersom det inte går att använda all visningsmaskinvara för att rapportera korrekt information. Vissa datorövervakare rapporterar inte DPI till operativsystemet alls, eller så kan användaren ha konfigurerat sitt system att rendera med en annan DPI än den faktiska maskinvaran (till exempel för att ändra storleken på användargränssnittets textelement). Program kan använda DPI för att välja hur stora saker som ska ritas, men bör inte förlita sig på det som en exakt fysisk mätning av visningsstorleken.
Ett DPI-värde på 96 anses vara ett neutralt standardvärde.
Vad är en pixel?
En pixel är en enda färgad punkt. Bilder i datorgrafik består av många bildpunkter ordnade i ett tvådimensionellt rutnät. Du kan se bildpunkter som atomerna som alla bilder skapas av.
Den fysiska storleken på en pixel kan variera kraftigt från en skärm till en annan. När en dator är ansluten till en stor men lågupplösningsskärm eller extern skärm kan pixlar vara ganska stora, men på en telefon med en 1080p-skärm bara några tum över är pixlarna små.
När du ser ett API i Win2D som anger en position eller storlek med heltalsdatatyper (eller en struct som BitmapSize som innehåller heltal) innebär det att API:et körs i pixelenheter.
De flesta Win2D-API:er fungerar med DIP:er i stället för bildpunkter.
Vad är en DIP?
DIP står för "enhetsoberoende pixel". Det här är en virtualiserad enhet som kan vara samma som, större eller mindre än en fysisk pixel.
Förhållandet mellan bildpunkter och DIP:er bestäms av DPI:
pixels = dips * dpi / 96
När DPI är 96 är bildpunkter och DIP:er desamma. När du använder högre DPI kan en enda DIP motsvara mer än en pixel (eller delar av pixlar i det vanliga fallet där DPI inte är en exakt multipel av 96).
De flesta Windows Runtime API:er, inklusive Win2D, använder DIP:er i stället för bildpunkter. Det här har fördelen att grafiken har ungefär samma fysiska storlek oavsett vilken skärm en app körs på. Till exempel om en app anger att en knapp är 100 DIPs bred, när den körs på en hög DPI-enhet, till exempel en telefon eller en 4k-skärm, skalas den här knappen automatiskt till mer än 100 bildpunkter i bredd, så det förblir en lämplig storlek som är möjlig för användaren att klicka på. Om knappstorleken angavs i bildpunkter skulle den däremot verka löjligt liten på den här typen av hög DPI-skärm, så appen skulle behöva utföra mer arbete för att justera layouterna på olika sätt för varje typ av skärm.
När du ser ett API i Win2D som anger en position eller storlek med hjälp av flyttalsdatatyper (eller structs som Vector2 eller Storlek som innehåller flyttalsvärden) innebär det att API:et körs i DIP:er.
Om du vill konvertera mellan DIP:er och bildpunkter använder du metoderna ConvertDipsToPixels(Single, CanvasDpiRounding) och ConvertPixelsToDips(Int32).
Win2D-resurser som har DPI
Alla Win2D-resurser som innehåller en bitmappsbild har också en associerad DPI-egenskap:
CanvasBitmapCanvasRenderTargetCanvasSwapChainCanvasControlCanvasVirtualControlCanvasAnimatedControlCanvasImageSource
Alla andra resurstyper är oberoende av DPI. Till exempel kan en enskild CanvasDevice instans användas för att rita till kontroller eller rendertargets för många olika DPIs, därför har enheten ingen egen DPI.
På samma sätt har CanvasCommandList ingen DPI-upplösning, eftersom den innehåller instruktioner för vektorgrafik snarare än en bitmappsbild. DPI spelar bara in under rasteriseringsprocessen, när kommandolistan dras till en rendertarget eller kontroll (som har DPI).
DPI-kontroll
Win2D-kontrollerna (CanvasControlCanvasVirtualControloch CanvasAnimatedControl) använder automatiskt samma DPI som den visning som appen körs på. Detta matchar koordinatsystemet som används av XAML och andra Windows Runtime API:er.
Om DPI-värdet ändras (till exempel om appen flyttas till en annan skärm) kommer kontrollen att utlösa händelsen CreateResources och skicka ett CanvasCreateResourcesReason av typen DpiChanged. Appar bör svara på den här händelsen genom att återskapa resurser (till exempel rendertargets) som är beroende av kontrollens DPI.
Renderingsmål DPI
Saker som kan dras till (som inkluderar inte bara CanvasRenderTarget men även rendertarget-liknande typer CanvasSwapChain och CanvasImageSource) har en egen DPI, men till skillnad från kontrollerna är dessa typer inte direkt anslutna till en skärm, så Win2D kan inte automatiskt avgöra vad DPI ska vara. Om du ritar till en rendertarget som senare kopieras till skärmen, vill du förmodligen att rendertarget ska använda samma DPI som skärmen, men om du ritar för något annat ändamål (t.ex. generera bilder för uppladdning till en webbplats) skulle en standard 96 DPI vara lämpligare.
För att göra båda dessa användningsmönster enkla tillhandahåller Win2D två typer av konstruktoröverlagring:
CanvasRenderTarget(ICanvasResourceCreator, width, height, dpi)
CanvasRenderTarget(ICanvasResourceCreatorWithDpi, width, height)
Gränssnittet ICanvasResourceCreator implementeras av CanvasDevice samt Win2D-kontrollerna. Eftersom en enhet inte har någon egen specifik DPI måste du uttryckligen ange DPI:n när du skapar en rendertarget från en.
Till exempel för att skapa ett återgivningsmål med standard-DPI där DIPs och pixlar alltid är samma sak:
const float defaultDpi = 96;
var rtWithFixedDpi = new CanvasRenderTarget(canvasDevice, width, height, defaultDpi);
ICanvasResourceCreatorWithDpi utökas ICanvasResourceCreator genom att lägga till en DPI-egenskap. Det här gränssnittet implementeras av Win2D-kontrollerna och gör det enkelt att skapa en rendertarget som automatiskt ärver samma DPI som kontrollen den skapades från:
var rtWithSameDpiAsDisplay = new CanvasRenderTarget(canvasControl, width, height);
Bitmappens DPI
CanvasBitmap, till skillnad från en rendertarget, ärver inte automatiskt DPI från en kontroll. Metoderna för att skapa och läsa in bitmappar omfattar överlagringar för att uttryckligen ange DPI, men om du utelämnar detta är bitmapps-DPI som standard 96 oavsett den aktuella visningskonfigurationen.
Anledningen till att bitmappar skiljer sig från andra typer är att de är en källa till indata, snarare än utdata som kommer att dras till. Så det viktiga för bitmappar är inte DPI för var utdata kommer att hamna, utan DPI för källbilden, som är helt orelaterad till de aktuella visningsinställningarna.
Om du till exempel läser in en bitmapp på 100 × 100 med standard-DPI och sedan ritar den på en rendertarget, skalas bitmappen från 100 DIPs vid 96 DPI (vilket är 100 pixlar) till 100 DIPs vid mål-rendertargetens DPI (vilket kan vara ett större antal pixlar om det är en rendertarget med hög DPI). Den resulterande bilden kommer alltid att vara 100 DIP:er i storlek (så det blir inga obehagliga layoutöverraskningar), men den kan bli suddig om en låg DPI-källbitmapp skalades upp till ett högre DPI-mål.
För maximal klarhet vid hög DPI kan vissa program vilja tillhandahålla flera uppsättningar bitmappsbilder med olika upplösningar och vid inläsningstillfället välja vilken version som bäst matchar målkontrollens DPI. Andra appar kanske föredrar att endast leverera höga DPI-bitmappar och låta Win2D skala ned dem när de körs på lägre DPI-skärmar (nedskalning kan ofta se bättre ut än att skala upp). I båda fallen kan bitmappens DPI anges som en parameter till LoadAsync(ICanvasResourceCreator, String, Single).
Observera att vissa bitmappsfilformat innehåller egna DPI-metadata, men Win2D ignorerar detta eftersom det ofta anges felaktigt. I stället måste DPI anges uttryckligen när bitmappen läses in.
CanvasDrawingSession DPI
CanvasDrawingSession ärver sin DPI från vilken kontroll, rendertarget, swapchain osv. den drar till sig.
Som standard fungerar alla ritningsåtgärder i DIP:er. Om du föredrar att arbeta i bildpunkter kan detta ändras via egenskapen Units .
Effekt-DPI
Bildeffektspipelinen ärver sin DPI från den yta CanvasDrawingSession som en effekt ritas på. Internt fungerar alltid effektbearbetning i bildpunkter. Parametervärden som storlekar eller positioner anges i DIP:er, men dessa enheter konverteras till bildpunkter innan någon faktisk bildmanipulering sker.
När en bitmapp med en annan DPI än målritningssessionen används som en effektkälla, infogas en intern DpiCompensationEffect automatiskt mellan bitmappen och effekten. Detta skalar bitmappen så att den matchar mål-DPI:et, vilket vanligtvis är vad du vill ha. Om det inte är det du vill kan du infoga din egen instans av DpiCompensationEffect för att anpassa beteendet.
Note
Om du implementerar en anpassad effekt bör du överväga att använda ett motsvarande DPI-hanteringsschema för att säkerställa konsekvent beteende när det används tillsammans med inbyggda Win2D-effekter.
API för sammansättning
Microsoft.Graphics.Canvas.Composition API:erna fungerar på en lägre nivå än Win2D XAML-kontroller, så de försöker inte automatiskt hantera DPI åt dig. Det är upp till dig att bestämma vilka enheter du föredrar att arbeta i och ange vilka transformeringar som krävs för att uppnå det som en del av ditt visuella kompositionsträd.
Kompositions-API:er som CreateDrawingSurface anger alltid storlekar i pixlar. När du använder Win2D för att rita på en kompositionsyta kan du ange vilken DPI du vill använda när du anropar CreateDrawingSession(CompositionDrawingSurface, Rect, Single). All ritning som utförs via den returnerade CanvasDrawingSession skalas upp eller ned i enlighet med detta.
Så här testar du DPI-hantering
Det enklaste sättet att testa att din app hanterar visnings-DPI på rätt sätt är att köra på Windows 10 eller Windows 11 och ändra visningsskalan medan appen körs:
- Högerklicka på skrivbordsbakgrunden och välj Visningsinställningar.
- Under Skala och layout ändrar du skalningsprocenten (till exempel från 100% till 150%).
- Appen får ett DPI-ändringsmeddelande och bör justeras automatiskt.
Du kan också testa genom att ansluta bildskärmar med olika DPI-inställningar och dra appfönstret mellan dem.
Windows developer