Author Topic: Black image instead of screen captures in Windows  (Read 1074 times)

artem101

  • Full Member
  • ***
  • Posts: 131
Black image instead of screen captures in Windows
« on: August 18, 2026, 01:55:13 pm »
My software takes screenshots from one or multiply monitors using this code:

Code: Pascal  [Select][+][-]
  1. procedure TScreenGrabber.CaptureRegion(AFileName: String; ARect: TRect);
  2. var
  3.   Bitmap: TBGRABitmap;
  4.   Writer: TFPCustomImageWriter;
  5.   ScreenDC: {$IfDef Windows}Windows.{$EndIf}HDC;
  6. begin
  7.   DebugLn('Start taking screenshot...');
  8.   DebugLn('Region: ', DbgS(ARect));
  9.  
  10.   Bitmap := TBGRABitmap.Create(ARect.Width, ARect.Height, BGRABlack);
  11.  
  12.   //Bitmap.TakeScreenshot(Rect); // Not supports multiply monitors
  13.   ScreenDC := GetDC(HWND_DESKTOP); // Get DC for all monitors
  14.   DebugLn('ScreenDC=', DbgS(ScreenDC));
  15.  
  16.   BitBlt(Bitmap.Canvas.Handle, 0, 0, ARect.Width, ARect.Height,
  17.            ScreenDC, ARect.Left, ARect.Top, SRCCOPY);
  18.  
  19.   ReleaseDC(0, ScreenDC);
  20.  
  21.   // ...
  22.  
  23. end;

Some users of Windows 7/10 reports that periodically black images arises instead on true screenshots. This problem not reproduces on my machine.

Sorry for insufficient amount of details, but what may be the reason? I heard something about hardware acceleration.

H₂SO₄

  • Sr. Member
  • ****
  • Posts: 493
Re: Black image instead of screen captures in Windows
« Reply #1 on: August 18, 2026, 02:18:50 pm »
I suspect DRM. Are your users trying to e.g. take screenshots of Netflix browser tabs in fullscreen mode?

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #2 on: August 18, 2026, 03:14:35 pm »
Are your users trying to e.g. take screenshots of Netflix browser tabs in fullscreen mode?

More likely no.

One person reported about black screenshots while playing game.

Xenno

  • Full Member
  • ***
  • Posts: 203
    • BS Programs
Re: Black image instead of screen captures in Windows
« Reply #3 on: August 18, 2026, 03:52:15 pm »
Many games uses exclusive mode which BitBlt won't be able to capture. PrintWindow function can capture in such situation but it only works for a window. If a game conquer the whole screen, PrintWindow can do as if it captures the whole screen when it is fed the game's window handle. The more advance technique than BilBlt or PrintWindow would be DirectX 11 Desktop Duplication API. However, up to now I cannot find the way to work with it in Lazarus. It involves WinRT and friends.
Lazarus 4.6, Windows 10, Website, YouTube channel
If I want to share, I give. If I want money, I sell. I don't set traps.

ADMGNS

  • Jr. Member
  • **
  • Posts: 90
  • keep it simple and smart
Re: Black image instead of screen captures in Windows
« Reply #4 on: August 21, 2026, 11:56:37 pm »
hello

i've test on linux, it captures full screen while vlc plays video clips in different render modes..

pls see atthmnt

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #5 on: September 02, 2026, 02:09:39 pm »
i've test on linux

Thanks, but my topic related to Windows only.

Many games uses exclusive mode which BitBlt won't be able to capture.

This issue occurs not in games only. Besides this, sometimes screenshots saved damaged - not fully black, but with colorfull dots/noise (see screenshot below). Another aspect - this often arises spontaneously. For example, after 10 good screenshots was taken one screenshot may be black or damaged and next screenshots are good again.

I guessed this can happen when CPU load is 100%, but I couldn't reproduce it.

Any more ideas?

Xenno

  • Full Member
  • ***
  • Posts: 203
    • BS Programs
Re: Black image instead of screen captures in Windows
« Reply #6 on: September 02, 2026, 03:24:10 pm »
I just tested an old code. It successfully captured my desktop while an app played a video.

Code: Pascal  [Select][+][-]
  1. uses LCLIntf...
  2.  
  3. procedure TForm1.Button1Click(Sender: TObject);
  4. var
  5.   cvs: TCanvas;
  6.   bmp: TBitmap;
  7.   r1, r2: TRect;
  8. begin
  9.   cvs := TCanvas.Create;
  10.   bmp := TBitmap.Create;
  11.   try
  12.     cvs.Handle := GetDC(0);
  13.     bmp.SetSize(Screen.Width, Screen.Height);
  14.     try
  15.       r1 := Rect(0, 0, bmp.Width, bmp.Height);
  16.       r2 := Rect(0, 0, Screen.Width, Screen.Height);
  17.       bmp.Canvas.CopyRect(r1, cvs, r2);
  18.     finally
  19.       ReleaseDC(0, cvs.Handle);
  20.       cvs.Handle := 0;
  21.     end;
  22.     Image1.Picture.Assign(bmp);
  23.   finally
  24.     bmp.Free;
  25.     cvs.Free;
  26.   end;
  27. end;


