Как правильно печатать любую информацию (растровые и векторные изображения), а также как сделать режим предварительного просмотра?
Материал из DRKB
Как правильно печатать любую информацию (растровые и векторные изображения), а также как сделать режим предварительного просмотра?
Маленькое предисловие.[править | править код]
Т.к. основная моя работа связана с написанием софта для института, обрабатывающего геоданные, то и в отделе, где работаю, так же мучаются проблемами печати (в одном случае - надо печатать каpты, с изолиниями, заливкой, подписями и пр.; в другом случае - свои таблицы и сложные отрисовки по внешнему виду).
В итоге, моим коллегой был написан кусок, в котором ему удалось добиться качественной печати в двух режимах: MetaFile, Bitmap.
Работа с MetaFile у нас сложилась уже исторически - достаточно удобно описать функцию, которая что-то отрисовыват (хоть на экране, хоть где), которая принимает TCanvas, и подсовывать ей то канвас дисплея, то канвас метафайла, а потом этот Metafile выбрасывать на печать.
Достаточно решить лишь проблемы масштабирования, после чего - вперед.
Главная головная боль при таком методе - при отрисовке больших кусков, которые занимают весь лист или его большую часть, надо этот метафайл по размерам делать сpазу же в пикселах на этот самый лист. Тогда при изменении размеров (просмотр пеpед печатью) - искажения при уменьшении не критичны, а вот при увеличении линии и шрифты не "поползут".
Итак :
Набор идей, которые были написаны (с) Андреем Аpистовым, программистом отдела матобеспечения СибНИИНП, г. Тюмень. Моего здесь только - приделывание сверху надстроек для личного использования.
Вся работа сводится к следующим шагам :[править | править код]
- Получить необходимые коэффициенты.
- Построить метафайл или bmp для последующего вывода на печать.
- Напечатать.
Hиже приведенный кусок (прошу меня не пинать, но писал я и писал для достаточно кpивой реализации с передачей параметров через глобальные переменные) я использую для того, чтобы получить коэффициенты пересчета.
kScale - для пересчета размеров шрифта, а потом уже закладываюсь на его размеры и получаю два новых коэффициента для kW, kH - которые и позволяют мне с учетом высоты шрифта выводить графику и пр. У меня при работе kW <> kH, что приходится учитывать.
Решили пункт 1.[править | править код]
procedure SetKoeffMeta; // установить коэф-ты
var
PrevMetafile: TMetafile;
MetaCanvas: TMetafileCanvas;
begin
PrevMetafile := nil;
MetaCanvas := nil;
try
PrevMetaFile := TMetaFile.Create;
try
MetaCanvas := TMetafileCanvas.Create(PrevMetafile, 0);
kScale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) / Screen.PixelsPerInch;
MetaCanvas.Font.Assign(oGrid.Font);
MetaCanvas.Font.Size := Round(oGrid.Font.Size * kScale);
kW := MetaCanvas.TextWidth('W') / oGrid.Canvas.TextWidth('W');
kH := MetaCanvas.TextHeight('W') / oGrid.Canvas.TextHeight('W');
finally
MetaCanvas.Free;
end;
finally
PrevMetafile.Free;
end;
end;
Решаем 2.[править | править код]
var
PrevMetafile: TMetafile;
MetaCanvas: TMetafileCanvas;
begin
PrevMetafile := nil;
MetaCanvas := nil;
try
PrevMetaFile := TMetaFile.Create;
PrevMetafile.Width := oWidth;
PrevMetafile.Height := oHeight;
try
MetaCanvas := TMetafileCanvas.Create(PrevMetafile, 0);
// здесь должен быть ваш код - с учетом масштабирования.
// я эту вещь вынес в ассигнуемую процедуру, и данный блок
// вызываю лишь для отрисовки целой страницы.
// см. PS1 (ниже)
finally
MetaCanvas.Free;
end;
//...
- PS1
- Код, который используется для отрисовки. oCanvas - TCanvas метафайла.
var
iHPage: Integer; // высота страницы
begin
with oCanvas do
begin
iHPage := 3000;
// залили область метайфайла белым - для дальнейшей работы
Pen.Color := clBlack;
Brush.Color := clWhite;
FillRect(Rect(0, 0, 2000, iHPage));
// установили шрифты - с учетом их дальнейшего масштабирования
oCanvas.Font.Assign( oGrid.Font);
oCanvas.Font.Size := Round( oGrid.Font.Size * kScale );
//...
xEnd := xBegin;
iH := Round(RowHeights[iRow] * kH);
for iCol := 0 to ColCount - 1 do
begin
x := xEnd;
xEnd := x + Round(ColWidths[iCol] * kW);
Rectangle(x, yBegin, xEnd, yBegin + iH);
r := Rect(x + 1, yBegin + 1, xEnd - 1, yBegin + iH - 1);
s := Cells[iCol, iRow];
// выписали в полученный квадрат текст
DrawText(oCanvas.Handle, PChar(s), Length(s), r, DT_WORDBREAK or DT_CENTER);
Главное, что важно помнить на этом этапе - это не забывать, что все выводимые объекты должны пользоваться описанными коэффициентами (как вы их получите - это уже ваше дело). В данном случае - я работаю с переделанным TStringGrid, который сделал для многостраничной печати.
Последний пункт[править | править код]
Надо сформированный метафайл или bmp напечатать.
var
Info: PBitmapInfo;
InfoSize: Integer;
Image: Pointer;
ImageSize: DWORD;
Bits: HBITMAP;
DIBWidth, DIBHeight: Longint;
PrintWidth, PrintHeight: Longint;
begin
case ImageType of
itMetafile:
begin
if Picture.Metafile <> nil then
Printer.Canvas.StretchDraw(Rect(aLeft, aTop, aLeft + fWidth,
aTop + fHeight), Picture.Metafile);
end;
itBitmap:
begin
if Picture.Bitmap <> nil then
begin
with Printer, Canvas do
begin
Bits := Picture.Bitmap.Handle;
GetDIBSizes(Bits, InfoSize, ImageSize);
Info := AllocMem(InfoSize);
try
Image := AllocMem(ImageSize);
try
GetDIB(Bits, 0, Info^, Image^);
with Info^.bmiHeader do
begin
DIBWidth := biWidth;
DIBHeight := biHeight;
end;
PrintWidth := DIBWidth;
PrintHeight := DIBHeight;
StretchDIBits(Canvas.Handle, aLeft, aTop, PrintWidth,
PrintHeight, 0, 0, DIBWidth, DIBHeight, Image, Info^,
DIB_RGB_COLORS, SRCCOPY);
finally
FreeMem(Image, ImageSize);
end;
finally
FreeMem(Info, InfoSize);
end;
end;
end;
end;
end;
В чем заключается идея PreView? Остается имея на руках Metafila, Bmp - отрисовать с пересчетом внешний вид изображения (надо высчитать левый верхний угол и размеры "предварительно просматриваемого" изображения.
Для показа изображения достаточно использовать StretchDraw.
После того, как удалось вывести объекты на печать, проблему создания PreView решили как "домашнее задание".
Кстати, когда мы работаем с Bmp, то для просмотра используем следующий хинт - записываем битовый обpаз через такую процедуру:
w := MulDiv(Bmp.Width, GetDeviceCaps(Printer.Handle, LOGPIXELSX), Screen.PixelsPerInch);
h := MulDiv(Bmp.Height, GetDeviceCaps(Printer.Handle, LOGPIXELSY), Screen.PixelsPerInch);
PrevBmp.Width := w;
PrevBmp.Height := h;
PrevBmp.Canvas.StretchDraw(Rect(0, 0, w, h), Bmp);
aPicture.Assign(PrevBmp);
При этом масштабируется битовый обpаз с минимальными искажениями, а вот при печати - приходится bmp печатать именно так, как описано выше.
Итог - наша bmp при печати чуть меньше, чем печатать ее через WinWord, но при этом - внешне - без каких-либо искажений.
Imho, я для себя проблему печати решил. Hа основе вышесказанного, сделал PreView для myStringGrid, где вывожу сложные многострочные заголовки и прочее на несколько листов, осталось кое-что допилить, но с принтером у меня проблем не будет уже точно :)
PS. Кстати, Андpей Аpистов на основе своей наработки сделал сложные геокарты, которые по качестве не хуже, а может и лучше, чем выдает Surfer (специалисты поймут). Hа ватмат.
PPS. Прошу прощения за возможные стилистические неточности - время вышло, охрана уже ругается. Hо код - выдран из работающих исходников.
Борисов Олег Николаевич (ZB) panterra@sbtx.tmn.ru (2:5077/5)
Author: Борисов Олег Николаевич (ZB)
Source: Взято с сайта http://blackman.wp-club.net/
ID: 03225