Перейти к содержанию
Fire Monkey от А до Я
  • 0

Смещение CANVSa или почему? при печати на принтер


Sashar333

Вопрос

Здравствуйте!

Подскажите пожалуйста в чем причина смещения изображения при печати по горизонтали относительно листа?

procedure ThePrint(day : arraySheet; prn : TPrintDialog);
var
  DestRect, Rect_cell, Rect_Size:TRectF;
  i,pageall:integer;
  textFill: tFillTextFlags;
  poses : TPoses;
  Col1 : boolean;
  COLROW : integer;
  sizeRow : Single;
  Image : TImage;
begin
  textFill := [];
  COLROW := 63;

  Printer.ActivePrinter := Printer.Printers[1];
  Printer.ActivePrinter.SelectDPI(Printer.ActivePrinter.DPI[Printer.ActivePrinter.DPICount-1]);

  Printer.BeginDoc;

  sizeRow := Printer.PageHeight / COLROW;
  poses := getPosY(day, sizeRow);

  Printer.Canvas.BeginScene;
  Printer.Canvas.Font.Size := sizeRow * 0.8;
  Printer.Canvas.Font.Family := 'Times New Roman';
  Printer.Canvas.Fill.Color := TAlphaColorRec.Black;
  Printer.Canvas.Fill.Kind := TBrushKind.Solid;
  Col1 := true;

  var WCol := Printer.PageWidth / 2 - 10;
  var WColW := WCol / 3;

  for var s := 0 to Length(poses)-1 do
    begin
      if Col1 then
        DestRect := RectF(0, poses[s], WCol, poses[s] + sizeRow)
      else
        DestRect := RectF(WCol, poses[s], Printer.Canvas.Width, poses[s] + sizeRow);

      Printer.Canvas.Font.Style:= Printer.Canvas.Font.Style + [TFontStyle.fsBold];
      Printer.Canvas.FillText(DestRect,day[0].listSheme[s].name,True,1,textFill,TTextAlign.Center,TTextAlign.Center);
      Printer.Canvas.Font.Style:= Printer.Canvas.Font.Style - [TFontStyle.fsBold];

      for var p := 0 to Length(day[0].listSheme[s].listPosition) - 1 do
        begin
          var nameSize := day[0].listSheme[s].listPosition[p].t + 'x' + day[0].listSheme[s].listPosition[p].w + 'x' +
                      day[0].listSheme[s].listPosition[p].l + '=';
          if day[0].listSheme[s].listPosition[p].c.ToInteger > 1 then
            nameSize := nameSize + day[0].listSheme[s].listPosition[p].c + 'л';


          Rect_cell := RectF(10, poses[s] + (sizeRow * (p+1)), WCol-30, poses[s] + (sizeRow * (p+2)));
          Rect_Size := RectF(0, poses[s] + (sizeRow * (p+1)), WCol - WColW, poses[s] + (sizeRow * (p+2)));
          if not Col1 then
          begin
            Rect_cell.Left := Rect_cell.Left + WCol + 20;
            Rect_cell.Right := Rect_cell.Right + WCol + 10;
            Rect_Size.Left := Rect_Size.Left + WCol + 20;
            Rect_Size.Right := Rect_Size.Right + WCol + 10;
          end;
          Printer.Canvas.FillText(Rect_cell, day[0].listSheme[s].listPosition[p].pn + ')' + day[0].listSheme[s].listPosition[p].s,
            True,1,textFill,TTextAlign.Leading,TTextAlign.Center);
          Printer.Canvas.FillText(Rect_Size, nameSize, True,1,textFill,TTextAlign.Trailing,TTextAlign.Center);
        end;


      Col1 := not(Col1);
    end;
  for var row  := 1 to COLROW do
  begin

    Printer.Canvas.DrawLine(TPointF.Create(0, sizeRow * row), TPointF.Create(WCol, sizeRow * row), 0.5);
    Printer.Canvas.DrawLine(TPointF.Create(WCol + 20, sizeRow * row), TPointF.Create(Printer.Canvas.Width, sizeRow * row), 0.5);
  end;

  DestRect := RectF(0, 0, Printer.Canvas.Width, sizeRow);
  Printer.Canvas.FillText(DestRect, day[0].name, True, 1, textFill, TTextAlign.Center,TTextAlign.Center);


  Printer.Canvas.DrawLine(TPointF.Create(WCol, sizeRow), TPointF.Create(WCol, Printer.Canvas.Height), 1);
  Printer.Canvas.DrawLine(TPointF.Create(WCol + 20, sizeRow), TPointF.Create(WCol + 20, Printer.Canvas.Height), 1);
  Printer.Canvas.DrawLine(TPointF.Create(0, sizeRow), TPointF.Create(500, Printer.Canvas.Height), 1);
  Printer.Canvas.DrawLine(TPointF.Create(Printer.Canvas.Width, sizeRow), TPointF.Create(Printer.Canvas.Width, Printer.Canvas.Height), 1);
  Printer.Canvas.DrawLine(TPointF.Create(WCol-WColW+20, sizeRow), TPointF.Create(WCol-WColW+20, Printer.Canvas.Height), 1);
  Printer.Canvas.DrawLine(TPointF.Create(Printer.Canvas.Width-WColW+20, sizeRow), TPointF.Create(Printer.Canvas.Width-WColW+20, Printer.Canvas.Height), 1);

  Printer.Canvas.EndScene;

  Printer.EndDoc;
