Как правильно печатать любую информацию (растровые и векторные изображения), а также как сделать режим предварительного просмотра?

Как правильно печатать любую информацию (растровые и векторные изображения), а также как сделать режим предварительного просмотра? 
== Маленькое предисловие. ==
Т.к. основная моя работа связана с написанием софта для института, обрабатывающего геоданные, то и в отделе, где работаю, так же мучаются проблемами печати (в одном случае - надо печатать ка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
Category:Принтер