I hope it would work for your case.



Perhaps BitBlt (or CopyRect) work just fine. You may want to check other aspects, such as image saving code or somewhere else.
« Last Edit: September 02, 2026, 03:41:02 pm by Xenno »
Lazarus 4.6, Windows 10, Website, YouTube channel
If I want to share, I give. If I want money, I sell. I don't set traps.

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #7 on: September 03, 2026, 03:25:10 pm »
I tried with CopyRect, but

Code: Pascal  [Select][+][-]
  1.  Error: Identifier not found "TCanvas"

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #8 on: September 03, 2026, 03:31:12 pm »
You may want to check other aspects, such as image saving code or somewhere else.

More code from my application:

Code: Pascal  [Select][+][-]
  1. procedure TScreenGrabber.CaptureMonitor(AFileName: String; AMonitorId: Integer);
  2. var
  3.   Rect: TRect;
  4.   UsedMonitor: TMonitor;
  5. begin
  6.   DebugLn(['Monitor id=', AMonitorId]);
  7.  
  8.   UsedMonitor := Screen.Monitors[AMonitorId];
  9.   Rect.Left   := UsedMonitor.Left;
  10.   Rect.Top    := UsedMonitor.Top;
  11.   Rect.Width  := UsedMonitor.Width;
  12.   Rect.Height := UsedMonitor.Height;
  13.   CaptureRegion(AFileName, Rect);
  14. end;
  15.  
  16. procedure TScreenGrabber.CaptureAllMonitors(AFileName: String);
  17. var
  18.   Rect: TRect;
  19. begin
  20.   Rect.Left   := GetSystemMetrics(SM_XVIRTUALSCREEN);
  21.   Rect.Top    := GetSystemMetrics(SM_YVIRTUALSCREEN);
  22.   Rect.Width  := GetSystemMetrics(SM_CXVIRTUALSCREEN);
  23.   Rect.Height := GetSystemMetrics(SM_CYVIRTUALSCREEN);
  24.   CaptureRegion(AFileName, Rect);
  25. end;
  26.  
  27. procedure TScreenGrabber.CaptureRegion(AFileName: String; ARect: TRect);
  28. {$IfDef Linux}
  29. const
  30.   HWND_DESKTOP = 0;
  31. {$EndIf}
  32. var
  33.   Bitmap: TBGRABitmap;
  34.   Writer: TFPCustomImageWriter;
  35.   //GIF: TGIFImage;
  36.   ScreenDC: {$IfDef Windows}Windows.{$EndIf}HDC;
  37. begin
  38.   DebugLn('Start taking screenshot...');
  39.   DebugLn('Region: ', DbgS(ARect));
  40.  
  41.   Bitmap := TBGRABitmap.Create(ARect.Width, ARect.Height, BGRABlack);
  42.  
  43.   //Bitmap.TakeScreenshot(Rect); // Not supports multiply monitors
  44.   ScreenDC := GetDC(HWND_DESKTOP); // Get DC for all monitors
  45.   DebugLn('ScreenDC=', DbgS(ScreenDC));
  46.   {$IfDef Windows}
  47.   // https://github.com/artem78/AutoScreenshot/issues/35
  48.   // and https://github.com/bgrabitmap/bgrabitmap/issues/200
  49.   BitBlt(Bitmap.Canvas.Handle, 0, 0, ARect.Width, ARect.Height,
  50.            ScreenDC, ARect.Left, ARect.Top, SRCCOPY);
  51.   {$EndIf}
  52.   {$IfDef Linux}
  53.   // ToDo: Check bug #35 in Linux
  54.   Bitmap.LoadFromDevice(ScreenDC, ARect);
  55.   {$EndIf}
  56.  
  57.   ReleaseDC(0, ScreenDC);
  58.  
  59.   case ImageFormat of
  60.     fmtPNG:      // PNG
  61.       begin
  62.         Writer := TFPWriterPNG.create;
  63.  
  64.         with Writer as TFPWriterPNG do
  65.         begin
  66.           GrayScale := IsGrayscale;
  67.           CompressionLevel := Self.CompressionLevel;
  68.           //Indexed := ...;
  69.           //UseAlpha := ...;
  70.         end;
  71.       end;
  72.  
  73.     fmtJPG:     // JPEG
  74.       begin
  75.         Writer := TFPWriterJPEG.Create;
  76.  
  77.         with Writer as TFPWriterJPEG do
  78.         begin
  79.           CompressionQuality := Quality;
  80.           GrayScale := IsGrayscale;
  81.         end;
  82.       end;
  83.  
  84.     fmtBMP:    // Bitmap (BMP)
  85.       begin
  86.         Writer := TFPWriterBMP.Create;
  87.  
  88.         with Writer as TFPWriterBMP do
  89.         begin
  90.           BitsPerPixel := Integer(ColorDepth);
  91.           //RLECompress := ...;
  92.         end;
  93.       end;
  94.  
  95.     {fmtGIF:    // GIF
  96.       begin
  97.         GIF := TGIFImage.Create;
  98.         try
  99.           GIF.Assign(Bitmap);
  100.           //GIF.OptimizeColorMap;
  101.           GIF.SaveToFile(AFileName);
  102.         finally
  103.           GIF.Free;
  104.         end;
  105.       end;}
  106.  
  107.       fmtTIFF:
  108.         begin
  109.           Writer := TFPWriterTiff.Create;
  110.         end;
  111.  
  112.       fmtWEBP:
  113.         begin
  114.           Writer := TBGRAWriterWebP.Create;
  115.         end;
  116.  
  117.       fmtAVIF:
  118.         begin
  119.           {$IfDef Windows}
  120.           // flipped image fix
  121.           Bitmap.VerticalFlip();
  122.           {$EndIf}
  123.           Writer := TBGRAWriterAvif.Create;
  124.         end;
  125.   end;
  126.  
  127.   try
  128.     try
  129.       Bitmap.SaveToFile(AFileName, Writer);
  130.     except
  131.       on E : Exception do
  132.       begin
  133.         DebugLn('Failed to take screenshot: ', E.ToString);
  134.         raise e;
  135.       end;
  136.     end;
  137.   finally
  138.     Writer.Free;
  139.     Bitmap.Free;
  140.   end;
  141.  
  142.   DebugLn('Screenshot saved to ', AFileName);
  143. end;

