コンパクトフレームワーク:透明性のエッジ

エントリー


開発者にとって残念なことに、Compact Framework、およびネイティブ関数も、個々のピクセルに対して異なる透明度を持つアルファチャネルをサポートしていません。 これは、画像間のスムーズな移行で説明できない美しさを作成する方法がないことを意味します。 しかし、少なくとも「完全な」アルファチャンネルの外観が必要な場合、つまり、完全に透明な領域を持つ半透明の画像を表示する場合はどうすればよいでしょうか。

画像を透明に表示する2つの方法を検討してください。

メソッド番号1。 固定色は透明です


public static void DrawImageTransparent( Graphics g, Bitmap b, Point location, Color transColor)
{
if (b == null || g == null )
return ;

ImageAttributes attrib = new ImageAttributes();
attrib.SetColorKey(transColor, transColor);

Rectangle destRect = new Rectangle(location.X, location.Y, b.Width, b.Height);

g.DrawImage(b, destRect, 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, attrib);
}


* This source code was highlighted with Source Code Highlighter .


DrawImageのこのトリッキーなバージョンだけが、指定されたColorKeyで画像を表示することを許可することに注意してください。これにより、描画しないピクセルが決まります。 シックなパラメーターセットが見つかりませんか? :)描画する場所、Rectangeを介して設定し、どこから-4つのパラメータを介して設定します。 まあ、これは私、マイクロソフトへの余談です。

実際には、透明なピクセルで画像を描画する主な方法はDrawImageTransparentです。 ただし、この方法のマイナスは明らかであり、透明度の状態は完全に透明と完全に不透明の2つのみです。

例:
透明ピクセル

実際、悪くはありません。そこでやめることができます。 しかし、私はもっと何かが欲しい:)

メソッド番号2。 画像全体の不透明度係数は固定されています。


この場合、DllImportなしでは実行できません。これに必要なすべてを準備します。

public struct BlendFunction
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}

public enum BlendOperation : byte
{
AC_SRC_OVER = 0x00
}

public enum BlendFlags : byte
{
Zero = 0x00
}

public enum SourceConstantAlpha : byte
{
Transparent = 0x00,
Opaque = 0xFF
}

public enum AlphaFormat : byte
{
AC_SRC_ALPHA = 0x01
}

public class PlatformAPI
{
[DllImport( "coredll.dll" )]
extern public static Int32 AlphaBlend( IntPtr hdcDest, Int32 xDest, Int32 yDest, Int32 cxDest, Int32 cyDest, IntPtr hdcSrc, Int32 xSrc, Int32 ySrc, Int32 cxSrc, Int32 cySrc, BlendFunction blendFunction);
}


* This source code was highlighted with Source Code Highlighter .


ご覧のとおり、トリムのみが可能なものはすべてトリムされます-1つのパラメーターによる列挙など。 それでも、私たちは続けます。 実際、私たちの機能:

public static void DrawAlpha( Graphics g, Bitmap b, Point location, byte opacity)
{
if (b == null || g == null )
return ;

using ( Graphics gxSrc = Graphics .FromImage(g))
{
IntPtr hdcDst = g.GetHdc();
IntPtr hdcSrc = gxSrc.GetHdc();
BlendFunction blendFunction = new BlendFunction();
blendFunction.BlendOp = ( byte )BlendOperation.AC_SRC_OVER;
blendFunction.BlendFlags = ( byte )BlendFlags.Zero;
blendFunction.SourceConstantAlpha = opacity;
blendFunction.AlphaFormat = ( byte )0;
PlatformAPI.AlphaBlend(hdcDst, location.X, location.Y, b.Width, b.Height, hdcSrc, 0, 0, b.Width, b.Height, blendFunction);
g.ReleaseHdc(hdcDst);
gxSrc.ReleaseHdc(hdcSrc);
}
}


* This source code was highlighted with Source Code Highlighter .


コードに関する小さなコメント-BlendFunctionのパラメーターを変更することはできません。それらは唯一可能なものです。 それは残念ですが、何もすることはありません。

例:

アルファブレンド

不気味だよね? 厄介な紫色のピクセルはどこにも行かず、少し透明になりました:(

両方の方法の併用


残念ながら、組み合わせるオプションはほとんどありません。 一見、まったくありません:)しかし、まだ1つの方法があります。

そのため、解決策は次のとおりです。 ColorKeyを同時に設定してAlphaBlendを呼び出すことはできないため、これらを順番に使用します。 最初に、フリルのない標準的な方法で背景を描画し、次に最初の方法でボタンを描画し、最後に... 2番目の方法で、背景の上に小さな不透明度で描画します!

g.DrawImage(background, 0, 0);
DrawImageTransparent(g, button, new Point(10, 10), Color.FromArgb(255, 0, 255));
DrawAlpha(g, background, new Point(0, 0), 75);


* This source code was highlighted with Source Code Highlighter .


結果:
アルファおよびピクセルの透明度

上記の方法は非常に実行可能です。 私はそれを使用し、作業の速度に非常に満足しています-同様のスタイルですべてのインターフェース要素をレンダリングするのに平均60〜80ミリ秒かかります(さまざまなデバイスでテストされました)。 もちろん、このスタイルでアプリケーションを作成する場合、標準コントロールは機能しませんが、簡単だと誰が約束しましたか? いずれにせよ、グラフィック要素をレンダリングするための独自のフレームワークなしで、説明できない美しさを作成することはできません。

Source: https://habr.com/ru/post/J44327/


All Articles