ExtCreatePenの線の印刷

[戻る]
ぶいしー 2008/02/25(月) 11:42:16
OS XP VC++6.0 MFC使用

以下のようにExtCreatePenで一点鎖線の線種の論理ペンを生成し、印刷したのですが、
プリンタの解像度によっては、期待した長さのピッチの線種になりません。
だれか詳しい方、教えてください。
ちなみに、PDFで出力して解像度を変更したりしてテストしています。

50mm幅の線の中に12mm(線),1.5mm(空白),3.5mm(線),1.5mm(空白)の線種になるので、
-------   -   ----------   -  -----------   ← こうなるはず、
実際は
------  -   ---------   -  ----------  --  ← 線幅が指定した通りにならない

    CPrintDialog dlg(FALSE);
    if (dlg.DoModal() == IDCANCEL)
    {
        return;
    }

    HDC hdc = dlg.GetPrinterDC();
    CDC dcPrn;
    dcPrn.Attach(hdc);

    DOCINFO di;
    ::ZeroMemory(&di, sizeof(DOCINFO));
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = _T("TEST");

    StartDoc(hdc, &di);
    StartPage(hdc);

    ::SetMapMode(hdc, MM_HIMETRIC);
    int nVert = dcPrn.GetDeviceCaps(VERTRES);
    ::SetViewportOrgEx(hdc, 0, nVert, NULL);

    DWORD Style[4];
    Style[0] = 1200;
    Style[1] = 150;
    Style[2] = 350;
    Style[3] = 150;

    // LOGBRUSH構造体の設定
    LOGBRUSH logbrush;
    logbrush.lbStyle = BS_SOLID;
    logbrush.lbColor = RGB(0, 0, 0);
    logbrush.lbHatch = 0;

    // ペンの生成
    CPen* pPen = new CPen;
    pPen->CreatePen(PS_GEOMETRIC | PS_USERSTYLE, 13, &logbrush, 4, Style);
    CPen* pOldPen = dcPrn.SelectObject(pPen);

    dcPrn.MoveTo(1000, 1000);
    dcPrn.LineTo(6000, 1000);

    EndPage(hdc);
    EndDoc(hdc);

    dcPrn.SelectObject(pOldPen);
    delete pPen;
    dcPrn.Detach();

マッピングモードはMM_HIMETRICにしているので、同じように印刷されると思っているの
ですが、、。
やはり、解像度による誤差なのでしょうか?回避策などありますでしょうか?

玲音 (st.lain) 2008/02/25(月) 12:31:22
過去の記憶なので自信がないですが。

> DWORD Style[4];
> Style[0] = 1200;
> Style[1] = 150;
> Style[2] = 350;
> Style[3] = 150;
これらの指定ってLP単位系のはずなので、CDC::HIMETRICtoLP()を使って
変換した値を使用しないと正確に印刷されないような気がします。

HIMETRICtoLP, LPtoHIMETRIC、あたりでググると詳細な資料が出てくると
思います。
(変換座標系関数 XxxExt, XxxOrgのリセット是非については注意してください)

玲音 (st.lain) 2008/02/25(月) 12:40:25
こちらの過去ログにも該当するスレッドがあったので追加です。

>> 文字サイズと用紙サイズ 
> http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200303/03030061.txt
文字系でのスレッドですが、何かしらの参考になるかと思います。

ぶいしー 2008/02/25(月) 15:03:10
ありがとうございます。

教えて頂いたようにHIMETRICtoLPを使用して変換した値で、ExtCreatePenを
使ったのですが、結果は同じでした。
(ちなみに、幅とMoveTo,LineToの座標値も変換しました。)

何か他に原因があるのでしょうか?

    DWORD Style[4];
    Style[0] = 1200;
    Style[1] = 150;
    Style[2] = 350;
    Style[3] = 150;

    for (int i = 0; i < 4; i++)
    {
        CSize szSize(Style[i], Style[i]);
        dcPrn.HIMETRICtoLP(&szSize);
        Style[i] = szSize.cx;
    }

玲音 (st.lain) 2008/02/25(月) 16:44:24
過去のプログラムを掘り漁ったらHIMETRICtoLP()を使ってませんでした(汗

> ::SetMapMode(hdc, MM_HIMETRIC);
> int nVert = dcPrn.GetDeviceCaps(VERTRES);
> ::SetViewportOrgEx(hdc, 0, nVert, NULL);
この部分を以下のように書き換えるとどうでしょうか?
(私の環境からPDF, 印刷で確認しましたが問題なさそうでした)


---
::SetMapMode(hdc, MM_HIMETRIC);
::SetMapMode(hdc, MM_ANISOTROPIC);
::ScaleWindowExtEx(hdc, 1, 1, 1, -1, NULL);
--- 

確か、Microsoftの技術文章で公開されてたと思うのですが、HIMETRICでスケーリング
した後に、Y座標系を反転(HMETRICは上が正座標なので)している、ハズです。

# スケーリングは冷静にならないとハマるなぁ・・・

ぶいしー 2008/02/25(月) 17:12:59
玲音 (st.lain) さん、どうもありがとうございました。

ご教授頂いた方法で、やってみたのですが、
PDF印刷等で、300DPIで印刷した場合と600DPIで印刷した場合で、
線の出力のされ方が違ってしまうので、困っています。
50mm幅の線の中に12mm(線),1.5mm(空白),3.5mm(線),1.5mm(空白)の線種
なので、600DPIの出力が正しい(一点鎖線が2回分になる)と思いますが、
300DPIでは最後に中途半端な線(点)が出力されてしまいます。

やはり、これはDPIによる誤差か何かでしょうか?それとも何か他に解決策が
ありますでしょうか?すいませんが、もし知っていたら教えてください。

Kerry 2008/02/25(月) 18:02:24
Canon MP610で試してみたところ、最初のコードでどの解像度でも
(300dpi/600dpi)正しい長さで印刷されました。

Acrobat Distiller 5.0で試すと、おっしゃる通り300dpi以下で
結果が変わります。

プリンタドライバの問題かもしれませんね。

玲音 (st.lain) 2008/02/25(月) 19:43:57
フリーの仮想プリンタに300, 600, 1200, 4000とまわしてみました。
中度半端な破線が出現することはありませんでしたが、左端合わせてある
拡大したキャプチャを並べましたが、びみょ〜な差異があるようです。

Windowsのプリンタ周りの保証精度について知りませんが(それともドライバ側に
その任があるのかも知りません)、環境に依存する線が強そうですね。

# LP, DP間の内部的な座標変換による誤差かと思ったのですが、Kerryさんの
# 結果を見る限りその線は薄そうですね。
# 調べたことはないですが、同じ300dpiでもGetDeviceCaps()辺りで値を調べると
# 違いでもでるのカナ、と勘ぐってみたり。

ぶいしー 2008/02/26(火) 11:16:14
みなさん、どうもありがとうございました。

プリンタドライバに依存するところもあるようですね。

画面で表示できてたので、印刷もそんなに苦労しないと思ってましたが、
結構、奥が深いですね。どんなプリンタでも同じように印刷できるのが、
理想ですけれど、なかなか難しいというのがよくわかりました。

古いスレッドには追加発言できません。