Можете ли вы сделать прозрачный альфа PNG с C #? - PullRequest
34 голосов
/ 23 декабря 2008

У меня есть страница с несколькими браузерами, которая показывает вертикальный текст.

В качестве уродливого хакера для получения текста, отображаемого вертикально во всех браузерах, я создал собственный обработчик страниц, который возвращает 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 );
    }
}

Теперь кажется, что альфа работает, но текст кажется блочным - как будто у него все еще есть края jaggie, но на черном фоне.

Это какая-то ошибка в .Net / GDI +? Я уже обнаружил, что он не работает даже с индексной прозрачностью для гифок, поэтому я не очень уверен в этом.

Это изображение показывает два пути, которые идут не так:

vertical text comparison

Верхнее изображение показывает его без белого фона или MakeTransparent вызова. Вторая с белым фоном и затем MakeTransparent вызывается для добавления прозрачности индекса.

Ничего из этого не является правильным - на втором изображении присутствуют неровности с алиасами белого цвета, которые мне не нужны, на первом изображается сплошной псевдоним с черным.

Ответы [ 9 ]

14 голосов
/ 04 мая 2009

Чтобы исправить текст "блочность", вы не можете просто сделать ...

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

после этой строки ...

Graphics g = Graphics.FromImage( (Image) image );
6 голосов
/ 23 декабря 2008

Вы можете использовать метод LockBits в своем растровом изображении для возврата объекта BitmapData и установить альфа-канал для каждого пикселя самостоятельно (вы также можете использовать GetPixel и SetPixel, но эти методы безумно медленны) См. этот ответ .

Я знаю, что это работает наверняка, потому что, когда я впервые начал использовать технику, я устанавливал значение альфа на 0, поэтому ни один из цветов, которые я устанавливал, не был виден.

Редактировать: вот пример эффекта объектива «рыбий глаз», полностью выполненного в .NET (с использованием LockBits):

альтернативный текст http://www.freeimagehosting.net/uploads/21ca8300cc.jpg

6 голосов
/ 23 декабря 2008

IIRC, вам нужно указать PixelFormat в конструкторе растрового изображения.

5 голосов
/ 23 декабря 2008

Для сглаживания текста поиграйтесь со значениями в Graphics.TextRenderingHint. Я бы посоветовал не использовать ClearType, потому что он будет отображаться только на ЖК-мониторах (не CRT) и может не работать из-за поворота.

P.S. Это Vilx-, а не Vlix. : D

1 голос
/ 24 декабря 2008

Извините, я недостаточно внимательно прочитал ваш вопрос.

Я знаю, что успешно нарисовал повернутый текст на цветном фоне, не видя ни одного из эффектов сглаживания в ваших примерах. Когда я вернулся, чтобы посмотреть на мой код, я понял, что рисую повернутый текст, используя логический шрифт, который красиво обернут в пространство имен Microsoft.WindowsCE.Forms. Этот метод устанавливает угол рисования как свойство логического шрифта (поэтому вы не вызываете TranslateTransform или RotateTransform).

За пределами мира Windows CE, вам нужно PInvoke, чтобы создать логический шрифт (я никогда не делал этого и не мог быстро найти хороший пример). Я не знаю, насколько хорошо это будет работать, но я точно знаю, что он будет рисовать повернутый текст без странных эффектов сглаживания, которые вы видите. Я думаю наверняка, что это ошибка в GDI + (или просто что-то, о чем они не думали, что кто-то когда-либо будет действительно использовать).

Альтернативный подход, который может работать даже лучше, чем логический шрифт, состоит в том, чтобы нарисовать текст обычно на цветном прямоугольном фоне (достаточно большой, чтобы вместить текст), а затем повернуть и скопировать прямоугольник на основное изображение. Похоже, что Graphics.DrawImage не может выполнять вращение, но этот эффект легко реализовать с помощью LockBits.

1 голос
/ 23 декабря 2008

Возможно, вы найдете ответ в исходном коде этой статьи CodeProject:

За пиксель альфа-смесь в C #

0 голосов
/ 24 декабря 2008

Или вы можете просто визуализировать текст в непрозрачный PNG, но использовать цвет фона (вместо белого), который соответствует цвету фона ячейки.

0 голосов
/ 24 декабря 2008

При создании растрового изображения необходимо по крайней мере указать 32-битный пиксельный формат (например, PixelFormat.Format32bppArgb), иначе GDI + не сможет управлять прозрачностью.

Чтобы настроить полученный файл при сохранении, вы можете использовать Сохранить с ImageCodecInfo и EncoderParameters.

0 голосов
/ 24 декабря 2008

Оказывается, что у Microsoft есть новая библиотека динамических изображений для Интернета как часть контента Asp.Net на CodePlex:

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

К сожалению, это немного много для того, что я хочу. Используя небезопасный код, я могу развернуть собственную альфа-прозрачность, но это слишком медленно, учитывая использование этого кода в качестве части веб-приложения с высокой нагрузкой.

Это просто ошибка в реализации MS GDI + .Net?

...