你能用C#做一个alpha透明的PNG吗?

时间:2008-12-23 11:38:12

标签: c# .net gdi+

我有一个显示垂直文本的多浏览器页面。

作为一个让所有浏览器都能垂直渲染文本的丑陋黑客,我创建了一个自定义页面处理程序,它返回一个垂直绘制文本的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时,它可以支持正确的alpha透明度。

有没有办法在.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 );
    }
}

现在alpha似乎有效,但文字看起来很块 - 好像它仍然有jaggie边缘但是黑色背景。

这是.Net / GDI +的一些错误吗?我已经发现它甚至没有GIF的索引透明度,所以我对它没有多少信心。

此图显示了出错的两种方式:

vertical text comparison

顶部图片显示没有白色背景或MakeTransparent来电。第二个背景填充白色然后调用MakeTransparent来添加索引透明度。

这些都不正确 - 第二张图片有我不想要的白色锯齿锯齿,第一张图片看起来对黑色有明显的别名。

9 个答案:

答案 0 :(得分:14)

要修复文本“阻塞”,你不能只做...

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

在此之后......

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

答案 1 :(得分:6)

IIRC您需要在位图构造函数中指定PixelFormat。

答案 2 :(得分:6)

您可以使用Bitmap上的LockBits方法返回BitmapData对象,并自己设置每个像素的Alpha(您也可以使用GetPixel和SetPixel,但这些方法非常慢)。请参阅this answer

我知道这肯定有用,因为当我第一次开始使用这项技术时,我将alpha值设置为0,因此我设置的颜色都不可见。

编辑:这是一个鱼眼镜头效果的示例,完全在.NET中完成(使用LockBits):

alt text http://www.freeimagehosting.net/uploads/21ca8300cc.jpg

答案 3 :(得分:5)

对于文本抗锯齿,使用Graphics.TextRenderingHint中的值。我建议不要使用ClearType,因为这只会在液晶显示器(而非CRT)上显示不错,并且由于旋转可能无效。

P.S。这是Vilx-,而不是Vlix。 :d

答案 4 :(得分:1)

也许您可以在CodeProject文章的源代码中找到答案:

Per Pixel Alpha Blend in C#

答案 5 :(得分:1)

抱歉,我没有仔细阅读你的问题。

我知道我已成功在彩色背景上绘制旋转文本,而不会在示例中看到任何混叠效果。当我回过头来查看我的代码时,我意识到我正在使用逻辑字体绘制旋转的文本,该字体很好地包装在Microsoft.WindowsCE.Forms命名空间中。此技术将绘制角度设置为逻辑字体的属性(因此不要调用TranslateTransform或RotateTransform)。

在Windows CE世界之外,您必须使用PInvoke来创建逻辑字体(我从来没有这样做过,我很快就找不到好的例子)。我不知道这会有多好,但我确信它会绘制旋转的文本,而不会出现你所看到的奇怪的混叠效果。我认为这肯定是GDI +中的一个错误(或者只是他们认为没有人会真正使用的东西)。

一种可能比逻辑字体表现更好的替代方法是在彩色矩形背景上正常绘制文本(大小足以容纳文本),然后将矩形旋转并复制到主图像上。 Graphics.DrawImage似乎无法进行旋转,但使用LockBits很容易实现此效果。

答案 6 :(得分:0)

事实证明,微软为网络提供了一个新的动态图像库,作为CodePlex上Asp.Net内容的一部分:

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

不幸的是,这对我想要的东西来说有点多了。使用不安全的代码我可以滚动自己的alpha透明度,但是这个代码被用作高使用率Web应用程序的一部分,这太慢了。

这只是MS的GDI + .Net实施中的一个错误吗?

答案 7 :(得分:0)

创建位图时,至少应指定32位像素格式(例如:PixelFormat.Format32bppArgb),否则GDI +无法管理透明度。

要在保存时调整生成的文件,可以使用Save with ImageCodecInfo和EncoderParameters。

答案 8 :(得分:0)

或者,您可以将文本渲染为不透明的PNG,但使用与单元格背景颜色匹配的背景颜色(而不是白色)。