(Растровое изображение) изображение ведет себя иначе, чем новое растровое изображение (изображение) - PullRequest
5 голосов
/ 08 ноября 2011

Вот тест, который я написал и который в настоящее время не пройдёт:

var unusableColor = Color.FromArgb(13, 19, 20, 19);
var retrievedColor = Color.Empty;
var tempFile = Path.GetTempFileName();

using (var bitmap = new Bitmap(1, 1))
{
    bitmap.SetPixel(0, 0, unusableColor);
    bitmap.Save(tempFile, ImageFormat.Png);
}

using (var image = Image.FromFile(tempFile))
// This will lead to the error
using (var bitmap = new Bitmap(image))
// But this will work
//using (var bitmap = (Bitmap)image)
{
    retrievedColor = bitmap.GetPixel(0, 0);
}

Assert.That(retrievedColor, Is.SameAs(unusableColor));

Если вы посмотрите на retrievedColor, вы обнаружите, что оно будет таким же, как Color.FromArgb(13, 19, 19, 19). Таким образом, разница будет в том, что зеленая часть изменилась с 20 на 19.

Есть идеи, почему это происходит или при каких условиях конструктор растрового изображения изменит пиксель?

Обновление

Кажется, это более глубокая вложенная проблема. Заменив конструктор Bitmap простым преобразованием переменной изображения, проблема исчезнет. Это может решить проблему, но не объясняет. Более того, я смог воспроизвести проблему даже в Paint.Net, выполнив следующую процедуру:

  • Откройте Paint.Net и создайте новое изображение (размер не имеет значения)
  • Выбрать все ( Ctrl + A )
  • Снять выделение ( Del )
  • Открыть диалоговое окно цвета ( F8 )
  • Введите вышеуказанные значения для RGB (19, 20, 19) и внизу прозрачность (13).
  • Выберите инструмент заливки ( F )
  • Заполните цвет пустым изображением
  • Выберите инструмент выбора цвета ( K )
  • Щелкните где-нибудь на вашем новом изображении и посмотрите цветовой диалог

Так что, похоже, это более серьезная проблема, вызванная не классом Bitmap или Image, а, возможно, более глубокой функциональностью, такой как GDI + или чем-то подобным.

Обновление 2

Я только что написал новый тест, чтобы выяснить все затронутые цвета:

for (int a = 0; a < 256; a++)
{
    for (int r = 0; r < 256; r++)
    {
        for (int g = 0; g < 256; g++)
        {
            for (int b = 0; b < 256; b++)
            {
                using (var bitmap = new Bitmap(1, 1))
                {
                    var desiredColor = Color.FromArgb(a, r, g, b);
                    bitmap.SetPixel(0, 0, desiredColor);

                    // This will fail in a lot of colors with a low alpha channel value
                    using (var copiedBitmap = new Bitmap(bitmap))
                    // This will work, cause the information is entirely copied.
                    //using (var copiedBitmap = (Bitmap)bitmap.Clone())
                    {
                        var retrievedColor = copiedBitmap.GetPixel(0, 0);

                        if (desiredColor != retrievedColor)
                        {
                            Debug.Print(desiredColor + " != " + retrievedColor);
                        }
                    }
                }
            }
        }
    }

Пожалуйста, не позволяйте ему работать полностью сам по себе, потому что потребуется много времени, чтобы закончить, и он также обнаружит множество различий. Но что вы можете видеть, если вы поиграете с прозрачностью (установив 1 или 10), то увидите, что значения RGB используют это как некоторую битовую глубину.

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

Просто имейте в виду, что цвет может измениться, вызвав конструктор растрового изображения, если цвет имеет низкое значение прозрачности. Если вам действительно нужны исходные цвета, чтобы остаться в живых во втором экземпляре, вместо этого используйте (Bitmap)myBitmap.Clone() или если вы загружаете его с диска, используйте (Bitmap)Image.FromFile(filename), потому что Image - это только абстрактный класс, который обычно создается через класс Bitmap.

Ответы [ 2 ]

8 голосов
/ 08 ноября 2011

Я проверил файл PNG, сохраненный с вашим кодом с помощью Paint.NET, и цвет пикселя точно равен unusableColor.
Если вы измените код чтения с помощью этого:

using (Bitmap bitmap = (Bitmap)Image.FromFile(tempFile))
{
    retrievedColor = bitmap.GetPixel(0, 0);
}

все работает

2 голосов
/ 08 ноября 2011

вы можете использовать метод Clone: ​​

    using (var image = Image.FromFile(tempFile))
    {
        using (var bitmap = image.Clone() as Bitmap)
        {
            retrievedColor = bitmap.GetPixel(0, 0);
        }
    }

Проблема в «новом растровом изображении», потому что он создает новый экземпляр.Если вы посмотрите в конструктор растрового изображения, он создаст новое прозрачное изображение и отрисовает исходное изображение.Графический объект имеет свойство режима сглаживания, которое используется для качества рисования.по умолчанию нет сглаживания.

Вот конструктор растрового изображения:

Graphics graphics = null;
try
{
    graphics = Graphics.FromImage(this);
    graphics.Clear(Color.Transparent);
    graphics.DrawImage(original, 0, 0, width, height);
}
finally
{
    if (graphics != null)
    {
        graphics.Dispose();
    }
}

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

...