Added multi-screen capture support! As a default the current screen under the cursor is captured. (ScreenCaptureMode.Auto)

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1806 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2012-04-19 11:10:57 +00:00
parent 54dd4614f5
commit e687450dfc
7 changed files with 161 additions and 19 deletions

View file

@ -535,7 +535,7 @@ namespace Greenshot.Drawing {
/// </summary> /// </summary>
/// <returns>true if cropped</returns> /// <returns>true if cropped</returns>
public bool AutoCrop() { public bool AutoCrop() {
Rectangle cropRectangle = ImageHelper.FindAutoCropRectangle(Image); Rectangle cropRectangle = ImageHelper.FindAutoCropRectangle(Image, conf.AutoCropDifference);
if (isCropPossible(ref cropRectangle)) { if (isCropPossible(ref cropRectangle)) {
DrawingMode = DrawingModes.Crop; DrawingMode = DrawingModes.Crop;
cropContainer = new CropContainer(this); cropContainer = new CropContainer(this);
@ -637,6 +637,18 @@ namespace Greenshot.Drawing {
newImage = ImageHelper.RotateFlip((Bitmap)Image, rotateFlipType); newImage = ImageHelper.RotateFlip((Bitmap)Image, rotateFlipType);
break; 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) { if (newImage != null) {
// Make sure the elements move according to the offset the effect made the bitmap move // Make sure the elements move according to the offset the effect made the bitmap move
@ -655,6 +667,11 @@ namespace Greenshot.Drawing {
} }
} }
/// <summary>
/// check if a crop is possible
/// </summary>
/// <param name="cropRectangle"></param>
/// <returns>true if this is possible</returns>
public bool isCropPossible(ref Rectangle cropRectangle) { public bool isCropPossible(ref Rectangle cropRectangle) {
cropRectangle = Helpers.GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); 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); if (cropRectangle.Left < 0) cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height);
@ -684,12 +701,16 @@ namespace Greenshot.Drawing {
} }
} }
/// <summary>
/// Crop the surface
/// </summary>
/// <param name="cropRectangle"></param>
/// <returns></returns>
public bool ApplyCrop(Rectangle cropRectangle) { public bool ApplyCrop(Rectangle cropRectangle) {
if (isCropPossible(ref cropRectangle)) { if (isCropPossible(ref cropRectangle)) {
Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
// we should not forget to Dispose the images!! // we should not forget to Dispose the images!!
Bitmap tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); Bitmap tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare);
tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution);
Point offset = new Point(-cropRectangle.Left, -cropRectangle.Top); Point offset = new Point(-cropRectangle.Left, -cropRectangle.Top);
// Make undoable // Make undoable

View file

@ -132,7 +132,6 @@ namespace Greenshot {
this.contextmenu_capturefullscreen.ShortcutKeyDisplayString = "Ctrl + Print"; this.contextmenu_capturefullscreen.ShortcutKeyDisplayString = "Ctrl + Print";
this.contextmenu_capturefullscreen.Size = new System.Drawing.Size(242, 22); this.contextmenu_capturefullscreen.Size = new System.Drawing.Size(242, 22);
this.contextmenu_capturefullscreen.Text = "Capture full screen"; this.contextmenu_capturefullscreen.Text = "Capture full screen";
this.contextmenu_capturefullscreen.Click += new System.EventHandler(this.CaptureFullScreenToolStripMenuItemClick);
// //
// toolStripSeparator4 // toolStripSeparator4
// //

View file

@ -562,6 +562,7 @@ namespace Greenshot {
void CaptureRegion() { void CaptureRegion() {
CaptureHelper.CaptureRegion(true); CaptureHelper.CaptureRegion(true);
} }
void CaptureClipboard() { void CaptureClipboard() {
CaptureHelper.CaptureClipboard(); CaptureHelper.CaptureClipboard();
} }
@ -575,15 +576,19 @@ namespace Greenshot {
} }
} }
} }
void CaptureFullScreen() { void CaptureFullScreen() {
CaptureHelper.CaptureFullscreen(true); CaptureHelper.CaptureFullscreen(true, conf.ScreenCaptureMode);
} }
void CaptureLastRegion() { void CaptureLastRegion() {
CaptureHelper.CaptureLastRegion(true); CaptureHelper.CaptureLastRegion(true);
} }
void CaptureIE() { void CaptureIE() {
CaptureHelper.CaptureIE(true); CaptureHelper.CaptureIE(true);
} }
void CaptureWindow() { void CaptureWindow() {
if (conf.CaptureWindowsInteractive) { if (conf.CaptureWindowsInteractive) {
CaptureHelper.CaptureWindowInteractive(true); CaptureHelper.CaptureWindowInteractive(true);
@ -609,6 +614,17 @@ namespace Greenshot {
} catch (Exception ex) { } catch (Exception ex) {
LOG.WarnFormat("Problem accessing IE information: {0}", ex.Message); 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) { void ContextMenuClosing(object sender, EventArgs e) {
@ -653,6 +669,56 @@ namespace Greenshot {
} }
} }
/// <summary>
/// MultiScreenDropDownOpening is called when mouse hovers over the Capture-Screen context menu
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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);
}
}
}
/// <summary>
/// MultiScreenDropDownOpening is called when mouse leaves the context menu
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MultiScreenDropDownClosing(object sender, EventArgs e) {
ToolStripMenuItem captureScreenMenuItem = (ToolStripMenuItem)sender;
captureScreenMenuItem.DropDownItems.Clear();
}
/// <summary> /// <summary>
/// Build a selectable list of windows when we enter the menu item /// Build a selectable list of windows when we enter the menu item
/// </summary> /// </summary>
@ -783,7 +849,7 @@ namespace Greenshot {
void CaptureFullScreenToolStripMenuItemClick(object sender, EventArgs e) { void CaptureFullScreenToolStripMenuItemClick(object sender, EventArgs e) {
BeginInvoke((MethodInvoker)delegate { BeginInvoke((MethodInvoker)delegate {
CaptureHelper.CaptureFullscreen(false); CaptureHelper.CaptureFullscreen(false, conf.ScreenCaptureMode);
}); });
} }

View file

@ -52,6 +52,7 @@ namespace Greenshot.Helpers {
private bool captureMouseCursor = false; private bool captureMouseCursor = false;
private ICapture capture = null; private ICapture capture = null;
private CaptureMode captureMode; private CaptureMode captureMode;
private ScreenCaptureMode screenCaptureMode = ScreenCaptureMode.Auto;
private Thread windowDetailsThread = null; private Thread windowDetailsThread = null;
public static void CaptureClipboard() { public static void CaptureClipboard() {
@ -64,7 +65,10 @@ namespace Greenshot.Helpers {
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse, destination); CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse, destination);
captureHelper.MakeCapture(); 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(); new CaptureHelper(CaptureMode.FullScreen, captureMouse).MakeCapture();
} }
public static void CaptureLastRegion(bool captureMouse) { public static void CaptureLastRegion(bool captureMouse) {
@ -103,6 +107,11 @@ namespace Greenshot.Helpers {
this.captureMouseCursor = captureMouseCursor; 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) { public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) {
capture.CaptureDetails.AddDestination(destination); capture.CaptureDetails.AddDestination(destination);
} }
@ -131,6 +140,16 @@ namespace Greenshot.Helpers {
MakeCapture(); MakeCapture();
} }
/// <summary>
/// Make Capture for region
/// </summary>
/// <param name="filename">filename</param>
private void MakeCapture(Rectangle region) {
captureRect = region;
MakeCapture();
}
/// <summary> /// <summary>
/// Make Capture with specified destinations /// Make Capture with specified destinations
/// </summary> /// </summary>
@ -210,7 +229,32 @@ namespace Greenshot.Helpers {
} }
break; break;
case CaptureMode.FullScreen: case CaptureMode.FullScreen:
// 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); capture = WindowCapture.CaptureScreen(capture);
}
HandleCapture(); HandleCapture();
break; break;
case CaptureMode.Clipboard: case CaptureMode.Clipboard:
@ -279,19 +323,25 @@ namespace Greenshot.Helpers {
break; break;
case CaptureMode.LastRegion: case CaptureMode.LastRegion:
if (!RuntimeConfig.LastCapturedRegion.IsEmpty) { if (!RuntimeConfig.LastCapturedRegion.IsEmpty) {
capture = WindowCapture.CaptureScreen(capture); capture = WindowCapture.CaptureRectangle(capture, RuntimeConfig.LastCapturedRegion);
if (windowDetailsThread != null) { if (windowDetailsThread != null) {
windowDetailsThread.Join(); windowDetailsThread.Join();
} }
capture.Crop(RuntimeConfig.LastCapturedRegion);
capture.CaptureDetails.AddMetaData("source", "screen"); capture.CaptureDetails.AddMetaData("source", "screen");
HandleCapture(); HandleCapture();
} }
break; break;
case CaptureMode.Region: case CaptureMode.Region:
// Check if a region is pre-supplied!
if (Rectangle.Empty.Equals(captureRect)) {
capture = WindowCapture.CaptureScreen(capture); capture = WindowCapture.CaptureScreen(capture);
capture.CaptureDetails.AddMetaData("source", "screen"); capture.CaptureDetails.AddMetaData("source", "screen");
CaptureWithFeedback(); CaptureWithFeedback();
} else {
capture = WindowCapture.CaptureRectangle(capture, captureRect);
capture.CaptureDetails.AddMetaData("source", "screen");
HandleCapture();
}
break; break;
case CaptureMode.Video: case CaptureMode.Video:
capture = WindowCapture.CaptureScreen(capture); capture = WindowCapture.CaptureScreen(capture);

View file

@ -71,7 +71,11 @@ namespace GreenshotPlugin.Core {
public bool CaptureWindowsInteractive; public bool CaptureWindowsInteractive;
[IniProperty("CaptureDelay", Description="Capture delay in millseconds.", DefaultValue="100")] [IniProperty("CaptureDelay", Description="Capture delay in millseconds.", DefaultValue="100")]
public int CaptureDelay; 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; 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")] [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; public bool WindowCaptureAllChildLocations;

View file

@ -98,20 +98,20 @@ namespace GreenshotPlugin.Core {
/// <param name="buffer"></param> /// <param name="buffer"></param>
/// <param name="colorPoint"></param> /// <param name="colorPoint"></param>
/// <returns></returns> /// <returns></returns>
private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) { private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint, int cropDifference) {
Rectangle cropRectangle = Rectangle.Empty; Rectangle cropRectangle = Rectangle.Empty;
Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y); Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y);
Point min = new Point(int.MaxValue, int.MaxValue); Point min = new Point(int.MaxValue, int.MaxValue);
Point max = new Point(int.MinValue, int.MinValue); 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 y = 0; y < buffer.Height; y++) {
for(int x = 0; x < buffer.Width; x++) { for(int x = 0; x < buffer.Width; x++) {
Color currentColor = buffer.GetColorAt(x, y); Color currentColor = buffer.GetColorAt(x, y);
int diffR = Math.Abs(currentColor.R - referenceColor.R); int diffR = Math.Abs(currentColor.R - referenceColor.R);
int diffG = Math.Abs(currentColor.G - referenceColor.G); int diffG = Math.Abs(currentColor.G - referenceColor.G);
int diffB = Math.Abs(currentColor.B - referenceColor.B); 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 (x < min.X) min.X = x;
if (y < min.Y) min.Y = y; if (y < min.Y) min.Y = y;
if (x > max.X) max.X = x; if (x > max.X) max.X = x;
@ -140,12 +140,13 @@ namespace GreenshotPlugin.Core {
} }
return cropRectangle; return cropRectangle;
} }
/// <summary> /// <summary>
/// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0
/// </summary> /// </summary>
/// <param name="image"></param> /// <param name="image"></param>
/// <returns>Rectangle</returns> /// <returns>Rectangle</returns>
public static Rectangle FindAutoCropRectangle(Image image) { public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) {
Rectangle cropRectangle = Rectangle.Empty; Rectangle cropRectangle = Rectangle.Empty;
using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) { using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) {
buffer.Lock(); buffer.Lock();
@ -162,7 +163,7 @@ namespace GreenshotPlugin.Core {
// find biggest area // find biggest area
foreach(Point checkPoint in checkPoints) { foreach(Point checkPoint in checkPoints) {
currentRectangle = FindAutoCropRectangle(buffer, checkPoint); currentRectangle = FindAutoCropRectangle(buffer, checkPoint, cropDifference);
if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) {
cropRectangle = currentRectangle; cropRectangle = currentRectangle;
} }

View file

@ -27,6 +27,7 @@ namespace Greenshot.Plugin {
/// The capture mode for Greenshot /// The capture mode for Greenshot
/// </summary> /// </summary>
public enum CaptureMode { None, Region, FullScreen, ActiveWindow, Window, LastRegion, Clipboard, File, IE, Video, Import }; public enum CaptureMode { None, Region, FullScreen, ActiveWindow, Window, LastRegion, Clipboard, File, IE, Video, Import };
public enum ScreenCaptureMode { Auto, FullScreen, Fixed};
/// <summary> /// <summary>
/// Details for the capture, like the window title and date/time etc. /// Details for the capture, like the window title and date/time etc.