如何读取其他显示器像素的颜色

时间:2020-04-08 18:03:01

标签: c# winforms gdi+ pixel

我遵循了this answer,它可以与一台显示器配合使用(尽管当时11岁:D)。但是,当我连接第二台显示器并使用它时,它不再起作用。相反,当class MissionSerializer(HyperlinkedModelSerializer): queryset = KnownLocation.objects.all() known_location = ChoiceField(choices=queryset, read_only=True) gdt = KnownLocationSerializer(many=False, read_only=True) redirect_to_knownlocation = URLField # not implented yet. class Meta: model = Mission fields = ('MissionName', 'UavLatitude', 'UavLongitude', 'UavElevation', 'Area', 'gdt', 'known_location')

时,它总是像所有黑色一样产生奇怪的颜色

enter image description here

编辑:我发现了问题,这是由于两个显示器上的文字比例不同(第一个是125%,第二个是100%),我将设置都更改为125%并像超级按钮一样工作。现在的问题是,如何在其他显示器上自动检测字体缩放(当前我在第一台显示器上使用this

1 个答案:

答案 0 :(得分:0)

所以问题是每台显示器的比例不同

首先,我使用this answer检测输入point在哪个监视器的索引:

    private int ConvertMousePointToScreenIndex(Point mousePoint)
    {
        //first get all the screens 
        System.Drawing.Rectangle ret;

        for (int i = 1; i <= Screen.AllScreens.Count(); i++)
        {
            ret = Screen.AllScreens[i - 1].Bounds;
            if (ret.Contains(mousePoint))
                return i - 1;
        }
        return 0;
    }

第二,我只需要基于this answer

获取该索引监视器的real width / virtual width
        const int ENUM_CURRENT_SETTINGS = -1;

        public double GetScale(Point point)
        {
            Screen screen = Screen.AllScreens[ConvertMousePointToScreenIndex(point)];
            DEVMODE dm = new DEVMODE();
            dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
            EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);

            double RealWidth = dm.dmPelsWidth;
            double VirtualWidth = screen.Bounds.Width;
            return RealWidth / VirtualWidth;
        }

        [DllImport("user32.dll")]
        public static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

        [StructLayout(LayoutKind.Sequential)]
        public struct DEVMODE
        {
            private const int CCHDEVICENAME = 0x20;
            private const int CCHFORMNAME = 0x20;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
            public string dmDeviceName;
            public short dmSpecVersion;
            public short dmDriverVersion;
            public short dmSize;
            public short dmDriverExtra;
            public int dmFields;
            public int dmPositionX;
            public int dmPositionY;
            public ScreenOrientation dmDisplayOrientation;
            public int dmDisplayFixedOutput;
            public short dmColor;
            public short dmDuplex;
            public short dmYResolution;
            public short dmTTOption;
            public short dmCollate;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
            public string dmFormName;
            public short dmLogPixels;
            public int dmBitsPerPel;
            public int dmPelsWidth;
            public int dmPelsHeight;
            public int dmDisplayFlags;
            public int dmDisplayFrequency;
            public int dmICMMethod;
            public int dmICMIntent;
            public int dmMediaType;
            public int dmDitherType;
            public int dmReserved1;
            public int dmReserved2;
            public int dmPanningWidth;
            public int dmPanningHeight;
        }

最后,将其应用于GetColorAt

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

        Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
        public Color GetColorAt(Point location)
        {
            double scale = GetScale(location);
            using (Graphics gdest = Graphics.FromImage(screenPixel))
            {
                using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
                {
                    IntPtr hSrcDC = gsrc.GetHdc();
                    IntPtr hDC = gdest.GetHdc();
                    int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, (int)Math.Round(point.X * scale), (int)Math.Round(point.Y * scale), (int)CopyPixelOperation.SourceCopy);
                    gdest.ReleaseHdc();
                    gsrc.ReleaseHdc();
                }
            }

            return screenPixel.GetPixel(0, 0);
        }