MM_ANISOTROPICモードで縮小時に補完したい

[戻る]
亀山 2011/02/25(金) 10:23:39
VC2008 MFC です。
MM_ANISOTROPICを使って、描画の拡大縮小機能を実装しています。
以下のテスト処理では、固定で枠付きの太い線を1/10に縮小表示していますが、
重ねて描画しているため、枠が欠けてしまいます。

void CTestDlg::OnPaint()
{
    CPen pen1, pen2;
    pen1.CreatePen(PS_SOLID, 50, RGB(0, 0, 0));
    pen2.CreatePen(PS_SOLID, 40, RGB(255, 255, 255));

    CPaintDC dc(this);
    dc.SaveDC();
    dc.SetMapMode(MM_ANISOTROPIC);
    dc.SetWindowExt(10, 10);
    dc.SetViewportExt(1, 1);
    dc.FillSolidRect(0, 0, 100, 200, RGB(255, 255, 255));
    dc.SelectObject(&pen1);
    dc.MoveTo(50, 50);
    dc.LineTo(50, 150);
    dc.SelectObject(&pen2);
    dc.MoveTo(50, 50);
    dc.LineTo(50, 150);
    dc.RestoreDC(-1);
}

これを、MM_ANISOTROPICを使わずに、事前に大きいサイズのまま描いておき、
それをStretchBltで縮小コピーすると、枠も綺麗に表示されます。

void CTestDlg::OnPaint()
{
    CPen pen1, pen2;
    pen1.CreatePen(PS_SOLID, 50, RGB(0, 0, 0));
    pen2.CreatePen(PS_SOLID, 40, RGB(255, 255, 255));

    CPaintDC dc(this);
    CBitmap bitmapMem;
    bitmapMem.CreateCompatibleBitmap(&dc, 100, 200);
    CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);
    dcMem.SaveDC();
    dcMem.SelectObject(&bitmapMem);
    dcMem.FillSolidRect(0, 0, 100, 200, RGB(255, 255, 255));
    dcMem.SelectObject(&pen1);
    dcMem.MoveTo(50, 50);
    dcMem.LineTo(50, 150);
    dcMem.SelectObject(&pen2);
    dcMem.MoveTo(50, 50);
    dcMem.LineTo(50, 150);
    dc.SetStretchBltMode(HALFTONE);
    dc.StretchBlt(0, 0, 10, 20, &dcMem, 0, 0, 100, 200, SRCCOPY);
    dcMem.RestoreDC(-1);
}

MM_ANISOTROPICのマッピングを使ったまま、
縮小時に綺麗に補完してくれるモードは無いものなのでしょうか?

仲澤@失業者 2011/02/25(金) 13:19:23
う〜んと、これは難しいですね。
とりあえず SetStretchBltMode() で転送時の伸縮モードを
いくつか試してみては、どうでしょう。だめかも知れんけど。

仲澤@失業者 2011/02/25(金) 13:34:19
まちがったorz。マップモードで縮小すると線が消えるんですね(vv;)。

マップモードがだめならSetGraphicsMode( GM_ADVANCED)して、
SetWorldTransform()してみるとか・・・でしょうか。

gak 2011/02/25(金) 18:22:42
> MM_ANISOTROPICのマッピングを使ったまま、縮小時に綺麗に補完してくれるモードは無
いものなのでしょうか?
一つの方法として、gdi+ のアンチエイリアスを利用した例。

xxxxxxxx(HDC hdc) {
    ULONG_PTR token;
    Gdiplus::GdiplusStartupInput input;
    Gdiplus::GdiplusStartup(&token, &input, NULL);
    {
        Gdiplus::Pen pen1(Gdiplus::Color(0, 0, 0), 50);
        pen1.SetDashStyle(Gdiplus::DashStyleSolid);
        pen1.SetStartCap(Gdiplus::LineCapRound);
        pen1.SetEndCap(Gdiplus::LineCapRound);
        Gdiplus::Pen pen2(Gdiplus::Color(255, 255, 255), 40);
        pen2.SetDashStyle(Gdiplus::DashStyleSolid);
        pen2.SetStartCap(Gdiplus::LineCapRound);
        pen2.SetEndCap(Gdiplus::LineCapRound);

        Gdiplus::Graphics graphics(hdc);
        graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
        Gdiplus::Point from(50, 50), to(50, 150);
        graphics.DrawLine(&pen1, from, to);
        graphics.DrawLine(&pen2, from, to);
    }
    Gdiplus::GdiplusShutdown(token);
}

亀山 2011/02/28(月) 11:17:56
仲澤@失業者さん、gakさん、ご意見ありがとうございます。

gakさんに提案していただいたGDI+を使う方法だと、
たしかに枠部分も表示されました。

仲澤@失業者さんに提案していただいた
SetGraphicsMode()やSetWorldTransform()などを使う方法を
いろいろ試してみてもうまく描画されないのですが、
GDIのままで描画する限りは、MM_ANISOTROPICで縮小する方法では
線の枠はうまく描けないということになってしまいますでしょうか?

枠だけでなく、他の描画もジャギーになってしまうのですが。

仲澤@失業者 2011/02/28(月) 13:43:09
>GDIのままで描画する限りは、MM_ANISOTROPICで縮小する方法では
>線の枠はうまく描けないということになってしまいますでしょうか?

ですね。
拡大はともかく、縮小したときに良いことは何もおこりません。
自前で縮小描画をしたほうがはるかに「まし」な結果にできます。
そうなると拡大だけMAP MODEを使うわけにはいかず、結局全て
自前で実装することになるのです。もちろん出力結果がこんなもん
で満足なら話は別ですけど。
gakさんの方法は良いですね。勉強になりました。

亀山 2011/03/07(月) 09:09:07
[[解決]]
> 拡大はともかく、縮小したときに良いことは何もおこりません。
> 自前で縮小描画をしたほうがはるかに「まし」な結果にできます。

やっぱりそうなってしまうのですね。
2年前には「MM_ANISOTROPICモードでテキストサイズがずれる」
という問題でも質問させていただきましたが、
マッピングモードで文字や図形の拡大縮小を実現するのって、
あまりよい方法ではなかったのかもしれません。
ありがとうございます。

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