【笔记】C#得到真正的屏幕大小

闲来研究下非神经网络的computer vision,啥库都不用,先C#试试手撸截屏器,抄起代码来可快了(见下面的代码)。可是使用的时候发现,为啥截屏只截了一部分呢?

        public static Rectangle GetScreenSize(Form from)
        {
            Rectangle rect = Screen.FromControl(from).Bounds;
            return rect;
        }

        public static Bitmap CaptureScreen(Form from, string outputFilename)
        {
            Rectangle rect = GetScreenSize(from);
            using (Bitmap bitmap = new Bitmap(rect.Width, rect.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(new Point(0, 0), Point.Empty, rect.Size);
                }
                if (outputFilename.Length > 0)
                {
                    bitmap.Save(outputFilename, ImageFormat.Png);
                }
                return bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.PixelFormat.DontCare);
            }
        }

然后搜索了各种方案,要么引用PresentationCore的,要么引用GetDpiForSystem的,一堆乱遭遭的;我只想知道我 2560x1600 的屏幕为啥 Screen 只返回 1707x1067
这个应该是DPI的问题,有点时间又没有接触windows了,想当初还是GetDC的年代…突然意识到我的显示屏的DPI应该是比默认值96高的…
所以查了下,默认原来Windows应用并没有给开启这个high DPI awareness…所以不管用什么API统一都是返回的96
所以这里应该有两种解决方案,一个是直接去读取Windows注册表,找到屏幕缩放比例设置的那个位置,另一个是给应用开启high DPI awareness,就是有一个叫SetProcessDpiAwareness的Windows API,在 Shcore.dll 里:

        [DllImport("shcore.dll")]
        public static extern uint SetProcessDpiAwareness(uint mode);

但是文档里写了,Windows 8.1 / Server 2012R2 才支持,那之前的是不是就不用考虑DPI的问题了,但是也得保证能运行呀。所以改成LoadLibrary的形式:

    static class NativeMethods
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);
    }

    // v--- in main form scope
        private void EnableDpiAwareness()
        {
            // skip this procedure if Windows version is below
            // Shcore.dll#SetProcessDpiAwareness [min] Windows 8.1 / Windows Server 2012 R2
            IntPtr shcoreDll = NativeMethods.LoadLibrary(@"Shcore.dll");
            if (shcoreDll != IntPtr.Zero) return;
            IntPtr ptrSetProcessDpiAwareness = NativeMethods.GetProcAddress(shcoreDll, "SetProcessDpiAwareness");
            if (ptrSetProcessDpiAwareness != IntPtr.Zero)
            {
                SetProcessDpiAwareness fnSetProcessDpiAwareness = (SetProcessDpiAwareness)System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(ptrSetProcessDpiAwareness, typeof(SetProcessDpiAwareness));
                fnSetProcessDpiAwareness(/* DPI_AWARENESS_SYSTEM_AWARE */ 1);
            }
            NativeMethods.FreeLibrary(shcoreDll);
        }

然后把EnableDpiAwareness放在mainInitializeComponent 之前运行就好了…所有都正常了…

你可能感兴趣的:(C#,Tools,c#,截屏,屏幕大小)