热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WINVNC源码分析(二)——图像

WINVNC是用bitmap格式保存桌面图像的,所以先补充下相关知识。图像“像素”(Pixel):把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构

WINVNC是用bitmap格式保存桌面图像的,所以先补充下相关知识。

 

图像“像素”(Pixel):把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。

图像分辨率:表示每一个方向上的像素数量,比如640X480,表示由640X480个像素组成。

DPI(Dot Per Inch):表示每英寸显示的像素数。图像显示清晰效果就看这个拉,一英寸等于25.4mm。

位/像素 (bpp:bits per pixel):既每个像素数据需要占用的bit数目,用来保存颜色。比如8位可得到256种颜色,16位可得到65,536种颜色,而24位可得到16,777,216种颜色。

 

view plain
  1. //WINDOWS API:
  2. int     nFullcomment">//获取x方向分辨率     
  3. int     nFullHeight=GetSystemMetrics(SM_CYSCREEN); //获取y方向分辨率
  4. BOOL EnumDisplaySettingsEx( //获取屏幕分辨率和bpp 
  5. LPCTSTR lpszDeviceName,  // display device 
  6. DWORD iModeNum,          // graphics mode 
  7. LPDEVMODE lpDevMode,      // graphics mode settings 
  8. DWORD dwFlags            // options);
  9. LONG ChangeDisplaySettingsEx( //改变屏幕分辨率和颜色质量 
  10. LPCTSTR lpszDeviceName,  // name of display device
  11. LPDEVMODE lpDevMode,     // graphics mode 
  12. HWND hwnd,               // not used; must be NULL 
  13. DWORD dwflags,            // graphics mode options 
  14. LPVOID lParam            // video parameters (or NULL)
  15. );
  16. int GetDeviceCaps(  //获取想要的设备信息,包括dpi等 
  17. HDC hdc,     // handle to DC 
  18. int nIndex   // index of capability
  19. );  
 

 

图像格式一般分为两种:映射图像和向量图像,bitmap就是映射图像。metafile是向量图像。

位映射图像用离散的像素来处理输出设备;而向量图像用笛卡尔座标系统来处理输出设备,其线条和填充对象能被个别拖移。现在大多数的图像输出设备是位映射设备,这包括视讯显示、点阵打印机、激光打印机和喷墨打印机。而笔式绘图机则是向量输出设备。

编辑bitmap大小一般就是复制或删除像素的某些行和列的像素。

 

view plain
  1. //WINDOWS API:
  2. BitBlt (hdcDst, xDst, yDst, cx, cy, hdcSrc, xSrc, ySrc, dwROP) ;//从称为「来源」的设备上下文中将一个矩形区的像素传输到称为「目的(destination)」的另一个设备上下文中相同大小的矩形区。来源和目的设备上下文可以相同而且bpp必须相同。、
  3. StretchBlt ( hdcDst, xDst, yDst, cxDst, cyDst,hdcSrc, xSrc, ySrc, cxSrc, cySrc, dwROP) ;//在复制时拉伸或者压缩图像尺寸
  4. int GetDIBits(  HDC hdc,           // handle to DC 
  5. HBITMAP hbmp,      // handle to bitmap 
  6. UINT uStartScan,   // first scan line to set 
  7. UINT cScanLines,   // number of scan lines to copy 
  8. LPVOID lpvBits,    // array for bitmap bits 
  9. LPBITMAPINFO lpbi, // bitmap data buffer 
  10. UINT uUsage        // RGB or palette index
  11. );
  12. //读取bitmap数据到缓冲区lpvBits。既按扫描顺序一个一个的像素数据。
  13. HDC CreateCompatibleDC(HDC hdc);//创建一个内存
  14. DCHBITMAP CreateCompatibleBitmap( 
  15. HDC hdc,        // handle to DC 
  16. int nWidth,     // width of bitmap,
  17. in pixels 
  18. int nHeight     // height of bitmap,
  19. in pixels
  20. );
  21. //创建设备环境兼容的位图。注意如果bitmap要做不同设备copy,hdc尽量不要用内存DC的。因为由CreateCompatibleBitmap函数创建的位图的颜色格式与由参数hdc标识的设备的颜色格式匹配。该位图可以选入任意一个与原设备兼容的内存设备环境中。由于内存设备环境允许彩色和单色两种位图。因此当指定的设备环境是内存设备环境时,由CreateCompatibleBitmap函数返回的位图格式不一定相同。然而为非内存设备环境创建的兼容位图通常拥有相同的颜色格式,并且使用与指定的设备环境一样的色彩调色板。
  22. HBITMAP CreateDIBSection(  HDC hdc,                 // handle to DC 
  23. CONST BITMAPINFO *pbmi,  // bitmap data 
  24. UINT iUsage,             // data type indicator 
  25. VOID **ppvBits,          // bit values 
  26. HANDLE hSection,         // handle to file mapping object 
  27. DWORD dwOffset           // offset to bitmap bit values
  28. );
  29. //可以得到创建的图像在内存中的首地址,可以直接访问图像内存地址了,这样就不要用GetDIBits来获取数据了GdiFlush();
  30. //让应用程序进入等待状态,直到所有待决的绘图操作完成为止。阻塞等屏幕绘画完。通过成批合并绘图操作命令,win32图形子系统(GDI)可改善绘图的性能。如调用一系列绘图命令,他们都返回布尔值(TRUE表示成功,零表示失败),就可将他们置于一个内部GDI队列里。此时,函数可以立即返回。随后,GDI子系统会执行这些待决的绘图命令。可考虑一种最常见的情况。在这种情况下,系统安装了一块显示卡。卡上自带图形处理器或加速器。画图的时候,GDI只需将图形命令简单的发送给显示卡,另其完成实际的操作。如果必须等待每个绘图命令都完成并返回,系统和应用程序的性能就会受到显示卡绘图速度的极大限制。所以在这个时候,GDI将绘图命令置于一个名为“批”(Batch)的队列里。这样一来,系统和应用程序就能继续运行,同时仍然让显示卡进行绘图操作。  
 

 

 

//下面是几个很重要的数据结构

BITMAPFILEHEADER

    BITMAPFILEHEADER结构包含关于类型,大小,布局设备无关的位图信息。

    typedef struct tagBITMAPFILEHEADER { 

      WORD    bfType; 

      DWORD   bfSize; 

      WORD    bfReserved1; 

      WORD    bfReserved2; 

      DWORD   bfOffBits; 

    } BITMAPFILEHEADER, *PBITMAPFILEHEADER; 

    /*成员

        bfType

            声明文件类型,必须是BM。

        bfSize

            声明位图文件的大小,以字节为单位。

        bfReserved1

            保留,必须为0。

        bfReserved2

            保留,必须为0。

        bfOffBits

            声明偏移量,从BITMAPFILEHEADER结构开始到位图数据,以字节为单位。

    备注

        在设备无关文件中,BITMAPINFOHEADER结构紧随其后。

*/

 

//BITMAPINFOHEADER

    //BITMAPINFOHEADER结构包含设备无关位图的大小以及色彩格式的信息。

    typedef struct tagBITMAPINFOHEADER{

      DWORD  biSize; 

      LONG   biWidth; 

      LONG   biHeight; 

      WORD   biPlanes; 

      WORD   biBitCount; 

      DWORD  biCompression; 

      DWORD  biSizeImage; 

      LONG   biXPelsPerMeter; 

      LONG   biYPelsPerMeter; 

      DWORD  biClrUsed; 

      DWORD  biClrImportant; 

    } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 

    /*成员

        biSize

            声明这个结构体所需要的字节数。

        biWidth

            声明位图的宽,以像素为单位。

        biHeight 

            声明位图的高,以像素为单位。如果biHeight是正数,位图是一个自下而上的设备无关位图,起点在左下角。如果biHeight是负数,位图是一个自上而下的设备无关位图,起点在左上角。

            如果biHeight是负数,指示一个自上而下的设备无关位图,biCompression就必须为BI_RGB或者BI_BITFIELDS。自上而下的设备无关位图不能被压缩。

        biPlanes

            为目标装置声明平面数,这个值必须是1。

        biBitCount

            声明每像素位数。BITMAPINFOHEADER的成员biBitCount确定了定义每一个像素需要的位数,以及位图所需颜色的最大值。这个成员必须是以下的值:

 

  Value   Meaning

    0        JPEG或者PNG格式声明每像素位数

    1        位图是单色的,包含两个颜色信息,位图数组中的每一位代表一个像素。如果这一位是0,那么这个点的颜色就是调色板中第一个RGBQUAD结构所定义的颜色。如果这一位是1,那么这个点的颜色就是调色板中第二个GBQUAD结构所定义的颜色。

    4        位图最多有16种颜色。调色板数组中有16个元素。位图中的每一个像素由一个4位的索引指向调色板。举个例子,位图的第一个字节是0x1F,这个字节代表两个像素,第一个像素颜色是调色板中的第二个RGBQUAD结构所定义的颜色,第二个像素颜色是调色板中的第十六个RGBQUAD结构所定义的颜色。

    8        位图最多有256种颜色。调色板中有256个元素。每一个字节代表一个颜色。

    16       位图有2^16种颜色。如果biCompression为BI_RGB,则没有调色板。RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。 RGB555是另一种16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。比如从高位到地位:X R R R R G G G G G B B B B B (X表示不用,可以忽略)。

  可以组合使用屏蔽字和移位操作来得到RGB各分量的值:

  #define RGB555_MASK_RED 0x7C00

  #define RGB555_MASK_GREEN 0x03E0

  #define RGB555_MASK_BLUE 0x001F

  R = (wPixel & RGB555_MASK_RED) >> 10; // 取值范围0-31

  G = (wPixel & RGB555_MASK_GREEN) >> 5; // 取值范围0-31

  B = wPixel & RGB555_MASK_BLUE; // 取值范围0-31

    24       位图最多有2^24种颜色。没有调色板。位图数组中每三个字节代表一个像素的红绿蓝相对强度。

        biCompression

            BI_RGB:对一种颜色进行编码的方法统称为“颜色空间”或“色域”。用最简单的话说,世界上任何一种颜色的“颜色空间”都可定义成一个固定的数字或变量。RGB(红、绿、蓝)只是众多颜色空间的一种。采用这种编码方法,每种颜色都可用三个变量来表示-红色绿色以及蓝色的强度。RGB1、RGB4、RGB8都是调色板类型的RGB格式,在描述这些媒体类型的格式细节时,通常会在BITMAPINFOHEADER数据结构后面跟着一个调色板(定义一系列颜色)。它们的图像数据并不是真正的颜色值,而是当前像素颜色值在调色板中的索引。以RGB1(2色位图)为例,比如它的调色板中定义的两种颜色值依次为0x000000(黑色)和0xFFFFFF(白色),那么图像数据001101010111…(每个像素用1位表示)表示对应各像素的颜色为:黑黑白白黑白黑白黑白白白…。

        biSizeImage

            声明图像文件的大小,以字节为单位。如果是BI_RGB位图,可能是0。

        biXPelsPerMeter 

            声明横向点距,以像素每米为单位。

        biYPelsPerMeter

            声明纵向点距,以像素每米为单位。

        biClrUsed

            声明实际使用到的颜色个数,如果是0,则使用所有颜色。

        biClrImportant

            声明显示这个位图必须的颜色索引个数,如果是0,则需要所有颜色。

*/

 

//RGBQUAD

    //RGBQUAD结构描述红绿蓝相对亮度

    typedef struct tagRGBQUAD {

      BYTE    rgbBlue; 

      BYTE    rgbGreen; 

      BYTE    rgbRed; 

      BYTE    rgbReserved; 

    } RGBQUAD;   

    /*成员 

        rgbBlue

            声明蓝色强度

        rgbGreen

            声明绿色强度

        rgbRed

            声明红色强度

        rgbReserved

            保留,必须是0

*/

 

 

//我们结合源码看下函数BOOL vncDesktop::SetPixShifts()就能更好的理解它们

view plain
  1. struct _BMInfo {BOOL            truecolour;BITMAPINFO       bmi;// Colormap info - comes straight after BITMAPINFO - **HACK**RGBQUAD            cmap[256];} m_bminfo;  
 

 

view plain
  1. BOOLvncDesktop::SetPixShifts()
  2. {
  3. // Sort out the colour shifts, etc.
  4. DWORD redMask=0, blueMask=0, greenMask = 0;
  5. switch (m_bminfo.bmi.bmiHeader.biBitCount)
  6. {
  7. case 16:
  8. // Standard 16-bit display
  9. if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB)
  10. //需要自己来指定三色各占哪几位,把该色的所占位置1其它位置0,保存该值(暂时叫色标吧)。
  11. //biBitCount位16,对于blue颜色来说0-4这5个位置1,得到blue色标blueMask = 0x001f,当然这里作了强制转换,因为blue为无符号32位
  12. //如果一个无符号16位的像素数据uspixel,先要强转为无符号32位的uipixel,当然不转也无所谓的,因为对应的色标也必定从无符号16位强转获取的。
  13. //我们要获得blue的索引值只要uipixel&blueMask就OK拉
  14. //当然red的索引值还是需要移位下(uipixel&redMask)>>10
  15. {
  16. // each word single pixel 5-5-5
  17. redMask = 0x7c00;
  18. greenMask = 0x03e0;
  19. blueMask = 0x001f;
  20. }
  21. else
  22. {
  23. if (m_bminfo.bmi.bmiHeader.biCompression == BI_BITFIELDS)//通过读取RGBQUAD来获取色标
  24. {
  25. redMask =   *(DWORD *) &m_bminfo.bmi.bmiColors[0];
  26. greenMask = *(DWORD *) &m_bminfo.bmi.bmiColors[1];
  27. blueMask =  *(DWORD *) &m_bminfo.bmi.bmiColors[2];
  28. }
  29. }
  30. break;
  31. case 32:// Standard 24/32 bit displays
  32. if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB)//同上,区别是每个颜色占了8位拉 each word single pixel 8-8-8
  33. {
  34. redMask = 0xff0000;
  35. greenMask = 0xff00;
  36. blueMask = 0x00ff;
  37. }
  38. else
  39. {
  40. if (m_bminfo.bmi.bmiHeader.biCompression == BI_BITFIELDS)
  41. {
  42. //同上
  43. redMask =   *(DWORD *) &m_bminfo.bmi.bmiColors[0];
  44. greenMask = *(DWORD *) &m_bminfo.bmi.bmiColors[1];
  45. blueMask =  *(DWORD *) &m_bminfo.bmi.bmiColors[2];
  46. }
  47. }
  48. break;
  49. default:// Other pixel formats are only valid if they're palette-based
  50. if (m_bminfo.truecolour)
  51. {
  52. vnclog.Print(LL_INTERR, "unsupported truecolour pixel format for setpixshifts/n");
  53. return FALSE;
  54. }
  55. return TRUE;
  56. }
  57. // Convert the data we just retrieved
  58. MaskToMaxAndShift(redMask, m_scrinfo.format.redMax, m_scrinfo.format.redShift);
  59. MaskToMaxAndShift(greenMask, m_scrinfo.format.greenMax, m_scrinfo.format.greenShift);
  60. MaskToMaxAndShift(blueMask, m_scrinfo.format.blueMax, m_scrinfo.format.blueShift);
  61. return TRUE;
  62. }  
 

 

