Поделиться через


DPI и DIPs

В этой статье объясняется различие между физическими пикселями и независимыми от устройства пикселями (DIPs) и способом обработки DPI (точки на дюйм) в Win2D.

Win2D разработан таким образом, чтобы многие приложения могли игнорировать это различие, так как оно обеспечивает разумное поведение по умолчанию, которое будет делать правильные действия при запуске на обоих устройствах с низким и высоким уровнем DPI. Если ваше приложение имеет более специализированные потребности, или если у вас есть другое мнение о том, что означает "разумное значение по умолчанию", ознакомьтесь с подробными сведениями о гори...

Что такое DPI?

DPI обозначает "точки на дюйм". Это приблизительная мера плотности пикселей вывода, например монитор компьютера или экран телефона. Чем выше DPI, тем больше, меньше точек составляют дисплей.

DPI — это лишь приблизительная мера, так как не все оборудование отображения можно полагаться на точную информацию. Некоторые мониторы компьютеров не сообщают о DPI операционной системе вообще, или пользователь может настроить свою систему для отрисовки с помощью другого DPI от фактического оборудования (например, чтобы изменить размер текстовых элементов пользовательского интерфейса). Приложения могут использовать DPI для выбора того, насколько большие вещи должны быть нарисованы, но не должны полагаться на него как точное физическое измерение размера дисплея.

Значение DPI 96 считается нейтральным по умолчанию.

Что такое пиксель?

Пиксель — это одна цветная точка. Изображения в компьютерной графике состоят из множества пикселей, расположенных в двухмерной сетке. Вы можете думать о пикселях как атомы, из которых строятся все изображения.

Физический размер пикселя может значительно отличаться от одного дисплея к другому. Если компьютер подключен к большому, но низкому монитору разрешения или внешнему экрану, пиксели могут быть довольно большими, но на телефоне с 1080p отображается всего лишь несколько дюймов в ширину, пиксели крошечные.

В Win2D каждый раз, когда вы видите API, указывающий позицию или размер, используя целые типы данных (или структуру, например BitmapSize, содержащую целые числа), это означает, что API работает в единицах пикселей.

Большинство API Win2D работают с DIPs, а не пикселями.

Что такое DIP?

DIP обозначает "независимый от устройства пиксель". Это виртуализированная единица, которая может быть такой же, как, больше или меньше физического пикселя.

Соотношение между пикселями и DIPs определяется DPI:

pixels = dips * dpi / 96

Если значение DPI равно 96, то пиксели и ДИП совпадают. При использовании более высокого DPI один DIP может соответствовать нескольким пикселям (или частям пикселей в обычном случае, когда DPI не является точным 96).

Большинство api среда выполнения Windows, включая Win2D, используют dips, а не пиксели. Это преимущество хранения графики примерно одинакового физического размера независимо от того, на каком экране запущено приложение. Например, если приложение указывает, что кнопка имеет ширину 100 ДИП, при запуске на устройстве с высоким уровнем DPI, например телефоне или мониторе 4k, эта кнопка автоматически масштабируется до более 100 пикселей в ширину, поэтому он остается разумным размером, который может щелкнуть пользователь. Если размер кнопки был указан в пикселях, с другой стороны, он будет отображаться смешно маленьким на этом типе отображения высокого DPI, поэтому приложение будет делать больше работы, чтобы настроить макеты по-разному для каждого вида экрана.

В Win2D каждый раз, когда вы видите API, указывающий позицию или размер, используя типы данных с плавающей запятой (или структуры, такие как Vector2 или Size, содержащие значения с плавающей запятой), это означает, что API работает в DIPs.

Для преобразования между DIPs и пикселями используйте методы ConvertDipsToPixels(Single, CanvasDpiRounding) и ConvertPixelsToDips(Int32).

Ресурсы Win2D с DPI

Все ресурсы Win2D, содержащие растровое изображение, также имеют связанное свойство DPI:

