mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-21 16:12:18 -05:00
233 lines
7.5 KiB
C#
233 lines
7.5 KiB
C#
using EDIDParser;
|
|
using EDIDParser.Descriptors;
|
|
using EDIDParser.Enums;
|
|
using NLog;
|
|
using NvAPIWrapper.Display;
|
|
using NvAPIWrapper.GPU;
|
|
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
using static novideo_srgb.Colorimetry;
|
|
|
|
namespace novideo_srgb
|
|
{
|
|
public class MonitorData : INotifyPropertyChanged
|
|
{
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
|
|
private readonly GPUOutput _output;
|
|
private bool _clamped;
|
|
|
|
private MainViewModel _viewModel;
|
|
|
|
public MonitorData(MainViewModel viewModel, int number, Display display, string path, bool hdrActive, bool clampSdr)
|
|
{
|
|
_viewModel = viewModel;
|
|
Number = number;
|
|
_output = display.Output;
|
|
|
|
Edid = Novideo.GetEDID(path, display);
|
|
|
|
Name = Edid.Descriptors.OfType<StringDescriptor>()
|
|
.FirstOrDefault(x => x.Type == StringDescriptorType.MonitorName)?.Value ?? "<no name>";
|
|
|
|
Path = path;
|
|
ClampSdr = clampSdr;
|
|
HdrActive = hdrActive;
|
|
|
|
var coords = Edid.DisplayParameters.ChromaticityCoordinates;
|
|
EdidColorSpace = new Colorimetry.ColorSpace
|
|
{
|
|
Red = new Colorimetry.Point { X = Math.Round(coords.RedX, 3), Y = Math.Round(coords.RedY, 3) },
|
|
Green = new Colorimetry.Point { X = Math.Round(coords.GreenX, 3), Y = Math.Round(coords.GreenY, 3) },
|
|
Blue = new Colorimetry.Point { X = Math.Round(coords.BlueX, 3), Y = Math.Round(coords.BlueY, 3) },
|
|
White = Colorimetry.D65
|
|
};
|
|
|
|
_clamped = Novideo.IsColorSpaceConversionActive(_output);
|
|
|
|
ProfilePath = "";
|
|
CustomGamma = 2.2;
|
|
CustomPercentage = 100;
|
|
}
|
|
|
|
public MonitorData(MainViewModel viewModel, int number, Display display, string path, bool hdrActive, bool clampSdr, bool useIcc, string profilePath,
|
|
bool calibrateGamma,
|
|
int selectedGamma, double customGamma, double customPercentage, int target, bool disableOptimization) :
|
|
this(viewModel, number, display, path, hdrActive, clampSdr)
|
|
{
|
|
UseIcc = useIcc;
|
|
ProfilePath = profilePath;
|
|
CalibrateGamma = calibrateGamma;
|
|
SelectedGamma = selectedGamma;
|
|
CustomGamma = customGamma;
|
|
CustomPercentage = customPercentage;
|
|
Target = target;
|
|
DisableOptimization = disableOptimization;
|
|
}
|
|
|
|
public int Number { get; }
|
|
public string Name { get; }
|
|
public EDID Edid { get; }
|
|
public string Path { get; }
|
|
public bool ClampSdr { get; set; }
|
|
public bool HdrActive { get; }
|
|
|
|
private void UpdateClamp(bool doClamp)
|
|
{
|
|
if (HdrActive)
|
|
{
|
|
_clamped = false;
|
|
return;
|
|
}
|
|
|
|
if (_clamped)
|
|
{
|
|
Novideo.DisableColorSpaceConversion(_output);
|
|
_clamped = Novideo.IsColorSpaceConversionActive(_output);
|
|
}
|
|
|
|
if (!doClamp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_clamped) Thread.Sleep(100);
|
|
if (UseEdid)
|
|
Novideo.SetColorSpaceConversion(_output, Colorimetry.RGBToRGB(TargetColorSpace, EdidColorSpace));
|
|
else if (UseIcc)
|
|
{
|
|
SetICCProfile(ProfilePath, SelectedGamma, TargetColorSpace);
|
|
}
|
|
}
|
|
|
|
private void SetICCProfile(string fileName, int selectedGamma, ColorSpace colorSpace)
|
|
{
|
|
var profile = ICCMatrixProfile.FromFile(fileName);
|
|
if (CalibrateGamma)
|
|
{
|
|
var trcBlack = Matrix.FromValues(new[,]
|
|
{
|
|
{ profile.trcs[0].SampleAt(0) },
|
|
{ profile.trcs[1].SampleAt(0) },
|
|
{ profile.trcs[2].SampleAt(0) }
|
|
});
|
|
var black = (profile.matrix * trcBlack)[1];
|
|
|
|
ToneCurve gamma;
|
|
switch (selectedGamma)
|
|
{
|
|
case 0:
|
|
gamma = new SrgbEOTF(black);
|
|
break;
|
|
case 1:
|
|
gamma = new GammaToneCurve(2.4, black, 0);
|
|
break;
|
|
case 2:
|
|
gamma = new GammaToneCurve(CustomGamma, black, CustomPercentage / 100);
|
|
break;
|
|
case 3:
|
|
gamma = new GammaToneCurve(CustomGamma, black, CustomPercentage / 100, true);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException("Unsupported gamma type " + selectedGamma);
|
|
}
|
|
|
|
Novideo.SetColorSpaceConversion(_output, profile, colorSpace, gamma, DisableOptimization);
|
|
}
|
|
else
|
|
{
|
|
Novideo.SetColorSpaceConversion(_output, profile, colorSpace);
|
|
}
|
|
}
|
|
|
|
private void HandleClampException(Exception e)
|
|
{
|
|
Logger.Error(e);
|
|
|
|
//System.Windows.MessageBox.Show(e.Message);
|
|
_clamped = Novideo.IsColorSpaceConversionActive(_output);
|
|
ClampSdr = _clamped;
|
|
_viewModel.SaveConfig();
|
|
OnPropertyChanged(nameof(Clamped));
|
|
}
|
|
|
|
public bool Clamped
|
|
{
|
|
set
|
|
{
|
|
try
|
|
{
|
|
UpdateClamp(value);
|
|
ClampSdr = value;
|
|
_viewModel.SaveConfig();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
HandleClampException(e);
|
|
return;
|
|
}
|
|
|
|
_clamped = value;
|
|
OnPropertyChanged();
|
|
}
|
|
get => _clamped;
|
|
}
|
|
|
|
public void ReapplyClamp(bool? forceClamp = null)
|
|
{
|
|
try
|
|
{
|
|
if (!ClampSdr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var clamped = CanClamp && ClampSdr && (!forceClamp.HasValue || forceClamp.Value);
|
|
UpdateClamp(clamped);
|
|
_clamped = clamped;
|
|
OnPropertyChanged(nameof(CanClamp));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
HandleClampException(e);
|
|
}
|
|
}
|
|
|
|
public bool CanClamp => !HdrActive && (UseEdid && !EdidColorSpace.Equals(TargetColorSpace) || UseIcc && ProfilePath != "");
|
|
|
|
public string GPU => _output.PhysicalGPU.FullName;
|
|
|
|
public bool UseEdid
|
|
{
|
|
set => UseIcc = !value;
|
|
get => !UseIcc;
|
|
}
|
|
|
|
public bool UseIcc { set; get; }
|
|
|
|
public string ProfilePath { set; get; }
|
|
|
|
public bool CalibrateGamma { set; get; }
|
|
|
|
public int SelectedGamma { set; get; }
|
|
|
|
public double CustomGamma { set; get; }
|
|
|
|
public double CustomPercentage { set; get; }
|
|
|
|
public bool DisableOptimization { set; get; }
|
|
|
|
public int Target { set; get; }
|
|
|
|
public Colorimetry.ColorSpace EdidColorSpace { get; }
|
|
|
|
private Colorimetry.ColorSpace TargetColorSpace => Colorimetry.ColorSpaces[Target];
|
|
|
|
private void OnPropertyChanged([CallerMemberName] string? name = null)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
|
}
|
|
}
|
|
} |