Снимки экрана в Windows Vista, Windows 7 с прозрачными областями вне области приложения - PullRequest
14 голосов
/ 07 июня 2010

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

Я написал быстрое тестовое приложение, которое работает на 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 при

.

2 Использование Desktop Window Manager API для получения миниатюры в натуральную величину: Это не сработало, потому что оно рисует прямо на экране и, как я могу сказать, вы можете ' получить скриншот прямо из этого API. Да, я мог бы открыть окно с розовым фоном, показать миниатюру, сделать снимок экрана, а затем скрыть это временное окно, но это ужасный пользовательский опыт и полный взлом, я бы предпочел, чтобы мое имя не отображалось.

3. Используя Graphics.CopyFromScreen или какой-либо другой вариант пинвока: Это не работает, потому что я не могу предположить, что окно, из которого мне нужна информация, находится в верхней части z-порядка на экран.

На данный момент лучшее решение, которое я могу придумать, - это особый случай Aero в Windows 7 и Vista, чтобы вручную стирать углы, жестко кодируя некоторые графические контуры, которые я рисую, но это решение будет неудачным, поскольку любое приложение, выполняющее пользовательский скиннинг сломаю это.

Можете ли вы придумать другое или лучшее решение?

Если вы здесь, спасибо, что нашли время прочитать этот пост, я ценю любую помощь или направление, которое вы можете предложить!

Ответы [ 4 ]

8 голосов
/ 18 июня 2010

Если вы ищете готовое приложение, есть 7capture , который также фиксирует полупрозрачность, поэтому изображения могут быть сохранены в формате PNG для последующего наложения.

EDIT:

Исходный вопрос и комментарии указывают на то, что вы хотите создать регион в Windows Vista / 7, который затем можно будет использовать для маскировки частей захваченного изображения, как это делается в Windows XP и не Aero UI. Использование региона не даст вам искомого результата, поскольку контур окна вычисляется не как регион, а как изображение с переменной прозрачностью - RGBA. Альфа-канал в этом изображении - это ваша маска, но это не маска включения-выключения, как область, а постепенная маска с диапазоном значений от пикселей, которые полностью включены до полной маскировки.

Хотя он использует недокументированные API, код на http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/ будет записан в буфер RGBA, который затем можно использовать для рендеринга или сохранения изображения с сохранением тени и других эффектов полупрозрачности.

В DwmCapture.cs Изменить

BackBufferFormat = Format.X8R8G8B8

до

BackBufferFormat = Format.A8R8G8B8

(X8-> A8)

И тогда вы сможете получить доступ как к обычным данным RGB, так и к прозрачности из захваченного буфера. Затем его можно сохранить в формате PNG или в другом формате с альфа-каналом для компоновки.

1 голос
/ 07 июня 2010

Убрана идея, которая ужасна, но была бы потрясающей в 90-х

Вы говорите, что использование DWM API позволяет вам захватывать только непосредственно на экран ... могли бы вы создать окно вне экрана (скажем, X = -100000px, Y = -100000px), но видимое (возможно, даже скрытое?) И нарисовать скриншот к нему? Поскольку при использовании DWM у каждого окна есть фоновая текстура, я думаю, что он все равно может быть хорошо прорисован, даже если цель не отображается непосредственно на экране.

Кроме того, если вы хотите пойти по пути DirectX и получить доступ к фактической DX-текстуре, поддерживающей окно, я нашел несколько отведений, которые могут помочь (особенно первая ссылка):

0 голосов
/ 03 декабря 2013

Вы можете взглянуть на исходный код AeroShot , как описано на главной странице, он может захватывать закругленные края и с эффектом прозрачности Aero Glass и сохранять его в файл PNG. Это написано на C #.

0 голосов
/ 23 июня 2010
Использование Graphics.CopyFromScreen или какого-либо другого варианта pinvoke этого: это не работает, потому что я не могу предположить, что окно, из которого мне нужна информация, находится вверху z-порядка на экране.1003 *

Если вы знаете, из какого окна вам нужна информация, можете ли вы вывести ее на передний план, вызвать Graphics.CopyFromScreen, а затем сбросить его z-индекс?Из опыта я знаю, что Aero делает странные вещи, когда элементы находятся в фоновом режиме, чтобы заставить их стеклянный интерфейс работать правильно (частичный рендеринг и т. Д.).Это не может быть отличным UX;однако это будет особый случай, который будет использоваться только при включенном Aero.

...