Blog

All Blog Posts  |  Next Post  |  Previous Post

Free component for making screen captures in TMS WEB Core applications

Tuesday, June 16, 2020


Sometimes it might be interesting to capture the content of the browser window, or parts of the browser window, as an image and send it back to a server or service. This can be a handy utility especially for customer support when wanting to see what is on the user browser when something is happening. This is at first sight not trivial to do though. The browser window is rendered from the DOM and consists typically of a collection of HTML elements. So, how could we convert this DOM of HTML elements to an image?

Fortunately the world-wide web development offerings are so incredibly rich that also for this particular need a nice JavaScript library exists. The handy JavaScript library for this case is html2canvas, an open source library for this particular task.

The documentation of html2canvas isn't extensive but specifies the essence of what we need:

html2canvas(document.querySelector("#capture")).then(canvas => {
    document.body.appendChild(canvas)
});
To start using this library, add the following library to your project HTML file

<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js" type="text/javascript"></script>

As you can see, a capture is performed on the HTML element returned by document.querySelector("#capture") and returned as a HTML CANVAS element. With this, we still do not have an image though.

That's why we did a little bit more effort to create a TMS WEB Core Pascal wrapper class for this that offers 6 methods:
 
  TScreenCaptureToCanvasProc = reference to procedure(ACanvas: TJSElement);
  TScreenCaptureToDataURLProc = reference to procedure(ADataURL: string);

  TWebScreenCapture = class(TComponent)
  public
    procedure CaptureElementToCanvasElement(AElement: TJSElement; Proc: TScreenCaptureToCanvasProc);
    procedure CaptureScreenToCanvasElement(Proc: TScreenCaptureToCanvasProc);

    procedure CaptureElementToDataURL(AElement: TJSElement; Proc: TScreenCaptureToDataURLProc );
    procedure CaptureScreenToDataURL(Proc: TScreenCaptureToDataURLProc);

    procedure CaptureElementToImageFile(AElement: TJSElement;AFileName: string; AType:TImageType);
    procedure CaptureScreenToImageFile(AFileName: string; AType:TImageType);
  end;

These methods are quite straightforward to understand.

There are the first 2 method to capture the browser window or a particular HTML element and return its rendered content as a HTML CANVAS element.

To capture the screen into a HTML CANVAS element, the Pascal code becomes:
 
var
  sc: TWebScreenCapture;
begin
  sc := TWebScreenCapture.Create(Self);

  sc.CaptureScreenToCanvasElement(
    procedure(ACanvas: TJSELement)
    begin
      document.body.appendChild(ACanvas);
    end
  );
end;

As you can see, an anonymous method is used that is being called when the rendering to CANVAS is ready and it returns this CANVAS element.

The second methods capture the content as data URL. A data URL can be set as URL for a HTML IMG element for example to make it visible. It is basically base64 encoded image data. This image data could for example also be used to send the capture back to a server.

To capture the screen this way, we can write code to show this data URL in a memo control:
 
var
  sc: TWebScreenCapture;
begin
  sc := TWebScreenCapture.Create(Self);

  sc.CaptureScreenToDataURL(
    procedure(ADataURL: string)
    begin
      WebMemo1.Lines.Add(ADataURL);
    end
  );

Finally, the last 2 methods allow to perform the capture and then save the captured image to a file that can be saved on the local file system. These methods have two additional parameters, the filename that is proposed for the image file download and the image type.

To save to a PNG file for example, the code now becomes:
 
var
  sc: TWebScreenCapture;
begin
  sc := TWebScreenCapture.Create(Self);
  sc.CaptureScreenToImageFile('webcorescreen', TImageType.itPNG);
end;

To make it even more convenient, we created a non-visual component that you can drop on the form and call the methods you wish to use when you want. A very nice feature in TMS WEB Core is that you can add an attribute of the type JSLibReference to a TMS WEB Core Pascal class to specify the dependencies on JavaScript libraries. In the case of this screen capture component, this is specified via:
  [ComponentPlatforms(TMSWebPlatform)]
  [JSLibReference('https://html2canvas.hertzen.com/dist/html2canvas.min.js')]
  TWebScreenCapture = class(TScreenCapture);

The first attribute here specifies that this component is available on the tool palette whenever a TMS WEB Core web form is opened in the designer.

You can download this component free for use with TMS WEB Core v1.4 Ravenna here. To install, open, compile & install the package from the "Component Library Source" folder. This will install the design-time TWebScreenCapture component.

For use at runtime, make sure that the file from the "Core Source" folder WEBLib.ScreenCapture.pas is in your TMS WEB Core specific library path that you can set via IDE Tools, Options, TMS Web, Library path. Don't stay behind, discover TMS WEB Core v1.4 now!

Active registered users of TMS WEB Core get the new version v1.4 free. Login on our website and download the newest release. Not yet a TMS WEB Core user? Signup for a fully functional trial version of TMS WEB Core now also supporting the newest Delphi 10.4 Sydney.

Excited about all the hot technology we offer for Delphi & C++Builder developers, get your VIP seat with TMS ALL-ACCESS, our no-nonsense subscription to our entire product offerings, priority support and access to betas (such as the upcoming TMS WEB Core for Visual Studio Code!



Bruno Fierens




This blog post has received 2 comments.


1. Tuesday, July 14, 2020 at 12:09:40 PM

I realise it would generate a security issue, but what would be REALLY great would be to be able to capture a screen grab (not just from the browser). Maybe if that isn''t possible allow them to paste a clipboard image into an image viewer and crop that.... Just thinking aloud.

Jason Chapman


2. Tuesday, July 14, 2020 at 4:00:28 PM

Jason:

The web app runs inside the browser and only what the browser "offers" is available. So to a web application a screenshot from the browser is actually "everything". You would have to build some kind of application that runs locally on the client and sends a screenshot to your backend.

Holger Flick




Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post