如何使用 WebBrowser Control 上的 DrawToBitmap 修复不透明度错误? [英] How to fix a opacity bug with DrawToBitmap on WebBrowser Control?

查看:15
本文介绍了如何使用 WebBrowser Control 上的 DrawToBitmap 修复不透明度错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据以下链接和我的控制台应用程序,方法 DrawToBitmap 不考虑不透明度.

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

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

我的 HTML 代码:http://fiddle.jshell.net/L37TC/

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 

我的 C# 控制台代码:

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));

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

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.

如果我让 WebBrowser 窗口对我的客户端可见并使用 CopyFromScreen 不透明度受到尊重并且 HIDDEN TEXT 没有显示,怎么办我不想让 WebBrowser 窗口在桌面屏幕上可见.

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.

我正在寻找一种内置解决方案,可以从问题中发布的 URL 中截取屏幕截图,而无需 HIDDEN TEXT.换句话说,一种尊重opacity的解决方案.

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.

我的 Bitmap class(.NET 类不是 BMP 格式)中的所有像素的 alpha 值为 255.所以问题是不与文件格式.我尝试过 PNG 和任何其他 .NET 支持的格式.

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.

完整的源代码(控制台模板,需要添加对System.DrawingSystem.Windows.Forms

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



    }
}

推荐答案

我正在寻找一种内置解决方案来截取已发布的屏幕截图没有隐藏文本的问题中的 URL.换句话说,解决方案尊重不透明度.

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.

以下代码就是这样做的:尊重 CSS 不透明度.除其他外,它使用 Metafile 对象和 OleDraw API 来呈现网页的图像.

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.

测试 HTML:

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

输出:

代码(控制台应用):

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;
        }
    }
}

这篇关于如何使用 WebBrowser Control 上的 DrawToBitmap 修复不透明度错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