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

Материал из 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