web-dev-qa-db-ja.com

C#でアルファ透明なPNGを作成できますか?

縦書きのテキストを表示するマルチブラウザページがあります。

すべてのブラウザーでテキストを垂直にレンダリングする醜いハックとして、テキストを垂直に描画したPNGを返すカスタムページハンドラーを作成しました。

これが私の基本的なコードです(C#3ですが、他のバージョンの1までの小さな変更)。

Font f = GetSystemConfiguredFont();
//this sets the text to be rotated 90deg clockwise (i.e. down)
StringFormat stringFormat = new StringFormat { FormatFlags = StringFormatFlags.DirectionVertical };

SizeF size;
// creates 1Kx1K image buffer and uses it to find out how bit the image needs to be to fit the text
using ( Image imageg = (Image) new Bitmap( 1000, 1000 ) )
    size = Graphics.FromImage( imageg ).
        MeasureString( text, f, 25, stringFormat );

using ( Bitmap image = new Bitmap( (int) size.Width, (int) size.Height ) )
{
    Graphics g = Graphics.FromImage( (Image) image );
    g.FillRectangle( Brushes.White, 0f, 0f, image.Width, image.Height );
    g.TranslateTransform( image.Width, image.Height );
    g.RotateTransform( 180.0F ); //note that we need the rotation as the default is down

    // draw text
    g.DrawString( text, f, Brushes.Black, 0f, 0f, stringFormat );

    //make be background transparent - this will be an index (rather than an alpha) transparency
    image.MakeTransparent( Color.White );

    //note that this image has to be a PNG, as GDI+'s gif handling renders any transparency as black.
    context.Response.AddHeader( "ContentType", "image/png" );
    using ( MemoryStream memStream = new MemoryStream() )
    {
        image.Save( memStream, ImageFormat.Png );
        memStream.WriteTo( context.Response.OutputStream );
    }
}

これにより、透明度がインデックスベースであることを除いて、私が望んでいるように見えるイメージが作成されます。 PNGを返すので、適切なアルファ透明度をサポートできます。

これを.netで行う方法はありますか?


Vlixのおかげで(コメントを参照)、いくつかの変更を加えましたが、まだ正しくありません。

using ( Bitmap image = new Bitmap( (int) size.Width, (int) size.Height, PixelFormat.Format32bppArgb ) )
{
    Graphics g = Graphics.FromImage( (Image) image );
    g.TranslateTransform( image.Width, image.Height );
    g.RotateTransform( 180.0F ); //note that we need the rotation as the default is down

    // draw text
    g.DrawString( text, f, Brushes.Black, 0f, 0f, stringFormat );

    //note that this image has to be a PNG, as GDI+'s gif handling renders any transparency as black.
    context.Response.AddHeader( "ContentType", "image/png" );
    using ( MemoryStream memStream = new MemoryStream() )
    {
        //note that context.Response.OutputStream doesn't support the Save, but does support WriteTo
        image.Save( memStream, ImageFormat.Png );
        memStream.WriteTo( context.Response.OutputStream );
    }
}

これでアルファは機能しているように見えますが、テキストはブロック状に見えます。まるでジャギーエッジが残っているように見えますが、背景は黒です。

これは.Net/GDI +のバグですか? gifのインデックス透明度でも失敗することはすでにわかっているので、あまり自信がありません。

この画像は、これがうまくいかない2つの方法を示しています。

vertical text comparison

上の画像は、白い背景またはMakeTransparent呼び出しなしでそれを示しています。 2つ目は、背景を白で塗りつぶし、次にMakeTransparentを呼び出して、インデックスの透明度を追加します。

これらはどちらも正しくありません。2番目の画像には、不要な白いエイリアシングジャギーがあります。最初の画像は、黒に対してしっかりエイリアス化されているように見えます。

34
Keith

「blockiness」というテキストを修正するには、ただ行うことはできません...

g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

この行の後...

Graphics g = Graphics.FromImage( (Image) image );
14
pmcilreavy

IIRCでは、ビットマップコンストラクターでPixelFormatを指定する必要があります。

6
leppie

BitmapでLockBitsメソッドを使用してBitmapDataオブジェクトを返し、各ピクセルにAlphaを自分で設定できます(GetPixelとSetPixelを使用することもできますが、これらのメソッドは非常に遅いです)。 この答え を参照してください。

私がこのテクニックを使い始めたとき、私はアルファ値を0に設定していたので、これが確実に機能することを知っています。

編集:これは完全に.NETで行われた魚眼レンズ効果のサンプルです(LockBitsを使用)。

代替テキストhttp://www.freeimagehosting.net/uploads/21ca8300cc.jpg

6
MusiGenesis

テキストのアンチエイリアスについては、Graphics.TextRenderingHintの値をいじってください。 ClearTypeは使用しないことをお勧めします。ClearTypeは、LCDモニター(CRTではなく))でのみ表示され、ローテーションのために機能しない可能性があるためです。

P.S。 VlixではなくVilx-です。 :D

5
Vilx-

多分あなたはこのCodeProjectの記事のソースコードで答えを見つけることができます:

C#のピクセル単位のアルファブレンド

1
splattne

申し訳ありませんが、質問を十分に読みませんでした。

私は、あなたの例でエイリアシング効果のどちらも見ずに、色付きの背景に回転したテキストを正常に描画したことを知っています。コードをもう一度見てみると、論理フォントを使用して回転したテキストを描画していることに気付きました。これは、Microsoft.WindowsCE.Forms名前空間にうまくラップされています。この手法では、描画角度を論理フォントのプロパティとして設定します(したがって、TranslateTransformやRotateTransformを呼び出さないでください)。

Windows CEの世界以外では、論理フォントを作成するためにPInvokeを実行する必要があります(私はこれを行ったことがないため、すぐに良い例を見つけることができませんでした)。これがどの程度うまく機能するかはわかりませんが、見た目と変なエイリアシング効果なしに回転したテキストが描画されることは確かです。これは確かにGDI +のバグだと思います(または、誰かが実際に使用するとは思わなかっただけです)。

論理フォントよりもパフォーマンスが向上する可能性のある別のアプローチは、通常、色付きの長方形の背景(テキストを保持するのに十分な大きさ)にテキストを描画し、長方形を回転してメイン画像にコピーすることです。 Graphics.DrawImageは回転できないようですが、この効果はLockBitsを使用して簡単に実装できます。

1
MusiGenesis

または、テキストを不透明なPNGにレンダリングし、セルの背景色に一致する背景色(白ではなく)を使用することもできます。

0
MusiGenesis

マイクロソフトには、CodePlexのAsp.Netコンテンツの一部として、Web用の新しい動的画像ライブラリがあることがわかりました。

http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16449

残念ながらそれは私が欲しいもののために少し多いです。安全でないコードを使用すると、独自のアルファ透明度をロールバックできますが、このコードを使用率の高いWebアプリケーションの一部として使用することを考えると、速度が遅すぎます。

これはMSのGDI + .Net実装の単なるバグですか?

0
Keith

ビットマップを作成するときは、少なくとも32ビットのピクセル形式(例:PixelFormat.Format32bppArgb)を指定する必要があります。指定しない場合、GDI +は透明度を管理できません。

保存時に結果のファイルを調整するには、ImageCodecInfoおよびEncoderParametersでSaveを使用できます。

0