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

发布于 2024-07-10 22:10:53 字数 2972 浏览 5 评论 0原文

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

作为让文本在所有浏览器中垂直渲染的丑陋黑客,我创建了一个自定义页面处理程序,它返回一个带有垂直绘制文本的 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 似乎可以工作,但文本看起来是块状的 - 就好像它仍然具有锯齿状边缘,但在黑色背景下。

这是 .Net/GDI+ 的一些错误吗? 我已经发现它甚至对于 gif 的索引透明度都失败,所以我对此没有太大信心。

此图片显示了出现问题的两种方式:

vertical text Comparison

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

这些都不正确 - 第二张图像有我不想要的白色锯齿锯齿,第一张图像似乎与黑色完全锯齿。

I have a multi-browser page that shows vertical text.

As an ugly hack to get text to render vertically in all browsers I've created a custom page handler that returns a PNG with the text drawn vertically.

Here's my basic code (C#3, but small changes to any other version down to 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 );
    }
}

This creates an image that looks how I want it to, except that the transparency is index based. As I'm returning a PNG it could support a proper alpha transparency.

Is there any way to do this in .net?


Thanks to Vlix (see comments) I've made some changes, though it still isn't right:

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 );
    }
}

Now the alpha appears to work, but the text appears blocky - as if it still has the jaggie edges but against a black background.

Is this some bug with .Net/GDI+? I've already found that it fails for even index transparencies for gifs, so I don't have much confidence it it.

This image shows the two ways this goes wrong:

vertical text comparison

The top image shows it with no white background or MakeTransparent call. The second with the background filled with white and then MakeTransparent called to add the index transparency.

Neither of these is correct - the second image has white aliasing jaggies that I don't want, the first appears to be solidly aliased against black.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

爱的故事 2024-07-17 22:10:53

要修复文本“块状”,你不能

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

在这一行之后做...

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

To fix the text "blockiness", can't you just do...

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

after this line...

Graphics g = Graphics.FromImage( (Image) image );
痞味浪人 2024-07-17 22:10:53

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

IIRC you need to specify the PixelFormat in the bitmap constructor.

凉风有信 2024-07-17 22:10:53

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

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

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

替代文本http://www.freeimagehosting.net/uploads/21ca8300cc.jpg

You can use the LockBits method on your Bitmap to return a BitmapData object, and set the Alpha for each pixel yourself (you could also use GetPixel and SetPixel, but these methods are insanely slow). See this answer.

I know this works for sure, because when I first started using the technique I was setting the alpha value to 0, so none of the colors I was setting were visible.

Edit: here is a sample of a fisheye lens effect, done entirely in .NET (using LockBits):

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

撩发小公举 2024-07-17 22:10:53

对于文本抗锯齿,可以使用 Graphics.TextRenderingHint 中的值。 我建议不要使用 ClearType,因为这只会在 LCD 显示器(而不是 CRT)上显示良好,并且可能由于旋转而无法工作。

PS 这是 Vilx-,不是 Vlix。 :D

For text antialiasing play around with values in Graphics.TextRenderingHint. I'd advise not to use ClearType, because that will only show up nice on LCD monitors (not CRT), and might not work due to the rotation.

P.S. It's Vilx-, not Vlix. :D

月光色 2024-07-17 22:10:53

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

Per Pixel Alpha融入 C#

Maybe you can find the answer in the source code of this CodeProject article:

Per Pixel Alpha Blend in C#

勿挽旧人 2024-07-17 22:10:53

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

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

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

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

Sorry, I didn't read your question carefully enough.

I know that I have successfully drawn rotated text on a colored background without seeing either of the aliasing effects in your examples. When I went back to look at my code, I realized that I was drawing the rotated text using a logical font, which is nicely wrapped in the Microsoft.WindowsCE.Forms namespace. This technique sets the drawing angle as a property of the logical font (so you don't call TranslateTransform or RotateTransform).

Outside of the Windows CE world, you have to PInvoke to create a logical font (I've never done this and I couldn't find a good example quickly). I don't know how well this would perform, but I know for sure that it will draw rotated text without the weird aliasing effects you're seeing. I think for sure this is a bug in GDI+ (or just something they didn't think anyone would ever really use).

An alternative approach that might even perform better than the logical font is to draw the text normally on a colored rectangle background (just large enough to hold the text), then rotate-and-copy the rectangle onto your main image. Graphics.DrawImage doesn't appear to be able to do rotation, but this effect is easy to implement using LockBits.

窗影残 2024-07-17 22:10:53

事实证明,Microsoft 有一个新的 Web 动态图像库,作为 CodePlex 上 Asp.Net 内容的一部分:

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

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

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

It turns out that Microsoft have a new dynamic image library for the web as part of the Asp.Net content on CodePlex:

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

Unfortunately it's a little bit much for what I want. Using unsafe code I can roll my own alpha transparency, but that's far too slow given this code's use as part of a high-usage web application.

Is this just a bug in MS's GDI+ .Net implementation?

人疚 2024-07-17 22:10:53

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

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

You should at least specify a 32bits pixel format (ex: PixelFormat.Format32bppArgb) when creating your bitmap, otherwise GDI+ cannot manage transparency.

To tune the resulting file when saving, you can use Save with ImageCodecInfo and EncoderParameters.

夜还是长夜 2024-07-17 22:10:53

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

Or, you could just render the text to a non-transparent PNG, but use a background color (instead of white) that matches the background color of the cell.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文