【原创】Api的GetPixel和BitMap的GetPixel的偏差

说起来发现这个还是因为做qq外挂

当时发现从屏幕上GetPixel一个点,然后将这个颜色SetPixel到一个BitMap上,但是很奇迹地发现两者居然不同

后来干脆先全屏截图,两种方法再取同样一个点,发现真的不一样。

翻查一些资料才知道,原来net中色值还包括一个透明度,而api的却是没有这个透明度

api中的色值最多只有六位,而net多了一个透明度变成八位了

然后我做了一个实验来求出他们之间的差值

请看:

 

  int  ret  =  Color.Red.ToArgb()  -   0xFF0000 ; // 值为-16777216
             int  r  =  Color.FromArgb( 0xFF0000   -   16777216 ).R; // 值为255

            
int  ret1  =  Color.Green.ToArgb() - 0x00FF00 ; // 值为-16809728  这个不知道为什么会这样
             int  g  =  Color.FromArgb( 0x00FF00   -   16777216 ).G; // 值为255

            
int  ret2  =  Color.Blue.ToArgb()  -   0x0000FF ; // 值为-16777216
             int  b  =  Color.FromArgb( 0x0000FF   -   16777216 ).B; // 值为255
    
            
int  ret3  =  Color.FromArgb( 123 123 123 ).ToArgb()  -   0x7B7b7B ; // 值为-16777216

            
// 以上如果忽略掉绿色的那个值,可得出公式
            
//
            
//           net的色值=api的色值-16777216
            
//
            
// 下面同样会验证对于绿色这个公式也是适合的
            
// -----------------------------------------------------


            
// 以下验证这个公式算出来的net色值分离r g b是否正确
            
// 事实证明是正确的 呵呵

            
int  tempr  =  Color.FromArgb( 0x7BFF7B   -   16777216 ).R; // 值为123
             int  tempg  =  Color.FromArgb( 0x7BFF7B   -   16777216 ).G; // 值为255
             int  tempb  =  Color.FromArgb( 0x7BFF7B   -   16777216 ).B; // 值为123

            
// 这里验证对于绿色也是适合的
             int  tempr1  =  Color.FromArgb( 0x00FF00   -   16777216 ).R; // 值为0
             int  tempg1  =  Color.FromArgb( 0x00FF00   -   16777216 ).G; // 值为255
             int  tempb1  =  Color.FromArgb( 0x00FF00   -   16777216 ).B; // 值为0

 

结论:net的色值=api的色值-16777216

 

至此,貌似得出了一个强大的结论,但是在我进一步的实验中,结果却并非如此

且看:

 

class  Program
    {
        
static   void  Main( string [] args)
        {
            Thread.Sleep(
1000 ); // 延迟片刻截图

            
// 截全屏
            Bitmap img  =   new  Bitmap(Screen.AllScreens[ 0 ].Bounds.Width, Screen.AllScreens[ 0 ].Bounds.Height);
            Graphics g 
=  Graphics.FromImage(img);
            g.CopyFromScreen(
new  Point( 0 0 ),  new  Point( 0 0 ), Screen.AllScreens[ 0 ].Bounds.Size);

            IntPtr imgHDC 
=  g.GetHdc(); // 获取图片的设备上下文

            
for  ( int  x  =   0 ; x  <  Screen.AllScreens[ 0 ].Bounds.Width / 100 ; x ++ )
                
for  ( int  y  =   0 ; y  <  Screen.AllScreens[ 0 ].Bounds.Height / 100 ; y ++ )
                {
                    
int  netColor  =  img.GetPixel(x, y).ToArgb();
                    
int  apiColor  =  Win32Api.GetPixel(imgHDC, x, y);
                    
int  sub  =  netColor  -  apiColor;

                    Console.WriteLine(
" 当前比较的点为:{0},{1} " ,x.ToString(),y.ToString());
                    Console.WriteLine(
" net色值为:{0} " ,netColor.ToString());
                    Console.WriteLine(
" api色值为:{0} " , apiColor.ToString());
                    Console.WriteLine(
" 差值为:{0} " , sub.ToString());
                    Console.WriteLine(
" ------------------------------------ " );
                }
            Console.ReadKey();
         
        }

结果为:

 

可以发现,得出的值每个都不一样,

但是为什么会这样呢?真是百思不得其解。

我迷茫了,不知道到底问题出在哪里,各位读者有知道的麻烦告知一下,就当做是指点一下新手了。呵呵

 

后记:

由于一直没有答案,我便开始考虑是不是我寻找的方向错了,后来我想,屏幕取色工具很可能会用到颜色转换。根据这个想法,我还真的找到了答案,还弄了一个屏幕取色的小程序。

至此,本研究终于有了成果,转换win32颜色到net的颜色,其实微软有个专门的类库来进行这些转换,代码如下:

 

int  win32Color = ColorTranslator.ToWin32(netColor); // 从net的Color结果取得win32的色值
Color netColor = ColorTranslator.FromWin32(win32Color); // 从win32的色值转换到net的Color结构

 

在我的屏幕取色工具中,使用net的方法是先截屏,然后对截的图使用net的GetPixel函数,获得颜色,使用ColorTranslator转换为win32的色值,接着为了对比,我又用了win32的api对桌面进行GetPixel,对比结果发现,都是同一色值!!那么为什么我的实验二会不同呢?

我仔细观察源代码,发现了这句极为可疑

IntPtr imgHDC  =  g.GetHdc(); // 获取图片的设备上下文
也许问题就出在这里,net从画板取得的DC很可能与win32的DC不一致,导致了结果不一致。但是这个结论我没有办法证明,不知谁可以解释一下?

你可能感兴趣的:(【原创】Api的GetPixel和BitMap的GetPixel的偏差)