1

ここで本当に助けが必要です。事前に乗算されたアルファを備えた 32bpp であると思われる画像をMenuItemにロードしようとしています(このガイドに従って GIMP で画像を作成しました)。ContextMenuStrip クラスは知っていますが、使用したくありません。

以下は、MenuItem に画像を設定するために使用しているコードです。

// apis
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetMenuItemInfo(IntPtr hMenu, uint uItem, bool fByPosition,
                                   [In] ref MENUITEMINFO lpmii);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType,
                               int cxDesired, int cyDesired, uint fuLoad);

// structures
[StructLayout(LayoutKind.Sequential)]
struct MENUITEMINFO
{
    public uint cbSize;
    public uint fMask;
    public uint fType;
    public uint fState;
    public uint wID;
    public IntPtr hSubMenu;
    public IntPtr hbmpChecked;
    public IntPtr hbmpUnchecked;
    public IntPtr dwItemData;
    public string dwTypeData;
    public uint cch;
    public IntPtr hbmpItem;
}

// constants
private const uint LR_LOADFROMFILE = 0x10u;
private const uint IMAGE_BITMAP = 0x0u;
private const uint MIIM_BITMAP = 0x80u;

// points the to the image below in the preview of GIMP
private const string IMAGE_PATH = @"C:\Test\Images\premultalpha.bmp";

// methods
private void SetMenuItemImage()
{

    // get the hbitmap for the image
    // i am assuming that the alpha channel is preservered on this call
    IntPtr hbitmap = LoadImage(IntPtr.Zero, IMAGE_PATH, 
                               IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

    // create the menuiteminfo structure
    MENUITEMINFO mii = new MENUITEMINFO();

    mii.cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO));

    // retrieves or sets the hbmpItem member
    mii.fMask = MIIM_BITMAP;

    // handle to the bitmap displayed
    mii.hbmpItem = hbitmap;

    // returns true
    SetMenuItemInfo(this.ContextMenu1.Handle, 0, true, ref mii);
}

これは私の画像を使用したコードの結果です:

コードの結果

ここで明らかな問題は、透明度がなく、代わりに黒い背景があることです。

これは、保存して再度開くに、事前に乗算されたアルファチャンネルを作成するためのガイドに従って、GIMP で画像がどのように見えるかです。

前

これは、保存して再度開いた後の GIMP での画像の外観です。

後

以前のバージョンの写真にあったアルファ チャネル マスクが見えなくなっていることに気付きました。変更前の画像を .bmp として保存しようとしたときに表示される次のメッセージと関係があるかどうかはわかりません。

ギンプ

とても長い投稿で申し訳ありませんが、できる限りの情報を提供しようとしています。MenuItem の透明性に関して、私の問題が何であるかわかりません。32bpp であらかじめ乗算されたアルファを含むビットマップをロードすると、透明度が正常に機能すると言われています。

Bitmap.Gethbitmap()アルファ チャネルが失われるため、マネージ メソッドを使用できないことはわかっています。これがLoadImage、保存することを期待して、代わりに winapi 呼び出しを使用する理由です。

どんな助けでも大歓迎です。

4

2 に答える 2

8

LoadImage 呼び出しの最後の引数に LR_CREATEDIBSECTION フラグを追加すると、32 ビット BMP ファイルの場合はアルファ チャネルを含め、BMP リソースがそのまま読み込まれます。画像が互換性のあるビットマップに変換されるため、他の操作を行うと (デスクトップが 32bpp に設定されていても) アルファ チャネルが失われるようです。

BMP ファイル自体が正しい場合、MIIM_BITMAP および hbmpItem を使用してメニュー項目に割り当てられたときに、その DIB が正常に機能するように見えます。

これは、テーマが有効になっている場合、Vista から Windows 8.1 までで動作します。

テーマが無効になっている場合、これは常にうまく機能するとは限りません。(Windows 8 でも、ユーザーがシステム全体でテーマを無効にできなくても、アプリケーションでテーマを無効にできることに注意してください。)

(テーマを無効にしても問題なく動作する場合がありますが、正直なところ理由はわかりません。メインの Win7x64 マシンでは、テーマの有無にかかわらずうまく動作しますが、Win7x64 を実行しているテスト仮想マシンでは、テーマが無効になっていると見栄えが悪くなります。メニューに追加された他のシェル拡張機能に依存すると思われます。おそらく、サードパーティの拡張機能が所有者描画アイコンを使用している場合、シェルを別のコードパスに切り替えて、新しい hbmpItem メソッドも機能させるテーマが設定されていない場合、デフォルトで機能しない場合の事故. それは単なる推測ですが. この矛盾は Windows のバグのようであり、Vista から Windows 8.1 まで存在していたことを考えると、修正される可能性は低いと思われます. Windows 7 または 8 でも、テーマが無効になっている場合に使用します。)

