帮酷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  |  如果智培  |  酷兔英语