看看函数最后调用的inline void vncDesktop::MaskToMaxAndShift(DWORD mask, CARD16 &max, CARD8 &shift)函数:

view plain
  1. inline voidvncDesktop::MaskToMaxAndShift(DWORD mask, CARD16 &max, CARD8 &shift)
  2. {
  3. for (shift = 0; (mask & 1) == 0; shift++)
  4. mask >>= 1;//无符号32位的mask右移操作,直到碰到位的值位1则退出。那么shift保留了mask从低位到高位数值连续为0的个数。
  5. //把右移后的值牵制转换成无符号16位,赋值给max。
  6. max = (CARD16) mask;
  7. //结合调用MaskToMaxAndShift(redMask, m_scrinfo.format.redMax, m_scrinfo.format.redShift);来看
  8. //那么m_scrinfo.format.redMax保存的就是red的最大值,m_scrinfo.format.redShift是色标到最大值的位移值
  9. //假设一个无符号N(16或者32)位的像素数据upixel,
  10. //那么red的值就是( uspixel  & (m_scrinfo.format.redMax<>shift
  11. }  
 

 

下篇再看看桌面包装类vncDesktop的其它函数。


推荐阅读
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 本文讲述了CodeForces1016C题目的解法。文章首先介绍了一种错误的理解,然后给出了正确的解法。其中,当位于一个角上时,有两种选择,一种是先一直走一行再返回来走,另一种是走到这一列的另一行上然后再往右走一列。作者给出了两种解法,一种是直接计算,一种是动态规划。最后,取两种解法的最优解作为答案。文章附上了源代码。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
author-avatar
潇潇-77
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有