帮酷LOGO
文章标签:图像捕捉  捕获  图像  cap  


Sample Image

介绍

本文将讨论以下主题:

  • 捕获桌面或者它的工作区的图像。
  • 捕获控件或者它的工作区的映像。
  • 捕获控件或者它的工作区下面的图像的图像。
  • 将图像从一种格式转换为另一种格式。
  • 将图像转换为可用的icon。

背景

有几个 C# 和 C++ 文章可用来讨论桌面捕获。 本文从那里概括,为各种图形格式,包括图像转换。图像转换和图像保存,提供了一个加载。捕获和保存的实验。

捕获的图像是 GDI Windows的区域,例如桌面或者 GDI+ 控件。 GDI ( 图形设备接口) 窗口由窗口句柄指定。 使用GDI方法操作 GDI+ 对象( 基本上是一个. NET 控件),我们需要使用它的GDI窗口句柄。 幸运的是,它可以。

// get a control's window handle for GDI manipulation. . .
System.Windows.Forms.Control ctl = new System.Windows.Forms.Control();
System.IntPtr wndHandle = ctl.Handle;
. . .

代码组织

解决方案由两个项目组成

  • 包含捕获方法( capture.cs )。互操作方法( dll.cs ) 以及一些调试和声音方法的C# 库,以及
  • 测试表单( testcapture.cs ) 来执行捕获方法。

模块 Dll.cs

这里 MODULE 为包含在各种dll中的方法定义入口点。 为了简化访问,定义了名为 Dll的命名空间,它的类名与要访问的dll相同。 然后,每个类定义所需的互操作DLL入口点和等效的C# 方法。

定义DLL的C# 可以访问入口点的示例类

. . .///<summary>/// GDI32 dll access///</summary>publicclass GDI32
{
 publicconstint SRCCOPY = 13369376;
 [DllImport("gdi32.dll", EntryPoint="DeleteDC")]
 publicstaticexternIntPtr DeleteDC(IntPtr hDc);
 [DllImport("gdi32.dll", EntryPoint="DeleteObject")]
 publicstaticexternIntPtr DeleteObject(IntPtr hDc);
 [DllImport("gdi32.dll", EntryPoint="BitBlt")]
 publicstaticexternbool BitBlt(IntPtr hdcDest,int xDest,
 int yDest,int wDest,int hDest,IntPtr hdcSource,
 int xSrc,int ySrc,int RasterOp);
 [DllImport("gdi32.dll", EntryPoint="CreateCompatibleBitmap")]
 publicstaticexternIntPtr CreateCompatibleBitmap(IntPtr hdc,
 int nWidth, int nHeight);
 [DllImport("gdi32.dll", EntryPoint="CreateCompatibleDC")]
 publicstaticexternIntPtr CreateCompatibleDC(IntPtr hdc);
 [DllImport("gdi32.dll", EntryPoint="SelectObject")]
 publicstaticexternIntPtr SelectObject(IntPtr hdc,IntPtr bmp);
} // end class GDI32. . .

直接从其他项目访问互操作方法不同,这里解决方案中的访问独立于 C# 库中的类,例如 Capture 类。

///<SUMMARY>/// Example of fully qualified Dll interop method access///</SUMMARY>. . .// release window and capture resources Dll.USER32.ReleaseDC(wndHWND,wndHDC); // release window context Dll.GDI32.DeleteDC(capHDC); // delete capture context Dll.GDI32.DeleteObject(capBMP); // delete capture bitmap. . .

模块 Capture.cs

GDI窗口捕获

其他捕获方法使用的基础方法如下所示。 这里方法在指定的窗口内捕获指定的rectangle 内的图像。 窗口是由GDI窗口句柄指定的。 图像作为. NET 位图返回。

方法操作如下。 首先,获取窗口设备上下文。 其次,使用窗口设备上下文创建兼容捕获设备上下文,并创建与该捕获设备上下文关联的GDI位图。 然后,窗口设备上下文中指定的rectangle 被复制到捕获设备上下文,从而填充GDI位图。 最后,GDI位图转换为 GDI+ 位图并返回给调用者。

