Обрезка изображения в памяти перед рисованием на форме

Я пытаюсь использовать следующий код, чтобы скопировать часть экрана в новое место в моей форме Windows.

private void Form1_Paint(object sender, PaintEventArgs e)
{
    var srcPoint = new Point(0,0);
    var dstPoint = new Point(Screen.PrimaryScreen.Bounds.Width/2, Screen.PrimaryScreen.Bounds.Height/2);
    var copySize = new Size(100, 100);

    e.Graphics.CopyFromScreen(srcPoint, dstPoint, copySize, CopyPixelOperation.SourceCopy);
}

Функция CopyFromScreen игнорирует все клипы, установленные перед ней.

e.SetClip(new Rectangle(srcPoint.X, srcPoint.Y, 20, 20));

Я делаю что-то не так или это просто неправильный подход.

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

Я знаю о FlawlessWidescreen, но он не поддерживает многие менее популярные игры. Я полагаю, что ковыряние в памяти (что делает безупречный) также может сработать, но почти всегда против TOS.

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

Редактировать № 2: Итак, каждые 100 мс рисуется неправильная форма. Оказывается, это просто тормозит игру, пока я не замедляю ее до каждых 500 мс. Но все же игра не гладкая. Будет ли эта операция копирования и рисования изображения слишком тяжелой для GDI+? Я думал, что это достаточно просто, чтобы ничего не увязнуть.

Что вы думаете, прежде чем я отмечу ответ как принятый?


person aitee    schedule 15.02.2015    source источник


Ответы (2)


Я думаю, что это действительно неправильный подход.

ClippingRegion используется только для отсечения команд DrawXXX и FillXXX, включая DrawImage (!).

Однако CopyFromScreen будет использовать данные Points и Size и не обрезать источник.

Для региона Rectangle это не проблема, поскольку вы можете добиться того же результата, выбрав правильные значения Point и Size.

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

Для этого можно создать более или менее сложные GraphicsPaths.

Вот пример кода:

Поместив координаты отсечения в Rectangleили GraphicsPath clip, вы можете написать что-то вроде этого:

e.Graphics.SetClip(clip);

using (Bitmap bitmap = new Bitmap(ClientSize.Width, ClientSize.Height))
{
    using (Graphics G = Graphics.FromImage(bitmap))
            G.CopyFromScreen(dstPoint, srcPoint, 
                             copySize, CopyPixelOperation.SourceCopy);
    e.Graphics.DrawImage(bitmap, 0, 0);
}
person TaW    schedule 15.02.2015
comment
Спасибо. Я действительно начал идти по этому пути. Я не совсем разобрался с графикой и растровыми изображениями. и теперь я думаю, что понял. Графика - это просто оболочка вокруг какого-то другого источника. Так что, будь то HDC или изображение, не имеет значения. Но вы никогда не копируете графику, вы должны смотреть на источник того, на что указывает графика. - person aitee; 15.02.2015
comment
Да: класс Graphics — это инструмент, который вы используете для работы с растровым изображением из какого-либо источника, будь то файл, поверхность управления или растровое изображение в чистой памяти; у него есть много методов и свойств для управления его работой, но он не содержит графических данных, то есть пикселей. - person TaW; 15.02.2015
comment
Были ли у вас какие-либо комментарии к Edit # 2? Простая копия образа выходит за пределы диапазона производительности для GDI+? - person aitee; 15.02.2015
comment
Не заметил правку, извините. Анимация GDI обычно довольно быстро достигает своих пределов. Вы можете кэшировать GraphicsPath, но я думаю, что скорость в основном зависит от размера копируемых областей. О том, какие размеры вы используете? - person TaW; 16.02.2015
comment
да, я могу представить, что это может быть несколько отрывисто. - person TaW; 16.02.2015

Разве это не должно быть

 e.Graphics.Clip = myRegion;
person tumasgiu    schedule 15.02.2015
comment
Да, извините за это. Я не просто скопировал свой код, чтобы сделать его кратким (напечатал в соответствующих частях). На самом деле в моем коде было e.Graphics.SetClip(...);. Я предполагаю/полагаю, что нет никакой разницы между этим и тем, что вы опубликовали. - person aitee; 15.02.2015