Использование Graphics.DrawImage () для рисования изображения с прозрачностью / альфа-каналом

Копирую изображение. (Мой реальный код изменяет размер изображения, но это не имеет отношения к моему вопросу.) Мой код выглядит примерно так.

Image src = ...

using (Image dest = new Bitmap(width, height))
{
    Graphics graph = Graphics.FromImage(dest);
    graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
    graph.DrawImage(src, 0, 0, width, height);
    dest.Save(filename, saveFormat);
}

Кажется, это отлично работает, если src не загружается из изображения с прозрачностью (например, GIF) или альфа-каналом (например, PNG).

Как я могу заставить DrawImage() перенести прозрачные пленки / альфа-канал в новое изображение, а затем сохранить их при сохранении файла?


person Jonathan Wood    schedule 18.05.2012    source источник
comment
Вопрос в том, каково значение переменной saveFormat? Это должен быть PixelFormat.Format32bppArgb (или другой формат с обработкой альфа-канала). Попробуйте также: using (Image dest = new Bitmap(width, height, PixelFormat.Format32bppArgb)).   -  person Lukasz M    schedule 19.05.2012
comment
Кажется, это работает для альфа-каналов, но не для прозрачных пленок GIF. saveFormat будет варьироваться в зависимости от формата входного файла. Если входной файл не поддерживает альфа-канал, можно с уверенностью предположить, что изображение не будет содержать пиксели альфа-канала.   -  person Jonathan Wood    schedule 19.05.2012
comment
Итак, какое тогда значение saveFormat для файлов GIF :)?   -  person Lukasz M    schedule 19.05.2012
comment
В этом случае это ImageFormat.Gif.   -  person Jonathan Wood    schedule 19.05.2012
comment
Спасибо за быстрый ответ. А пока я нашел статью о прозрачности GIF. Взгляните на это: support.microsoft.com/kb/319061. Я полагаю, что в основном вам просто нужно получить палитру изображения и установить цвет, сохраненный в первом индексе, на прозрачный.   -  person Lukasz M    schedule 19.05.2012
comment
Ой. Спасибо, но по многим из них я не совсем понял. В любом случае, если мне нужен весь этот код только для обработки файлов GIF, это действительно прискорбно. Все еще ищу...   -  person Jonathan Wood    schedule 19.05.2012
comment
Кстати, я тоже пробовал using (Image dest = new Bitmap(src, width, height)). Это делает изображение совместимым с исходным изображением. Как и в вашей рекомендации, он поддерживает альфа-каналы, но, к сожалению, не поддерживает прозрачность GIF.   -  person Jonathan Wood    schedule 19.05.2012
comment
Я не могу найти подходящий файл для проверки, но попробуйте: if (saveFormat == ImageFormat.Gif && src.Palette.Entries.Length > 0) { System.Drawing.Color firstColor = src.Palette.Entries[0]; src.Palette.Entries[0] = System.Drawing.Color.FromArgb(0, firstColor); } перед сохранением файла.   -  person Lukasz M    schedule 19.05.2012
comment
Извините, в предыдущем комментарии была ошибка. Я имел в виду, что вы, конечно, должны изменить палитру для конечного изображения (не в src).   -  person Lukasz M    schedule 19.05.2012
comment
Или вы можете попробовать это по всем направлениям, может сработать: src.Palette.Entries.CopyTo(dest.Palette.Entries, 0);   -  person yamen    schedule 19.05.2012
comment
@JonathanWood: Вы пробовали использовать мои предложения по обновлению палитры?   -  person Lukasz M    schedule 19.05.2012
comment
@ Лукас: Нет. Это только часть большой задачи, над которой мы работаем, а файлы GIF - это лишь небольшая часть файлов, которые мы хотим поддерживать. Я еще не определил, стоит ли писать собственный код только для прозрачных пленок GIF. Я могу определить это позже. Я ценю вклад.   -  person Jonathan Wood    schedule 19.05.2012
comment
Если описанное мной решение сработало для вас, возможно, другие форматы (для которых оно не работает) также связаны с изменением палитры или / и созданием растрового изображения с поддержкой альфа-канала.   -  person Lukasz M    schedule 19.05.2012


Ответы (2)


Это довольно непонятно, вы много чего не сказали. Самая большая проблема с прозрачностью в том, что вы ее не видите. Вы пропустили пару шагов, вы явно не указали формат пикселей вашего нового растрового изображения, вы вообще не инициализировали его и не сказали, какой формат вывода вы используете. Некоторые не поддерживают прозрачность. Итак, давайте сделаем версию, которая проясняет ситуацию. Из изображения PNG, которое в paint.net выглядит так:

введите описание изображения здесь

Используя этот код

        using (var src = new Bitmap("c:/temp/trans.png"))
        using (var bmp = new Bitmap(100, 100, PixelFormat.Format32bppPArgb)) 
        using (var gr = Graphics.FromImage(bmp)) {
            gr.Clear(Color.Blue);
            gr.DrawImage(src, new Rectangle(0, 0, bmp.Width, bmp.Height));
            bmp.Save("c:/temp/result.png", ImageFormat.Png);
        }

Создает это изображение:

введите описание изображения здесь

Вы можете отчетливо видеть синий фон, поэтому прозрачность сработала.

person Hans Passant    schedule 19.05.2012
comment
Что ж, я намеревался поддержать любой формат, соответствующий входному файлу. Я думал, что был довольно конкретным. Просто код не предназначался для поддержки только одного типа файлов. Возможно, мне понадобится связка кода для обработки каждого типа файлов - я не знаю. Я попытался указать PixelFormat, как и вы, но потом мне показалось, что это вызывает ошибки, когда тип файла - GIF с прозрачностью. И, действительно, некоторые варианты, казалось, нормально работали с PNG без указания PixelFormat. - person Jonathan Wood; 19.05.2012
comment
@JonathanWood создаст новое растровое изображение с шириной и высотой старого растрового изображения и вашим новым желаемым форматом. Желательно в операторе using создать объект Graphics FromImage(your new bitmap) и DrawImage(your old bitmap). - person ; 20.02.2016

Я нашел этот поток, потому что у меня была такая же проблема (т.е. DrawImage не копировал альфа-канал), но в моем случае это было просто потому, что я упустил из виду, что использовал PixelFormat.Format32bppRgb вместо PixelFormat.Format32bppArgb. Так примерно то, что Лукаш М. сказал в комментариях.

person Alex    schedule 10.01.2019