如何修复与DrawToBitmap上WebBrowser控件一个不透明的错误?控件、不透明、错误、DrawToBitmap

2023-09-02 01:20:49 作者:小手拉大手丶愛妳永不走

根据下面的链接,我的控制台应用程序的方法 DrawToBitmap 不尊重透明度。

证明链接: http://social.msdn.microsoft.com/Forums/vstudio/en-US/e9704309-0c52-442d-80e0-2f8393dcd313/webbrowser-opacity-problem-

我的HTML code: http://fiddle.jshell.net/L37TC/

 < D​​IV ID =推子的风格=背景颜色:#FF0000> FFFF< / DIV>
< D​​IV的风格=背景颜色:蓝色,不透明度:0;过滤器:α(不透明度= 0);!>隐匿文字< / DIV>
SomeText
 

我的C#控制台code:

  VAR BMP =新位图(640,480,的PixelFormat :: Format32bppArgb)
VAR网络=(System.Windows.Forms.Control的)发送;
web.DrawToBitmap(BMP,矩形(0,0,640480));
 

所以我在寻找替代.NET内置的解决方案(没有CEF,Awesomium,或任何扩展的请的)只是一个内置的.NET功能以修复该错误或替代解决方案采取的Web URL的屏幕截图在我的控制台应用程序。

C webBrowser控件问题

如果我让 web浏览器窗口看到我的客户,并使用 CopyFromScreen 的不透明度尊重和隐藏文本不显示,怎么过的,我不想让 web浏览器窗可见的桌面屏幕。

我在寻找一个内置的解决方案,采取从问题发布网址的截图没有隐藏文本。换句话说解决的尊重透明度

EDIT1:在我的位图 (.NET类没有BMP所有像素格式)具有255的α值,因此问题不在于文件格式。我曾尝试PNG和其他任何.NET支持的格式。

