Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

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

01.01.2007

Приведенный ниже модуль демонстрирует принцип использования 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 {iPosition};
 
function jPosition(const j: INTEGER): INTEGER;
begin
 
  RESULT := Integer(j * LongInt(Printer.PageHeight) div 1000)
end {jPosition};
 
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;
begin
 
  Printer.Orientation := poLandscape;
  Printer.BeginDoc;
 
{Делаем прямоугольник для показа полей}
  Printer.Canvas.Rectangle(0, 0, Printer.PageWidth, Printer.PageHeight);
 
{Свойства принтера и страницы}
  Printer.Canvas.Font.Name := 'Times New Roman';
  Printer.Canvas.Font.Size := 12;
  Printer.Canvas.Font.Style := [fsBold];
  Printer.Canvas.TextOut(iPosition(50), jPosition(40), 'Свойства принтера и страницы');
 
  Printer.Canvas.Font.Style := [];
  Printer.Canvas.Font.Size := 10;
  iBase := iPosition(50);
  jBase := 60;
  jDelta := 18;
  Printer.Canvas.TextOut(iPosition(50), jPosition(jBase),
    Printer.Printers.Strings[Printer.PrinterIndex]);
  INC(jBase, jDelta);
 
  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Пикселей:  ' + IntToStr(Printer.PageWidth) + ' X ' +
    IntToStr(Printer.PageHeight));
  INC(jBase, jDelta);
 
  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Дюймов:  ' + FormatFloat('0.000',
    Printer.PageWidth / Printer.Canvas.Font.PixelsPerInch) + ' X ' +
    FormatFloat('0.000',
    Printer.PageHeight / Printer.Canvas.Font.PixelsPerInch));
  INC(jBase, 2 * jDelta);
 
  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Шрифт:  ' + Printer.Canvas.Font.Name + '   Размер:  ' +
    IntToStr(Printer.Canvas.Font.Size));
  INC(jBase, jDelta);
 
  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Пикселей в дюйме:  ' + IntToStr(Printer.Canvas.Font.PixelsPerInch));
  INC(jBase, jDelta);
 
  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    '`ТЕКСТ`:  ' + IntToStr(Printer.Canvas.TextWidth('ТЕКСТ')) + ' X ' +
    IntToStr(Printer.Canvas.TextHeight('ТЕКСТ')) + '
    пикселей');
 
{Значения GetDeviceCaps}
    INC(jBase, 2 * jDelta);
    Printer.Canvas.Font.Size := 12;
    Printer.Canvas.Font.Style := [fsBold];
    Printer.Canvas.TextOut(iBase, jPosition(jBase), 'GetDeviceCaps');
    INC(jBase, jDelta);
 
    Printer.Canvas.Font.Size := 10;
    Printer.Canvas.Font.Style := [];
 
    for j := LOW(DeviceCapsIndex) to HIGH(DeviceCapsIndex) do
      begin
        value := GetDeviceCaps(Printer.Handle, DeviceCapsIndex[j]);
        Printer.Canvas.TextOut(iBase, jPosition(jBase), DeviceCapsString[j]);
 
        if (DeviceCapsIndex[j] < 28) or (DeviceCapsIndex[j] > 38) then
          Printer.Canvas.TextOut(iPosition(250), jPosition(jBase), Format('%-8d', [value]))
        else
          Printer.Canvas.TextOut(iPosition(250), jPosition(jBase), Format('%.4x', [value]));
 
        INC(jBase, jDelta);
 
      end;
 
{Помещаем изображение в левый нижний угол}
    Printer.Canvas.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));
 
    Printer.Canvas.TextOut(4 * iPixelsPerInch, jPixelsPerInch -
    Printer.Canvas.TextHeight('X'),
    '2" ширина от (4", 1")');
    Printer.Canvas.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);
 
    Printer.Canvas.TextOut(4 * iPixelsPerInch, 4 * jPixelsPerInch -
    Printer.Canvas.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;
 
      Printer.Canvas.CopyRect(DestinationRectangle, OffScreen.Canvas,
        SourceRectangle);
    finally
      OffScreen.Free
    end;
 
{Список шрифтов для данного принтера}
    iBase := iPosition(750);
    Printer.Canvas.Font.Name := 'Times New Roman';
    Printer.Canvas.Font.Size := 12;
    Printer.Canvas.Font.Style := [fsBold];
    Printer.Canvas.TextOut(iBase, jPosition(40), 'Шрифты');
 
    Printer.Canvas.Font.Style := [];
    Printer.Canvas.Font.Size := 10;
    jDelta := 16;
    for j := 0 to Printer.Fonts.Count - 1 do
      begin
        Printer.Canvas.TextOut(iBase, jPosition(60 + jDelta * j), Printer.Fonts.Strings[j])
      end;
 
    Printer.EndDoc;
 
end;
 
end.

Взято из Советов по Delphi от Валентина Озерова

Сборник Kuliba