Rebranding

This commit is contained in:
Jared Goodwin 2019-02-27 21:21:53 -08:00
parent fe5dbc23e1
commit b3f03a8b56
9 changed files with 134 additions and 279 deletions

View File

@ -62,9 +62,6 @@ namespace Remotely_ScreenCast.Capture
PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
graphic = Graphics.FromImage(CurrentFrame);
desktopName = Win32Interop.GetCurrentDesktop();
Debug.WriteLine($"Starting BitBltCapture.");
Debug.WriteLine($"Current Desktop: {desktopName}");
}
public void Capture()
@ -97,12 +94,5 @@ namespace Remotely_ScreenCast.Capture
Logger.Write(ex);
}
}
public Point GetAbsoluteScreenCoordinatesFromPercentages(decimal percentX, decimal percentY)
{
var absoluteX = (CurrentScreenBounds.Width * percentX) + CurrentScreenBounds.Left;
var absoluteY = (CurrentScreenBounds.Height * percentY) + CurrentScreenBounds.Top;
return new Point((int)absoluteX, (int)absoluteY);
}
}
}

View File

@ -119,10 +119,6 @@ namespace Remotely_ScreenCast.Capture
};
screenTexture = new Texture2D(device, textureDesc);
duplicatedOutput = output1.DuplicateOutput(device);
Debug.WriteLine($"Starting DXCapture.");
Debug.WriteLine($"Current Desktop: {desktopName}");
}
public void Capture()
{
@ -216,12 +212,5 @@ namespace Remotely_ScreenCast.Capture
Capture();
}
}
public Point GetAbsoluteScreenCoordinatesFromPercentages(decimal percentX, decimal percentY)
{
var absoluteX = (CurrentScreenBounds.Width * percentX) + CurrentScreenBounds.Left;
var absoluteY = (CurrentScreenBounds.Height * percentY) + CurrentScreenBounds.Top;
return new Point((int)absoluteX, (int)absoluteY);
}
}
}

View File

@ -16,7 +16,5 @@ namespace Remotely_ScreenCast.Capture
void Capture();
EventHandler<Rectangle> ScreenChanged { get; set; }
int SelectedScreen { get; set; }
Point GetAbsoluteScreenCoordinatesFromPercentages(decimal percentX, decimal percentY);
}
}

View File

