2012-04-25 4 views
1

Привет, я создаю сайт с iFrame и кнопкой. Функция этой кнопки - получить снимок экрана из того, что отображается внутри iFrame, и сохранить его как изображение на harddisk.Below это код, я используюснятие скриншота 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); 

Я не могу понять, как решить it.Any помощь будет значительно appreciated.Thank вам

ответ

4

В вашем случае content является исходным HTML, что делает страницу а не как его визуализировать - это зависит от браузера, чтобы решить (посмотрите на него в отладчике), так как это не base 64 (это способ кодирования двоичных данных с использованием только символов ASCII), в для этого вам нужно будет получить базовые 64 кодированные двоичные данные JPEG-кодированного изображения, однако браузер отобразил HTML-код, который вы не делаете t есть.

Я думаю, что это нелегко достичь в веб-приложении, поскольку в .net-коде, который вы используете на сервере, и это задача клиента отображать HTML-код в нечто, что вы можете сделать снимок экрана из. Вы могли бы (и это, вероятно, будет действительно хрупким, поэтому я бы не рекомендовал его, поскольку такой элемент управления winforms, как это в веб-приложении, обычно является рецептом проблем, но я думаю, что это возможно) используйте browser control на вашей стороне сервера и установить URL-адрес этого, но тогда вам нужно как-то скриншот его - это может помочь: Taking Website Screenshots With The WebBrowser Control.

Update

спрятан в комментариях на веб-сайте я связан последний некоторый код, который на самом деле работает, чтобы сделать скриншот веб-страницы (с помощью элемента управления WebBrowser). Это требует, чтобы у вас есть ссылки на следующие:

  • System.Drawing
  • System.Windows.Forms
  • Microsoft HTML Object Library (это COM ссылки, а не .NET один)

Вот это класс, который делает работу мы хотим (есть только один метод визуализации на нем, который принимает Ури и размер и возвращает 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; 
    } 
} 

Примечание Как я уже говорил, я не уверен, что это отличная идея, чтобы использовать веб-приложения для нескольких причин:

  1. Это является Windows, контроль форм, так как она имеет дело с память не может быть совместима с использованием в веб-приложении.
  2. Это означает, что учетная запись, сделанная на скриншоте, будет той, которую работает веб-приложение, а не конечным пользователем.

ОК, так что я думаю, что выше было бы хорошо в приложении WinForms, но, возможно, не подходит для работы в Интернете, но, эй, мы можем заставить его работать в любом случае, здесь идет ...

Я при условии, что вы собираетесь для регулярного применения веб-ASP .NET в этом случае вы бы что-то подобное в .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 будет иметь скриншот Google в нем.

+0

Привет, спасибо за отзыв. Мой iframe содержит отчеты от pentaho. Также я использовал метод, который вы указали ранее, но все, что я получаю, это пустая фотография. Я пробовал много скриншотов, но они не работают. Я просто хочу чтобы сделать снимок экрана в моем iframe. – nitinvertigo

+0

@nitinvertigo Фактическое рабочее решение находится в комментариях к этой статье (я не уверен, что код в статье действительно работает), похоже, в Интернете есть много вещей о том, как это сделать, что не работает). Я упростил его и обновил этот ответ. Я также показываю, как назвать это из приложения asp .net webforms. – kmp

+0

Большое спасибо. Ваш код работает отлично :) Я обязан ua лечить :) – nitinvertigo

Смежные вопросы