双指缩放
@@ -1,8 +1,8 @@
|
||||
import { sendWebsocketMsg } from './request'
|
||||
|
||||
|
||||
export const notifyUpdate = (speed, msg) => {
|
||||
export const notifyUpdate = (speed, msg, star) => {
|
||||
return sendWebsocketMsg('notify/update', {
|
||||
speed, msg
|
||||
speed, msg, star
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { sendWebsocketMsg } from './request'
|
||||
|
||||
export const reportUpdate = (names) => {
|
||||
return sendWebsocketMsg('report/update', names);
|
||||
export const reportUpdate = (names, reportType) => {
|
||||
return sendWebsocketMsg('report/update', {
|
||||
names, reportType
|
||||
});
|
||||
}
|
||||
export const reportPing = (names) => {
|
||||
return sendWebsocketMsg('report/ping', names);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { sendWebsocketMsg } from './request'
|
||||
|
||||
export const screenUpdateFull = (names) => {
|
||||
return sendWebsocketMsg('screen/full', names);
|
||||
export const screenUpdateFull = (names, type) => {
|
||||
return sendWebsocketMsg('screen/full', {
|
||||
names, type
|
||||
});
|
||||
}
|
||||
export const screenUpdateRegion = (names) => {
|
||||
return sendWebsocketMsg('screen/region', names);
|
||||
|
||||
@@ -7,7 +7,8 @@ export default {
|
||||
Report: {
|
||||
fps: 0,
|
||||
fpsTimes: 0,
|
||||
ping: 0
|
||||
ping: 0,
|
||||
updated: false
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -32,7 +33,14 @@ export default {
|
||||
reportInterval() {
|
||||
if (this.reported) {
|
||||
this.reported = false;
|
||||
reportUpdate(this.globalData.value.reportNames).then(() => {
|
||||
|
||||
const names = this.globalData.value.reportNames;
|
||||
let reportType = 1;
|
||||
this.globalData.value.devices.filter(c => names.indexOf(c.MachineName) >= 0).forEach(item => {
|
||||
reportType &&= Number(item.Report.updated);
|
||||
item.Report.updated = true;
|
||||
});
|
||||
reportUpdate(names, reportType).then(() => {
|
||||
this.reported = true;
|
||||
this.reportTimer = setTimeout(() => {
|
||||
this.reportInterval();
|
||||
|
||||
@@ -5,12 +5,47 @@ export default {
|
||||
field() {
|
||||
return {
|
||||
Screen: {
|
||||
regions: [],
|
||||
img: null,
|
||||
fullUpdated: false,
|
||||
|
||||
draw(canvas, ctx) {
|
||||
this.drawFps(canvas, ctx);
|
||||
this.drawRectangle(canvas, ctx);
|
||||
this.drawTouch(canvas, ctx);
|
||||
},
|
||||
|
||||
lastInput: 0,
|
||||
fps: 0,
|
||||
fpsTimes: 0,
|
||||
img: null,
|
||||
regions: [],
|
||||
LastInput: 0,
|
||||
drawFps(canvas, ctx) {
|
||||
ctx.lineWidth = 5;
|
||||
ctx.font = 'bold 60px Arial';
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.5)';
|
||||
ctx.fillText(`FPS : ${this.fps} 、LT : ${this.lastInput}ms`, 50, 70);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.strokeText(`FPS : ${this.fps} 、LT : ${this.lastInput}ms`, 50, 70);
|
||||
},
|
||||
|
||||
rectangles: [],
|
||||
drawRectangle(canvas, ctx) {
|
||||
if (this.rectangles.length > 0 && this.touch.scale == 1) {
|
||||
ctx.lineWidth = 5;
|
||||
ctx.strokeStyle = 'rgba(255,0,0,1)';
|
||||
for (let i = 0; i < this.rectangles.length; i++) {
|
||||
|
||||
const rectangle = this.rectangles[i];
|
||||
ctx.rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.font = 'bold 100px Arial';
|
||||
ctx.fillStyle = 'rgba(255,0,0,1)';
|
||||
ctx.fillText(i, rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height / 2);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
touch: {
|
||||
//上次位置
|
||||
lastTouch: { x1: 0, y1: 0, x2: 0, y2: 0, dist: 0, },
|
||||
@@ -21,6 +56,20 @@ export default {
|
||||
updated: false,
|
||||
type: 0
|
||||
},
|
||||
drawTouch(canvas, ctx) {
|
||||
if (this.touch.type == 2) {
|
||||
ctx.fillStyle = 'red';
|
||||
ctx.strokeStyle = 'yellow';
|
||||
ctx.rect(this.touch.origin.x - 50, this.touch.origin.y - 50, 100, 100);
|
||||
ctx.fill();
|
||||
|
||||
ctx.lineWidth = 5;
|
||||
ctx.strokeStyle = 'yellow';
|
||||
ctx.moveTo(this.touch.lastTouch.x1, this.touch.lastTouch.y1);
|
||||
ctx.lineTo(this.touch.lastTouch.x2, this.touch.lastTouch.y2);
|
||||
ctx.stroke();
|
||||
}
|
||||
},
|
||||
|
||||
touchend(event) {
|
||||
this.touch.type = 0;
|
||||
@@ -75,6 +124,7 @@ export default {
|
||||
};
|
||||
|
||||
} else if (event.touches.length == 1) {
|
||||
if (this.touch.scale == 1) return;
|
||||
this.touch.type = 1;
|
||||
const { x1, y1 } = this.getPosition(event);
|
||||
this.touch.lastTouch.x1 = x1;
|
||||
@@ -102,7 +152,7 @@ export default {
|
||||
|
||||
this.touch.updated = true;
|
||||
} else if (event.touches.length == 1) {
|
||||
if (this.touch.type != 1) return;
|
||||
if (this.touch.type != 1 || this.touch.scale == 1) return;
|
||||
const { x1, y1 } = this.getPosition(event);
|
||||
|
||||
const distX = x1 - this.touch.lastTouch.x1;
|
||||
@@ -222,36 +272,40 @@ export default {
|
||||
const item = devices[i];
|
||||
if (!item.canvas) {
|
||||
item.canvas = document.getElementById(`canvas-${item.MachineName}`);
|
||||
if (item.canvas) {
|
||||
item.ctx = item.canvas.getContext('2d');
|
||||
}
|
||||
if (!item.infoCanvas) {
|
||||
item.infoCanvas = document.createElement('canvas');
|
||||
item.infoCanvas.width = item.canvas.width;
|
||||
item.infoCanvas.height = item.canvas.height;
|
||||
item.infoCtx = item.infoCanvas.getContext('2d');
|
||||
}
|
||||
if (item.ctx) {
|
||||
item.infoCtx.clearRect(0, 0, item.infoCanvas.width, item.infoCanvas.height);
|
||||
|
||||
const img = item.Screen.img;
|
||||
item.ctx.clearRect(0, 0, item.canvas.width, item.canvas.height);
|
||||
if (img) {
|
||||
item.ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, item.canvas.width, item.canvas.height);
|
||||
} else {
|
||||
//screenUpdateFull(this.globalData.value.reportNames);
|
||||
}
|
||||
|
||||
const regions = item.Screen.regions;
|
||||
for (let i = 0; i < regions.length; i++) {
|
||||
const { x, y, w, h } = regions[i].param;
|
||||
item.ctx.drawImage(regions[i], 0, 0, regions[i].width, regions[i].height, x, y, w, h);
|
||||
item.infoCtx.drawImage(regions[i], 0, 0, regions[i].width, regions[i].height, x, y, w, h);
|
||||
}
|
||||
|
||||
this.drawFps(item);
|
||||
|
||||
for (let j in item) {
|
||||
try {
|
||||
if (item[j] && item[j].draw) {
|
||||
item[j].draw(item.canvas, item.ctx);
|
||||
|
||||
item[j].draw(item.infoCanvas, item.infoCtx);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
item.ctx.drawImage(item.infoCanvas, 0, 0, item.infoCanvas.width, item.infoCanvas.height, 0, 0, item.canvas.width, item.canvas.height);
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
@@ -268,42 +322,6 @@ export default {
|
||||
this.fpsInterval();
|
||||
}, 1000)
|
||||
},
|
||||
drawFps(item) {
|
||||
item.ctx.lineWidth = 5;
|
||||
item.ctx.font = 'bold 60px Arial';
|
||||
item.ctx.fillStyle = 'rgba(0,0,0,0.5)';
|
||||
item.ctx.fillText(`FPS : ${item.Screen.fps} 、LT : ${item.Screen.LastInput}ms`, 50, 70);
|
||||
item.ctx.lineWidth = 2;
|
||||
item.ctx.strokeStyle = '#fff';
|
||||
item.ctx.strokeText(`FPS : ${item.Screen.fps} 、LT : ${item.Screen.LastInput}ms`, 50, 70);
|
||||
|
||||
if (item.Screen.rectangles.length > 0) {
|
||||
item.ctx.lineWidth = 5;
|
||||
for (let i = 0; i < item.Screen.rectangles.length; i++) {
|
||||
item.ctx.strokeStyle = 'rgba(255,0,0,0.5)';
|
||||
const rectangle = item.Screen.rectangles[i];
|
||||
item.ctx.rect(rectangle.X / 0.2, rectangle.Y / 0.2, rectangle.Width / 0.2, rectangle.Height / 0.2);
|
||||
item.ctx.stroke();
|
||||
|
||||
item.ctx.font = 'bold 100px Arial';
|
||||
item.ctx.fillStyle = 'rgba(0,0,0,1)';
|
||||
item.ctx.fillText(i, rectangle.X / 0.2, rectangle.Y / 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Screen.touch.type == 2) {
|
||||
item.ctx.fillStyle = 'red';
|
||||
item.ctx.strokeStyle = 'yellow';
|
||||
item.ctx.rect(item.Screen.touch.origin.x - 50, item.Screen.touch.origin.y - 50, 100, 100);
|
||||
item.ctx.fill();
|
||||
|
||||
item.ctx.lineWidth = 5;
|
||||
item.ctx.strokeStyle = 'yellow';
|
||||
item.ctx.moveTo(item.Screen.touch.lastTouch.x1, item.Screen.touch.lastTouch.y1);
|
||||
item.ctx.lineTo(item.Screen.touch.lastTouch.x2, item.Screen.touch.lastTouch.y2);
|
||||
item.ctx.stroke();
|
||||
}
|
||||
},
|
||||
|
||||
clipTimer: 0,
|
||||
clipInterver() {
|
||||
@@ -326,7 +344,9 @@ export default {
|
||||
reportInterval() {
|
||||
if (this.reported) {
|
||||
this.reported = false;
|
||||
screenUpdateFull(this.globalData.value.reportNames).then(() => {
|
||||
|
||||
const names = this.globalData.value.reportNames;
|
||||
screenUpdateFull(names, 0).then(() => {
|
||||
this.reported = true;
|
||||
this.reportTimer = setTimeout(() => {
|
||||
this.reportInterval();
|
||||
@@ -347,6 +367,6 @@ export default {
|
||||
update(item, report) {
|
||||
if (!report.Screen) return;
|
||||
|
||||
item.Screen.LastInput = report.Screen.LT || 0;
|
||||
item.Screen.lastInput = report.Screen.LT || 0;
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
if (res) {
|
||||
ElMessage.success('操作成功!');
|
||||
if (value.notify) {
|
||||
notifyUpdate(2, `恭喜[${props.data.Share.UserName.Value}]获得【${value.star}星】点评`);
|
||||
notifyUpdate(2, props.data.Share.UserName.Value, value.star);
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('操作失败!');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using cmonitor.server.service;
|
||||
using cmonitor.server.client.reports;
|
||||
using cmonitor.server.service;
|
||||
using cmonitor.server.service.messengers.command;
|
||||
using cmonitor.server.service.messengers.sign;
|
||||
using common.libs;
|
||||
@@ -22,15 +23,14 @@ namespace cmonitor.server.api.services
|
||||
}
|
||||
public bool Update(ClientServiceParamsInfo param)
|
||||
{
|
||||
string[] names = param.Content.DeJson<string[]>();
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
UpdateInfo updateinfo = param.Content.DeJson<UpdateInfo>();
|
||||
byte[] bytes = new byte[] { (byte)updateinfo.ReportType };
|
||||
for (int i = 0; i < updateinfo.Names.Length; i++)
|
||||
{
|
||||
bool res = signCaching.Get(names[i], out SignCacheInfo cache)
|
||||
&& cache.Connected
|
||||
&& cache.GetReport(config.ReportDelay)
|
||||
&& Interlocked.CompareExchange(ref cache.ReportFlag, 0, 1) == 1;
|
||||
bool connectionRes = (signCaching.Get(updateinfo.Names[i], out SignCacheInfo cache) && cache.Connected);
|
||||
bool reportTimeRes = cache.GetReport(config.ReportDelay) && Interlocked.CompareExchange(ref cache.ReportFlag, 0, 1) == 1;
|
||||
|
||||
if (res)
|
||||
if (connectionRes && (reportTimeRes || updateinfo.ReportType == ReportType.Full))
|
||||
{
|
||||
cache.UpdateReport();
|
||||
_ = messengerSender.SendOnly(new MessageRequestWrap
|
||||
@@ -38,6 +38,7 @@ namespace cmonitor.server.api.services
|
||||
Connection = cache.Connection,
|
||||
MessengerId = (ushort)ReportMessengerIds.Update,
|
||||
Timeout = 1000,
|
||||
Payload = bytes,
|
||||
}).ContinueWith((result) =>
|
||||
{
|
||||
Interlocked.Exchange(ref cache.ReportFlag, 1);
|
||||
@@ -80,5 +81,12 @@ namespace cmonitor.server.api.services
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sealed class UpdateInfo
|
||||
{
|
||||
public string[] Names { get; set; }
|
||||
public ReportType ReportType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,21 +20,19 @@ namespace cmonitor.server.api.services
|
||||
}
|
||||
public bool Full(ClientServiceParamsInfo param)
|
||||
{
|
||||
string[] names = param.Content.DeJson<string[]>();
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
ScreenReportInfo report = param.Content.DeJson<ScreenReportInfo>();
|
||||
for (int i = 0; i < report.Names.Length; i++)
|
||||
{
|
||||
bool res = signCaching.Get(names[i], out SignCacheInfo cache)
|
||||
&& cache.Connected
|
||||
&& cache.GetScreen(config.ScreenDelay)
|
||||
&& Interlocked.CompareExchange(ref cache.ScreenFlag, 0, 1) == 1;
|
||||
if (res)
|
||||
bool connectionRes = signCaching.Get(report.Names[i], out SignCacheInfo cache) && cache.Connected;
|
||||
bool reportRes = cache.GetScreen(config.ScreenDelay) && Interlocked.CompareExchange(ref cache.ScreenFlag, 0, 1) == 1;
|
||||
if (connectionRes && reportRes)
|
||||
{
|
||||
cache.UpdateScreen();
|
||||
_ = messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
Connection = cache.Connection,
|
||||
MessengerId = (ushort)ScreenMessengerIds.Full,
|
||||
Timeout = 1000,
|
||||
Timeout = 1000
|
||||
}).ContinueWith((result) =>
|
||||
{
|
||||
Interlocked.Exchange(ref cache.ScreenFlag, 1);
|
||||
@@ -60,7 +58,6 @@ namespace cmonitor.server.api.services
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public bool Region(ClientServiceParamsInfo param)
|
||||
{
|
||||
string[] names = param.Content.DeJson<string[]>();
|
||||
@@ -88,6 +85,12 @@ namespace cmonitor.server.api.services
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ScreenReportInfo
|
||||
{
|
||||
public string[] Names { get; set; }
|
||||
public byte Type { get; set; }
|
||||
}
|
||||
public sealed class ScreenClipParamInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace cmonitor.server.client.reports
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public object GetReports();
|
||||
public object GetReports(ReportType reportType);
|
||||
}
|
||||
|
||||
public sealed class ReportTransfer : IReport
|
||||
@@ -27,6 +27,8 @@ namespace cmonitor.server.client.reports
|
||||
|
||||
private List<IReport> reports;
|
||||
private Dictionary<string, object> reportObj;
|
||||
private ReportType reportType = ReportType.Full;
|
||||
|
||||
public ReportTransfer(ClientSignInState clientSignInState, MessengerSender messengerSender, ServiceProvider serviceProvider, Config config)
|
||||
{
|
||||
this.clientSignInState = clientSignInState;
|
||||
@@ -39,7 +41,7 @@ namespace cmonitor.server.client.reports
|
||||
}
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -53,8 +55,9 @@ namespace cmonitor.server.client.reports
|
||||
|
||||
private uint reportFlag = 0;
|
||||
private long ticks = 0;
|
||||
public void Update()
|
||||
public void Update(ReportType reportType)
|
||||
{
|
||||
this.reportType = reportType;
|
||||
ticks = DateTime.UtcNow.Ticks;
|
||||
Interlocked.CompareExchange(ref reportFlag, 1, 0);
|
||||
}
|
||||
@@ -90,7 +93,7 @@ namespace cmonitor.server.client.reports
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.Name) == false)
|
||||
{
|
||||
object val = item.GetReports();
|
||||
object val = item.GetReports(reportType);
|
||||
if (val != null)
|
||||
{
|
||||
reportObj[item.Name] = val;
|
||||
@@ -99,6 +102,7 @@ namespace cmonitor.server.client.reports
|
||||
}
|
||||
if (reportObj.Count > 0)
|
||||
{
|
||||
|
||||
string json = reportObj.ToJsonDefault();
|
||||
byte[] res = MemoryPackSerializer.Serialize(json);
|
||||
await messengerSender.SendOnly(new MessageRequestWrap
|
||||
@@ -110,4 +114,9 @@ namespace cmonitor.server.client.reports
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ReportType : byte
|
||||
{
|
||||
Full = 0, Trim = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ namespace cmonitor.server.client.reports.active
|
||||
}
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if (report.Pid != lastPid || report.Title != lastTitle)
|
||||
if (reportType == ReportType.Full || report.Pid != lastPid || report.Title != lastTitle)
|
||||
{
|
||||
lastPid = report.Pid;
|
||||
lastTitle = report.Title;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace cmonitor.server.client.reports.command
|
||||
{
|
||||
public string Name => "Command";
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ namespace cmonitor.server.client.reports.hijack
|
||||
|
||||
private readonly HijackEventHandler hijackEventHandler;
|
||||
private readonly HijackConfig hijackConfig;
|
||||
ulong[] array = new ulong[3];
|
||||
ulong[] lastArray = new ulong[3];
|
||||
private ulong[] array = new ulong[3];
|
||||
private ulong[] lastArray = new ulong[3];
|
||||
private long ticks = DateTime.UtcNow.Ticks;
|
||||
|
||||
public HijackReport(HijackEventHandler hijackEventHandler, HijackController hijackController, HijackConfig hijackConfig)
|
||||
{
|
||||
this.hijackEventHandler = hijackEventHandler;
|
||||
@@ -28,15 +30,17 @@ namespace cmonitor.server.client.reports.hijack
|
||||
}
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
array[0] = hijackEventHandler.UdpSend + hijackEventHandler.TcpSend;
|
||||
array[1] = hijackEventHandler.TcpReceive + hijackEventHandler.UdpReceive;
|
||||
ulong count = (ulong)(hijackConfig.AllowIPs.Length + hijackConfig.DeniedIPs.Length + hijackConfig.AllowDomains.Length + hijackConfig.DeniedDomains.Length + hijackConfig.AllowProcesss.Length + hijackConfig.DeniedProcesss.Length);
|
||||
array[2] = count;
|
||||
|
||||
if(array.SequenceEqual(lastArray) == false)
|
||||
long _ticks = DateTime.UtcNow.Ticks;
|
||||
if (((_ticks - ticks) / TimeSpan.TicksPerMillisecond >= 300 && array.SequenceEqual(lastArray) == false))
|
||||
{
|
||||
ticks = _ticks;
|
||||
lastArray[0] = array[0];
|
||||
lastArray[1] = array[1];
|
||||
lastArray[2] = array[2];
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if (report.Value != lastValue)
|
||||
if (reportType == ReportType.Full || report.Value != lastValue)
|
||||
{
|
||||
lastValue = report.Value;
|
||||
return report;
|
||||
|
||||
@@ -20,13 +20,13 @@ namespace cmonitor.server.client.reports.llock
|
||||
}
|
||||
|
||||
DateTime startTime = new DateTime(1970, 1, 1);
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if (shareReport.GetShare(Name, out ShareItemInfo share) && string.IsNullOrWhiteSpace(share.Value) == false && long.TryParse(share.Value, out long time))
|
||||
{
|
||||
report.Value = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds - time < 1000;
|
||||
}
|
||||
if(report.Value != lastValue)
|
||||
if(reportType == ReportType.Full || report.Value != lastValue)
|
||||
{
|
||||
lastValue = report.Value;
|
||||
return report;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace cmonitor.server.client.reports.notify
|
||||
{
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -21,7 +21,7 @@ namespace cmonitor.server.client.reports.notify
|
||||
Task.Run(() =>
|
||||
{
|
||||
CommandHelper.Windows(string.Empty, new string[] {
|
||||
$"start notify.win.exe {notify.Speed} \"{notify.Msg}\""
|
||||
$"start notify.win.exe {notify.Speed} \"{notify.Msg}\" {notify.Star}"
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -32,6 +32,7 @@ namespace cmonitor.server.client.reports.notify
|
||||
{
|
||||
public byte Speed { get; set; }
|
||||
public string Msg { get; set; }
|
||||
public byte Star { get; set; } = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MemoryPack;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
namespace cmonitor.server.client.reports.screen
|
||||
{
|
||||
public class DesktopFrame
|
||||
{
|
||||
@@ -8,12 +8,8 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
public Rectangle[] UpdatedRegions { get; internal set; }
|
||||
public Memory<byte> RegionImage { get; internal set; }
|
||||
|
||||
public int Width { get; internal set; }
|
||||
public int Height { get; internal set; }
|
||||
|
||||
public float ScaleX { get; internal set; }
|
||||
public float ScaleY { get; internal set; }
|
||||
//public MovedRegion[] MovedRegions { get; internal set; }
|
||||
public MovedRegion[] MovedRegions { get; internal set; }
|
||||
//public Rectangle[] Updateds { get; internal set; }
|
||||
|
||||
}
|
||||
@@ -25,6 +21,31 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
public Rectangle Destination { get; internal set; }
|
||||
}
|
||||
|
||||
public struct Scale
|
||||
{
|
||||
public Scale(int x, int y,float scale)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Value = scale;
|
||||
}
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public float Value { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public struct Rect
|
||||
{
|
||||
public Rect(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public partial struct Rectangle
|
||||
{
|
||||
@@ -8,13 +8,11 @@ using System.Runtime.InteropServices;
|
||||
using System.Drawing.Imaging;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
using common.libs;
|
||||
using common.libs.extends;
|
||||
using cmonitor.server.client.reports.screen.aforge;
|
||||
using System.Drawing.Drawing2D;
|
||||
using Factory1 = SharpDX.DXGI.Factory1;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
namespace cmonitor.server.client.reports.screen
|
||||
{
|
||||
public class DesktopDuplicator
|
||||
public sealed class DxgiDesktop
|
||||
{
|
||||
private Adapter1 adapter;
|
||||
private Device mDevice;
|
||||
@@ -28,18 +26,24 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
private ShaderResourceView smallerTextureView = null;
|
||||
private OutputDuplicateFrameInformation frameInfo = new OutputDuplicateFrameInformation();
|
||||
|
||||
public DesktopDuplicator(int whichMonitor)
|
||||
private int whichGraphicsCardAdapter;
|
||||
private int whichOutputDevice;
|
||||
|
||||
public DxgiDesktop(int whichMonitor)
|
||||
: this(0, whichMonitor) { }
|
||||
|
||||
public DesktopDuplicator(int whichGraphicsCardAdapter, int whichOutputDevice)
|
||||
public DxgiDesktop(int whichGraphicsCardAdapter, int whichOutputDevice)
|
||||
{
|
||||
this.whichGraphicsCardAdapter = whichGraphicsCardAdapter;
|
||||
this.whichOutputDevice = whichOutputDevice;
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
InitCapture(whichGraphicsCardAdapter, whichOutputDevice);
|
||||
InitCapture();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitCapture(int whichGraphicsCardAdapter, int whichOutputDevice)
|
||||
|
||||
private void InitAdapter()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -56,11 +60,15 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
}
|
||||
adapter = new Factory1().GetAdapter1(whichGraphicsCardAdapter);
|
||||
}
|
||||
catch (SharpDXException)
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("Could not find the specified graphics card adapter.");
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
|
||||
}
|
||||
private void InitDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mDevice != null)
|
||||
@@ -68,13 +76,17 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
mDevice.Dispose();
|
||||
mDevice = null;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
mDevice = new Device(adapter);
|
||||
|
||||
|
||||
}
|
||||
private void InitOutput()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
@@ -89,12 +101,14 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
{
|
||||
}
|
||||
output = adapter.GetOutput(whichOutputDevice);
|
||||
}
|
||||
catch (SharpDXException)
|
||||
{
|
||||
throw new Exception("Could not find the specified output device.");
|
||||
}
|
||||
mOutputDesc = output.Description;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (output1 != null)
|
||||
@@ -102,12 +116,17 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
output1.Dispose();
|
||||
output1 = null;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
output1 = output.QueryInterface<Output1>();
|
||||
this.mOutputDesc = output.Description;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
|
||||
}
|
||||
private void InitTexture()
|
||||
{
|
||||
int width = output1.Description.DesktopBounds.Right - output1.Description.DesktopBounds.Left;
|
||||
int height = output1.Description.DesktopBounds.Bottom - output1.Description.DesktopBounds.Top;
|
||||
|
||||
@@ -174,7 +193,9 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
{
|
||||
}
|
||||
smallerTextureView = new ShaderResourceView(mDevice, smallerTexture);
|
||||
|
||||
}
|
||||
private void InitDesk()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mDeskDupl != null)
|
||||
@@ -182,27 +203,138 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
mDeskDupl.Dispose();
|
||||
mDeskDupl = null;
|
||||
}
|
||||
this.mDeskDupl = output1.DuplicateOutput(mDevice);
|
||||
mDeskDupl = output1.DuplicateOutput(mDevice);
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.NotCurrentlyAvailable.Result.Code)
|
||||
{
|
||||
throw new Exception("There is already the maximum number of applications using the Desktop Duplication API running, please close one of the applications and try again.");
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error("There is already the maximum number of applications using the Desktop Duplication API running, please close one of the applications and try again.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
private void InitCapture()
|
||||
{
|
||||
try
|
||||
{
|
||||
InitAdapter();
|
||||
InitDevice();
|
||||
InitOutput();
|
||||
InitTexture();
|
||||
InitDesk();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
private bool RetrieveFrame()
|
||||
{
|
||||
SharpDX.DXGI.Resource desktopResource = null;
|
||||
try
|
||||
{
|
||||
|
||||
public DesktopFrame GetLatestFrame(ScreenReportType screenReportType, float configScale)
|
||||
Result result = mDeskDupl.TryAcquireNextFrame(100, out frameInfo, out desktopResource);
|
||||
if (desktopResource == null)
|
||||
{
|
||||
uint code = (uint)result.Code;
|
||||
//超时、GPU繁忙、暂时不可用
|
||||
if (code == 0x887A0027 || code == 0x887A000A || code == 0x887A0022)
|
||||
{
|
||||
//不需操作
|
||||
}
|
||||
//复制接口无效,比如切换了桌面
|
||||
else if (code == 0x887A0026)
|
||||
{
|
||||
InitDesk();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
InitDesk();
|
||||
return false;
|
||||
}
|
||||
|
||||
using Texture2D tempTexture = desktopResource.QueryInterface<Texture2D>();
|
||||
mDevice.ImmediateContext.CopySubresourceRegion(tempTexture, 0, null, smallerTexture, 0);
|
||||
|
||||
desktopResource.Dispose();
|
||||
return true;
|
||||
}
|
||||
private void RetrieveFrameMetadata(DesktopFrame frame)
|
||||
{
|
||||
if (frameInfo.TotalMetadataBufferSize > 0)
|
||||
{
|
||||
|
||||
OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[frameInfo.TotalMetadataBufferSize];
|
||||
mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out int movedRegionsLength);
|
||||
//Console.WriteLine($"movedRegionsLength:{movedRegionsLength}");
|
||||
frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
|
||||
for (int i = 0; i < frame.MovedRegions.Length; i++)
|
||||
{
|
||||
int width = movedRectangles[i].DestinationRect.Right - movedRectangles[i].DestinationRect.Left;
|
||||
int height = movedRectangles[i].DestinationRect.Bottom - movedRectangles[i].DestinationRect.Top;
|
||||
frame.MovedRegions[i] = new MovedRegion()
|
||||
{
|
||||
Source = new Point(movedRectangles[i].SourcePoint.X, movedRectangles[i].SourcePoint.Y),
|
||||
Destination = new Rectangle(movedRectangles[i].DestinationRect.Left, movedRectangles[i].DestinationRect.Top, width, height)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
RawRectangle[] dirtyRectangles = new RawRectangle[frameInfo.TotalMetadataBufferSize];
|
||||
mDeskDupl.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out int dirtyRegionsLength);
|
||||
frame.UpdatedRegions = new Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];
|
||||
for (int i = 0; i < frame.UpdatedRegions.Length; i++)
|
||||
{
|
||||
int width = dirtyRectangles[i].Right - dirtyRectangles[i].Left;
|
||||
int height = dirtyRectangles[i].Bottom - dirtyRectangles[i].Top;
|
||||
frame.UpdatedRegions[i] = new Rectangle(dirtyRectangles[i].Left, dirtyRectangles[i].Top, width, height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.MovedRegions = new MovedRegion[0];
|
||||
frame.UpdatedRegions = new Rectangle[0];
|
||||
}
|
||||
}
|
||||
private void ReleaseFrame()
|
||||
{
|
||||
try
|
||||
{
|
||||
mDeskDupl.ReleaseFrame();
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (ex.ResultCode.Failure)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
Logger.Instance.Error("Failed to release frame.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte[] fullImageBytes = Helper.EmptyArray;
|
||||
public DesktopFrame GetLatestFullFrame(float configScale)
|
||||
{
|
||||
DesktopFrame frame = new DesktopFrame() { FullImage = Helper.EmptyArray, RegionImage = Helper.EmptyArray };
|
||||
bool retrievalTimedOut = RetrieveFrame(frame, configScale);
|
||||
if (retrievalTimedOut)
|
||||
bool success = RetrieveFrame();
|
||||
if (success == false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -210,19 +342,172 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
try
|
||||
{
|
||||
RetrieveFrameMetadata(frame);
|
||||
if (frame.UpdatedRegions.Length > 0 || GdiCapture.IsClip())
|
||||
{
|
||||
if (screenReportType == ScreenReportType.Full)
|
||||
{
|
||||
ProcessFrameFull(frame, configScale);
|
||||
}
|
||||
else if (screenReportType == ScreenReportType.Region)
|
||||
catch
|
||||
{
|
||||
ReleaseFrame();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
ReleaseFrame();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
private unsafe void ProcessFrameFull(DesktopFrame frame, float configScale)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
try
|
||||
{
|
||||
mDevice.ImmediateContext.GenerateMips(smallerTextureView);
|
||||
|
||||
Rect sourceRect = new Rect(smallerTexture.Description.Width, smallerTexture.Description.Height);
|
||||
Rectangle sourceRectangle = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
|
||||
GetSystemScale(out float scaleX, out float scaleY, out int sourceWidth, out int sourceHeight);
|
||||
//画布尺寸
|
||||
GetNewSize(sourceRect, scaleX, scaleY, configScale, out Rect textureRect);
|
||||
//最终尺寸
|
||||
Rect distRect = textureRect;
|
||||
|
||||
//由于画布只能缩小2次方尺寸,需要计算一下
|
||||
int sourceSubresource = sourceRectangle.Width / textureRect.Width;
|
||||
if (sourceSubresource >= 0)
|
||||
{
|
||||
while (sourceSubresource > 0 && sourceRect.Width / (1 << sourceSubresource) < textureRect.Width)
|
||||
{
|
||||
sourceSubresource--;
|
||||
}
|
||||
if (sourceSubresource >= 3) sourceSubresource = 3;
|
||||
|
||||
textureRect.Width = sourceRect.Width / (1 << sourceSubresource);
|
||||
textureRect.Height = sourceRect.Height / (1 << sourceSubresource);
|
||||
}
|
||||
|
||||
//拷贝画布
|
||||
Texture2DDescription desc = desktopImageTexture.Description;
|
||||
desc.Width = textureRect.Width;
|
||||
desc.Height = textureRect.Height;
|
||||
using Texture2D texture = new Texture2D(mDevice, desc);
|
||||
mDevice.ImmediateContext.CopySubresourceRegion(smallerTexture, sourceSubresource, new ResourceRegion
|
||||
{
|
||||
Left = sourceRectangle.X,
|
||||
Right = sourceRectangle.X + sourceRectangle.Width,
|
||||
Top = sourceRectangle.Y,
|
||||
Bottom = sourceRectangle.Y + sourceRectangle.Height,
|
||||
Back = 1
|
||||
}, texture, 0, 0, 0);
|
||||
|
||||
//拷贝到图像
|
||||
DataBox mapSource = mDevice.ImmediateContext.MapSubresource(texture, 0, MapMode.Read, MapFlags.None);
|
||||
using Bitmap image = new Bitmap(desc.Width, desc.Height, PixelFormat.Format32bppArgb);
|
||||
System.Drawing.Rectangle boundsRect = new System.Drawing.Rectangle(0, 0, desc.Width, desc.Height);
|
||||
BitmapData mapDest = image.LockBits(boundsRect, ImageLockMode.WriteOnly, image.PixelFormat);
|
||||
nint sourcePtr = mapSource.DataPointer;
|
||||
nint destPtr = mapDest.Scan0;
|
||||
for (int y = 0; y < desc.Height; y++)
|
||||
{
|
||||
Utilities.CopyMemory(destPtr, sourcePtr, desc.Width * 4);
|
||||
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
|
||||
destPtr = IntPtr.Add(destPtr, mapDest.Stride);
|
||||
}
|
||||
image.UnlockBits(mapDest);
|
||||
mDevice.ImmediateContext.UnmapSubresource(texture, 0);
|
||||
|
||||
//弥补到最终尺寸
|
||||
Bitmap bmp = image;
|
||||
if (desc.Width - distRect.Width > 50)
|
||||
{
|
||||
bmp = new Bitmap(distRect.Width, distRect.Height);
|
||||
using Graphics graphic = Graphics.FromImage(bmp);
|
||||
graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, distRect.Width, distRect.Height), 0, 0, desc.Width, desc.Height, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
using Graphics g = Graphics.FromImage(bmp);
|
||||
WinApi.DrawCursorIcon(g, bmp.Width*1.0f/sourceRect.Width, bmp.Height*1.0f/sourceRect.Height);
|
||||
|
||||
//转字节数组
|
||||
using Image image1 = bmp;
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
image1.Save(ms, ImageFormat.Jpeg);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
int length = (int)ms.Length;
|
||||
if (length > fullImageBytes.Length)
|
||||
{
|
||||
fullImageBytes = new byte[length];
|
||||
}
|
||||
ms.Read(fullImageBytes.AsSpan(0, length));
|
||||
frame.FullImage = fullImageBytes.AsMemory(0, length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool GetSystemScale(out float x, out float y, out int sourceWidth, out int sourceHeight)
|
||||
{
|
||||
x = 1;
|
||||
y = 1;
|
||||
sourceWidth = 0;
|
||||
sourceHeight = 0;
|
||||
IntPtr hdc = WinApi.GetDC(IntPtr.Zero);
|
||||
if (hdc != IntPtr.Zero)
|
||||
{
|
||||
sourceWidth = WinApi.GetDeviceCaps(hdc, WinApi.DESKTOPHORZRES);
|
||||
sourceHeight = WinApi.GetDeviceCaps(hdc, WinApi.DESKTOPVERTRES);
|
||||
int screenWidth = WinApi.GetSystemMetrics(WinApi.SM_CXSCREEN);
|
||||
int screenHeight = WinApi.GetSystemMetrics(WinApi.SM_CYSCREEN);
|
||||
|
||||
x = (sourceWidth * 1.0f / screenWidth);
|
||||
y = (sourceHeight * 1.0f / screenHeight);
|
||||
|
||||
WinApi.ReleaseDC(IntPtr.Zero, hdc);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private bool GetNewSize(Rect sourceRect, float scaleX, float scaleY, float configScale, out Rect rect)
|
||||
{
|
||||
int width = (int)(sourceRect.Width * 1.0 / scaleX * configScale);
|
||||
int height = (int)(sourceRect.Height * 1.0 / scaleY * configScale);
|
||||
rect = new Rect(width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public DesktopFrame GetLatestRegionFrame(float configScale)
|
||||
{
|
||||
DesktopFrame frame = new DesktopFrame() { FullImage = Helper.EmptyArray, RegionImage = Helper.EmptyArray };
|
||||
bool success = RetrieveFrame();
|
||||
if (success == false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
RetrieveFrameMetadata(frame);
|
||||
|
||||
if (frame.UpdatedRegions.Length > 0)
|
||||
{
|
||||
frame.UpdatedRegions = Rectangle.UnionRectangles(frame.UpdatedRegions);
|
||||
ProcessFrameRegion(frame, configScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
ReleaseFrame();
|
||||
@@ -240,192 +525,6 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
private bool RetrieveFrame(DesktopFrame frame, float configScale)
|
||||
{
|
||||
SharpDX.DXGI.Resource desktopResource = null;
|
||||
try
|
||||
{
|
||||
mDeskDupl.TryAcquireNextFrame(500, out frameInfo, out desktopResource);
|
||||
if (desktopResource == null)
|
||||
{
|
||||
InitCapture(0,0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (ex.ResultCode.Failure)
|
||||
{
|
||||
throw new Exception("Failed to acquire next frame.");
|
||||
}
|
||||
}
|
||||
|
||||
int sourceWidth = smallerTexture.Description.Width;
|
||||
int sourceHeight = smallerTexture.Description.Height;
|
||||
|
||||
frame.Width = sourceWidth;
|
||||
frame.Height = sourceHeight;
|
||||
|
||||
GdiCapture.GetScale(out float scalex, out float scaley, out int sourceWidth1, out int sourceHeight1);
|
||||
frame.ScaleX = scalex;
|
||||
frame.ScaleY = scaley;
|
||||
|
||||
GdiCapture.CalcClip(sourceWidth, sourceHeight, out int left, out int top, out int _width, out int _height);
|
||||
|
||||
frame.Width = _width;
|
||||
frame.Height = _height;
|
||||
|
||||
using Texture2D tempTexture = desktopResource.QueryInterface<Texture2D>();
|
||||
mDevice.ImmediateContext.CopySubresourceRegion(tempTexture, 0, new ResourceRegion
|
||||
{
|
||||
Left = left,
|
||||
Top = top,
|
||||
Right = left + _width,
|
||||
Bottom = top + _height,
|
||||
Back = 1
|
||||
}, smallerTexture, 0);
|
||||
|
||||
desktopResource.Dispose();
|
||||
return false;
|
||||
}
|
||||
private void RetrieveFrameMetadata(DesktopFrame frame)
|
||||
{
|
||||
if (frameInfo.TotalMetadataBufferSize > 0)
|
||||
{
|
||||
/*
|
||||
OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[frameInfo.TotalMetadataBufferSize];
|
||||
mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out int movedRegionsLength);
|
||||
//Console.WriteLine($"movedRegionsLength:{movedRegionsLength}");
|
||||
frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
|
||||
for (int i = 0; i < frame.MovedRegions.Length; i++)
|
||||
{
|
||||
int width = movedRectangles[i].DestinationRect.Right - movedRectangles[i].DestinationRect.Left;
|
||||
int height = movedRectangles[i].DestinationRect.Bottom - movedRectangles[i].DestinationRect.Top;
|
||||
frame.MovedRegions[i] = new MovedRegion()
|
||||
{
|
||||
Source = new System.Drawing.Point(movedRectangles[i].SourcePoint.X, movedRectangles[i].SourcePoint.Y),
|
||||
Destination = new Rectangle(movedRectangles[i].DestinationRect.Left, movedRectangles[i].DestinationRect.Top, width, height)
|
||||
};
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
RawRectangle[] dirtyRectangles = new RawRectangle[frameInfo.TotalMetadataBufferSize];
|
||||
mDeskDupl.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out int dirtyRegionsLength);
|
||||
frame.UpdatedRegions = new Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];
|
||||
for (int i = 0; i < frame.UpdatedRegions.Length; i++)
|
||||
{
|
||||
int width = dirtyRectangles[i].Right - dirtyRectangles[i].Left;
|
||||
int height = dirtyRectangles[i].Bottom - dirtyRectangles[i].Top;
|
||||
frame.UpdatedRegions[i] = new Rectangle(dirtyRectangles[i].Left, dirtyRectangles[i].Top, width, height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//frame.MovedRegions = new MovedRegion[0];
|
||||
frame.UpdatedRegions = new Rectangle[0];
|
||||
}
|
||||
}
|
||||
|
||||
byte[] fullImageBytes = Helper.EmptyArray;
|
||||
private unsafe void ProcessFrameFull(DesktopFrame frame, float configScale)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
try
|
||||
{
|
||||
mDevice.ImmediateContext.GenerateMips(smallerTextureView);
|
||||
GdiCapture.GetNewSize(smallerTexture.Description.Width, smallerTexture.Description.Height, frame.ScaleX, frame.ScaleY, configScale, out int width, out int height);
|
||||
|
||||
int sourceSubresource = frame.Width / width;
|
||||
if (sourceSubresource >= 0)
|
||||
{
|
||||
while (sourceSubresource > 0 && smallerTexture.Description.Width / (1 << sourceSubresource) < width)
|
||||
{
|
||||
sourceSubresource--;
|
||||
}
|
||||
if (sourceSubresource >= 3) sourceSubresource = 3;
|
||||
frame.Width = smallerTexture.Description.Width / (1 << sourceSubresource);
|
||||
frame.Height = smallerTexture.Description.Height / (1 << sourceSubresource);
|
||||
}
|
||||
|
||||
mDevice.ImmediateContext.CopySubresourceRegion(smallerTexture, sourceSubresource, new ResourceRegion
|
||||
{
|
||||
Left = 0,
|
||||
Right = frame.Width,
|
||||
Top = 0,
|
||||
Bottom = frame.Height,
|
||||
Back = 1
|
||||
}, desktopImageTexture, 0);
|
||||
|
||||
|
||||
DataBox mapSource = mDevice.ImmediateContext.MapSubresource(desktopImageTexture, 0, MapMode.Read, MapFlags.None);
|
||||
using Bitmap image = new Bitmap(frame.Width, frame.Height, PixelFormat.Format32bppArgb);
|
||||
System.Drawing.Rectangle boundsRect = new System.Drawing.Rectangle(0, 0, frame.Width, frame.Height);
|
||||
BitmapData mapDest = image.LockBits(boundsRect, ImageLockMode.WriteOnly, image.PixelFormat);
|
||||
nint sourcePtr = mapSource.DataPointer;
|
||||
nint destPtr = mapDest.Scan0;
|
||||
for (int y = 0; y < frame.Height; y++)
|
||||
{
|
||||
Utilities.CopyMemory(destPtr, sourcePtr, frame.Width * 4);
|
||||
|
||||
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
|
||||
destPtr = IntPtr.Add(destPtr, mapDest.Stride);
|
||||
}
|
||||
image.UnlockBits(mapDest);
|
||||
mDevice.ImmediateContext.UnmapSubresource(desktopImageTexture, 0);
|
||||
|
||||
Bitmap bmp = image;
|
||||
if (frame.Width - width > 50)
|
||||
{
|
||||
bmp = new Bitmap(width, height);
|
||||
using Graphics graphic = Graphics.FromImage(bmp);
|
||||
graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, width, height), 0, 0, frame.Width, frame.Height, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
using System.Drawing.Image image1 = bmp;
|
||||
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
image1.Save(ms, ImageFormat.Jpeg);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
int length = (int)ms.Length;
|
||||
if (length > fullImageBytes.Length)
|
||||
{
|
||||
fullImageBytes = new byte[length];
|
||||
}
|
||||
ms.Read(fullImageBytes.AsSpan(0, length));
|
||||
frame.FullImage = fullImageBytes.AsMemory(0, length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
Logger.Instance.Error(ex);
|
||||
}
|
||||
desktopImageTexture.Dispose();
|
||||
desktopImageTexture = new Texture2D(mDevice, new Texture2DDescription()
|
||||
{
|
||||
CpuAccessFlags = CpuAccessFlags.Read,
|
||||
BindFlags = BindFlags.None,
|
||||
Format = Format.B8G8R8A8_UNorm,
|
||||
Width = smallerTexture.Description.Width,
|
||||
Height = smallerTexture.Description.Height,
|
||||
OptionFlags = ResourceOptionFlags.None,
|
||||
MipLevels = 1,
|
||||
ArraySize = 1,
|
||||
SampleDescription = { Count = 1, Quality = 0 },
|
||||
Usage = ResourceUsage.Staging
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] regionImageBytes = Helper.EmptyArray;
|
||||
private unsafe void ProcessFrameRegion(DesktopFrame frame, float configScale)
|
||||
{
|
||||
@@ -547,19 +646,6 @@ namespace cmonitor.server.client.reports.screen.sharpDX
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseFrame()
|
||||
{
|
||||
try
|
||||
{
|
||||
mDeskDupl.ReleaseFrame();
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (ex.ResultCode.Failure)
|
||||
{
|
||||
throw new Exception("Failed to release frame.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
using System.Buffers;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen
|
||||
{
|
||||
public sealed class GdiCapture
|
||||
{
|
||||
static ScreenClipInfo screenClipInfo = new ScreenClipInfo { X = 0, Y = 0, Scale = 1 };
|
||||
public static void Clip(ScreenClipInfo _screenClipInfo)
|
||||
{
|
||||
screenClipInfo = _screenClipInfo;
|
||||
}
|
||||
public static bool IsClip()
|
||||
{
|
||||
return screenClipInfo.Scale != 0;
|
||||
}
|
||||
public static void CalcClip(int sourceWidth, int sourceHeight, out int left, out int top, out int width, out int height)
|
||||
{
|
||||
CalcClip(sourceWidth, sourceHeight, screenClipInfo.X, screenClipInfo.Y, screenClipInfo.Scale, out left, out top, out width, out height);
|
||||
|
||||
}
|
||||
public static void CalcClip(int sourceWidth, int sourceHeight,int x,int y,float scale, out int left, out int top, out int width, out int height)
|
||||
{
|
||||
//缩放后宽高
|
||||
int newSourceWidth = (int)(sourceWidth * screenClipInfo.Scale);
|
||||
int newSourceHeight = (int)(sourceHeight * screenClipInfo.Scale);
|
||||
|
||||
//减去的宽高
|
||||
int clipWidth = (int)((newSourceWidth - sourceWidth) * 1.0 / newSourceWidth * sourceWidth);
|
||||
int clipHeight = (int)((newSourceHeight - sourceHeight) * 1.0 / newSourceHeight * sourceHeight);
|
||||
//留下的宽高
|
||||
width = sourceWidth - clipWidth;
|
||||
height = sourceHeight - clipHeight;
|
||||
|
||||
float scaleX = screenClipInfo.X * 1.0f / sourceWidth;
|
||||
float scaleY = screenClipInfo.Y * 1.0f / sourceHeight;
|
||||
|
||||
left = (int)(clipWidth * scaleX);
|
||||
top = (int)(clipHeight * scaleY);
|
||||
|
||||
}
|
||||
|
||||
public static void Return(byte[] bytes)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(bytes);
|
||||
}
|
||||
|
||||
public static bool GetScale(out float x, out float y, out int sourceWidth, out int sourceHeight)
|
||||
{
|
||||
x = 1;
|
||||
y = 1;
|
||||
sourceWidth = 0;
|
||||
sourceHeight = 0;
|
||||
IntPtr hdc = GetDC(IntPtr.Zero);
|
||||
if (hdc != IntPtr.Zero)
|
||||
{
|
||||
sourceWidth = GetDeviceCaps(hdc, DESKTOPHORZRES);
|
||||
sourceHeight = GetDeviceCaps(hdc, DESKTOPVERTRES);
|
||||
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
|
||||
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
x = (sourceWidth * 1.0f / screenWidth);
|
||||
y = (sourceHeight * 1.0f / screenHeight);
|
||||
|
||||
ReleaseDC(IntPtr.Zero, hdc);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static bool GetNewSize(int sourceWidth, int sourceHeight, float scaleX, float scaleY, float configScale, out int width, out int height)
|
||||
{
|
||||
width = (int)(sourceWidth * 1.0 / scaleX * configScale);
|
||||
height = (int)(sourceHeight * 1.0 / scaleY * configScale);
|
||||
return true;
|
||||
}
|
||||
public static void DrawCursorIcon(Graphics g, int sourceWidth, int scaleX, int scaleY, float configScale)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
int curWidth = (int)(sourceWidth * configScale * configScale);
|
||||
CURSORINFO pci;
|
||||
pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
|
||||
if (GetCursorInfo(out pci))
|
||||
{
|
||||
if (pci.flags == CURSOR_SHOWING)
|
||||
{
|
||||
var hdc1 = g.GetHdc();
|
||||
DrawIconEx(hdc1, pci.ptScreenPos.x * scaleX, pci.ptScreenPos.y * scaleY, pci.hCursor, curWidth, curWidth, 0, IntPtr.Zero, DI_NORMAL);
|
||||
g.ReleaseHdc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private const int DESKTOPVERTRES = 117;
|
||||
private const int DESKTOPHORZRES = 118;
|
||||
private const int SM_CXSCREEN = 0;
|
||||
private const int SM_CYSCREEN = 1;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetDC(IntPtr ptr);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
|
||||
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
|
||||
|
||||
[DllImport("gdi32.dll", EntryPoint = "GetDeviceCaps", SetLastError = true)]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
|
||||
private static extern int GetSystemMetrics(int mVal);
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct CURSORINFO
|
||||
{
|
||||
public Int32 cbSize;
|
||||
public Int32 flags;
|
||||
public IntPtr hCursor;
|
||||
public POINTAPI ptScreenPos;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct POINTAPI
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
}
|
||||
private const Int32 CURSOR_SHOWING = 0x0001;
|
||||
private const Int32 DI_NORMAL = 0x0003;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetCursorInfo(out CURSORINFO pci);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
static extern bool DrawIconEx(IntPtr hdc, int xLeft, int yTop, IntPtr hIcon, int cxWidth, int cyHeight, int istepIfAniCur, IntPtr hbrFlickerFreeDraw, int diFlags);
|
||||
}
|
||||
}
|
||||
136
cmonitor/server/client/reports/screen/GdiDesktop.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing;
|
||||
using common.libs;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen
|
||||
{
|
||||
public sealed class GdiDesktop
|
||||
{
|
||||
public GdiDesktop() { }
|
||||
|
||||
ScreenClipInfo screenClipInfo = new ScreenClipInfo { X = 0, Y = 0, Scale = 1 };
|
||||
public void Clip(ScreenClipInfo _screenClipInfo)
|
||||
{
|
||||
screenClipInfo = _screenClipInfo;
|
||||
}
|
||||
public bool IsClip()
|
||||
{
|
||||
return screenClipInfo.Scale != 1;
|
||||
}
|
||||
public bool IsLockScreen()
|
||||
{
|
||||
return WinApi.Locked();
|
||||
}
|
||||
|
||||
byte[] fullImageBytes = new byte[0];
|
||||
public DesktopFrame GetLatestFrame(float configScale)
|
||||
{
|
||||
DesktopFrame frame = new DesktopFrame { FullImage = Helper.EmptyArray, MovedRegions = new MovedRegion[0], RegionImage = Helper.EmptyArray, UpdatedRegions = new Rectangle[0] };
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
IntPtr hdc = WinApi.GetDC(IntPtr.Zero);
|
||||
if (hdc == IntPtr.Zero) return frame;
|
||||
|
||||
GetSystemScale(out float scaleX, out float scaleY, out int sourceWidth, out int sourceHeight);
|
||||
Rect sourceRect = new Rect(sourceWidth, sourceHeight);
|
||||
CalcClip(sourceRect, out Rectangle clipRectangle);
|
||||
GetNewSize(sourceRect, scaleX, scaleY, configScale, out Rect distRect);
|
||||
|
||||
using Bitmap image = new Bitmap(clipRectangle.Width, clipRectangle.Height);
|
||||
using (Graphics g = Graphics.FromImage(image))
|
||||
{
|
||||
g.CopyFromScreen(clipRectangle.X, clipRectangle.Y, 0, 0, image.Size, CopyPixelOperation.SourceCopy);
|
||||
g.Dispose();
|
||||
}
|
||||
WinApi.ReleaseDC(IntPtr.Zero, hdc);
|
||||
|
||||
Bitmap bmp = image;
|
||||
if (clipRectangle.Width - distRect.Width > 50)
|
||||
{
|
||||
bmp = new Bitmap(distRect.Width, distRect.Height);
|
||||
using Graphics graphic = Graphics.FromImage(bmp);
|
||||
graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, distRect.Width, distRect.Height), 0, 0, clipRectangle.Width, clipRectangle.Height, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
|
||||
using Image image1 = bmp;
|
||||
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
image1.Save(ms, ImageFormat.Jpeg);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
int length = (int)ms.Length;
|
||||
if (length > fullImageBytes.Length)
|
||||
{
|
||||
fullImageBytes = new byte[length];
|
||||
}
|
||||
ms.Read(fullImageBytes.AsSpan(0, length));
|
||||
frame.FullImage = fullImageBytes.AsMemory(0, length);
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
private void CalcClip(Rect sourceRect, out Rectangle rectangle)
|
||||
{
|
||||
Scale scale = new Scale(screenClipInfo.X, screenClipInfo.Y, screenClipInfo.Scale);
|
||||
CalcClip(sourceRect, scale, out rectangle);
|
||||
|
||||
}
|
||||
private void CalcClip(Rect sourceRect, Scale scale, out Rectangle rectangle)
|
||||
{
|
||||
//缩放后宽高
|
||||
int newSourceWidth = (int)(sourceRect.Width * scale.Value);
|
||||
int newSourceHeight = (int)(sourceRect.Height * scale.Value);
|
||||
|
||||
//减去的宽高
|
||||
int clipWidth = (int)((newSourceWidth - sourceRect.Width) * 1.0 / newSourceWidth * sourceRect.Width);
|
||||
int clipHeight = (int)((newSourceHeight - sourceRect.Height) * 1.0 / newSourceHeight * sourceRect.Height);
|
||||
//留下的宽高
|
||||
int width = sourceRect.Width - clipWidth;
|
||||
int height = sourceRect.Height - clipHeight;
|
||||
|
||||
float scaleX = scale.X * 1.0f / sourceRect.Width;
|
||||
float scaleY = scale.Y * 1.0f / sourceRect.Height;
|
||||
|
||||
int left = (int)(clipWidth * scaleX);
|
||||
int top = (int)(clipHeight * scaleY);
|
||||
|
||||
rectangle = new Rectangle(left, top, width, height);
|
||||
|
||||
}
|
||||
|
||||
private bool GetSystemScale(out float x, out float y, out int sourceWidth, out int sourceHeight)
|
||||
{
|
||||
x = 1;
|
||||
y = 1;
|
||||
sourceWidth = 0;
|
||||
sourceHeight = 0;
|
||||
IntPtr hdc = WinApi.GetDC(IntPtr.Zero);
|
||||
if (hdc != IntPtr.Zero)
|
||||
{
|
||||
sourceWidth = WinApi.GetDeviceCaps(hdc, WinApi.DESKTOPHORZRES);
|
||||
sourceHeight = WinApi.GetDeviceCaps(hdc, WinApi.DESKTOPVERTRES);
|
||||
int screenWidth = WinApi.GetSystemMetrics(WinApi.SM_CXSCREEN);
|
||||
int screenHeight = WinApi.GetSystemMetrics(WinApi.SM_CYSCREEN);
|
||||
|
||||
x = (sourceWidth * 1.0f / screenWidth);
|
||||
y = (sourceHeight * 1.0f / screenHeight);
|
||||
|
||||
WinApi.ReleaseDC(IntPtr.Zero, hdc);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private bool GetNewSize(Rect sourceRect, float scaleX, float scaleY, float configScale, out Rect rect)
|
||||
{
|
||||
int width = (int)(sourceRect.Width * 1.0 / scaleX * configScale);
|
||||
int height = (int)(sourceRect.Height * 1.0 / scaleY * configScale);
|
||||
rect = new Rect(width, height);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using cmonitor.server.service;
|
||||
using common.libs;
|
||||
using cmonitor.server.service.messengers.screen;
|
||||
using System.Runtime.InteropServices;
|
||||
using MemoryPack;
|
||||
using cmonitor.server.client.reports.screen.sharpDX;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen
|
||||
@@ -18,7 +16,8 @@ namespace cmonitor.server.client.reports.screen
|
||||
|
||||
private ScreenReportInfo report = new ScreenReportInfo();
|
||||
private uint lastInput;
|
||||
private readonly DesktopDuplicator desktopDuplicator;
|
||||
private readonly DxgiDesktop dxgiDesktop;
|
||||
private readonly GdiDesktop gdiDesktop;
|
||||
|
||||
public ScreenReport(ClientSignInState clientSignInState, MessengerSender messengerSender, Config config)
|
||||
{
|
||||
@@ -28,13 +27,15 @@ namespace cmonitor.server.client.reports.screen
|
||||
if (config.IsCLient)
|
||||
{
|
||||
ScreenCaptureTask();
|
||||
InitLastInputInfo();
|
||||
WinApi.InitLastInputInfo();
|
||||
dxgiDesktop = new DxgiDesktop(0);
|
||||
gdiDesktop = new GdiDesktop();
|
||||
}
|
||||
desktopDuplicator = new DesktopDuplicator(0);
|
||||
|
||||
}
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
report.LT = GetLastInputInfo();
|
||||
report.LT = WinApi.GetLastInputInfo();
|
||||
if (report.LT < lastInput || report.LT - lastInput > 1000)
|
||||
{
|
||||
lastInput = report.LT;
|
||||
@@ -44,7 +45,6 @@ namespace cmonitor.server.client.reports.screen
|
||||
}
|
||||
|
||||
|
||||
#region 截图
|
||||
private ScreenReportType screenReportType = ScreenReportType.None;
|
||||
private long ticks = 0;
|
||||
public void Full()
|
||||
@@ -54,7 +54,9 @@ namespace cmonitor.server.client.reports.screen
|
||||
}
|
||||
public void Clip(ScreenClipInfo screenClipInfo)
|
||||
{
|
||||
GdiCapture.Clip(screenClipInfo);
|
||||
ticks = DateTime.UtcNow.Ticks;
|
||||
screenReportType = ScreenReportType.Full;
|
||||
gdiDesktop.Clip(screenClipInfo);
|
||||
}
|
||||
public void Region()
|
||||
{
|
||||
@@ -73,10 +75,7 @@ namespace cmonitor.server.client.reports.screen
|
||||
while (true)
|
||||
{
|
||||
int delayms = 0;
|
||||
bool res = clientSignInState.Connected == true
|
||||
&& screenReportType > ScreenReportType.None
|
||||
&& (DateTime.UtcNow.Ticks - ticks) / TimeSpan.TicksPerMillisecond < 1000;
|
||||
if (res)
|
||||
if (clientSignInState.Connected == true && ((DateTime.UtcNow.Ticks - ticks) / TimeSpan.TicksPerMillisecond < 1000))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -102,12 +101,25 @@ namespace cmonitor.server.client.reports.screen
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
private async Task SendScreenCapture()
|
||||
{
|
||||
DesktopFrame frame = null;
|
||||
if (gdiDesktop.IsClip()/*|| gdiDesktop.IsLockScreen()*/)
|
||||
{
|
||||
frame = gdiDesktop.GetLatestFrame(config.ScreenScale);
|
||||
}
|
||||
else if (screenReportType == ScreenReportType.Full)
|
||||
{
|
||||
//var sw = new Stopwatch();
|
||||
//sw.Start();
|
||||
DesktopFrame frame = desktopDuplicator.GetLatestFrame(screenReportType, config.ScreenScale);
|
||||
frame = dxgiDesktop.GetLatestFullFrame(config.ScreenScale);
|
||||
//sw.Stop();
|
||||
// Console.WriteLine($"{frame.FullImage.Length}->{sw.ElapsedMilliseconds}");
|
||||
//Console.WriteLine(sw.ElapsedMilliseconds);
|
||||
}
|
||||
else if (screenReportType == ScreenReportType.Region)
|
||||
{
|
||||
frame = dxgiDesktop.GetLatestRegionFrame(config.ScreenScale);
|
||||
}
|
||||
|
||||
if (frame != null)
|
||||
{
|
||||
if (frame.FullImage.Length > 0)
|
||||
@@ -128,47 +140,18 @@ namespace cmonitor.server.client.reports.screen
|
||||
Payload = frame.RegionImage,
|
||||
});
|
||||
}
|
||||
/*
|
||||
if (frame.Updateds.Length > 0)
|
||||
if (frame.UpdatedRegions.Length > 0)
|
||||
{
|
||||
await messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)ScreenMessengerIds.Rectangles,
|
||||
Payload = MemoryPackSerializer.Serialize(frame.Updateds),
|
||||
Payload = MemoryPackSerializer.Serialize(frame.UpdatedRegions),
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 最后活动时间
|
||||
private LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
|
||||
private void InitLastInputInfo()
|
||||
{
|
||||
lastInputInfo.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
|
||||
}
|
||||
private uint GetLastInputInfo()
|
||||
{
|
||||
bool res = GetLastInputInfo(ref lastInputInfo);
|
||||
if (res)
|
||||
{
|
||||
return (uint)Environment.TickCount - lastInputInfo.dwTime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct LASTINPUTINFO
|
||||
{
|
||||
public uint cbSize;
|
||||
public uint dwTime;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public sealed class ScreenReportInfo
|
||||
|
||||
204
cmonitor/server/client/reports/screen/WinApi.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen
|
||||
{
|
||||
public sealed class WinApi
|
||||
{
|
||||
|
||||
public static void DrawCursorIcon(Graphics g, int sourceWidth, float scaleX, float scaleY, float configScale)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
int curWidth = (int)(sourceWidth * configScale * configScale);
|
||||
CURSORINFO pci;
|
||||
pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
|
||||
if (GetCursorInfo(out pci))
|
||||
{
|
||||
if (pci.flags == CURSOR_SHOWING)
|
||||
{
|
||||
var hdc1 = g.GetHdc();
|
||||
DrawIconEx(hdc1, (int)(pci.ptScreenPos.x * scaleX), (int)(pci.ptScreenPos.y * scaleY), pci.hCursor, curWidth, curWidth, 0, IntPtr.Zero, DI_NORMAL);
|
||||
g.ReleaseHdc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawCursorIcon(Graphics g, float scaleX, float scaleY)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
CURSORINFO pci;
|
||||
pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
|
||||
if (GetCursorInfo(out pci))
|
||||
{
|
||||
if (pci.flags == CURSOR_SHOWING)
|
||||
{
|
||||
using System.Drawing.Icon icon = System.Drawing.Icon.FromHandle(pci.hCursor);
|
||||
|
||||
g.DrawIcon(icon, new System.Drawing.Rectangle(new Point((int)(pci.ptScreenPos.x * scaleX), (int)(pci.ptScreenPos.y * scaleY)), icon.Size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct CURSORINFO
|
||||
{
|
||||
public Int32 cbSize;
|
||||
public Int32 flags;
|
||||
public IntPtr hCursor;
|
||||
public POINTAPI ptScreenPos;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct POINTAPI
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IconInfo
|
||||
{
|
||||
public bool fIcon;
|
||||
public int xHotspot;
|
||||
public int yHotspot;
|
||||
public IntPtr hbmMask;
|
||||
public IntPtr hbmColor;
|
||||
}
|
||||
private const Int32 CURSOR_SHOWING = 0x0001;
|
||||
private const Int32 DI_NORMAL = 0x0003;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetCursorInfo(out CURSORINFO pci);
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool GetIconInfo(IntPtr hIcon, out IconInfo piconinfo);
|
||||
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
static extern bool DrawIconEx(IntPtr hdc, int xLeft, int yTop, IntPtr hIcon, int cxWidth, int cyHeight, int istepIfAniCur, IntPtr hbrFlickerFreeDraw, int diFlags);
|
||||
|
||||
|
||||
public const int DESKTOPVERTRES = 117;
|
||||
public const int DESKTOPHORZRES = 118;
|
||||
public const int SM_CXSCREEN = 0;
|
||||
public const int SM_CYSCREEN = 1;
|
||||
public const int SM_REMOTESESSION = 0x1000;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetDC(IntPtr ptr);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
|
||||
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
|
||||
|
||||
[DllImport("gdi32.dll", EntryPoint = "GetDeviceCaps", SetLastError = true)]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
|
||||
public static extern int GetSystemMetrics(int mVal);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region 最后活动时间
|
||||
private static LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
|
||||
public static void InitLastInputInfo()
|
||||
{
|
||||
lastInputInfo.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
|
||||
}
|
||||
public static uint GetLastInputInfo()
|
||||
{
|
||||
bool res = GetLastInputInfo(ref lastInputInfo);
|
||||
if (res)
|
||||
{
|
||||
return (uint)Environment.TickCount - lastInputInfo.dwTime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct LASTINPUTINFO
|
||||
{
|
||||
public uint cbSize;
|
||||
public uint dwTime;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
[DllImport("wtsapi32.dll")]
|
||||
static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned);
|
||||
[DllImport("wtsapi32.dll")]
|
||||
static extern void WTSFreeMemory(IntPtr pMemory);
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct WTSINFO
|
||||
{
|
||||
public int SessionId;
|
||||
public int WinStationNameLen;
|
||||
public string WinStationName;
|
||||
public int State;
|
||||
}
|
||||
enum WTS_INFO_CLASS
|
||||
{
|
||||
WTSInitialProgram,
|
||||
WTSApplicationName,
|
||||
WTSWorkingDirectory,
|
||||
WTSOEMId,
|
||||
WTSSessionId,
|
||||
WTSUserName,
|
||||
WTSWinStationName,
|
||||
WTSDomainName,
|
||||
WTSConnectState,
|
||||
WTSClientBuildNumber,
|
||||
WTSClientName,
|
||||
WTSClientDirectory,
|
||||
WTSClientProductId,
|
||||
WTSClientHardwareId,
|
||||
WTSClientAddress,
|
||||
WTSClientDisplay,
|
||||
WTSClientProtocolType,
|
||||
WTSIdleTime,
|
||||
WTSLogonTime,
|
||||
WTSIncomingBytes,
|
||||
WTSOutgoingBytes,
|
||||
WTSIncomingFrames,
|
||||
WTSOutgoingFrames,
|
||||
WTSClientInfo,
|
||||
WTSSessionInfo,
|
||||
WTSConfigInfo,
|
||||
WTSShadowInfo,
|
||||
WTSValidConnectionTypes,
|
||||
WTSRemoteAddressV4,
|
||||
WTSRemoteAddressV6,
|
||||
WTSIsRemoteSession
|
||||
}
|
||||
public static bool Locked()
|
||||
{
|
||||
IntPtr buffer = IntPtr.Zero;
|
||||
uint bytesReturned = 0;
|
||||
try
|
||||
{
|
||||
bool result = WTSQuerySessionInformation(IntPtr.Zero, -1, WTS_INFO_CLASS.WTSSessionInfo, out buffer, out bytesReturned);
|
||||
|
||||
if (result)
|
||||
{
|
||||
WTSINFO sessionInfo = (WTSINFO)Marshal.PtrToStructure(buffer, typeof(WTSINFO));
|
||||
|
||||
return sessionInfo.State == 0;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (buffer != IntPtr.Zero)
|
||||
{
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
public abstract class BaseResizeFilter : BaseTransformationFilter
|
||||
{
|
||||
protected int newWidth;
|
||||
|
||||
protected int newHeight;
|
||||
|
||||
public int NewWidth
|
||||
{
|
||||
get { return newWidth; }
|
||||
set { newWidth = Math.Max( 1, value ); }
|
||||
}
|
||||
|
||||
public int NewHeight
|
||||
{
|
||||
get { return newHeight; }
|
||||
set { newHeight = Math.Max( 1, value ); }
|
||||
}
|
||||
|
||||
protected BaseResizeFilter( int newWidth, int newHeight )
|
||||
{
|
||||
this.newWidth = newWidth;
|
||||
this.newHeight = newHeight;
|
||||
}
|
||||
|
||||
protected override Size CalculateNewImageSize()
|
||||
{
|
||||
return new Size( newWidth, newHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
|
||||
public abstract class BaseTransformationFilter
|
||||
{
|
||||
public abstract Dictionary<PixelFormat, PixelFormat> FormatTranslations { get; }
|
||||
|
||||
public Bitmap Apply(Bitmap image,int x,int y,int width,int height)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
BitmapData srcData = image.LockBits(
|
||||
new Rectangle(x, y, width, height),
|
||||
ImageLockMode.ReadOnly, image.PixelFormat);
|
||||
|
||||
Bitmap dstImage = null;
|
||||
|
||||
try
|
||||
{
|
||||
dstImage = Apply(srcData);
|
||||
if ((image.HorizontalResolution > 0) && (image.VerticalResolution > 0))
|
||||
{
|
||||
dstImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
image.UnlockBits(srcData);
|
||||
}
|
||||
|
||||
return dstImage;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Bitmap Apply(BitmapData imageData)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
CheckSourceFormat(imageData.PixelFormat);
|
||||
|
||||
PixelFormat dstPixelFormat = FormatTranslations[imageData.PixelFormat];
|
||||
|
||||
Size newSize = CalculateNewImageSize();
|
||||
|
||||
Bitmap dstImage = (dstPixelFormat == PixelFormat.Format8bppIndexed) ?
|
||||
cmonitor.server.client.reports.screen.aforge.Image.CreateGrayscaleImage(newSize.Width, newSize.Height) :
|
||||
new Bitmap(newSize.Width, newSize.Height, dstPixelFormat);
|
||||
|
||||
BitmapData dstData = dstImage.LockBits(
|
||||
new Rectangle(0, 0, newSize.Width, newSize.Height),
|
||||
ImageLockMode.ReadWrite, dstPixelFormat);
|
||||
|
||||
try
|
||||
{
|
||||
ProcessFilter(new UnmanagedImage(imageData), new UnmanagedImage(dstData));
|
||||
}
|
||||
finally
|
||||
{
|
||||
dstImage.UnlockBits(dstData);
|
||||
}
|
||||
|
||||
return dstImage;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public UnmanagedImage Apply(UnmanagedImage image)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
CheckSourceFormat(image.PixelFormat);
|
||||
|
||||
Size newSize = CalculateNewImageSize();
|
||||
|
||||
UnmanagedImage dstImage = UnmanagedImage.Create(newSize.Width, newSize.Height, FormatTranslations[image.PixelFormat]);
|
||||
|
||||
ProcessFilter(image, dstImage);
|
||||
|
||||
return dstImage;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Apply(UnmanagedImage sourceImage, UnmanagedImage destinationImage)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
CheckSourceFormat(sourceImage.PixelFormat);
|
||||
|
||||
if (destinationImage.PixelFormat != FormatTranslations[sourceImage.PixelFormat])
|
||||
{
|
||||
throw new Exception("Destination pixel format is specified incorrectly.");
|
||||
}
|
||||
|
||||
Size newSize = CalculateNewImageSize();
|
||||
|
||||
if ((destinationImage.Width != newSize.Width) || (destinationImage.Height != newSize.Height))
|
||||
{
|
||||
throw new Exception("Destination image must have the size expected by the filter.");
|
||||
}
|
||||
|
||||
ProcessFilter(sourceImage, destinationImage);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract System.Drawing.Size CalculateNewImageSize();
|
||||
|
||||
protected abstract unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData);
|
||||
|
||||
private void CheckSourceFormat(PixelFormat pixelFormat)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
if (!FormatTranslations.ContainsKey(pixelFormat))
|
||||
throw new Exception("Source pixel format is not supported by the filter.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
public class RGB
|
||||
{
|
||||
public const short R = 2;
|
||||
|
||||
public const short G = 1;
|
||||
|
||||
public const short B = 0;
|
||||
|
||||
public const short A = 3;
|
||||
|
||||
public byte Red;
|
||||
|
||||
public byte Green;
|
||||
|
||||
public byte Blue;
|
||||
|
||||
public byte Alpha;
|
||||
|
||||
public System.Drawing.Color Color
|
||||
{
|
||||
get { return Color.FromArgb( Alpha, Red, Green, Blue ); }
|
||||
set
|
||||
{
|
||||
Red = value.R;
|
||||
Green = value.G;
|
||||
Blue = value.B;
|
||||
Alpha = value.A;
|
||||
}
|
||||
}
|
||||
|
||||
public RGB( )
|
||||
{
|
||||
Red = 0;
|
||||
Green = 0;
|
||||
Blue = 0;
|
||||
Alpha = 255;
|
||||
}
|
||||
|
||||
public RGB( byte red, byte green, byte blue )
|
||||
{
|
||||
this.Red = red;
|
||||
this.Green = green;
|
||||
this.Blue = blue;
|
||||
this.Alpha = 255;
|
||||
}
|
||||
|
||||
public RGB( byte red, byte green, byte blue, byte alpha )
|
||||
{
|
||||
this.Red = red;
|
||||
this.Green = green;
|
||||
this.Blue = blue;
|
||||
this.Alpha = alpha;
|
||||
}
|
||||
|
||||
public RGB( System.Drawing.Color color )
|
||||
{
|
||||
this.Red = color.R;
|
||||
this.Green = color.G;
|
||||
this.Blue = color.B;
|
||||
this.Alpha = color.A;
|
||||
}
|
||||
}
|
||||
|
||||
public class HSL
|
||||
{
|
||||
public int Hue;
|
||||
|
||||
public float Saturation;
|
||||
|
||||
public float Luminance;
|
||||
|
||||
public HSL( ) { }
|
||||
|
||||
public HSL( int hue, float saturation, float luminance )
|
||||
{
|
||||
this.Hue = hue;
|
||||
this.Saturation = saturation;
|
||||
this.Luminance = luminance;
|
||||
}
|
||||
|
||||
public static void FromRGB( RGB rgb, HSL hsl )
|
||||
{
|
||||
float r = ( rgb.Red / 255.0f );
|
||||
float g = ( rgb.Green / 255.0f );
|
||||
float b = ( rgb.Blue / 255.0f );
|
||||
|
||||
float min = Math.Min( Math.Min( r, g ), b );
|
||||
float max = Math.Max( Math.Max( r, g ), b );
|
||||
float delta = max - min;
|
||||
|
||||
// get luminance value
|
||||
hsl.Luminance = ( max + min ) / 2;
|
||||
|
||||
if ( delta == 0 )
|
||||
{
|
||||
// gray color
|
||||
hsl.Hue = 0;
|
||||
hsl.Saturation = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get saturation value
|
||||
hsl.Saturation = ( hsl.Luminance <= 0.5 ) ? ( delta / ( max + min ) ) : ( delta / ( 2 - max - min ) );
|
||||
|
||||
// get hue value
|
||||
float hue;
|
||||
|
||||
if ( r == max )
|
||||
{
|
||||
hue = ( ( g - b ) / 6 ) / delta;
|
||||
}
|
||||
else if ( g == max )
|
||||
{
|
||||
hue = ( 1.0f / 3 ) + ( ( b - r ) / 6 ) / delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = ( 2.0f / 3 ) + ( ( r - g ) / 6 ) / delta;
|
||||
}
|
||||
|
||||
// correct hue if needed
|
||||
if ( hue < 0 )
|
||||
hue += 1;
|
||||
if ( hue > 1 )
|
||||
hue -= 1;
|
||||
|
||||
hsl.Hue = (int) ( hue * 360 );
|
||||
}
|
||||
}
|
||||
|
||||
public static HSL FromRGB( RGB rgb )
|
||||
{
|
||||
HSL hsl = new HSL( );
|
||||
FromRGB( rgb, hsl );
|
||||
return hsl;
|
||||
}
|
||||
|
||||
public static void ToRGB( HSL hsl, RGB rgb )
|
||||
{
|
||||
if ( hsl.Saturation == 0 )
|
||||
{
|
||||
// gray values
|
||||
rgb.Red = rgb.Green = rgb.Blue = (byte) ( hsl.Luminance * 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
float v1, v2;
|
||||
float hue = (float) hsl.Hue / 360;
|
||||
|
||||
v2 = ( hsl.Luminance < 0.5 ) ?
|
||||
( hsl.Luminance * ( 1 + hsl.Saturation ) ) :
|
||||
( ( hsl.Luminance + hsl.Saturation ) - ( hsl.Luminance * hsl.Saturation ) );
|
||||
v1 = 2 * hsl.Luminance - v2;
|
||||
|
||||
rgb.Red = (byte) ( 255 * Hue_2_RGB( v1, v2, hue + ( 1.0f / 3 ) ) );
|
||||
rgb.Green = (byte) ( 255 * Hue_2_RGB( v1, v2, hue ) );
|
||||
rgb.Blue = (byte) ( 255 * Hue_2_RGB( v1, v2, hue - ( 1.0f / 3 ) ) );
|
||||
}
|
||||
rgb.Alpha = 255;
|
||||
}
|
||||
|
||||
public RGB ToRGB( )
|
||||
{
|
||||
RGB rgb = new RGB( );
|
||||
ToRGB( this, rgb );
|
||||
return rgb;
|
||||
}
|
||||
|
||||
#region Private members
|
||||
// HSL to RGB helper routine
|
||||
private static float Hue_2_RGB( float v1, float v2, float vH )
|
||||
{
|
||||
if ( vH < 0 )
|
||||
vH += 1;
|
||||
if ( vH > 1 )
|
||||
vH -= 1;
|
||||
if ( ( 6 * vH ) < 1 )
|
||||
return ( v1 + ( v2 - v1 ) * 6 * vH );
|
||||
if ( ( 2 * vH ) < 1 )
|
||||
return v2;
|
||||
if ( ( 3 * vH ) < 2 )
|
||||
return ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3 ) - vH ) * 6 );
|
||||
return v1;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class YCbCr
|
||||
{
|
||||
public const short YIndex = 0;
|
||||
|
||||
public const short CbIndex = 1;
|
||||
|
||||
public const short CrIndex = 2;
|
||||
|
||||
public float Y;
|
||||
|
||||
public float Cb;
|
||||
|
||||
public float Cr;
|
||||
|
||||
public YCbCr( ) { }
|
||||
|
||||
public YCbCr( float y, float cb, float cr )
|
||||
{
|
||||
this.Y = Math.Max( 0.0f, Math.Min( 1.0f, y ) );
|
||||
this.Cb = Math.Max( -0.5f, Math.Min( 0.5f, cb ) );
|
||||
this.Cr = Math.Max( -0.5f, Math.Min( 0.5f, cr ) );
|
||||
}
|
||||
|
||||
public static void FromRGB( RGB rgb, YCbCr ycbcr )
|
||||
{
|
||||
float r = (float) rgb.Red / 255;
|
||||
float g = (float) rgb.Green / 255;
|
||||
float b = (float) rgb.Blue / 255;
|
||||
|
||||
ycbcr.Y = (float) ( 0.2989 * r + 0.5866 * g + 0.1145 * b );
|
||||
ycbcr.Cb = (float) ( -0.1687 * r - 0.3313 * g + 0.5000 * b );
|
||||
ycbcr.Cr = (float) ( 0.5000 * r - 0.4184 * g - 0.0816 * b );
|
||||
}
|
||||
public static YCbCr FromRGB( RGB rgb )
|
||||
{
|
||||
YCbCr ycbcr = new YCbCr( );
|
||||
FromRGB( rgb, ycbcr );
|
||||
return ycbcr;
|
||||
}
|
||||
|
||||
public static void ToRGB( YCbCr ycbcr, RGB rgb )
|
||||
{
|
||||
// don't warry about zeros. compiler will remove them
|
||||
float r = Math.Max( 0.0f, Math.Min( 1.0f, (float) ( ycbcr.Y + 0.0000 * ycbcr.Cb + 1.4022 * ycbcr.Cr ) ) );
|
||||
float g = Math.Max( 0.0f, Math.Min( 1.0f, (float) ( ycbcr.Y - 0.3456 * ycbcr.Cb - 0.7145 * ycbcr.Cr ) ) );
|
||||
float b = Math.Max( 0.0f, Math.Min( 1.0f, (float) ( ycbcr.Y + 1.7710 * ycbcr.Cb + 0.0000 * ycbcr.Cr ) ) );
|
||||
|
||||
rgb.Red = (byte) ( r * 255 );
|
||||
rgb.Green = (byte) ( g * 255 );
|
||||
rgb.Blue = (byte) ( b * 255 );
|
||||
rgb.Alpha = 255;
|
||||
}
|
||||
|
||||
public RGB ToRGB( )
|
||||
{
|
||||
RGB rgb = new RGB( );
|
||||
ToRGB( this, rgb );
|
||||
return rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
|
||||
[Serializable]
|
||||
public struct DoublePoint
|
||||
{
|
||||
public double X;
|
||||
|
||||
public double Y;
|
||||
|
||||
public DoublePoint( double x, double y )
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public static bool operator ==( DoublePoint point1, DoublePoint point2 )
|
||||
{
|
||||
return ( ( point1.X == point2.X ) && ( point1.Y == point2.Y ) );
|
||||
}
|
||||
|
||||
public static bool operator !=( DoublePoint point1, DoublePoint point2 )
|
||||
{
|
||||
return ( ( point1.X != point2.X ) || ( point1.Y != point2.Y ) );
|
||||
}
|
||||
|
||||
public override bool Equals( object obj )
|
||||
{
|
||||
return ( obj is DoublePoint ) ? ( this == (DoublePoint) obj ) : false;
|
||||
}
|
||||
|
||||
public override int GetHashCode( )
|
||||
{
|
||||
return X.GetHashCode( ) + Y.GetHashCode( );
|
||||
}
|
||||
|
||||
public static explicit operator IntPoint( DoublePoint point )
|
||||
{
|
||||
return new IntPoint( (int) point.X, (int) point.Y );
|
||||
}
|
||||
|
||||
public static explicit operator Point( DoublePoint point )
|
||||
{
|
||||
return new Point( (float) point.X, (float) point.Y );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
public static class Image
|
||||
{
|
||||
public static bool IsGrayscale(Bitmap image)
|
||||
{
|
||||
|
||||
bool ret = false;
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
if (image.PixelFormat == PixelFormat.Format8bppIndexed)
|
||||
{
|
||||
ret = true;
|
||||
ColorPalette cp = image.Palette;
|
||||
Color c;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
c = cp.Entries[i];
|
||||
if ((c.R != i) || (c.G != i) || (c.B != i))
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Bitmap CreateGrayscaleImage(int width, int height)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
Bitmap image = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
||||
SetGrayscalePalette(image);
|
||||
return image;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void SetGrayscalePalette(Bitmap image)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
if (image.PixelFormat != PixelFormat.Format8bppIndexed)
|
||||
throw new Exception("Source image is not 8 bpp image.");
|
||||
|
||||
ColorPalette cp = image.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(i, i, i);
|
||||
}
|
||||
image.Palette = cp;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetPixelFormatSize(PixelFormat pixfmt)
|
||||
{
|
||||
return ((int)pixfmt >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.Drawing;
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
|
||||
[Serializable]
|
||||
public struct IntPoint
|
||||
{
|
||||
public int X;
|
||||
|
||||
public int Y;
|
||||
|
||||
public IntPoint(int x, int y)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator Point(IntPoint point)
|
||||
{
|
||||
return new Point(point.X, point.Y);
|
||||
}
|
||||
|
||||
public static implicit operator DoublePoint(IntPoint point)
|
||||
{
|
||||
return new DoublePoint(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public struct Point
|
||||
{
|
||||
public float X;
|
||||
|
||||
public float Y;
|
||||
|
||||
public Point( float x, float y )
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public float DistanceTo( Point anotherPoint )
|
||||
{
|
||||
float dx = X - anotherPoint.X;
|
||||
float dy = Y - anotherPoint.Y;
|
||||
|
||||
return (float) System.Math.Sqrt( dx * dx + dy * dy );
|
||||
}
|
||||
|
||||
public float SquaredDistanceTo( Point anotherPoint )
|
||||
{
|
||||
float dx = X - anotherPoint.X;
|
||||
float dy = Y - anotherPoint.Y;
|
||||
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
public static Point operator +( Point point1, Point point2 )
|
||||
{
|
||||
return new Point( point1.X + point2.X, point1.Y + point2.Y );
|
||||
}
|
||||
|
||||
public static Point Add( Point point1, Point point2 )
|
||||
{
|
||||
return new Point( point1.X + point2.X, point1.Y + point2.Y );
|
||||
}
|
||||
|
||||
public static Point operator -( Point point1, Point point2 )
|
||||
{
|
||||
return new Point( point1.X - point2.X, point1.Y - point2.Y );
|
||||
}
|
||||
|
||||
public static Point Subtract( Point point1, Point point2 )
|
||||
{
|
||||
return new Point( point1.X - point2.X, point1.Y - point2.Y );
|
||||
}
|
||||
|
||||
public static Point operator +( Point point, float valueToAdd )
|
||||
{
|
||||
return new Point( point.X + valueToAdd, point.Y + valueToAdd );
|
||||
}
|
||||
|
||||
public static Point Add( Point point, float valueToAdd )
|
||||
{
|
||||
return new Point( point.X + valueToAdd, point.Y + valueToAdd );
|
||||
}
|
||||
|
||||
public static Point operator -( Point point, float valueToSubtract )
|
||||
{
|
||||
return new Point( point.X - valueToSubtract, point.Y - valueToSubtract );
|
||||
}
|
||||
|
||||
public static Point Subtract( Point point, float valueToSubtract )
|
||||
{
|
||||
return new Point( point.X - valueToSubtract, point.Y - valueToSubtract );
|
||||
}
|
||||
|
||||
public static Point operator *( Point point, float factor )
|
||||
{
|
||||
return new Point( point.X * factor, point.Y * factor );
|
||||
}
|
||||
|
||||
public static Point Multiply( Point point, float factor )
|
||||
{
|
||||
return new Point( point.X * factor, point.Y * factor );
|
||||
}
|
||||
|
||||
public static Point operator /( Point point, float factor )
|
||||
{
|
||||
return new Point( point.X / factor, point.Y / factor );
|
||||
}
|
||||
|
||||
public static Point Divide( Point point, float factor )
|
||||
{
|
||||
return new Point( point.X / factor, point.Y / factor );
|
||||
}
|
||||
|
||||
public static bool operator ==( Point point1, Point point2 )
|
||||
{
|
||||
return ( ( point1.X == point2.X ) && ( point1.Y == point2.Y ) );
|
||||
}
|
||||
|
||||
public static bool operator !=( Point point1, Point point2 )
|
||||
{
|
||||
return ( ( point1.X != point2.X ) || ( point1.Y != point2.Y ) );
|
||||
}
|
||||
|
||||
public override bool Equals( object obj )
|
||||
{
|
||||
return ( obj is Point ) ? ( this == (Point) obj ) : false;
|
||||
}
|
||||
|
||||
public override int GetHashCode( )
|
||||
{
|
||||
return X.GetHashCode( ) + Y.GetHashCode( );
|
||||
}
|
||||
|
||||
public static explicit operator IntPoint( Point point )
|
||||
{
|
||||
return new IntPoint( (int) point.X, (int) point.Y );
|
||||
}
|
||||
|
||||
public static implicit operator DoublePoint( Point point )
|
||||
{
|
||||
return new DoublePoint( point.X, point.Y );
|
||||
}
|
||||
|
||||
public IntPoint Round( )
|
||||
{
|
||||
return new IntPoint( (int) Math.Round( X ), (int) Math.Round( Y ) );
|
||||
}
|
||||
|
||||
public override string ToString( )
|
||||
{
|
||||
return string.Format( System.Globalization.CultureInfo.InvariantCulture, "{0}, {1}", X, Y );
|
||||
}
|
||||
|
||||
public float EuclideanNorm( )
|
||||
{
|
||||
return (float) System.Math.Sqrt( X * X + Y * Y );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
using System.Drawing.Imaging;
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
|
||||
public class ResizeBilinear : BaseResizeFilter
|
||||
{
|
||||
private Dictionary<PixelFormat, PixelFormat> formatTranslations;
|
||||
|
||||
public override Dictionary<PixelFormat, PixelFormat> FormatTranslations
|
||||
{
|
||||
get { return formatTranslations; }
|
||||
}
|
||||
public ResizeBilinear( int newWidth, int newHeight ) :
|
||||
base( newWidth, newHeight )
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
formatTranslations = new Dictionary<PixelFormat, PixelFormat>();
|
||||
formatTranslations[PixelFormat.Format8bppIndexed] = PixelFormat.Format8bppIndexed;
|
||||
formatTranslations[PixelFormat.Format24bppRgb] = PixelFormat.Format24bppRgb;
|
||||
formatTranslations[PixelFormat.Format32bppRgb] = PixelFormat.Format32bppRgb;
|
||||
formatTranslations[PixelFormat.Format32bppArgb] = PixelFormat.Format32bppArgb;
|
||||
}
|
||||
}
|
||||
|
||||
protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData )
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
// get source image size
|
||||
int width = sourceData.Width;
|
||||
int height = sourceData.Height;
|
||||
|
||||
int pixelSize = System.Drawing.Image.GetPixelFormatSize(sourceData.PixelFormat) / 8;
|
||||
int srcStride = sourceData.Stride;
|
||||
int dstOffset = destinationData.Stride - pixelSize * newWidth;
|
||||
double xFactor = (double)width / newWidth;
|
||||
double yFactor = (double)height / newHeight;
|
||||
|
||||
// do the job
|
||||
byte* src = (byte*)sourceData.ImageData.ToPointer();
|
||||
byte* dst = (byte*)destinationData.ImageData.ToPointer();
|
||||
|
||||
// coordinates of source points
|
||||
double ox, oy, dx1, dy1, dx2, dy2;
|
||||
int ox1, oy1, ox2, oy2;
|
||||
// width and height decreased by 1
|
||||
int ymax = height - 1;
|
||||
int xmax = width - 1;
|
||||
// temporary pointers
|
||||
byte* tp1, tp2;
|
||||
byte* p1, p2, p3, p4;
|
||||
|
||||
// for each line
|
||||
for (int y = 0; y < newHeight; y++)
|
||||
{
|
||||
// Y coordinates
|
||||
oy = (double)y * yFactor;
|
||||
oy1 = (int)oy;
|
||||
oy2 = (oy1 == ymax) ? oy1 : oy1 + 1;
|
||||
dy1 = oy - (double)oy1;
|
||||
dy2 = 1.0 - dy1;
|
||||
|
||||
// get temp pointers
|
||||
tp1 = src + oy1 * srcStride;
|
||||
tp2 = src + oy2 * srcStride;
|
||||
|
||||
// for each pixel
|
||||
for (int x = 0; x < newWidth; x++)
|
||||
{
|
||||
// X coordinates
|
||||
ox = (double)x * xFactor;
|
||||
ox1 = (int)ox;
|
||||
ox2 = (ox1 == xmax) ? ox1 : ox1 + 1;
|
||||
dx1 = ox - (double)ox1;
|
||||
dx2 = 1.0 - dx1;
|
||||
|
||||
// get four points
|
||||
p1 = tp1 + ox1 * pixelSize;
|
||||
p2 = tp1 + ox2 * pixelSize;
|
||||
p3 = tp2 + ox1 * pixelSize;
|
||||
p4 = tp2 + ox2 * pixelSize;
|
||||
|
||||
// interpolate using 4 points
|
||||
for (int i = 0; i < pixelSize; i++, dst++, p1++, p2++, p3++, p4++)
|
||||
{
|
||||
*dst = (byte)(
|
||||
dy2 * (dx2 * (*p1) + dx1 * (*p2)) +
|
||||
dy1 * (dx2 * (*p3) + dx1 * (*p4)));
|
||||
}
|
||||
}
|
||||
dst += dstOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
public static class SystemTools
|
||||
{
|
||||
public static IntPtr CopyUnmanagedMemory(IntPtr dst, IntPtr src, int count)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyUnmanagedMemory((byte*)dst.ToPointer(), (byte*)src.ToPointer(), count);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
public static unsafe byte* CopyUnmanagedMemory(byte* dst, byte* src, int count)
|
||||
{
|
||||
#if !MONO
|
||||
return memcpy(dst, src, count);
|
||||
#else
|
||||
int countUint = count >> 2;
|
||||
int countByte = count & 3;
|
||||
|
||||
uint* dstUint = (uint*) dst;
|
||||
uint* srcUint = (uint*) src;
|
||||
|
||||
while ( countUint-- != 0 )
|
||||
{
|
||||
*dstUint++ = *srcUint++;
|
||||
}
|
||||
|
||||
byte* dstByte = (byte*) dstUint;
|
||||
byte* srcByte = (byte*) srcUint;
|
||||
|
||||
while ( countByte-- != 0 )
|
||||
{
|
||||
*dstByte++ = *srcByte++;
|
||||
}
|
||||
return dst;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static IntPtr SetUnmanagedMemory(IntPtr dst, int filler, int count)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
SetUnmanagedMemory((byte*)dst.ToPointer(), filler, count);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
public static unsafe byte* SetUnmanagedMemory(byte* dst, int filler, int count)
|
||||
{
|
||||
#if !MONO
|
||||
return memset(dst, filler, count);
|
||||
#else
|
||||
int countUint = count >> 2;
|
||||
int countByte = count & 3;
|
||||
|
||||
byte fillerByte = (byte) filler;
|
||||
uint fiilerUint = (uint) filler | ( (uint) filler << 8 ) |
|
||||
( (uint) filler << 16 );// |
|
||||
//( (uint) filler << 24 );
|
||||
|
||||
uint* dstUint = (uint*) dst;
|
||||
|
||||
while ( countUint-- != 0 )
|
||||
{
|
||||
*dstUint++ = fiilerUint;
|
||||
}
|
||||
|
||||
byte* dstByte = (byte*) dstUint;
|
||||
|
||||
while ( countByte-- != 0 )
|
||||
{
|
||||
*dstByte++ = fillerByte;
|
||||
}
|
||||
return dst;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !MONO
|
||||
[DllImport("ntdll.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static unsafe extern byte* memcpy(
|
||||
byte* dst,
|
||||
byte* src,
|
||||
int count);
|
||||
|
||||
[DllImport("ntdll.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static unsafe extern byte* memset(
|
||||
byte* dst,
|
||||
int filler,
|
||||
int count);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Threading;
|
||||
|
||||
namespace cmonitor.server.client.reports.screen.aforge
|
||||
{
|
||||
|
||||
|
||||
public class UnmanagedImage : IDisposable
|
||||
{
|
||||
private IntPtr imageData;
|
||||
private int width, height;
|
||||
private int stride;
|
||||
private PixelFormat pixelFormat;
|
||||
private bool mustBeDisposed = false;
|
||||
|
||||
public IntPtr ImageData
|
||||
{
|
||||
get { return imageData; }
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get { return width; }
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get { return height; }
|
||||
}
|
||||
|
||||
public int Stride
|
||||
{
|
||||
get { return stride; }
|
||||
}
|
||||
|
||||
public PixelFormat PixelFormat
|
||||
{
|
||||
get { return pixelFormat; }
|
||||
}
|
||||
|
||||
public UnmanagedImage( IntPtr imageData, int width, int height, int stride, PixelFormat pixelFormat )
|
||||
{
|
||||
this.imageData = imageData;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.stride = stride;
|
||||
this.pixelFormat = pixelFormat;
|
||||
}
|
||||
|
||||
public UnmanagedImage( BitmapData bitmapData )
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
this.imageData = bitmapData.Scan0;
|
||||
this.width = bitmapData.Width;
|
||||
this.height = bitmapData.Height;
|
||||
this.stride = bitmapData.Stride;
|
||||
this.pixelFormat = bitmapData.PixelFormat;
|
||||
}
|
||||
}
|
||||
|
||||
~UnmanagedImage( )
|
||||
{
|
||||
Dispose( false );
|
||||
}
|
||||
|
||||
public void Dispose( )
|
||||
{
|
||||
Dispose( true );
|
||||
// remove me from the Finalization queue
|
||||
GC.SuppressFinalize( this );
|
||||
}
|
||||
|
||||
protected virtual void Dispose( bool disposing )
|
||||
{
|
||||
if ( disposing )
|
||||
{
|
||||
// dispose managed resources
|
||||
}
|
||||
// free image memory if the image was allocated using this class
|
||||
if ( ( mustBeDisposed ) && ( imageData != IntPtr.Zero ) )
|
||||
{
|
||||
System.Runtime.InteropServices.Marshal.FreeHGlobal( imageData );
|
||||
System.GC.RemoveMemoryPressure( stride * height );
|
||||
imageData = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static UnmanagedImage Create( int width, int height, PixelFormat pixelFormat )
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
int bytesPerPixel = 0;
|
||||
|
||||
// calculate bytes per pixel
|
||||
switch (pixelFormat)
|
||||
{
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
bytesPerPixel = 1;
|
||||
break;
|
||||
case PixelFormat.Format16bppGrayScale:
|
||||
bytesPerPixel = 2;
|
||||
break;
|
||||
case PixelFormat.Format24bppRgb:
|
||||
bytesPerPixel = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppRgb:
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
bytesPerPixel = 4;
|
||||
break;
|
||||
case PixelFormat.Format48bppRgb:
|
||||
bytesPerPixel = 6;
|
||||
break;
|
||||
case PixelFormat.Format64bppArgb:
|
||||
case PixelFormat.Format64bppPArgb:
|
||||
bytesPerPixel = 8;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Can not create image with specified pixel format.");
|
||||
}
|
||||
|
||||
// check image size
|
||||
if ((width <= 0) || (height <= 0))
|
||||
{
|
||||
throw new Exception("Invalid image size specified.");
|
||||
}
|
||||
|
||||
// calculate stride
|
||||
int stride = width * bytesPerPixel;
|
||||
|
||||
if (stride % 4 != 0)
|
||||
{
|
||||
stride += (4 - (stride % 4));
|
||||
}
|
||||
|
||||
// allocate memory for the image
|
||||
IntPtr imageData = System.Runtime.InteropServices.Marshal.AllocHGlobal(stride * height);
|
||||
cmonitor.server.client.reports.screen.aforge.SystemTools.SetUnmanagedMemory(imageData, 0, stride * height);
|
||||
System.GC.AddMemoryPressure(stride * height);
|
||||
|
||||
UnmanagedImage image = new UnmanagedImage(imageData, width, height, stride, pixelFormat);
|
||||
image.mustBeDisposed = true;
|
||||
|
||||
return image;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void SetPixel( IntPoint point, Color color )
|
||||
{
|
||||
SetPixel( point.X, point.Y, color );
|
||||
}
|
||||
|
||||
public void SetPixel( int x, int y, Color color )
|
||||
{
|
||||
SetPixel( x, y, color.R, color.G, color.B, color.A );
|
||||
}
|
||||
|
||||
public void SetPixel( int x, int y, byte value )
|
||||
{
|
||||
SetPixel( x, y, value, value, value, 255 );
|
||||
}
|
||||
|
||||
private void SetPixel( int x, int y, byte r, byte g, byte b, byte a )
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
if ((x >= 0) && (y >= 0) && (x < width) && (y < height))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
int pixelSize = Bitmap.GetPixelFormatSize(pixelFormat) / 8;
|
||||
byte* ptr = (byte*)imageData.ToPointer() + y * stride + x * pixelSize;
|
||||
ushort* ptr2 = (ushort*)ptr;
|
||||
|
||||
switch (pixelFormat)
|
||||
{
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
*ptr = (byte)(0.2125 * r + 0.7154 * g + 0.0721 * b);
|
||||
break;
|
||||
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
ptr[RGB.R] = r;
|
||||
ptr[RGB.G] = g;
|
||||
ptr[RGB.B] = b;
|
||||
break;
|
||||
|
||||
case PixelFormat.Format32bppArgb:
|
||||
ptr[RGB.R] = r;
|
||||
ptr[RGB.G] = g;
|
||||
ptr[RGB.B] = b;
|
||||
ptr[RGB.A] = a;
|
||||
break;
|
||||
|
||||
case PixelFormat.Format16bppGrayScale:
|
||||
*ptr2 = (ushort)((ushort)(0.2125 * r + 0.7154 * g + 0.0721 * b) << 8);
|
||||
break;
|
||||
|
||||
case PixelFormat.Format48bppRgb:
|
||||
ptr2[RGB.R] = (ushort)(r << 8);
|
||||
ptr2[RGB.G] = (ushort)(g << 8);
|
||||
ptr2[RGB.B] = (ushort)(b << 8);
|
||||
break;
|
||||
|
||||
case PixelFormat.Format64bppArgb:
|
||||
ptr2[RGB.R] = (ushort)(r << 8);
|
||||
ptr2[RGB.G] = (ushort)(g << 8);
|
||||
ptr2[RGB.B] = (ushort)(b << 8);
|
||||
ptr2[RGB.A] = (ushort)(a << 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("The pixel format is not supported: " + pixelFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Color GetPixel( IntPoint point )
|
||||
{
|
||||
return GetPixel( point.X, point.Y );
|
||||
}
|
||||
|
||||
public Color GetPixel( int x, int y )
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
if ((x < 0) || (y < 0))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("x", "The specified pixel coordinate is out of image's bounds.");
|
||||
}
|
||||
|
||||
if ((x >= width) || (y >= height))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("y", "The specified pixel coordinate is out of image's bounds.");
|
||||
}
|
||||
|
||||
Color color = new Color();
|
||||
|
||||
unsafe
|
||||
{
|
||||
int pixelSize = Bitmap.GetPixelFormatSize(pixelFormat) / 8;
|
||||
byte* ptr = (byte*)imageData.ToPointer() + y * stride + x * pixelSize;
|
||||
|
||||
switch (pixelFormat)
|
||||
{
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
color = Color.FromArgb(*ptr, *ptr, *ptr);
|
||||
break;
|
||||
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
color = Color.FromArgb(ptr[RGB.R], ptr[RGB.G], ptr[RGB.B]);
|
||||
break;
|
||||
|
||||
case PixelFormat.Format32bppArgb:
|
||||
color = Color.FromArgb(ptr[RGB.A], ptr[RGB.R], ptr[RGB.G], ptr[RGB.B]);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("The pixel format is not supported: " + pixelFormat);
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
return new Color();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ namespace cmonitor.server.client.reports.share
|
||||
private readonly Config config;
|
||||
|
||||
Dictionary<string, ShareItemInfo> dic = new Dictionary<string, ShareItemInfo>();
|
||||
private bool updated = false;
|
||||
|
||||
public ShareReport(Config config)
|
||||
{
|
||||
this.config = config;
|
||||
@@ -18,11 +20,12 @@ namespace cmonitor.server.client.reports.share
|
||||
InitShare();
|
||||
}
|
||||
}
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
updated = false;
|
||||
GetShare();
|
||||
if (dic.Count == 0) return null;
|
||||
return dic;
|
||||
if ((dic.Count > 0 && updated) || reportType == ReportType.Full) return dic;
|
||||
return null;
|
||||
}
|
||||
public bool GetShare(string key, out ShareItemInfo item)
|
||||
{
|
||||
@@ -66,6 +69,12 @@ namespace cmonitor.server.client.reports.share
|
||||
{
|
||||
val = Encoding.UTF8.GetString(span.Slice(2 + keyLen, valLen));
|
||||
}
|
||||
|
||||
if(dic.TryGetValue(key,out ShareItemInfo item) == false || item.Value != val)
|
||||
{
|
||||
updated = true;
|
||||
}
|
||||
|
||||
dic[key] = new ShareItemInfo
|
||||
{
|
||||
Index = index,
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
ReportTask();
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if(systemReportInfo.Cpu != lastCpu || systemReportInfo.Memory != lastMemory)
|
||||
if(reportType == ReportType.Full || systemReportInfo.Cpu != lastCpu || systemReportInfo.Memory != lastMemory)
|
||||
{
|
||||
lastCpu = systemReportInfo.Cpu;
|
||||
lastMemory = systemReportInfo.Memory;
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace cmonitor.server.client.reports.llock
|
||||
}
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if (report.Value != lastValue)
|
||||
if (reportType == ReportType.Full || report.Value != lastValue)
|
||||
{
|
||||
lastValue = report.Value;
|
||||
return report;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace cmonitor.server.client.reports.volume
|
||||
Init();
|
||||
}
|
||||
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
@@ -24,7 +24,7 @@ namespace cmonitor.server.client.reports.volume
|
||||
report.Mute = GetVolumeMute();
|
||||
report.MasterPeak = GetMasterPeakValue();
|
||||
}
|
||||
if (report.Value != lastValue || report.Mute != lastMute || report.MasterPeak != lastMasterPeak)
|
||||
if (reportType == ReportType.Full || report.Value != lastValue || report.Mute != lastMute || report.MasterPeak != lastMasterPeak)
|
||||
{
|
||||
lastValue = report.Value;
|
||||
lastMute = report.Mute;
|
||||
|
||||
@@ -18,13 +18,13 @@ namespace cmonitor.server.client.reports.llock
|
||||
}
|
||||
|
||||
DateTime startTime = new DateTime(1970, 1, 1);
|
||||
public object GetReports()
|
||||
public object GetReports(ReportType reportType)
|
||||
{
|
||||
if (shareReport.GetShare(Name, out ShareItemInfo share) && string.IsNullOrWhiteSpace(share.Value) == false && long.TryParse(share.Value, out long time))
|
||||
{
|
||||
report.Value = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds - time < 1000;
|
||||
}
|
||||
if (report.Value != lastValue)
|
||||
if (reportType == ReportType.Full || report.Value != lastValue)
|
||||
{
|
||||
lastValue = report.Value;
|
||||
return report;
|
||||
|
||||
@@ -20,7 +20,13 @@ namespace cmonitor.server.service.messengers.report
|
||||
[MessengerId((ushort)ReportMessengerIds.Update)]
|
||||
public void Update(IConnection connection)
|
||||
{
|
||||
reportTransfer.Update();
|
||||
ReportType reportType = ReportType.Trim;
|
||||
if(connection.ReceiveRequestWrap.Payload.Length > 0)
|
||||
{
|
||||
reportType = (ReportType)connection.ReceiveRequestWrap.Payload.Span[0];
|
||||
}
|
||||
|
||||
reportTransfer.Update(reportType);
|
||||
connection.Write(Helper.TrueArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using cmonitor.server.api;
|
||||
using cmonitor.server.client.reports.screen;
|
||||
using cmonitor.server.client.reports.screen.sharpDX;
|
||||
using cmonitor.server.service.messengers.sign;
|
||||
using MemoryPack;
|
||||
using MemoryPack.Compression;
|
||||
using System;
|
||||
|
||||
namespace cmonitor.server.service.messengers.screen
|
||||
{
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0"><link rel="icon" href="/favicon.ico"><title>cmonitor.web</title><script defer="defer" src="/js/chunk-vendors.9b0dc62c.js"></script><script defer="defer" src="/js/app.4c3fbccb.js"></script><link href="/css/chunk-vendors.faad7142.css" rel="stylesheet"><link href="/css/app.9c6b579f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but cmonitor.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0"><link rel="icon" href="/favicon.ico"><title>cmonitor.web</title><script defer="defer" src="/js/chunk-vendors.9b0dc62c.js"></script><script defer="defer" src="/js/app.28446d51.js"></script><link href="/css/chunk-vendors.faad7142.css" rel="stylesheet"><link href="/css/app.9c6b579f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but cmonitor.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
1
cmonitor/web/js/316.b77fb74e.js
Normal file
@@ -81,7 +81,7 @@ namespace llock.win
|
||||
while (true)
|
||||
{
|
||||
WriteLLock();
|
||||
Thread.Sleep(100);
|
||||
Thread.Sleep(30);
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
@@ -89,10 +89,16 @@ namespace llock.win
|
||||
MemoryMappedViewAccessor accessor2;
|
||||
DateTime startTime = new DateTime(1970, 1, 1);
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes("LLock");
|
||||
|
||||
long lastTime = 0;
|
||||
private void WriteLLock()
|
||||
{
|
||||
long time = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds;
|
||||
if(time - lastTime >= 300)
|
||||
{
|
||||
WriteMemory(this.shareIndex, keyBytes, Encoding.UTF8.GetBytes(time.ToString()));
|
||||
lastTime = time;
|
||||
}
|
||||
}
|
||||
private void WriteMemory(int index, byte[] key, byte[] value)
|
||||
{
|
||||
|
||||
132
notify.win/Form1.Designer.cs
generated
@@ -28,60 +28,116 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
|
||||
this.username = new System.Windows.Forms.Label();
|
||||
this.star5 = new System.Windows.Forms.PictureBox();
|
||||
this.star4 = new System.Windows.Forms.PictureBox();
|
||||
this.star3 = new System.Windows.Forms.PictureBox();
|
||||
this.star2 = new System.Windows.Forms.PictureBox();
|
||||
this.star1 = new System.Windows.Forms.PictureBox();
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
this.pictureBox2 = new System.Windows.Forms.PictureBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star5)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star4)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star3)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star2)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star1)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// username
|
||||
//
|
||||
this.username.Font = new System.Drawing.Font("宋体", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.username.ForeColor = System.Drawing.Color.Orange;
|
||||
this.username.Location = new System.Drawing.Point(4, 5);
|
||||
this.username.Name = "username";
|
||||
this.username.Size = new System.Drawing.Size(171, 23);
|
||||
this.username.TabIndex = 6;
|
||||
this.username.Text = "label1";
|
||||
this.username.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// star5
|
||||
//
|
||||
this.star5.Image = global::notify.win.Properties.Resources.star1;
|
||||
this.star5.Location = new System.Drawing.Point(145, 31);
|
||||
this.star5.Name = "star5";
|
||||
this.star5.Size = new System.Drawing.Size(30, 30);
|
||||
this.star5.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.star5.TabIndex = 5;
|
||||
this.star5.TabStop = false;
|
||||
//
|
||||
// star4
|
||||
//
|
||||
this.star4.Image = global::notify.win.Properties.Resources.star1;
|
||||
this.star4.Location = new System.Drawing.Point(110, 31);
|
||||
this.star4.Name = "star4";
|
||||
this.star4.Size = new System.Drawing.Size(30, 30);
|
||||
this.star4.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.star4.TabIndex = 4;
|
||||
this.star4.TabStop = false;
|
||||
//
|
||||
// star3
|
||||
//
|
||||
this.star3.Image = global::notify.win.Properties.Resources.star1;
|
||||
this.star3.Location = new System.Drawing.Point(74, 31);
|
||||
this.star3.Name = "star3";
|
||||
this.star3.Size = new System.Drawing.Size(30, 30);
|
||||
this.star3.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.star3.TabIndex = 3;
|
||||
this.star3.TabStop = false;
|
||||
//
|
||||
// star2
|
||||
//
|
||||
this.star2.Image = global::notify.win.Properties.Resources.star1;
|
||||
this.star2.Location = new System.Drawing.Point(38, 31);
|
||||
this.star2.Name = "star2";
|
||||
this.star2.Size = new System.Drawing.Size(30, 30);
|
||||
this.star2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.star2.TabIndex = 2;
|
||||
this.star2.TabStop = false;
|
||||
//
|
||||
// star1
|
||||
//
|
||||
this.star1.Image = global::notify.win.Properties.Resources.star1;
|
||||
this.star1.Location = new System.Drawing.Point(3, 31);
|
||||
this.star1.Name = "star1";
|
||||
this.star1.Size = new System.Drawing.Size(30, 30);
|
||||
this.star1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.star1.TabIndex = 1;
|
||||
this.star1.TabStop = false;
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
|
||||
this.pictureBox1.Location = new System.Drawing.Point(55, 203);
|
||||
this.pictureBox1.Image = global::notify.win.Properties.Resources._3;
|
||||
this.pictureBox1.Location = new System.Drawing.Point(31, 66);
|
||||
this.pictureBox1.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(236, 250);
|
||||
this.pictureBox1.Size = new System.Drawing.Size(118, 113);
|
||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.pictureBox1.TabIndex = 0;
|
||||
this.pictureBox1.TabStop = false;
|
||||
//
|
||||
// pictureBox2
|
||||
//
|
||||
this.pictureBox2.BackColor = System.Drawing.Color.Transparent;
|
||||
this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image")));
|
||||
this.pictureBox2.Location = new System.Drawing.Point(1, -7);
|
||||
this.pictureBox2.Name = "pictureBox2";
|
||||
this.pictureBox2.Size = new System.Drawing.Size(331, 271);
|
||||
this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.pictureBox2.TabIndex = 1;
|
||||
this.pictureBox2.TabStop = false;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.BackColor = System.Drawing.Color.Gray;
|
||||
this.label1.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.label1.Location = new System.Drawing.Point(67, 108);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(200, 121);
|
||||
this.label1.TabIndex = 2;
|
||||
this.label1.Text = "恭喜地方发鬼地方获得【五星点评】";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 24F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(333, 450);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.pictureBox2);
|
||||
this.ClientSize = new System.Drawing.Size(179, 179);
|
||||
this.Controls.Add(this.username);
|
||||
this.Controls.Add(this.star5);
|
||||
this.Controls.Add(this.star4);
|
||||
this.Controls.Add(this.star3);
|
||||
this.Controls.Add(this.star2);
|
||||
this.Controls.Add(this.star1);
|
||||
this.Controls.Add(this.pictureBox1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.Name = "Form1";
|
||||
this.Text = "广播";
|
||||
this.Load += new System.EventHandler(this.OnLoad);
|
||||
((System.ComponentModel.ISupportInitialize)(this.star5)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star4)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star3)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star2)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.star1)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@@ -89,8 +145,12 @@
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
private System.Windows.Forms.PictureBox pictureBox2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.PictureBox star1;
|
||||
private System.Windows.Forms.PictureBox star2;
|
||||
private System.Windows.Forms.PictureBox star3;
|
||||
private System.Windows.Forms.PictureBox star4;
|
||||
private System.Windows.Forms.PictureBox star5;
|
||||
private System.Windows.Forms.Label username;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@ using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
|
||||
|
||||
namespace notify.win
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
{
|
||||
|
||||
protected override bool ShowWithoutActivation => true;
|
||||
protected override CreateParams CreateParams
|
||||
{
|
||||
get
|
||||
@@ -24,10 +26,12 @@ namespace notify.win
|
||||
|
||||
private int speed;
|
||||
private string msg;
|
||||
public Form1(int speed, string msg)
|
||||
private int star;
|
||||
public Form1(int speed, string msg,int star)
|
||||
{
|
||||
this.speed = speed;
|
||||
this.msg = msg;
|
||||
this.star = Math.Min(star,5);
|
||||
|
||||
InitializeComponent();
|
||||
this.AllowTransparency = true;
|
||||
@@ -37,12 +41,24 @@ namespace notify.win
|
||||
this.TopMost = true;
|
||||
this.ShowInTaskbar = false;
|
||||
|
||||
label1.BackColor = Color.FromArgb(255, 248, 153);
|
||||
label1.ForeColor = Color.Green;
|
||||
//username.BackColor = Color.FromArgb(255, 248, 153);
|
||||
//username.ForeColor = Color.LightGreen;
|
||||
}
|
||||
|
||||
private void OnLoad(object sender, EventArgs e)
|
||||
{
|
||||
PictureBox[] stars = new PictureBox[] { star1, star2, star3, star4, star5 };
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
stars[i].Image = global::notify.win.Properties.Resources.star2;
|
||||
}
|
||||
for (int i = 0; i < star; i++)
|
||||
{
|
||||
stars[i].Image = global::notify.win.Properties.Resources.star1;
|
||||
}
|
||||
Bitmap[] images = new Bitmap[] { Properties.Resources._0, Properties.Resources._1, Properties.Resources._2, Properties.Resources._3, Properties.Resources._4, Properties.Resources._5 };
|
||||
pictureBox1.Image = images[new Random().Next(0,6)];
|
||||
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
//将窗口置顶
|
||||
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
@@ -62,7 +78,7 @@ namespace notify.win
|
||||
int width = this.Width;
|
||||
int height = this.Height;
|
||||
|
||||
label1.Text = this.msg;
|
||||
username.Text = this.msg;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
||||
@@ -14,10 +14,17 @@ namespace notify.win
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
int speed = int.Parse(args[0]);
|
||||
string msg = args[1];
|
||||
int speed = 1;
|
||||
string msg = "少年郎秃头呀";
|
||||
int star = 1;
|
||||
if(args.Length > 1)
|
||||
{
|
||||
speed = int.Parse(args[0]);
|
||||
msg = args[1];
|
||||
star = int.Parse(args[2]);
|
||||
}
|
||||
|
||||
Application.Run(new Form1(speed,msg));
|
||||
Application.Run(new Form1(speed,msg, star));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
128
notify.win/Properties/Resources.Designer.cs
generated
@@ -3,47 +3,42 @@
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能导致不正确的行为,如果
|
||||
// 重新生成代码,则所做更改将丢失。
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace notify.win.Properties
|
||||
{
|
||||
namespace notify.win.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 强类型资源类,用于查找本地化字符串等。
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存 ResourceManager 实例。
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("notify.win.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
@@ -56,16 +51,103 @@ namespace notify.win.Properties
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap _0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap _1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap _2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap _3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap _4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap _5 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("5", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap notify {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("notify", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap star1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("star1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap star2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("star2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
@@ -60,6 +60,7 @@
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
@@ -68,9 +69,10 @@
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
@@ -85,9 +87,10 @@
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
@@ -109,9 +112,37 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\1.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="star1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\star1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\2.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="star2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\star2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="notify" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\notify.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\0.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\3.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\4.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="5" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\5.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
notify.win/Resources/0.gif
Normal file
|
After Width: | Height: | Size: 316 KiB |
BIN
notify.win/Resources/1.gif
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
notify.win/Resources/2.gif
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
notify.win/Resources/3.gif
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
notify.win/Resources/4.gif
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
notify.win/Resources/5.gif
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
notify.win/Resources/notify.gif
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
notify.win/Resources/star1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
notify.win/Resources/star2.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
@@ -65,6 +65,7 @@
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
@@ -79,5 +80,32 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\star1.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\star2.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\notify.gif" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\1.gif" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\2.gif" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\0.gif" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\3.gif" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\4.gif" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\5.gif" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -96,7 +96,6 @@ namespace wallpaper.win
|
||||
pictureBox1.ImageLocation = imgUrl;
|
||||
this.Dock = DockStyle.Fill;
|
||||
this.ShowInTaskbar = false;
|
||||
this.WindowState = FormWindowState.Maximized;
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
|
||||
hook.Start();
|
||||
@@ -104,6 +103,8 @@ namespace wallpaper.win
|
||||
Find();
|
||||
Init();
|
||||
|
||||
this.WindowState = FormWindowState.Maximized;
|
||||
|
||||
IntPtr oldprogramIntPtr = programIntPtr;
|
||||
new Thread(() =>
|
||||
{
|
||||
@@ -122,6 +123,7 @@ namespace wallpaper.win
|
||||
}).Start();
|
||||
|
||||
|
||||
|
||||
mmf2 = MemoryMappedFile.CreateOrOpen(this.shareMkey, this.shareMLength);
|
||||
accessor2 = mmf2.CreateViewAccessor();
|
||||
WriteKeyBoard("init");
|
||||
@@ -168,10 +170,16 @@ namespace wallpaper.win
|
||||
{
|
||||
WriteMemory(this.shareKeyBoardIndex, keyBytes, emptyArray);
|
||||
}
|
||||
|
||||
long lastTime = 0;
|
||||
private void WriteWallpaper()
|
||||
{
|
||||
long time = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds;
|
||||
if(time- lastTime >= 300)
|
||||
{
|
||||
WriteMemory(this.shareWallpaperIndex, wallpaperBytes, Encoding.UTF8.GetBytes(time.ToString()));
|
||||
lastTime = time;
|
||||
}
|
||||
}
|
||||
private void WriteMemory(int index, byte[] key, byte[] value)
|
||||
{
|
||||
|
||||
@@ -18,11 +18,19 @@ namespace wallpaper.win
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
string imgUrl = arg[0];
|
||||
string shareMkey = arg[1];
|
||||
int shareMLength = int.Parse(arg[2]);
|
||||
int shareKeyBoardIndex = int.Parse(arg[3]);
|
||||
int shareWallpaperIndex = int.Parse(arg[4]);
|
||||
string imgUrl = string.Empty;
|
||||
string shareMkey = "test";
|
||||
int shareMLength = 2550;
|
||||
int shareKeyBoardIndex = 0;
|
||||
int shareWallpaperIndex = 1;
|
||||
if (arg.Length > 0)
|
||||
{
|
||||
imgUrl = arg[0];
|
||||
shareMkey = arg[1];
|
||||
shareMLength = int.Parse(arg[2]);
|
||||
shareKeyBoardIndex = int.Parse(arg[3]);
|
||||
shareWallpaperIndex = int.Parse(arg[4]);
|
||||
}
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new Form1(imgUrl, shareMkey, shareMLength, shareKeyBoardIndex, shareWallpaperIndex));
|
||||
|
||||