/// <summary>Captures a screenshot of a window using Windows GDI. Captures transparency.</summary> /// <param name="handle">handle of the window to capture</param> /// <returns>the captured window image</returns> private static Image CaptureWindowWithGDI(Workflow wfgdi, IntPtr handle, out Rectangle windowRect) { Image windowImageGdi = null; Bitmap whiteBGImage = null, blackBGImage = null, white2BGImage = null; if (wfgdi.ActiveWindowTryCaptureChildren) { windowRect = new WindowRectangle(handle).CalculateWindowRectangle(); } else { windowRect = CaptureHelpers.GetWindowRectangle(handle); } try { using (new Freeze(wfgdi, handle)) using (Form form = new Form()) { form.BackColor = Color.White; form.FormBorderStyle = FormBorderStyle.None; form.ShowInTaskbar = false; int offset = wfgdi.ActiveWindowIncludeShadows && !NativeMethods.IsWindowMaximized(handle) ? 20 : 0; windowRect.Inflate(offset, offset); windowRect.Intersect(CaptureHelpers.GetScreenBounds()); NativeMethods.ShowWindow(form.Handle, (int)WindowShowStyle.ShowNormalNoActivate); NativeMethods.SetWindowPos(form.Handle, handle, windowRect.X, windowRect.Y, windowRect.Width, windowRect.Height, NativeMethods.SWP_NOACTIVATE); Application.DoEvents(); whiteBGImage = (Bitmap)Screenshot.CaptureRectangleNative2(windowRect); form.BackColor = Color.Black; Application.DoEvents(); blackBGImage = (Bitmap)Screenshot.CaptureRectangleNative2(windowRect); if (!wfgdi.ActiveWindowGDIFreezeWindow) { form.BackColor = Color.White; Application.DoEvents(); white2BGImage = (Bitmap)Screenshot.CaptureRectangleNative2(windowRect); } } if (wfgdi.ActiveWindowGDIFreezeWindow || whiteBGImage.AreBitmapsEqual(white2BGImage)) { windowImageGdi = HelpersLib.GraphicsHelper.Core.ComputeOriginal(whiteBGImage, blackBGImage); } else { windowImageGdi = (Image)whiteBGImage.Clone(); } } finally { if (whiteBGImage != null) { whiteBGImage.Dispose(); } if (blackBGImage != null) { blackBGImage.Dispose(); } if (white2BGImage != null) { white2BGImage.Dispose(); } } if (windowImageGdi != null) { Rectangle windowRectCropped = HelpersLib.GraphicsHelper.Core.GetCroppedArea((Bitmap)windowImageGdi); windowImageGdi = CaptureHelpers.CropImage(windowImageGdi, windowRectCropped); if (wfgdi.DrawCursor) { #if DEBUG DebugHelper.WriteLine("Fixed cursor position (before): " + windowRect.ToString()); #endif windowRect.X += windowRectCropped.X; windowRect.Y += windowRectCropped.Y; #if DEBUG DebugHelper.WriteLine("Fixed cursor position (after): " + windowRect.ToString()); #endif } } return(windowImageGdi); }
/// <summary> /// Make a full-size thumbnail of the captured window on a new topmost form, and capture /// this new form with a black and then white background. Then compute the transparency by /// difference between the black and white versions. /// This method has these advantages: /// - the full form is captured even if it is obscured on the Windows desktop /// - there is no problem with unpredictable Z-order anymore (the background and /// the window to capture are drawn on the same window) /// Note: now that GDI capture is more robust, DWM capture is not that useful anymore. /// </summary> /// <param name="handle">handle of the window to capture</param> /// <param name="windowRect">the bounds of the window</param> /// <param name="redBGImage">the window captured with a red background</param> /// <param name="captureRedBGImage">whether to do the capture of the window with a red background</param> /// <returns>the captured window image</returns> private static Image CaptureWindowWithTransparencyDWM(IntPtr handle, Rectangle windowRect, out Bitmap redBGImage, bool captureRedBGImage) { Image windowImage = null; redBGImage = null; using (Form form = new Form()) { form.FormBorderStyle = FormBorderStyle.None; form.ShowInTaskbar = false; form.BackColor = Color.White; form.TopMost = true; form.Bounds = windowRect; IntPtr thumb; NativeMethods.DwmRegisterThumbnail(form.Handle, handle, out thumb); SIZE size; NativeMethods.DwmQueryThumbnailSourceSize(thumb, out size); if (size.x <= 0 || size.y <= 0) { return(null); } form.Location = new Point(windowRect.X, windowRect.Y); form.Size = new Size(size.x, size.y); form.Show(); NativeMethods.DWM_THUMBNAIL_PROPERTIES props = new NativeMethods.DWM_THUMBNAIL_PROPERTIES(); props.dwFlags = NativeMethods.DWM_TNP_VISIBLE | NativeMethods.DWM_TNP_RECTDESTINATION | NativeMethods.DWM_TNP_OPACITY; props.fVisible = true; props.opacity = (byte)255; props.rcDestination = new RECT(0, 0, size.x, size.y); NativeMethods.DwmUpdateThumbnailProperties(thumb, ref props); NativeMethods.ActivateWindowRepeat(handle, 250); Bitmap whiteBGImage = CaptureRectangle(windowRect) as Bitmap; form.BackColor = Color.Black; form.Refresh(); NativeMethods.ActivateWindowRepeat(handle, 250); Bitmap blackBGImage = CaptureRectangle(windowRect) as Bitmap; if (captureRedBGImage) { form.BackColor = Color.Red; form.Refresh(); NativeMethods.ActivateWindowRepeat(handle, 250); redBGImage = CaptureRectangle(windowRect) as Bitmap; } form.BackColor = Color.White; form.Refresh(); NativeMethods.ActivateWindowRepeat(handle, 250); Bitmap whiteBGImage2 = CaptureRectangle(windowRect) as Bitmap; // Don't do transparency calculation if an animated picture is detected if (whiteBGImage.AreBitmapsEqual(whiteBGImage2)) { windowImage = GraphicsMgr.ComputeOriginal(whiteBGImage, blackBGImage); } else { FileSystem.AppendDebug("Detected animated image => cannot compute transparency"); form.Close(); Application.DoEvents(); Image result = new Bitmap(whiteBGImage.Width, whiteBGImage.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(result)) { // Redraw the image on a black background to avoid transparent pixels artifacts g.Clear(Color.Black); g.DrawImage(whiteBGImage, 0, 0); } windowImage = result; } NativeMethods.DwmUnregisterThumbnail(thumb); blackBGImage.Dispose(); whiteBGImage.Dispose(); whiteBGImage2.Dispose(); } return(windowImage); }
/// <summary> /// Make a full-size thumbnail of the captured window on a new topmost form, and capture /// this new form with a black and then white background. Then compute the transparency by /// difference between the black and white versions. /// This method has these advantages: /// - the full form is captured even if it is obscured on the Windows desktop /// - there is no problem with unpredictable Z-order anymore (the background and /// the window to capture are drawn on the same window) /// </summary> /// <param name="handle">handle of the window to capture</param> /// <param name="windowRect">the bounds of the window</param> /// <param name="redBGImage">the window captured with a red background</param> /// <param name="captureRedBGImage">whether to do the capture of the window with a red background</param> /// <returns>the captured window image</returns> private static Image CaptureWindowWithDWM(IntPtr handle, Rectangle windowRect, out Bitmap redBGImage, Color backColor) { Image windowImage = null; redBGImage = null; if (backColor != Color.White) { backColor = Color.FromArgb(255, backColor.R, backColor.G, backColor.B); } using (Form form = new Form()) { form.StartPosition = FormStartPosition.Manual; form.FormBorderStyle = FormBorderStyle.None; form.ShowInTaskbar = false; form.BackColor = backColor; form.TopMost = true; form.Bounds = CaptureHelpers.GetWindowRectangle(handle, false); IntPtr thumb; NativeMethods.DwmRegisterThumbnail(form.Handle, handle, out thumb); SIZE size; NativeMethods.DwmQueryThumbnailSourceSize(thumb, out size); #if DEBUG DebugHelper.WriteLine("Rectangle Size: " + windowRect.ToString()); DebugHelper.WriteLine("Window Size: " + size.ToString()); #endif if (size.Width <= 0 || size.Height <= 0) { return(null); } DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES(); props.dwFlags = NativeMethods.DWM_TNP_VISIBLE | NativeMethods.DWM_TNP_RECTDESTINATION | NativeMethods.DWM_TNP_OPACITY; props.fVisible = true; props.opacity = (byte)255; props.rcDestination = new RECT(0, 0, size.Width, size.Height); NativeMethods.DwmUpdateThumbnailProperties(thumb, ref props); form.Show(); System.Threading.Thread.Sleep(250); if (form.BackColor != Color.White) { // no need for transparency; user has requested custom background color NativeMethods.ActivateWindowRepeat(form.Handle, 250); windowImage = Screenshot.CaptureRectangleNative(windowRect) as Bitmap; } else if (form.BackColor == Color.White) { // transparent capture NativeMethods.ActivateWindowRepeat(handle, 250); Bitmap whiteBGImage = Screenshot.CaptureRectangleNative(windowRect) as Bitmap; form.BackColor = Color.Black; form.Refresh(); NativeMethods.ActivateWindowRepeat(handle, 250); Bitmap blackBGImage = Screenshot.CaptureRectangleNative(windowRect) as Bitmap; // Capture rounded corners with except for Windows 8 if (ZAppHelper.IsWindows8()) { form.BackColor = Color.Red; form.Refresh(); NativeMethods.ActivateWindowRepeat(handle, 250); redBGImage = Screenshot.CaptureRectangleNative(windowRect) as Bitmap; } form.BackColor = Color.White; form.Refresh(); NativeMethods.ActivateWindowRepeat(handle, 250); Bitmap whiteBGImage2 = Screenshot.CaptureRectangleNative(windowRect) as Bitmap; // Don't do transparency calculation if an animated picture is detected if (whiteBGImage.AreBitmapsEqual(whiteBGImage2)) { windowImage = HelpersLib.GraphicsHelper.Core.ComputeOriginal(whiteBGImage, blackBGImage); } else { DebugHelper.WriteLine("Detected animated image => cannot compute transparency"); form.Close(); Application.DoEvents(); Image result = new Bitmap(whiteBGImage.Width, whiteBGImage.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(result)) { // Redraw the image on a black background to avoid transparent pixels artifacts g.Clear(Color.Black); g.DrawImage(whiteBGImage, 0, 0); } windowImage = result; } blackBGImage.Dispose(); whiteBGImage.Dispose(); whiteBGImage2.Dispose(); } NativeMethods.DwmUnregisterThumbnail(thumb); } return(windowImage); }
/// <summary> /// Captures a screenshot of a window using Windows GDI. Captures transparency. /// </summary> /// <param name="handle">handle of the window to capture</param> /// <returns>the captured window image</returns> private static Image CaptureWindowWithTransparencyGDI(IntPtr handle, Rectangle windowRect) { Image windowImage = null; Bitmap whiteBGImage = null, blackBGImage = null, white2BGImage = null; try { using (new Freeze(handle)) using (Form form = new Form()) { form.BackColor = Color.White; form.FormBorderStyle = FormBorderStyle.None; form.ShowInTaskbar = false; int offset = Engine.conf.ActiveWindowIncludeShadows && !NativeMethods.IsWindowMaximized(handle) ? 20 : 0; windowRect = windowRect.AddMargin(offset); windowRect.Intersect(GraphicsMgr.GetScreenBounds()); NativeMethods.ShowWindow(form.Handle, (int)NativeMethods.WindowShowStyle.ShowNormalNoActivate); NativeMethods.SetWindowPos(form.Handle, handle, windowRect.X, windowRect.Y, windowRect.Width, windowRect.Height, NativeMethods.SWP_NOACTIVATE); Application.DoEvents(); whiteBGImage = (Bitmap)CaptureRectangle(NativeMethods.GetDesktopWindow(), windowRect); form.BackColor = Color.Black; Application.DoEvents(); blackBGImage = (Bitmap)CaptureRectangle(NativeMethods.GetDesktopWindow(), windowRect); if (!Engine.conf.ActiveWindowGDIFreezeWindow) { form.BackColor = Color.White; Application.DoEvents(); white2BGImage = (Bitmap)CaptureRectangle(NativeMethods.GetDesktopWindow(), windowRect); } } if (Engine.conf.ActiveWindowGDIFreezeWindow || whiteBGImage.AreBitmapsEqual(white2BGImage)) { windowImage = GraphicsMgr.ComputeOriginal(whiteBGImage, blackBGImage); } else { windowImage = (Image)whiteBGImage.Clone(); } } finally { if (whiteBGImage != null) { whiteBGImage.Dispose(); } if (blackBGImage != null) { blackBGImage.Dispose(); } if (white2BGImage != null) { white2BGImage.Dispose(); } } if (windowImage != null) { Rectangle windowRectCropped = GraphicsMgr.GetCroppedArea((Bitmap)windowImage); windowImage = GraphicsMgr.CropImage(windowImage, windowRectCropped); if (Engine.conf.ShowCursor) { windowRect.X += windowRectCropped.X; windowRect.Y += windowRectCropped.Y; DrawCursor(windowImage, windowRect.Location); } if (Engine.conf.ActiveWindowShowCheckers) { windowImage = ImageEffects.DrawCheckers(windowImage); } } return(windowImage); }