@ -14,16 +14,9 @@ namespace Remotely_ScreenCast.Capture
public class ImageDiff
{
private static BitmapData bd1;
private static BitmapData bd2;
private static BitmapData bd3;
private static Bitmap mergedFrame;
private static byte[] rgbValues1;
private static byte[] rgbValues2;
private static byte[] rgbValues3;
public static Bitmap GetImageDiff(Bitmap currentFrame, Bitmap previousFrame, bool captureFullscreen)
{
if (currentFrame.Height != previousFrame.Height || currentFrame.Width != previousFrame.Width)
{
throw new Exception("Bitmaps are not of equal dimensions.");
@ -36,11 +29,11 @@ namespace Remotely_ScreenCast.Capture
var width = currentFrame.Width;
var height = currentFrame.Height;
mergedFrame = new Bitmap(width, height);
var mergedFrame = new Bitmap(width, height);
bd1 = previousFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, currentFrame.PixelFormat);
bd2 = currentFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat);
bd3 = mergedFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, currentFrame.PixelFormat);
var bd1 = previousFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, currentFrame.PixelFormat);
var bd2 = currentFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat);
var bd3 = mergedFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, currentFrame.PixelFormat);
// Get the address of the first line.
@ -50,9 +43,9 @@ namespace Remotely_ScreenCast.Capture
// Declare an array to hold the bytes of the bitmap.
int arraySize = Math.Abs(bd1.Stride) * currentFrame.Height;
rgbValues1 = new byte[arraySize];
rgbValues2 = new byte[arraySize];
rgbValues3 = new byte[arraySize];
var rgbValues1 = new byte[arraySize];
var rgbValues2 = new byte[arraySize];
var rgbValues3 = new byte[arraySize];
// Copy the RGBA values into the array.
Marshal.Copy(ptr1, rgbValues1, 0, arraySize);
@ -89,7 +82,7 @@ namespace Remotely_ScreenCast.Capture
currentFrame.UnlockBits(bd2);
mergedFrame.UnlockBits(bd3);
return mergedFrame;
return mergedFrame;
}
public static byte[] EncodeBitmap(Bitmap bitmap)
@ -101,152 +94,5 @@ namespace Remotely_ScreenCast.Capture
return ms.ToArray();
}
}
public byte[] GetDiffImage(Rectangle imageArea, Bitmap CurrentFrame)
{
using (var ms = new MemoryStream())
{
using (var croppedFrame = CurrentFrame.Clone(imageArea, PixelFormat.Format24bppRgb))
{
var encoderParams = new EncoderParameters(1);
encoderParams.Param = new EncoderParameter[] { new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 1) };
croppedFrame.Save(ms, ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Png.Guid), encoderParams);
// Byte array that indicates top left coordinates of the image.
byte[] header;
using (var headerStream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(headerStream, new Point(imageArea.X, imageArea.Y));
header = headerStream.ToArray();
}
return header.Concat(ms.ToArray()).ToArray();
}
}
}
public Rectangle GetDiffArea(Bitmap previousFrame, Bitmap currentFrame, bool captureFullscreen)
{
if (captureFullscreen)
{
captureFullscreen = false;
return new Rectangle(0, 0, currentFrame.Width, currentFrame.Height);
}
if (currentFrame.Height != previousFrame.Height || currentFrame.Width != previousFrame.Width)
{
throw new Exception("Bitmaps are not of equal dimensions.");
}
if (!Bitmap.IsAlphaPixelFormat(currentFrame.PixelFormat) || !Bitmap.IsAlphaPixelFormat(previousFrame.PixelFormat) ||
!Bitmap.IsCanonicalPixelFormat(currentFrame.PixelFormat) || !Bitmap.IsCanonicalPixelFormat(previousFrame.PixelFormat))
{
throw new Exception("Bitmaps must be 32 bits per pixel and contain alpha channel.");
}
var width = currentFrame.Width;
var height = currentFrame.Height;
var left = int.MaxValue;
var top = int.MaxValue;
var right = int.MinValue;
var bottom = int.MinValue;
try
{
bd1 = currentFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, currentFrame.PixelFormat);
}
catch
{
try
{
currentFrame.UnlockBits(bd1);
bd1 = currentFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, currentFrame.PixelFormat);
}
catch
{
return Rectangle.Empty;
}
}
try
{
bd2 = previousFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat);
}
catch
{
try
{
previousFrame.UnlockBits(bd2);
bd2 = previousFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat);
}
catch
{
return Rectangle.Empty;
}
}
// Get the address of the first line.
IntPtr ptr1 = bd1.Scan0;
IntPtr ptr2 = bd2.Scan0;
// Declare an array to hold the bytes of the bitmap.
int arraySize = Math.Abs(bd1.Stride) * currentFrame.Height;
rgbValues1 = new byte[arraySize];
rgbValues2 = new byte[arraySize];
// Copy the RGBA values into the array.
Marshal.Copy(ptr1, rgbValues1, 0, arraySize);
Marshal.Copy(ptr2, rgbValues2, 0, arraySize);
// Check RGBA value for each pixel.
for (int counter = 0; counter < rgbValues1.Length - 4; counter += 4)
{
if (rgbValues1[counter] != rgbValues2[counter] ||
rgbValues1[counter + 1] != rgbValues2[counter + 1] ||
rgbValues1[counter + 2] != rgbValues2[counter + 2] ||
rgbValues1[counter + 3] != rgbValues2[counter + 3])
{
// Change was found.
var pixel = counter / 4;
var row = (int)Math.Floor((double)pixel / bd1.Width);
var column = pixel % bd1.Width;
if (row < top)
{
top = row;
}
if (row > bottom)
{
bottom = row;
}
if (column < left)
{
left = column;
}
if (column > right)
{
right = column;
}
}
}
if (left < right && top < bottom)
{
// Bounding box is valid.
left = Math.Max(left - 20, 0);
top = Math.Max(top - 20, 0);
right = Math.Min(right + 20, currentFrame.Width);
bottom = Math.Min(bottom + 20, currentFrame.Height);
currentFrame.UnlockBits(bd1);
previousFrame.UnlockBits(bd2);
return new Rectangle(left, top, right - left, bottom - top);
}
else
{
currentFrame.UnlockBits(bd1);
previousFrame.UnlockBits(bd2);
return Rectangle.Empty;
}
}
}
}