テーマが有効になっているかどうかに関係なく、これは Windows XP ではうまく機能しません。

XP、およびテーマが無効になっている Windows の新しいバージョンでは、結果が醜い場合があります。

  • アイコンはメニューの他のほとんどのアイコンとは異なる場所で右に行き過ぎてしまいます。また、メニュー行の高さが小さいため、テーマ メニューの他のアイコンと見栄えがよく一貫性のある 16x16 のアイコンは大きすぎます。テーマのないメニューで。

  • XP は、32bpp HBITMAP が提供された場合もアルファ チャネルを無視するため、背景が黒一色のアイコンが表示されます。

  • したがって、これらのケースが気になる場合は、フォールバックして、古いシステムまたはテーマのないシステムではアイコンをまったく提供しないか、代替のアイコンを提供する必要があります。(13x13 にして、実行時にシステム メニューの色とブレンドします。) また、hbmpItem の代わりに hbmpUnchecked フィールドを使用して、アイコンが目的の場所に表示されるようにします。

  • おまけ: これだけでは不十分であるかのように、テーマ検出 API はめちゃくちゃで、システム全体のテーマについては教えてくれるかもしれませんが、アプリケーション自体がテーマを無効にしているかどうか、または古い comctl32 を使用するように明示されているかどうかについては教えてくれません。 .dll. Windows XP のテストに加えて、これは十分なチェックのようです。

    (IsThemeActive() && IsAppThemed() && (GetThemeAppProperties() & STAP_ALLOW_CONTROLS))

    comctl32.dll DllGetVersion エクスポートを使用して、アプリケーションが comctl32.dll バージョン 6 以降を使用しているかどうかを確認することもできます (つまり、テーマはサポートされていますが、有効か無効かはわかりません)。それが必要かどうかわからない。

テーマが有効であり、XP を使用していない主なケースに戻ります。

  • メニューに透明度が見られるが、奇妙なドットやその他のアーティファクトが表示される、またはメニュー項目の上にマウスを移動するとドットが消えてアイコンの背景が白くなるなどの問題がある場合は、アルファ チャネルが正しくないことを意味します。黒で事前に乗算された、事前に乗算されたアルファである必要があります。

私は GIMP をインストールしていないので、そこを手伝うことはできませんが、Photoshop を使用して BMP ファイルを作成する手順を以下に示します。

フォトショップで:

  • ソース画像を、たとえば PNG として取得します。
  • [チャンネル] タブで、新しいレイヤーを追加します (自動的に「アルファ」と呼ばれる必要があります)。
  • アルファ チャネル全体を黒で塗りつぶします。
  • [レイヤー] タブに戻りctrl、メイン レイヤー (これまでのところ唯一のレイヤーである必要があります) を クリックして、その透明マスクを選択します。
  • [チャンネル] タブに戻り、[アルファ チャンネル] をクリックします。前のステップで行った選択はまだアクティブになっているはずです。その選択範囲を白で塗りつぶします。
  • (この時点で、明示的なアルファ チャネルを持つ事前乗算されていないアルファ イメージがあります。)
  • [レイヤー] タブに戻り、メインのレイヤーの後ろに新しいレイヤーを作成します。黒で塗りつぶします。
  • 最後に、ファイルを 32 bpp BMP として保存します。(Photoshop の [名前を付けて保存] ダイアログで [アルファ チャンネル] チェックボックスがオンになっていることを確認してください。)

アルファ チャネル (背景レイヤーを追加する前に作成) と黒の背景レイヤーを組み合わせると、事前に黒で乗算されたアルファが生成されます。

于 2013-10-19T02:07:12.867 に答える
1

このアプローチの問題は、LoadImage()アルファもサポートしていないことです。

GDI+ を使用してイメージをロードすることに固執する必要があると思います。アルファ ビットを取得できるためです。これらのビットをHBITMAP失わずに手動で取得する方法が必要です。

.NET については、これをサポートしていないと断言できるほど詳しくはありませんが、簡単な検索で簡単な解決策を見つけることができませんでした。Bitmap.LockBitsしたがって、生データにアクセスするために使用し、pinvokeCreateDIBSection()を介して使用し、自分でビットを DIB セクションにコピーするのが最善の策だと思います。

memcpy()コピー元とコピー先の両方のビットマップが同じサイズの場合、すべてのビットマップ データを一度にコピーするには、1 つまたは同等のサイズが必要です(x * y * 4バイト)。

于 2013-10-11T20:02:48.940 に答える