Open Yari27 opened 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
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.
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));
}
}
}
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
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.
ColorPicker incorrectly converts the cursor position at magnification other than 100% DPI.