Все остальные типы ресурсов не зависят от DPI. Например, один CanvasDevice экземпляр можно использовать для рисования элементов управления или отрисовки множества различных DPIs, поэтому устройство не имеет собственного DPI.

CanvasCommandList Аналогичным образом, не имеет DPI, так как он содержит инструкции по рисованию векторов, а не растровое изображение. DPI выполняется только во время процесса растеризации, когда список команд обращается к объекту rendertarget или элементу управления (которые имеют DPI).

Элемент управления DPI

Элементы управления Win2D (CanvasControlи) автоматически используют тот же DPI, CanvasVirtualControl что и CanvasAnimatedControlотображение приложения. Это соответствует системе координат, используемой XAML, CoreWindow и другими среда выполнения Windows API.

Если DPI изменяется (например, если приложение перемещено на другой дисплей), элемент управления вызовет CreateResources событие и передает значение CanvasCreateResourcesReason DpiChanged. Приложения должны реагировать на это событие путем повторного создания любых ресурсов (таких как rendertargets), которые зависят от DPI элемента управления.

Rendertarget DPI

Элементы, которые можно нарисовать на (включая не только CanvasRenderTarget , но и типы CanvasSwapChain rendertarget и CanvasImageSource) имеют собственный DPI, но в отличие от элементов управления эти типы не напрямую подключены к экрану, поэтому Win2D не может автоматически определить, какой DPI должен быть. Если вы рисуете в отрисовку, которая позже будет скопирована на экран, вероятно, вы хотите, чтобы отрисовка использовал тот же DPI, что и экран, но если вы рисуете для некоторых других целей (например, создание изображений для отправки на веб-сайт) будет более подходящим по умолчанию 96 DPI.

Чтобы упростить оба этих шаблона использования, Win2D предоставляет два типа перегрузки конструктора:

CanvasRenderTarget(ICanvasResourceCreator, width, height, dpi)
CanvasRenderTarget(ICanvasResourceCreatorWithDpi, width, height)

Интерфейс ICanvasResourceCreator реализуется CanvasDevice , а также элементами управления Win2D. Так как устройство не имеет собственного DPI, необходимо явно указать DPI при создании отрисовки из одного.

Например, чтобы создать отрисовку DPI по умолчанию, где diPs и пиксели всегда будут одинаковыми:

const float defaultDpi = 96;
var rtWithFixedDpi = new CanvasRenderTarget(canvasDevice, width, height, defaultDpi);

ICanvasResourceCreatorWithDpi расширяется ICanvasResourceCreator путем добавления свойства DPI. Этот интерфейс реализуется элементами управления Win2D и упрощает создание объекта rendertarget, который автоматически наследует тот же DPI, что и созданный элемент управления:

var rtWithSameDpiAsDisplay = new CanvasRenderTarget(canvasControl, width, height);

DPI растрового изображения

CanvasBitmapВ отличие от отрисовки, не наследуется от элемента управления автоматически. Методы создания и загрузки растровых карт включают перегрузки для явного указания DPI, но если этот параметр не задан, то по умолчанию по умолчанию 96 битовая карта по умолчанию имеет значение 96 независимо от текущей конфигурации дисплея.

Причина, по которой растровые изображения отличаются от других типов, заключается в том, что они являются источником входных данных, а не выходными данными, на которые будут нарисованы. Поэтому важной вещью для растровых изображений является не DPI того места, в котором выходные данные будут в конечном итоге, но DPI исходного изображения, который полностью не связан с текущими параметрами отображения.

Если вы загружаете растровое изображение по умолчанию 100x100, а затем рисуете его на отрисовку, то растровое изображение будет масштабироваться от 100 до 96 DPI (то есть 100 пикселей) до 100 ДИП в DPI целевой отрисовки отрисовки (что может быть большим числом пикселей, если это высокая отрисовка DPI). Результирующее изображение всегда будет иметь размер 100 DIPS (поэтому не будет неприятных сюрпризов макета), но это может привести к размытию, если исходное растровое изображение с низким уровнем DPI было масштабировано до более высокого назначения DPI.

