Night Vision Mode on WPF Windows

后端 未结 2 621
孤街浪徒
孤街浪徒 2021-01-01 04:46

We\'ve made a WPF application with a traditional UI (common controls like tabs, buttons, labels, textboxes, and so on).

We need to add a \"night vision\" mode, which

2条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-01 05:41

    Alternatively, consider just using the DWM Magnification functionality to make all of windows go into "Night-Mode".

    Example:

    See the Magnification API sample, with modifications below:

    /*************************************************************************************************
    *
    * File: FullscreenMagnifierSample.cpp
    *
    * Description: Implements simple UI to control fullscreen magnification, using the 
    * Magnification API.
    *
    *  Copyright (C) Microsoft Corporation.  All rights reserved.
    * 
    * This source code is intended only as a supplement to Microsoft
    * Development Tools and/or on-line documentation.  See these other
    * materials for detailed information regarding Microsoft code samples.
    * 
    * THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
    * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
    * PARTICULAR PURPOSE.
    * 
    *************************************************************************************************/
    
    #include "windows.h"
    #include "resource.h"
    #include "strsafe.h"
    #include "magnification.h"
    
    // Global variables and strings.
    const LPWSTR g_pszAppTitle = L"Night Colors";
    
    // Initialize color effect matrices to apply grayscale or restore the colors on the desktop.
    MAGCOLOREFFECT g_MagEffectIdentity = { 
        1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
    MAGCOLOREFFECT g_MagEffectWashout = {
        0.5f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.3f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.3f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
    
    MAGCOLOREFFECT g_MagEffectWashout2 = {
        0.35f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.2f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.2f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
    
    MAGCOLOREFFECT g_MagEffectWashout3 = {
        0.25f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.13f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.13f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
    
    /*MAGCOLOREFFECT g_MagEffectGrayscale = {0.3f,  0.3f,  0.3f,  0.0f,  0.0f,
                                           0.6f,  0.6f,  0.6f,  0.0f,  0.0f,
                                           0.1f,  0.1f,  0.1f,  0.0f,  0.0f,
                                           0.0f,  0.0f,  0.0f,  1.0f,  0.0f,
                                           0.0f,  0.0f,  0.0f,  0.0f,  1.0f};*/
    
    MAGCOLOREFFECT g_MagEffectGrayscaleInverted = { 
        -0.3f, 0.0f, 0.0f, 0.0f, 0.0f,
        -0.6f, 0.0f, 0.0f, 0.0f, 0.0f,
        -0.1f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        1.0f, 0.0f, 0.0f, 0.0f, 1.0f };
    
    MAGCOLOREFFECT g_MagEffectInverted = { 
        -1.0f,  0.0f,  0.0f, 0.0f, 0.0f,
         0.0f, -1.0f,  0.0f, 0.0f, 0.0f,
         0.0f,  0.0f, -1.0f, 0.0f, 0.0f,
         0.0f,  0.0f,  0.0f, 1.0f, 0.0f,
         1.0f,  1.0f,  1.0f, 0.0f, 1.0f 
    };
    
    MAGCOLOREFFECT g_MagEffectGrayscale = {0.3f,  0.0f,  0.0f,  0.0f,  0.0f,
                                           0.6f,  0.0f,  0.0f,  0.0f,  0.0f,
                                           0.1f,  0.0f,  0.0f,  0.0f,  0.0f,
                                           0.0f,  0.0f,  0.0f,  1.0f,  0.0f,
                                           0.0f,  0.0f,  0.0f,  0.0f,  1.0f};
    
    // Forward declarations.
    INT_PTR CALLBACK SampleDialogProc(_In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam);
    void InitDlg(_In_ HWND hwndDlg);
    void HandleCommand(_In_ HWND hwndDlg, _In_ WORD wCtrlId);
    
    //
    // FUNCTION: WinMain()
    //
    // PURPOSE: Entry point for the application.
    //
    int APIENTRY WinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE /*hPrevInstance*/,
                         _In_ LPSTR     /*lpCmdLine*/,
                         _In_ int       /*nCmdShow*/)
    {
        // Initialize the magnification functionality for this process.
        if (MagInitialize())
        {
            // Present a dialog box to allow the user to control fullscreen magnification.
            DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_FULLSCREENMAGNIFICATIONCONTROL), NULL, SampleDialogProc);
    
            // Any current magnification and color effects will be turned off as a result of calling MagUninitialize().
            MagUninitialize();
        }
        else
        {
            MessageBox(NULL, L"Failed to initialize magnification.", g_pszAppTitle, MB_OK);
        }
    
        return 0;
    }
    
    //
    // FUNCTION: SampleDialogProc()
    //
    // PURPOSE: Dialog proc for the UI used for controlling fullscreen magnification.
    //
    INT_PTR CALLBACK SampleDialogProc(
      _In_  HWND   hwndDlg,
      _In_  UINT   uMsg,
      _In_  WPARAM wParam,
      _In_  LPARAM /*lParam*/
    )
    {
        INT_PTR ipRet = 0;
    
        switch (uMsg)
        {
        case WM_INITDIALOG:
    
            InitDlg(hwndDlg);
    
            ipRet = 0;
    
            break;
    
        case WM_COMMAND:
    
            if(HIWORD(wParam) == BN_CLICKED)
            {
                WORD wCtrlId = LOWORD(wParam);
    
                HandleCommand(hwndDlg, wCtrlId);
    
                ipRet = 1;
            }
    
            break;
    
        case WM_CLOSE:
    
            EndDialog(hwndDlg, 0);
    
            break;
        }
    
        return ipRet;
    }
    
    //
    // FUNCTION: InitDlg()
    //
    // PURPOSE: Initialize the sample dialog box's position and controls.
    //
    void InitDlg(_In_ HWND hwndDlg)
    {
        // Position the dialog box in the center of the primary monitor.
        RECT rcDlg;
        GetWindowRect(hwndDlg, &rcDlg);
    
        int xDlg = (GetSystemMetrics(SM_CXSCREEN) - (rcDlg.right - rcDlg.left)) / 2;
        int yDlg = (GetSystemMetrics(SM_CYSCREEN) - (rcDlg.bottom - rcDlg.top)) / 2;
    
        SetWindowPos(hwndDlg, NULL, xDlg, yDlg, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
    
        // Set the default color and invalidate the status
        DWORD defaultColor = IDC_CHECK_SETRED_INVERTED;
        HWND hwndControl = GetDlgItem(hwndDlg, defaultColor);
        SendMessage(hwndControl, BM_SETCHECK, BST_CHECKED, 0);
        HandleCommand(hwndDlg, defaultColor);
        SetFocus(hwndControl);
    }        
    
    //
    // FUNCTION: HandleCommand()
    //
    // PURPOSE: Take action in response to user action at the dialog box's controls.
    //
    void HandleCommand(_In_ HWND hwndDlg, _In_ WORD wCtrlId)
    {
        switch (wCtrlId)
        {
            case IDC_CHECK_SETRED:
                {
                    if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SETRED))
                    {
                        MagSetFullscreenColorEffect(&g_MagEffectGrayscale);
                    }
                }
                break;
            case IDC_CHECK_SETRED_INVERTED:
                {
                    if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SETRED_INVERTED))
                    {
                        MagSetFullscreenColorEffect(&g_MagEffectGrayscaleInverted);
                    }
                }
                break;
            case IDC_CHECK_SET_INVERTED:
                {
                    if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_INVERTED))
                    {
                        MagSetFullscreenColorEffect(&g_MagEffectInverted);
                    }
                }
                break;
            case IDC_CHECK_SET_WASHOUT:
            {
                if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_WASHOUT))
                {
                    MagSetFullscreenColorEffect(&g_MagEffectWashout);
                }
            }
            break;
            case IDC_CHECK_SET_WASHOUT2:
            {
                if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_WASHOUT2))
                {
                    MagSetFullscreenColorEffect(&g_MagEffectWashout2);
                }
            }
            break;
            case IDC_CHECK_SET_WASHOUT3:
            {
                if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_WASHOUT3))
                {
                    MagSetFullscreenColorEffect(&g_MagEffectWashout3);
                }
            }
            break;
        }
    }
    

    Window Specific

    You can also do this on a window by window basis by compiling a HLSL shader and setting it as an effect upon the window. This technique also works if you need to vary the intensity.

    /// 
    /// Interaction logic for MainWindow.xaml
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            this.img.Source = new BitmapImage(new Uri("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"));
            this.Effect = new ColorComplementEffect();
        }
    }
    
    public class ColorComplementEffect : ShaderEffect
    {
        public ColorComplementEffect()
        {
            PixelShader = _shader;
            UpdateShaderValue(InputProperty);
        }
    
        public Brush Input
        {
            get { return (Brush)GetValue(InputProperty); }
            set { SetValue(InputProperty, value); }
        }
    
        public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(ColorComplementEffect), 0);
        private static PixelShader _shader = new PixelShader() { UriSource = new Uri(@"cc.ps") };
    }
    

    Shader:

    sampler2D implicitInput : register(s0);
    
    float4 main(float2 uv : TEXCOORD) : COLOR
    {
        float4 color = tex2D(implicitInput, uv);
    
        float4 complement;
        complement.r = (color.a - color.r) * 0.2;
        complement.g = (color.a - color.g) * 0.2;
        complement.b = (color.a - color.b) * 0.2;
        complement.a = color.a;
    
        return complement;
    }
    

提交回复
热议问题