Graphics.DrawImage потемнело? - PullRequest
       21

Graphics.DrawImage потемнело?

0 голосов
/ 05 февраля 2011

Я использую функцию DrawImage Image, чтобы скопировать часть из изображения в другое. Можно ли сделать так, чтобы скопированная часть была «темнее»? Мол, особый цветовой тон? Может кто-нибудь привести пример? Я слышал о чем-то под названием ImageAttributes, но я не могу его найти!

Примечание. Я не хочу редактировать исходное изображение.

Ответы [ 2 ]

1 голос
/ 05 февраля 2011

(Не обязательно прямой ответ на этот вопрос, но на дополнительный вопрос, в котором указание ImageAttributes для метода DrawImage привело к снижению производительности. Этот вопрос с тех пор был удален, но я все равно разместил здесь свой ответ, так как я уже написал это. Проигнорируйте, если хотите.)

Рисование графики выполняется медленно, особенно если вы одновременно применяете эффект рендеринга. Потратьте несколько минут на работу в Photoshop, и вы поймете, о чем я. Затемнение изображения - вычислительно дорогая задача. Вы мало что можете сделать, чтобы он шел быстрее.

Проблема дополнительно усугубляется тем фактом, что подпрограммы в классе System.Drawing.Graphics в .NET Framework внутренне реализованы с использованием GDI +, что не с аппаратным ускорением. Возможной альтернативой является переключение обратно на рендеринг на основе GDI, который аппаратно ускоряется в большинстве систем (это зависит от поставщика вашей видеокарты, но почти каждая карта, которую вы найдете сегодня, имеет аппаратное ускорение для основных функций, таких как передача битовых блоков) , Конечно, это намного сложнее, потому что вам понадобится P / Invoke-функции из Windows API, чтобы использовать основанные на GDI процедуры рисования; все, что предоставляет вам .NET - это GDI +. Это намного больше работы, чем необходимо, и улучшения скорости, вероятно, минимальны на современном оборудовании (особенно с включенной темой Aero в Windows Vista / 7, которая не использует аппаратное ускорение даже с GDI, потому что все обращается к растровому изображению в памяти) .

Придерживаясь текущей реализации, на ум приходит еще пара возможных оптимизаций:

  1. Вы изменяете размер изображения, когда перерисовываете его? Если это так, это требует интерполяции изображения, что очень медленно по сравнению.

  2. В каком PixelFormat находится изображение? Format32bppPArgb намного быстрее, чем альтернативы. Убедитесь, что вы работаете с изображением в этом формате. Если вы этого не сделаете, внесение этого изменения должно значительно увеличить скорость рендеринга.

  3. Почему вам нужно повторять изображение так часто? Если это одно и то же изображение, нарисуйте его один раз, применив эффекты, и кешируйте возвращаемый объект Bitmap. Затем каждый раз, когда вам нужно перерисовать изображение, используйте тот, который уже находится в памяти, а не создавайте новый. Это простой трюк, но он удерживает вас от необходимости каждый раз делать дорогую часть снова. Как вы упоминаете, только DrawImage намного быстрее, чем установка отображаемых атрибутов.

Как правило, пользователи готовы подождать, пока будут отображаться большие изображения. Настройка вашего интерфейса соответственно более уместна, чем попытка оптимизировать графические процедуры. То, что индикатор выполнения и занятый курсор используются для указания на то, что что-то происходит на самом деле, пойдет намного дальше, чем это касается пользователя, чем выжимать еще несколько миллисекунд из вашего кода. Если вы не применяете этот эффект снова и снова в цикле примерно 100 или 1000 раз (что выглядит довольно глупо), то не стоит потратить время на оптимизацию.

1 голос
/ 05 февраля 2011

Функция DrawImage даже имеет специальную перегрузку, которая устанавливает объект ImageAttributes именно по этой причине:

private void Example(PaintEventArgs e)
{
    ImageAttributes imageAttr = new ImageAttributes();
    imageAttr.SetGamma(2.2f);

    Rectangle rect = new Rectangle(250, 20, 200, 200);
    e.Graphics.DrawImage(myImage, rect, 0, 0, 200, 200, GraphicsUnit.Pixel, imageAttr);    
}
...