diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 67f783c0e..c2a1711f2 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -535,7 +535,7 @@ namespace Greenshot.Drawing { /// /// true if cropped public bool AutoCrop() { - Rectangle cropRectangle = ImageHelper.FindAutoCropRectangle(Image); + Rectangle cropRectangle = ImageHelper.FindAutoCropRectangle(Image, conf.AutoCropDifference); if (isCropPossible(ref cropRectangle)) { DrawingMode = DrawingModes.Crop; cropContainer = new CropContainer(this); @@ -637,6 +637,18 @@ namespace Greenshot.Drawing { newImage = ImageHelper.RotateFlip((Bitmap)Image, rotateFlipType); break; } + // The following was added to correct any unneeded pixels, had the bad effect that sometimes everything was cropped... :( + //Rectangle autoCropRectangle = ImageHelper.FindAutoCropRectangle(newImage, 0); + //if (!Size.Empty.Equals(autoCropRectangle.Size) && !autoCropRectangle.Size.Equals(newImage.Size)) { + // LOG.InfoFormat("Crop to {0}", autoCropRectangle); + // using (Bitmap tmpImage = newImage) { + // newImage = ImageHelper.CloneArea(newImage, autoCropRectangle, PixelFormat.DontCare); + // } + // // Fix offset + // offset = new Point(offset.X - autoCropRectangle.X, offset.Y - autoCropRectangle.Y); + //} else { + // LOG.DebugFormat("No cropping needed!"); + //} if (newImage != null) { // Make sure the elements move according to the offset the effect made the bitmap move @@ -655,6 +667,11 @@ namespace Greenshot.Drawing { } } + /// + /// check if a crop is possible + /// + /// + /// true if this is possible public bool isCropPossible(ref Rectangle cropRectangle) { cropRectangle = Helpers.GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); if (cropRectangle.Left < 0) cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); @@ -684,12 +701,16 @@ namespace Greenshot.Drawing { } } + /// + /// Crop the surface + /// + /// + /// public bool ApplyCrop(Rectangle cropRectangle) { if (isCropPossible(ref cropRectangle)) { Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); // we should not forget to Dispose the images!! Bitmap tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution); Point offset = new Point(-cropRectangle.Left, -cropRectangle.Top); // Make undoable diff --git a/Greenshot/Forms/MainForm.Designer.cs b/Greenshot/Forms/MainForm.Designer.cs index f30c7ddd6..6e567c76b 100644 --- a/Greenshot/Forms/MainForm.Designer.cs +++ b/Greenshot/Forms/MainForm.Designer.cs @@ -132,7 +132,6 @@ namespace Greenshot { this.contextmenu_capturefullscreen.ShortcutKeyDisplayString = "Ctrl + Print"; this.contextmenu_capturefullscreen.Size = new System.Drawing.Size(242, 22); this.contextmenu_capturefullscreen.Text = "Capture full screen"; - this.contextmenu_capturefullscreen.Click += new System.EventHandler(this.CaptureFullScreenToolStripMenuItemClick); // // toolStripSeparator4 // diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 13131d2d0..88d5e4c05 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -562,6 +562,7 @@ namespace Greenshot { void CaptureRegion() { CaptureHelper.CaptureRegion(true); } + void CaptureClipboard() { CaptureHelper.CaptureClipboard(); } @@ -575,15 +576,19 @@ namespace Greenshot { } } } + void CaptureFullScreen() { - CaptureHelper.CaptureFullscreen(true); + CaptureHelper.CaptureFullscreen(true, conf.ScreenCaptureMode); } + void CaptureLastRegion() { CaptureHelper.CaptureLastRegion(true); } + void CaptureIE() { CaptureHelper.CaptureIE(true); } + void CaptureWindow() { if (conf.CaptureWindowsInteractive) { CaptureHelper.CaptureWindowInteractive(true); @@ -609,6 +614,17 @@ namespace Greenshot { } catch (Exception ex) { LOG.WarnFormat("Problem accessing IE information: {0}", ex.Message); } + + // Multi-Screen captures + this.contextmenu_capturefullscreen.Click -= new System.EventHandler(this.CaptureFullScreenToolStripMenuItemClick); + this.contextmenu_capturefullscreen.DropDownOpening -= new System.EventHandler(MultiScreenDropDownOpening); + this.contextmenu_capturefullscreen.DropDownClosed -= new System.EventHandler(MultiScreenDropDownClosing); + if (Screen.AllScreens.Length > 1) { + this.contextmenu_capturefullscreen.DropDownOpening += new System.EventHandler(MultiScreenDropDownOpening); + this.contextmenu_capturefullscreen.DropDownClosed += new System.EventHandler(MultiScreenDropDownClosing); + } else { + this.contextmenu_capturefullscreen.Click += new System.EventHandler(this.CaptureFullScreenToolStripMenuItemClick); + } } void ContextMenuClosing(object sender, EventArgs e) { @@ -653,6 +669,56 @@ namespace Greenshot { } } + /// + /// MultiScreenDropDownOpening is called when mouse hovers over the Capture-Screen context menu + /// + /// + /// + private void MultiScreenDropDownOpening(object sender, EventArgs e) { + ToolStripMenuItem captureScreenMenuItem = (ToolStripMenuItem)sender; + captureScreenMenuItem.DropDownItems.Clear(); + if (Screen.AllScreens.Length > 1) { + ToolStripMenuItem captureScreenItem; + string allDeviceName = ""; + foreach (Screen screen in Screen.AllScreens) { + string deviceName = screen.DeviceName; + if (allDeviceName.Length > 0) { + allDeviceName += " + "; + } + allDeviceName += deviceName.Substring(deviceName.Length - 1); + } + captureScreenItem = new ToolStripMenuItem(allDeviceName); + captureScreenItem.Click += delegate { + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureFullscreen(false, ScreenCaptureMode.FullScreen); + }); + }; + captureScreenMenuItem.DropDownItems.Add(captureScreenItem); + foreach (Screen screen in Screen.AllScreens) { + Screen screenToCapture = screen; + string deviceName = screenToCapture.DeviceName; + deviceName = deviceName.Substring(deviceName.Length - 1); + captureScreenItem = new ToolStripMenuItem(deviceName); + captureScreenItem.Click += delegate { + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureRegion(false, screenToCapture.Bounds); + }); + }; + captureScreenMenuItem.DropDownItems.Add(captureScreenItem); + } + } + } + + /// + /// MultiScreenDropDownOpening is called when mouse leaves the context menu + /// + /// + /// + private void MultiScreenDropDownClosing(object sender, EventArgs e) { + ToolStripMenuItem captureScreenMenuItem = (ToolStripMenuItem)sender; + captureScreenMenuItem.DropDownItems.Clear(); + } + /// /// Build a selectable list of windows when we enter the menu item /// @@ -783,7 +849,7 @@ namespace Greenshot { void CaptureFullScreenToolStripMenuItemClick(object sender, EventArgs e) { BeginInvoke((MethodInvoker)delegate { - CaptureHelper.CaptureFullscreen(false); + CaptureHelper.CaptureFullscreen(false, conf.ScreenCaptureMode); }); } diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 68743cd71..860f6a1e7 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -52,6 +52,7 @@ namespace Greenshot.Helpers { private bool captureMouseCursor = false; private ICapture capture = null; private CaptureMode captureMode; + private ScreenCaptureMode screenCaptureMode = ScreenCaptureMode.Auto; private Thread windowDetailsThread = null; public static void CaptureClipboard() { @@ -64,7 +65,10 @@ namespace Greenshot.Helpers { CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse, destination); captureHelper.MakeCapture(); } - public static void CaptureFullscreen(bool captureMouse) { + public static void CaptureRegion(bool captureMouse, Rectangle region) { + new CaptureHelper(CaptureMode.Region, captureMouse).MakeCapture(region); + } + public static void CaptureFullscreen(bool captureMouse, ScreenCaptureMode screenCaptureMode) { new CaptureHelper(CaptureMode.FullScreen, captureMouse).MakeCapture(); } public static void CaptureLastRegion(bool captureMouse) { @@ -103,6 +107,11 @@ namespace Greenshot.Helpers { this.captureMouseCursor = captureMouseCursor; } + public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, ScreenCaptureMode screenCaptureMode) : this(captureMode) { + this.captureMouseCursor = captureMouseCursor; + this.screenCaptureMode = screenCaptureMode; + } + public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) { capture.CaptureDetails.AddDestination(destination); } @@ -131,6 +140,16 @@ namespace Greenshot.Helpers { MakeCapture(); } + /// + /// Make Capture for region + /// + /// filename + private void MakeCapture(Rectangle region) { + captureRect = region; + MakeCapture(); + } + + /// /// Make Capture with specified destinations /// @@ -210,7 +229,32 @@ namespace Greenshot.Helpers { } break; case CaptureMode.FullScreen: - capture = WindowCapture.CaptureScreen(capture); + // Check how we need to capture the screen + bool captureTaken = false; + switch (screenCaptureMode) { + case ScreenCaptureMode.Auto: + Point mouseLocation = WindowCapture.GetCursorLocation(); + foreach (Screen screen in Screen.AllScreens) { + if (screen.Bounds.Contains(mouseLocation)) { + capture = WindowCapture.CaptureRectangle(capture, screen.Bounds); + captureTaken = true; + break; + } + } + break; + case ScreenCaptureMode.Fixed: + if (conf.ScreenToCapture > 0 && conf.ScreenToCapture <= Screen.AllScreens.Length) { + capture = WindowCapture.CaptureRectangle(capture, Screen.AllScreens[conf.ScreenToCapture].Bounds); + captureTaken = true; + } + break; + case ScreenCaptureMode.FullScreen: + // Do nothing, we take the fullscreen capture automatically + break; + } + if (!captureTaken) { + capture = WindowCapture.CaptureScreen(capture); + } HandleCapture(); break; case CaptureMode.Clipboard: @@ -279,19 +323,25 @@ namespace Greenshot.Helpers { break; case CaptureMode.LastRegion: if (!RuntimeConfig.LastCapturedRegion.IsEmpty) { - capture = WindowCapture.CaptureScreen(capture); + capture = WindowCapture.CaptureRectangle(capture, RuntimeConfig.LastCapturedRegion); if (windowDetailsThread != null) { windowDetailsThread.Join(); } - capture.Crop(RuntimeConfig.LastCapturedRegion); capture.CaptureDetails.AddMetaData("source", "screen"); HandleCapture(); } break; case CaptureMode.Region: - capture = WindowCapture.CaptureScreen(capture); - capture.CaptureDetails.AddMetaData("source", "screen"); - CaptureWithFeedback(); + // Check if a region is pre-supplied! + if (Rectangle.Empty.Equals(captureRect)) { + capture = WindowCapture.CaptureScreen(capture); + capture.CaptureDetails.AddMetaData("source", "screen"); + CaptureWithFeedback(); + } else { + capture = WindowCapture.CaptureRectangle(capture, captureRect); + capture.CaptureDetails.AddMetaData("source", "screen"); + HandleCapture(); + } break; case CaptureMode.Video: capture = WindowCapture.CaptureScreen(capture); diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index 83a624ae8..203f8529d 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -71,7 +71,11 @@ namespace GreenshotPlugin.Core { public bool CaptureWindowsInteractive; [IniProperty("CaptureDelay", Description="Capture delay in millseconds.", DefaultValue="100")] public int CaptureDelay; - [IniProperty("WindowCaptureMode", Description="The capture mode used to capture a Window.", DefaultValue="Auto")] + [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] + public ScreenCaptureMode ScreenCaptureMode; + [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] + public int ScreenToCapture; + [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] public WindowCaptureMode WindowCaptureMode; [IniProperty("WindowCaptureAllChildLocations", Description="Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue="False")] public bool WindowCaptureAllChildLocations; diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index c717ee2f4..f52c5e297 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -98,20 +98,20 @@ namespace GreenshotPlugin.Core { /// /// /// - private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) { + private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint, int cropDifference) { Rectangle cropRectangle = Rectangle.Empty; Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); Point max = new Point(int.MinValue, int.MinValue); - - if (conf.AutoCropDifference > 0) { + + if (cropDifference > 0) { for(int y = 0; y < buffer.Height; y++) { for(int x = 0; x < buffer.Width; x++) { Color currentColor = buffer.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); int diffG = Math.Abs(currentColor.G - referenceColor.G); int diffB = Math.Abs(currentColor.B - referenceColor.B); - if (((diffR+diffG+diffB)/3) > conf.AutoCropDifference) { + if (((diffR + diffG + diffB) / 3) > cropDifference) { if (x < min.X) min.X = x; if (y < min.Y) min.Y = y; if (x > max.X) max.X = x; @@ -140,12 +140,13 @@ namespace GreenshotPlugin.Core { } return cropRectangle; } + /// /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 /// /// /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image) { + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) { Rectangle cropRectangle = Rectangle.Empty; using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) { buffer.Lock(); @@ -162,7 +163,7 @@ namespace GreenshotPlugin.Core { // find biggest area foreach(Point checkPoint in checkPoints) { - currentRectangle = FindAutoCropRectangle(buffer, checkPoint); + currentRectangle = FindAutoCropRectangle(buffer, checkPoint, cropDifference); if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { cropRectangle = currentRectangle; } diff --git a/GreenshotPlugin/Interfaces/Capture.cs b/GreenshotPlugin/Interfaces/Capture.cs index ee77f0dec..384b78167 100644 --- a/GreenshotPlugin/Interfaces/Capture.cs +++ b/GreenshotPlugin/Interfaces/Capture.cs @@ -27,6 +27,7 @@ namespace Greenshot.Plugin { /// The capture mode for Greenshot /// public enum CaptureMode { None, Region, FullScreen, ActiveWindow, Window, LastRegion, Clipboard, File, IE, Video, Import }; + public enum ScreenCaptureMode { Auto, FullScreen, Fixed}; /// /// Details for the capture, like the window title and date/time etc.