Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Подробное описание способа печати содержимого формы

01.01.2007

Данный документ содержит подробное описание способа печати содержимого формы: получение отдельных битов устройства при 256-цветной форме, и использования полученных битов для печати формы на принтере.

Кроме того, в данном коде осуществляется проверка палитры устройства (экран или принтер), и включается обработка палитры соответствующего устройства. Если устройством палитры является устройство экрана, принимаются дополнительные меры по заполнению палитры растрового изображения из системной палитры, избавляющие от некорректного заполнения палитры некоторыми видеодрайверами.

Примечание

Поскольку данный код делает снимок формы, форма должна располагаться на самом верху, поверх остальных форм, быть полность на экране, и быть видимой на момент ее "съемки".

unit Prntit;
 
interface
 
uses
 
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
 
Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
 
type
  TForm1
= class(TForm)
    Button1
: TButton;
    Image1
: TImage;
    procedure Button1Click
(Sender: TObject);
 
private
   
{ Private declarations }
 
public
   
{ Public declarations }
 
end;
 
var
  Form1
: TForm1;
 
implementation
 
{$R *.DFM}
 
uses
Printers;
 
procedure TForm1
.Button1Click(Sender: TObject);
var
 
  dc
: HDC;
  isDcPalDevice
: BOOL;
 
MemDc: hdc;
 
MemBitmap: hBitmap;
 
OldMemBitmap: hBitmap;
  hDibHeader
: Thandle;
  pDibHeader
: pointer;
  hBits
: Thandle;
  pBits
: pointer;
 
ScaleX: Double;
 
ScaleY: Double;
  ppal
: PLOGPALETTE;
  pal
: hPalette;
 
Oldpal: hPalette;
  i
: integer;
begin
 
 
{Получаем dc экрана}
  dc
:= GetDc(0);
 
{Создаем совместимый dc}
 
MemDc := CreateCompatibleDc(dc);
 
{создаем изображение}
 
MemBitmap := CreateCompatibleBitmap(Dc,
    form1
.width,
    form1
.height);
 
{выбираем изображение в dc}
 
OldMemBitmap := SelectObject(MemDc, MemBitmap);
 
 
{Производим действия, устраняющие ошибки при работе с некоторыми типами видеодрайверов}
  isDcPalDevice
:= false;
 
if GetDeviceCaps(dc, RASTERCAPS) and
    RC_PALETTE
= RC_PALETTE then
 
begin
   
GetMem(pPal, sizeof(TLOGPALETTE) +
     
(255 * sizeof(TPALETTEENTRY)));
   
