Implement SkiaSharp. Remove manual quality controls.

This commit is contained in:
Jared 2021-03-18 22:10:04 -07:00 committed by Jared Goodwin
parent c00e01436b
commit 0d98fcd278
23 changed files with 74 additions and 316 deletions

View File

@ -47,6 +47,8 @@
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="5.0.0" />
<PackageReference Include="Microsoft.MixedReality.WebRTC" Version="2.0.2" />
<PackageReference Include="SkiaSharp" Version="2.80.2" />
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
</ItemGroup>

View File

@ -90,9 +90,6 @@ namespace Remotely.Desktop.Core.Services
case BaseDtoType.CtrlAltDel:
await viewer.SendCtrlAltDel();
break;
case BaseDtoType.AutoQualityAdjust:
SetAutoQualityAdjust(message, viewer);
break;
case BaseDtoType.ToggleAudio:
ToggleAudio(message);
break;
@ -108,9 +105,6 @@ namespace Remotely.Desktop.Core.Services
case BaseDtoType.KeyPress:
await KeyPress(message);
break;
case BaseDtoType.QualityChange:
QualityChange(message, viewer);
break;
case BaseDtoType.File:
await DownloadFile(message);
break;
@ -223,11 +217,6 @@ namespace Remotely.Desktop.Core.Services
{
FileTransferService.OpenFileTransferWindow(viewer);
}
private void QualityChange(byte[] message, Services.Viewer viewer)
{
var dto = MessagePackSerializer.Deserialize<QualityChangeDto>(message);
viewer.ImageQuality = dto.QualityLevel;
}
private void SelectScreen(byte[] message, Services.Viewer viewer)
{
@ -235,12 +224,6 @@ namespace Remotely.Desktop.Core.Services
viewer.Capturer.SetSelectedScreen(dto.DisplayName);
}
private void SetAutoQualityAdjust(byte[] message, Services.Viewer viewer)
{
var dto = MessagePackSerializer.Deserialize<AutoQualityAdjustDto>(message);
viewer.AutoAdjustQuality = dto.IsOn;
}
private void SetKeyStatesUp()
{
KeyboardMouseInput.SetKeyStatesUp();

View File

@ -21,6 +21,8 @@ namespace Remotely.Desktop.Core.Services
{
private readonly Conductor _conductor;
private readonly ICursorIconWatcher _cursorIconWatcher;
private readonly int _maxQuality = 75;
private readonly int _minQuality = 10;
private readonly ISessionIndicator _sessionIndicator;
private readonly IShutdownService _shutdownService;
@ -42,6 +44,8 @@ namespace Remotely.Desktop.Core.Services
try
{
var sendFramesLock = new SemaphoreSlim(1, 1);
var lastFullscreen = DateTimeOffset.Now;
var currentQuality = _maxQuality;
Bitmap currentFrame = null;
Bitmap previousFrame = null;
@ -90,7 +94,7 @@ namespace Remotely.Desktop.Core.Services
{
await viewer.SendScreenCapture(new CaptureFrame()
{
EncodedImageBytes = ImageUtils.EncodeJpg(initialFrame, viewer.EncoderParams),
EncodedImageBytes = ImageUtils.EncodeJpg(initialFrame, _maxQuality),
Left = viewer.Capturer.CurrentScreenBounds.Left,
Top = viewer.Capturer.CurrentScreenBounds.Top,
Width = viewer.Capturer.CurrentScreenBounds.Width,
@ -134,18 +138,56 @@ namespace Remotely.Desktop.Core.Services
currentFrame?.Dispose();
currentFrame = viewer.Capturer.GetNextFrame();
var diffArea = ImageUtils.GetDiffArea(currentFrame, previousFrame, viewer.Capturer.CaptureFullscreen);
if (diffArea.IsEmpty)
if (currentFrame is null)
{
continue;
}
if (DateTimeOffset.Now - lastFullscreen > TimeSpan.FromSeconds(5))
{
viewer.Capturer.CaptureFullscreen = true;
}
var diffArea = ImageUtils.GetDiffArea(currentFrame, previousFrame, viewer.Capturer.CaptureFullscreen);
if (diffArea.IsEmpty)
{
if (currentQuality < _maxQuality)
{
currentQuality++;
}
continue;
}
if (viewer.Capturer.CaptureFullscreen)
{
currentQuality = _maxQuality;
lastFullscreen = DateTimeOffset.Now;
}
if (viewer.PendingSentFrames.Any())
{
currentQuality = Math.Min(_minQuality, currentQuality - viewer.PendingSentFrames.Count);
}
if (viewer.PendingSentFrames.TryPeek(out var oldestFrame) &&
DateTimeOffset.Now - oldestFrame > TimeSpan.FromMilliseconds(100))
{
currentQuality = Math.Max(_minQuality, currentQuality - 10);
}
else
{
currentQuality = Math.Min(_maxQuality, currentQuality + 5);
}
viewer.Capturer.CaptureFullscreen = false;
var clone = currentFrame.Clone(diffArea, currentFrame.PixelFormat);
using var clone = currentFrame.Clone(diffArea, currentFrame.PixelFormat);
var encodedImageBytes = ImageUtils.EncodeJpg(clone, currentQuality);
await sendFramesLock.WaitAsync();
SendFrame(clone, diffArea, viewer, sendFramesLock);
SendFrame(encodedImageBytes, diffArea, viewer, sendFramesLock);
}
catch (Exception ex)
{
@ -172,14 +214,13 @@ namespace Remotely.Desktop.Core.Services
}
}
private static void SendFrame(Bitmap clone, Rectangle diffArea, Viewer viewer, SemaphoreSlim sendFramesLock)
private static void SendFrame(byte[] encodedImageBytes, Rectangle diffArea, Viewer viewer, SemaphoreSlim sendFramesLock)
{
_ = Task.Run(async () =>
{
try
{
var encodedImageBytes = ImageUtils.EncodeJpg(clone, viewer.EncoderParams);
if (encodedImageBytes.Length == 0)
{
return;
@ -198,7 +239,6 @@ namespace Remotely.Desktop.Core.Services
finally
{
sendFramesLock.Release();
clone.Dispose();
}
});
}

View File

@ -16,9 +16,6 @@ namespace Remotely.Desktop.Core.Services
{
public class Viewer : IDisposable
{
private readonly int _defaultImageQuality = 60;
private long _imageQuality;
private DateTimeOffset _lastQualityAdjustment;
public Viewer(ICasterSocket casterSocket,
IScreenCapturer screenCapturer,
IClipboardService clipboardService,
@ -28,45 +25,17 @@ namespace Remotely.Desktop.Core.Services
Capturer = screenCapturer;
CasterSocket = casterSocket;
WebRtcSessionFactory = webRtcSessionFactory;
EncoderParams = new EncoderParameters();
ImageQuality = _defaultImageQuality;
ClipboardService = clipboardService;
ClipboardService.ClipboardTextChanged += ClipboardService_ClipboardTextChanged;
AudioCapturer = audioCapturer;
AudioCapturer.AudioSampleReady += AudioCapturer_AudioSampleReady;
}
public bool AutoAdjustQuality { get; set; } = true;
public IScreenCapturer Capturer { get; }
public bool DisconnectRequested { get; set; }
public EncoderParameters EncoderParams { get; private set; }
public bool HasControl { get; set; } = true;
public long ImageQuality
{
get
{
return _imageQuality;
}
set
{
if (_imageQuality == value)
{
return;
}
if (_imageQuality > 100 || _imageQuality < 0)
{
return;
}
_imageQuality = value;
EncoderParams.Param[0] = new EncoderParameter(Encoder.Quality, value);
}
}
public bool IsConnected => CasterSocket.IsConnected;
public bool IsStalled
@ -259,8 +228,7 @@ namespace Remotely.Desktop.Core.Services
Width = width,
Height = height,
EndOfFrame = false,
ImageBytes = screenFrame.EncodedImageBytes.Skip(i).Take(50_000).ToArray(),
ImageQuality = _imageQuality
ImageBytes = screenFrame.EncodedImageBytes.Skip(i).Take(50_000).ToArray()
};
await SendToViewer(() => RtcSession.SendDto(dto),
@ -273,8 +241,7 @@ namespace Remotely.Desktop.Core.Services
Top = top,
Width = width,
Height = height,
EndOfFrame = true,
ImageQuality = _imageQuality
EndOfFrame = true
};
await SendToViewer(() => RtcSession.SendDto(endOfFrameDto),
@ -312,14 +279,7 @@ namespace Remotely.Desktop.Core.Services
public void ThrottleIfNeeded()
{
TaskHelper.DelayUntil(() =>
{
UpdateImageQuality();
return PendingSentFrames.Count < 7 &&
(
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result < TimeSpan.FromSeconds(1)
);
},
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result < TimeSpan.FromSeconds(1),
TimeSpan.MaxValue);
}
@ -357,23 +317,5 @@ namespace Remotely.Desktop.Core.Services
return Task.CompletedTask;
}
}
private void UpdateImageQuality()
{
if (AutoAdjustQuality && DateTimeOffset.Now - _lastQualityAdjustment > TimeSpan.FromSeconds(2))
{
_lastQualityAdjustment = DateTimeOffset.Now;
if (PendingSentFrames.TryPeek(out var result) && DateTimeOffset.Now - result > TimeSpan.FromMilliseconds(200))
{
var latency = (DateTimeOffset.Now - result).TotalMilliseconds;
ImageQuality = Math.Max(20, (int)(200 / latency * _defaultImageQuality));
}
else if (ImageQuality != _defaultImageQuality)
{
ImageQuality = Math.Min(_defaultImageQuality, ImageQuality + 10);
}
}
}
}
}

View File

@ -1,4 +1,6 @@
using System;
using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
@ -12,29 +14,18 @@ namespace Remotely.Desktop.Core.Utilities
{
public class ImageUtils
{
public static ImageCodecInfo GifEncoder { get; } = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Gif.Guid);
public static ImageCodecInfo JpegEncoder { get; } = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Jpeg.Guid);
public static byte[] EncodeJpg(Bitmap bitmap, EncoderParameters encoderParams)
{
using var ms = new MemoryStream();
bitmap.Save(ms, JpegEncoder, encoderParams);
return ms.ToArray();
}
public static byte[] EncodePng(Bitmap bitmap)
public static byte[] EncodeJpg(Bitmap bitmap, int quality)
{
using var ms = new MemoryStream();
bitmap.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
var info = new SKImageInfo(bitmap.Width, bitmap.Height);
var skBitmap = new SKBitmap(info);
using (var pixmap = skBitmap.PeekPixels())
{
bitmap.ToSKPixmap(pixmap);
}
skBitmap.Encode(ms, SKEncodedImageFormat.Jpeg, quality);
public static byte[] EncodeGif(Bitmap diffImage)
{
diffImage.MakeTransparent(Color.FromArgb(0, 0, 0, 0));
using var ms = new MemoryStream();
diffImage.Save(ms, ImageFormat.Gif);
return ms.ToArray();
}

View File

@ -55,6 +55,8 @@
<PackageReference Include="Avalonia" Version="0.10.0" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.0" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0" />
<PackageReference Include="SkiaSharp" Version="2.80.2" />
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Desktop.Core\Desktop.Core.csproj" />

View File

@ -39,6 +39,8 @@
<PackageReference Include="SharpDX" Version="4.2.0" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="SharpDX.DXGI" Version="4.2.0" />
<PackageReference Include="SkiaSharp" Version="2.80.2" />
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
</ItemGroup>

View File

@ -154,10 +154,6 @@
<button id="fitToScreenButton" class="toggled option-button" title="If toggled, will resize image to fit in the window.">
Fit <i class="fas fa-expand"></i>
</button>
<button id="qualityButton" class="option-button" title="Adjust the image quality when not in Stream Mode.">
Quality <i class="far fa-image"></i>
</button>
</div>
@ -197,19 +193,6 @@
</div>
<div id="qualityBar" class="horizontal-button-bar">
<div style="color:white; font-size:12px">
Image Quality
</div>
<div>
<input id="qualityRangeInput" value="60" max="100" class="form-control-range" type="range" />
<div style="color:white; font-size:12px; text-align: left">
<input id="autoAdjustQualityCheckBox" type="checkbox" checked />
<label for="autoAdjustQualityCheckBox">Auto Adjust</label>
</div>
</div>
</div>
<div id="clipboardTransferBar" class="horizontal-button-bar">
<div style="color:white; font-size:12px">
Shared Clipboard

View File

@ -31,9 +31,6 @@ export const ViewerApp = {
Settings: GetSettings(),
Init: () => {
UI.AutoQualityAdjustCheckBox.checked = ViewerApp.Settings.autoQualityEnabled;
UI.QualitySlider.value = String(ViewerApp.Settings.qualityLevel);
if (ViewerApp.ViewOnlyMode) {
UI.ViewOnlyButton.classList.add("toggled");
}

View File

@ -60,10 +60,6 @@ export class DtoMessageHandler {
}
HandleCaptureFrame(captureFrame: CaptureFrameDto) {
if (UI.AutoQualityAdjustCheckBox.checked &&
Number(UI.QualitySlider.value) != captureFrame.ImageQuality) {
UI.QualitySlider.value = String(captureFrame.ImageQuality);
}
if (captureFrame.EndOfFrame) {
let completedFrame = new Blob(this.ImagePartials, { type: "image/jpeg" });
@ -114,8 +110,6 @@ export class DtoMessageHandler {
}
HandleScreenData(screenDataDto: ScreenDataDto) {
UI.UpdateDisplays(screenDataDto.SelectedScreen, screenDataDto.DisplayNames);
ViewerApp.MessageSender.SendAutoQualityAdjust(ViewerApp.Settings.autoQualityEnabled);
ViewerApp.MessageSender.SendQualityChange(ViewerApp.Settings.qualityLevel);
}
HandleScreenSize(screenSizeDto: ScreenSizeDto) {

View File

@ -19,10 +19,6 @@
TouchKeyboardTextArea,
MenuFrame,
MenuButton,
QualityButton,
QualityBar,
QualitySlider,
AutoQualityAdjustCheckBox,
ScreenViewerWrapper,
WindowsSessionSelect,
RecordSessionButton,
@ -219,18 +215,6 @@ export function ApplyInputHandlers() {
ev.stopPropagation();
MenuButton.style.top = `${ev.touches[0].clientY}px`;
});
QualityButton.addEventListener("click", (ev) => {
closeAllHorizontalBars("qualityBar");
QualityBar.classList.toggle("open");
})
QualitySlider.addEventListener("change", (ev) => {
var value = Number(QualitySlider.value);
ViewerApp.Settings.qualityLevel = value;
SetSettings(ViewerApp.Settings);
ViewerApp.MessageSender.SendQualityChange(value);
});
StreamVideoButton.addEventListener("click", (ev) => {
var toggleOn = !StreamVideoButton.classList.contains("toggled");
@ -240,14 +224,6 @@ export function ApplyInputHandlers() {
UpdateStreamingToggled(toggleOn);
ViewerApp.MessageSender.SendToggleWebRtcVideo(toggleOn);
});
AutoQualityAdjustCheckBox.addEventListener("change", ev => {
var checked = AutoQualityAdjustCheckBox.checked;
ViewerApp.Settings.autoQualityEnabled = checked;
SetSettings(ViewerApp.Settings);
ViewerApp.MessageSender.SendAutoQualityAdjust(checked);
});
[ ScreenViewer, VideoScreenViewer ].forEach(viewer => {
viewer.addEventListener("pointermove", function (e: PointerEvent) {

View File

@ -2,15 +2,6 @@ import { BaseDto } from "./BaseDto.js";
import { BaseDtoType } from "../../Shared/Enums/BaseDtoType.js";
import { WindowsSession } from "../../Shared/Models/WindowsSession.js";
export class AutoQualityAdjustDto implements BaseDto {
constructor(isOn: boolean) {
this.IsOn = isOn;
}
IsOn: boolean;
DtoType: BaseDtoType = BaseDtoType.AutoQualityAdjust;
}
export interface AudioSampleDto extends BaseDto {
Buffer: Uint8Array;
@ -23,7 +14,6 @@ export interface CaptureFrameDto extends BaseDto {
Width: number;
Height: number;
ImageBytes: Uint8Array;
ImageQuality: number;
}
export interface ClipboardTextDto extends BaseDto {
@ -163,15 +153,6 @@ export class MouseWheelDto implements BaseDto {
DtoType: BaseDtoType = BaseDtoType.MouseWheel;
}
export class QualityChangeDto implements BaseDto {
constructor(qualityLevel: number) {
this.QualityLevel = qualityLevel;
}
QualityLevel: number;
DtoType: BaseDtoType = BaseDtoType.QualityChange;
}
export interface ScreenDataDto extends BaseDto {
DisplayNames: string[];
SelectedScreen: string;

View File

@ -1,5 +1,3 @@
export interface Settings {
autoQualityEnabled: boolean;
qualityLevel: number;
streamModeEnabled: boolean;
}

View File

@ -8,10 +8,8 @@ import {
MouseMoveDto,
MouseUpDto,
MouseWheelDto,
QualityChangeDto,
SelectScreenDto,
TapDto,
AutoQualityAdjustDto,
ToggleAudioDto,
ToggleBlockInputDto,
ClipboardTransferDto,
@ -131,16 +129,6 @@ export class MessageSender {
() => ViewerApp.ViewerHubConnection.SendDtoToClient(dto));
}
SendQualityChange(qualityLevel: number) {
var dto = new QualityChangeDto(qualityLevel);
this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto),
() => ViewerApp.ViewerHubConnection.SendDtoToClient(dto));
}
SendAutoQualityAdjust(isOn: boolean) {
var dto = new AutoQualityAdjustDto(isOn);
this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto),
() => ViewerApp.ViewerHubConnection.SendDtoToClient(dto));
}
SendToggleAudio(toggleOn: boolean) {
var dto = new ToggleAudioDto(toggleOn);
this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto),

View File

@ -31,7 +31,6 @@ export class RtcSession {
UI.StreamVideoButton.setAttribute("hidden", "hidden");
UI.ScreenViewer.removeAttribute("hidden");
UI.QualityButton.removeAttribute("hidden");
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
};
this.DataChannel.onerror = (ev) => {
@ -41,7 +40,6 @@ export class RtcSession {
UI.StreamVideoButton.setAttribute("hidden", "hidden");
UI.ScreenViewer.removeAttribute("hidden");
UI.QualityButton.removeAttribute("hidden");
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
};
this.DataChannel.onmessage = (ev) => {

View File

@ -1,10 +1,6 @@
import { ViewerApp } from "./App.js";
import { Settings } from "./Interfaces/Settings.js";
import { AutoQualityAdjustCheckBox, QualitySlider, UpdateStreamingToggled } from "./UI.js";
import { Settings } from "./Interfaces/Settings.js";
const defaultSettings = {
autoQualityEnabled: true,
qualityLevel: 60,
streamModeEnabled: false
};

View File

@ -17,13 +17,9 @@ export var Screen2DContext = ScreenViewer ? ScreenViewer.getContext("2d") : null
export var HorizontalBars = document.querySelectorAll(".horizontal-button-bar");
export var ConnectBox = document.getElementById("connectBox") as HTMLDivElement;
export var ScreenSelectBar = document.getElementById("screenSelectBar") as HTMLDivElement;
export var QualityBar = document.getElementById("qualityBar") as HTMLDivElement;
export var QualitySlider = document.getElementById("qualityRangeInput") as HTMLInputElement;
export var AutoQualityAdjustCheckBox = document.getElementById("autoAdjustQualityCheckBox") as HTMLInputElement;
export var ActionsBar = document.getElementById("actionsBar") as HTMLDivElement;
export var ViewBar = document.getElementById("viewBar") as HTMLDivElement;
export var ChangeScreenButton = document.getElementById("changeScreenButton") as HTMLButtonElement;
export var QualityButton = document.getElementById("qualityButton") as HTMLButtonElement;
export var StreamVideoButton = document.getElementById("streamVideoButton") as HTMLButtonElement;
export var FitToScreenButton = document.getElementById("fitToScreenButton") as HTMLButtonElement;
export var BlockInputButton = document.getElementById("blockInputButton") as HTMLButtonElement;
@ -161,12 +157,10 @@ export function UpdateStreamingToggled(toggleOn: boolean) {
StreamVideoButton.classList.add("toggled");
VideoScreenViewer.removeAttribute("hidden");
ScreenViewer.setAttribute("hidden", "hidden");
QualityButton.setAttribute("hidden", "hidden");
}
else {
StreamVideoButton.classList.remove("toggled");
ScreenViewer.removeAttribute("hidden");
QualityButton.removeAttribute("hidden");
VideoScreenViewer.setAttribute("hidden", "hidden");
}
}

View File

@ -15,12 +15,10 @@
KeyDown = 13,
KeyUp = 14,
CtrlAltDel = 15,
AutoQualityAdjust = 16,
ToggleAudio = 17,
ToggleBlockInput = 18,
ClipboardTransfer = 19,
KeyPress = 20,
QualityChange = 21,
File = 22,
WindowsSessions = 23,
SetKeyStatesUp = 24,

View File

@ -37,8 +37,6 @@ namespace Remotely.Shared.Enums
KeyUp = 14,
[EnumMember(Value = "CtrlAltDel")]
CtrlAltDel = 15,
[EnumMember(Value = "AutoQualityAdjust")]
AutoQualityAdjust = 16,
[EnumMember(Value = "ToggleAudio")]
ToggleAudio = 17,
[EnumMember(Value = "ToggleBlockInput")]
@ -47,8 +45,6 @@ namespace Remotely.Shared.Enums
ClipboardTransfer = 19,
[EnumMember(Value = "KeyPress")]
KeyPress = 20,
[EnumMember(Value = "QualityChange")]
QualityChange = 21,
[EnumMember(Value = "File")]
File = 22,
[EnumMember(Value = "WindowsSessions")]

View File

@ -1,15 +0,0 @@
using Remotely.Shared.Enums;
using System.Runtime.Serialization;
namespace Remotely.Shared.Models.RemoteControlDtos
{
[DataContract]
public class AutoQualityAdjustDto : BaseDto
{
[DataMember(Name = "IsOn")]
public bool IsOn { get; set; }
[DataMember(Name = "DtoType")]
public new BaseDtoType DtoType { get; } = BaseDtoType.AutoQualityAdjust;
}
}

View File

@ -18,9 +18,6 @@ namespace Remotely.Shared.Models.RemoteControlDtos
[DataMember(Name = "ImageBytes")]
public byte[] ImageBytes { get; set; }
[DataMember(Name = "ImageQuality")]
public long ImageQuality { get; set; }
[DataMember(Name = "Left")]
public int Left { get; set; }
[DataMember(Name = "Top")]

View File

@ -1,15 +0,0 @@
using Remotely.Shared.Enums;
using System.Runtime.Serialization;
namespace Remotely.Shared.Models.RemoteControlDtos
{
[DataContract]
public class QualityChangeDto : BaseDto
{
[DataMember(Name = "QualityLevel")]
public int QualityLevel { get; set; }
[DataMember(Name = "DtoType")]
public new BaseDtoType DtoType { get; } = BaseDtoType.QualityChange;
}
}

View File

@ -100,8 +100,8 @@ namespace Remotely.Tests
tempImage.Save(ms, jpegEncoder, encoderParams);
diffSize = ms.ToArray().Length;
}
Debug.WriteLine($"Diff size: {diffSize}");
Debug.WriteLine($"Diff time: {sw.Elapsed.TotalMilliseconds}");
Debug.WriteLine($"Diff area size: {diffSize}");
Debug.WriteLine($"Diff area time: {sw.Elapsed.TotalMilliseconds}");
sw.Restart();
@ -116,76 +116,6 @@ namespace Remotely.Tests
Debug.WriteLine($"Diff Image time: {sw.Elapsed.TotalMilliseconds}");
sw.Restart();
var gifImage = (Bitmap)diffImage.Clone();
using (var ms = new MemoryStream())
{
gifImage.MakeTransparent(Color.FromArgb(0, 0, 0, 0));
gifImage.Save(ms, ImageFormat.Gif);
Debug.WriteLine($"GIF image size: {ms.ToArray().Length}");
}
Debug.WriteLine($"GIF Image time: {sw.Elapsed.TotalMilliseconds}");
//sw.Restart();
//using (var ms = new MemoryStream())
//{
// diffImage.Save(ms, ImageFormat.Jpeg);
// ms.Seek(0, SeekOrigin.Begin);
// var pngEncoder = new PngEncoder() { CompressionLevel = PngCompressionLevel.BestSpeed };
// using (var ms2 = new MemoryStream())
// {
// SixLabors.ImageSharp.Image.Load(ms).Save(ms2, pngEncoder);
// Debug.WriteLine($"ImageSharp size: {ms2.ToArray().Length}");
// }
//}
//Debug.WriteLine($"ImageSharp encode time: {sw.Elapsed.TotalMilliseconds}");
//sw.Restart();
//using (var ms = new MemoryStream())
//{
// diffImage.Save(ms, ImageFormat.Jpeg);
// ms.Seek(0, SeekOrigin.Begin);
// using (var ms2 = new MemoryStream())
// {
// Aspose.Imaging.Image.Load(ms).Save(ms2, new PngOptions() { CompressionLevel = 5 });
// Debug.WriteLine($"Aspose size: {ms2.ToArray().Length}");
// }
//}
//Debug.WriteLine($"Aspose encode time: {sw.Elapsed.TotalMilliseconds}");
//sw.Restart();
//var drawingBytes = ImageUtils.EncodeBitmap(frame1, null);
//Debug.WriteLine($"Drawing Encoder time: {sw.Elapsed.TotalMilliseconds}");
//Debug.WriteLine($"Drawing encoder size: {drawingBytes.Length}");
//sw.Restart();
//using (var ms = new MemoryStream())
//{
// frame1.Clone(new Rectangle(0, 0, 500, 500), PixelFormat.Format32bppArgb)
// .Save(ms, GetEncoder(ImageFormat.Jpeg), encoderParams);
// Debug.WriteLine($"Jpeg encode time: {sw.Elapsed.TotalMilliseconds}");
// Debug.WriteLine($"Jpeg encode size: {ms.ToArray().Length}");
//}
//var factory = new ImageProcessor.ImageFactory();
//sw.Restart();
//using (var ms = new MemoryStream())
//{
// var webPFormat = new ImageProcessor.Plugins.WebP.Imaging.Formats.WebPFormat();
// factory.Load(diffImage)
// .Format(webPFormat)
// .Quality(60)
// .Save(ms);
// Debug.WriteLine($"Webp encode time: {sw.Elapsed.TotalMilliseconds}");
// Debug.WriteLine($"Webp encode size: {ms.ToArray().Length}");
//}
Debug.WriteLine($"\n");
}
}