我正在浏览器/查看器Delphi应用程序中使用TEdgeBrowser组件。对于最初的实现,经过简短的学习曲线之后,我几乎没有什么问题。
现在,我可以尝试一些特性(比如屏幕截图)。
要将屏幕捕获到文件中,只需添加:
EdgeBrowser1.CapturePreview(ScrFileName);其中ScrFileName是文件的路径,即c:\pic\screenshot.png
我希望每秒钟都能捕捉屏幕(并使用Indy组件(TIdHTTPServer)在内部中继屏幕(http)。
我可以这样做,但效率很低。有人能推荐另一种选择吗?
procedure TMainForm.IdHTTPServer1CommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
Const
EOL = #13;
var
Strm: TMemoryStream;
begin
if ARequestInfo.Document = '' then
begin
AResponseInfo.Redirect('/');
end
else if ARequestInfo.Document = '/' then
begin
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentType := 'text/html';
AResponseInfo.ContentText := '<!DOCTYPE html>'+EOL+
'<html>'+EOL+
'<head>'+EOL+
'<meta name="viewport" content="width=device-width, initial-scale=5">'+EOL+
'<meta http-equiv="Refresh" content=1>'+EOL+
'<style type="text/css">'+EOL+
' img.fullscr {'+EOL+
' display:block;'+EOL+
' width:100%;'+EOL+
' }'+EOL+
'</style>'+EOL+
'</head>'+EOL+
'<body>'+EOL+
'<img src="/image" class="fullscr">'+EOL+
'</body>'+EOL+
'</html>'+EOL;
end
else if ARequestInfo.Document = '/image' then
begin
Strm := TMemoryStream.Create;
try
Strm.Clear;
Strm.LoadFromFile(ScrFileName);
Strm.Position := 0;
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentType := 'image/png';
AResponseInfo.ContentStream := Strm;
except
Strm.Free;
raise;
end;
end
else begin
AResponseInfo.ResponseNo := 404;
end;
end;发布于 2022-06-28 19:44:06
您考虑过根本不将捕获的映像保存到磁盘上吗?TEdgeBrowser.CapturePreview()有一个重载,可以保存到TStream。您可以定期将捕获保存到与TMemoryStream共享的TIdHTTPServer,以便将最新捕获发送到HTTP客户端。
TIdHTTPServer是一个多线程组件,它的OnCommand...事件是在工作线程的上下文中触发的,所以一定要使用线程安全锁(如TCriticalSection )来保护TMemoryStream。
例如:
private
// using 2 TMemoryStreams so Edge can be preparing a new capture
// while TIdHTTPServer continues serving the previous capture to
// clients until the new capture is ready...
CapturingImageStream: TMemoryStream;
ReadyImageStream: TMemoryStream;
ImageLock: TCriticalSection;
// TODO: keep track of last capture time and etag, in case clients
// want to use Conditional-GET requests ('If-Modified-Since' and
// 'If-None-Match' HTTP headers) to cache retrievals in case captures
// haven't changed yet in between multiple GET requests...
...
procedure TMainForm.FormCreate(Sender: TObject);
begin
CapturingImageStream := TMemoryStream.Create;
ReadyImageStream := TMemoryStream.Create;
ImageLock := TCriticalSection.Create;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
IdHTTPServer1.Active := False;
CapturingImageStream.Free;
ReadyImageStream.Free;
ImageLock.Free;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
var
Strm: TMemoryStream;
begin
CapturingImageStream.Clear;
EdgeBrowser1.CapturePreview(CapturingImageStream);
ImageLock.Enter;
try
Strm := ReadyImageStream;
ReadyImageStream := CapturingImageStream;
CapturingImageStream := Strm;
finally
ImageLock.Leave;
end;
end;
procedure TMainForm.IdHTTPServer1CommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
if ARequestInfo.Document = '' then
begin
AResponseInfo.Redirect('/');
end
else if ARequestInfo.Document = '/' then
begin
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentType := 'text/html';
AResponseInfo.ContentText := '<!DOCTYPE html>'+sLineBreak+
'<html>'+sLineBreak+
'<head>'+sLineBreak+
'<meta name="viewport" content="width=device-width, initial-scale=5">'+sLineBreak+
'<meta http-equiv="Refresh" content=1>'+sLineBreak+
'<style type="text/css">'+sLineBreak+
' img.fullscr {'+sLineBreak+
' display:block;'+sLineBreak+
' width:100%;'+sLineBreak+
' }'+sLineBreak+
'</style>'+sLineBreak+
'</head>'+sLineBreak+
'<body>'+sLineBreak+
'<img src="/image" class="fullscr">'+sLineBreak+
'</body>'+sLineBreak+
'</html>'+sLineBreak;
end
else if ARequestInfo.Document = '/image' then
begin
ImageLock.Enter;
try
// TODO: check request's 'If-Modified-Since' and 'If-None-Match'
// headers, send 304 if the current capture hasn't changed yet...
ReadyImageStream.Position := 0;
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentType := 'image/png';
AResponseInfo.ContentStream := ReadyImageStream;
AResponseInfo.FreeContentStream := False;
// need to send the ContentStream inside the read lock...
AResponseInfo.WriteHeader;
AResponseInfo.WriteContent;
finally
ImageLock.Leave;
end;
end
else begin
AResponseInfo.ResponseNo := 404;
end;
end;为了进一步优化这一点,您可以考虑更改HTML以使用客户端AJAX或WebSocket脚本定期请求和显示最新的图像,而不必每次重新加载整个HTML页面。
例如,如果您要使用WebSocket,您可以在代码中添加一个WebSocket服务器(Indy此时没有一个,但有第三方实现),并让WebSocket服务器在准备就绪时将一个新捕获推送到浏览器,而不必等待一个HTTP请求首先到达。
https://stackoverflow.com/questions/72791757
复制相似问题