How to scale on a high DPI image of a Windows Form button?

I can’t find a way to zoom in on a Windows Form button. Below is what the Windows Form Designer looks like shown on a 200% DPI (I know that the Windows Form Designer should only be used in a 100% / 96 DPI, this screenshot just illustrates my point correctly).

While the button size is scaled correctly (34x33), the button-sized image does not scale / stretch / scale (it remains 16x16). I have made many attempts to solve this:

  • The parent AutoScaleMode control AutoScaleMode set to Font ; installing it in Dpi does not do this job.
  • AutoSize settings button - true or false does not work.
  • The settings button or parent AutoSizeMode control for any value does not work.
  • there is no Button.ImageLayout that can be set to Stretch or Zoom .
  • Using the new App.Config setting <add key="EnableWindowsFormsHighDpiAutoResizing" value="true" /> does not make it work.
  • The FlatStyle or ImageAlign change button does not work.

How did you decide to do this in your application?

Windows Form Button Image doesn't scale

+5
source share
2 answers

Therefore, despite the fact that the MS philosophy approaches ready-made stretched images for Windows Form controls at a high DPI level , it seems that the images on the button need to be manually stretched. Of course, even the best solution would be for each bitmap shown to the user (on the button and everywhere) to define several bitmaps adapted to 250% 200% 150% and 125% DPI.

Here is the code:

  public static IEnumerable<IDisposable> AdjustControlsThroughDPI(this Control.ControlCollection controls) { Debug.Assert(controls != null); if (DPIRatioIsOne) { return new IDisposable[0]; // No need to adjust on DPI One } var list = new List<IDisposable>(); foreach (Control control in controls) { if (control == null) { continue; } var button = control as ButtonBase; if (button != null) { button.AdjustControlsThroughDPI(list); continue; } // Here more controls tahn button can be adjusted if needed... // Recursive var nestedControls = control.Controls; Debug.Assert(nestedControls != null); if (nestedControls.Count == 0) { continue; } var disposables = nestedControls.AdjustControlsThroughDPI(); list.AddRange(disposables); } return list; } private static void AdjustControlsThroughDPI(this ButtonBase button, IList<IDisposable> list) { Debug.Assert(button != null); Debug.Assert(list != null); var image = button.Image; if (image == null) { return; } var imageStretched = image.GetImageStretchedDPI(); button.Image = imageStretched; list.Add(imageStretched); } private static Image GetImageStretchedDPI(this Image imageIn) { Debug.Assert(imageIn != null); var newWidth = imageIn.Width.MultipliedByDPIRatio(); var newHeight = imageIn.Height.MultipliedByDPIRatio(); var newBitmap = new Bitmap(newWidth, newHeight); using (var g = Graphics.FromImage(newBitmap)) { // According to this blog post http://blogs.msdn.com/b/visualstudio/archive/2014/03/19/improving-high-dpi-support-for-visual-studio-2013.aspx // NearestNeighbor is more adapted for 200% and 200%+ DPI var interpolationMode = InterpolationMode.HighQualityBicubic; if (s_DPIRatio >= 2.0f) { interpolationMode = InterpolationMode.NearestNeighbor; } g.InterpolationMode = interpolationMode; g.DrawImage(imageIn, new Rectangle(0, 0, newWidth, newHeight)); } imageIn.Dispose(); return newBitmap; } 

Note that a list of one-time bitmaps is returned. If you don’t like placing bitmaps on buttons, you don’t have to worry about deleting the bitmap.

Please note that we have the original bitmap images of the buttons.

Pay attention to our own members for working with DPI: MultipliedByDPIRatio(this int) , DPIRatioIsOne:bool , s_DPIRatio . You can write your own, the difficult task is to get the actual DPI ratio. To compile DPI, the best way to find this one .

Check out the link to the blog post Improving High DPI Support for Visual Studio 2013 , where the VS team explains that for their icon style, they determine that the image is stretched between> 200%, 100% [best achieved using the algorithm Bikubitsa and above or equal to 200%, is best achieved with the naive nearest neighbor algorithm. The code presented reflects these options.


Edit: screenshot with different interpolation mode at 200% DPI, IMHO InterpolationMode.HighQualityBicubic better than InterpolationMode.NearestNeighbor .

Interpolation mode

+5
source

Here's a ready-to-use helper class based on the accepted answer, which includes extracting a DPI scale and adding support for scaling PictureBox images:

 public static class HighDpiHelper { public static void AdjustControlImagesDpiScale(Control container) { var dpiScale = GetDpiScale(container).Value; if (CloseToOne(dpiScale)) return; AdjustControlImagesDpiScale(container.Controls, dpiScale); } private static void AdjustButtonImageDpiScale(ButtonBase button, float dpiScale) { var image = button.Image; if (image == null) return; button.Image = ScaleImage(image, dpiScale); } private static void AdjustControlImagesDpiScale(Control.ControlCollection controls, float dpiScale) { foreach (Control control in controls) { var button = control as ButtonBase; if (button != null) AdjustButtonImageDpiScale(button, dpiScale); else { var pictureBox = control as PictureBox; if (pictureBox != null) AdjustPictureBoxDpiScale(pictureBox, dpiScale); } AdjustControlImagesDpiScale(control.Controls, dpiScale); } } private static void AdjustPictureBoxDpiScale(PictureBox pictureBox, float dpiScale) { var image = pictureBox.Image; if (image == null) return; if (pictureBox.SizeMode == PictureBoxSizeMode.CenterImage) pictureBox.Image = ScaleImage(pictureBox.Image, dpiScale); } private static bool CloseToOne(float dpiScale) { return Math.Abs(dpiScale - 1) < 0.001; } private static Lazy<float> GetDpiScale(Control control) { return new Lazy<float>(() => { using (var graphics = control.CreateGraphics()) return graphics.DpiX / 96.0f; }); } private static Image ScaleImage(Image image, float dpiScale) { var newSize = ScaleSize(image.Size, dpiScale); var newBitmap = new Bitmap(newSize.Width, newSize.Height); using (var g = Graphics.FromImage(newBitmap)) { // According to this blog post http://blogs.msdn.com/b/visualstudio/archive/2014/03/19/improving-high-dpi-support-for-visual-studio-2013.aspx // NearestNeighbor is more adapted for 200% and 200%+ DPI var interpolationMode = InterpolationMode.HighQualityBicubic; if (dpiScale >= 2.0f) interpolationMode = InterpolationMode.NearestNeighbor; g.InterpolationMode = interpolationMode; g.DrawImage(image, new Rectangle(new Point(), newSize)); } return newBitmap; } private static Size ScaleSize(Size size, float scale) { return new Size((int)(size.Width * scale), (int)(size.Height * scale)); } } 
+1
source

Source: https://habr.com/ru/post/1206709/


All Articles