end;

ВОТ ЧТО ПОЛУЧАЕТСЯ:

image.thumb.png.d43d86e8cbd7fa73f2e09c1061cb35c9.png

Линия спецом под угол, что бы понять само смещение в лево относительно листа.

Соответственно текст тоже видно на половину

Написано на Delphi 11, FMX.Printer

Заранее спасибо!

 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Вы печатаете с начала листа, но существуют так называемые "аппаратные поля" или "физические поля", в зависимости от возможностей принтера: это область, недоступная для печати, вокруг бумаги; то есть, если вы нарисуете что-то в этой области, оно не будет напечатано - эти поля зависят от принтера, и в некоторых случаях можно получить значения этих полей с помощью вызова

    LeftSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
    TopSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);

Ссылка на комментарий
  • 0
PHYSICALOFFSETX
For printing devices: the distance from the left edge of the physical page to the left edge of the printable area, in device units. For example, a printer set to print at 600 dpi on 8.5-by-11-inch paper, that cannot print on the leftmost 0.25-inch of paper, has a horizontal physical offset of 150 device units.
PHYSICALOFFSETY
For printing devices: the distance from the top edge of the physical page to the top edge of the printable area, in device units. For example, a printer set to print at 600 dpi on 8.5-by-11-inch paper, that cannot print on the topmost 0.5-inch of paper, has a vertical physical offset of 300 device units.
Ссылка на комментарий
  • 0
14 часов назад, OnePeople сказал:

Вы печатаете с начала листа, но существуют так называемые "аппаратные поля" или "физические поля", в зависимости от возможностей принтера: это область, недоступная для печати, вокруг бумаги; то есть, если вы нарисуете что-то в этой области, оно не будет напечатано - эти поля зависят от принтера, и в некоторых случаях можно получить значения этих полей с помощью вызова

    LeftSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
    TopSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);

Про поля понял, спасибо!

а где и как можно получить Printer.Handle?

в FMX.Printer не могу найти его ...

 

Ссылка на комментарий
  • 0

есть такой косяк у fmx. нельзя получить ширину этих полей у листа а соответственно печать немного кособочит. если есть возможность найдите (купите) fastreport fmx там они свои модули для печати написали и можно разобраться как работает. 

как костыль, более-менее получается правильно когда сначала рисуешь на TBitmap потом копируешь картинку на канву принтера. НО! при этом появляется другой косяк, в fmx картинка не может быть больше 8000х8000 а у принтеров может быть разрешение и побольше. 

 

Ссылка на комментарий
  • 0
8 часов назад, haword сказал:

есть такой косяк у fmx. нельзя получить ширину этих полей у листа а соответственно печать немного кособочит. если есть возможность найдите (купите) fastreport fmx там они свои модули для печати написали и можно разобраться как работает. 

как костыль, более-менее получается правильно когда сначала рисуешь на TBitmap потом копируешь картинку на канву принтера. НО! при этом появляется другой косяк, в fmx картинка не может быть больше 8000х8000 а у принтеров может быть разрешение и побольше. 

 

Все понятно, всем спасибо!

 

Ссылка на комментарий
  • 0
В 23.12.2021 в 00:11, haword сказал:

есть такой косяк у fmx. нельзя получить ширину этих полей у листа а соответственно печать немного кособочит. если есть возможность найдите (купите) fastreport fmx там они свои модули для печати написали и можно разобраться как работает. 

как костыль, более-менее получается правильно когда сначала рисуешь на TBitmap потом копируешь картинку на канву принтера. НО! при этом появляется другой косяк, в fmx картинка не может быть больше 8000х8000 а у принтеров может быть разрешение и побольше. 

 

Printer.Canvas.DrawBitmap(Image1.Bitmap, SrcRect, DestRect, 1);

С bitmap'ом тоже так же печатает.

Может существует максимальное для принтеров смещение (PHYSICALOFFSETX)?

 

Ссылка на комментарий
  • 0
В 24.12.2021 в 13:04, Sashar333 сказал:

С bitmap'ом тоже так же печатает.

картинка ровная в image1 а на принтере косо? а так тоже криво? 

Printer.Canvas.DrawBitmap(Image1.Bitmap, RectF(0,0, Image1.Bitmap.Width, Image1.Bitmap.Height) , RectF(0,0, Printer.PageWidth, Printer.PageHeight), 1);

 

 

Ссылка на комментарий
  • 0
12 часов назад, haword сказал:

картинка ровная в image1 а на принтере косо? а так тоже криво? 

Printer.Canvas.DrawBitmap(Image1.Bitmap, RectF(0,0, Image1.Bitmap.Width, Image1.Bitmap.Height) , RectF(0,0, Printer.PageWidth, Printer.PageHeight), 1);

 

 

Не то что косо, происходит смещение, как-бы за границу видимости на листе.

т.е. если если нарисовать вертикальную линию от 0,0 до 0,Printer.PageHeight, то она не напечатается у меня на принтере,

а если, допустим, рисовать от 200,0 до 200,Printer.PageHeight то она печатается

Мне требуется нарисовать таблицу максимальную по размерам листа, но она обрезается как на рисунке выше.

Делал как в учебнике: 

SrcRect := Image1.LocalRect;
DestRect := TRectF.Create(0, 0, Printer.PageWidth, Printer.PageHeight);
Printer.Canvas.DrawBitmap(Image1.Bitmap, SrcRect, DestRect, 1);

 

или RectF(0,0, Image1.Bitmap.Width, Image1.Bitmap.Height) это совсем другое чем Image1.LocalRect ?

 

Ссылка на комментарий
  • 0
В 27.12.2021 в 08:33, Sashar333 сказал:

Не то что косо, происходит смещение, как-бы за границу видимости на листе.

тогда не понял ничего. почему бы вам не сделать смещение в пикселах для печати? типа настройки страницы и там в точках отступ и его при печати использовать? тогда под каждый принтер можно будет подстроиться. 

у меня другая проблема была, у меня при печати текста было ощущение что весь текст на несколько градусов повернут что ли, и у буквы К вертикальная грань  сверху съезжала на 1 пиксель где то относительно низа. Но это было только при печати в pdf на macos.

Ссылка на комментарий
  • 0
10 часов назад, haword сказал:

тогда не понял ничего. почему бы вам не сделать смещение в пикселах для печати? типа настройки страницы и там в точках отступ и его при печати использовать? тогда под каждый принтер можно будет подстроиться. 

у меня другая проблема была, у меня при печати текста было ощущение что весь текст на несколько градусов повернут что ли, и у буквы К вертикальная грань  сверху съезжала на 1 пиксель где то относительно низа. Но это было только при печати в pdf на macos.

А как это смещение вычислить, сколько пикселей составляет это смещение?

На разных принтерах оно разное?

Требуется запуск печати двумя кнопками, без личных настроек пользователя:

нажал кнопку печать - выбрал принтер - нажал кнопку ОК

Ссылка на комментарий
  • 0

 uses PrinterAPI;

var

FkPrinter: TMyPrinter;

begin

FkPrinter:=TMyPrinter.Create(Printer.Printers[cbPrinters.ItemIndex].Device,true);
  OffsetX := FkPrinter.GetOffsetX;

  OffsetY := FkPrinter.GetOffsetY;

Printer.Canvas.Offset := TPoint.Create(OffsetX , OffsetY );

PrinterAPI.rar

Изменено пользователем OnePeople
Ссылка на комментарий
  • 0
2 часа назад, OnePeople сказал:

 uses PrinterAPI;

var