FillChar(pPal^, sizeof(TLOGPALETTE) +
     
(255 * sizeof(TPALETTEENTRY)), #0);
    pPal
^.palVersion := $300;
    pPal
^.palNumEntries :=
     
GetSystemPaletteEntries(dc,
     
0,
     
256,
      pPal
^.palPalEntry);
   
if pPal^.PalNumEntries <> 0 then
   
begin
      pal
:= CreatePalette(pPal^);
      oldPal
:= SelectPalette(MemDc, Pal, false);
      isDcPalDevice
:= true
   
end
   
else
     
FreeMem(pPal, sizeof(TLOGPALETTE) +
       
(255 * sizeof(TPALETTEENTRY)));
 
end;
 
 
{копируем экран в memdc/bitmap}
 
BitBlt(MemDc,
   
0, 0,
    form1
.width, form1.height,
   
Dc,
    form1
.left, form1.top,
   
SrcCopy);
 
 
if isDcPalDevice = true then
 
begin
   
SelectPalette(MemDc, OldPal, false);
   
DeleteObject(Pal);
 
end;
 
 
{удаляем выбор изображения}
 
SelectObject(MemDc, OldMemBitmap);
 
{удаляем dc памяти}
 
DeleteDc(MemDc);
 
{Распределяем память для структуры DIB}
  hDibHeader
:= GlobalAlloc(GHND,
   
sizeof(TBITMAPINFO) +
   
(sizeof(TRGBQUAD) * 256));
 
{получаем указатель на распределенную память}
  pDibHeader
:= GlobalLock(hDibHeader);
 
 
{заполняем dib-структуру информацией, которая нам необходима в DIB}
 
FillChar(pDibHeader^,
   
sizeof(TBITMAPINFO) + (sizeof(TRGBQUAD) * 256),
   
#0);
  PBITMAPINFOHEADER
(pDibHeader)^.biSize :=
   
sizeof(TBITMAPINFOHEADER);
  PBITMAPINFOHEADER
(pDibHeader)^.biPlanes := 1;
  PBITMAPINFOHEADER
(pDibHeader)^.biBitCount := 8;
  PBITMAPINFOHEADER
(pDibHeader)^.biWidth := form1.width;
  PBITMAPINFOHEADER
(pDibHeader)^.biHeight := form1.height;
  PBITMAPINFOHEADER
(pDibHeader)^.biCompression := BI_RGB;
 
 
{узнаем сколько памяти необходимо для битов}
 
GetDIBits(dc,
   
MemBitmap,
   
0,
    form1
.height,
   
nil,
   
TBitmapInfo(pDibHeader^),
    DIB_RGB_COLORS
);
 
 
{Распределяем память для битов}
  hBits
:= GlobalAlloc(GHND,
   
PBitmapInfoHeader(pDibHeader)^.BiSizeImage);
 
{Получаем указатель на биты}
  pBits
:= GlobalLock(hBits);
 
 
{Вызываем функцию снова, но на этот раз нам передают биты!}
 
GetDIBits(dc,
   
MemBitmap,
   
0,
    form1
.height,
    pBits
,
   
PBitmapInfo(pDibHeader)^,
    DIB_RGB_COLORS
);
 
 
{Пробуем исправить ошибки некоторых видеодрайверов}
 
if isDcPalDevice = true then
 
begin
   
for i := 0 to (pPal^.PalNumEntries - 1) do
   
begin
     
PBitmapInfo(pDibHeader)^.bmiColors[i].rgbRed :=
        pPal
^.palPalEntry[i].peRed;
     
PBitmapInfo(pDibHeader)^.bmiColors[i].rgbGreen :=
        pPal
^.palPalEntry[i].peGreen;
     
PBitmapInfo(pDibHeader)^.bmiColors[i].rgbBlue :=
        pPal
^.palPalEntry[i].peBlue;
   
end;
   
FreeMem(pPal, sizeof(TLOGPALETTE) +
     
(255 * sizeof(TPALETTEENTRY)));
 
end;
 
 
{Освобождаем dc экрана}
 
ReleaseDc(0, dc);
 
{Удаляем изображение}
 
DeleteObject(MemBitmap);
 
 
{Запускаем работу печати}
 
Printer.BeginDoc;
 
 
{Масштабируем размер печати}
 
if Printer.PageWidth < Printer.PageHeight then
 
begin
   
ScaleX := Printer.PageWidth;
   
ScaleY := Form1.Height * (Printer.PageWidth / Form1.Width);
 
end
 
else
 
begin
   
ScaleX := Form1.Width * (Printer.PageHeight / Form1.Height);
   
ScaleY := Printer.PageHeight;
 
end;
 
 
{Просто используем драйвер принтера для устройства палитры}
  isDcPalDevice
:= false;
 
if GetDeviceCaps(Printer.Canvas.Handle, RASTERCAPS) and
    RC_PALETTE
= RC_PALETTE then
 
begin
   
{Создаем палитру для dib}
   
GetMem(pPal, sizeof(TLOGPALETTE) +
     
(255 * sizeof(TPALETTEENTRY)));
   
FillChar(pPal^, sizeof(TLOGPALETTE) +
     
(255 * sizeof(TPALETTEENTRY)), #0);
    pPal
^.palVersion := $300;
    pPal
^.palNumEntries := 256;
   
for i := 0 to (pPal^.PalNumEntries - 1) do
   
begin
      pPal
^.palPalEntry[i].peRed :=
       
PBitmapInfo(pDibHeader)^.bmiColors[i].rgbRed;
      pPal
^.palPalEntry[i].peGreen :=
       
PBitmapInfo(pDibHeader)^.bmiColors[i].rgbGreen;
      pPal
^.palPalEntry[i].peBlue :=
       
PBitmapInfo(pDibHeader)^.bmiColors[i].rgbBlue;
   
end;
    pal
:= CreatePalette(pPal^);
   
FreeMem(pPal, sizeof(TLOGPALETTE) +
     
(255 * sizeof(TPALETTEENTRY)));
    oldPal
:= SelectPalette(Printer.Canvas.Handle, Pal, false);
    isDcPalDevice
:= true
 
end;
 
 
{посылаем биты на принтер}
 
StretchDiBits(Printer.Canvas.Handle,
   
0, 0,
   
Round(scaleX), Round(scaleY),
   
0, 0,
    Form1
.Width, Form1.Height,
    pBits
,
   
PBitmapInfo(pDibHeader)^,
    DIB_RGB_COLORS
,
    SRCCOPY
);
 
 
{Просто используем драйвер принтера для устройства палитры}
 
if isDcPalDevice = true then
 
begin
   
SelectPalette(Printer.Canvas.Handle, oldPal, false);
   
DeleteObject(Pal);
 
end;
 
 
{Очищаем распределенную память} GlobalUnlock(hBits);
 
GlobalFree(hBits);
 
GlobalUnlock(hDibHeader);
 
GlobalFree(hDibHeader);
 
 
{Заканчиваем работу печати}
 
Printer.EndDoc;
 
end;

Взято с https://delphiworld.narod.ru