cyotek / Cyotek.Windows.Forms.ColorPicker

Color picker control suite for Windows Forms applications.
http://cyotek.com/blog/tag/colorpicker
MIT License
149 stars 41 forks source link

Not support Font Zoom Size in Win10 #14

Open Yari27 opened 6 years ago

Yari27 commented 6 years ago

ColorPicker incorrectly converts the cursor position at magnification other than 100% DPI.

2018-02-10_18-56-51

change-font-size-windows-10

cyotek commented 6 years ago

Hello,

Thanks for taking the time to log the issue! However, this is actually a duplicate of #12

I spent quite a bit of time trying to get this to "just work", but unfortunately I can't get Windows to stop "lying" to me unless I use a manifest which states the application is DPI-aware. This is not something the Color Picker Controls can do; only their host application. If you add a manifest stating that your application supports high DPI, then this works absolutely fine. However, you have to be certain that your application really does support it. Quite a few of mine do UI positioning by hand and completely break in high DPI.

There is a branch of the controls where I've been dabbling in making the controls (especially the ColorGrid) work better when used in a high DPI application, but it's still dependant on the client manifest.

Unfortunately I just don't have a solution to make them work in a program that doesn't report it is DPI-aware. My advice for now is to try adding a manifest and see how your application fares with it.

Regards; Richard Moss

Yari27 commented 6 years ago

Just need some calculation and for me work great: In the farthest corner of the screen, one pixel is missing, but it can be rounded off.

2018-02-11_12-58-32

Proof: YouTube

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace PositonInFontZoomMode
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }
        private Point point;

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            point = DisplayTools.GetRoundedRealPoint(Cursor.Position);

            label1.Text = "Position: " + point.ToString();
            label2.Text = "Font Zoom: " + DisplayTools.GetFontZoom() + "%";

            panel1.BackColor = GetPixelColor(point);
            label3.Text = panel1.BackColor.ToString();
            pictureBox1.Image = TakeCenterSnapshot(point, pictureBox1.Size);
        }

        #region GetPixelColor

        [DllImport("user32.dll")]
        public static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("gdi32.dll")]
        public static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

        [DllImport("user32.dll")]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        public static Color GetPixelColor(int x, int y)
        {
            IntPtr hdc = GetDC(IntPtr.Zero);
            uint pixel = GetPixel(hdc, x, y);
            ReleaseDC(IntPtr.Zero, hdc);
            return Color.FromArgb((int)(pixel & 0x000000FF), (int)(pixel & 0x0000FF00) >> 8, (int)(pixel & 0x00FF0000) >> 16);
        }
        public static Color GetPixelColor(Point position)
        {
            return GetPixelColor(position.X, position.Y);
        }

        #endregion

        public static Bitmap TakeCenterSnapshot(Point source, Size size)
        {
            Bitmap bmp = new Bitmap(size.Width, size.Height);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp);
            g.CopyFromScreen(new Point(source.X - size.Width / 2, source.Y - size.Height / 2), new Point(0, 0), size);
            return bmp;
        }
    }

    static class DisplayTools
    {
        [DllImport("gdi32.dll")]
        static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

        private enum DeviceCap
        {
            Desktopvertres = 117,
            Desktophorzres = 118
        }

        public static Size GetPhysicalDisplaySize()
        {
            Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();

            int physicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.Desktopvertres);
            int physicalScreenWidth = GetDeviceCaps(desktop, (int)DeviceCap.Desktophorzres);

            return new Size(physicalScreenWidth, physicalScreenHeight);
        }

        public static Size GetVirtualDisplaySize()
        {
            return new Size(SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height);
        }

        public static int GetFontZoom()
        {
            Size resolution = GetPhysicalDisplaySize();
            Size virtualscreen = GetVirtualDisplaySize();
            int zoomH = (resolution.Height * 100) / virtualscreen.Height;
            int zoomW = (resolution.Width * 100) / virtualscreen.Width;

            return zoomH == zoomW ? zoomH : 100;
        }

        public static PointF GetRealPoint(Point cursor)
        {
            return new PointF(cursor.X * ((float)GetFontZoom() / 100),
                cursor.Y * ((float)GetFontZoom() / 100));
        }

        public static Point GetRoundedRealPoint(Point cursor)
        {
            return new Point((int)Math.Round(cursor.X * ((float)GetFontZoom() / 100), 0),
                (int)Math.Round(cursor.Y * ((float)GetFontZoom() / 100), 0));
        }

    }
}
cyotek commented 6 years ago

Hello,

Thanks for posting this, that's interesting. I'll test that out when I get a moment and integrate it into the Color Picker controls if I don't find any issues with it. Definitely would be nice to get this one addressed.

Regards; Richard Moss

UweKeim commented 3 years ago

After changing

return zoomH == zoomW ? zoomH : 100;

to

return Math.Max(zoomW, zoomH);

I managed to use this code snippet to fix the ScreenColorPicker control by replacing the call to

MousePosition

to

DisplayTools.GetRoundedRealPoint(MousePosition)

So thank you, @Yari27 for the code snippets.

See also this SO answer for a related solution.