FkPrinter: TMyPrinter;

begin

FkPrinter:=TMyPrinter.Create(Printer.Printers[cbPrinters.ItemIndex].Device,true);
  OffsetX := FkPrinter.GetOffsetX;

  OffsetY := FkPrinter.GetOffsetY;

Printer.Canvas.Offset := TPoint.Create(OffsetX , OffsetY );

PrinterAPI.rar 4 \u043a\u0411 · 0 загрузок

Сделал вот так:

FkPrinter:=TMyPrinter.Create(Printer.ActivePrinter.Device,true);
var OffsetX := FkPrinter.GetOffsetX;
var OffsetY := FkPrinter.GetOffsetY;
printer.Canvas.Offset := TPoint.Create(OffsetX , OffsetY);

 

При выборе любого принтера (у меня их три), все Offset'ы = 0

И печатает соответственно также ...

Может еще есть варианты для пробы?

 

 

Ссылка на комментарий
  • 0

 DialogService: IFMXDialogService;
 FMargin, FMinMargin: TRect;
 FPaperSize: TPointf;
 FUnits: TPageMeasureUnits;
 FOptions : TPageSetupDialogOptions;
begin


  if TPlatformServices.Current.SupportsPlatformService(IFMXDialogService, DialogService) then
    DialogService.PageSetupGetDefaults(FMargin, FMinMargin, FPaperSize, FUnits, FOptions);

Text8.Text := FMinMargin.Left.ToString + ' ' + FMinMargin.Top.ToString;

А так сколько показывает?

Ссылка на комментарий
  • 0
14 часов назад, OnePeople сказал:

 DialogService: IFMXDialogService;
 FMargin, FMinMargin: TRect;
 FPaperSize: TPointf;
 FUnits: TPageMeasureUnits;
 FOptions : TPageSetupDialogOptions;
begin


  if TPlatformServices.Current.SupportsPlatformService(IFMXDialogService, DialogService) then
    DialogService.PageSetupGetDefaults(FMargin, FMinMargin, FPaperSize, FUnits, FOptions);

Text8.Text := FMinMargin.Left.ToString + ' ' + FMinMargin.Top.ToString;

А так сколько показывает?

Всегда 6 7

Ссылка на комментарий
  • 0
В 30.12.2021 в 15:25, krapotkin сказал:

а вот что с кроссплатформой делать - не знаю

то же самое просто ставить развилки в зависимости от ос )

по винде можно попробовать этот вариант из интернета 

type
  TMargins = record
    Left,
    Top,
    Right,
    Bottom: Double
end;

procedure GetPrinterMargins(var Margins: TMargins);
var
  PixelsPerInch: TPoint;
  PhysPageSize: TPoint;
  OffsetStart: TPoint;
  PageRes: TPoint;
begin
  PixelsPerInch.y := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
  PixelsPerInch.x := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
  Escape(Printer.Handle, GETPHYSPAGESIZE, 0, nil, @PhysPageSize);
  Escape(Printer.Handle, GETPRINTINGOFFSET, 0, nil, @OffsetStart);
  PageRes.y := GetDeviceCaps(Printer.Handle, VERTRES);
  PageRes.x := GetDeviceCaps(Printer.Handle, HORZRES);
  // Top Margin
  Margins.Top := OffsetStart.y / PixelsPerInch.y;
  // Left Margin
  Margins.Left := OffsetStart.x / PixelsPerInch.x;
  // Bottom Margin
  Margins.Bottom := ((PhysPageSize.y - PageRes.y) / PixelsPerInch.y) -
    (OffsetStart.y / PixelsPerInch.y);
  // Right Margin
  Margins.Right := ((PhysPageSize.x - PageRes.x) / PixelsPerInch.x) -
    (OffsetStart.x / PixelsPerInch.x);
end;

function InchToCm(Pixel: Single): Single;
// Convert inch to Centimeter
begin
  Result := Pixel * 2.54
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Margins: TMargins;
begin
 GetPrinterMargins(Margins);
 ShowMessage(Format('Margins: (Left: %1.3f, Top: %1.3f, Right: %1.3f, Bottom: %1.3f)',
  [InchToCm(Margins.Left),
   InchToCm(Margins.Top),
   InchToCm(Margins.Right),
   InchToCm(Margins.Bottom)]));
end;

а вообще может просто лист не правильно в принтер вставляешь?)

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...