///<summary>/// Captures the window or part thereof to a bitmap image.///</summary>publicstatic Bitmap Window(IntPtr wndHWND, 
 int x, int y, int width, int height)
{
 IntPtr wndHDC = USER32.GetDC(wndHWND);
 // get context for window // create compatibile capture context and bitmapIntPtr capHDC = GDI32.CreateCompatibleDC(wndHDC);
 IntPtr capBMP = GDI32.CreateCompatibleBitmap(wndHDC, width, height);
 // make sure bitmap non-zeroif (capBMP == IntPtr.Zero)// if no compatible bitmap {
 USER32.ReleaseDC(wndHWND,wndHDC); // release window context GDI32.DeleteDC(capHDC); // delete capture contextreturnnull; // return null bitmap }
 // select compatible bitmap in compatible context// copy window context to compatible context// select previous bitmap back into compatible contextIntPtr prvHDC = (IntPtr)GDI32.SelectObject(capHDC,capBMP); 
 GDI32.BitBlt(capHDC,0,0,width,height,wndHDC,x,y,GDI32.SRCCOPY); 
 GDI32.SelectObject(capHDC,prvHDC);
 // create GDI+ bitmap for window Bitmap bmp = System.Drawing.Image.FromHbitmap(capBMP); 
 // release window and capture resources USER32.ReleaseDC(wndHWND,wndHDC); // release window context GDI32.DeleteDC(capHDC); // delete capture context GDI32.DeleteObject(capBMP); // delete capture bitmap// return bitmap image to userreturn bmp; // return bitmap} // end method Window

桌面捕获

桌面捕获方法( DesktopDesktopWA ) 如下所示。

方法 Desktop 捕获整个桌面。 它选取桌面的宽度和高度,桌面的窗口句柄,然后使用捕获方法 Window 返回桌面的位图。 使用互操作例程获取宽度和高度。 也可以使用该方法获取这里信息 System.Windows.Forms.Screen.PrimaryScreen.Bounds

方法 DesktopWA 捕获桌面的工作区域。 它根据工作区中的指定控件获取桌面工作区域的边界,然后使用catch方法 Window 返回桌面的位图。

///<summary>/// Captures the desktop to a bitmap image///</summary>publicstatic Bitmap Desktop()
{
 // desktop widthint width = USER32.GetSystemMetrics(USER32.SM_CXSCREEN);
 // desktop heightint height = USER32.GetSystemMetrics(USER32.SM_CYSCREEN);
 // desktop window handleIntPtr desktopHWND = USER32.GetDesktopWindow();
 // return desktop bitmapreturn Window(desktopHWND,0,0,width,height);
} // end method Desktop///<summary>/// Captures the desktop work area to a bitmap image///</summary>publicstatic Bitmap DesktopWA(Control ctl)
{
 // desktop work area Rectangle wa = Screen.GetWorkingArea(ctl);
 // desktop window handle IntPtr desktopHWND = USER32.GetDesktopWindow();
 // return work area bitmapreturn Window(desktopHWND,wa.X,wa.Y,wa.Width,wa.Height);
} // end method DesktopWA

控件捕获

控件捕获方法为 Control。 第一种方法 Control 捕获整个控件。 第二个方法 Control 捕获控件的指定部分或者控件下面的内容。

捕获控件下方的内容时,需要的区域转换为屏幕坐标,并将屏幕( 桌面)的窗口句柄用于捕获控件。 控件的窗口句柄无法使用,因为所需区域位于控件下方的屏幕上。 要执行这里捕获并获取所需位图,必须在捕获之前隐藏控件。

捕获控件上的区域时,所需区域转换为控件坐标,并使用该控件的窗口句柄来捕获控件。

///<summary>/// Captures the control to a bitmap image. The entire control is/// captured including both the client and non-client areas.///</summary>publicstatic Bitmap Control(System.Windows.Forms.Control ctl)
{
 return Control(ctl,false,false); // capture entire control} // end method Control///<summary>/// Captures the specified area of the control or whats underneath/// the control. If the argument flag client is true, only the client/// area of the control is captured, otherwise the entire control is /// captured. If the argument flag under is true, the capture area under/// the control is captured, otherwise the specified area on the control/// is captured.///</summary>publicstatic Bitmap Control(System.Windows.Forms.Control ctl
, bool client,bool under)
{
 Bitmap bmp; // capture bitmap Rectangle ctlR; // capture area in control coordinates Rectangle scrR; // capture area in screen coordinates// get capture rectangle in control// coordinates and in screen coordinatesif (client) // if capturing client area {
 // get rectangle in control coordinates ctlR = ctl.ClientRectangle;
 // get rectangle in screen coordinates scrR = ctl.RectangleToScreen(ctlR);
 }
 else// if capturing entire control {
 // get rectangle in parent coordinates scrR = ctl.Bounds;
 if (ctl.Parent!= null) // if parent exists// map to screen coordinates scrR = ctl.Parent.RectangleToScreen(scrR);
 // get rectangle in control coordinates ctlR = ctl.RectangleToClient(scrR);
 }
 // capture an area under the controlif (under) // if capture area is under control {
 // save control visibilitybool prvV = ctl.Visible;
 if (prvV) // if control visible {
 // make control invisible ctl.Visible = false;
 // allow time for control to vanish Thread.Sleep(m_HDelay);
 ) // prior to image capture// Capture bitmap using desktop window handle and screen coordinates// for the capture area. Note, the control window handle can NOT be used// for capturing an area under the control.// get window handle for desktopIntPtr desktopHWND = USER32.GetDesktopWindow();
 // get bitmap for capture area under control bmp = Window(desktopHWND,scrR);
 if (ctl.Visible!= prvV) // if control visibility was changed ctl.Visible = prvV; // restore previous visibility }
 // capture an area on the controlelse// if capture area not under control {
 // Capture bitmap using control window handle and control coordinates// for capture area. bmp = Window(ctl.Handle,ctlR);
 // get bitmap using control window handle }
 return bmp; // return requested bitmap} // end method Control

