1

How to get screenshot of browser in DCEF3?

I create browser like this without VCL. The TakePicture method will only work if

  • No debugger is used
  • If ShowWindow is used

    var
      info: TCefWindowInfo;
      Settings: TCefBrowserSettings;
    begin
      FillChar(info, SizeOf(info), 0);
      info.width := width;
      info.height := height;
      FillChar(Settings, SizeOf(TCefBrowserSettings), 0);
      Settings.Size := SizeOf(TCefBrowserSettings);
      GetSettings(Settings);
      CefBrowserHostCreateBrowser(@info, FHandler, FDefaultUrl, @settings, nil);
    end;
    
    procedure TakePicture(const Browser: ICefBrowser; Height, Width: Integer);
    var
      DC: HDC;
      Bmp : TBitmap;
      Handle : HWND;
      Rect : trect;
      BarHeight : integer;
      BarLeft : integer;
    begin
      Bmp := TBitmap.Create;
      Bmp.PixelFormat := pf32bit;
      Handle := Browser.Host.WindowHandle;
      ShowWindow(handle, SW_RESTORE); // will work only if this is used otherwise black image!
      BarLeft := GetSystemMetrics(SM_CXFRAME);
      BarHeight := GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
      GetWindowRect(Handle, Rect);
      DC := GetDC(Handle);
      Bmp.Width := Rect.Right - Rect.Left;
      Bmp.Height := (Rect.Bottom - Rect.Top);
      BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, DC, -BarLeft, -BarHeight, SRCCOPY);
      ReleaseDC(Handle, DC);
      Bmp.SaveToFile('c:\test.bmp');
      Bmp.Free;
    end;
    
user3655788
  • 135
  • 1
  • 10

1 Answers1

1

This is basically off-screen rendering. In the demos folder of DCEF3 you'll find a project 'offscreen'. The code you're looking for is in the OnPaint event of TChromiumOSR. It renders to a TBitmap32, but any bitmap could be made to work. Notice that it has been optimized to only paint the so-called "dirty" areas (those that have changed since last painting), but if you're making a screenshot, that's not what you want. In my check-out of the repository there's a line commented out showing the naive case of just painting everything:

SomeBitmap.SetSize(width, height);
Move(buffer^, SomeBitmap32.Bits^, width * height * 4);

It's my best guess that the magic number 4 represents 4 bytes (32-bits).

I warmly recommend using Graphics32 but it you have to use a regular TBitmap, I'll leave it up to you to work out how to turn the array of bits into pixels. Be warmed it will probably be a lot slower.

Thijs van Dien
  • 6,516
  • 1
  • 29
  • 48
  • Not much help this answer. Need concrete example. – user3655788 May 20 '14 at 10:54
  • @user3655788 My answer basically tells you where to find the example. – Thijs van Dien May 20 '14 at 10:57
  • I get a black image. I doubt i need to use offscreen rendering to get a simple screenshot. Thats for firemonkey. – user3655788 May 20 '14 at 10:58
  • 1
    @user3655788 Try that demo; it works. There's not really any VCL involved there until the `TBitmap32` is rendered by the `TPaintBox32`. Have a good look at it and translate it to your own code but it basically comes down to the above. A "simple screenshot" still involves rendering the website. If you don't have it rendered to the form already (in which case you could use the link @JanDoggen provided), you'll need to render off-screen. – Thijs van Dien May 20 '14 at 11:06
  • @user3655788 The only problem you might run into with that demo is that you need to change `event.type_` into `event.kind` (error when compiling). – Thijs van Dien May 20 '14 at 11:11
  • Problem is this `OnPaint` is not even called. – user3655788 May 24 '14 at 16:21