Сохранение точных размеров при печати
Материал из DRKB
Приведенный ниже модуль демонстрирует принцип использования 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