ImageCapture.cs

图像捕获窗体允许加载。保存。捕获和转换图像。 它一次处理一个图像,但还不包括图像编辑函数。 它还可以选择保留图像的纵横比。 加载和保存支持多种图像格式,允许图像格式转换。 而且,图像可以转换并保存为可用的图标。 表单用于测试,具有非常元素错误检查和恢复功能。

图像捕获

操作菜单项控制图像捕获。 通过单击适当的操作菜单项"捕获桌面"或者"捕获桌面工作区"来完成桌面或者桌面区域图像捕获。

部分桌面图像捕获使用viewport完成。 viewport是窗体的工作区。 要使用 viewport,必须先打开它。 这是通过单击动作菜单项"打开 viewport"完成的。 打开viewport使表单键的透明度设置为表单的背景颜色。 这使得表单工作区下方的区域对用户可见。 用户将表单移动并调整窗体大小以包含所需的选择。 图像捕获是通过单击动作菜单项"捕获视图"完成的。 这将导致捕获视图,并关闭 viewport。

在加载或者捕获其他图像之前,必须保存或者释放当前图像。 操作菜单项"发布视图"将去除当前图像。

图像加载

可以从文件加载图像。 对于图标以外的其他图像,使用 Image.FromFile 方法输入图像。 这里方法在输入时自动检测图像的格式,无需用户指定该格式。 然后将图像转换为位图。

图标是特殊大小写图标使用 Icon 构造函数输入,然后转换为位图。

