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

Posted on 2009-02-14 00:24  土匪  阅读(2514)  评论(5编辑  收藏  举报

说起来发现这个还是因为做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(123123123).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(00), new Point(00), 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不一致,导致了结果不一致。但是这个结论我没有办法证明,不知谁可以解释一下?