Xenno

  • Full Member
  • ***
  • Posts: 203
    • BS Programs
Re: Black image instead of screen captures in Windows
« Reply #9 on: September 03, 2026, 03:51:31 pm »
Code: Pascal  [Select][+][-]
  1.  Error: Identifier not found "TCanvas"
Code: Pascal  [Select][+][-]
  1. uses ... Graphics ...

More code from my application:
...
This needs extensive check.
I can only suggest a few things although I'm sure you've done:
  • Make sure to test running in debug mode.
  • Ensure all Create-Free pairs flow.
  • Wrap GetDC-ReleaseDC in try-finally.
  • BitBlt is function returning Boolean. You may need read this.
Lazarus 4.6, Windows 10, Website, YouTube channel
If I want to share, I give. If I want money, I sell. I don't set traps.

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #10 on: September 11, 2026, 12:21:54 pm »
  • BitBlt is function returning Boolean. You may need read this.

Several times I catched broken screenshots on my computer with enabled logging and in all cases BitBlt returned True. Seems you are right and the real cause somewhere in another place...

Xenno

  • Full Member
  • ***
  • Posts: 203
    • BS Programs
Re: Black image instead of screen captures in Windows
« Reply #11 on: September 11, 2026, 12:47:16 pm »
A small check: Is ARect param for CaptureRegion procedure always the same with retangle of the screen to capture? Probably, a game changes screen resolution. Thus the procedure needs to read (refresh) the screen rectangle itself before setting bitmap size and capturing. I doubt my own question, though, cause you called it CaptureRegion which I assume not the whole screen (monitor).
Lazarus 4.6, Windows 10, Website, YouTube channel
If I want to share, I give. If I want money, I sell. I don't set traps.

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #12 on: September 12, 2026, 10:50:56 pm »
My application supports multiscreen. CaptureRegion can be called only from two places: CaptureMonitor and CaptureAllMonitors. So it recieves TRect contains coordinates of one monitor or whole area for all available monitors.

A small check: Is ARect param for CaptureRegion procedure always the same with retangle of the screen to capture?

Yes. On the attached image you can see part of the log when broken image happen. Selected lines corresponds to broken screenshot (on the right window). All other to normal screenshots. As you can see region everywhere has correct value of my single monitor 1440x900.

artem101

  • Full Member
  • ***
  • Posts: 131
Re: Black image instead of screen captures in Windows
« Reply #13 on: September 12, 2026, 10:57:34 pm »
Just now I saw in log very strange thing! Each time value of ScreenDC variable is different. But when broken screenshot taken this variable has previous value.

It's too late. I go to bed now and will check this tomorrow...


 

TinyPortal © 2005-2018