在单击按钮时截取iFrame的屏幕截图



您好,我正在创建一个具有iFrame和按钮的网站。该按钮的功能是获取iFrame中显示的任何内容的屏幕截图,并将其另存为硬盘上的图像。以下是我正在使用的代码

private void saveURLToImage(string url) 
    { 
        if (!string.IsNullOrEmpty(url)) 
        { 
            string content = ""; 

            System.Net.WebRequest webRequest = WebRequest.Create(url); 
            System.Net.WebResponse webResponse = webRequest.GetResponse(); 
            System.IO.StreamReader sr = new StreamReader(webResponse.GetResponseStream(), System.Text.Encoding.GetEncoding("UTF-8"));
            content = sr.ReadToEnd(); 
            //save to file 
            byte[] b = Convert.FromBase64String(content); 
            System.IO.MemoryStream ms = new System.IO.MemoryStream(b); 
            System.Drawing.Image img = System.Drawing.Image.FromStream(ms); 
            img.Save(@"c:pic.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); 

            img.Dispose(); 
            ms.Close(); 
        } 
    } 

这是按钮单击的代码

 protected void Button1_Click(object sender, ImageClickEventArgs e)
{
saveURLToImage("http://www.google.com");
}

但是,当我单击该按钮时,我收到错误

The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or a non-white space character among the padding characters.

在这一行

byte[] b = Convert.FromBase64String(content);

我无法弄清楚如何解决它。任何帮助将不胜感激。谢谢

在您的情况下,content是构成页面的原始 HTML,而不是它的呈现方式 - 这将由浏览器决定(在调试器中查看它)所以,由于这不是 base 64(这是一种仅使用 ASCII 字符对二进制数据进行编码的方法),为了使其正常工作,您需要获取 JPEG 的 base 64 编码二进制数据但是浏览器已呈现 HTML 的编码图像,而您没有。

我认为这在 Web 应用程序中实现起来并不容易,因为在 .net 代码中,您在服务器上运行,客户端的工作是将 HTML 呈现为可以截取屏幕截图的内容。 您可以(这可能非常脆弱,所以我不会真正推荐它,在 Web 应用程序中托管这样的 winforms 控件通常会导致麻烦,但我认为这可能是可能的)在服务器端使用浏览器控件并设置它的 URL,但随后您需要以某种方式截取它 - 这可能会有所帮助: 使用 Web 浏览器控件拍摄网站屏幕截图。

更新

隐藏在我上次链接的网站的评论中,有一些代码实际上可以截取网页的屏幕截图(使用 WebBrowser 控件)。 它要求您具有对以下内容的引用:

  • 系统.绘图
  • System.Windows.Forms
  • Microsoft HTML 对象库(这是一个 COM 引用,而不是 .NET 引用)

这是一个完成我们想要的工作的类(上面只有一个 Render 方法,它接受一个 Uri 和一个大小并返回一个位图):

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using mshtml;
public class HtmlToBitmapConverter
{
    public Bitmap Render(Uri uri, Size size)
    {
        var browser = new WebBrowser
                          {
                              ScrollBarsEnabled = false,
                              ScriptErrorsSuppressed = true,
                              Size = size
                          };
        browser.BringToFront();
        NavigateAndWaitForLoad(browser, uri, 0);
        var bitmap = new Bitmap(size.Width, size.Height);
        GetImage(browser.Document.DomDocument, bitmap, Color.White);
        return bitmap;
    }
    private void NavigateAndWaitForLoad(WebBrowser browser,
                                        Uri uri,
                                        int waitTime)
    {
        const int sleepTimeMiliseconds = 5000;
        browser.Navigate(uri);
        var count = 0;
        while (browser.ReadyState != WebBrowserReadyState.Complete)
        {
            Thread.Sleep(sleepTimeMiliseconds);
            Application.DoEvents();
            count++;
            if (count > waitTime / sleepTimeMiliseconds)
            {
                break;
            }
        }
        while (browser.Document.Body == null)
        {
            Application.DoEvents();
        }
        var document = (IHTMLDocument2)browser.Document.DomDocument;
        var style = (IHTMLStyle2)document.body.style;
        style.overflowX = "hidden";
        style.overflowY = "hidden";
    }
    private static void GetImage(object obj,
                                Image destination,
                                Color backgroundColor)
    {
        using (var graphics = Graphics.FromImage(destination))
        {
            var deviceContextHandle = IntPtr.Zero;
            var rectangle = new Rect
            {
                Right = destination.Width,
                Bottom = destination.Height
            };
            graphics.Clear(backgroundColor);
            try
            {
                deviceContextHandle = graphics.GetHdc();
                var viewObject = (IViewObject)obj;
                viewObject.Draw(1,
                                -1,
                                IntPtr.Zero,
                                IntPtr.Zero,
                                IntPtr.Zero,
                                deviceContextHandle,
                                ref rectangle,
                                IntPtr.Zero,
                                IntPtr.Zero,
                                0);
            }
            finally
            {
                if (deviceContextHandle != IntPtr.Zero)
                {
                    graphics.ReleaseHdc(deviceContextHandle);
                }
            }
        }
    }
    [ComImport]
    [Guid("0000010D-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IViewObject
    {
        void Draw([MarshalAs(UnmanagedType.U4)] uint dwAspect,
                  int lindex,
                  IntPtr pvAspect,
                  [In] IntPtr ptd,
                  IntPtr hdcTargetDev,
                  IntPtr hdcDraw,
                  [MarshalAs(UnmanagedType.Struct)] ref Rect lprcBounds,
                  [In] IntPtr lprcWBounds,
                  IntPtr pfnContinue,
                  [MarshalAs(UnmanagedType.U4)] uint dwContinue);
    }
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
}

注意:正如我之前所说,我不确定这是否是在 Web 应用程序中使用的好主意,原因如下:

  1. 它是一个 Windows 窗体控件,因此它处理内存的方式可能与在 Web 应用程序中使用的方式不兼容。
  2. 这意味着截取屏幕截图的帐户将是运行 Web 应用程序的帐户,不一定是最终用户。

好的,所以我认为上述内容在 winforms 应用程序中很好,但可能不适合网络,但是,嘿,无论如何我们都可以让它工作,在这里......

我假设您要使用常规的ASP .NET Web应用程序,在这种情况下,您将在.aspx页面中有类似的东西:

<asp:Button runat="server" OnClick="TakeScreenShot" Text="Take Screenshot"/>

然后在 TakeScreenshot 方法背后的代码中如下所示:

protected void TakeScreenShot(object sender, EventArgs e)
{
    Uri uri = new Uri("http://www.google.com");
    // Because it is a WebBrowser control it needs to run in an STA 
    // thread - what we will do is render the image to a Bitmap then
    // store the raw bytes in this byte array from a newly created
    // thread
    byte[] screenshot = null;
    var t = new Thread(() =>
                           {
                               using (var ms = new MemoryStream())
                               {
                                   // The screenshot object contains a 640x480 
                                   // screenshot 
                                   var bitmap = new HtmlToBitmapConverter()
                                       .Render(uri,
                                               new Size(640, 480));
                                   bitmap.Save(ms, ImageFormat.Jpeg);
                                   screenshot = ms.ToArray();
                               }
                           });
    t.SetApartmentState(ApartmentState.STA);
    t.Start();
    t.Join();            
    // Here we have the JPEG encoded bytes of the image - we can
    // just save them to a file like so...
    using (var f = File.Create(@"c:google.jpg"))
    {
        f.Write(screenshot, 0, screenshot.Length);
    }
}

你去 - c:\google.jpg 里面会有谷歌的截图。

最新更新