点击按钮获取iFrame的屏幕截图

时间:2012-04-25 10:00:18

标签: asp.net iframe buttonclick

你好我正在创建一个有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);

我无法弄清楚如何解决它。非常感谢任何帮助。谢谢你

1 个答案:

答案 0 :(得分:4)

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

我认为在Web应用程序中实现这一点并不容易,因为在服务器上运行的.net代码中,客户端的工作就是将HTML呈现为可以截取屏幕截图的内容。 。你可能(这可能会非常脆弱,所以我不会真的推荐它,在Web应用程序中托管像这样的winforms控件通常是一个麻烦的方法,但我认为这可能是可能的)使用browser control在你的服务器端并设置它的URL然后你需要以某种方式截取它 - 这可能会有所帮助:Taking Website Screenshots With The WebBrowser Control

<强>更新

隐藏在我最后链接的网站的评论中是一些实际上用于截取网页截图的代码(使用WebBrowser控件)。它要求您引用以下内容:

  • System.Drawing中
  • System.Windows.Forms的
  • Microsoft HTML Object Library(这是一个COM引用,而不是.NET引用)

这是一个完成我们想要的工作的类(只有一个Render方法,它接受一个Uri和一个Size并返回一个Bitmap):

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应用程序的帐户,而不一定是最终用户。
  3. 好的,所以我认为以上在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将有一个谷歌的截图。