Freebie Friday: capture controls or forms
New year, new ideas. So, I’m happy to kick off with one of the many new ideas we have, which is the Freebie Friday!
Freebie Friday is simple. We share a useful code snippet that might be handy in your projects. We present it, you copy and paste it and you use it in your applications where you see use for it. Freebie Friday free source code snippets are the result of our daily work, writing components, offering support & consulting for customers … Over time, a huge collection of useful code builds up and instead of letting this collect dust, we cheer up your Friday, just before the weekend and present it here.
This first freebie is two routines that enable you to capture a control as image. The first that might come up is, why write a routine for this, a control offers control.PaintTo() and we can just use that to have the control paint to a canvas and save that to a file.
In theory yes, in practice, sadly this doesn’t work well with many controls. So, therefore these two routines that do work with any VCL control and as a bonus, it works with a VCL form as well, so you can capture entire forms to a bitmap or image.
Here we go, here is the code:
interface uses Classes, Windows, Messages, Graphics, JPEG, Controls, Types, Forms; procedure CaptureControl(AControl: TControl; ABitmap: TBitmap); procedure CaptureControlToJpeg(AControl: TControl; AFileName: string; AQuality: integer = 70); implementation uses Winapi.DwmApi, SysUtils; procedure CaptureControl(AControl: TControl; ABitmap: TBitmap); var LDesktopDC: HDC; LRect: TRect; LDWMRect: TRect; LPt: TPoint; begin LPt := AControl.ClientToScreen(Point(0,0)); LRect := Rect(LPt.X, LPt.Y, LPt.X + AControl.Width, LPt.Y + AControl.Height); if (AControl is TWinControl) and (AControl as TWinControl).HandleAllocated then begin GetWindowRect((AControl as TWinControl).Handle, LRect); end; if (AControl is TCustomForm) and (AControl as TCustomForm).HandleAllocated then begin GetWindowRect((AControl as TCustomForm).Handle, LRect); if (Win32MajorVersion >= 6) and DwmCompositionEnabled then begin if (DwmGetWindowAttribute((AControl as TCustomForm).Handle, DWMWA_EXTENDED_FRAME_BOUNDS, @LDWMRect, SizeOf(LDWMRect)) = S_OK) then begin LRect := LDWMRect; end; end; end; LDesktopDC := GetWindowDC(GetDesktopWindow); try ABitmap.PixelFormat := pf24bit; ABitmap.Height := LRect.Bottom - LRect.Top; ABitmap.Width := LRect.Right - LRect.Left; BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, LDesktopDC, LRect.Left, LRect.Top, SRCCOPY); finally ReleaseDC(GetDesktopWindow, LDesktopDC); end; end; procedure CaptureControlToJpeg(AControl: TControl; AFileName: string; AQuality: integer = 70); var LJpeg: TJpegImage; LBmp: TBitmap; begin LBmp := TBitmap.Create; try CaptureControl(AControl, LBmp); LJpeg := TJpegImage.Create; try LJpeg.Assign(LBmp); LJpeg.CompressionQuality := AQuality; LJpeg.SaveToFile(AFileName); finally LJpeg.Free; end; finally LBmp.Free; end; end;
To use these routines, you can do this with:
begin // capture a control to JPEG file setting JPEG quality to 90 CaptureControlToJpeg(mycontrol, 'mycontrol.jpg', 90); // capture a form (Self) to JPEG file setting JPEG quality to 50 CaptureControlToJpeg(Self, 'myform.jpg', 50); end;
To capture a control to bitmap, use:
var LBmp: TBitmap; begin LBmp := TBitmap.Create; try CaptureControl(mycontrol, LBmp); // do what you want with the bitmap here finally LBmp.Free; end; end;
Enjoy and have a good weekend!