完整源$ C ​​$ C(控制台模板,需要将引用添加到 System.Drawing中 System.Windows.Forms的

 类节目
{
    静态System.Windows.Forms.WebBrowser W =新System.Windows.Forms.WebBrowser();

    [STAThread]
    静态无效的主要(字串[] args)
    {

        w.Navigate(http://fiddle.jshell.net/L37TC/show/);
        w.DocumentCompleted + = w_DocumentCompleted;
        System.Windows.Forms.Application.Run();
        而(真)Console.Read();

    }

    静态无效w_DocumentCompleted(对象发件人,System.Windows.Forms.WebBrowserDocumentCompletedEventArgs E)
    {

        VAR BMP =新System.Drawing.Bitmap(w.Width,w.Height,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        ((System.Windows.Forms.Control的)瓦特).DrawToBitmap(BMP,新System.Drawing.Rectangle(0,0,w.Width,w.Height));
        对(INT I = 0; I&其中; w.Width; i ++在)为(诠释J = 0; J&所述; w.Height; J ++)如果(!bmp.GetPixel(I,J).A = 255)
                {
                    Console.WriteLine(阿尔法= 255!);
                    返回;
                }

        Console.WriteLine(所有的像素有255阿尔法值);
        bmp.Save(@D: ss.png,System.Drawing.Imaging.ImageFormat.Png);
        //隐藏的文本有0 opcity但它出现在图像



    }
}
 

解决方案   

我在寻找一个内置的解决方案,采取截图的发布   URL中没有隐藏文本的问题。换句话说解决   对于不透明度。

下面code做到了这一点:方面的CSS不透明度。除其他事项外,它使用的 图元文件 对象的 OleDraw API来渲染网页的形象。

测试HTML:

<!DOCTYPE HTML> <车身风格=背景颜色:灰色'>     <股利风格=背景色:蓝色;不透明度:0.2;颜色:黄色'>这是一个文字< / DIV> < /身体GT;

输出:

的code (控制台应用程序):

使用的Microsoft.Win32; 使用系统; 使用System.ComponentModel; 使用System.Drawing中; 使用System.Drawing.Imaging; 使用了System.Runtime.InteropServices; 使用的System.Threading; 使用System.Threading.Tasks; 使用System.Windows.Forms的; 命名空间Console_21697048 {     // http://stackoverflow.com/q/21697048/1768303     类节目     {         常量字符串的HTML =< D​​OCTYPE HTML><车身风格=背景色:灰!><股利风格=背景颜色:蓝色,不透明:0.2;颜色:黄色'>这是一个文字< / DIV>< /身体GT;;         常量字符串FILE_NAME =webpage.png;         只读静态尺寸IMAGE_SIZE =新的大小(320,200);         // 主要         静态无效的主要(字串[] args)         {             尝试             {                 //启用HTML5等(假设我们正在运行IE9 +)                 SetFeatureBrowserFeature(FEATURE_BROWSER_EMULATION,9000);                 //力软件渲染                 SetFeatureBrowserFeature(FEATURE_IVIEWOBJECTDRAW_DMLT9_WITH_GDI,1);                 SetFeatureBrowserFeature(FEATURE_GPU_RENDERING,0);                 使用(VAR公寓=新MessageLoopApartment())                 {                     //与自己的消息循环一个seprate线程创建web浏览器                     VAR web浏览器= apartment.Invoke(()=>新建web浏览器());                     //导航并等待结果                     apartment.Invoke(()=>                     {                         VAR pageLoadedTcs =新TaskCompletionSource<布尔>();                         webBrowser.DocumentCompleted + =(S,E)=>                             pageLoadedTcs.TrySetResult(真正的);                         webBrowser.DocumentText = HTML;                         返回pageLoadedTcs.Task;                     })。等待();                     //保存图片                     apartment.Invoke(()=>                     {                         webBrowser.Size = IMAGE_SIZE;                         VAR矩形=新的Rectangle(0,0,webBrowser.Width,webBrowser.Height);                         //获取参考DC                         使用(VAR screenGraphics = webBrowser.CreateGraphics())                         {                             变种screenHdc = screenGraphics.GetHdc();                             //创建一个图元文件                             使用(VAR图元文件=新的图元文件(screenHdc,矩形,MetafileFrameUnit.Pixel))                             {                                 使用(VAR图形= Graphics.FromImage(图元文件))                                 {                                     变种HDC = graphics.GetHdc();                                     变种矩形=新矩形(0,0,320,50);                                     OleDraw(webBrowser.ActiveXInstance,DVASPECT_CONTENT,HDC,裁判矩形);                                     graphics.ReleaseHdc(HDC);                                 }                                 //保存图元文件的位图                                 metafile.Save(FILE_NAME,ImageFormat.Png);                             }                             screenGraphics.ReleaseHdc(screenHdc);                         }                     });                     //处理web浏览器的                     apartment.Invoke(()=> webBrowser.Dispose());                     web浏览器= NULL;                 }             }             赶上(例外前)             {                 Console.WriteLine(ex.ToString());             }         }         //互操作         常量UINT DVASPECT_CONTENT = 1;         [的DllImport(OLE32.DLL,preserveSig = FALSE)]         静态外部无效OleDraw(             [的MarshalAs(UnmanagedType.IUnknown)对象朋克,             UINT dwAspect,             IntPtr的hdcDraw,             [在] REF System.Drawing.Rectangle lprcBounds);         // web浏览器功能控制         // http://msdn.microsoft.com/en-us/library/ie/ee330733(v=vs.85).aspx         静态无效SetFeatureBrowserFeature(字符串功能,UINT值)         {             如果(LicenseManager.UsageMode!= LicenseUsageMode.Runtime)                 返回;             变种的appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess()MainModule.FileName。);             Registry.SetValue(@HKEY_CURRENT_USER 软件微软的Internet Explorer MAIN FeatureControl +功能,                 的appName,价值,RegistryValueKind.DWord);         }     }     // MessageLoopApartment     //更多信息:http://stackoverflow.com/a/21808747/1768303     公共类MessageLoopApartment:IDisposable的     {         螺纹_Thread; // STA线程         的TaskScheduler _taskScheduler; // STA线程的任务调度         公众的TaskScheduler的TaskScheduler {{返回_taskScheduler; }}         ///<总结> MessageLoopApartment构造< /总结>         公共MessageLoopApartment()         {             VAR TCS =新TaskCompletionSource<的TaskScheduler>();             //启动一个STA线程,并得到一个任务调度             _Thread =新主题(startArg =>             {                 事件处理程序idleHandler = NULL;                 idleHandler =(S,E)=>                 {                     //处理Application.Idle只有一次                     Application.Idle - = idleHandler;                     //返回任务调度程序                     tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());                 };                 //处理Application.Idle只有一次                 //确保我们的消息循环中                 //和的SynchronizationContext已经正确安装                 Application.Idle + = idleHandler;                 Application.Run();             });             _thread.SetApartmentState(ApartmentState.STA);             _thread.IsBackground = TRUE;             _thread.Start();             _taskScheduler = tcs.Task.Result;         }         ///<总结>关机STA线程< /总结>         公共无效的Dispose()         {             如果(_taskScheduler!= NULL)             {                 VAR的TaskScheduler = _taskScheduler;                 _taskScheduler = NULL;                 // STA线程上执行Application.ExitThread()                 Task.Factory.StartNew(                     ()=> Application.ExitThread(),                     CancellationToken.None,                     TaskCreationOptions.None,                     的TaskScheduler).Wait();                 _thread.Join();                 _Thread = NULL;             }         }         ///<总结> Task.Factory.StartNew包装< /总结>         公共无效调用(动作的动作)         {             Task.Factory.StartNew(动作,                 CancellationToken.None,TaskCreationOptions.None,_taskScheduler).Wait();         }         公共TResult调用< TResult>(Func键< TResult>动作)         {             返回Task.Factory.StartNew(动作,                 CancellationToken.None,TaskCreationOptions.None,_taskScheduler)。结果;         }     } }

According to following link and my console application the method DrawToBitmap doesn't respect opacity.

Proof link: http://social.msdn.microsoft.com/Forums/vstudio/en-US/e9704309-0c52-442d-80e0-2f8393dcd313/webbrowser-opacity-problem-

My HTML code : http://fiddle.jshell.net/L37TC/

<div id="fader" style="background-color: #ff0000">ffff</div>
<div style="background-color: blue;  opacity:0;filter:alpha(opacity=0);">HIDDEN TEXT!</div>
SomeText 

My C# console code :

var bmp = new  Bitmap(640,480, PixelFormat::Format32bppArgb)
var web = (System.Windows.Forms.Control)sender;
web.DrawToBitmap(bmp, Rectangle(0, 0, 640,480));

So I'm looking for alternative .NET built-in solution (no CEF, Awesomium, or any extension please) just a built-in feature of .NET to fix the bug or alternative solution to take screenshot of a web URL in my console application.

If I make WebBrowser window visible to my client and use CopyFromScreen the opacity is respected and HIDDEN TEXT isn't showing, how ever I don't want to make WebBrowser window visible to desktop screen.

I'm looking for a built-in solution to take a screenshot from posted URL in the question without HIDDEN TEXT. In other words a solution to respect opacity.

EDIT1: All pixels in my Bitmap class (.NET class not BMP format) has alpha value of 255. So the problem is NOT with file format. I have tried PNG and any other .NET supported format.

Complete source code (Console Template, Need to add references to System.Drawing and System.Windows.Forms

class Program
{
    static System.Windows.Forms.WebBrowser w = new System.Windows.Forms.WebBrowser();

    [STAThread]
    static void Main(string[] args)
    {

        w.Navigate("http://fiddle.jshell.net/L37TC/show/");
        w.DocumentCompleted += w_DocumentCompleted;
        System.Windows.Forms.Application.Run();
        while (true) Console.Read();

    }

    static void w_DocumentCompleted(object sender, System.Windows.Forms.WebBrowserDocumentCompletedEventArgs e)
    {

        var bmp = new System.Drawing.Bitmap(w.Width, w.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        ((System.Windows.Forms.Control)w).DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, w.Width, w.Height));
        for (int i = 0; i < w.Width; i++) for (int j = 0; j < w.Height; j++) if (bmp.GetPixel(i, j).A != 255)
                {
                    Console.WriteLine("Alpha != 255");
                    return;
                }

        Console.WriteLine("All pixels have alpha value of 255");
        bmp.Save(@"d:ss.png", System.Drawing.Imaging.ImageFormat.Png);
        // HIDDEN TEXT has opcity of 0 but it's appearing in image



    }
}

解决方案

I'm looking for a built-in solution to take a screenshot from posted URL in the question without HIDDEN TEXT. In other words a solution to respect opacity.

The following code does just that: respects CSS opacity. Amongst other things, it uses a Metafile object and OleDraw API to render the web page's image.

The test HTML:

<!DOCTYPE html>
<body style='background-color: grey'>
    <div style='background-color: blue; opacity: 0.2; color: yellow'>This is a text</div>
</body>

The output:

The code (console app):

using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Console_21697048
{
    // http://stackoverflow.com/q/21697048/1768303

    class Program
    {
        const string HTML = "<!DOCTYPE html><body style='background-color: grey'><div style='background-color: blue; opacity: 0.2; color: yellow'>This is a text</div></body>";
        const string FILE_NAME = "webpage.png";
        readonly static Size IMAGE_SIZE = new Size(320, 200); 

        // Main
        static void Main(string[] args)
        {
            try
            {
                // enable HTML5 etc (assuming we're running IE9+)
                SetFeatureBrowserFeature("FEATURE_BROWSER_EMULATION", 9000);
                // force software rendering
                SetFeatureBrowserFeature("FEATURE_IVIEWOBJECTDRAW_DMLT9_WITH_GDI", 1);
                SetFeatureBrowserFeature("FEATURE_GPU_RENDERING", 0);

                using (var apartment = new MessageLoopApartment())
                {
                    // create WebBrowser on a seprate thread with its own message loop
                    var webBrowser = apartment.Invoke(() => new WebBrowser());

                    // navigate and wait for the result 
                    apartment.Invoke(() =>
                    {
                        var pageLoadedTcs = new TaskCompletionSource<bool>();
                        webBrowser.DocumentCompleted += (s, e) =>
                            pageLoadedTcs.TrySetResult(true);

                        webBrowser.DocumentText = HTML;
                        return pageLoadedTcs.Task;
                    }).Wait();

                    // save the picture
                    apartment.Invoke(() =>
                    {
                        webBrowser.Size = IMAGE_SIZE;
                        var rectangle = new Rectangle(0, 0, webBrowser.Width, webBrowser.Height);

                        // get reference DC
                        using (var screenGraphics = webBrowser.CreateGraphics())
                        {
                            var screenHdc = screenGraphics.GetHdc();
                            // create a metafile
                            using (var metafile = new Metafile(screenHdc, rectangle, MetafileFrameUnit.Pixel))
                            {
                                using (var graphics = Graphics.FromImage(metafile))
                                {
                                    var hdc = graphics.GetHdc();
                                    var rect = new Rectangle(0, 0, 320, 50);
                                    OleDraw(webBrowser.ActiveXInstance, DVASPECT_CONTENT, hdc, ref rectangle);
                                    graphics.ReleaseHdc(hdc);
                                }
                                // save the metafile as bitmap
                                metafile.Save(FILE_NAME, ImageFormat.Png);
                            }
                            screenGraphics.ReleaseHdc(screenHdc);
                        }
                    });

                    // dispose of webBrowser
                    apartment.Invoke(() => webBrowser.Dispose());
                    webBrowser = null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        // interop
        const uint DVASPECT_CONTENT = 1;

        [DllImport("ole32.dll", PreserveSig = false)]
        static extern void OleDraw(
            [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
            uint dwAspect,
            IntPtr hdcDraw,
            [In] ref System.Drawing.Rectangle lprcBounds);

        // WebBrowser Feature Control
        // http://msdn.microsoft.com/en-us/library/ie/ee330733(v=vs.85).aspx
        static void SetFeatureBrowserFeature(string feature, uint value)
        {
            if (LicenseManager.UsageMode != LicenseUsageMode.Runtime)
                return;
            var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
            Registry.SetValue(@"HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerMainFeatureControl" + feature,
                appName, value, RegistryValueKind.DWord);
        }
    }


    // MessageLoopApartment
    // more info: http://stackoverflow.com/a/21808747/1768303

    public class MessageLoopApartment : IDisposable
    {
        Thread _thread; // the STA thread

        TaskScheduler _taskScheduler; // the STA thread's task scheduler

        public TaskScheduler TaskScheduler { get { return _taskScheduler; } }

        /// <summary>MessageLoopApartment constructor</summary>
        public MessageLoopApartment()
        {
            var tcs = new TaskCompletionSource<TaskScheduler>();

            // start an STA thread and gets a task scheduler
            _thread = new Thread(startArg =>
            {
                EventHandler idleHandler = null;

                idleHandler = (s, e) =>
                {
                    // handle Application.Idle just once
                    Application.Idle -= idleHandler;
                    // return the task scheduler
                    tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());
                };

                // handle Application.Idle just once
                // to make sure we're inside the message loop
                // and SynchronizationContext has been correctly installed
                Application.Idle += idleHandler;
                Application.Run();
            });

            _thread.SetApartmentState(ApartmentState.STA);
            _thread.IsBackground = true;
            _thread.Start();
            _taskScheduler = tcs.Task.Result;
        }

        /// <summary>shutdown the STA thread</summary>
        public void Dispose()
        {
            if (_taskScheduler != null)
            {
                var taskScheduler = _taskScheduler;
                _taskScheduler = null;

                // execute Application.ExitThread() on the STA thread
                Task.Factory.StartNew(
                    () => Application.ExitThread(),
                    CancellationToken.None,
                    TaskCreationOptions.None,
                    taskScheduler).Wait();

                _thread.Join();
                _thread = null;
            }
        }

        /// <summary>Task.Factory.StartNew wrappers</summary>
        public void Invoke(Action action)
        {
            Task.Factory.StartNew(action, 
                CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Wait();
        }

        public TResult Invoke<TResult>(Func<TResult> action)
        {
            return Task.Factory.StartNew(action,
                CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Result;
        }
    }
}