Сохранение точных размеров при печати

Приведенный ниже модуль демонстрирует принцип использования GetDeviceCaps для получения исчерпывающей информации о вашем принтере, включая HORZRES и VERTRES (горизонтальное и вертикальное разрешение в пикселах) на дюйм бумаги. Используя значения LOGPIXELSX и LOGPIXELSY, вы можете откалибровать принтер для точного задания количества точек на дюйм в горизонтальном и вертикальном направлениях.
В дополнение к информации о принтере, приведенный модуль демонстрирует способ печати, при котором изображение выводится на принтер "естественного" размера; также показана возможность размещения изображения на бумаге в определенной позиции и определенного размера (т.е. с применением масштабирования). Я думаю это должно вам помочь в деле управления принтером.
Пример также демонстрирует вывод на печать синусной кривой в конкретной позиции печати с заданными в дюймах размерами. Я думаю вы без труда разберетесь как перейти на метрическую систему размеров.
unit Tstpr2fm;
{ Пример использования объекта Printer из модуля TPrinter.
Приведен избыточный стиль программирования для облегчения
восприятия материала.
Демонстрация величин, возвращаемых функцией Windows API GetDeviceCaps. }
interface
uses
 SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
 Forms, Dialogs, StdCtrls, ExtCtrls;
type
 TForm1 = class(TForm)
 Print: TButton;
 Image1: TImage;
 procedure PrintClick(Sender: TObject);
 private
 { Private declarations }
 public
 { Public declarations }
 end;
var
 Form1: TForm1;
implementation
uses
 Printers;
{ Константы WINAPI GetDeviceCaps получены из C++ windows.h и wingdi.h }
{ Отдельные константы здесь приведены только для информации о их наличии }
const
 DRIVERVERSION = 0;
 TECHNOLOGY = 2; { Смотри windows.h для значения маски }
 HORZSIZE = 4;
 VERTSIZE = 6;
 HORZRES = 8;
 VERTRES = 10;
 BITSPIXEL = 12;
 PLANES = 14;
 NUMBRUSHES = 16;
 NUMPENS = 18;
 NUMMARKERS = 20;
 NUMFONTS = 22;
 NUMCOLORS = 24;
 PDEVICESIZE = 26;
 CURVECAPS = 28; { Смотри windows.h для значения маски }
 LINECAPS = 30; { Смотри windows.h для значения маски }
 POLYGONALCAPS = 32; { Смотри windows.h для значения маски }
 TEXTCAPS = 34; { Смотри windows.h для значения маски }
 CLIPCAPS = 36; { Смотри windows.h для значения маски }
 RASTERCAPS = 38; { Смотри windows.h для значения маски }
 ASPECTX = 40;
 ASPECTY = 42;
 ASPECTXY = 44;
 LOGPIXELSX = 88;
 LOGPIXELSY = 90;
 SIZEPALETTE = 104;
 NUMRESERVED = 106;
 COLORRES = 108;
 PHYSICALWIDTH = 110; { Смотри определение в windows.h }
 PHYSICALHEIGHT = 111; { Смотри определение в windows.h }
 PHYSICALOFFSETX = 112; { Смотри определение в windows.h }
 PHYSICALOFFSETY = 113; { Смотри определение в windows.h }
 SCALINGFACTORX = 114; { Смотри определение в windows.h }
 SCALINGFACTORY = 115; { Смотри определение в windows.h }
 DeviceCapsString: array[1..34] of string =
 ('DRIVERVERSION', 'TECHNOLOGY', 'HORZSIZE',
 'VERTSIZE', 'HORZRES', 'VERTRES',
 'BITSPIXEL', 'PLANES', 'NUMBRUSHES',
 'NUMPENS', 'NUMMARKERS', 'NUMFONTS',
 'NUMCOLORS', 'PDEVICESIZE', 'CURVECAPS',
 'LINECAPS', 'POLYGONALCAPS', 'TEXTCAPS',
 'CLIPCAPS', 'RASTERCAPS', 'ASPECTX',
 'ASPECTY', 'ASPECTXY', 'LOGPIXELSX',
 'LOGPIXELSY', 'SIZEPALETTE', 'NUMRESERVED',
 'COLORRES', 'PHYSICALWIDTH', 'PHYSICALHEIGHT',
 'PHYSICALOFFSETX', 'PHYSICALOFFSETY', 'SCALINGFACTORX',
 'SCALINGFACTORY');
 DeviceCapsIndex: array[1..34] of Integer =
 (0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
 20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
 40, 42, 44, 88, 90, 104, 106, 108, 110, 111,
 112, 113, 114, 115);
{$R *.DFM}
function iPosition(const i: Integer): Integer;
begin
 Result := Integer(i * LongInt(Printer.PageWidth) div 1000);