Для максимальной ясности на высоком уровне DPI некоторые приложения могут предоставить несколько наборов растровых изображений в разных разрешениях, а во время загрузки выбрать любую версию, наиболее тесно соответствующую DPI конечного элемента управления. Другие приложения могут предпочесть отправлять только растровые изображения с высоким уровнем DPI, и позволить Win2D масштабировать их при выполнении на более низком уровне DPI (масштабирование может часто выглядеть лучше, чем масштабирование вверх). В любом случае DPI растрового изображения можно указать в качестве параметра LoadAsync(ICanvasResourceCreator, String, Single).

Обратите внимание, что некоторые форматы файлов растровых карт содержат метаданные DPI собственных, но Win2D игнорирует это, так как часто оно часто задано неправильно. Вместо этого при загрузке растрового изображения необходимо явно указать DPI.

CanvasDrawingSession DPI

CanvasDrawingSession наследует его DPI от любого элемента управления, rendertarget, буферной цепочки и т. д., он нарисовывается.

По умолчанию все операции рисования работают в dips. Если вы предпочитаете работать в пикселях, это можно изменить с помощью Units свойства.

DPI эффекта

Конвейер эффектов изображения наследует его DPI от любого CanvasDrawingSession эффекта, нарисованного. Внутренняя обработка эффектов всегда работает в пикселях. Значения параметров, такие как размеры или позиции, указываются в dips, но эти единицы преобразуются в пиксели до того, как выполняется любая фактическая обработка изображений.

Если растровое изображение отличается от целевого сеанса рисования, используется в качестве исходного изображения эффекта, внутренний DpiCompensationEffect элемент автоматически вставляется между растровым изображением и эффектом. Это масштабирует растровое изображение, чтобы соответствовать целевому DPI, который обычно является нужным. Если это не нужно, можно вставить собственный экземпляр DpiCompensationEffect для настройки поведения.

Примечание.

При реализации пользовательского эффекта рекомендуется применить эквивалентную схему обработки DPI, чтобы обеспечить согласованное поведение при использовании вместе со встроенными эффектами Win2D.

API композиции

Microsoft.Graphics.Canvas.Composition API работают на более низком уровне, чем элементы управления Win2D XAML, поэтому они не пытаются автоматически обрабатывать DPI от вашего имени. Вы можете решить, в каких единицах вы предпочитаете работать, и задать любые преобразования, необходимые для достижения этого в составе визуального дерева композиции.

Windows.UI.Composition API, такие как CreateDrawingSurface всегда указывают размеры в единицах пикселей. При использовании Win2D для рисования на поверхности композиции можно указать любой DPI, который вы хотите использовать при вызове CreateDrawingSession(CompositionDrawingSurface, Rect, Single). Все рисунки, выполненные с помощью возвращаемого CanvasDrawingSession значения, будут масштабироваться вверх или вниз соответствующим образом.

Тестирование обработки DPI

Самый простой способ проверить правильность приложения в ответ на изменение DPI отображения — запустить в Windows 10 или Windows 11 и изменить параметры отображения во время работы приложения:

  • Щелкните правой кнопкой мыши фон рабочего стола и выберите пункт "Параметры отображения"
  • Перемещение ползунка с меткой "Изменение размера текста, приложений и других элементов"
  • Нажмите кнопку "Применить"
  • Выберите "Выйти позже"

Если у вас нет Windows 10 или Windows 11, можно также протестировать с помощью симулятора Windows. На панели инструментов Visual Studio измените параметр "Локальный компьютер" на "Симулятор", а затем используйте значок разрешения изменений для переключения имитированного отображения между:

  • 100 % (DPI = 96)
  • 140 % (DPI = 134.4)
  • 180 % (DPI = 172.8)