DpiHelper
using System.Diagnostics.CodeAnalysis;
using System.Drawing.Drawing2D;
using System.Runtime.CompilerServices;
using Windows.Win32;
using Windows.Win32.Graphics.Gdi;
namespace System.Drawing
{
[NullableContext(1)]
[Nullable(0)]
internal static class DpiHelper
{
private const double LogicalDpi = 96;
private static bool s_isInitialized;
private static double s_deviceDpiX = 96;
private static double s_deviceDpiY = 96;
private static double s_logicalToDeviceUnitsScalingFactorX;
private static double s_logicalToDeviceUnitsScalingFactorY;
private static InterpolationMode s_interpolationMode = InterpolationMode.Invalid;
private static double LogicalToDeviceUnitsScalingFactorX {
get {
if (s_logicalToDeviceUnitsScalingFactorX == 0) {
Initialize();
s_logicalToDeviceUnitsScalingFactorX = s_deviceDpiX / 96;
}
return s_logicalToDeviceUnitsScalingFactorX;
}
}
private static double LogicalToDeviceUnitsScalingFactorY {
get {
if (s_logicalToDeviceUnitsScalingFactorY == 0) {
Initialize();
s_logicalToDeviceUnitsScalingFactorY = s_deviceDpiY / 96;
}
return s_logicalToDeviceUnitsScalingFactorY;
}
}
private static InterpolationMode InterpolationMode {
get {
if (s_interpolationMode == InterpolationMode.Invalid) {
int num = (int)Math.Round(LogicalToDeviceUnitsScalingFactorX * 100);
if (num % 100 == 0)
s_interpolationMode = InterpolationMode.NearestNeighbor;
else if (num < 100) {
s_interpolationMode = InterpolationMode.HighQualityBilinear;
} else {
s_interpolationMode = InterpolationMode.HighQualityBicubic;
}
}
return s_interpolationMode;
}
}
public static bool IsScalingRequired {
get {
Initialize();
if (s_deviceDpiX == 96)
return s_deviceDpiY != 96;
return true;
}
}
private static void Initialize()
{
if (!s_isInitialized) {
GetDcScope scope = GetDcScope.ScreenDC;
try {
s_deviceDpiX = (double)PInvokeCore.GetDeviceCaps((HDC)ref scope, GET_DEVICE_CAPS_INDEX.LOGPIXELSX);
s_deviceDpiY = (double)PInvokeCore.GetDeviceCaps((HDC)ref scope, GET_DEVICE_CAPS_INDEX.LOGPIXELSY);
s_isInitialized = true;
} finally {
scope.Dispose();
}
}
}
private static Bitmap ScaleBitmapToSize(Bitmap logicalImage, Size deviceImageSize)
{
Bitmap bitmap = new Bitmap(deviceImageSize.Width, deviceImageSize.Height, logicalImage.PixelFormat);
using (Graphics graphics = Graphics.FromImage(bitmap)) {
graphics.InterpolationMode = InterpolationMode;
Size size = logicalImage.Size;
float width = (float)size.Width;
size = logicalImage.Size;
RectangleF srcRect = new RectangleF(0, 0, width, (float)size.Height);
RectangleF destRect = new RectangleF(0, 0, (float)deviceImageSize.Width, (float)deviceImageSize.Height);
srcRect.Offset(-0.5, -0.5);
graphics.DrawImage(logicalImage, destRect, srcRect, GraphicsUnit.Pixel);
return bitmap;
}
}
private static Bitmap CreateScaledBitmap(Bitmap logicalImage)
{
Size deviceImageSize = LogicalToDeviceUnits(logicalImage.Size);
return ScaleBitmapToSize(logicalImage, deviceImageSize);
}
public static int LogicalToDeviceUnitsX(int value)
{
return (int)Math.Round(LogicalToDeviceUnitsScalingFactorX * (double)value);
}
public static int ScaleToInitialSystemDpi(int value)
{
return (int)Math.Round(LogicalToDeviceUnitsScalingFactorY * (double)value);
}
public static Size LogicalToDeviceUnits(Size logicalSize)
{
return new Size(LogicalToDeviceUnitsX(logicalSize.Width), ScaleToInitialSystemDpi(logicalSize.Height));
}
[NullableContext(2)]
[return: NotNullIfNotNull("logicalImage")]
public static Bitmap CreateResizedBitmap(Bitmap logicalImage, Size targetImageSize)
{
if (logicalImage == null)
return null;
return ScaleBitmapToSize(logicalImage, targetImageSize);
}
[NullableContext(2)]
public static void ScaleBitmapLogicalToDevice([NotNullIfNotNull("logicalBitmap")] ref Bitmap logicalBitmap)
{
if (logicalBitmap != null) {
Bitmap bitmap = CreateScaledBitmap(logicalBitmap);
logicalBitmap.Dispose();
logicalBitmap = bitmap;
}
}
}
}