- PR -

ドット単位で印刷-プリンタの解像度に合わせて

投稿者投稿内容
未記入
大ベテラン
会議室デビュー日: 2005/03/12
投稿数: 148
投稿日時: 2006-12-11 22:33
まあ、スレ主の肩を持つつもりはまったくないので

もっと語れよ
未記入
大ベテラン
会議室デビュー日: 2005/03/12
投稿数: 148
投稿日時: 2006-12-11 22:41
コミュニティ(MLや掲示板)について俺が思っていることのひとつ

# かつての俺もそうだったし
# 今でもそうなんだけど テヘヘ
言葉遣いが悪い発言を見つけると言葉遣いが悪いよとは言わず
* 気に入らない相手は叩く
* 揚げ足を取る
* たとえ話は変な解釈をしてまで揚げ足を取る
* 変なたとえ話で誘ってでも叩く
* 煽ってでも叩く
* いろいろ
* 叩かれたほうも煽ったり叩き返すことに夢中
それがコミュニティ
PAO
ベテラン
会議室デビュー日: 2004/10/21
投稿数: 66
投稿日時: 2006-12-11 22:43
他にもあるけど・・・
例えば・・・

===================================
件名 : ODP.NET + 更新系ストアドプロシージャ + DataSet
返答した方 : Edosson
-----------------------------------
こいつ、社長なんでね?
IT関係の零細企業の社長ってさ、被害妄想の塊……
===================================

こんなんに、まともに、返事書けって?

冗談じゃない!


ちなみに、あっしは、社長じゃない。ごめん。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-12-11 22:45
300DPI でスキャンして、このような結果を得ています。もちろん、P/Invoke は使用していません。
いったい、どのような結果なので、「とうてい1ドット単位に印刷されているとは思えない粗さ」なんでしょう?
CANON iP4200
※ 適当に消します。
消しました

[ メッセージ編集済み 編集者: Jitta 編集日時 2006-12-11 23:18 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-12-11 22:48
> このログを参考にする人は必ずいるんだから。
確かに。では、参考にされる方のために、まとめ直します。
引用:

 Graphics に描画した線を、プリンタの解像度を元に、ドット単位※1で印刷したいと思っています。

 最近のプリンタの解像度は、おおよそ 300DPI の倍数になっています。また、Graphics.PageUnit を GraphicsUnit.Document にセットすると、大きさとしては、正しく印字できます。※2
 ここで、1ピクセル幅の線を描画し、印字してみたのですが、どう考えても1ドット幅の線であるとは思えない幅で※3印字されてしまいます。

 C# で直接描画するのが無理であれば、unmanaged C++ で直接 GDI を操作することも考えています。1ドットで印刷させる方法をご存じであれば、お教えください。


編注:
※1:印刷物上で、プリンタが描画するための最小の単位と定義する。しかし、それをどの様にプリンタが表現するかは、不明。
※2:「大きさ」が、何に対する何の大きさなのかは不明。何に対して描画したものが、何で表現されたときのものと比較しているのか、わからない。
※3:ここで、インクのにじみはないものとする。また、ヘッドの移動方向によるズレもないものとする。ただし、どの様な結果なので「とうていドット単位に印字されているとは思えない」という判断に至ったかは不明。インクのにじみだったのかもしれないし、ヘッドが汚れているためにゆがんでいるのかもしれない。
引用:

 いろいろ調べてみましたが、プリンタのデバイス コンテキストを取得して、そこに直接描画すればいいのではないか、と思います。しかし、デバイス コンテキストを、.NET Framework にて取得する方法が解りません。
 なお、このメソッドを使用する、実際に印刷を行う呼び出し元には GDI+ の(編注:.NET Framework の GDI+ 描画面をカプセル化する)Graphics オブジェクトを返そうと思っていたのですが、無理でしょうか。Windows Platform API の、HDC をインターフェイスとする方法しかないでしょうか。

__________

 さらに調査した結果、次のようにすることで、望みの結果が得られました。※1
コード:
private void printDocument1_PrintPage(...)
{ 
    e.Graphics.PageUnit = GraphicsUnit.Millimeter;
    e.Graphics.DrawString("印刷テスト"
        , new Font("MS 明朝", 32), Brushes.Black
        , new RectangleF(10,10,100,50), new StringFormat());

    drawLine(e.Graphics);
}

[DllImport("gdi32.dll")]
private static extern bool LineTo(IntPtr hDC, int x, int y) ;
[DllImport("gdi32.dll")]
private static extern bool MoveToEx(IntPtr hDC, int x, int y, IntPtr OldPoint);

private void drawLine(Graphics g)
{ 
    IntPtr hDC = g.GetHdc();

    MoveToEx(hDC, 100, 500, IntPtr.Zero);
    LineTo(hDC, 100, 1000);

    //Release the device context handle obtained by a previous call
    g.ReleaseHdc(hDC);
}


 結局、.NET Framework から gdi32.dll の関数がコールできるかどうかを調査すればよかったのですね。


編注:
※1:ここで、e.Graphics.PageUnit を、GraphicsUnit.Millimeter としているが、これでは以降の単位はすべてミリメートルとなり、幅"1"の線は、1mm 幅の線として描画される。もし、このまま線を引いていたのであれば、当然望む結果になるはずはない。ここは GraphicsUnit.Pixel を、線を描画する前に再指定するべきであるが、そうしていたかどうかは、これまでの投稿に書かれていないため、不明。
 もっとも、GraphicsUnit.Document についての記述があるため、おおよそわかっていると考えられる。しかし、プリンタ プロパティにて 1200DPI に設定されているときに、GraphicsUnit.Document を指定した場合、期待のおよそ4倍で描かれることが予想される。
 また、DrawLine メソッドで ReleaseHdc を使用しているが、printDocument1_PrintPage イベント ハンドラ メソッドから DrawLine を呼び出した後、さらに e.Graphics を使用しているはずなので、ここでリリースする必要はない、むしろしてはいけないと思われる。ここで恐いのは、テスト中は何ともないのに、本番稼働中に「リリース済みのため使用できない」というエラーが発生した場合である。編者は幸運なことに、テスト中にこのエラーに遭遇したため、本番稼働前に修正することが出来た。
引用:

 なお、プリンタの解像度に合わせて処理を行うときは、次のようにして解像度を取得できます。
 2つの値は、ほとんどの場合、同じになるでしょう。プリンタののプロパティの「最高解像度」より低い値になることがありますが、ここで取得できる値は、現在設定されている値です。解像度をソフトウェアから変更する方法については、今のところ不明です。
コード:
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hDC,int nIndex);

