Выполнение скриншотов в Windows Vista, Windows 7, с прозрачными областями за пределами области приложения
Я пытаюсь сделать снимок экрана приложения, и я хотел бы сделать части прямоугольника, которые не являются частью области приложений, прозрачными. Так, например, в стандартном приложении Windows я хотел бы сделать округленные углы прозрачными.
Я написал быстрое приложение test, которое работает на XP (или vista/windows 7 с отключенным aero):
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
// Just find a window to test with
IntPtr hwnd = FindWindowByCaption(IntPtr.Zero, "Calculator");
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hwnd, ref info);
Rectangle r = Rectangle.FromLTRB(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
IntPtr hrgn = CreateRectRgn(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
GetWindowRgn(hwnd, hrgn);
// fill a rectangle which would be where I would probably
// write some mask color
g.FillRectangle(Brushes.Red, r);
// fill the region over the top, all I am trying to do here
// is show the contrast between the applications region and
// the rectangle that the region would be placed in
Region region = Region.FromHrgn(hrgn);
region.Translate(info.rcWindow.Left, info.rcWindow.Top);
g.FillRegion(Brushes.Blue, region);
}
Когда я запускаю это тестовое приложение на XP (или Vista/Windows 7 с отключенным Aero), я получаю что-то вроде этого, и это здорово, потому что я могу использовать маску xor из этого, которую можно использовать позже с BitBlt.
удалена мертвая ссылка Imageshack - Скриншот
Вот проблема, на Vista или Windows 7 с включенным Aero, в окне не обязательно есть область, на самом деле в большинстве случаев ее нет. Может ли кто-нибудь помочь мне выяснить способ создания такой маски на этих платформах?
Вот некоторые из подходов, которые я уже пробовал...
1. Использование функции PrintWindow: Это не работает, потому что она возвращает скриншот из окна с отключенным Aero и этим окном это другая форма из окна, возвращенного с помощью Aero on
2 Используя Desktop Window Manager API, чтобы получить миниатюру полного размера: Это не сработало, потому что он обращается непосредственно к экрану и из того, что я могу сказать, вы не можете получить скриншот прямо из этого api. Да, я мог бы открыть окно с розовым фоном, показать миниатюру, снять скриншот, затем скрыть это временное окно, но это ужасный пользовательский интерфейс и полный хак, я бы предпочел не иметь мое имя.
3. Используя Graphics.CopyFromScreen или какой-либо другой вариант pinvoke этого: Это не работает, потому что я не могу предположить, что это окно Мне нужна информация, находящаяся в верхней части z-порядка на экране.
В настоящее время лучшим решением, которое я могу придумать, является специальный случай Aero в Windows 7 и Vista, чтобы вручную вытереть углы, жестко кодируя некоторые графические пути, которые я рисую, но это решение будет сосать, поскольку любое приложение, которое выполняет пользовательское скинирование нарушит это.
Можете ли вы придумать другое или лучшее решение?
Если вы здесь, спасибо за то, что нашли время, чтобы прочитать это сообщение, я ценю любую помощь или направление, которые вы можете предложить!
Ответы
Ответ 1
Если вы ищете готовое приложение, 7capture, который также отображает прозрачность, поэтому изображения можно сохранить в PNG формат для последующего компоновки.
EDIT:
В исходном вопросе и комментариях указывается, что вы хотите создать регион в Windows Vista/7, который затем можно использовать для маскировки частей захваченного изображения, как это делается с Windows XP и не-Aero. Использование региона не даст вам результат, который вы ищете, поскольку контур окна не вычисляется как регион, а как изображение с переменной прозрачностью - RGBA. Альфа-канал в этом изображении - ваша маска, но это не встроенная маска, как область, а постепенная маска с диапазоном значений из пикселей, полностью включаемых в полностью замаскированную.
Хотя он использует недокументированные API, код http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/ будет захватывать буфер RGBA, который затем можно использовать для рендеринга или сохранения изображение с тенью и другими эффектами прозрачности.
В DwmCapture.cs
Изменить
BackBufferFormat = Format.X8R8G8B8
к
BackBufferFormat = Format.A8R8G8B8
(X8- > А8)
И тогда вы должны иметь доступ к обычным данным RGB плюс прозрачность из захваченного буфера. Затем это можно сохранить как PNG или другой формат с альфа-каналом для компоновки.
Ответ 2
Удаленная идея, которая ужасна, но была бы ужасной в 90-е годы
Вы говорите, что использование DWM API позволяет вам напрямую захватывать экран... вы можете создать окно вне экрана (скажем, X = -100000px, Y = -100000px), но видимое (возможно, даже скрытое?) и нарисуйте скриншот к нему? Поскольку при использовании DWM каждое окно имеет текстуру подложки, я думаю, что она все равно может быть нарисована, даже если цель не находится на экране.
Кроме того, если вы хотите перейти по пути DirectX и получить доступ к фактической текстуре DX в окне, я нашел несколько потенциальных ссылок, которые могут помочь (особенно первая ссылка):
Ответ 3
- Использование Graphics.CopyFromScreen или другого варианта вывода: Это не работает, потому что я не могу предположим, что окно мне нужно информация находится в верхней части z-порядок на экране.
Если вам известно, в каком окне вам нужна информация, вы можете перенести ее на передний план, вызовите Graphics.CopyFromScreen, а затем reset его z-index? Я знаю по опыту, что Aero делает странные вещи, когда элементы находятся в фоновом режиме, чтобы сделать их стеклянный интерфейс работать правильно (частичный рендеринг и т.д.). Это не может быть большим UX; однако это будет особый случай и будет использоваться только при включении Aero.
Ответ 4
Вы можете посмотреть исходный код AeroShot, как описано на главной странице, он может захватывать закругленные края и с помощью эффект прозрачности Aero Glass и сохранить его в PNG файле. Это написано на С#.