線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1730
推到 Plurk!
推到 Facebook!

Canvas.TextOut() 點陣印表機列印位置會不對但雷射卻正確

答題得分者是:t27
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-12-30 10:52:20 IP:220.128.xxx.xxx 未訂閱
各位好,一值都有這個問題,我的報表系統是自己寫的,所有文字都用 Canvas.TextOut() 輸出到印表機,用雷射印表機列印的話,跟預覽時的位置是相同的,但用點陣印表機列印的話,位置都往右往下偏離,X 和 Y 的值愈大,偏羞愈多,點聞印表機己很少人使用,但客戶的客戶偏偏就要提供底稿套表列印,不用點陣都不行。
很明顯,不能用預監時的 X,Y 值給 TextOut() 列印,因為印表機的解析度跟螢幕不同,必須先換算,換算方法很簡單,如下。

Windows 虛擬印表機解釋度是一/吋 96 點,螢幕的 Xm 要轉換為列印的 Xp,照比例算出來就好。

Xp := 印表機解析度 / 虛擬印表機解釋度度 * Xm;

假如
Xm = 500
虛擬印表機解釋度度 = 300

Xp = 300 / 96 * 500 = 1563
雷射的解析度都在 600 以上,都不會有問題,解析度低的,例如 300 或以下,列印位置總是往右往下偏,不知道是甚麼原因。

是不是有其他比較好的方法?我知道 Canvas 的 Dimension 單位,是可以更改的,預設是像素,好像可以改為吋、公分之類,這樣我就可以先把 Xp 除以 38 成為吋,再輸出。請問有人自己寫報表程式嗎?正確的做法是...?
t27
中階會員


發表:34
回覆:95
積分:90
註冊:2002-06-19

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-12-30 14:35:31 IP:61.224.xxx.xxx 訂閱
這是以前在網路上找到的, 在雷射印表機 影印機 傳真機 試過都ok. 但沒在點矩陣印表機試過.
你參考試一試. 希望能有所幫助.

部分列印程式:
function TPreviewPrinter.PrintRange(StartPage, StopPage: integer): boolean;
var
Page : integer;
R : TRect;
begin
Screen.Cursor := crHourGlass;
try
Result := True;
Printer.Orientation := Orientation;
Printer.BeginDoc;
Printer.Title := Title;
InitPrinterVars(Printer.Handle);
for Page := StartPage to StopPage do
begin
if Assigned(OnStatus) then
OnStatus(Self, Format('Printing page %d', [Page]), Page, stPrinting);
R := Rect(-offx,-offy,Printer.PageWidth,Printer.PageHeight);
Printer.Canvas.StretchDraw(R, MetaFiles[Page]);
if Page < StopPage then Printer.NewPage;
end;
Printer.EndDoc;
if Assigned(OnStatus) then
OnStatus(Self, 'Print Job Complete', -1, stPrintFinished);
finally
Screen.Cursor := crDefault;
end;
end;

procedure TPreviewPrinter.InitPrinterVars(hdc: THandle);
var
rate,hhh,vvv:double;
begin
hdc := Printer.Handle;
if PaperSize <> Custom then
begin
ppix := GetDeviceCaps(hdc, LOGPIXELSX);
ppiy := GetDeviceCaps(hdc, LOGPIXELSY);
sizex := GetDeviceCaps(hdc, PHYSICALWIDTH);
sizey := GetDeviceCaps(hdc, PHYSICALHEIGHT);
if Units = unCentimeters then
begin
PaperLength := StrToFloat(Format('%8.1f',[sizex / ppix * INCH_TO_CM]));
PaperWidth := StrToFloat(Format('%8.1f',[sizey / ppiy * INCH_TO_CM]));
end;
if Printer.Printers.Count = 0 then
begin
sizex := Round(8.5 * Screen.PixelsPerInch);
sizey := Round(11 * Screen.PixelsPerInch);
end;
end
else
begin
ppix := GetDeviceCaps(hdc, LOGPIXELSX);
ppiy := GetDeviceCaps(hdc, LOGPIXELSY);
if FUnits = unInches then
begin
sizex := round(PaperWidth * ppix);
sizey := round(PaperLength * ppiy);
end;
if FUnits = unCentimeters then
begin
offx := GetDeviceCaps(hdc, PHYSICALOFFSETX);
offy := GetDeviceCaps(hdc, PHYSICALOFFSETY);
sizex := round(PaperWidth / INCH_TO_CM * ppix){ offx};
sizey := round(PaperLength / INCH_TO_CM * ppiy){ offy};
end;
if Printer.Printers.Count = 0 then
begin
sizex := Round(8.5 * Screen.PixelsPerInch);
sizey := Round(11 * Screen.PixelsPerInch);
end;
end;
offx := GetDeviceCaps(hdc, PHYSICALOFFSETX);
offy := GetDeviceCaps(hdc, PHYSICALOFFSETY);
end;
編輯記錄
t27 重新編輯於 2011-12-29 23:36:34, 註解 無‧
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-12-30 19:24:57 IP:220.128.xxx.xxx 未訂閱
t27 大,謝謝分享,我花點時間研究看看,一般的 pdf 虛擬印表機也會有往右往下偏的情形,例如 pdfFactory,我用它來試看看
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#4 引用回覆 回覆 發表時間:2012-01-17 10:27:39 IP:220.128.xxx.xxx 未訂閱
t27 大,

原程式碼看不太懂,今天再看一次,看到了重點的 PHYSICALOFFSETX ,PHYSICALOFFSETY,和 -offx, -offy

offx := GetDeviceCaps(hdc, PHYSICALOFFSETX); // 印表機預設偏移
offy := GetDeviceCaps(hdc, PHYSICALOFFSETY);
...
R := Rect(-offx,-offy,Printer.PageWidth,Printer.PageHeight); // 用負數抵消偏移
Printer.Canvas.StretchDraw(R, forbiddenFiles[Page]);

試了一下兩支 pdf 虛擬印表機,一支列印位置正確,另一支仍是偏右偏下,原來是印表機預設的偏移值在搞鬼,正確的那一台偏移值都是零,另一即則是 75 和 75,怪不得上面的程式碼用 -offx 和 -offy 來抵消它們,修改了程式,算出列印的 X 和 Y 值後,分別加上負數的偏移值,就幾打都正確了,謝謝 t27 大。
系統時間:2017-12-17 12:22:51
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!