C#

[WPF] 모니터 밝기 및 감마 조절

Dongmin Jang 2021. 1. 27. 15:42

GDI의 SetDeviceGammaRamp를 이용해 모니터 밝기 및 감마 조절이 가능한 기능 구현

 

참고한 사이트:

florisdriessen.nl/programming/c-sharp-how-to-change-the-color-gamma-and-brightness/

www.digipine.com/index.php?mid=windowsmfc&document_srl=631

www.pinvoke.net/default.aspx/gdi32.setdevicegammaramp

 

 

WPF로 만든 모니터 밝기 및 감마 조절

// BrightnessWindow.xaml

<Window x:Class="Brightness.BrightnessWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Brightness"
        mc:Ignorable="d"
        Title="BrightnessWindow" Height="112.079" Width="492.416">
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="35"/>
                <ColumnDefinition Width="2*"/>
                <ColumnDefinition Width="60"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Row="0" Grid.Column="0" Content="Brightness" HorizontalAlignment="Center" VerticalAlignment="Center" Height="26"/>
            <TextBlock Grid.Row="0" Grid.Column="1" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding ElementName=sliderBrightness, Path=Value}" Width="40"/>
            <Slider Grid.Row="0" Grid.Column="2" x:Name="sliderBrightness" HorizontalAlignment="Center" VerticalAlignment="Center" Width="300" Minimum="5" Maximum="100" SmallChange="1" LargeChange="10" TickFrequency="1" IsSnapToTickEnabled="True" Value="50"/>
            <Button Grid.Row="0" Grid.Column="3" Content="적용" HorizontalAlignment="Center" VerticalAlignment="Center" Width="43" Click="ButtonApply_Clicked"/>
            <Label Grid.Row="1" Grid.Column="0" Content="Gamma" HorizontalAlignment="Center" VerticalAlignment="Center" Height="26"/>
            <TextBlock Grid.Row="1" Grid.Column="1" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding ElementName=sliderGamma, Path=Value}" Width="40"/>
            <Slider Grid.Row="1" Grid.Column="2" x:Name="sliderGamma" HorizontalAlignment="Center" VerticalAlignment="Center" Width="300" Minimum="5" Maximum="100" SmallChange="1" LargeChange="10" TickFrequency="1" IsSnapToTickEnabled="True" Value="50"/>
            <Button Grid.Row="1" Grid.Column="3" Content="취소" HorizontalAlignment="Center" VerticalAlignment="Center" Width="43" Click="ButtonCancel_Clicked"/>
        </Grid>
    </Grid>
</Window>
// BrightnessWindow.xaml.cs

using System.Windows;

namespace Brightness
{
    public partial class BrightnessWindow : Window
    {
        private DisplayRamp displayRamp;

        public BrightnessWindow()
        {
            InitializeComponent();

            displayRamp = new DisplayRamp();
            sliderBrightness.ValueChanged += this.SliderBrightness_ValueChanged;
            sliderGamma.ValueChanged += this.SliderGamma_ValueChanged;
        }

        private void SliderBrightness_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            displayRamp.SetBrightness(sliderBrightness.Value);
        }

        private void SliderGamma_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            displayRamp.SetGamma(sliderGamma.Value);
        }

        private void ButtonApply_Clicked(object sender, RoutedEventArgs e)
        {
            displayRamp.SetBrightness(sliderBrightness.Value);
            displayRamp.SetGamma(sliderGamma.Value);
            this.Close();
        }

        private void ButtonCancel_Clicked(object sender, RoutedEventArgs e)
        {
            displayRamp.UpdateRamps(true);
            this.Close();
        }
    }
}

 

// DisplayRamp.cs

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Brightness
{
    public sealed class DisplayRamp : IDisposable
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct RAMP
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Red;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Green;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Blue;
        }

        private double _brightness = 1;
        private double _gamma = 1;
        private IntPtr _hdc;
        private Screen _screen;
        private RAMP _oldRamps;

        public double Brightness { get => _brightness; set => _brightness = value; }
        public double Gamma { get => _gamma; set => _gamma = value; }
        public IntPtr Hdc { get => _hdc; set => _hdc = value; }
        public Screen Screen { get => _screen; set => _screen = value; }
        public RAMP OldRamps { get => _oldRamps; set => _oldRamps = value; }

        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleDC(IntPtr hDC);
        [DllImport("gdi32.dll")]
        private static extern bool DeleteDC(IntPtr hDC);
        [DllImport("gdi32.dll")]
        private static extern bool SetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);
        [DllImport("gdi32.dll")]
        private static extern bool GetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);

        public DisplayRamp()
        {
            IntPtr screenDc = CreateDC(System.Windows.Forms.Screen.PrimaryScreen.DeviceName, "", "", IntPtr.Zero);
            Hdc = CreateCompatibleDC(screenDc);

            RAMP ramp = new RAMP
            {
                Red = new ushort[256],
                Green = new ushort[256],
                Blue = new ushort[256]
            };
            bool bReturn = GetDeviceGammaRamp(Hdc, ref ramp);
            OldRamps = ramp;
        }

        public bool SetBrightness(double brightness)
        {
            Brightness = brightness / 50f;
            return UpdateRamps();
        }

        public bool SetGamma(double gamma)
        {
            Gamma = gamma / 50f;
            return UpdateRamps();
        }

        public bool UpdateRamps(bool bUseOldRamp = false)
        {
            RAMP ramp;
            if (true == bUseOldRamp)
            {
                ramp = OldRamps;
            }
            else
            {
                ramp = new RAMP
                {
                    Red = new ushort[256],
                    Green = new ushort[256],
                    Blue = new ushort[256]
                };

                for (int iIndex = 0; iIndex < 256; iIndex++)
                {
                    ushort arrayValue = (ushort)Math.Min(65535, Math.Round(Math.Max(0, (Math.Pow(iIndex / 256.0f, 1 / Gamma) * 65535 + 0.5) * Brightness)));
                    ramp.Red[iIndex] = ramp.Green[iIndex] = ramp.Blue[iIndex] = arrayValue;
                }
            }
                
            return SetDeviceGammaRamp(Hdc, ref ramp);
        }

        public void Dispose()
        {
            DeleteDC(Hdc);
        }
    }
}