How to fix opacity error using DrawToBitmap in WebBrowser Control?

According to the following link and my console application, the DrawToBitmap method DrawToBitmap not take opacity into account.

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

My HTML is: 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 an alternative .NET built-in solution ( without CEF, Awesomium or any extension ), just a .NET built-in function to fix a bug or an alternative solution to take a screenshot of the web URL in my console application.

If I create a WebBrowser window that is visible to my client and use CopyFromScreen , the opacity is respected and HIDDEN TEXT not displayed, as much as I would like the WebBrowser window WebBrowser be displayed on the desktop screen.

I am looking for a built-in solution to take a screenshot from a hosted URL in a question without HIDDEN TEXT . In other words, the solution corresponds to opacity .

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

Full source code (console template, add links 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 appearing in image } } 
+8
c # webbrowser-control
Feb 11 '14 at 8:51
source share
1 answer

I am looking for a built-in solution to take a screenshot from a published URL in a question without HIDDEN TEXT. In other words, the decision to respect opacity.

The following code does just that: respects CSS opacity . Among other things, it uses the Metafile object and OleDraw to display the image of the web page.

HTML test:

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

Exit:

opacity

Code (console application):

 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_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\" + 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 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; } } } 
+5
Feb 17 '14 at 11:47
source share



All Articles