diff --git a/ShareX.HelpersLib/Helpers/ImageHelpers.cs b/ShareX.HelpersLib/Helpers/ImageHelpers.cs index 9d91eab57..bcd4f0b62 100644 --- a/ShareX.HelpersLib/Helpers/ImageHelpers.cs +++ b/ShareX.HelpersLib/Helpers/ImageHelpers.cs @@ -60,6 +60,7 @@ You should have received a copy of the GNU General Public License using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; @@ -1222,5 +1223,26 @@ public static Image LoadImage(string filePath) return null; } + + public static Image CombineImages(IEnumerable images, int space = 0) + { + int width = images.Sum(x => x.Width); + int height = images.Sum(x => x.Height); + Bitmap bmp = new Bitmap(width, height + (space * (images.Count() - 1))); + + using (Graphics g = Graphics.FromImage(bmp)) + { + g.SetHighQuality(); + int y = 0; + + foreach (Image image in images) + { + g.DrawImage(image, 0, y, image.Width, image.Height); + y += image.Height + space; + } + } + + return bmp; + } } } \ No newline at end of file diff --git a/ShareX.HelpersLib/Native/NativeEnums.cs b/ShareX.HelpersLib/Native/NativeEnums.cs index 662d96125..97aeeddb0 100644 --- a/ShareX.HelpersLib/Native/NativeEnums.cs +++ b/ShareX.HelpersLib/Native/NativeEnums.cs @@ -2815,4 +2815,22 @@ public enum ScrollBarCommands SB_RIGHT = 7, SB_ENDSCROLL = 8 } + + public enum SBOrientation : int + { + SB_HORZ = 0x0, + SB_VERT = 0x1, + SB_CTL = 0x2, + SB_BOTH = 0x3 + } + + public enum ScrollInfoMask : uint + { + SIF_RANGE = 0x1, + SIF_PAGE = 0x2, + SIF_POS = 0x4, + SIF_DISABLENOSCROLL = 0x8, + SIF_TRACKPOS = 0x10, + SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) + } } \ No newline at end of file diff --git a/ShareX.HelpersLib/Native/NativeMethods.cs b/ShareX.HelpersLib/Native/NativeMethods.cs index ad032e70e..69bbdf827 100644 --- a/ShareX.HelpersLib/Native/NativeMethods.cs +++ b/ShareX.HelpersLib/Native/NativeMethods.cs @@ -137,6 +137,10 @@ public static partial class NativeMethods [DllImport("user32.dll")] public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowConstants wCmd); + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi); + [DllImport("user32.dll")] public static extern int GetSystemMetrics(int smIndex); diff --git a/ShareX.HelpersLib/Native/NativeMethods_Helpers.cs b/ShareX.HelpersLib/Native/NativeMethods_Helpers.cs index b624e03fb..f58eb7807 100644 --- a/ShareX.HelpersLib/Native/NativeMethods_Helpers.cs +++ b/ShareX.HelpersLib/Native/NativeMethods_Helpers.cs @@ -475,5 +475,14 @@ public static bool FlashWindowEx(Form frm) return FlashWindowEx(ref fInfo); } + + public static bool IsScrollReachedBottom(IntPtr handle) + { + SCROLLINFO scrollInfo = new SCROLLINFO(); + scrollInfo.cbSize = (uint)Marshal.SizeOf(scrollInfo); + scrollInfo.fMask = (uint)(ScrollInfoMask.SIF_RANGE | ScrollInfoMask.SIF_PAGE | ScrollInfoMask.SIF_TRACKPOS); + NativeMethods.GetScrollInfo(handle, (int)SBOrientation.SB_VERT, ref scrollInfo); + return scrollInfo.nMax == scrollInfo.nTrackPos + scrollInfo.nPage - 1; + } } } \ No newline at end of file diff --git a/ShareX.HelpersLib/Native/NativeStructs.cs b/ShareX.HelpersLib/Native/NativeStructs.cs index 53a2a6632..258bff55e 100644 --- a/ShareX.HelpersLib/Native/NativeStructs.cs +++ b/ShareX.HelpersLib/Native/NativeStructs.cs @@ -609,4 +609,16 @@ public struct FLASHWINFO public UInt32 uCount; public UInt32 dwTimeout; } + + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct SCROLLINFO + { + public uint cbSize; + public uint fMask; + public int nMin; + public int nMax; + public uint nPage; + public int nPos; + public int nTrackPos; + } } \ No newline at end of file diff --git a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs index 089ce88ef..ecf4ddcb1 100644 --- a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs +++ b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.Designer.cs @@ -7,19 +7,6 @@ partial class ScrollingCaptureForm /// private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - #region Windows Form Designer generated code /// @@ -37,13 +24,23 @@ private void InitializeComponent() this.nudMaximumScrollCount = new System.Windows.Forms.NumericUpDown(); this.lblScrollDelay = new System.Windows.Forms.Label(); this.lblMaximumScrollCount = new System.Windows.Forms.Label(); + this.tcScrollingCapture = new System.Windows.Forms.TabControl(); + this.tpCapture = new System.Windows.Forms.TabPage(); + this.tpOutput = new System.Windows.Forms.TabPage(); + this.pbOutput = new System.Windows.Forms.PictureBox(); + this.pOutput = new System.Windows.Forms.Panel(); ((System.ComponentModel.ISupportInitialize)(this.nudScrollDelay)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nudMaximumScrollCount)).BeginInit(); + this.tcScrollingCapture.SuspendLayout(); + this.tpCapture.SuspendLayout(); + this.tpOutput.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbOutput)).BeginInit(); + this.pOutput.SuspendLayout(); this.SuspendLayout(); // // btnSelectHandle // - this.btnSelectHandle.Location = new System.Drawing.Point(8, 8); + this.btnSelectHandle.Location = new System.Drawing.Point(12, 10); this.btnSelectHandle.Name = "btnSelectHandle"; this.btnSelectHandle.Size = new System.Drawing.Size(304, 23); this.btnSelectHandle.TabIndex = 0; @@ -53,7 +50,7 @@ private void InitializeComponent() // // lblControlText // - this.lblControlText.Location = new System.Drawing.Point(320, 13); + this.lblControlText.Location = new System.Drawing.Point(324, 15); this.lblControlText.Name = "lblControlText"; this.lblControlText.Size = new System.Drawing.Size(240, 19); this.lblControlText.TabIndex = 1; @@ -62,7 +59,7 @@ private void InitializeComponent() // btnCapture // this.btnCapture.Enabled = false; - this.btnCapture.Location = new System.Drawing.Point(8, 104); + this.btnCapture.Location = new System.Drawing.Point(12, 106); this.btnCapture.Name = "btnCapture"; this.btnCapture.Size = new System.Drawing.Size(152, 23); this.btnCapture.TabIndex = 2; @@ -76,7 +73,7 @@ private void InitializeComponent() // // nudScrollDelay // - this.nudScrollDelay.Location = new System.Drawing.Point(136, 44); + this.nudScrollDelay.Location = new System.Drawing.Point(140, 46); this.nudScrollDelay.Maximum = new decimal(new int[] { 5000, 0, @@ -90,7 +87,7 @@ private void InitializeComponent() // // nudMaximumScrollCount // - this.nudMaximumScrollCount.Location = new System.Drawing.Point(136, 68); + this.nudMaximumScrollCount.Location = new System.Drawing.Point(140, 70); this.nudMaximumScrollCount.Name = "nudMaximumScrollCount"; this.nudMaximumScrollCount.Size = new System.Drawing.Size(80, 20); this.nudMaximumScrollCount.TabIndex = 4; @@ -100,7 +97,7 @@ private void InitializeComponent() // lblScrollDelay // this.lblScrollDelay.AutoSize = true; - this.lblScrollDelay.Location = new System.Drawing.Point(8, 48); + this.lblScrollDelay.Location = new System.Drawing.Point(12, 50); this.lblScrollDelay.Name = "lblScrollDelay"; this.lblScrollDelay.Size = new System.Drawing.Size(64, 13); this.lblScrollDelay.TabIndex = 5; @@ -109,31 +106,91 @@ private void InitializeComponent() // lblMaximumScrollCount // this.lblMaximumScrollCount.AutoSize = true; - this.lblMaximumScrollCount.Location = new System.Drawing.Point(8, 72); + this.lblMaximumScrollCount.Location = new System.Drawing.Point(12, 74); this.lblMaximumScrollCount.Name = "lblMaximumScrollCount"; this.lblMaximumScrollCount.Size = new System.Drawing.Size(111, 13); this.lblMaximumScrollCount.TabIndex = 6; this.lblMaximumScrollCount.Text = "Maximum scroll count:"; // + // tcScrollingCapture + // + this.tcScrollingCapture.Controls.Add(this.tpCapture); + this.tcScrollingCapture.Controls.Add(this.tpOutput); + this.tcScrollingCapture.Dock = System.Windows.Forms.DockStyle.Fill; + this.tcScrollingCapture.Location = new System.Drawing.Point(0, 0); + this.tcScrollingCapture.Name = "tcScrollingCapture"; + this.tcScrollingCapture.SelectedIndex = 0; + this.tcScrollingCapture.Size = new System.Drawing.Size(567, 427); + this.tcScrollingCapture.TabIndex = 7; + // + // tpCapture + // + this.tpCapture.Controls.Add(this.btnSelectHandle); + this.tpCapture.Controls.Add(this.lblMaximumScrollCount); + this.tpCapture.Controls.Add(this.lblControlText); + this.tpCapture.Controls.Add(this.lblScrollDelay); + this.tpCapture.Controls.Add(this.btnCapture); + this.tpCapture.Controls.Add(this.nudMaximumScrollCount); + this.tpCapture.Controls.Add(this.nudScrollDelay); + this.tpCapture.Location = new System.Drawing.Point(4, 22); + this.tpCapture.Name = "tpCapture"; + this.tpCapture.Padding = new System.Windows.Forms.Padding(3); + this.tpCapture.Size = new System.Drawing.Size(559, 401); + this.tpCapture.TabIndex = 0; + this.tpCapture.Text = "Capture"; + this.tpCapture.UseVisualStyleBackColor = true; + // + // tpOutput + // + this.tpOutput.Controls.Add(this.pOutput); + this.tpOutput.Location = new System.Drawing.Point(4, 22); + this.tpOutput.Name = "tpOutput"; + this.tpOutput.Padding = new System.Windows.Forms.Padding(3); + this.tpOutput.Size = new System.Drawing.Size(559, 401); + this.tpOutput.TabIndex = 1; + this.tpOutput.Text = "Output"; + this.tpOutput.UseVisualStyleBackColor = true; + // + // pbOutput + // + this.pbOutput.Location = new System.Drawing.Point(0, 0); + this.pbOutput.Name = "pbOutput"; + this.pbOutput.Size = new System.Drawing.Size(100, 100); + this.pbOutput.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; + this.pbOutput.TabIndex = 0; + this.pbOutput.TabStop = false; + // + // pOutput + // + this.pOutput.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.pOutput.AutoScroll = true; + this.pOutput.Controls.Add(this.pbOutput); + this.pOutput.Location = new System.Drawing.Point(8, 8); + this.pOutput.Name = "pOutput"; + this.pOutput.Size = new System.Drawing.Size(544, 384); + this.pOutput.TabIndex = 1; + // // ScrollingCaptureForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(567, 427); - this.Controls.Add(this.lblMaximumScrollCount); - this.Controls.Add(this.lblScrollDelay); - this.Controls.Add(this.nudMaximumScrollCount); - this.Controls.Add(this.nudScrollDelay); - this.Controls.Add(this.btnCapture); - this.Controls.Add(this.lblControlText); - this.Controls.Add(this.btnSelectHandle); + this.Controls.Add(this.tcScrollingCapture); this.Name = "ScrollingCaptureForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "ShareX - Scrolling capture"; ((System.ComponentModel.ISupportInitialize)(this.nudScrollDelay)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nudMaximumScrollCount)).EndInit(); + this.tcScrollingCapture.ResumeLayout(false); + this.tpCapture.ResumeLayout(false); + this.tpCapture.PerformLayout(); + this.tpOutput.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pbOutput)).EndInit(); + this.pOutput.ResumeLayout(false); + this.pOutput.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } @@ -147,5 +204,10 @@ private void InitializeComponent() private System.Windows.Forms.NumericUpDown nudMaximumScrollCount; private System.Windows.Forms.Label lblScrollDelay; private System.Windows.Forms.Label lblMaximumScrollCount; + private System.Windows.Forms.TabControl tcScrollingCapture; + private System.Windows.Forms.TabPage tpCapture; + private System.Windows.Forms.TabPage tpOutput; + private System.Windows.Forms.Panel pOutput; + private System.Windows.Forms.PictureBox pbOutput; } } \ No newline at end of file diff --git a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs index d17dfdd50..85cfafd53 100644 --- a/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs +++ b/ShareX.ScreenCaptureLib/Forms/ScrollingCaptureForm.cs @@ -30,6 +30,7 @@ You should have received a copy of the GNU General Public License using System.Data; using System.Drawing; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; @@ -42,6 +43,7 @@ public partial class ScrollingCaptureForm : BaseForm private WindowInfo selectedWindow; private int currentScrollCount; + private List images = new List(); public ScrollingCaptureForm(ScrollingCaptureOptions options) { @@ -51,6 +53,21 @@ public ScrollingCaptureForm(ScrollingCaptureOptions options) nudMaximumScrollCount.Value = Options.MaximumScrollCount; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (components != null) + { + components.Dispose(); + } + + Clean(); + } + + base.Dispose(disposing); + } + private void btnSelectHandle_Click(object sender, EventArgs e) { Hide(); @@ -109,7 +126,7 @@ private SimpleWindowInfo GetWindowInfo() private void StartCapture() { btnCapture.Enabled = false; - currentScrollCount = 0; + Clean(); selectedWindow.Activate(); captureTimer.Interval = Options.ScrollDelay; captureTimer.Start(); @@ -119,18 +136,46 @@ private void StopCapture() { captureTimer.Stop(); btnCapture.Enabled = true; + this.ShowActivate(); + tcScrollingCapture.SelectedTab = tpOutput; + pbOutput.Image = ImageHelpers.CombineImages(images); + } + + private void Clean() + { + currentScrollCount = 0; + + if (images != null) + { + foreach (Image image in images) + { + if (image != null) + { + image.Dispose(); + } + } + + images.Clear(); + } } private void captureTimer_Tick(object sender, EventArgs e) { - NativeMethods.SendMessage(selectedWindow.Handle, (int)WindowsMessages.VSCROLL, (int)ScrollBarCommands.SB_PAGEDOWN, 0); + Image image = Screenshot.CaptureRectangle(selectedWindow.Rectangle); + + if (image != null) + { + images.Add(image); + } currentScrollCount++; - if (currentScrollCount == Options.MaximumScrollCount) + if (currentScrollCount == Options.MaximumScrollCount || NativeMethods.IsScrollReachedBottom(selectedWindow.Handle)) { StopCapture(); } + + NativeMethods.SendMessage(selectedWindow.Handle, (int)WindowsMessages.VSCROLL, (int)ScrollBarCommands.SB_PAGEDOWN, 0); } private void nudScrollDelay_ValueChanged(object sender, EventArgs e)