Данный документ содержит подробное описание способа печати содержимого формы:
получение отдельных битов устройства при 256-цветной форме, и использования
полученных битов для печати формы на принтере.
Кроме того, в данном коде осуществляется проверка палитры устройства (экран
или принтер), и включается обработка палитры соответствующего устройства. Если
устройством палитры является устройство экрана, принимаются дополнительные меры
по заполнению палитры растрового изображения из системной палитры, избавляющие
от некорректного заполнения палитры некоторыми видеодрайверами.
Примечание: Поскольку данный код делает снимок формы, форма должна
располагаться на самом верху, поверх остальных форм, быть полность на экране, и
быть видимой на момент ее "съемки".
unit Prntit;
interfaceuses
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 thenbegin
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 thenbegin
pal := CreatePalette(pPal^);
oldPal := SelectPalette(MemDc, Pal, false);
isDcPalDevice := trueendelse
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 = truethenbegin
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 = truethenbeginfor i := 0 to (pPal^.PalNumEntries - 1) dobegin
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 thenbegin
ScaleX := Printer.PageWidth;
ScaleY := Form1.Height * (Printer.PageWidth / Form1.Width);
endelsebegin
ScaleX := Form1.Width * (Printer.PageHeight / Form1.Height);
ScaleY := Printer.PageHeight;
end;
{Просто используем драйвер принтера для устройства палитры}
isDcPalDevice := false;
if GetDeviceCaps(Printer.Canvas.Handle, RASTERCAPS) and
RC_PALETTE = RC_PALETTE thenbegin{Создаем палитру для 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) dobegin
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 := trueend;
{посылаем биты на принтер}
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 = truethenbegin
SelectPalette(Printer.Canvas.Handle, oldPal, false);
DeleteObject(Pal);
end;
{Очищаем распределенную память} GlobalUnlock(hBits);
GlobalFree(hBits);
GlobalUnlock(hDibHeader);
GlobalFree(hDibHeader);
{Заканчиваем работу печати}
Printer.EndDoc;
end;
Текст:
Код предназначен для печати формы на принтере с помощью функции StretchDiBits, которая растягивает и печатает форму на принтере. Код также включает в себя обработку ошибок для некоторых видеодрайверов, которые могут не работать корректно с определенным типом палеток.
Основные точки кода:
Обработка палеток: Код проверяет, является ли контекст устройства (DC) палеткой устройства, то есть это экран или принтер с глубиной цвета 8 бит на пиксель. Если это так, код создает палету и выбирает ее для DC.
Создание битовки: Код создает битовку из формы с помощью функции CreateCompatibleBitmap.
Обработка DIB (Device-Independent Bitmap): Код использует DIB для хранения изображения формы в устройствонезависимом формате, который может быть использован любым устройством, поддерживающим битмапы.
StretchDiBits: Код использует функцию StretchDiBits для растягивания и печати формы на принтере.
Вот некоторые улучшения, которые можно было бы сделать:
Организация кода: Код quite long and complex. Он будет легче читаться, если он будет разбит на более маленькие функции, каждая из которых имеет свою ответственность.
Обработка ошибок: Код имеет некоторые обработки ошибок для конкретных видеодрайверов, но это не полноценная обработка ошибок. Лучше было бы иметь более robust механизм обработки ошибок.
Комментарии кода: В коде нет комментариев, что делает его трудным для понимания, что каждый раздел кода делает.
Имя переменных: Некоторые имена переменных, такие как pPal и pDibHeader, не очень описательны.
Обратите внимание, что это упрощенная версия кода и может не работать в вашей конкретной ситуации.
Лучший способ печати формы: получение отдельных битов устройства при 256-цветной форме, и использования полученных битов для печати формы на принтере.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.