1

こんにちは私は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);

私はそれを解決する方法を理解することができません。どんな助けでも大歓迎です。ありがとう

4

1 に答える 1

5

あなたの場合content、ページを構成する生のHTMLであり、レンダリング方法ではありません。これは、ベース64(これは、 ASCII文字のみを使用してバイナリデータをエンコードする方法)、これを機能させるには、JPEGエンコード画像のbase 64エンコードバイナリデータを取得する必要がありますが、ブラウザはHTMLをレンダリングしますが、これはありません。

サーバー上で実行している.netコードでは、スクリーンショットを撮ることができるものにHTMLをレンダリングするのはクライアントの仕事であるため、これをWebアプリケーションで実現するのは簡単ではないと思います。サーバーでブラウザーコントロールを使用することはできます(これはおそらく非常に壊れやすいので、あまりお勧めしません。このようなwinformsコントロールをWebアプリケーションでホストすることは、通常、問題のレシピですが、可能かもしれません) 。サイドとそのURLを設定しますが、それからどういうわけかそれをスクリーンショットする必要があります-これは役立つかもしれません:WebBrowserコントロールでウェブサイトのスクリーンショットを撮る

アップデート

最後にリンクしたWebサイトのコメントに隠れているのは、(WebBrowserコントロールを使用して)Webページのスクリーンショットを撮るために実際に機能するコードです。以下への参照が必要です。

  • System.Drawing
  • System.Windows.Forms
  • Microsoft HTMLオブジェクトライブラリ(これはCOMリファレンスであり、.NETのものではありません)

これが私たちが望む仕事をするクラスです(UriとSizeを取り、ビットマップを返す単一のRenderメソッドがあります):

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アプリケーションが実行されているアカウントになることを意味します。

OK、それで、上記はwinformsアプリでは問題ないと思いますが、Webには適切ではないかもしれませんが、とにかくそれを機能させることができます、ここに行きます...

通常のASP.NETWebアプリケーションを使用することを想定しています。その場合、.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のスクリーンショットが含まれています。

于 2012-04-25T12:15:50.723 に答える