Битовая обработка байтов в C # - PullRequest
3 голосов
/ 27 июля 2011

Борьба с манипулированием нижележащими байтами объекта Bitmap для удаления прозрачности изображения.У меня есть статический метод удаления прозрачности, который принимает растровый объект, соответствующий код: http://pastebin.com/ZjjPSdx8

Теперь, когда я вызываю это с растровым объектом, основанным на файле, растровое изображение не изменяется.Если я правильно понимаю, это потому, что, поскольку он основан на файле в соответствии с http://support.microsoft.com/kb/814675

Таким образом, создан метод для копирования растрового изображения: http://pastebin.com/9rXRJ6cx

private Bitmap LoadBmp(string name)
    {
        Assembly asm = Assembly.GetExecutingAssembly();
        string loc = Path.GetDirectoryName(asm.Location);
        string path = Path.Combine(loc, "Images\\" + name);
        Bitmap notsafe = (Bitmap)Bitmap.FromFile(path);
        return ImageProcessor.SafeBitmap(notsafe);
...

Все отлично и денди.Хорошо работает с PNG, но не с GIF.Они получаются ужасно искаженными.

Попробовал альтернативный метод записи файла в байтовый массив, а затем на основе растрового изображения:

        byte[] b = new byte[2048];
        int c;
        byte[] imgArr;
        using (FileStream fs = new FileStream(path, FileMode.Open))
        {
            using (MemoryStream ms = new MemoryStream())
            {
                while ((c = fs.Read(b, 0, b.Length)) > 0)
                    ms.Write(b, 0, c);
                imgArr = ms.ToArray();
            }
        }

        return (Bitmap)Bitmap.FromStream(new MemoryStream(imgArr));

Это не искажает GIF-файлы.однако мой метод удаления прозрачности больше не работает на PNG!Очевидно, что я делаю что-то не так, надеюсь, кто-то может помочь!

Ответы [ 2 ]

4 голосов
/ 27 июля 2011

РЕДАКТИРОВАТЬ:

Вы можете решить проблему неизменяемого растрового изображения при загрузке из файла следующим образом:

var bmp = new Bitmap(Image.FromFile("C:\bmp.bmp"))

Это предотвращает необходимость выполнения Marshal.Copy (которые выполняются медленно), а также решает проблему искажения и искажения GIF-файлов. Внутренний код .NET, который делает это, если вам интересно, следующий:

 g = Graphics.FromImage(this);
 g.Clear(Color.Transparent); 
 g.DrawImage(original, 0, 0, width, height);

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

Однако, если вы можете одновременно выполнять загрузку и копирование через g.FromImage, я получаю скорости (5.6 seconds g.FromImage vs 6.4 seconds yours with 1000 gifs @ 543x341)

Теоретически вы можете сделать свое дело быстрее, если объедините копирование и удаление прозрачности в одной функции. Если вы загрузите GIF без перезаписи изображения, оно будет в другом пиксельном формате, на самом деле, 8bppindexed, что означает, что ваша функция не будет работать как есть. В любом случае, приведенное выше решение решит проблему при использовании вашей функции CheckIfTransparent, а решение ниже (мне пришлось немного отредактировать) сделает это быстрее. Я могу потратить некоторое время на поиски этого, если сделаю. Я нахожу проблему интересной.

Я заметил, что ваш алгоритм удаления альфы не совсем точен. Я не уверен, где именно, но ваш алгоритм выглядит неправильно при использовании с прозрачными градиентами. Тот, который использует прямой GDI, выглядит как и ожидалось. Я бы убедился, что вы правильно конвертируете цвета.


Если вы просто хотите удалить прозрачность в png или gif, сделав все это Marshal.Copy и небезопасный код, почему бы просто не создать новое растровое изображение, нарисовать белый фон, а затем наложить выходящий png / gif на Это? Похоже, менее сложный код.

РЕДАКТИРОВАТЬ: Примерно так:

    public static Bitmap ManagedSafeBitmap(string file)
    {
        using (var img = Image.FromFile(file))
        {
            var bmp = new Bitmap(img.Width, img.Height);
            bmp.SetResolution(img.HorizontalResolution, img.VerticalResolution);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.Clear(Color.White);
                g.DrawImage(img, 0, 0);
            }

            return bmp;
        }
    }

Это даст вам новое изображение с белым фоном и поместит исходное изображение поверх него, эффективно изменив все прозрачные пиксели на Color.White или любой цвет, который вы хотите передать g.Clear()

0 голосов
/ 27 июля 2011

Я бы попробовал с WriteableBitmap классом. Я слышал, что он был создан только для манипулирования пикселями с использованием управляемого кода.

...