///<summary>/// Menu selection to load an image from a file.///</summary>privatevoid miLoad_Click(object sender, System.EventArgs e)
{
 if (UnsavedBM()) // if unsaved image existsreturn; // return CloseViewport(); // close viewport DialogResult dr = ofd.ShowDialog(this); // show the dialogif (dr!= DialogResult.OK) // if not okreturn; // forget itstring fn = ofd.FileName; // pick up file pathint idx = fn.LastIndexOf(""); // get last backslash sfd.InitialDirectory = (idx <= 0)? "" : fn.Substring(0,idx);
 sfd.FileName = fn; // make default for save Dispose(capBM); // dispose of previous bitmap (if any) idx = fn.LastIndexOf(".") + 1; // find start of extensionstring ext = (idx >0) && (idx < fn.Length)? fn.Substring(idx) : "";
 if (ext.ToLower().Equals("ico")) // if file is an icon {
 this.Icon = new Icon(fn); // read new form icon from file capBM = this.Icon.ToBitmap(); // convert to bitmap }
 else// if file not an icon capBM = new Bitmap(Image.FromFile(fn));// read bitmap from file PicInCtl(curCtl,false); // place new image in current control capBMSaved = true; // image has been saved, it came from a file Play("LoadView.wav"); // play load view sound} // end action miLoad_Click

显示图片

加载或者捕获的图像在内部作为 Bitmap 进行操作。 应该注意,Bitmap 基于 Image,因这里可以在必要时将它的视为图像。 实际上,当前图像显示为窗体工作区的背景。 调整窗体大小后,图像将调整大小以适应它的工作区。 如果图像宽度比正在保留,则正常情况下,图像的高宽版本将适合表单的客户端区域。 保留原始位图后没有丢失图像意义。

图像保存

可以将图像保存到文件中。 对于图标以外的图像,将使用 Bitmap 实例方法 Save 输出图像。 这里方法支持大量图像格式。 但是,在调用 Bitmap 实例方法 Save 时,必须显式指定图像格式。 在保存文件对话框中使用过滤器,以允许用户选择图像格式。

///<summary>/// Menu selection to save the image to a file.///</summary>privatevoid miSave_Click(object sender, System.EventArgs e)
{
 if (capBM == null) // if no bitmapreturn; // return DialogResult dr = sfd.ShowDialog(this); // show the dialogif (dr!= DialogResult.OK) // if not okreturn; // forget itstring fn = sfd.FileName; // pick up file pathif (fn.Equals("")) // if no filename {
 Play("Error.wav"); // play nothing saved sound MessageBox.Show("No filename specified, nothing saved");
 return;
 }
 // set default image type to selected filter format ImageType it = ImageType.SetImageType(sfd.FilterIndex-1); 
 // filter index is one basedif (it.format == ImageFormat.Icon) // if saving an icon {
 Icon = BitmapToIcon(capBM,aspect); // convert bitmap to icon Stream s = sfd.OpenFile(); // open file Icon.Save(s); // save the icon s.Close(); // close file }
 else// if saving other format capBM.Save(fn,it.format); // use generic image save capBMSaved = true; // image has been saved Play("SaveView.wav"); // play image saved sound} // end action miSave_Click

图像到 icon

图像可以保存为 icon。 一个可用的icon 基于一个小位图。 这里位图的最大大小由显示分辨率和颜色支持决定。 在本演示中,假定至少支持 256种颜色或者更多的显示器。 对于这里显示假设,最大位图大小为 96到 96. 将图像位图转换为 icon的位图不是问题。 然而,保持图像纵横比是一个问题。

本演示中对 icon 方面保存的选择是在最长的方向上降低意义。 换句话说,位图形成了最短方向和最长方向上的96像素。 然后使用中心 rectangle 从这个位图中提取 icon 位图,从而沿着最长方向向外移动一些重要性。 为了保持方面不丢失意义,图像应该编辑和/或者裁剪成正方形。 这可以在外部图像编辑器中完成,因为这些特性目前不存在于ImageCapture中。

///<summary>/// Convert bitmap to icon preserving aspect if requested///</summary>private Icon BitmapToIcon(Bitmap obm,bool preserve)
{
 Bitmap bm;
 // if not preserving aspectif (!preserve) // if not preserving aspect bm = new Bitmap(obm,ICON_W,ICON_H); // rescale from original bitmap// if preserving aspect drop excess// significance in least significant directionelse// if preserving aspect {
 Rectangle rc = new Rectangle(0,0,ICON_W,ICON_H);
 if (obm.Width >= obm.Height) // if width least significant { // rescale width based on max icon height bm = new Bitmap(obm,(ICON_H*obm.Width)/obm.Height,ICON_H);
 rc.X = (bm.Width - ICON_W)/2; // chop off excess width significanceif (rc.X <0) rc.X = 0;
 }
 else// if height least significant { // rescale height based on max icon width bm = new Bitmap(obm,ICON_W,(ICON_W*obm.Height)/obm.Width);
 rc.Y = (bm.Height - ICON_H)/2; // chop off excess height significanceif (rc.Y <0) rc.Y = 0;
 }
 bm = bm.Clone(rc,bm.PixelFormat); // bitmap for icon rectangle }
 // create icon from bitmap Icon icon = Icon.FromHandle(bm.GetHicon()); // create icon from bitmap bm.Dispose(); // dispose of bitmapreturn icon; // return icon} // end method BitmapToIcon

Points of Interest

  • 面向方面的保存方法。 对表单的大小进行修改,然后修改表单的客户端区域,创建一系列的表单大小变化。 尽管这些问题最终被解决了,但是这种方法却被放弃了。
  • 由于可以使用 Control.FromHandle 方法访问关联的GDI+ 控件,所以可能有可能使用这里方法访问桌面,从而使用GDI窗口句柄。 当然,测试这个假设后的结果令人失望。 虽然调试器不同地报告了测试崩溃,但是尚未使用这里技术来为桌面提供 GDI+ 控件。
  • 控制下面的图像- 测试各种方法以收集控件下的图像。 在早期测试过程中出现了计时问题。 引入了可变延迟来克服这里问题。 代码仍有 5ms 个延迟,以允许控件被隐藏在桌面位图中。 这里延迟可能不再需要。 在这方面需要做更多的测试。

历史记录

01/31/2004 - 初始版本。



文章标签:图像  cap  捕获  图像捕捉  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语