From 022853ef4da49b5392c0ecbdb8cc70b9e38f25c7 Mon Sep 17 00:00:00 2001 From: Jaex Date: Sat, 26 Sep 2015 03:42:43 +0300 Subject: [PATCH] Added guess trim edges and guess combine adjustments so scrolling capture can automatically combine without user interaction --- .../Forms/ScrollingCaptureForm.Designer.cs | 75 ++++-- .../Forms/ScrollingCaptureForm.cs | 251 ++++++++++++++++-- 2 files changed, 279 insertions(+), 47 deletions(-) diff --git a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs index 815bbeed1..4d565217b 100644 --- a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs +++ b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs @@ -34,7 +34,8 @@ private void InitializeComponent() this.tcScrollingCapture = new System.Windows.Forms.TabControl(); this.tpCapture = new System.Windows.Forms.TabPage(); this.tpOutput = new System.Windows.Forms.TabPage(); - this.btnGuessSettings = new System.Windows.Forms.Button(); + this.btnProcess = new System.Windows.Forms.Button(); + this.btnGuessEdges = new System.Windows.Forms.Button(); this.btnCombine = new System.Windows.Forms.Button(); this.gbCombineAdjustments = new System.Windows.Forms.GroupBox(); this.lblCombineLastVertical = new System.Windows.Forms.Label(); @@ -52,7 +53,8 @@ private void InitializeComponent() this.nudTrimRight = new System.Windows.Forms.NumericUpDown(); this.pOutput = new System.Windows.Forms.Panel(); this.pbOutput = new System.Windows.Forms.PictureBox(); - this.btnProcess = new System.Windows.Forms.Button(); + this.btnGuessCombineAdjustments = new System.Windows.Forms.Button(); + this.btnResetCombine = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.nudScrollDelay)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nudMaximumScrollCount)).BeginInit(); this.tcScrollingCapture.SuspendLayout(); @@ -174,8 +176,10 @@ private void InitializeComponent() // // tpOutput // + this.tpOutput.Controls.Add(this.btnResetCombine); + this.tpOutput.Controls.Add(this.btnGuessCombineAdjustments); this.tpOutput.Controls.Add(this.btnProcess); - this.tpOutput.Controls.Add(this.btnGuessSettings); + this.tpOutput.Controls.Add(this.btnGuessEdges); this.tpOutput.Controls.Add(this.btnCombine); this.tpOutput.Controls.Add(this.gbCombineAdjustments); this.tpOutput.Controls.Add(this.gbTrimEdges); @@ -188,23 +192,35 @@ private void InitializeComponent() this.tpOutput.Text = "Output"; this.tpOutput.UseVisualStyleBackColor = true; // - // btnGuessSettings + // btnProcess // - this.btnGuessSettings.Location = new System.Drawing.Point(312, 16); - this.btnGuessSettings.Name = "btnGuessSettings"; - this.btnGuessSettings.Size = new System.Drawing.Size(168, 23); - this.btnGuessSettings.TabIndex = 8; - this.btnGuessSettings.Text = "1. Guess settings"; - this.btnGuessSettings.UseVisualStyleBackColor = true; - this.btnGuessSettings.Click += new System.EventHandler(this.btnGuessSettings_Click); + this.btnProcess.Location = new System.Drawing.Point(312, 88); + this.btnProcess.Name = "btnProcess"; + this.btnProcess.Size = new System.Drawing.Size(376, 23); + this.btnProcess.TabIndex = 9; + this.btnProcess.Text = "4. Upload/save depending on after capture settings"; + this.btnProcess.UseVisualStyleBackColor = true; + this.btnProcess.Click += new System.EventHandler(this.btnProcess_Click); + // + // btnGuessEdges + // + this.btnGuessEdges.Enabled = false; + this.btnGuessEdges.Location = new System.Drawing.Point(312, 16); + this.btnGuessEdges.Name = "btnGuessEdges"; + this.btnGuessEdges.Size = new System.Drawing.Size(376, 23); + this.btnGuessEdges.TabIndex = 8; + this.btnGuessEdges.Text = "1. Guess edge values to trim"; + this.btnGuessEdges.UseVisualStyleBackColor = true; + this.btnGuessEdges.Click += new System.EventHandler(this.btnGuessEdges_Click); // // btnCombine // - this.btnCombine.Location = new System.Drawing.Point(312, 48); + this.btnCombine.Enabled = false; + this.btnCombine.Location = new System.Drawing.Point(312, 64); this.btnCombine.Name = "btnCombine"; - this.btnCombine.Size = new System.Drawing.Size(168, 23); + this.btnCombine.Size = new System.Drawing.Size(376, 23); this.btnCombine.TabIndex = 8; - this.btnCombine.Text = "2. Combine images"; + this.btnCombine.Text = "3. Combine images using these settings"; this.btnCombine.UseVisualStyleBackColor = true; this.btnCombine.Click += new System.EventHandler(this.btnCombine_Click); // @@ -397,15 +413,26 @@ private void InitializeComponent() this.pbOutput.TabIndex = 0; this.pbOutput.TabStop = false; // - // btnProcess + // btnGuessCombineAdjustments // - this.btnProcess.Location = new System.Drawing.Point(312, 80); - this.btnProcess.Name = "btnProcess"; - this.btnProcess.Size = new System.Drawing.Size(168, 23); - this.btnProcess.TabIndex = 9; - this.btnProcess.Text = "3. Upload/Save"; - this.btnProcess.UseVisualStyleBackColor = true; - this.btnProcess.Click += new System.EventHandler(this.btnProcess_Click); + this.btnGuessCombineAdjustments.Enabled = false; + this.btnGuessCombineAdjustments.Location = new System.Drawing.Point(312, 40); + this.btnGuessCombineAdjustments.Name = "btnGuessCombineAdjustments"; + this.btnGuessCombineAdjustments.Size = new System.Drawing.Size(376, 23); + this.btnGuessCombineAdjustments.TabIndex = 10; + this.btnGuessCombineAdjustments.Text = "2. Guess combine adjustments"; + this.btnGuessCombineAdjustments.UseVisualStyleBackColor = true; + this.btnGuessCombineAdjustments.Click += new System.EventHandler(this.btnGuessCombineAdjustments_Click); + // + // btnResetCombine + // + this.btnResetCombine.Location = new System.Drawing.Point(696, 16); + this.btnResetCombine.Name = "btnResetCombine"; + this.btnResetCombine.Size = new System.Drawing.Size(75, 23); + this.btnResetCombine.TabIndex = 11; + this.btnResetCombine.Text = "Reset"; + this.btnResetCombine.UseVisualStyleBackColor = true; + this.btnResetCombine.Click += new System.EventHandler(this.btnResetCombine_Click); // // ScrollingCaptureForm // @@ -469,7 +496,9 @@ private void InitializeComponent() private NumericUpDown nudTrimRight; private Button btnCombine; private Label lblCombineLastVertical; - private Button btnGuessSettings; + private Button btnGuessEdges; private Button btnProcess; + private Button btnGuessCombineAdjustments; + private Button btnResetCombine; } } \ No newline at end of file diff --git a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs index e86ad7b4b..8f003ae6b 100644 --- a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs +++ b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs @@ -29,6 +29,7 @@ You should have received a copy of the GNU General Public License using System.ComponentModel; using System.Data; using System.Drawing; +using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -45,8 +46,9 @@ public partial class ScrollingCaptureForm : BaseForm public Image Result { get; set; } private WindowInfo selectedWindow; - private int currentScrollCount; private List images = new List(); + private int currentScrollCount; + private bool isBusy; public ScrollingCaptureForm(ScrollingCaptureOptions options) { @@ -71,6 +73,14 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + protected void OnProcessRequested(Image image) + { + if (ProcessRequested != null) + { + ProcessRequested(image); + } + } + private void btnSelectHandle_Click(object sender, EventArgs e) { Hide(); @@ -141,8 +151,8 @@ private void StopCapture() btnCapture.Enabled = true; this.ShowActivate(); tcScrollingCapture.SelectedTab = tpOutput; - if (pbOutput.Image != null) pbOutput.Image.Dispose(); - pbOutput.Image = ImageHelpers.CombineImages(images); + btnGuessEdges.Enabled = btnGuessCombineAdjustments.Enabled = btnCombine.Enabled = images.Count > 1; + ResetCombine(); } private void Clean() @@ -257,8 +267,14 @@ private void nudCombineLastVertical_ValueChanged(object sender, EventArgs e) CombineAndPreviewImages(); } - private void btnGuessSettings_Click(object sender, EventArgs e) + private void btnGuessEdges_Click(object sender, EventArgs e) { + GuessEdges(); + } + + private void btnGuessCombineAdjustments_Click(object sender, EventArgs e) + { + GuessCombineAdjustments(); } private void btnCombine_Click(object sender, EventArgs e) @@ -271,11 +287,25 @@ private void btnProcess_Click(object sender, EventArgs e) OnProcessRequested((Image)Result.Clone()); } + private void btnResetCombine_Click(object sender, EventArgs e) + { + ResetCombine(); + } + + private void ResetCombine() + { + nudTrimLeft.Value = nudTrimTop.Value = nudTrimRight.Value = nudTrimBottom.Value = nudCombineVertical.Value = nudCombineLastVertical.Value = 0; + CombineAndPreviewImages(); + } + private void CombineAndPreviewImages() { - if (pbOutput.Image != null) pbOutput.Image.Dispose(); - Result = CombineImages(); - pbOutput.Image = Result; + if (!isBusy) + { + if (pbOutput.Image != null) pbOutput.Image.Dispose(); + Result = CombineImages(); + pbOutput.Image = Result; + } } private Image CombineImages() @@ -294,23 +324,28 @@ private Image CombineImages() for (int i = 0; i < images.Count; i++) { + Image newImage = null; Image image = images[i]; - Rectangle rect = new Rectangle(Options.TrimLeftEdge, Options.TrimTopEdge, image.Width - Options.TrimLeftEdge - Options.TrimRightEdge, - image.Height - Options.TrimTopEdge - Options.TrimBottomEdge); - - if (i == images.Count - 1) + if (Options.TrimLeftEdge > 0 || Options.TrimTopEdge > 0 || Options.TrimTopEdge > 0 || Options.TrimBottomEdge > 0 || + Options.CombineAdjustmentVertical > 0 || Options.CombineAdjustmentLastVertical > 0) { - rect.Y += Options.CombineAdjustmentLastVertical; - rect.Height -= Options.CombineAdjustmentLastVertical; - } - else if (i > 0) - { - rect.Y += Options.CombineAdjustmentVertical; - rect.Height -= Options.CombineAdjustmentVertical; - } + Rectangle rect = new Rectangle(Options.TrimLeftEdge, Options.TrimTopEdge, image.Width - Options.TrimLeftEdge - Options.TrimRightEdge, + image.Height - Options.TrimTopEdge - Options.TrimBottomEdge); - Image newImage = ImageHelpers.CropImage(image, rect); + if (i == images.Count - 1) + { + rect.Y += Options.CombineAdjustmentLastVertical; + rect.Height -= Options.CombineAdjustmentLastVertical; + } + else if (i > 0) + { + rect.Y += Options.CombineAdjustmentVertical; + rect.Height -= Options.CombineAdjustmentVertical; + } + + newImage = ImageHelpers.CropImage(image, rect); + } if (newImage == null) { @@ -320,15 +355,183 @@ private Image CombineImages() output.Add(newImage); } - return ImageHelpers.CombineImages(output); + Image result = ImageHelpers.CombineImages(output); + + foreach (Image image in output) + { + if (image != null) + { + image.Dispose(); + } + } + + output.Clear(); + + return result; } - protected void OnProcessRequested(Image image) + private void GuessEdges() { - if (ProcessRequested != null) + if (images.Count < 2) return; + + isBusy = true; + + nudTrimLeft.Value = nudTrimTop.Value = nudTrimRight.Value = nudTrimBottom.Value = 0; + + Rectangle rect = new Rectangle(0, 0, images[0].Width, images[0].Height); + + using (UnsafeBitmap bmp1 = new UnsafeBitmap((Bitmap)images[0], true, ImageLockMode.ReadOnly)) + using (UnsafeBitmap bmp2 = new UnsafeBitmap((Bitmap)images[1], true, ImageLockMode.ReadOnly)) { - ProcessRequested(image); + bool valueFound = false; + + // Left edge + for (int x = rect.X; !valueFound && x < rect.Width; x++) + { + for (int y = rect.Y; y < rect.Height; y++) + { + if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y)) + { + valueFound = true; + nudTrimLeft.Value = x; + rect.X = x; + break; + } + } + } + + valueFound = false; + + // Top edge + for (int y = rect.Y; !valueFound && y < rect.Height; y++) + { + for (int x = rect.X; x < rect.Width; x++) + { + if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y)) + { + valueFound = true; + nudTrimTop.Value = y; + rect.Y = y; + break; + } + } + } + + valueFound = false; + + // Right edge + for (int x = rect.Width - 1; !valueFound && x >= rect.X; x--) + { + for (int y = rect.Y; y < rect.Height; y++) + { + if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y)) + { + valueFound = true; + nudTrimRight.Value = rect.Width - x - 1; + rect.Width = x + 1; + break; + } + } + } + + valueFound = false; + + // Bottom edge + for (int y = rect.Height - 1; !valueFound && y >= rect.X; y--) + { + for (int x = rect.X; x < rect.Width; x++) + { + if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y)) + { + valueFound = true; + nudTrimBottom.Value = rect.Height - y - 1; + rect.Height = y + 1; + break; + } + } + } } + + isBusy = false; + } + + private void GuessCombineAdjustments() + { + if (images.Count > 1) + { + isBusy = true; + + nudCombineVertical.Value = CalculateVerticalOffset(images[0], images[1]); + + if (images.Count > 2) + { + nudCombineLastVertical.Value = CalculateVerticalOffset(images[images.Count - 2], images[images.Count - 1]); + } + + isBusy = false; + } + } + + private int CalculateVerticalOffset(Image img1, Image img2, int ignoreRightOffset = 50, int matchCount = 5) + { + Rectangle rect = new Rectangle(Options.TrimLeftEdge, Options.TrimTopEdge, + img1.Width - Options.TrimLeftEdge - Options.TrimRightEdge - (img1.Width > ignoreRightOffset ? ignoreRightOffset : 0), + img1.Height - Options.TrimTopEdge - Options.TrimBottomEdge); + + using (UnsafeBitmap bmp1 = new UnsafeBitmap((Bitmap)img1, true, ImageLockMode.ReadOnly)) + using (UnsafeBitmap bmp2 = new UnsafeBitmap((Bitmap)img2, true, ImageLockMode.ReadOnly)) + { + for (int y = rect.Y; y < rect.Height; y++) + { + bool isLineMatches = true; + + for (int x = rect.X; x < rect.Width; x++) + { + if (bmp2.GetPixel(x, y) != bmp1.GetPixel(x, rect.Height - 1)) + { + isLineMatches = false; + break; + } + } + + if (isLineMatches) + { + int lineMatchesCount = 0; + int y3 = 2; + + for (int y2 = y - 1; y2 >= rect.Y; y2--) + { + bool isLineMatches2 = true; + + for (int x2 = rect.X; x2 < rect.Width; x2++) + { + if (bmp2.GetPixel(x2, y2) != bmp1.GetPixel(x2, rect.Height - y3)) + { + isLineMatches2 = false; + break; + } + } + + if (isLineMatches2) + { + lineMatchesCount++; + y3++; + } + else + { + break; + } + + if (lineMatchesCount == matchCount || y2 == rect.Y) + { + return y; + } + } + } + } + } + + return 0; } } } \ No newline at end of file