如何使用 WebBrowser Control 上的 DrawToBitmap 修复不透明度错误? [英] How to fix a opacity bug with DrawToBitmap on WebBrowser Control?
问题描述
根据以下链接和我的控制台应用程序,方法 DrawToBitmap
不考虑不透明度.
According to following link and my console application the method DrawToBitmap
doesn't respect opacity.
我的 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.Drawing
和System.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屋!