View File

@ -0,0 +1,119 @@
using Microsoft.AspNetCore.SignalR.Client;
using Remotely_ScreenCast.Sockets;
using Remotely_ScreenCast.Utilities;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Remotely_ScreenCast.Capture
{
public class ScreenCaster
{
private static object CaptureLock { get; } = new object();
public static async void BeginScreenCasting(HubConnection hubConnection,
string viewerID,
string requesterName,
OutgoingMessages outgoingMessages)
{
ICapturer capturer;
CaptureMode captureMode;
try
{
if (Program.Viewers.Count == 0)
{
capturer = new DXCapture();
captureMode = CaptureMode.DirectX;
}
else
{
capturer = new BitBltCapture();
captureMode = CaptureMode.BitBtl;
}
}
catch (Exception ex)
{
Logger.Write(ex);
capturer = new BitBltCapture();
captureMode = CaptureMode.BitBtl;
}
Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capture Mode: {captureMode.ToString()}.");
var viewer = new Models.Viewer()
{
Capturer = capturer,
CurrentScreenIndex = 0,
DisconnectRequested = false,
Name = requesterName,
ViewerConnectionID = viewerID,
HasControl = Program.Mode == "unattended"
};
var success = false;
while (!success)
{
success = Program.Viewers.TryAdd(viewerID, viewer);
}
await outgoingMessages.SendScreenCount(
Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen),
Screen.AllScreens.Length,
viewerID);
await outgoingMessages.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
capturer.ScreenChanged += async (sender, size) =>
{
await outgoingMessages.SendScreenSize(size.Width, size.Height, viewerID);
};
while (!viewer.DisconnectRequested)
{
try
{
if (viewer.NextCaptureDelay > 0)
{
await Task.Delay(viewer.NextCaptureDelay);
viewer.NextCaptureDelay = 0;
}
capturer.Capture();
var newImage = ImageDiff.GetImageDiff(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);
var img = ImageDiff.EncodeBitmap(newImage);
if (capturer.CaptureFullscreen)
{
capturer.CaptureFullscreen = false;
}
if (img?.Length > 0)
{
await outgoingMessages.SendScreenCapture(img, viewerID, DateTime.Now);
}
}
catch (Exception ex)
{
Logger.Write($"Outer Error: {ex.Message}{Environment.NewLine}{ex.StackTrace}");
}
}
success = false;
while (!success)
{
Program.Viewers.TryRemove(viewerID, out _);
}
Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}.");
}
public static Tuple<double, double> GetAbsoluteScreenCoordinatesFromPercentages(double percentX, double percentY, ICapturer capturer)
{
var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left;
var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top;
return new Tuple<double, double>(absoluteX / SystemInformation.VirtualScreen.Width, absoluteY / SystemInformation.VirtualScreen.Height);
}
}
}

View File

@ -4,7 +4,6 @@ using Remotely_ScreenCast.Capture;
using Remotely_ScreenCast.Models;
using Remotely_ScreenCast.Sockets;
using Remotely_ScreenCast.Utilities;
using Remotely_ScreenCast.Capture;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

View File

@ -146,6 +146,7 @@
<Compile Include="Capture\DXCapture.cs" />
<Compile Include="Capture\ICapturer.cs" />
<Compile Include="Capture\ImageDiff.cs" />
<Compile Include="Capture\ScreenCaster.cs" />
<Compile Include="Models\Viewer.cs" />
<Compile Include="Sockets\MessageHandlers.cs" />
<Compile Include="Sockets\OutgoingMessages.cs" />