end;
function jPosition(const j: Integer): Integer;
begin
 Result := Integer(j * LongInt(Printer.PageHeight) div 1000);
end;
procedure TForm1.PrintClick(Sender: TObject);
var
 DestinationRectangle: TRect;
 GraphicAspectRatio: Double;
 i: Integer;
 j: Integer;
 iBase: Integer;
 iPixelsPerInch: WORD;
 jBase: Integer;
 jDelta: Integer;
 jPixelsPerInch: WORD;
 OffScreen: TBitMap;
 PixelAspectRatio: Double;
 SourceRectangle: TRect;
 TargetRectangle: TRect;
 value: Integer;
 x: Double;
 y: Double;
 c: TCanvas;
begin
 Printer.Orientation := poLandscape;
 Printer.BeginDoc;
 c := Printer.Canvas;
 { Делаем прямоугольник для показа полей }
 c.Rectangle(0, 0, Printer.PageWidth, Printer.PageHeight);
 { Свойства принтера и страницы }
 c.Font.Name := 'Times New Roman';
 c.Font.Size := 12;
 c.Font.Style := [fsBold];
 c.TextOut(iPosition(50), jPosition(40), 'Свойства принтера и страницы');
 c.Font.Style := [];
 c.Font.Size := 10;
 iBase := iPosition(50);
 jBase := 60;
 jDelta := 18;
 c.TextOut(iPosition(50), jPosition(jBase),
 Printer.Printers.Strings[Printer.PrinterIndex]);
 Inc(jBase, jDelta);
 c.TextOut(iBase, jPosition(jBase),
 'Пикселей: ' + IntToStr(Printer.PageWidth) + ' X ' +
 IntToStr(Printer.PageHeight));
 Inc(jBase, jDelta);
 c.TextOut(iBase, jPosition(jBase),
 'Дюймов: ' + FormatFloat('0.000',
 Printer.PageWidth / c.Font.PixelsPerInch) + ' X ' +
 FormatFloat('0.000',
 Printer.PageHeight / c.Font.PixelsPerInch));
 Inc(jBase, 2 * jDelta);
 c.TextOut(iBase, jPosition(jBase),
 'Шрифт: ' + c.Font.Name + ' Размер: ' +
 IntToStr(c.Font.Size));
 Inc(jBase, jDelta);
 c.TextOut(iBase, jPosition(jBase),
 'Пикселей в дюйме: ' + IntToStr(c.Font.PixelsPerInch));
 Inc(jBase, jDelta);
 c.TextOut(iBase, jPosition(jBase),
 '`ТЕКСТ`: ' + IntToStr(c.TextWidth('ТЕКСТ')) + ' X ' +
 IntToStr(c.TextHeight('ТЕКСТ')) + '
 пикселей');
 { Значения GetDeviceCaps }
 Inc(jBase, 2 * jDelta);
 c.Font.Size := 12;
 c.Font.Style := [fsBold];
 c.TextOut(iBase, jPosition(jBase), 'GetDeviceCaps');
 Inc(jBase, jDelta);
 c.Font.Size := 10;
 c.Font.Style := [];
 for j := Low(DeviceCapsIndex) to High(DeviceCapsIndex) do
 begin
 value := GetDeviceCaps(Printer.Handle, DeviceCapsIndex[j]);
 c.TextOut(iBase, jPosition(jBase), DeviceCapsString[j]);
 if (DeviceCapsIndex[j] < 28) or (DeviceCapsIndex[j] > 38) then
 c.TextOut(iPosition(250), jPosition(jBase), Format('%-8d', [value]))
 else
 c.TextOut(iPosition(250), jPosition(jBase), Format('%.4x', [value]));
 Inc(jBase, jDelta);
 end;
 { Помещаем изображение в левый нижний угол }
 c.Draw(iPosition(300), jPosition(100),
 Form1.Image1.Picture.Graphic);
 { Помещаем то же изображение, имеющее ширину 1" и пропорциональную
 высоту в позиции 4"-правее и 1"-ниже верхнего левого угла }
 GraphicAspectRatio := Form1.Image1.Picture.Height /
 Form1.Image1.Picture.Width;
 iPixelsPerInch := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
 jPixelsPerInch := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
 PixelAspectRatio := jPixelsPerInch / iPixelsPerInch;
 TargetRectangle := Rect(4 * iPixelsPerInch, { 4" }
 jPixelsPerInch, { 1" }
 6 * iPixelsPerInch, { 6" -- 2" ширина }
 jPixelsPerInch +
 TRUNC(2 * iPixelsPerInch * GraphicAspectRatio *
 PixelAspectRatio));
 c.TextOut(4 * iPixelsPerInch, jPixelsPerInch -
 c.TextHeight('X'),
 '2" ширина от (4", 1")');
 c.StretchDraw(TargetRectangle, Form1.Image1.Picture.Graphic);
 { Создаем изображение в памяти и затем копируем его на холст принтера }
 SourceRectangle := Rect(0, 0, 3 * iPixelsPerInch - 1, 2 * jPixelsPerInch - 1);
 { Это не должно работать! Rectangle = Left, Top, Right, Bottom
 Top и Bottom считаются зарезервированными? }
 DestinationRectangle := Rect(4 * iPixelsPerInch, 6 * jPixelsPerInch,
 7 * iPixelsPerInch - 1, 4 * jPixelsPerinch - 1);
 c.TextOut(4 * iPixelsPerInch, 4 * jPixelsPerInch - c.TextHeight('X'),
 IntToStr(3 * iPixelsPerInch) + ' пикселей на ' +
 IntToStr(2 * jPixelsPerInch) + ' пикселей -- ' +
 '3"-на-2" в (4",4")');
 OffScreen := TBitMap.Create;
 try
 OffScreen.Width := SourceRectangle.Right + 1;
 OffScreen.Height := SourceRectangle.Bottom + 1;
 with OffScreen.Canvas do
 begin
 Pen.Color := clBlack;
 Brush.Color := clWhite;
 Rectangle(0, 0, 3 * iPixelsPerInch - 1, 2 * jPixelsPerInch - 1);
 Brush.Color := clRed;
 MoveTo(0, 0);
 LineTo(3 * iPixelsPerInch - 1, 2 * jPixelsPerInch - 1);
 Brush.Color := clBlue;
 MoveTo(0, 0);
 for i := 0 to 3 * iPixelsPerInch - 1 do
 begin
 x := 12 * PI * (i / (3 * iPixelsPerInch - 1));
 y := jPixelsPerInch + jPixelsPerInch * SIN(x);
 LineTo(i, TRUNC(y));
 end;
 end;
 c.CopyRect(DestinationRectangle, OffScreen.Canvas, SourceRectangle);
 finally
 OffScreen.Free;
 end;
 { Список шрифтов для данного принтера }
 iBase := iPosition(750);
 c.Font.Name := 'Times New Roman';
 c.Font.Size := 12;
 c.Font.Style := [fsBold];
 c.TextOut(iBase, jPosition(40), 'Шрифты');
 c.Font.Style := [];
 c.Font.Size := 10;
 jDelta := 16;
 for j := 0 to Printer.Fonts.Count - 1 do
 begin
 c.TextOut(iBase, jPosition(60 + jDelta * j), Printer.Fonts.Strings[j])
 end;
 Printer.EndDoc;
end;
end.
Source: Взято из Советов по Delphi от Валентина Озерова
ID: 03241
Category:Принтер