Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra la differenza tra i pixel fisici e i pixel indipendenti dal dispositivo (DIP) e il modo in cui i valori DPI (punti per pollice) vengono gestiti in Win2D.
Win2D è progettato in modo che molte app possano ignorare questa distinzione, in quanto fornisce comportamenti predefiniti sensibili che eseguiranno la cosa giusta quando vengono eseguiti su dispositivi DPI bassi e alti. Se la tua app ha esigenze più specializzate o se hai un'opinione diversa su ciò che significa "impostazione predefinita sensibile", leggi per i dettagli gory...
Cos'è DPI?
DPI è l'acronimo di "dots per inch". Si tratta di una misura approssimativa della densità di pixel di uno schermo di output, ad esempio un monitor del computer o uno schermo del telefono. Maggiore è il valore DPI, più i punti più piccoli costituiscono lo schermo.
DPI è solo una misura approssimativa perché non tutti gli hardware di visualizzazione possono essere basati su per segnalare informazioni accurate. Alcuni monitor computer non segnalano affatto dpi al sistema operativo o l'utente potrebbe aver configurato il sistema per il rendering usando un dpi diverso dall'hardware effettivo (ad esempio per modificare le dimensioni degli elementi di testo dell'interfaccia utente). Le applicazioni possono usare dpi per scegliere la quantità di elementi di grandi dimensioni da disegnare, ma non devono basarsi su di essa come misura fisica esatta delle dimensioni dello schermo.
Un valore DPI pari a 96 è considerato un valore predefinito neutro.
Che cos'è un pixel?
Un pixel è un singolo punto colorato. Le immagini in computer graphics sono costituite da molti pixel disposti in una griglia bidimensionale. È possibile pensare ai pixel come agli atomi da cui vengono compilate tutte le immagini.
Le dimensioni fisiche di un pixel possono variare notevolmente da uno schermo a un altro. Quando un computer è connesso a un monitor di grandi dimensioni ma a bassa risoluzione o a uno schermo esterno, i pixel possono essere abbastanza grandi, ma in un telefono con un display di 1080p solo pochi pollici su di esso, i pixel sono piccoli.
In Win2D, ogni volta che viene visualizzata un'API che specifica una posizione o una dimensione usando tipi di dati integer (o uno struct come BitmapSize che contiene numeri interi), significa che l'API funziona in unità pixel.
La maggior parte delle API Win2D funziona con DIP anziché pixel.
Che cos'è una rete DIP?
DIP è l'acronimo di "device independent pixel". Si tratta di un'unità virtualizzata che può essere uguale a, maggiore o minore di un pixel fisico.
Il rapporto tra pixel e DIP è determinato da DPI:
pixels = dips * dpi / 96
Quando DPI è 96, i pixel e i dip sono uguali. Quando si usano valori DPI superiori, un singolo DIP può corrispondere a più di un pixel (o parti di pixel nel caso comune in cui DPI non è un multiplo esatto di 96).
La maggior parte delle API di Windows Runtime, tra cui Win2D, usa DIP anziché pixel. Questo ha il vantaggio di mantenere la grafica approssimativamente la stessa dimensione fisica indipendentemente dalla visualizzazione su cui viene eseguita un'app. Ad esempio, se un'app specifica che un pulsante è largo 100 DIP, quando viene eseguito su un dispositivo DPI elevato, ad esempio un telefono o un monitor di 4k, questo pulsante verrà ridimensionato automaticamente in modo da avere una larghezza superiore a 100 pixel, quindi rimane una dimensione ragionevole che è possibile fare clic sull'utente. Se le dimensioni del pulsante sono state specificate in pixel, d'altra parte, apparirebbero ridicolmente piccole su questo tipo di display DPI elevato, quindi l'app dovrà fare più lavoro per regolare i layout in modo diverso per ogni tipo di schermo.
In Win2D, ogni volta che viene visualizzata un'API che specifica una posizione o una dimensione usando tipi di dati a virgola mobile (o struct come Vector2 o Size che contengono valori a virgola mobile), ciò significa che l'API funziona in DIP.
Per eseguire la conversione tra DIP e pixel, usare i metodi ConvertDipsToPixels(Single, CanvasDpiRounding)
e ConvertPixelsToDips(Int32)
.
Risorse Win2D con DPI
Tutte le risorse Win2D che contengono un'immagine bitmap hanno anche una proprietà DPI associata:
CanvasBitmap
CanvasRenderTarget
CanvasSwapChain
CanvasControl
CanvasVirtualControl
CanvasAnimatedControl
CanvasImageSource
Tutti gli altri tipi di risorse sono indipendenti da DPI. Ad esempio, una singola CanvasDevice
istanza può essere usata per disegnare, per controllare o eseguire il rendering di molti DPI diversi e, pertanto, il dispositivo non ha DPI propri.
Analogamente, CanvasCommandList
non ha un valore DPI, perché contiene istruzioni di disegno vettoriale anziché un'immagine bitmap. DPI entra in gioco solo durante il processo di rasterizzazione, quando l'elenco dei comandi viene disegnato in un renderingtarget o controllo (che hanno DPI).
DPI controllo
I controlli Win2D (CanvasControl
, CanvasVirtualControl
e CanvasAnimatedControl
) usano automaticamente lo stesso valore DPI della visualizzazione in cui è in esecuzione l'app. Corrisponde al sistema di coordinate usato da XAML, CoreWindow e altre API di Windows Runtime.
Se il valore DPI cambia ,ad esempio se l'app viene spostata in una visualizzazione diversa, il controllo genererà l'evento CreateResources
e passerà un oggetto CanvasCreateResourcesReason
di DpiChanged
. Le app devono rispondere a questo evento ricreando tutte le risorse (ad esempio renderingtarget) che dipendono dalla DPI del controllo.
DPI di rendering
Le cose che possono essere disegnate su (che includono non solo CanvasRenderTarget
, ma anche i tipi rendertarget-like CanvasSwapChain
e CanvasImageSource
) hhanno un DPI proprio, ma a differenza dei controlli che questi tipi non sono direttamente connessi a uno schermo, quindi Win2D non può determinare automaticamente quale valore DPI deve essere. Se stai disegnando in un oggetto rendertarget che verrà copiato successivamente sullo schermo, probabilmente vuoi che il rendertarget usi lo stesso DPI dello schermo, ma se stai disegnando per altri scopi (ad esempio, generando immagini per il caricamento in un sito Web) un valore DPI predefinito di 96 sarebbe più appropriato.
Per semplificare entrambi questi modelli di utilizzo, Win2D offre due tipi di overload del costruttore:
CanvasRenderTarget(ICanvasResourceCreator, width, height, dpi)
CanvasRenderTarget(ICanvasResourceCreatorWithDpi, width, height)
L'interfaccia ICanvasResourceCreator
viene implementata da CanvasDevice
, nonché dai controlli Win2D. Poiché un dispositivo non dispone di valori DPI specifici, è necessario specificare in modo esplicito il valore DPI durante la creazione di un oggetto rendertarget da uno.
Ad esempio, per creare un rendering DPI predefinito, dove i dip e i pixel saranno sempre la stessa cosa:
const float defaultDpi = 96;
var rtWithFixedDpi = new CanvasRenderTarget(canvasDevice, width, height, defaultDpi);
ICanvasResourceCreatorWithDpi
estende ICanvasResourceCreator
aggiungendo una proprietà DPI. Questa interfaccia viene implementata dai controlli Win2D e semplifica la creazione di un oggetto rendertarget che erediterà automaticamente lo stesso DPI del controllo da cui è stato creato:
var rtWithSameDpiAsDisplay = new CanvasRenderTarget(canvasControl, width, height);
Bitmap DPI
CanvasBitmap
, a differenza di un oggetto rendertarget, non eredita automaticamente DPI da un controllo. I metodi per la creazione e il caricamento di bitmap includono overload per specificare in modo esplicito DPI, ma se si esce da questo valore, il valore predefinito della DPI bitmap è 96 indipendentemente dalla configurazione di visualizzazione corrente.
Il motivo per cui le bitmap sono diverse da altri tipi è che sono un'origine di dati di input, anziché un output su cui verrà disegnato. Quindi, l'aspetto importante per le bitmap non è il valore DPI di dove l'output finirà, ma il valore DPI dell'immagine di origine, che non è completamente correlato alle impostazioni di visualizzazione correnti.
Se si carica una bitmap DPI predefinita da 100x100 e quindi la si disegna in un oggetto rendertarget, la bitmap verrà ridimensionata da 100 DIP a 96 DPI (ovvero 100 pixel) a 100 DIP in corrispondenza della DPI del rendertarget di destinazione (che potrebbe essere un numero maggiore di pixel se si tratta di un rendering DPI elevato). L'immagine risultante sarà sempre di 100 DIP in dimensioni (quindi non ci saranno sorprese di layout spiacevoli), ma potrebbe subire qualche sfocatura se una bitmap di origine DPI bassa è stata ridimensionata fino a una destinazione DPI superiore.
Per maggiore chiarezza con valori DPI elevati, alcune applicazioni potrebbero voler fornire più set di immagini bitmap a risoluzioni diverse e in fase di caricamento selezionare quale versione corrisponde più strettamente al valore DPI del controllo di destinazione. Altre app possono preferire la spedizione solo di bitmap DPI elevate e consentire a Win2D di ridurli quando vengono eseguiti su schermi DPI inferiori (il ridimensionamento può spesso risultare migliore rispetto all'aumento delle prestazioni). In entrambi i casi, il valore DPI bitmap può essere specificato come parametro per LoadAsync(ICanvasResourceCreator, String, Single)
.
Si noti che alcuni formati di file bitmap contengono metadati DPI propri, ma Win2D ignora questo perché spesso è impostato in modo non corretto. Al contrario, è necessario specificare in modo esplicito DPI durante il caricamento della bitmap.
CanvasDrawingSession DPI
CanvasDrawingSession
eredita il valore DPI da qualsiasi controllo, rendertarget, swapchain e così via, su cui viene disegnato.
Per impostazione predefinita, tutte le operazioni di disegno operano in DIP. Se si preferisce lavorare in pixel, questa operazione può essere modificata tramite la Units
proprietà.
DPI effetto
La pipeline dell'effetto immagine eredita il valore DPI da qualsiasi CanvasDrawingSession
effetto che venga disegnato. Internamente, l'elaborazione degli effetti opera sempre in pixel. I valori dei parametri, ad esempio dimensioni o posizioni, vengono specificati in DIP, ma queste unità vengono convertite in pixel prima che venga eseguita una modifica effettiva delle immagini.
Quando una bitmap di valori DPI diversi rispetto alla sessione di disegno di destinazione viene utilizzata come immagine di origine dell'effetto, un oggetto interno DpiCompensationEffect
viene inserito automaticamente tra la bitmap e l'effetto. In questo modo la bitmap viene ridimensionata in modo che corrisponda al valore DPI di destinazione, che in genere è quello desiderato. Se non è quello desiderato, è possibile inserire la propria istanza di DpiCompensationEffect
per personalizzare il comportamento.
Nota
Se si implementa un effetto personalizzato, è consigliabile applicare uno schema di gestione DPI equivalente per garantire un comportamento coerente quando usato insieme agli effetti Win2D predefiniti.
API di composizione
Le Microsoft.Graphics.Canvas.Composition
API operano a un livello inferiore rispetto ai controlli XAML Win2D, quindi non tentano di gestire automaticamente i valori DPI per conto dell'utente. Spetta a te decidere in quali unità si preferisce operare e impostare le trasformazioni necessarie per ottenere tale risultato come parte della struttura ad albero visuale della composizione.
Windows.UI.Composition
Le API, ad esempio CreateDrawingSurface
specificano sempre le dimensioni in unità pixel. Quando si usa Win2D per disegnare su una superficie di composizione, è possibile specificare il valore DPI che si vuole usare quando si chiama CreateDrawingSession(CompositionDrawingSurface, Rect, Single)
. Tutto il disegno eseguito tramite il restituito CanvasDrawingSession
verrà ridimensionato o ridotto di conseguenza.
Come testare la gestione DPI
Il modo più semplice per testare che l'app eseguirà la cosa giusta in risposta alla modifica della dpi di visualizzazione consiste nell'eseguire in Windows 10 o Windows 11 e modificare le impostazioni di visualizzazione mentre l'app è in esecuzione:
- Fare clic con il pulsante destro del mouse sullo sfondo del desktop e scegliere "Impostazioni di visualizzazione"
- Spostare il dispositivo di scorrimento con etichetta "Modificare le dimensioni di testo, app e altri elementi"
- Fare clic sul pulsante "Applica"
- Scegliere "Disconnetti in un secondo momento"
Se non hai Windows 10 o Windows 11, puoi anche testare con il simulatore Windows. Nella barra degli strumenti di Visual Studio modificare l'impostazione "Computer locale" su "Simulatore", quindi usare l'icona Modifica risoluzione per cambiare la visualizzazione simulata tra:
- 100% (DPI = 96)
- 140% (DPI = 134,4)
- 180% (DPI = 172,8)