View File

@ -2,7 +2,6 @@
using Remotely_ScreenCast.Capture;
using Remotely_ScreenCast.Utilities;
using Remotely_ScreenCast;
using Remotely_ScreenCast.Capture;
using System;
using System.Collections.Generic;
using System.Linq;
@ -26,7 +25,7 @@ namespace Remotely_ScreenCast.Sockets
hubConnection.On("GetScreenCast", (string viewerID, string requesterName) =>
{
BeginScreenCasting(hubConnection, viewerID, requesterName, outgoingMessages);
ScreenCaster.BeginScreenCasting(hubConnection, viewerID, requesterName, outgoingMessages);
});
hubConnection.On("KeyDown", (int keyCode, string viewerID) =>
@ -57,13 +56,13 @@ namespace Remotely_ScreenCast.Sockets
}
});
hubConnection.On("MouseMove", (decimal percentX, decimal percentY, string viewerID) =>
hubConnection.On("MouseMove", (double percentX, double percentY, string viewerID) =>
{
var viewer = Program.Viewers[viewerID];
if (viewer.HasControl)
{
var mousePoint = viewer.Capturer.GetAbsoluteScreenCoordinatesFromPercentages(percentX, percentY);
Win32Interop.SendMouseMove(mousePoint.X, mousePoint.Y);
var mousePoint = ScreenCaster.GetAbsoluteScreenCoordinatesFromPercentages(percentX, percentY, viewer.Capturer);
Win32Interop.SendMouseMove(mousePoint.Item1, mousePoint.Item2);
}
});
@ -93,91 +92,5 @@ namespace Remotely_ScreenCast.Sockets
}
});
}
private static async void BeginScreenCasting(HubConnection hubConnection,
string viewerID,
string requesterName,
OutgoingMessages outgoingMessages)
{
ICapturer capturer;
CaptureMode captureMode;
try
{
capturer = new DXCapture();
captureMode = CaptureMode.DirectX;
}
catch (Exception ex)
{
Logger.Write(ex);
capturer = new BitBltCapture();
captureMode = CaptureMode.BitBtl;
}
Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capture Mode: {captureMode.ToString()}.");
var viewer = new Models.Viewer()
{
Capturer = capturer,
CurrentScreenIndex = 0,
DisconnectRequested = false,
Name = requesterName,
ViewerConnectionID = viewerID,
HasControl = Program.Mode == "unattended"
};
var success = false;
while (!success)
{
success = Program.Viewers.TryAdd(viewerID, viewer);
}
await outgoingMessages.SendScreenCount(
Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen),
Screen.AllScreens.Length,
viewerID);
await outgoingMessages.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
capturer.ScreenChanged += async (sender, size) =>
{
await outgoingMessages.SendScreenSize(size.Width, size.Height, viewerID);
};
while (!viewer.DisconnectRequested)
{
try
{
if (viewer.NextCaptureDelay > 0)
{
await Task.Delay(viewer.NextCaptureDelay);
viewer.NextCaptureDelay = 0;
}
capturer.Capture();
var newImage = ImageDiff.GetImageDiff(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);
var img = ImageDiff.EncodeBitmap(newImage);
if (capturer.CaptureFullscreen)
{
capturer.CaptureFullscreen = false;
}
if (img?.Length > 0)
{
await outgoingMessages.SendScreenCapture(img, viewerID, DateTime.Now);
}
}
catch (Exception ex)
{
Logger.Write($"Outer Error: {ex.Message}{Environment.NewLine}{ex.StackTrace}");
}
}
success = false;
while (!success)
{
Program.Viewers.TryRemove(viewerID, out _);
}
Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}.");
}
}
}

View File

@ -138,7 +138,7 @@ namespace Win32
}
// Offsets are used in case there's a multi-monitor setup where the left-most or top-most edge of the virtual screen
// is not 0. The coordinates sent from the web viewer are always zero-based, so the offset must be applied.
// is not 0.
public static uint SendMouseMove(double x, double y)
{
// Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.