private Image CreateImage(GeckoWebBrowser browser) { if (_syncControl.InvokeRequired) { return((Image)_syncControl.Invoke(new Func <GeckoWebBrowser, Image>(CreateImage), browser)); } #if __MonoCS__ var offscreenBrowser = browser as OffScreenGeckoWebBrowser; Debug.Assert(offscreenBrowser != null); return(offscreenBrowser.GetBitmap(browser.Width, browser.Height)); #else var creator = new ImageCreator(browser); byte[] imageBytes = creator.CanvasGetPngImage((uint)browser.Width, (uint)browser.Height); // Ensure image is still valid after the MemoryStream closes. using (var stream = new MemoryStream(imageBytes)) { using (var image = new Bitmap(stream)) { return(new Bitmap((image))); } } #endif }
public void LinuxSend() { ImageCreator ic = new ImageCreator(geckoWebBrowser1); // TODO: Clean and speed up this nonsense! byte[] b = ic.CanvasGetPngImage(0, 0, (uint)geckoWebBrowser1.Width, (uint)geckoWebBrowser1.Height); using (MemoryStream ms = new MemoryStream(b)) { using (Image img = Image.FromStream(ms)) { using (Bitmap bmp = new Bitmap(img, 800, 450)) { MemoryStream res = new MemoryStream(); bmp.Save(res, ImageFormat.Png); byte[] result = res.ToArray(); byte[] len = BitConverter.GetBytes((int)res.Length); Program.STDOut.Write(len, 0, 4); Program.STDOut.Write(result, 0, (int)res.Length); Program.STDOut.Flush(); } } } }
private Image CreateImage(GeckoWebBrowser browser, Color coverColor, int top, int bottom) { if (_syncControl.InvokeRequired) { return((Image)_syncControl.Invoke(new Func <GeckoWebBrowser, Color, int, int, Image>(CreateImage), browser, coverColor, top, bottom)); } // It's REALLY tricky to get the thumbnail created so that it reliably shows the image. // See BL-4170 and then BL-6257. We tried all kinds of tricks to tell when the image is // loaded into the document, such as checking image.completed and image.naturalWidth > 0 // and waiting for two cycles of window.requestAnimationFrame (which is supposed to cover // starting and completing painting images) after the onload event fires. None of this // helped appreciably. A 400ms delay was enough for most images on a fast desktop, but // there was no way to tell how long would be enough on a slow laptop. // So, we finally came up with this technique, which is to examine the actual bitmap // that is produced to see whether there is something drawn in the image region of the // page. Even that did not prove to be enough: it's quite possible (especially with a tall // PNG image) for CanvasGetPngImage to return an image with the cover picture only partly // drawn. Fortunately, it seems to consistently draw from the top down, so we can be pretty // sure there is no more image to come if we do two cycles and there is no change in the // last line that is drawn. // On a typical tall PNG this loop has three iterations. // image is partly drawn (~40ms); ~140ms to find last line // image is fully drawn (~80ms); 1ms to find last line // image is fully drawn again (~28ms); 1ms to find last line // On a typical wide png, 2 iterations: // ~40 to draw image, ~80 to find last line (and repeat) // For jpg we seem to typically have three also: // ~20ms to make image; ~200ms to determine nothing is there // ~600ms to make image; ~40 to find last line // ~120 to redraw; ~40 to find last line while (true) // Exit when we settle on an image and return it. { var watch = new Stopwatch(); watch.Start(); int lastLineOfImage = -1; while (true) { var creator = new ImageCreator(browser); byte[] imageBytes = creator.CanvasGetPngImage((uint)browser.Width, (uint)browser.Height); using (var stream = new MemoryStream(imageBytes)) { using (var image = new Bitmap(stream)) { if (watch.ElapsedMilliseconds > 5000) { // Maybe there's no image or it's color perfectly mathches the background? // When we used to do this with a simple delay 400ms was usually enough; // if we can't get it in 5s give up, and use whatever we've got. watch.Stop(); Debug.WriteLine("returned possibly incomplete thumnail after more than 5000ms"); return(new Bitmap(image)); } if (top < 0) { // no image to wait for, go with what we have. return(new Bitmap(image)); } // I'm not sure how top or bottom can get to be greater than image.Height, but if they do, // it causes a crash. It makes no sense to look for the last line drawn beyond the end of the // image, so if something tries, just start looking at the bottom. var newLastLine = GetLastLineOfImage(coverColor, Math.Min(top, image.Height), Math.Min(bottom, image.Height), image); // If nothing has been drawn yet, we want to keep trying until something is. // If something has been drawn, we want to keep trying until a cycle when // nothing more gets added. if (newLastLine == -1 || newLastLine > lastLineOfImage) { lastLineOfImage = newLastLine; // This is meant to give the browser more of a chance to load it. // It may well have been working on it anyway in another thread // while we were checking pixels. Not too sure about the best length // for this delay; longer might mean less time wasted checking pixels, // but the minimum delay is two times this interval, so we don't want // it too long. 50ms, at least on my desktop, usually doesn't result // in any wasted iterations, nor much delay. Thread.Sleep(50); continue; // try again } // No more image drawn than the last iteration, and we got something, so assume we have the whole thing. watch.Stop(); Debug.WriteLine("Got image after waiting " + watch.ElapsedMilliseconds); return(new Bitmap(image)); } } } } }