private void drawLine(Graphics g)
{
    IntPtr hDC = g.GetHdc();

    int l = GetDeviceCaps(hDC, 88);    // Windows API で定義された、LOGPIXELSX
    int l2 = GetDeviceCaps(hDC, 90);   // Windows API で定義された、LOGPIXELSY
    MessageBox.Show(this, l.ToString() + " : " + l2.ToString());
(以下略)




編注:
 わざわざ Platform Invoke しなくても、PrintDocument.PrintPage イベント ハンドラ メソッドで、e.Graphics.DpiX と e.Graphics.DpiY を調べればわかる。
_________________
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-12-11 22:54
 大元の質問事項も、P/Invoke する必要はなく、次のコードで実現可能です。要は、どの様に描画するか、ということです。描画単位さえ正しく設定すれば、おおよそ、望むとおりに描画できます。なぜなら、PrintDocument.PrintPage イベント ハンドラ メソッドに渡される Graphics オブジェクトは、プリンタの能力、詳細設定によって初期化されていますので。
 次のコードを実行すると、2つの四角形が描かれます。500単位×500単位の四角形を描きますが、1つはピクセル、1つは 1/300インチを単位としています。ここで、プリンタのプロパティで複数の解像度を選べる場合、解像度を変えて複数回印刷してみてください。それぞれで結果が異なることがわかるでしょう。
 もちろん、1200DPI で出力可能なプリンタに、300DPI で描画した画像を印刷すると、拡大されて印刷されることになります。このときの拡大ロジックは、おそらくドライバかプリンタのファームに依存し、Windows からは変更不可能と思います。
 また、1200DPI で出力可能なプリンタに 300DPI で描画した画像を印刷するなら、「ドットやピクセルが、プリンタの解像度の最小単位を指している」とは言えないのではないでしょうか。
 プリンターの解像度を設定するには、PrintDocument.QueryPageSettings イベントにて、QueryPageSettingsEventArgs オブジェクトから PageSettings オブジェクトを参照し、PageSettings.PrinterResolution プロパティを設定すればいいと思う(未確認)。設定できる解像度は、PrinterSettings.PrinterResolutions プロパティで取得できます。
コード:
private void printDocument1_PrintPage(...) {
    e.Graphics.PageUnit = System.Drawing.GraphicsUnit.Millimeter;
    e.Graphics.DrawString("印刷テスト", new Font("MS 明朝", 32)
        , Brushes.Black, new RectangleF(10, 10, 100, 50)
        , new StringFormat());
    e.Graphics.PageUnit = System.Drawing.GraphicsUnit.Pixel;
    e.Graphics.DrawLines(System.Drawing.Pens.Black
        , new System.Drawing.Point[] {
                     new System.Drawing.Point(100, 100)
                     , new System.Drawing.Point(100, 600)
                     , new System.Drawing.Point(600, 600)
                     , new System.Drawing.Point(600, 100)
                     , new System.Drawing.Point(100, 100)});
    e.Graphics.PageUnit = System.Drawing.GraphicsUnit.Document;
    e.Graphics.DrawLines(System.Drawing.Pens.Black
        , new System.Drawing.Point[] {
                     new System.Drawing.Point(1100, 100)
                     , new System.Drawing.Point(1100, 600)
                     , new System.Drawing.Point(1600, 600)
                     , new System.Drawing.Point(1600, 100)
                     , new System.Drawing.Point(1100, 100)});
}



 最初は PageUnit の設定を疑ったわけですが、GraphicsUnit.Document の記述があるので、まぁ、その辺は大丈夫なのかな?と。でも、やっぱりこれを間違ったみたいですね。

 質問の意図は、インク ジェット プリンタの場合、インクを飛ばして紙に付着させるわけですが、このインク1滴が1描画単位なのか?少なくともカラーの場合は CMY の組合せ数滴で色が構成されるため、例えば5滴で1描画単位なら、「1ドット単位に印字されているとは思えない」のは当たり前なんじゃない?と思ったわけです。薄いインクを使う、6色以上のモノは、薄い色を何滴か重ねて表現していたと思うし。
 キヤノンのプリンタを調べましたが、PIXUS MP510 の場合「最小1/4800インチのドット(インク滴)間隔でプリントします。」と書かれています。なので、1滴=1描画単位=1ドットなのですね。

 ん?カラーは?1pl と 2pl で、同じ大きさのドットになるんだろうか?インクを同じ量でしか混ぜられないのなら、7色しか表現できないような?やっぱり、1滴≠1ドットなんじゃない???

 ところで、「ドット単位に印字されているとは思えない、荒さ」というのも、見ていない者にとってはわからないんですよね。ギザギザになっているのか、とっても太いのか。レーザー プリンタの出力を見ていますが、紙の繊維に沿ってトナーがにじんでいます。もちろん、インク ジェットでも、インクのにじみは発生します。これを「ドット単位に印字されているとは思えない」と表現されると、紙屋さんやトナー屋さんが辛いかなぁ?少なくとも、プログラムで何とか出来るモノじゃないよなぁ。

 インク リボンをバチバチ叩く時代からプリンタと付き合っていると、ヘッドの移動方向によってラインがずれるのは経験済みで、それのことなのかなぁ?とか思ったり。対象のプリンタが書かれていませんしね。


 んで、煽った...というか、むかついたまんま返したのは [2006-12-10 00:33] だけで、後はいたってまじめに聞いていたんだけどなぁ。。。まぁ、「見られない人にもわかるように説明せんかい!」とは思った。

_________________
PAO
ベテラン
会議室デビュー日: 2004/10/21
投稿数: 66
投稿日時: 2006-12-11 22:55
Jitta さん

あなたのおこなぅた結果は、思い込みですね。
バーコードの検査機などを入手して、
100通りのプリンターで試してから、
物を言ってください。

全然だめーー。
残念!
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-12-11 22:58
引用:

PAOさんの書き込み (2006-12-11 22:55) より:
Jitta さん

あなたのおこなぅた結果は、思い込みですね。
バーコードの検査機などを入手して、
100通りのプリンターで試してから、
物を言ってください。

全然だめーー。
残念!

だから、どういうものを「ダメ」と言っているのか、示してください。
見られない人には、「どんなの」か、わからないんですよ。

で、私は、一貫してそういっているのですが、どうしてわかってもらえないんだろう?


追加
「普通のプリンタでは解像度を変更できない」とおっしゃられましたが、
普通の用途でバーコード検査機なんか使わないですよ。

[ メッセージ編集済み 編集者: Jitta 編集日時 2006-12-11 23:01 ]

スキルアップ/キャリアアップ(JOB@IT)