mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-21 16:12:18 -05:00
add Nvidia digital vibrance/hue control, add creation of custom color profile, add support for LG A2/A3 service menu unlocker
This commit is contained in:
1 parent
6b3b0b4b17
commit
5611c1bea7
57 files changed
+5277
-153
No files matched your search
@@ -15,6 +15,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NLogViewer", "NLogViewer\NL
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LittleCms", "LittleCms\LittleCms.csproj", "{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MHC2Gen", "MHC2Gen\MHC2Gen.csproj", "{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -71,6 +75,22 @@ Global
|
||||
{8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|x64.Build.0 = Debug|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|x64.ActiveCfg = Release|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<PublisherName>Maassoft</PublisherName>
|
||||
<Company>Maassoft</Company>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>9.7.2.0</ApplicationVersion>
|
||||
<Version>9.7.2.0</Version>
|
||||
<ApplicationVersion>9.8.0.0</ApplicationVersion>
|
||||
<Version>9.8.0.0</Version>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||
<BootstrapperEnabled>false</BootstrapperEnabled>
|
||||
@@ -29,7 +29,7 @@
|
||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||
<ApplicationIcon>pngbarn.ico</ApplicationIcon>
|
||||
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
|
||||
<Copyright>2020-2023 Maassoft</Copyright>
|
||||
<Copyright>2020-2024 Maassoft</Copyright>
|
||||
<Authors>Maassoft</Authors>
|
||||
<ManifestCertificateThumbprint>CF0BC153EA664CD97AC6F234B91F45D34630958F</ManifestCertificateThumbprint>
|
||||
<ManifestKeyFile>ColorControl_1_TemporaryKey.pfx</ManifestKeyFile>
|
||||
@@ -52,6 +52,7 @@
|
||||
<PathMap Condition="'$(Configuration)' == 'Release'">$(MSBuildThisFileDirectory)=.\</PathMap>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="XForms\ColorProfileWindow.xaml" />
|
||||
<None Remove="XForms\LogWindow.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -113,11 +114,16 @@
|
||||
<PackageReference Include="RawInput.Sharp" Version="0.1.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="XForms\ColorProfileWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="XForms\LogWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MHC2Gen\MHC2Gen.csproj" />
|
||||
<ProjectReference Include="..\NLogViewer\NLogViewer.csproj" />
|
||||
<ProjectReference Include="..\novideo_srgb\novideo_srgb.csproj" />
|
||||
<ProjectReference Include="..\Nspector\Nspector.csproj" />
|
||||
|
||||
@@ -8,15 +8,12 @@ namespace ColorControl.Forms
|
||||
public partial class InfoPanel : UserControl
|
||||
{
|
||||
private readonly WinApiService _winApiService;
|
||||
private bool _initialized;
|
||||
|
||||
public InfoPanel(WinApiService winApiService)
|
||||
{
|
||||
_winApiService = winApiService;
|
||||
InitializeComponent();
|
||||
|
||||
_initialized = true;
|
||||
|
||||
if (DarkModeUtils.UseDarkMode)
|
||||
{
|
||||
grpInfo.ForeColor = FormUtils.CurrentForeColor;
|
||||
@@ -29,14 +26,14 @@ namespace ColorControl.Forms
|
||||
{
|
||||
var currentVersionInfo = FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
|
||||
|
||||
Text = Application.ProductName + " " + Application.ProductVersion;
|
||||
var text = Application.ProductName + " " + Application.ProductVersion;
|
||||
|
||||
if (_winApiService.IsAdministrator())
|
||||
{
|
||||
Text += " (administrator)";
|
||||
text += " (administrator)";
|
||||
}
|
||||
|
||||
lblInfo.Text = Text + " - " + currentVersionInfo.LegalCopyright;
|
||||
lblInfo.Text = text + " - " + currentVersionInfo.LegalCopyright;
|
||||
|
||||
lbPlugins.Items.Add("lgtv.net by gr4b4z");
|
||||
lbPlugins.Items.Add("Newtonsoft.Json by James Newton-King");
|
||||
@@ -49,7 +46,8 @@ namespace ColorControl.Forms
|
||||
lbPlugins.Items.Add("Novideo sRGB by ledoge");
|
||||
lbPlugins.Items.Add("NLogViewer by dojo90");
|
||||
lbPlugins.Items.Add("WPFDarkTheme by AngryCarrot789");
|
||||
|
||||
lbPlugins.Items.Add("Little-CMS by mm2");
|
||||
lbPlugins.Items.Add("MHC2 by dantmnf");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Generated
+35
@@ -28,6 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
tcMain = new System.Windows.Forms.TabControl();
|
||||
tabOptions = new System.Windows.Forms.TabPage();
|
||||
@@ -35,6 +36,7 @@
|
||||
label1 = new System.Windows.Forms.Label();
|
||||
chkModules = new System.Windows.Forms.CheckedListBox();
|
||||
grpMiscellaneousOptions = new System.Windows.Forms.GroupBox();
|
||||
btnOptionsColorProfiles = new System.Windows.Forms.Button();
|
||||
btnSetShortcutScreenSaver = new System.Windows.Forms.Button();
|
||||
label11 = new System.Windows.Forms.Label();
|
||||
edtBlankScreenSaverShortcut = new System.Windows.Forms.TextBox();
|
||||
@@ -60,11 +62,14 @@
|
||||
chkStartAfterLogin = new System.Windows.Forms.CheckBox();
|
||||
tabInfo = new System.Windows.Forms.TabPage();
|
||||
btnUpdate = new System.Windows.Forms.Button();
|
||||
mnuColorProfiles = new System.Windows.Forms.ContextMenuStrip(components);
|
||||
miCreateHDRColorProfile = new System.Windows.Forms.ToolStripMenuItem();
|
||||
tcMain.SuspendLayout();
|
||||
tabOptions.SuspendLayout();
|
||||
grpOptionsModules.SuspendLayout();
|
||||
grpMiscellaneousOptions.SuspendLayout();
|
||||
grpGeneralOptions.SuspendLayout();
|
||||
mnuColorProfiles.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tcMain
|
||||
@@ -130,6 +135,7 @@
|
||||
//
|
||||
// grpMiscellaneousOptions
|
||||
//
|
||||
grpMiscellaneousOptions.Controls.Add(btnOptionsColorProfiles);
|
||||
grpMiscellaneousOptions.Controls.Add(btnSetShortcutScreenSaver);
|
||||
grpMiscellaneousOptions.Controls.Add(label11);
|
||||
grpMiscellaneousOptions.Controls.Add(edtBlankScreenSaverShortcut);
|
||||
@@ -144,6 +150,17 @@
|
||||
grpMiscellaneousOptions.TabStop = false;
|
||||
grpMiscellaneousOptions.Text = "Miscellaneous";
|
||||
//
|
||||
// btnOptionsColorProfiles
|
||||
//
|
||||
btnOptionsColorProfiles.Location = new System.Drawing.Point(538, 17);
|
||||
btnOptionsColorProfiles.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
btnOptionsColorProfiles.Name = "btnOptionsColorProfiles";
|
||||
btnOptionsColorProfiles.Size = new System.Drawing.Size(112, 27);
|
||||
btnOptionsColorProfiles.TabIndex = 12;
|
||||
btnOptionsColorProfiles.Text = "Color Profiles...";
|
||||
btnOptionsColorProfiles.UseVisualStyleBackColor = true;
|
||||
btnOptionsColorProfiles.Click += btnOptionsColorProfiles_Click;
|
||||
//
|
||||
// btnSetShortcutScreenSaver
|
||||
//
|
||||
btnSetShortcutScreenSaver.Location = new System.Drawing.Point(181, 98);
|
||||
@@ -455,6 +472,20 @@
|
||||
btnUpdate.Visible = false;
|
||||
btnUpdate.Click += btnUpdate_Click;
|
||||
//
|
||||
// mnuColorProfiles
|
||||
//
|
||||
mnuColorProfiles.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
mnuColorProfiles.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miCreateHDRColorProfile });
|
||||
mnuColorProfiles.Name = "mnuLgButtons";
|
||||
mnuColorProfiles.Size = new System.Drawing.Size(214, 26);
|
||||
//
|
||||
// miCreateHDRColorProfile
|
||||
//
|
||||
miCreateHDRColorProfile.Name = "miCreateHDRColorProfile";
|
||||
miCreateHDRColorProfile.Size = new System.Drawing.Size(213, 22);
|
||||
miCreateHDRColorProfile.Text = "Create HDR Color Profile...";
|
||||
miCreateHDRColorProfile.Click += miCreateHDRColorProfile_Click;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
@@ -486,6 +517,7 @@
|
||||
grpMiscellaneousOptions.PerformLayout();
|
||||
grpGeneralOptions.ResumeLayout(false);
|
||||
grpGeneralOptions.PerformLayout();
|
||||
mnuColorProfiles.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
@@ -522,6 +554,9 @@
|
||||
private System.Windows.Forms.CheckBox chkOptionsUseDarkMode;
|
||||
private System.Windows.Forms.Button btnOptionsAdvanced;
|
||||
private System.Windows.Forms.Button btnOptionsLog;
|
||||
private System.Windows.Forms.Button btnOptionsColorProfiles;
|
||||
private System.Windows.Forms.ContextMenuStrip mnuColorProfiles;
|
||||
private System.Windows.Forms.ToolStripMenuItem miCreateHDRColorProfile;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ namespace ColorControl
|
||||
|
||||
private AmdPanel _amdPanel;
|
||||
private bool _skipResize;
|
||||
private FileVersionInfo _currentVersionInfo;
|
||||
private bool _checkedForUpdates = false;
|
||||
private string _updateHtmlUrl;
|
||||
private string _downloadUrl;
|
||||
@@ -96,6 +95,15 @@ namespace ColorControl
|
||||
_dataDir = Program.DataDir;
|
||||
_config = Program.Config;
|
||||
|
||||
var currentVersionInfo = FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
|
||||
|
||||
Text = Application.ProductName + " " + Application.ProductVersion;
|
||||
|
||||
if (_winApiService.IsAdministrator())
|
||||
{
|
||||
Text += " (administrator)";
|
||||
}
|
||||
|
||||
LoadConfig();
|
||||
|
||||
KeyboardShortcutManager.SetUseRawInput(_config.UseRawInput);
|
||||
@@ -1423,5 +1431,15 @@ Currently ColorControl is {(_winApiService.IsAdministrator() ? "" : "not ")}runn
|
||||
var module = _config.Modules[index];
|
||||
module.IsActive = e.NewValue == CheckState.Checked;
|
||||
}
|
||||
|
||||
private void miCreateHDRColorProfile_Click(object sender, EventArgs e)
|
||||
{
|
||||
ColorProfileWindow.CreateAndShow();
|
||||
}
|
||||
|
||||
private void btnOptionsColorProfiles_Click(object sender, EventArgs e)
|
||||
{
|
||||
mnuColorProfiles.ShowCustom(btnOptionsColorProfiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,9 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="mnuColorProfiles.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>147, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
@@ -256,6 +256,7 @@ namespace ColorControl
|
||||
services.AddSingleton<MainForm>();
|
||||
services.AddSingleton<ElevatedForm>();
|
||||
services.AddSingleton<LogWindow>();
|
||||
services.AddTransient<ColorProfileWindow>();
|
||||
services.AddSingleton<RestartDetector>();
|
||||
services.AddSingleton<InfoPanel>();
|
||||
});
|
||||
|
||||
@@ -77,7 +77,14 @@ namespace ColorControl.Services.GameLauncher
|
||||
|
||||
if (_winApiService.IsAdministrator())
|
||||
{
|
||||
var fileName = process.MainModule.FileName;
|
||||
var mainModule = process.MainModule;
|
||||
|
||||
if (mainModule == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fileName = mainModule.FileName;
|
||||
|
||||
preset = _presets.FirstOrDefault(p => fileName.Contains(Path.GetDirectoryName(p.Path), System.StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
@@ -829,7 +829,7 @@ Do you want to continue?"
|
||||
mnuLgOLEDMotionPro.Visible = visible;
|
||||
miLgEnableMotionPro.Visible = enableVisible;
|
||||
|
||||
var svcMenuFlagVisible = new[] { "B2", "C2", "G2", "B3", "C3", "G3" }.Any(m => device?.ModelName?.Contains(m) == true);
|
||||
var svcMenuFlagVisible = new[] { "A2", "B2", "C2", "G2", "A3", "B3", "C3", "G3" }.Any(m => device?.ModelName?.Contains(m) == true);
|
||||
|
||||
mnuLgSetSvcMenuFlag.Visible = svcMenuFlagVisible;
|
||||
|
||||
|
||||
+23
-5
@@ -57,6 +57,8 @@ namespace ColorControl.Services.NVIDIA
|
||||
miNvPrimaryDisplay = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNvPresetsColorSettings = new System.Windows.Forms.ToolStripMenuItem();
|
||||
miNvPresetColorSettings = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNvPresetsColorEnhancements = new System.Windows.Forms.ToolStripMenuItem();
|
||||
miNvPresetColorEnhancementsIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuRefreshRate = new System.Windows.Forms.ToolStripMenuItem();
|
||||
miRefreshRateIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNvResolution = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -94,8 +96,8 @@ namespace ColorControl.Services.NVIDIA
|
||||
miNvNovideo = new System.Windows.Forms.ToolStripMenuItem();
|
||||
miNvSettings = new System.Windows.Forms.ToolStripMenuItem();
|
||||
miNvTestDithering = new System.Windows.Forms.ToolStripMenuItem();
|
||||
lvNvPresetsToolTip = new System.Windows.Forms.ToolTip(components);
|
||||
miNVIDIAInfo = new System.Windows.Forms.ToolStripMenuItem();
|
||||
lvNvPresetsToolTip = new System.Windows.Forms.ToolTip(components);
|
||||
mnuNvPresets.SuspendLayout();
|
||||
mnuNvSettings.SuspendLayout();
|
||||
SuspendLayout();
|
||||
@@ -326,9 +328,9 @@ namespace ColorControl.Services.NVIDIA
|
||||
// mnuNvPresets
|
||||
//
|
||||
mnuNvPresets.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
mnuNvPresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvApply, miNvPresetApplyOnStartup, tssNvPresetMenu, mnuNvDisplay, mnuNvPresetsColorSettings, mnuRefreshRate, mnuNvResolution, miNvPresetDithering, miNvHDR, mnuNvDriverSettings, mnuNvOtherSettings, mnuNvHdmiSettings, mnuNvOverclocking, miNvCopyId });
|
||||
mnuNvPresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvApply, miNvPresetApplyOnStartup, tssNvPresetMenu, mnuNvDisplay, mnuNvPresetsColorSettings, mnuNvPresetsColorEnhancements, mnuRefreshRate, mnuNvResolution, miNvPresetDithering, miNvHDR, mnuNvDriverSettings, mnuNvOtherSettings, mnuNvHdmiSettings, mnuNvOverclocking, miNvCopyId });
|
||||
mnuNvPresets.Name = "mnuNvPresets";
|
||||
mnuNvPresets.Size = new System.Drawing.Size(185, 296);
|
||||
mnuNvPresets.Size = new System.Drawing.Size(185, 340);
|
||||
mnuNvPresets.Opening += mnuNvPresets_Opening;
|
||||
//
|
||||
// miNvApply
|
||||
@@ -375,10 +377,24 @@ namespace ColorControl.Services.NVIDIA
|
||||
// miNvPresetColorSettings
|
||||
//
|
||||
miNvPresetColorSettings.Name = "miNvPresetColorSettings";
|
||||
miNvPresetColorSettings.Size = new System.Drawing.Size(120, 22);
|
||||
miNvPresetColorSettings.Size = new System.Drawing.Size(180, 22);
|
||||
miNvPresetColorSettings.Text = "Included";
|
||||
miNvPresetColorSettings.Click += miNvPresetColorSettings_Click;
|
||||
//
|
||||
// mnuNvPresetsColorEnhancements
|
||||
//
|
||||
mnuNvPresetsColorEnhancements.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvPresetColorEnhancementsIncluded });
|
||||
mnuNvPresetsColorEnhancements.Name = "mnuNvPresetsColorEnhancements";
|
||||
mnuNvPresetsColorEnhancements.Size = new System.Drawing.Size(184, 22);
|
||||
mnuNvPresetsColorEnhancements.Text = "Color Enhancements";
|
||||
//
|
||||
// miNvPresetColorEnhancementsIncluded
|
||||
//
|
||||
miNvPresetColorEnhancementsIncluded.Name = "miNvPresetColorEnhancementsIncluded";
|
||||
miNvPresetColorEnhancementsIncluded.Size = new System.Drawing.Size(180, 22);
|
||||
miNvPresetColorEnhancementsIncluded.Text = "Included";
|
||||
miNvPresetColorEnhancementsIncluded.Click += miNvPresetColorEnhancementsIncluded_Click;
|
||||
//
|
||||
// mnuRefreshRate
|
||||
//
|
||||
mnuRefreshRate.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { miRefreshRateIncluded });
|
||||
@@ -638,7 +654,7 @@ namespace ColorControl.Services.NVIDIA
|
||||
mnuNvSettings.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
mnuNvSettings.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvProfileInspector, miNvNovideo, miNvSettings, miNvTestDithering, miNVIDIAInfo });
|
||||
mnuNvSettings.Name = "mnuLgButtons";
|
||||
mnuNvSettings.Size = new System.Drawing.Size(202, 136);
|
||||
mnuNvSettings.Size = new System.Drawing.Size(202, 114);
|
||||
//
|
||||
// miNvProfileInspector
|
||||
//
|
||||
@@ -778,5 +794,7 @@ namespace ColorControl.Services.NVIDIA
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvHdmiIncluded;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvTestDithering;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNVIDIAInfo;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNvPresetsColorEnhancements;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvPresetColorEnhancementsIncluded;
|
||||
}
|
||||
}
|
||||
@@ -337,6 +337,8 @@ namespace ColorControl.Services.NVIDIA
|
||||
mnuNvDisplay.Visible = presetItemsVisible;
|
||||
miNvPresetColorSettings.Enabled = presetItemsVisible;
|
||||
mnuNvPresetsColorSettings.Enabled = preset != null;
|
||||
miNvPresetColorEnhancementsIncluded.Enabled = presetItemsVisible;
|
||||
mnuNvPresetsColorEnhancements.Enabled = preset != null;
|
||||
mnuRefreshRate.Enabled = preset != null;
|
||||
mnuNvResolution.Enabled = preset != null;
|
||||
miNvPresetDithering.Enabled = preset != null;
|
||||
@@ -363,6 +365,7 @@ namespace ColorControl.Services.NVIDIA
|
||||
|
||||
miNvPresetApplyDithering.Visible = !isCurrentDisplay;
|
||||
miNvPresetColorSettings.Visible = !isCurrentDisplay;
|
||||
miNvPresetColorEnhancementsIncluded.Visible = !isCurrentDisplay;
|
||||
miNvResolutionIncluded.Visible = !isCurrentDisplay;
|
||||
miRefreshRateIncluded.Visible = !isCurrentDisplay;
|
||||
miHDRIncluded.Visible = !isCurrentDisplay;
|
||||
@@ -422,8 +425,10 @@ namespace ColorControl.Services.NVIDIA
|
||||
miNvOtherIncluded.Checked = preset.applyOther;
|
||||
miNvHdmiIncluded.Checked = preset.applyHdmiSettings;
|
||||
miNvDriverSettingsIncluded.Checked = preset.applyDriverSettings;
|
||||
miNvPresetColorEnhancementsIncluded.Checked = preset.ApplyColorEnhancements;
|
||||
|
||||
mnuNvPresetsColorSettings.Font = _menuItemFonts[preset.applyColorData];
|
||||
mnuNvPresetsColorEnhancements.Font = _menuItemFonts[preset.ApplyColorEnhancements];
|
||||
mnuRefreshRate.Font = _menuItemFonts[preset.applyRefreshRate];
|
||||
mnuNvResolution.Font = _menuItemFonts[preset.applyResolution];
|
||||
miNvPresetDithering.Font = _menuItemFonts[preset.applyDithering];
|
||||
@@ -432,22 +437,19 @@ namespace ColorControl.Services.NVIDIA
|
||||
mnuNvOtherSettings.Font = _menuItemFonts[preset.applyOther];
|
||||
mnuNvHdmiSettings.Font = _menuItemFonts[preset.applyHdmiSettings];
|
||||
|
||||
var itemName = $"{mnuNvOtherSettings.Name}_SDRBrightness";
|
||||
var brightnessMenu = FormUtils.BuildMenuItem(mnuNvOtherSettings.DropDownItems, itemName, "SDR brightness");
|
||||
FormUtils.BuildMenuItemAndSub(mnuNvPresetsColorEnhancements, "Digital Vibrance",
|
||||
$"{preset.ColorEnhancementSettings.DigitalVibranceLevel}% (click to change)", nvPresetDvcMenuItem_Click);
|
||||
FormUtils.BuildMenuItemAndSub(mnuNvPresetsColorEnhancements, "Hue",
|
||||
$"{preset.ColorEnhancementSettings.HueAngle}° (click to change)", nvPresetHueMenuItem_Click);
|
||||
|
||||
var subItemName = $"{itemName}_SubItem";
|
||||
var subItem = FormUtils.BuildMenuItem(brightnessMenu.DropDownItems, subItemName, "", onClick: nvPresetBrightnessMenuItem_Click);
|
||||
subItem.Text = (preset.SDRBrightness.HasValue ? $"{preset.SDRBrightness.Value}%" : "Unset") + " (click to change)";
|
||||
FormUtils.BuildMenuItemAndSub(mnuNvOtherSettings, "SDR brightness",
|
||||
(preset.SDRBrightness.HasValue ? $"{preset.SDRBrightness.Value}%" : "Unset") + " (click to change)", nvPresetBrightnessMenuItem_Click);
|
||||
|
||||
FormUtils.BuildDropDownMenu(mnuNvOtherSettings, "Scaling", typeof(Scaling), preset, "scaling", nvPresetScalingMenuItem_Click, unchanged: true, skipValues: new object[] { Scaling.Customized })
|
||||
.DropDownItems[0].Visible = !isCurrentDisplay;
|
||||
|
||||
var itemNameProfile = $"{mnuNvOtherSettings.Name}_Profile";
|
||||
var profileMenu = FormUtils.BuildMenuItem(mnuNvOtherSettings.DropDownItems, itemNameProfile, "Color Profile");
|
||||
|
||||
var subItemNameProfile = $"{itemNameProfile}_SubItem";
|
||||
var subItemProfile = FormUtils.BuildMenuItem(profileMenu.DropDownItems, subItemNameProfile, "", onClick: nvPresetColorProfileMenuItem_Click);
|
||||
subItemProfile.Text = (!preset.ColorProfileSettings.ProfileName.IsNullOrWhiteSpace() ? $"{preset.ColorProfileSettings.ProfileName}" : "Unset") + " (click to change)";
|
||||
FormUtils.BuildMenuItemAndSub(mnuNvOtherSettings, "Color Profile",
|
||||
(!preset.ColorProfileSettings.ProfileName.IsNullOrWhiteSpace() ? $"{preset.ColorProfileSettings.ProfileName}" : "Unset") + " (click to change)", nvPresetColorProfileMenuItem_Click);
|
||||
|
||||
FormUtils.BuildDropDownMenu(mnuNvHdmiSettings, "Content type", typeof(InfoFrameVideoContentType), preset.HdmiInfoFrameSettings, "ContentType", nvPresetHdmiContentTypeMenuItem_Click, unchanged: true)
|
||||
.DropDownItems[0].Visible = !isCurrentDisplay;
|
||||
@@ -833,6 +835,68 @@ namespace ColorControl.Services.NVIDIA
|
||||
AddOrUpdateItem();
|
||||
}
|
||||
|
||||
private void nvPresetDvcMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var preset = GetSelectedNvPreset(true);
|
||||
|
||||
var label = "Digital vibrance in % (clear to set to default)";
|
||||
|
||||
var display = _nvService.ResolveDisplay(preset);
|
||||
var dvControl = display.DigitalVibranceControl;
|
||||
|
||||
var value = SelectValue(dvControl.MinimumLevel, dvControl.MaximumLevel, preset.ColorEnhancementSettings.DigitalVibranceLevel, label);
|
||||
|
||||
if (value == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var intValue = value ?? dvControl.DefaultLevel;
|
||||
|
||||
if (preset.IsDisplayPreset)
|
||||
{
|
||||
_nvService.SetDigitalVibranceLevel(preset.Display, intValue);
|
||||
|
||||
UpdateDisplayInfoItems();
|
||||
return;
|
||||
}
|
||||
|
||||
preset.ColorEnhancementSettings.DigitalVibranceLevel = intValue;
|
||||
|
||||
AddOrUpdateItem();
|
||||
}
|
||||
|
||||
private void nvPresetHueMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var preset = GetSelectedNvPreset(true);
|
||||
|
||||
var label = "Hue angle in ° (clear to set to default)";
|
||||
|
||||
var display = _nvService.ResolveDisplay(preset);
|
||||
var hueControl = display.HUEControl;
|
||||
|
||||
var value = SelectValue(hueControl.DefaultAngle, 359, preset.ColorEnhancementSettings.HueAngle, label);
|
||||
|
||||
if (value == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var intValue = value ?? hueControl.DefaultAngle;
|
||||
|
||||
if (preset.IsDisplayPreset)
|
||||
{
|
||||
_nvService.SetHueAngle(preset.Display, intValue);
|
||||
|
||||
UpdateDisplayInfoItems();
|
||||
return;
|
||||
}
|
||||
|
||||
preset.ColorEnhancementSettings.HueAngle = intValue;
|
||||
|
||||
AddOrUpdateItem();
|
||||
}
|
||||
|
||||
private void nvPresetScalingMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var menuItem = (ToolStripMenuItem)sender;
|
||||
@@ -1931,5 +1995,14 @@ namespace ColorControl.Services.NVIDIA
|
||||
|
||||
MessageForms.ShowControl(panel, "NVIDIA Info", height: 800);
|
||||
}
|
||||
|
||||
private void miNvPresetColorEnhancementsIncluded_Click(object sender, EventArgs e)
|
||||
{
|
||||
var preset = GetSelectedNvPreset();
|
||||
|
||||
preset.ApplyColorEnhancements = !preset.ApplyColorEnhancements;
|
||||
|
||||
AddOrUpdateItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace ColorControl.Services.NVIDIA
|
||||
|
||||
public bool applyColorData { get; set; }
|
||||
public ColorData colorData { get; set; }
|
||||
public bool ApplyColorEnhancements { get; set; }
|
||||
public NvColorEnhancementSettings ColorEnhancementSettings { get; set; }
|
||||
public bool applyHDR { get; set; }
|
||||
public bool HDREnabled { get; set; }
|
||||
public bool toggleHDR { get; set; }
|
||||
@@ -77,6 +79,7 @@ namespace ColorControl.Services.NVIDIA
|
||||
ocSettings = new List<NvGpuOcSettings>();
|
||||
HdmiInfoFrameSettings = new NvHdmiInfoFrameSettings();
|
||||
ColorProfileSettings = new NvColorProfileSettings();
|
||||
ColorEnhancementSettings = new NvColorEnhancementSettings();
|
||||
}
|
||||
|
||||
public NvPreset(ColorData colorData) : this()
|
||||
@@ -116,6 +119,9 @@ namespace ColorControl.Services.NVIDIA
|
||||
|
||||
HdmiInfoFrameSettings = new NvHdmiInfoFrameSettings(preset.HdmiInfoFrameSettings);
|
||||
applyHdmiSettings = preset.applyHdmiSettings;
|
||||
|
||||
ColorEnhancementSettings = new NvColorEnhancementSettings(preset.ColorEnhancementSettings);
|
||||
ApplyColorEnhancements = preset.ApplyColorEnhancements;
|
||||
}
|
||||
|
||||
public NvPreset Clone()
|
||||
@@ -127,7 +133,7 @@ namespace ColorControl.Services.NVIDIA
|
||||
|
||||
public static string[] GetColumnNames()
|
||||
{
|
||||
return new[] { "Name", "Display|140", "Color settings (BPC, format, dyn. range, color space)|260", "Refresh rate|100", "Resolution|120", "Dithering", "HDR", "Driver settings|300", "HDMI settings|200", "Other|200", "Overclocking|300", "Shortcut", "Apply on startup" };
|
||||
return new[] { "Name", "Display|140", "Color settings (BPC, format, dyn. range, color space)|260", "Color enhancements", "Refresh rate|100", "Resolution|120", "Dithering", "HDR", "Driver settings|300", "HDMI settings|200", "Other|200", "Overclocking|300", "Shortcut", "Apply on startup" };
|
||||
}
|
||||
|
||||
public override List<string> GetDisplayValues(Config config = null)
|
||||
@@ -145,6 +151,9 @@ namespace ColorControl.Services.NVIDIA
|
||||
var colorSettings = FormatDisplaySetting(string.Format("{0}, {1}, {2}, {3}", colorData.ColorDepth, colorData.ColorFormat, colorData.DynamicRange, colorData.Colorimetry), isCurrent, applyColorData);
|
||||
|
||||
values.Add(colorSettings);
|
||||
|
||||
values.Add(FormatDisplaySetting(GetColorEnhancementsDescription(), isCurrent, ApplyColorEnhancements));
|
||||
|
||||
values.Add(FormatDisplaySetting(string.Format("{0}Hz", refreshRate), isCurrent, applyRefreshRate));
|
||||
|
||||
if (applyResolution || resolutionWidth > 0)
|
||||
@@ -298,6 +307,27 @@ namespace ColorControl.Services.NVIDIA
|
||||
return string.Join(", ", values);
|
||||
}
|
||||
|
||||
public string GetColorEnhancementsDescription()
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
if (ColorEnhancementSettings.DigitalVibranceLevel != 50)
|
||||
{
|
||||
values.Add($"Digital vibrance: {ColorEnhancementSettings.DigitalVibranceLevel}%");
|
||||
}
|
||||
if (ColorEnhancementSettings.HueAngle != 0)
|
||||
{
|
||||
values.Add($"Hue: {ColorEnhancementSettings.HueAngle}°");
|
||||
}
|
||||
|
||||
if (!values.Any())
|
||||
{
|
||||
values.Add("None");
|
||||
}
|
||||
|
||||
return string.Join(", ", values);
|
||||
}
|
||||
|
||||
public static ColorData DefaultColorData => new ColorData(ColorDataFormat.Auto, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.Default, colorSelectionPolicy: ColorDataSelectionPolicy.BestQuality);
|
||||
|
||||
public static List<NvPreset> GetDefaultPresets()
|
||||
|
||||
@@ -398,6 +398,12 @@ namespace ColorControl.Services.NVIDIA
|
||||
}
|
||||
}
|
||||
|
||||
if (preset.ApplyColorEnhancements)
|
||||
{
|
||||
SetDigitalVibranceLevel(display, preset.ColorEnhancementSettings.DigitalVibranceLevel);
|
||||
SetHueAngle(display, preset.ColorEnhancementSettings.HueAngle);
|
||||
}
|
||||
|
||||
if (preset.applyDriverSettings)
|
||||
{
|
||||
SetDriverSettings(preset.driverSettings);
|
||||
@@ -609,6 +615,28 @@ namespace ColorControl.Services.NVIDIA
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetDigitalVibranceLevel(Display display, int level)
|
||||
{
|
||||
var dvControl = display.DigitalVibranceControl;
|
||||
|
||||
dvControl.CurrentLevel = level;
|
||||
}
|
||||
|
||||
public int GetDigitalVibranceLevel(Display display)
|
||||
{
|
||||
return display.DigitalVibranceControl.CurrentLevel;
|
||||
}
|
||||
|
||||
public void SetHueAngle(Display display, int angle)
|
||||
{
|
||||
display.HUEControl.CurrentAngle = angle;
|
||||
}
|
||||
|
||||
public int GetHueAngle(Display display)
|
||||
{
|
||||
return display.HUEControl.CurrentAngle;
|
||||
}
|
||||
|
||||
public bool SetDithering(NvDitherState state, uint bits = 1, uint mode = 4, NvPreset preset = null, Display currentDisplay = null)
|
||||
{
|
||||
var result = true;
|
||||
@@ -1132,6 +1160,7 @@ namespace ColorControl.Services.NVIDIA
|
||||
|
||||
preset.displayName = FormUtils.ExtendedDisplayName(display.Name);
|
||||
preset.colorData = GetCurrentColorData(display);
|
||||
preset.ColorEnhancementSettings = GetCurrentColorEnhancements(display);
|
||||
preset.HdmiInfoFrameSettings = GetHdmiSettings(display);
|
||||
preset.SDRBrightness = GetSDRBrightness(display);
|
||||
preset.scaling = GetScaling(display);
|
||||
@@ -1199,6 +1228,15 @@ namespace ColorControl.Services.NVIDIA
|
||||
return preset;
|
||||
}
|
||||
|
||||
private NvColorEnhancementSettings GetCurrentColorEnhancements(Display display)
|
||||
{
|
||||
return new NvColorEnhancementSettings
|
||||
{
|
||||
DigitalVibranceLevel = GetDigitalVibranceLevel(display),
|
||||
HueAngle = GetHueAngle(display)
|
||||
};
|
||||
}
|
||||
|
||||
public List<SettingItem> GetVisibleSettings()
|
||||
{
|
||||
return GetSettings().Where(s => _driverSettingIds.Contains(s.SettingId)).ToList();
|
||||
@@ -1368,14 +1406,14 @@ namespace ColorControl.Services.NVIDIA
|
||||
Utils.WriteObject(_configFilename, Config);
|
||||
}
|
||||
|
||||
internal void ResolveDisplay(NvPreset preset)
|
||||
internal Display ResolveDisplay(NvPreset preset)
|
||||
{
|
||||
if (preset.Display != null)
|
||||
if (preset.Display == null)
|
||||
{
|
||||
return;
|
||||
preset.Display = GetPresetDisplay(preset);
|
||||
}
|
||||
|
||||
preset.Display = GetPresetDisplay(preset);
|
||||
return preset.Display;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
using ColorControl.Shared.Common;
|
||||
using ColorControl.Shared.Forms;
|
||||
using ColorControl.Shared.Native;
|
||||
using ColorControl.Shared.XForms;
|
||||
using MHC2Gen;
|
||||
using novideo_srgb;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using WindowsDisplayAPI;
|
||||
|
||||
namespace ColorControl.XForms;
|
||||
|
||||
public enum SaveOption
|
||||
{
|
||||
Install,
|
||||
[Description("Install and set as default")]
|
||||
InstallAndSetAsDefault,
|
||||
[Description("Save to file")]
|
||||
SaveToFile
|
||||
}
|
||||
|
||||
public enum DisplayPrimariesSource
|
||||
{
|
||||
Custom,
|
||||
EDID,
|
||||
Windows
|
||||
}
|
||||
|
||||
public class CustomDisplay
|
||||
{
|
||||
public Display Display { get; set; }
|
||||
|
||||
public string DisplayName => Display.DisplayName;
|
||||
public string DevicePath => Display.DevicePath;
|
||||
public bool IsHDRSupportedAndEnabled()
|
||||
{
|
||||
var advancedColor = CCD.GetAdvancedColorSupportedAndEnabled(DisplayName);
|
||||
|
||||
return advancedColor.isSupported && advancedColor.isEnabled;
|
||||
}
|
||||
|
||||
public CustomDisplay(Display display)
|
||||
{
|
||||
Display = display;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{FormUtils.ExtendedDisplayName(Display.DisplayName)} on {Display.Adapter.DeviceName}";
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorPointModel : BaseViewModel
|
||||
{
|
||||
private double _x;
|
||||
public double X { get => _x; set { _x = value; OnPropertyChanged(); } }
|
||||
|
||||
private double _y;
|
||||
public double Y { get => _y; set { _y = value; OnPropertyChanged(); } }
|
||||
|
||||
public ColorPointModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ColorPointModel(CIExy coord)
|
||||
{
|
||||
X = coord.x;
|
||||
Y = coord.y;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ColorProfileViewModel : BaseViewModel
|
||||
{
|
||||
[StringLength(30)]
|
||||
public string Description { get; set; }
|
||||
|
||||
public ColorPointModel RedPoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Red);
|
||||
public ColorPointModel GreenPoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Green);
|
||||
public ColorPointModel BluePoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Blue);
|
||||
public ColorPointModel WhitePoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.White);
|
||||
public Dictionary<DisplayPrimariesSource, string> PrimariesSources { get; } = Utils.EnumToDictionary<DisplayPrimariesSource>();
|
||||
public DisplayPrimariesSource PrimariesSource { get; set; } = DisplayPrimariesSource.EDID;
|
||||
public Dictionary<ColorGamut, string> ColorGamuts { get; } = Utils.EnumToDictionary<ColorGamut>();
|
||||
public ColorGamut ColorGamut { get; set; } = ColorGamut.Native;
|
||||
public Dictionary<SDRTransferFunction, string> SDRTransferFunctions { get; } = Utils.EnumToDictionary<SDRTransferFunction>();
|
||||
public SDRTransferFunction SDRTransferFunction { get; set; } = SDRTransferFunction.PurePower;
|
||||
[Range(0.1, 10)]
|
||||
public double CustomGamma { get; set; } = 2.20;
|
||||
[Range(0, 10)]
|
||||
public double MinCLL { get; set; } = 0;
|
||||
[Range(11, 10000)]
|
||||
public double MaxCLL { get; set; } = 1000;
|
||||
[Range(0, 10)]
|
||||
public double BlackLuminance { get; set; } = 0;
|
||||
[Range(11, 10000)]
|
||||
public double WhiteLuminance { get; set; } = 1000;
|
||||
[Range(0, 10)]
|
||||
public double SDRMinBrightness { get; set; } = 0;
|
||||
[Range(11, 1000)]
|
||||
public double SDRMaxBrightness { get; set; } = 100;
|
||||
[Range(-50, 50)]
|
||||
public double SDRBrightnessBoost { get; set; }
|
||||
|
||||
public CustomDisplay SelectedDisplay { get; set; }
|
||||
public IEnumerable<CustomDisplay> Displays { get; set; }
|
||||
|
||||
public string SelectedDisplayName => SelectedDisplay?.DisplayName;
|
||||
|
||||
public List<string> ExistingProfiles { get; set; }
|
||||
public string SelectedExistingProfile { get; set; } = CreateANewProfile;
|
||||
public string NewProfileName { get; set; }
|
||||
public string ProfileName => SelectedExistingProfile == CreateANewProfile ? NewProfileName : SelectedExistingProfile;
|
||||
public bool IsHDR { get; set; } = true;
|
||||
public Dictionary<SaveOption, string> SaveOptions { get; } = Utils.EnumToDictionary<SaveOption>();
|
||||
public SaveOption SaveOption { get; set; } = SaveOption.InstallAndSetAsDefault;
|
||||
|
||||
|
||||
public override string this[string columnName]
|
||||
{
|
||||
get
|
||||
{
|
||||
var baseResult = base[columnName];
|
||||
|
||||
if (columnName == "SelectedDisplay" || columnName == "PrimariesSource")
|
||||
{
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
return baseResult;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool PreValidate()
|
||||
{
|
||||
return base.PreValidate() && Displays.Any();
|
||||
}
|
||||
|
||||
public const string CreateANewProfile = "<create a new profile>";
|
||||
|
||||
public ColorProfileViewModel(bool isHDR = true)
|
||||
{
|
||||
IsHDR = isHDR;
|
||||
|
||||
RefreshDisplays();
|
||||
|
||||
ExistingProfiles = new List<string> { CreateANewProfile };
|
||||
NewProfileName = $"CC_{(isHDR ? "HDR" : "SDR")}_profile_{DateTime.Now:yyyyMMddHHmmss}.icm";
|
||||
Description = $"CC_{(isHDR ? "HDR" : "SDR")}";
|
||||
|
||||
if (Displays.Any())
|
||||
{
|
||||
SelectedDisplay = Displays.First();
|
||||
|
||||
UpdateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshDisplays()
|
||||
{
|
||||
Displays = Display.GetDisplays().Select(d => new CustomDisplay(d)).ToList();
|
||||
|
||||
if (IsHDR)
|
||||
{
|
||||
Displays = Displays.Where(d => d.IsHDRSupportedAndEnabled()).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDisplay()
|
||||
{
|
||||
if (SelectedDisplay == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var colorParams = CCD.GetColorParams(SelectedDisplay.DisplayName);
|
||||
|
||||
if (colorParams.MaxLuminance > 0)
|
||||
{
|
||||
if (PrimariesSource == DisplayPrimariesSource.Windows)
|
||||
{
|
||||
var divider = colorParams.RedPointX <= 1 << 10 ? 1 << 10 : 1 << 20;
|
||||
|
||||
RedPoint.X = (double)colorParams.RedPointX / divider;
|
||||
RedPoint.Y = (double)colorParams.RedPointY / divider;
|
||||
GreenPoint.X = (double)colorParams.GreenPointX / divider;
|
||||
GreenPoint.Y = (double)colorParams.GreenPointY / divider;
|
||||
BluePoint.X = (double)colorParams.BluePointX / divider;
|
||||
BluePoint.Y = (double)colorParams.BluePointY / divider;
|
||||
WhitePoint.X = (double)colorParams.WhitePointX / divider;
|
||||
WhitePoint.Y = (double)colorParams.WhitePointY / divider;
|
||||
}
|
||||
|
||||
WhiteLuminance = (double)colorParams.MaxLuminance / 10000;
|
||||
OnPropertyChanged(nameof(WhiteLuminance));
|
||||
BlackLuminance = (double)colorParams.MinLuminance / 10000;
|
||||
OnPropertyChanged(nameof(BlackLuminance));
|
||||
MinCLL = BlackLuminance;
|
||||
OnPropertyChanged(nameof(MinCLL));
|
||||
MaxCLL = WhiteLuminance;
|
||||
OnPropertyChanged(nameof(MaxCLL));
|
||||
}
|
||||
|
||||
if (PrimariesSource == DisplayPrimariesSource.EDID)
|
||||
{
|
||||
GetEDID();
|
||||
}
|
||||
|
||||
if (!CCD.GetUsePerUserDisplayProfiles(SelectedDisplay.DisplayName))
|
||||
{
|
||||
if (MessageForms.QuestionYesNo("To be able to select/activate a color profile, user specific settings have to be enabled. Do you want to enable this?") == DialogResult.Yes)
|
||||
{
|
||||
CCD.SetUsePerUserDisplayProfiles(SelectedDisplay.DisplayName, true);
|
||||
}
|
||||
}
|
||||
|
||||
ExistingProfiles = new List<string> { CreateANewProfile };
|
||||
ExistingProfiles.AddRange(CCD.GetDisplayColorProfiles(SelectedDisplay.DisplayName));
|
||||
}
|
||||
|
||||
private void GetEDID()
|
||||
{
|
||||
if (SelectedDisplay == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var path = SelectedDisplay.DevicePath;
|
||||
|
||||
var edid = Novideo.GetEDID(path, null);
|
||||
var primaries = edid?.DisplayParameters?.ChromaticityCoordinates;
|
||||
|
||||
if (primaries == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RedPoint.X = primaries.RedX;
|
||||
RedPoint.Y = primaries.RedY;
|
||||
GreenPoint.X = primaries.GreenX;
|
||||
GreenPoint.Y = primaries.GreenY;
|
||||
BluePoint.X = primaries.BlueX;
|
||||
BluePoint.Y = primaries.BlueY;
|
||||
WhitePoint.X = primaries.WhiteX;
|
||||
WhitePoint.Y = primaries.WhiteY;
|
||||
}
|
||||
|
||||
internal RgbPrimaries GetDevicePrimaries()
|
||||
{
|
||||
return new RgbPrimaries(
|
||||
new CIExy { x = RedPoint.X, y = RedPoint.Y },
|
||||
new CIExy { x = GreenPoint.X, y = GreenPoint.Y },
|
||||
new CIExy { x = BluePoint.X, y = BluePoint.Y },
|
||||
new CIExy { x = WhitePoint.X, y = WhitePoint.Y });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<src:BaseWindow x:Class="ColorControl.XForms.ColorProfileWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
Title="Create Color Profile"
|
||||
ResizeMode="CanResize"
|
||||
Width="773"
|
||||
Height="775"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
SnapsToDevicePixels="True"
|
||||
Style="{DynamicResource CustomWindowStyle}"
|
||||
xmlns:src="clr-namespace:ColorControl.Shared.XForms;assembly=Shared" Loaded="Window_Loaded">
|
||||
<StackPanel Margin="6,6,6,6" Width="733">
|
||||
<GroupBox DockPanel.Dock="Top" Margin="0,0,0,0" Header="General Profile Settings" Padding="6" Height="287" Width="733" HorizontalAlignment="Left">
|
||||
<Grid Height="270" VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="132*"/>
|
||||
<ColumnDefinition Width="577*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="Maximum Luminance (nits):" HorizontalAlignment="Left" Margin="206,232,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="412,236,0,0" TextWrapping="Wrap" Text="{Binding WhiteLuminance, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" Name="tbMaxLuminance" Height="18" InputScope="Number"/>
|
||||
<Label Content="Minimum Luminance (nits):" HorizontalAlignment="Left" Margin="-5,232,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="76,236,0,0" TextWrapping="Wrap" Text="{Binding BlackLuminance, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbMinLuminance" Height="18" InputScope="Number"/>
|
||||
<Label Content="Display:" HorizontalAlignment="Left" Margin="-6,8,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<ComboBox Margin="76,10,0,0" HorizontalAlignment="Left" Width="318" VerticalAlignment="Top" Grid.Column="1" Height="22" SelectedValue="{Binding SelectedDisplay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" ItemsSource="{Binding Displays}"/>
|
||||
<Label Content="Color Gamut:" HorizontalAlignment="Left" Margin="-5,201,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<ComboBox Margin="76,203,0,0" HorizontalAlignment="Left" Width="318" VerticalAlignment="Top" Grid.Column="1" Height="22" ItemsSource="{Binding ColorGamuts}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding ColorGamut}" />
|
||||
<Label Content="Display Primaries Source:" HorizontalAlignment="Left" Margin="-5,39,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<ComboBox Margin="76,41,0,0" HorizontalAlignment="Left" Width="318" VerticalAlignment="Top" Grid.Column="1" Height="24" ItemsSource="{Binding PrimariesSources}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding PrimariesSource, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" />
|
||||
<Label Content="Custom Primaries:" HorizontalAlignment="Left" Margin="-5,74,0,0" VerticalAlignment="Top" Width="118" Height="26"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="76,78,0,0" TextWrapping="Wrap" Text="{Binding RedPoint.X, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy" Height="18" InputScope="Number"/>
|
||||
<Label HorizontalContentAlignment="Right" Content="Red:" HorizontalAlignment="Left" Margin="20,74,0,0" VerticalAlignment="Top" Width="51" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="195,78,0,0" TextWrapping="Wrap" Text="{Binding RedPoint.Y, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy1" Height="18" InputScope="Number"/>
|
||||
<Label Content="x" HorizontalAlignment="Left" Margin="164,74,0,0" VerticalAlignment="Top" Width="26" Height="26" Grid.Column="1"/>
|
||||
<Label Content="y" HorizontalAlignment="Center" Margin="0,74,0,0" VerticalAlignment="Top" Width="24" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="76,109,0,0" TextWrapping="Wrap" Text="{Binding GreenPoint.X, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy2" Height="18" InputScope="Number"/>
|
||||
<Label HorizontalContentAlignment="Right" Content="Green:" HorizontalAlignment="Left" Margin="20,105,0,0" VerticalAlignment="Top" Width="52" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="195,109,0,0" TextWrapping="Wrap" Text="{Binding GreenPoint.Y, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy3" Height="18" InputScope="Number"/>
|
||||
<Label Content="x" HorizontalAlignment="Left" Margin="164,105,0,0" VerticalAlignment="Top" Width="26" Height="26" Grid.Column="1"/>
|
||||
<Label Content="y" HorizontalAlignment="Center" Margin="0,105,0,0" VerticalAlignment="Top" Width="24" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="76,140,0,0" TextWrapping="Wrap" Text="{Binding BluePoint.X, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy4" Height="18" InputScope="Number"/>
|
||||
<Label HorizontalContentAlignment="Right" Content="Blue:" HorizontalAlignment="Left" Margin="19,136,0,0" VerticalAlignment="Top" Width="52" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="195,140,0,0" TextWrapping="Wrap" Text="{Binding BluePoint.Y, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy5" Height="18" InputScope="Number"/>
|
||||
<Label Content="x" HorizontalAlignment="Left" Margin="164,136,0,0" VerticalAlignment="Top" Width="26" Height="26" Grid.Column="1"/>
|
||||
<Label Content="y" HorizontalAlignment="Center" Margin="0,136,0,0" VerticalAlignment="Top" Width="24" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="76,171,0,0" TextWrapping="Wrap" Text="{Binding WhitePoint.X, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy7" Height="18" InputScope="Number"/>
|
||||
<Label HorizontalContentAlignment="Right" Content="White:" HorizontalAlignment="Left" Margin="19,167,0,0" VerticalAlignment="Top" Width="52" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="195,171,0,0" TextWrapping="Wrap" Text="{Binding WhitePoint.Y, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="83" x:Name="tbSDRMinBrightness_Copy8" Height="18" InputScope="Number"/>
|
||||
<Label Content="x" HorizontalAlignment="Left" Margin="164,167,0,0" VerticalAlignment="Top" Width="26" Height="26" Grid.Column="1"/>
|
||||
<Label Content="y" HorizontalAlignment="Center" Margin="0,167,0,0" VerticalAlignment="Top" Width="24" Height="26" Grid.Column="1"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Advanced HDR Settings" Padding="6" Height="133" Width="734" HorizontalAlignment="Left">
|
||||
<Grid Height="103">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="179*"/>
|
||||
<ColumnDefinition Width="735*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="SDR Transfer Function & Gamma:" HorizontalAlignment="Left" Margin="-5,6,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<ComboBox Margin="69,8,0,0" HorizontalAlignment="Left" Width="318" VerticalAlignment="Top" Grid.Column="1" Height="22" ItemsSource="{Binding SDRTransferFunctions}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding SDRTransferFunction}"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="405,10,0,0" TextWrapping="Wrap" Text="{Binding CustomGamma, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbCustomGamma" Height="18" InputScope="Number"/>
|
||||
<Label Content="SDR minimum brightness (nits):" HorizontalAlignment="Left" Margin="-5,37,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="69,41,0,0" TextWrapping="Wrap" Text="{Binding SDRMinBrightness, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbSDRMinBrightness" Height="18" InputScope="Number"/>
|
||||
<Label Content="SDR maximum brightness (nits):" HorizontalAlignment="Left" Margin="197,37,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="405,41,0,0" TextWrapping="Wrap" Text="{Binding SDRMaxBrightness, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbSDRMaxBrightness" Height="18" InputScope="Number"/>
|
||||
<Label Content="SDR brightness boost (%):" HorizontalAlignment="Left" Margin="-5,64,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="69,68,0,0" TextWrapping="Wrap" Text="{Binding SDRBrightnessBoost, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbSDRMinBrightness_Copy6" Height="18" InputScope="Number"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Advanced Profile Settings" Padding="6" Height="78" Width="734" HorizontalAlignment="Left">
|
||||
<Grid Height="47">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="4*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="MHC2 MinCLL (nits):" HorizontalAlignment="Left" Margin="-3,6,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="66,10,0,0" TextWrapping="Wrap" Text="{Binding MinCLL, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbMinLuminance_Copy" Height="18" InputScope="Number"/>
|
||||
<Label Content="MHC2 MaxCLL (nits):" HorizontalAlignment="Left" Margin="201,6,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.Column="1"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="400,10,0,0" TextWrapping="Wrap" Text="{Binding MaxCLL, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="120" x:Name="tbMinLuminance_Copy1" Height="18" InputScope="Number"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox DockPanel.Dock="Right" Margin="0,0,0,0" Header="Generate Options" Padding="6" Height="197" Width="733" HorizontalAlignment="Left">
|
||||
<Grid Height="163" Margin="-2,0,2,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="8*"/>
|
||||
<ColumnDefinition Width="27*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button IsEnabled="{Binding IsValid}" Click="Button_Click" Content="Generate" Margin="46,132,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="20" Width="75" Grid.Column="1"/>
|
||||
<Label Content="Overwrite existing profile:" HorizontalAlignment="Left" Margin="0,40,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<ComboBox Margin="46,42,0,0" HorizontalAlignment="Left" Width="318" VerticalAlignment="Top" Grid.Column="1" Height="22" SelectedValue="{Binding SelectedExistingProfile}" ItemsSource="{Binding ExistingProfiles}"/>
|
||||
<Label Content="New profile name:" HorizontalAlignment="Left" Margin="0,73,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="46,77,0,0" TextWrapping="Wrap" Text="{Binding NewProfileName}" VerticalAlignment="Top" Width="318" x:Name="tbName" Height="18"/>
|
||||
<Label Content="Save option:" HorizontalAlignment="Left" Margin="0,8,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<ComboBox Margin="46,10,0,0" HorizontalAlignment="Left" Width="318" VerticalAlignment="Top" Grid.Column="1" Height="22" ItemsSource="{Binding SaveOptions}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding SaveOption}" />
|
||||
<Label Content="Description:" HorizontalAlignment="Left" Margin="0,101,0,0" VerticalAlignment="Top" Width="208" Height="26" Grid.ColumnSpan="2"/>
|
||||
<TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="46,105,0,0" TextWrapping="Wrap" Text="{Binding Description, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="318" x:Name="tbName_Copy" Height="18"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<StackPanel HorizontalAlignment="Right" Margin="0,6,0,0" VerticalAlignment="Bottom"/>
|
||||
<Button Click="Close_Click" IsCancel="True" Content="Close" Width="75" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
|
||||
</StackPanel>
|
||||
</src:BaseWindow>
|
||||
@@ -0,0 +1,152 @@
|
||||
using ColorControl.Shared.Forms;
|
||||
using ColorControl.Shared.Native;
|
||||
using ColorControl.Shared.Services;
|
||||
using ColorControl.Shared.XForms;
|
||||
using MHC2Gen;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms.Integration;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
namespace ColorControl.XForms
|
||||
{
|
||||
public partial class ColorProfileWindow : BaseWindow
|
||||
{
|
||||
private ColorProfileViewModel _viewModel;
|
||||
private readonly WinApiAdminService _winApiAdminService;
|
||||
|
||||
public ColorProfileWindow(WinApiAdminService winApiAdminService)
|
||||
{
|
||||
_viewModel = new ColorProfileViewModel();
|
||||
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
_winApiAdminService = winApiAdminService;
|
||||
}
|
||||
|
||||
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
var processStartInfo = new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
};
|
||||
System.Diagnostics.Process.Start(processStartInfo);
|
||||
}
|
||||
|
||||
public static void CreateAndShow(bool show = true)
|
||||
{
|
||||
if (Application.Current == null)
|
||||
{
|
||||
new Application();
|
||||
}
|
||||
|
||||
var window = Program.ServiceProvider.GetRequiredService<ColorProfileWindow>();
|
||||
|
||||
if (show)
|
||||
{
|
||||
ElementHost.EnableModelessKeyboardInterop(window);
|
||||
window.WindowState = WindowState.Normal;
|
||||
window.Show();
|
||||
window.Topmost = true;
|
||||
window.Topmost = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
//e.Cancel = true;
|
||||
|
||||
//Hide();
|
||||
}
|
||||
|
||||
protected override void OnStateChanged(EventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Minimized)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
base.OnStateChanged(e);
|
||||
}
|
||||
|
||||
private void Close_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_viewModel.Displays.Any())
|
||||
{
|
||||
MessageForms.WarningOk("There are no displays available that support HDR and have it enabled. Please activate HDR first.");
|
||||
}
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var command = new GenerateProfileCommand
|
||||
{
|
||||
Description = _viewModel.Description,
|
||||
MinCLL = _viewModel.MinCLL,
|
||||
MaxCLL = _viewModel.MaxCLL,
|
||||
BlackLuminance = _viewModel.BlackLuminance,
|
||||
WhiteLuminance = _viewModel.WhiteLuminance,
|
||||
SDRMinBrightness = _viewModel.SDRMinBrightness,
|
||||
SDRMaxBrightness = _viewModel.SDRMaxBrightness,
|
||||
SDRTransferFunction = _viewModel.SDRTransferFunction,
|
||||
SDRBrightnessBoost = _viewModel.SDRBrightnessBoost,
|
||||
ColorGamut = _viewModel.ColorGamut,
|
||||
Gamma = _viewModel.CustomGamma,
|
||||
DevicePrimaries = _viewModel.GetDevicePrimaries(),
|
||||
};
|
||||
|
||||
var bytes = MHC2Wrapper.GenerateSdrAcmProfile(command);
|
||||
|
||||
if (_viewModel.SaveOption == SaveOption.SaveToFile)
|
||||
{
|
||||
var saveFileDialog = new System.Windows.Forms.SaveFileDialog
|
||||
{
|
||||
FileName = _viewModel.NewProfileName
|
||||
};
|
||||
if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
File.WriteAllBytes(saveFileDialog.FileName, bytes);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var tempFilename = Path.GetFullPath(_viewModel.ProfileName, Path.GetTempPath());
|
||||
|
||||
if (File.Exists(tempFilename))
|
||||
{
|
||||
File.Delete(tempFilename);
|
||||
}
|
||||
|
||||
File.WriteAllBytes(tempFilename, bytes);
|
||||
|
||||
_winApiAdminService.UninstallColorProfile(tempFilename);
|
||||
|
||||
CCD.InstallColorProfile(tempFilename);
|
||||
|
||||
if (_viewModel.SaveOption != SaveOption.InstallAndSetAsDefault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var displayName = _viewModel.SelectedDisplayName;
|
||||
|
||||
var profileName = Path.GetFileName(tempFilename);
|
||||
|
||||
CCD.SetDisplayDefaultColorProfile(displayName, profileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public class CmsContext
|
||||
{
|
||||
public IntPtr Handle { get; }
|
||||
public bool OwnedByGC { get; private set; }
|
||||
|
||||
|
||||
static readonly ConcurrentDictionary<IntPtr, CmsContext> GCOwnedContext = new();
|
||||
|
||||
public static CmsContext Default { get; } = new CmsContext(IntPtr.Zero, false);
|
||||
|
||||
|
||||
private void MoveToGC()
|
||||
{
|
||||
OwnedByGC = true;
|
||||
|
||||
GCOwnedContext.TryAdd(Handle, this);
|
||||
}
|
||||
|
||||
public CmsContext() {
|
||||
Handle = CmsNative.cmsCreateContext(IntPtr.Zero, IntPtr.Zero);
|
||||
MoveToGC();
|
||||
}
|
||||
|
||||
private CmsContext(IntPtr handle, bool moveOwnership){
|
||||
Handle = handle;
|
||||
if (moveOwnership)
|
||||
{
|
||||
MoveToGC();
|
||||
}
|
||||
}
|
||||
|
||||
public static CmsContext GetFromHandle(IntPtr handle, bool moveOwnership = false)
|
||||
{
|
||||
if (handle == IntPtr.Zero) return Default;
|
||||
if (GCOwnedContext.TryGetValue(handle, out var x)) return x;
|
||||
return new CmsContext(handle, moveOwnership);
|
||||
}
|
||||
|
||||
public double SetAdaptionState(double state)
|
||||
{
|
||||
return CmsNative.cmsSetAdaptationStateTHR(Handle, state);
|
||||
}
|
||||
|
||||
|
||||
~CmsContext()
|
||||
{
|
||||
if (OwnedByGC && Handle != IntPtr.Zero )
|
||||
{
|
||||
if (GCOwnedContext.TryRemove(new(Handle, this))) {
|
||||
CmsNative.cmsDeleteContext(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
using System;
|
||||
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0169
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public enum TagSignature
|
||||
{
|
||||
AToB0Tag = 0x41324230, // 'A2B0'
|
||||
AToB1Tag = 0x41324231, // 'A2B1'
|
||||
AToB2Tag = 0x41324232, // 'A2B2'
|
||||
BlueColorantTag = 0x6258595A, // 'bXYZ'
|
||||
BlueMatrixColumnTag = 0x6258595A, // 'bXYZ'
|
||||
BlueTRCTag = 0x62545243, // 'bTRC'
|
||||
BToA0Tag = 0x42324130, // 'B2A0'
|
||||
BToA1Tag = 0x42324131, // 'B2A1'
|
||||
BToA2Tag = 0x42324132, // 'B2A2'
|
||||
CalibrationDateTimeTag = 0x63616C74, // 'calt'
|
||||
CharTargetTag = 0x74617267, // 'targ'
|
||||
ChromaticAdaptationTag = 0x63686164, // 'chad'
|
||||
ChromaticityTag = 0x6368726D, // 'chrm'
|
||||
ColorantOrderTag = 0x636C726F, // 'clro'
|
||||
ColorantTableTag = 0x636C7274, // 'clrt'
|
||||
ColorantTableOutTag = 0x636C6F74, // 'clot'
|
||||
ColorimetricIntentImageStateTag = 0x63696973, // 'ciis'
|
||||
CopyrightTag = 0x63707274, // 'cprt'
|
||||
CrdInfoTag = 0x63726469, // 'crdi'
|
||||
DataTag = 0x64617461, // 'data'
|
||||
DateTimeTag = 0x6474696D, // 'dtim'
|
||||
DeviceMfgDescTag = 0x646D6E64, // 'dmnd'
|
||||
DeviceModelDescTag = 0x646D6464, // 'dmdd'
|
||||
DeviceSettingsTag = 0x64657673, // 'devs'
|
||||
DToB0Tag = 0x44324230, // 'D2B0'
|
||||
DToB1Tag = 0x44324231, // 'D2B1'
|
||||
DToB2Tag = 0x44324232, // 'D2B2'
|
||||
DToB3Tag = 0x44324233, // 'D2B3'
|
||||
BToD0Tag = 0x42324430, // 'B2D0'
|
||||
BToD1Tag = 0x42324431, // 'B2D1'
|
||||
BToD2Tag = 0x42324432, // 'B2D2'
|
||||
BToD3Tag = 0x42324433, // 'B2D3'
|
||||
GamutTag = 0x67616D74, // 'gamt'
|
||||
GrayTRCTag = 0x6b545243, // 'kTRC'
|
||||
GreenColorantTag = 0x6758595A, // 'gXYZ'
|
||||
GreenMatrixColumnTag = 0x6758595A, // 'gXYZ'
|
||||
GreenTRCTag = 0x67545243, // 'gTRC'
|
||||
LuminanceTag = 0x6C756d69, // 'lumi'
|
||||
MeasurementTag = 0x6D656173, // 'meas'
|
||||
MediaBlackPointTag = 0x626B7074, // 'bkpt'
|
||||
MediaWhitePointTag = 0x77747074, // 'wtpt'
|
||||
MHC2 = 0x4D484332, // 'MHC2'
|
||||
NamedColorTag = 0x6E636f6C, // 'ncol' // Deprecated by the ICC
|
||||
NamedColor2Tag = 0x6E636C32, // 'ncl2'
|
||||
OutputResponseTag = 0x72657370, // 'resp'
|
||||
PerceptualRenderingIntentGamutTag = 0x72696730, // 'rig0'
|
||||
Preview0Tag = 0x70726530, // 'pre0'
|
||||
Preview1Tag = 0x70726531, // 'pre1'
|
||||
Preview2Tag = 0x70726532, // 'pre2'
|
||||
ProfileDescriptionTag = 0x64657363, // 'desc'
|
||||
ProfileDescriptionMLTag = 0x6473636d, // 'dscm'
|
||||
ProfileSequenceDescTag = 0x70736571, // 'pseq'
|
||||
ProfileSequenceIdTag = 0x70736964, // 'psid'
|
||||
Ps2CRD0Tag = 0x70736430, // 'psd0'
|
||||
Ps2CRD1Tag = 0x70736431, // 'psd1'
|
||||
Ps2CRD2Tag = 0x70736432, // 'psd2'
|
||||
Ps2CRD3Tag = 0x70736433, // 'psd3'
|
||||
Ps2CSATag = 0x70733273, // 'ps2s'
|
||||
Ps2RenderingIntentTag = 0x70733269, // 'ps2i'
|
||||
RedColorantTag = 0x7258595A, // 'rXYZ'
|
||||
RedMatrixColumnTag = 0x7258595A, // 'rXYZ'
|
||||
RedTRCTag = 0x72545243, // 'rTRC'
|
||||
SaturationRenderingIntentGamutTag = 0x72696732, // 'rig2'
|
||||
ScreeningDescTag = 0x73637264, // 'scrd'
|
||||
ScreeningTag = 0x7363726E, // 'scrn'
|
||||
TechnologyTag = 0x74656368, // 'tech'
|
||||
UcrBgTag = 0x62666420, // 'bfd '
|
||||
ViewingCondDescTag = 0x76756564, // 'vued'
|
||||
ViewingConditionsTag = 0x76696577, // 'view'
|
||||
VcgtTag = 0x76636774, // 'vcgt'
|
||||
MetaTag = 0x6D657461, // 'meta'
|
||||
ArgyllArtsTag = 0x61727473 // 'arts'
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ICC Color spaces
|
||||
/// </summary>
|
||||
public enum ColorSpaceSignature
|
||||
{
|
||||
XYZ = 0x58595A20, // 'XYZ '
|
||||
Lab = 0x4C616220, // 'Lab '
|
||||
Luv = 0x4C757620, // 'Luv '
|
||||
YCbCr = 0x59436272, // 'YCbr'
|
||||
Yxy = 0x59787920, // 'Yxy '
|
||||
Rgb = 0x52474220, // 'RGB '
|
||||
Gray = 0x47524159, // 'GRAY'
|
||||
Hsv = 0x48535620, // 'HSV '
|
||||
Hls = 0x484C5320, // 'HLS '
|
||||
Cmyk = 0x434D594B, // 'CMYK'
|
||||
Cmy = 0x434D5920, // 'CMY '
|
||||
MCH1 = 0x4D434831, // 'MCH1'
|
||||
MCH2 = 0x4D434832, // 'MCH2'
|
||||
MCH3 = 0x4D434833, // 'MCH3'
|
||||
MCH4 = 0x4D434834, // 'MCH4'
|
||||
MCH5 = 0x4D434835, // 'MCH5'
|
||||
MCH6 = 0x4D434836, // 'MCH6'
|
||||
MCH7 = 0x4D434837, // 'MCH7'
|
||||
MCH8 = 0x4D434838, // 'MCH8'
|
||||
MCH9 = 0x4D434839, // 'MCH9'
|
||||
MCHA = 0x4D434841, // 'MCHA'
|
||||
MCHB = 0x4D434842, // 'MCHB'
|
||||
MCHC = 0x4D434843, // 'MCHC'
|
||||
MCHD = 0x4D434844, // 'MCHD'
|
||||
MCHE = 0x4D434845, // 'MCHE'
|
||||
MCHF = 0x4D434846, // 'MCHF'
|
||||
Named = 0x6e6d636c, // 'nmcl'
|
||||
MultiColor1 = 0x31434C52, // '1CLR'
|
||||
MultiColor2 = 0x32434C52, // '2CLR'
|
||||
MultiColor3 = 0x33434C52, // '3CLR'
|
||||
MultiColor4 = 0x34434C52, // '4CLR'
|
||||
MultiColor5 = 0x35434C52, // '5CLR'
|
||||
MultiColor6 = 0x36434C52, // '6CLR'
|
||||
MultiColor7 = 0x37434C52, // '7CLR'
|
||||
MultiColor8 = 0x38434C52, // '8CLR'
|
||||
MultiColor9 = 0x39434C52, // '9CLR'
|
||||
MultiColor10 = 0x41434C52, // 'ACLR'
|
||||
MultiColor11 = 0x42434C52, // 'BCLR'
|
||||
MultiColor12 = 0x43434C52, // 'CCLR'
|
||||
MultiColor13 = 0x44434C52, // 'DCLR'
|
||||
MultiColor14 = 0x45434C52, // 'ECLR'
|
||||
MultiColor15 = 0x46434C52, // 'FCLR'
|
||||
LuvK = 0x4C75764B // 'LuvK'
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ICC Profile Class
|
||||
/// </summary>
|
||||
public enum ProfileClassSignature
|
||||
{
|
||||
Input = 0x73636E72, // 'scnr'
|
||||
Display = 0x6D6E7472, // 'mntr'
|
||||
Output = 0x70727472, // 'prtr'
|
||||
Link = 0x6C696E6B, // 'link'
|
||||
Abstract = 0x61627374, // 'abst'
|
||||
ColorSpace = 0x73706163, // 'spac'
|
||||
NamedColor = 0x6e6d636c // 'nmcl'
|
||||
|
||||
}
|
||||
public struct CIEXYZ
|
||||
{
|
||||
public double X;
|
||||
public double Y;
|
||||
public double Z;
|
||||
|
||||
public static CIEXYZ operator +(in CIEXYZ a, in CIEXYZ b)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
X = a.X + b.X,
|
||||
Y = a.Y + b.Y,
|
||||
Z = a.Z + b.Z
|
||||
};
|
||||
}
|
||||
|
||||
public static CIEXYZ operator -(in CIEXYZ a, in CIEXYZ b)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
X = a.X - b.X,
|
||||
Y = a.Y - b.Y,
|
||||
Z = a.Z - b.Z
|
||||
};
|
||||
}
|
||||
|
||||
public static CIEXYZ operator -(in CIEXYZ a)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
X = -a.X,
|
||||
Y = -a.Y,
|
||||
Z = -a.Z
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public struct CIExyY
|
||||
{
|
||||
public double x;
|
||||
public double y;
|
||||
public double Y;
|
||||
}
|
||||
public enum InfoType
|
||||
{
|
||||
Description = 0,
|
||||
Manufacturer = 1,
|
||||
Model = 2,
|
||||
Copyright = 3
|
||||
}
|
||||
|
||||
public enum ProfileUsedDirection
|
||||
{
|
||||
AsInput = 0,
|
||||
AsOutput = 1,
|
||||
AsProof = 2,
|
||||
}
|
||||
|
||||
public struct CIEXYZTRIPLE
|
||||
{
|
||||
public CIEXYZ Red;
|
||||
public CIEXYZ Green;
|
||||
public CIEXYZ Blue;
|
||||
}
|
||||
|
||||
public struct CIExyYTRIPLE
|
||||
{
|
||||
public CIExyY Red;
|
||||
public CIExyY Green;
|
||||
public CIExyY Blue;
|
||||
}
|
||||
|
||||
public struct ICCData
|
||||
{
|
||||
public uint Flag;
|
||||
public Memory<byte> Data;
|
||||
}
|
||||
|
||||
internal struct _ICCDataHeader
|
||||
{
|
||||
public uint len;
|
||||
public uint flag;
|
||||
}
|
||||
|
||||
internal unsafe struct _ICCData
|
||||
{
|
||||
public uint len;
|
||||
public uint flag;
|
||||
public fixed byte data[1];
|
||||
|
||||
internal static unsafe ICCData ToManaged(_ICCData* ptr)
|
||||
{
|
||||
var result = new ICCData();
|
||||
result.Flag = ptr->flag;
|
||||
result.Data = new ReadOnlySpan<byte>(ptr->data, (int)ptr->len).ToArray();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public struct CIELab
|
||||
{
|
||||
public double L;
|
||||
public double a;
|
||||
public double b;
|
||||
}
|
||||
|
||||
public struct CIELCh
|
||||
{
|
||||
public double L;
|
||||
public double C;
|
||||
public double h;
|
||||
}
|
||||
|
||||
public struct JCh
|
||||
{
|
||||
public double J;
|
||||
public double C;
|
||||
public double h;
|
||||
}
|
||||
|
||||
public enum IlluminantType
|
||||
{
|
||||
UNKNOWN = 0x0000000,
|
||||
D50 = 0x0000001,
|
||||
D65 = 0x0000002,
|
||||
D93 = 0x0000003,
|
||||
F2 = 0x0000004,
|
||||
D55 = 0x0000005,
|
||||
A = 0x0000006,
|
||||
E = 0x0000007,
|
||||
F8 = 0x0000008,
|
||||
}
|
||||
|
||||
public struct ICCMeasurementConditions
|
||||
{
|
||||
public uint Observer; // 0 = unknown, 1=CIE 1931, 2=CIE 1964
|
||||
public CIEXYZ Backing; // Value of backing
|
||||
public uint Geometry; // 0=unknown, 1=45/0, 0/45 2=0d, d/0
|
||||
public double Flare; // 0..1.0
|
||||
public IlluminantType IlluminantType;
|
||||
|
||||
}
|
||||
|
||||
public struct ICCViewingConditions
|
||||
{
|
||||
public CIEXYZ IlluminantXYZ; // Not the same struct as CAM02,
|
||||
public CIEXYZ SurroundXYZ; // This is for storing the tag
|
||||
public IlluminantType IlluminantType; // viewing condition
|
||||
}
|
||||
|
||||
public enum HeaderFlags
|
||||
{
|
||||
EmbeddedProfile = 1,
|
||||
UseWithEmbeddedDataOnly = 2
|
||||
}
|
||||
|
||||
internal struct CmsStructTm
|
||||
{
|
||||
public int tm_sec; // seconds after the minute - [0, 60] including leap second
|
||||
public int tm_min; // minutes after the hour - [0, 59]
|
||||
public int tm_hour; // hours since midnight - [0, 23]
|
||||
public int tm_mday; // day of the month - [1, 31]
|
||||
public int tm_mon; // months since January - [0, 11]
|
||||
public int tm_year; // years since 1900
|
||||
public int tm_wday; // days since Sunday - [0, 6]
|
||||
public int tm_yday; // days since January 1 - [0, 365]
|
||||
public int tm_isdst; // daylight savings time flag
|
||||
|
||||
public DateTime ToDateTime() => new DateTime(tm_year, tm_mon + 1, tm_mday, tm_hour, tm_min, tm_sec);
|
||||
|
||||
public static CmsStructTm FromDateTime(DateTime d)
|
||||
{
|
||||
return new CmsStructTm
|
||||
{
|
||||
tm_year = d.Year,
|
||||
tm_mon = d.Month - 1,
|
||||
tm_mday = d.Day,
|
||||
tm_hour = d.Hour,
|
||||
tm_min = d.Minute,
|
||||
tm_sec = d.Second,
|
||||
tm_wday = (int)d.DayOfWeek,
|
||||
tm_yday = d.DayOfYear,
|
||||
tm_isdst = d.IsDaylightSavingTime() ? 1 : 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpotShape
|
||||
{
|
||||
Unknown = 0,
|
||||
PrinterDefault = 1,
|
||||
Round = 2,
|
||||
Diamond = 3,
|
||||
Ellipse = 4,
|
||||
Line = 5,
|
||||
Square = 6,
|
||||
Cross = 7,
|
||||
}
|
||||
|
||||
public struct cmsScreeningChannel
|
||||
{
|
||||
public double Frequency;
|
||||
public double ScreenAngle;
|
||||
public SpotShape SpotShape;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Where to place/locate the stages in the pipeline chain
|
||||
/// </summary>
|
||||
public enum StageLoc
|
||||
{
|
||||
AtBegin,
|
||||
AtEnd,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multi process elements types
|
||||
/// </summary>
|
||||
public enum StageSignature
|
||||
{
|
||||
CurveSetElemType = 0x63767374, //'cvst'
|
||||
MatrixElemType = 0x6D617466, //'matf'
|
||||
CLutElemType = 0x636C7574, //'clut'
|
||||
|
||||
BAcsElemType = 0x62414353, // 'bACS'
|
||||
EAcsElemType = 0x65414353, // 'eACS'
|
||||
|
||||
// Custom from here, not in the ICC Spec
|
||||
XYZ2LabElemType = 0x6C327820, // 'l2x '
|
||||
Lab2XYZElemType = 0x78326C20, // 'x2l '
|
||||
NamedColorElemType = 0x6E636C20, // 'ncl '
|
||||
LabV2toV4 = 0x32203420, // '2 4 '
|
||||
LabV4toV2 = 0x34203220, // '4 2 '
|
||||
|
||||
// Identities
|
||||
IdentityElemType = 0x69646E20, // 'idn '
|
||||
|
||||
// Float to floatPCS
|
||||
Lab2FloatPCS = 0x64326C20, // 'd2l '
|
||||
FloatPCS2Lab = 0x6C326420, // 'l2d '
|
||||
XYZ2FloatPCS = 0x64327820, // 'd2x '
|
||||
FloatPCS2XYZ = 0x78326420, // 'x2d '
|
||||
ClipNegativesElemType = 0x636c7020 // 'clp '
|
||||
}
|
||||
|
||||
public struct cmsViewingConditions
|
||||
{
|
||||
public const int AVG_SURROUND = 1;
|
||||
public const int DIM_SURROUND = 2;
|
||||
public const int DARK_SURROUND = 3;
|
||||
public const int CUTSHEET_SURROUND = 4;
|
||||
|
||||
public const double D_CALCULATE = (-1);
|
||||
|
||||
public CIEXYZ whitePoint;
|
||||
public double Yb;
|
||||
public double La;
|
||||
public uint surround;
|
||||
public double D_value;
|
||||
}
|
||||
|
||||
public enum CmsError
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
FILE = 1,
|
||||
RANGE = 2,
|
||||
INTERNAL = 3,
|
||||
NULL = 4,
|
||||
READ = 5,
|
||||
SEEK = 6,
|
||||
WRITE = 7,
|
||||
UNKNOWN_EXTENSION = 8,
|
||||
COLORSPACE_CHECK = 9,
|
||||
ALREADY_DEFINED = 10,
|
||||
BAD_SIGNATURE = 11,
|
||||
CORRUPTION_DETECTED = 12,
|
||||
NOT_SUITABLE = 13,
|
||||
}
|
||||
|
||||
public enum RenderingIntent
|
||||
{
|
||||
// ICC Intents
|
||||
PERCEPTUAL = 0,
|
||||
RELATIVE_COLORIMETRIC = 1,
|
||||
SATURATION = 2,
|
||||
ABSOLUTE_COLORIMETRIC = 3,
|
||||
// Non-ICC intents
|
||||
PRESERVE_K_ONLY_PERCEPTUAL = 10,
|
||||
PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC = 11,
|
||||
PRESERVE_K_ONLY_SATURATION = 12,
|
||||
PRESERVE_K_PLANE_PERCEPTUAL = 13,
|
||||
PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC = 14,
|
||||
PRESERVE_K_PLANE_SATURATION = 15,
|
||||
}
|
||||
|
||||
public enum TransformFlags
|
||||
{
|
||||
NOCACHE = 0x0040, // Inhibit 1-pixel cache
|
||||
NOOPTIMIZE = 0x0100, // Inhibit optimizations
|
||||
NULLTRANSFORM = 0x0200, // Don't transform anyway
|
||||
|
||||
// Proofing flags
|
||||
GAMUTCHECK = 0x1000, // Out of Gamut alarm
|
||||
SOFTPROOFING = 0x4000, // Do softproofing
|
||||
|
||||
// Misc
|
||||
BLACKPOINTCOMPENSATION = 0x2000,
|
||||
NOWHITEONWHITEFIXUP = 0x0004, // Don't fix scum dot
|
||||
HIGHRESPRECALC = 0x0400, // Use more memory to give better accuracy
|
||||
LOWRESPRECALC = 0x0800, // Use less memory to minimize resources
|
||||
|
||||
// For devicelink creation
|
||||
DEVICELINK_8BITS = 0x0008, // Create 8 bits devicelinks
|
||||
GUESSDEVICECLASS = 0x0020, // Guess device class (for transform2devicelink)
|
||||
KEEP_SEQUENCE = 0x0080, // Keep profile sequence for devicelink creation
|
||||
|
||||
// Specific to a particular optimizations
|
||||
FORCE_CLUT = 0x0002, // Force CLUT optimization
|
||||
CLUT_POST_LINEARIZATION = 0x0001, // create postlinearization tables if possible
|
||||
CLUT_PRE_LINEARIZATION = 0x0010, // create prelinearization tables if possible
|
||||
|
||||
// Specific to unbounded mode
|
||||
NONEGATIVES = 0x8000, // Prevent negative numbers in floating point transforms
|
||||
|
||||
// Copy alpha channels when transforming
|
||||
COPY_ALPHA = 0x04000000,
|
||||
|
||||
// Fine-tune control over number of gridpoints
|
||||
// #define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16)
|
||||
|
||||
// CRD special
|
||||
NODEFAULTRESOURCEDEF = 0x01000000
|
||||
}
|
||||
|
||||
public enum PSResourceType
|
||||
{
|
||||
CSA,
|
||||
CRD
|
||||
}
|
||||
|
||||
public enum PixelType
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't check colorspace
|
||||
/// </summary>
|
||||
ANY = 0,
|
||||
|
||||
// 1 & 2 are reserved
|
||||
|
||||
GRAY = 3,
|
||||
RGB = 4,
|
||||
CMY = 5,
|
||||
CMYK = 6,
|
||||
YCbCr = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Lu'v'
|
||||
/// </summary>
|
||||
YUV = 8,
|
||||
|
||||
XYZ = 9,
|
||||
Lab = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Lu'v'K
|
||||
/// </summary>
|
||||
YUVK = 11,
|
||||
|
||||
HSV = 12,
|
||||
HLS = 13,
|
||||
Yxy = 14,
|
||||
MCH1 = 15,
|
||||
MCH2 = 16,
|
||||
MCH3 = 17,
|
||||
MCH4 = 18,
|
||||
MCH5 = 19,
|
||||
MCH6 = 20,
|
||||
MCH7 = 21,
|
||||
MCH8 = 22,
|
||||
MCH9 = 23,
|
||||
MCH10 = 24,
|
||||
MCH11 = 25,
|
||||
MCH12 = 26,
|
||||
MCH13 = 27,
|
||||
MCH14 = 28,
|
||||
MCH15 = 29,
|
||||
LabV2 = 30,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public class CmsException : Exception
|
||||
{
|
||||
public CmsError CmsError { get; }
|
||||
public CmsException() : base("Error occurred in lcms2") { CmsError = CmsError.UNDEFINED; }
|
||||
public CmsException(CmsError code, string message) : base(message) { CmsError = code; }
|
||||
}
|
||||
|
||||
partial class CmsNative
|
||||
{
|
||||
private static readonly ThreadLocal<CmsException?> LastError;
|
||||
static CmsNative()
|
||||
{
|
||||
var libver = cmsGetEncodedCMMversion();
|
||||
if (libver != LCMS_VERSION)
|
||||
{
|
||||
throw new TypeLoadException("lcms2 version mismatch");
|
||||
}
|
||||
LastError = new();
|
||||
cmsSetLogErrorHandler(ErrorCallback);
|
||||
}
|
||||
|
||||
private static void ErrorCallback(IntPtr ContextID, CmsError ErrorCode, string Text)
|
||||
{
|
||||
LastError.Value = new(ErrorCode, Text);
|
||||
}
|
||||
|
||||
private static void ThrowLastTlsError()
|
||||
{
|
||||
if (LastError.IsValueCreated && LastError.Value != null)
|
||||
{
|
||||
var ex = LastError.Value;
|
||||
LastError.Value = null;
|
||||
throw ex;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CmsException();
|
||||
}
|
||||
}
|
||||
|
||||
public static uint CheckError(uint value)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
ThrowLastTlsError();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void CheckError(bool value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
ThrowLastTlsError();
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr CheckError(IntPtr value)
|
||||
{
|
||||
if (value == IntPtr.Zero)
|
||||
{
|
||||
ThrowLastTlsError();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public unsafe static void* CheckError(void* value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
ThrowLastTlsError();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public static class CmsExtension
|
||||
{
|
||||
|
||||
public static CIExyY ToCIExyY(this CIEXYZ xyz)
|
||||
{
|
||||
return new CIExyY { x = xyz.X / (xyz.X + xyz.Y + xyz.Z), y = xyz.Y / (xyz.X + xyz.Y + xyz.Z), Y = xyz.Y };
|
||||
}
|
||||
public static CIExyY ToXY(this CIEXYZ xyz)
|
||||
{
|
||||
var sum = xyz.X + xyz.Y + xyz.Z;
|
||||
return new() { x = xyz.X / sum, y = xyz.Y / sum, Y = 1 };
|
||||
}
|
||||
|
||||
public static CIEXYZ ToXYZ(this CIExyY xyY)
|
||||
{
|
||||
return new() { X = xyY.x * xyY.Y / xyY.y, Y = xyY.Y, Z = (1 - xyY.x - xyY.y) * xyY.Y / xyY.y };
|
||||
}
|
||||
|
||||
public static int GetChannelCount(this ColorSpaceSignature sig)
|
||||
{
|
||||
return (int)CmsNative.cmsChannelsOf(sig);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public class CmsGlobal
|
||||
{
|
||||
|
||||
public static CIEXYZ D50XYZ { get; } = CmsNative.cmsD50_XYZ();
|
||||
public static CIExyY D50xyY { get; } = CmsNative.cmsD50_xyY();
|
||||
|
||||
|
||||
public unsafe static CIEXYZ AdaptToIlluminant(in CIEXYZ SourceWhitePt, in CIEXYZ Illuminant, in CIEXYZ Value)
|
||||
{
|
||||
CmsNative.CheckError(CmsNative.cmsAdaptToIlluminant(out var result, SourceWhitePt, Illuminant, Value));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,958 @@
|
||||
using LittleCms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0169
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
internal unsafe partial class CmsNative
|
||||
{
|
||||
private const int LCMS_VERSION = 2131;
|
||||
private const string LIB = "lcms2";
|
||||
|
||||
public static readonly Encoding WcharEncoding = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Encoding.Unicode : Encoding.UTF32;
|
||||
|
||||
// Get LittleCMS version (for shared objects) -----------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsGetEncodedCMMversion();
|
||||
|
||||
|
||||
// Context handling --------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility
|
||||
// though using the global context is not recommended. Proper context handling makes lcms more thread-safe.
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateContext(IntPtr Plugin, IntPtr UserData);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsDeleteContext(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsDupContext(IntPtr ContextID, IntPtr NewUserData);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGetContextUserData(IntPtr ContextID);
|
||||
|
||||
// Plug-In registering --------------------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsPlugin(void* Plugin);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsPluginTHR(IntPtr ContextID, void* Plugin);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsUnregisterPlugins();
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsUnregisterPluginsTHR(IntPtr ContextID);
|
||||
|
||||
// Error logging ----------------------------------------------------------------------------------------------------------
|
||||
|
||||
// There is no error handling at all. When a function fails, it returns proper value.
|
||||
// For example, all create functions does return NULL on failure. Other may return FALSE.
|
||||
// It may be interesting, for the developer, to know why the function is failing.
|
||||
// for that reason, lcms2 does offer a logging function. This function will get
|
||||
// an ENGLISH string with some clues on what is going wrong. You can show this
|
||||
// info to the end user if you wish, or just create some sort of log on disk.
|
||||
// The logging function should NOT terminate the program, as this obviously can leave
|
||||
// unfreed resources. It is the programmer's responsibility to check each function
|
||||
// return code to make sure it didn't fail.
|
||||
|
||||
|
||||
// Error logger is called with the ContextID when a message is raised. This gives the
|
||||
// chance to know which thread is responsible of the warning and any environment associated
|
||||
// with it. Non-multithreading applications may safely ignore this parameter.
|
||||
// Note that under certain special circumstances, ContextID may be NULL.
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void cmsLogErrorHandlerFunction(IntPtr ContextID, CmsError ErrorCode, [In, MarshalAs(UnmanagedType.LPStr)] string Text);
|
||||
|
||||
// Allows user to set any specific logger
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetLogErrorHandlerTHR(IntPtr ContextID, cmsLogErrorHandlerFunction Fn);
|
||||
|
||||
// Returns pointers to constant structs
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ref readonly CIEXYZ cmsD50_XYZ();
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ref readonly CIExyY cmsD50_xyY();
|
||||
|
||||
// Colorimetric space conversions
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsXYZ2xyY(out CIExyY Dest, in CIEXYZ Source);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsxyY2XYZ(CIEXYZ* Dest, in CIExyY Source);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsXYZ2Lab(in CIEXYZ WhitePoint, out CIELab Lab, in CIEXYZ xyz);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsLab2XYZ(in CIEXYZ WhitePoint, out CIEXYZ xyz, in CIELab Lab);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsLab2LCh(out CIELCh LCh, in CIELab Lab);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsLCh2Lab(out CIELab Lab, in CIELCh LCh);
|
||||
|
||||
// Encoding /Decoding on PCS
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsLabEncoded2Float(out CIELab Lab, in ushort wLab_3);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsLabEncoded2FloatV2(out CIELab Lab, in ushort wLab_3);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsFloat2LabEncoded(out ushort wLab_3, in CIELab Lab);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsFloat2LabEncodedV2(out ushort wLab_3, in CIELab Lab);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsXYZEncoded2Float(out CIEXYZ fxyz, in ushort XYZ_3);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsFloat2XYZEncoded(out ushort XYZ_3, in CIEXYZ fXYZ);
|
||||
|
||||
|
||||
// DeltaE metrics
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsDeltaE(in CIELab Lab1, in CIELab Lab2);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsCIE94DeltaE(in CIELab Lab1, in CIELab Lab2);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsBFDdeltaE(in CIELab Lab1, in CIELab Lab2);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsCMCdeltaE(in CIELab Lab1, in CIELab Lab2, double l, double c);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsCIE2000DeltaE(in CIELab Lab1, in CIELab Lab2, double Kl, double Kc, double Kh);
|
||||
|
||||
// Temperature <-> Chromaticity (Black body)
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsWhitePointFromTemp(out CIExyY WhitePoint, double TempK);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsTempFromWhitePoint(double* TempK, in CIExyY WhitePoint);
|
||||
|
||||
// Chromatic adaptation
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsAdaptToIlluminant(out CIEXYZ Result, in CIEXYZ SourceWhitePt,
|
||||
in CIEXYZ Illuminant,
|
||||
in CIEXYZ Value);
|
||||
|
||||
// CIECAM02 ---------------------------------------------------------------------------------------------------
|
||||
|
||||
// Viewing conditions. Please note those are CAM model viewing conditions, and not the ICC tag viewing
|
||||
// conditions, which I'm naming cmsICCViewingConditions to make differences evident. Unfortunately, the tag
|
||||
// cannot deal with surround La, Yb and D value so is basically useless to store CAM02 viewing conditions.
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCIECAM02Init(IntPtr ContextID, in cmsViewingConditions pVC);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsCIECAM02Done(IntPtr hModel);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsCIECAM02Forward(IntPtr hModel, in CIEXYZ pIn, out JCh pOut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsCIECAM02Reverse(IntPtr hModel, in JCh pIn, out CIEXYZ pOut);
|
||||
|
||||
|
||||
// Tone curves -----------------------------------------------------------------------------------------
|
||||
|
||||
// This describes a curve segment. For a table of supported types, see the manual. User can increase the number of
|
||||
// available types by using a proper plug-in. Parametric segments allow 10 parameters at most
|
||||
public struct cmsCurveSegment
|
||||
{
|
||||
public float x0, x1; // Domain; for x0 < x <= x1
|
||||
public int Type; // Parametric type, Type == 0 means sampled segment. Negative values are reserved
|
||||
public fixed double Params[10]; // Parameters if Type != 0
|
||||
public uint nGridPoints; // Number of grid points if Type == 0
|
||||
public float* SampledPoints; // Points to an array of floats if Type == 0
|
||||
}
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsBuildSegmentedToneCurve(IntPtr ContextID, uint nSegments, in cmsCurveSegment Segments);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsBuildParametricToneCurve(IntPtr ContextID, int Type, in double Params);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsBuildGamma(IntPtr ContextID, double Gamma);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsBuildTabulatedToneCurve16(IntPtr ContextID, uint nEntries, in ushort values);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsBuildTabulatedToneCurveFloat(IntPtr ContextID, uint nEntries, in float values);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsFreeToneCurve(IntPtr Curve);
|
||||
//[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
//public static extern void cmsFreeToneCurveTriple(IntPtr Curve[3]);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsDupToneCurve(IntPtr Src);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsReverseToneCurve(IntPtr InGamma);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsReverseToneCurveEx(uint nResultSamples, IntPtr InGamma);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsJoinToneCurve(IntPtr ContextID, IntPtr X, IntPtr Y, uint nPoints);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsSmoothToneCurve(IntPtr Tab, double lambda);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern float cmsEvalToneCurveFloat(IntPtr Curve, float v);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ushort cmsEvalToneCurve16(IntPtr Curve, ushort v);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsToneCurveMultisegment(IntPtr InGamma);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsToneCurveLinear(IntPtr Curve);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsToneCurveMonotonic(IntPtr t);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsToneCurveDescending(IntPtr t);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsGetToneCurveParametricType(IntPtr t);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsEstimateGamma(IntPtr t, double Precision);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ref readonly double cmsGetToneCurveParams(IntPtr t);
|
||||
|
||||
// Tone curve tabular estimation
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetToneCurveEstimatedTableEntries(IntPtr t);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ref readonly ushort cmsGetToneCurveEstimatedTable(IntPtr t);
|
||||
|
||||
// Implements pipelines of multi-processing elements -------------------------------------------------------------
|
||||
|
||||
// Those are hi-level pipelines
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsPipelineAlloc(IntPtr ContextID, uint InputChannels, uint OutputChannels);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsPipelineFree(IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsPipelineDup(IntPtr Orig);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGetPipelineContextID(IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsPipelineInputChannels(IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsPipelineOutputChannels(IntPtr lut);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsPipelineStageCount(IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsPipelineGetPtrToFirstStage(IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsPipelineGetPtrToLastStage(IntPtr lut);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsPipelineEval16(in ushort In, out ushort Out, IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsPipelineEvalFloat(in float In, out float Out, IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsPipelineEvalReverseFloat(ref float Target, ref float Result, ref float Hint, IntPtr lut);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsPipelineCat(IntPtr l1, IntPtr l2);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsPipelineSetSaveAs8bitsFlag(IntPtr lut, bool On);
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal unsafe partial class CmsNative
|
||||
{
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsPipelineInsertStage(IntPtr lut, StageLoc loc, IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsPipelineUnlinkStage(IntPtr lut, StageLoc loc, out IntPtr mpe);
|
||||
|
||||
// This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements
|
||||
// that conform the Pipeline. It should be called with the Pipeline, the number of expected elements and
|
||||
// then a list of expected types followed with a list of double pointers to Stage elements. If
|
||||
// the function founds a match with current pipeline, it fills the pointers and returns TRUE
|
||||
// if not, returns FALSE without touching anything.
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern bool cmsPipelineCheckAndRetreiveStages(IntPtr Lut, uint n, __arglist);
|
||||
|
||||
// Matrix has double precision and CLUT has only float precision. That is because an ICC profile can encode
|
||||
// matrices with far more precision that CLUTS
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocIdentity(IntPtr ContextID, uint nChannels);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocToneCurves(IntPtr ContextID, uint nChannels, in IntPtr Curves);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocMatrix(IntPtr ContextID, uint Rows, uint Cols, in double Matrix, in double Offset);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocCLut16bit(IntPtr ContextID, uint nGridPoints, uint inputChan, uint outputChan, in ushort Table);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocCLutFloat(IntPtr ContextID, uint nGridPoints, uint inputChan, uint outputChan, in float Table);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocCLut16bitGranular(IntPtr ContextID, in uint clutPoints, uint inputChan, uint outputChan, in ushort Table);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageAllocCLutFloatGranular(IntPtr ContextID, in uint clutPoints, uint inputChan, uint outputChan, in float Table);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageDup(IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsStageFree(IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageNext(IntPtr mpe);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsStageInputChannels(IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsStageOutputChannels(IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern StageSignature cmsStageType(IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsStageData(IntPtr mpe);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGetStageContextID(IntPtr mpe);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int cmsSAMPLER16(ushort* In, ushort* Out, IntPtr Cargo);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int cmsSAMPLERFLOAT(float* In, float* Out, IntPtr Cargo);
|
||||
|
||||
const uint SAMPLER_INSPECT = 0x01000000;
|
||||
|
||||
// For CLUT only
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsStageSampleCLut16bit(IntPtr mpe, cmsSAMPLER16 Sampler, void* Cargo, uint dwFlags);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsStageSampleCLutFloat(IntPtr mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, uint dwFlags);
|
||||
|
||||
// Slicers
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsSliceSpace16(uint nInputs, in uint clutPoints,
|
||||
cmsSAMPLER16 Sampler, void* Cargo);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsSliceSpaceFloat(uint nInputs, in uint clutPoints,
|
||||
cmsSAMPLERFLOAT Sampler, void* Cargo);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsMLUalloc(IntPtr ContextID, uint nItems);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsMLUfree(IntPtr mlu);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsMLUdup(IntPtr mlu);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, CharSet = CharSet.Ansi)]
|
||||
public static extern bool cmsMLUsetASCII(IntPtr mlu,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
string ASCIIString);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsMLUsetWide(IntPtr mlu,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
in byte WideString);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsMLUgetASCII(IntPtr mlu,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
byte* Buffer, uint BufferSize);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsMLUgetWide(IntPtr mlu,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
byte* Buffer, uint BufferSize);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsMLUgetTranslation(IntPtr mlu,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
ref byte ObtainedLanguage_3, ref byte ObtainedCountry_3);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsMLUtranslationsCount(IntPtr mlu);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsMLUtranslationsCodes(IntPtr mlu,
|
||||
uint idx,
|
||||
ref byte LanguageCode_3,
|
||||
ref byte CountryCode_3);
|
||||
|
||||
|
||||
struct cmsUcrBg
|
||||
{
|
||||
IntPtr UcrToneCurve;
|
||||
IntPtr BgToneCurve;
|
||||
IntPtr DescMLU;
|
||||
}
|
||||
|
||||
public const int cmsPRINTER_DEFAULT_SCREENS = 0x0001;
|
||||
public const int cmsFREQUENCE_UNITS_LINES_CM = 0x0000;
|
||||
public const int cmsFREQUENCE_UNITS_LINES_INCH = 0x0002;
|
||||
|
||||
|
||||
public struct cmsDICTentry
|
||||
{
|
||||
public cmsDICTentry* Next;
|
||||
IntPtr DisplayNameMLU;
|
||||
IntPtr DisplayValueMLU;
|
||||
byte* NameWcharT;
|
||||
byte* ValueWcharT;
|
||||
}
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsDictAlloc(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsDictFree(IntPtr hDict);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsDictDup(IntPtr hDict);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsDictAddEntry(IntPtr hDict, void* Name, void* Value, IntPtr DisplayNameMLU, IntPtr DisplayValueMLU);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern cmsDICTentry* cmsDictGetEntryList(IntPtr hDict);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern cmsDICTentry* cmsDictNextEntry(cmsDICTentry* e);
|
||||
|
||||
// Access to Profile data ----------------------------------------------------------------------------------------------
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateProfilePlaceholder(IntPtr ContextID);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGetProfileContextID(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsGetTagCount(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern TagSignature cmsGetTagSignature(IntPtr hProfile, uint n);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsTag(IntPtr hProfile, TagSignature sig);
|
||||
|
||||
// Read and write pre-formatted data
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void* cmsReadTag(IntPtr hProfile, TagSignature sig);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsWriteTag(IntPtr hProfile, TagSignature sig, void* data);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsLinkTag(IntPtr hProfile, TagSignature sig, TagSignature dest);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern TagSignature cmsTagLinkedTo(IntPtr hProfile, TagSignature sig);
|
||||
|
||||
// Read and write raw data
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsReadRawTag(IntPtr hProfile, TagSignature sig, void* Buffer, uint BufferSize);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsWriteRawTag(IntPtr hProfile, TagSignature sig, in byte data, uint Size);
|
||||
|
||||
|
||||
// Access header data
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern HeaderFlags cmsGetHeaderFlags(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsGetHeaderAttributes(IntPtr hProfile, out ulong Flags);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsGetHeaderProfileID(IntPtr hProfile, out Guid ProfileID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsGetHeaderCreationDateTime(IntPtr hProfile, out CmsStructTm Dest);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetHeaderRenderingIntent(IntPtr hProfile);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetHeaderFlags(IntPtr hProfile, HeaderFlags Flags);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetHeaderManufacturer(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetHeaderManufacturer(IntPtr hProfile, uint manufacturer);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetHeaderCreator(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetHeaderModel(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetHeaderModel(IntPtr hProfile, uint model);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetHeaderAttributes(IntPtr hProfile, ulong Flags);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetHeaderProfileID(IntPtr hProfile, in Guid ProfileID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetHeaderRenderingIntent(IntPtr hProfile, uint RenderingIntent);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ColorSpaceSignature
|
||||
cmsGetPCS(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetPCS(IntPtr hProfile, ColorSpaceSignature pcs);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ColorSpaceSignature
|
||||
cmsGetColorSpace(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetColorSpace(IntPtr hProfile, ColorSpaceSignature sig);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ProfileClassSignature
|
||||
cmsGetDeviceClass(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetDeviceClass(IntPtr hProfile, ProfileClassSignature sig);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetProfileVersion(IntPtr hProfile, double Version);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsGetProfileVersion(IntPtr hProfile);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetEncodedICCversion(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetEncodedICCversion(IntPtr hProfile, uint Version);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsIntentSupported(IntPtr hProfile, uint Intent, ProfileUsedDirection UsedDirection);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsMatrixShaper(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIsCLUT(IntPtr hProfile, uint Intent, ProfileUsedDirection UsedDirection);
|
||||
|
||||
// Translate form/to our notation to ICC
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern ColorSpaceSignature _cmsICCcolorSpace(int OurNotation);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int _cmsLCMScolorSpace(ColorSpaceSignature ProfileSpace);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsChannelsOf(ColorSpaceSignature ColorSpace);
|
||||
|
||||
// Build a suitable formatter for the colorspace of this profile. nBytes=1 means 8 bits, nBytes=2 means 16 bits.
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsFormatterForColorspaceOfProfile(IntPtr hProfile, uint nBytes, bool lIsFloat);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsFormatterForPCSOfProfile(IntPtr hProfile, uint nBytes, bool lIsFloat);
|
||||
|
||||
// Localized info
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetProfileInfo(IntPtr hProfile, InfoType Info,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
void* Buffer, uint BufferSize);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetProfileInfoASCII(IntPtr hProfile, InfoType Info,
|
||||
in uint LanguageCode, in uint CountryCode,
|
||||
byte* Buffer, uint BufferSize);
|
||||
|
||||
// MD5 message digest --------------------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsMD5computeID(IntPtr hProfile);
|
||||
|
||||
// IO handlers ----------------------------------------------------------------------------------------------------------
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr cmsOpenIOhandlerFromMem(IntPtr ContextID, void* Buffer, uint size, string AccessMode);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsOpenIOhandlerFromNULL(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGetProfileIOhandler(IntPtr hProfile);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsCloseIOhandler(IntPtr io);
|
||||
|
||||
|
||||
// Profile high level functions ------------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsOpenProfileFromMem(void* MemPtr, uint dwSize);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsOpenProfileFromMemTHR(IntPtr ContextID, void* MemPtr, uint dwSize);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsOpenProfileFromIOhandlerTHR(IntPtr ContextID, IntPtr io);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsOpenProfileFromIOhandler2THR(IntPtr ContextID, IntPtr io, bool write);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsCloseProfile(IntPtr hProfile);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsSaveProfileToMem(IntPtr hProfile, void* MemPtr, ref uint BytesNeeded);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsSaveProfileToIOhandler(IntPtr hProfile, IntPtr io);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateRGBProfileTHR(IntPtr ContextID,
|
||||
in CIExyY WhitePoint,
|
||||
in CIExyYTRIPLE Primaries,
|
||||
ref IntPtr TransferFunction3);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateRGBProfile(in CIExyY WhitePoint,
|
||||
in CIExyYTRIPLE Primaries,
|
||||
ref IntPtr TransferFunction);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateGrayProfileTHR(IntPtr ContextID,
|
||||
in CIExyY WhitePoint,
|
||||
IntPtr TransferFunction);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateGrayProfile(in CIExyY WhitePoint,
|
||||
IntPtr TransferFunction);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateLinearizationDeviceLinkTHR(IntPtr ContextID,
|
||||
ColorSpaceSignature ColorSpace,
|
||||
ref IntPtr TransferFunctions);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateLinearizationDeviceLink(ColorSpaceSignature ColorSpace,
|
||||
ref IntPtr TransferFunctions);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateInkLimitingDeviceLinkTHR(IntPtr ContextID,
|
||||
ColorSpaceSignature ColorSpace, double Limit);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateInkLimitingDeviceLink(ColorSpaceSignature ColorSpace, double Limit);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateLab2ProfileTHR(IntPtr ContextID, in CIExyY WhitePoint);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateLab2Profile(in CIExyY WhitePoint);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateLab4ProfileTHR(IntPtr ContextID, in CIExyY WhitePoint);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateLab4Profile(in CIExyY WhitePoint);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateXYZProfileTHR(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateXYZProfile();
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreate_sRGBProfileTHR(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreate_sRGBProfile();
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateBCHSWabstractProfileTHR(IntPtr ContextID,
|
||||
uint nLUTPoints,
|
||||
double Bright,
|
||||
double Contrast,
|
||||
double Hue,
|
||||
double Saturation,
|
||||
uint TempSrc,
|
||||
uint TempDest);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateBCHSWabstractProfile(uint nLUTPoints,
|
||||
double Bright,
|
||||
double Contrast,
|
||||
double Hue,
|
||||
double Saturation,
|
||||
uint TempSrc,
|
||||
uint TempDest);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateNULLProfileTHR(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateNULLProfile();
|
||||
|
||||
// Converts a transform to a devicelink profile
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsTransform2DeviceLink(IntPtr hTransform, double Version, uint dwFlags);
|
||||
|
||||
// Call with NULL as parameters to get the intent count
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetSupportedIntents(uint nMax, uint* Codes, byte** Descriptions);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetSupportedIntentsTHR(IntPtr ContextID, uint nMax, uint* Codes, byte** Descriptions);
|
||||
|
||||
|
||||
// Transforms ---------------------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateTransformTHR(IntPtr ContextID,
|
||||
IntPtr Input,
|
||||
uint InputFormat,
|
||||
IntPtr Output,
|
||||
uint OutputFormat,
|
||||
uint Intent,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateTransform(IntPtr Input,
|
||||
uint InputFormat,
|
||||
IntPtr Output,
|
||||
uint OutputFormat,
|
||||
uint Intent,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateProofingTransformTHR(IntPtr ContextID,
|
||||
IntPtr Input,
|
||||
uint InputFormat,
|
||||
IntPtr Output,
|
||||
uint OutputFormat,
|
||||
IntPtr Proofing,
|
||||
uint Intent,
|
||||
uint ProofingIntent,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateProofingTransform(IntPtr Input,
|
||||
uint InputFormat,
|
||||
IntPtr Output,
|
||||
uint OutputFormat,
|
||||
IntPtr Proofing,
|
||||
uint Intent,
|
||||
uint ProofingIntent,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateMultiprofileTransformTHR(IntPtr ContextID,
|
||||
ref IntPtr hProfiles,
|
||||
uint nProfiles,
|
||||
uint InputFormat,
|
||||
uint OutputFormat,
|
||||
uint Intent,
|
||||
uint dwFlags);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateMultiprofileTransform(ref IntPtr hProfiles,
|
||||
uint nProfiles,
|
||||
uint InputFormat,
|
||||
uint OutputFormat,
|
||||
uint Intent,
|
||||
uint dwFlags);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsCreateExtendedTransform(IntPtr ContextID,
|
||||
uint nProfiles, ref IntPtr hProfiles,
|
||||
ref bool BPC,
|
||||
ref uint Intents,
|
||||
ref double AdaptationStates,
|
||||
IntPtr hGamutProfile,
|
||||
uint nGamutPCSposition,
|
||||
uint InputFormat,
|
||||
uint OutputFormat,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsDeleteTransform(IntPtr hTransform);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsDoTransform(IntPtr Transform,
|
||||
void* InputBuffer,
|
||||
void* OutputBuffer,
|
||||
uint Size);
|
||||
|
||||
[Obsolete]
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsDoTransformStride(IntPtr Transform, // Deprecated
|
||||
void* InputBuffer,
|
||||
void* OutputBuffer,
|
||||
uint Size,
|
||||
uint Stride);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsDoTransformLineStride(IntPtr Transform,
|
||||
void* InputBuffer,
|
||||
void* OutputBuffer,
|
||||
uint PixelsPerLine,
|
||||
uint LineCount,
|
||||
uint BytesPerLineIn,
|
||||
uint BytesPerLineOut,
|
||||
uint BytesPerPlaneIn,
|
||||
uint BytesPerPlaneOut);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetAlarmCodes(ref ushort NewAlarm_cmsMAXCHANNELS);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsGetAlarmCodes(ref ushort NewAlarm_cmsMAXCHANNELS);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsSetAlarmCodesTHR(IntPtr ContextID,
|
||||
ref ushort NewAlarm_cmsMAXCHANNELS);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsGetAlarmCodesTHR(IntPtr ContextID,
|
||||
ref ushort NewAlarm_cmsMAXCHANNELS);
|
||||
|
||||
|
||||
|
||||
// Adaptation state for absolute colorimetric intent
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsSetAdaptationState(double d);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsSetAdaptationStateTHR(IntPtr ContextID, double d);
|
||||
|
||||
|
||||
|
||||
// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGetTransformContextID(IntPtr hTransform);
|
||||
|
||||
// Grab the input/output formats
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetTransformInputFormat(IntPtr hTransform);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetTransformOutputFormat(IntPtr hTransform);
|
||||
|
||||
// For backwards compatibility
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsChangeBuffersFormat(IntPtr hTransform,
|
||||
uint InputFormat,
|
||||
uint OutputFormat);
|
||||
|
||||
// PostScript ColorRenderingDictionary and ColorSpaceArray ----------------------------------------------------
|
||||
|
||||
// lcms2 unified method to access postscript color resources
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetPostScriptColorResource(IntPtr ContextID,
|
||||
PSResourceType Type,
|
||||
IntPtr hProfile,
|
||||
uint Intent,
|
||||
uint dwFlags,
|
||||
IntPtr io);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetPostScriptCSA(IntPtr ContextID, IntPtr hProfile, uint Intent, uint dwFlags, void* Buffer, uint dwBufferLen);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsGetPostScriptCRD(IntPtr ContextID, IntPtr hProfile, uint Intent, uint dwFlags, void* Buffer, uint dwBufferLen);
|
||||
|
||||
|
||||
// IT8.7 / CGATS.17-200x handling -----------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsIT8Alloc(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsIT8Free(IntPtr hIT8);
|
||||
|
||||
// Tables
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsIT8TableCount(IntPtr hIT8);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsIT8SetTable(IntPtr hIT8, uint nTable);
|
||||
|
||||
// Persistence
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsIT8LoadFromMem(IntPtr ContextID, void* Ptr, uint len);
|
||||
//[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
//public static extern IntPtr cmsIT8LoadFromIOhandler(IntPtr ContextID, IntPtr io);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SaveToMem(IntPtr hIT8, void* MemPtr, uint* BytesNeeded);
|
||||
|
||||
// Properties
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||
public static extern string cmsIT8GetSheetType(IntPtr hIT8);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetSheetType(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Type);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetComment(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cComment);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetPropertyStr(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cProp, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Str);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetPropertyDbl(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cProp, double Val);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetPropertyHex(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cProp, uint Val);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetPropertyMulti(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Key, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string SubKey, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Buffer);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetPropertyUncooked(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Key, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Buffer);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
public static extern string cmsIT8GetProperty(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cProp);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsIT8GetPropertyDbl(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cProp);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
public static extern string cmsIT8GetPropertyMulti(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Key, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string SubKey);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsIT8EnumProperties(IntPtr hIT8, out byte** PropertyNames);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint cmsIT8EnumPropertyMulti(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cProp, out byte** SubpropertyNames);
|
||||
|
||||
// Datasets
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
public static extern string cmsIT8GetDataRowCol(IntPtr hIT8, int row, int col);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsIT8GetDataRowColDbl(IntPtr hIT8, int row, int col);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetDataRowCol(IntPtr hIT8, int row, int col,
|
||||
[In, MarshalAs(UnmanagedType.LPUTF8Str)] string Val);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetDataRowColDbl(IntPtr hIT8, int row, int col,
|
||||
double Val);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
public static extern string cmsIT8GetData(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cPatch, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSample);
|
||||
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsIT8GetDataDbl(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cPatch, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSample);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetData(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cPatch,
|
||||
[In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSample,
|
||||
[In, MarshalAs(UnmanagedType.LPUTF8Str)] string Val);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetDataDbl(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cPatch,
|
||||
[In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSample,
|
||||
double Val);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsIT8FindDataFormat(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSample);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetDataFormat(IntPtr hIT8, int n, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Sample);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsIT8EnumDataFormat(IntPtr hIT8, out byte** SampleNames);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
public static extern string cmsIT8GetPatchName(IntPtr hIT8, int nPatch, void* buffer);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsIT8GetPatchByName(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cPatch);
|
||||
|
||||
// The LABEL extension
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern int cmsIT8SetTableByLabel(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSet, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cField, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string ExpectedType);
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsIT8SetIndexColumn(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string cSample);
|
||||
|
||||
// Formatter for double
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsIT8DefineDblFormat(IntPtr hIT8, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string Formatter);
|
||||
|
||||
|
||||
// Gamut boundary description routines ------------------------------------------------------------------------------
|
||||
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern IntPtr cmsGBDAlloc(IntPtr ContextID);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern void cmsGBDFree(IntPtr hGBD);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsGDBAddPoint(IntPtr hGBD, in CIELab Lab);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsGDBCompute(IntPtr hGDB, uint dwFlags);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsGDBCheckPoint(IntPtr hGBD, in CIELab Lab);
|
||||
|
||||
// Feature detection ----------------------------------------------------------------------------------------------
|
||||
|
||||
// Estimate the black point
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsDetectBlackPoint(out CIEXYZ BlackPoint, IntPtr hProfile, uint Intent, uint dwFlags);
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsDetectDestinationBlackPoint(out CIEXYZ BlackPoint, IntPtr hProfile, uint Intent, uint dwFlags);
|
||||
|
||||
// Estimate total area coverage
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsDetectTAC(IntPtr hProfile);
|
||||
|
||||
// Estimate gamma space, always positive. Returns -1 on error.
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern double cmsDetectRGBProfileGamma(IntPtr hProfile, double threshold);
|
||||
|
||||
// Poor man's gamut mapping
|
||||
[DllImport(LIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern bool cmsDesaturateLab(ref CIELab Lab,
|
||||
double amax, double amin,
|
||||
double bmax, double bmin);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public abstract class CmsObject
|
||||
{
|
||||
private IntPtr handle;
|
||||
private bool isOwner;
|
||||
|
||||
public IntPtr Handle => handle;
|
||||
public bool IsOwner => isOwner;
|
||||
|
||||
public abstract CmsContext Context { get; }
|
||||
|
||||
|
||||
protected CmsObject() { }
|
||||
|
||||
protected CmsObject(IntPtr handle, bool moveOwnership)
|
||||
{
|
||||
AttachObject(handle, isOwner);
|
||||
}
|
||||
|
||||
|
||||
protected void AttachObject(IntPtr handle, bool moveOwnership)
|
||||
{
|
||||
if (handle != IntPtr.Zero && isOwner)
|
||||
{
|
||||
FreeObject();
|
||||
}
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
this.handle = handle;
|
||||
this.isOwner = moveOwnership;
|
||||
}
|
||||
|
||||
~CmsObject() {
|
||||
if (handle != IntPtr.Zero && isOwner) {
|
||||
FreeObject();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void FreeObject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public struct CmsPixelFormat
|
||||
{
|
||||
public uint Value;
|
||||
|
||||
public static implicit operator uint(CmsPixelFormat x) => x.Value;
|
||||
|
||||
// boolean fields
|
||||
const int shift_IsPremultipliedAlpha = 23;
|
||||
const int shift_IsFloatingPoint = 22;
|
||||
const int shift_IsOptimized = 21;
|
||||
const int shift_RotateFirstChannel = 14;
|
||||
const int shift_IsInvertedIntensity = 13;
|
||||
const int shift_IsPlanar = 12;
|
||||
const int shift_IsWordOrderSwapped = 11;
|
||||
const int shift_IsByteOrderSwapped = 10;
|
||||
|
||||
// enum fields
|
||||
const uint mask_PixelType = 0b11111u;
|
||||
const int shift_PixelType = 16;
|
||||
|
||||
// uint fields
|
||||
const uint mask_ExtraChannels = 0b111u;
|
||||
const int shift_ExtraChannels = 7;
|
||||
const uint mask_Channels = 0b1111u;
|
||||
const int shift_Channels = 3;
|
||||
const uint mask_BytesPerChannel = 0b111;
|
||||
const int shift_BytesPerChannel = 0;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool GetBit(int shift)
|
||||
{
|
||||
var mask = 1u << shift;
|
||||
return (Value & mask) != 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void SetBit(int shift, bool value)
|
||||
{
|
||||
var mask = 1u << shift;
|
||||
Value = (Value & (~mask)) | (value ? mask : 0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private uint GetBits(int shift, uint mask) => (Value >> shift) & mask;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void SetBits(int shift, uint mask, uint value)
|
||||
{
|
||||
var smask = mask << shift;
|
||||
value = (value & mask) << shift;
|
||||
Value = (Value & (~smask)) | value;
|
||||
}
|
||||
|
||||
|
||||
public bool IsPremultipliedAlpha
|
||||
{
|
||||
get => GetBit(shift_IsPremultipliedAlpha);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsPremultipliedAlpha, value);
|
||||
}
|
||||
|
||||
public bool IsFloatingPoint
|
||||
{
|
||||
get => GetBit(shift_IsFloatingPoint);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsFloatingPoint, value);
|
||||
}
|
||||
public bool IsOptimized
|
||||
{
|
||||
get => GetBit(shift_IsOptimized);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsOptimized, value);
|
||||
}
|
||||
public bool RotateFirstChannel
|
||||
{
|
||||
get => GetBit(shift_RotateFirstChannel);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_RotateFirstChannel, value);
|
||||
}
|
||||
public bool IsPlanar
|
||||
{
|
||||
get => GetBit(shift_IsPlanar);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsPlanar, value);
|
||||
}
|
||||
public bool IsInvertedIntensity
|
||||
{
|
||||
get => GetBit(shift_IsInvertedIntensity);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsInvertedIntensity, value);
|
||||
}
|
||||
public bool IsWordOrderSwapped
|
||||
{
|
||||
get => GetBit(shift_IsWordOrderSwapped);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsWordOrderSwapped, value);
|
||||
}
|
||||
public bool IsByteOrderSwapped
|
||||
{
|
||||
get => GetBit(shift_IsByteOrderSwapped);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBit(shift_IsByteOrderSwapped, value);
|
||||
}
|
||||
|
||||
public PixelType PixelType
|
||||
{
|
||||
get => (PixelType)GetBits(shift_PixelType, mask_PixelType);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBits(shift_PixelType, mask_PixelType, (uint)value);
|
||||
}
|
||||
public int ExtraChannels
|
||||
{
|
||||
get => (int)GetBits(shift_ExtraChannels, mask_ExtraChannels);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBits(shift_ExtraChannels, mask_ExtraChannels, (uint)value);
|
||||
}
|
||||
public int Channels
|
||||
{
|
||||
get => (int)GetBits(shift_Channels, mask_Channels);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBits(shift_Channels, mask_Channels, (uint)value);
|
||||
}
|
||||
/// <summary>
|
||||
/// use 0 for double-precision IEEE-754 floating point.
|
||||
/// </summary>
|
||||
public int BytesPerChannel
|
||||
{
|
||||
get => (int)GetBits(shift_BytesPerChannel, mask_BytesPerChannel);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => SetBits(shift_BytesPerChannel, mask_BytesPerChannel, (uint)value);
|
||||
}
|
||||
|
||||
|
||||
public static CmsPixelFormat RGB8 => new CmsPixelFormat { PixelType = PixelType.RGB, Channels = 3, BytesPerChannel = 1 };
|
||||
public static CmsPixelFormat RGBDouble => new CmsPixelFormat { PixelType = PixelType.RGB, Channels = 3, BytesPerChannel = 0, IsFloatingPoint = true };
|
||||
public static CmsPixelFormat XYZDouble => new CmsPixelFormat { PixelType = PixelType.XYZ, Channels = 3, BytesPerChannel = 0, IsFloatingPoint = true };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using static LittleCms.CmsNative;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public class CmsTransform : CmsObject
|
||||
{
|
||||
private IccProfile inputProfile;
|
||||
private IccProfile outputProfile;
|
||||
public override CmsContext Context { get; }
|
||||
public CmsTransform(IccProfile inputProfile, CmsPixelFormat inputFormat,
|
||||
IccProfile outputProfile, CmsPixelFormat outputFormat,
|
||||
RenderingIntent intent, TransformFlags flags) : this(CmsContext.Default, inputProfile, inputFormat, outputProfile, outputFormat, intent, flags) { }
|
||||
|
||||
public CmsTransform(CmsContext context, IccProfile inputProfile, CmsPixelFormat inputFormat,
|
||||
IccProfile outputProfile, CmsPixelFormat outputFormat,
|
||||
RenderingIntent intent, TransformFlags flags)
|
||||
{
|
||||
this.Context = context;
|
||||
this.inputProfile = inputProfile;
|
||||
this.outputProfile = outputProfile;
|
||||
|
||||
var handle = CheckError(cmsCreateTransformTHR(context.Handle, inputProfile.Handle, inputFormat, outputProfile.Handle, outputFormat, (uint)intent, (uint)flags));
|
||||
AttachObject(handle, true);
|
||||
}
|
||||
|
||||
|
||||
protected override void FreeObject()
|
||||
{
|
||||
cmsDeleteTransform(Handle);
|
||||
}
|
||||
|
||||
public unsafe void DoTransform<TIn, TOut>(ReadOnlySpan<TIn> input, Span<TOut> output, uint pixelsToTransform) where TIn : unmanaged where TOut : unmanaged
|
||||
{
|
||||
fixed (TIn* inptr = input)
|
||||
fixed (TOut* outptr = output)
|
||||
cmsDoTransform(Handle, inptr, outptr, pixelsToTransform);
|
||||
}
|
||||
|
||||
public unsafe void DoTransform<TIn, TOut>(ReadOnlySpan<TIn> input, Span<TOut> output, uint pixelsPerLine, uint lineCount,
|
||||
uint bytesPerLineIn, uint bytesPerLineOut, uint bytesPerPlaneIn, uint bytesPerPlaneOut) where TIn : unmanaged where TOut : unmanaged
|
||||
{
|
||||
fixed (TIn* inptr = input)
|
||||
fixed (TOut* outptr = output)
|
||||
cmsDoTransformLineStride(Handle, inptr, outptr, pixelsPerLine, lineCount, bytesPerLineIn, bytesPerLineOut, bytesPerPlaneIn, bytesPerPlaneOut);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
internal record BlittableDataTag<T>(TagSignature TagSignature) : ISafeTagSignature<T> where T : unmanaged
|
||||
{
|
||||
public unsafe T ReadFromProfile(IccProfile profile)
|
||||
{
|
||||
var ptr = profile.ReadTag(TagSignature);
|
||||
if (ptr == null) throw new TagNotFoundException();
|
||||
return *(T*)ptr;
|
||||
}
|
||||
|
||||
public unsafe void WriteToProfile(IccProfile profile, T data)
|
||||
{
|
||||
profile.WriteTag(TagSignature, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
internal class ChromaticAdaptationTagSignature : ISafeTagSignature<double[,]>
|
||||
{
|
||||
public TagSignature TagSignature => TagSignature.ChromaticAdaptationTag;
|
||||
|
||||
public unsafe double[,] ReadFromProfile(IccProfile profile)
|
||||
{
|
||||
var ptr = (double*)profile.ReadTag(TagSignature);
|
||||
if (ptr == null) throw new TagNotFoundException();
|
||||
var result = new double[3, 3];
|
||||
new ReadOnlySpan<double>(ptr, 9).CopyTo(MemoryMarshal.CreateSpan(ref result[0, 0], 9));
|
||||
return result;
|
||||
}
|
||||
|
||||
public unsafe void WriteToProfile(IccProfile profile, double[,] data)
|
||||
{
|
||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||
fixed (double* ptr = &data[0, 0])
|
||||
profile.WriteTag(TagSignature, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
public interface ISafeTagSignature<T>
|
||||
{
|
||||
TagSignature TagSignature { get; }
|
||||
T ReadFromProfile(IccProfile profile);
|
||||
void WriteToProfile(IccProfile profile, T data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
internal record IccDataTagSignature(TagSignature TagSignature) : ISafeTagSignature<ICCData>
|
||||
{
|
||||
public unsafe ICCData ReadFromProfile(IccProfile profile)
|
||||
{
|
||||
var ptr = profile.ReadTag(TagSignature);
|
||||
if (ptr == null) throw new TagNotFoundException();
|
||||
return _ICCData.ToManaged((_ICCData*)ptr);
|
||||
}
|
||||
|
||||
public unsafe void WriteToProfile(IccProfile profile, ICCData obj)
|
||||
{
|
||||
var data = new byte[sizeof(_ICCDataHeader) + obj.Data.Length];
|
||||
obj.Data.Span.CopyTo(data.AsSpan().Slice(sizeof(_ICCDataHeader)));
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
var header = (_ICCDataHeader*)ptr;
|
||||
header->flag = obj.Flag;
|
||||
header->len = (uint)obj.Data.Length;
|
||||
|
||||
profile.WriteTag(TagSignature, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ComponentModel;
|
||||
|
||||
|
||||
using static LittleCms.CmsNative;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
public class MLU : CmsObject
|
||||
{
|
||||
public const string NoLanguage = "\0\0";
|
||||
public const string NoCountry = "\0\0";
|
||||
|
||||
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
|
||||
[Obsolete("Only allocator in context is used in MLU, which is not modeled in this binding")]
|
||||
public override CmsContext Context { get; } = CmsContext.Default;
|
||||
#pragma warning restore CS0809
|
||||
|
||||
internal unsafe static (uint, uint) EncodeLanguageCountryCode(string code1, string code2)
|
||||
{
|
||||
if (code1 == null || code1.Length != 2 || code1[0] >= 0x80 || code1[1] >= 0x80) throw new ArgumentException();
|
||||
if (code2 == null || code2.Length != 2 || code2[0] >= 0x80 || code2[1] >= 0x80) throw new ArgumentException();
|
||||
Span<uint> result32 = stackalloc uint[2];
|
||||
var result8 = MemoryMarshal.Cast<uint, byte>(result32);
|
||||
result8[0] = (byte)code1[0];
|
||||
result8[1] = (byte)code1[1];
|
||||
result8[4] = (byte)code2[0];
|
||||
result8[5] = (byte)code2[1];
|
||||
return (result32[0], result32[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attach a cmsMLU
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
/// <param name="moveOwnership"></param>
|
||||
public MLU(IntPtr handle, bool moveOwnership = false) : base(handle, moveOwnership)
|
||||
{
|
||||
// FIXME: missing cmsGetMLUContextID
|
||||
}
|
||||
|
||||
public MLU(int itemCount) : this(CmsContext.Default, itemCount) { }
|
||||
|
||||
public MLU(CmsContext context, int itemCount)
|
||||
{
|
||||
Context = context;
|
||||
IntPtr handle = CheckError(cmsMLUalloc(context.Handle, (uint)itemCount));
|
||||
AttachObject(handle, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy a cmsMLU by handle
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public static MLU CopyFromObject(nint handleToCopy)
|
||||
{
|
||||
nint handle = CheckError(cmsMLUdup(handleToCopy));
|
||||
return new(handle, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a MLU with en-US string
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public MLU(string s) : this(1)
|
||||
{
|
||||
Set("en", "US", s);
|
||||
}
|
||||
|
||||
protected override void FreeObject()
|
||||
{
|
||||
cmsMLUfree(Handle);
|
||||
}
|
||||
|
||||
public unsafe void Set(string language, string country, string s)
|
||||
{
|
||||
var (lang, cont) = EncodeLanguageCountryCode(language, country);
|
||||
var wchbuf = WcharEncoding.GetBytes(s + "\0");
|
||||
CheckError(cmsMLUsetWide(Handle, in lang, in cont, in wchbuf[0]));
|
||||
|
||||
}
|
||||
|
||||
public unsafe string? Get(string languageCode, string countryCode)
|
||||
{
|
||||
var (lang, cont) = EncodeLanguageCountryCode(languageCode, countryCode);
|
||||
var len = cmsMLUgetWide(Handle, in lang, in cont, null, 0);
|
||||
if (len == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var buf = new byte[(int)len];
|
||||
fixed (byte* ptr = buf)
|
||||
len = CheckError(cmsMLUgetWide(Handle, in lang, in cont, ptr, len));
|
||||
var s = WcharEncoding.GetString(buf);
|
||||
return s[..^1];
|
||||
}
|
||||
|
||||
public string? GetAny() => Get(NoLanguage, NoCountry);
|
||||
|
||||
public override string ToString() => GetAny() ?? "";
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
internal record MluTagSignature(TagSignature TagSignature) : ISafeTagSignature<MLU>
|
||||
{
|
||||
public unsafe MLU ReadFromProfile(IccProfile profile)
|
||||
{
|
||||
var ptr = profile.ReadTag(TagSignature);
|
||||
if (ptr == null) throw new TagNotFoundException();
|
||||
return MLU.CopyFromObject((IntPtr)ptr);
|
||||
}
|
||||
|
||||
public unsafe void WriteToProfile(IccProfile profile, MLU data)
|
||||
{
|
||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||
profile.WriteTag(TagSignature, (void*)data.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
public record RgbToneCurve(ToneCurve Red, ToneCurve Green, ToneCurve Blue)
|
||||
{
|
||||
public ToneCurve[] ToArray() => new[] { Red, Green, Blue };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
public static partial class SafeTagSignature
|
||||
{
|
||||
public static ISafeTagSignature<CIExyYTRIPLE> ChromaticityTag { get; } = new BlittableDataTag<CIExyYTRIPLE>(TagSignature.ChromaticityTag);
|
||||
public static ISafeTagSignature<CIEXYZ> MediaWhitePointTag { get; } = new BlittableDataTag<CIEXYZ>(TagSignature.MediaWhitePointTag);
|
||||
public static ISafeTagSignature<CIEXYZ> BlueColorantTag { get; } = new BlittableDataTag<CIEXYZ>(TagSignature.BlueColorantTag);
|
||||
public static ISafeTagSignature<CIEXYZ> GreenColorantTag { get; } = new BlittableDataTag<CIEXYZ>(TagSignature.GreenColorantTag);
|
||||
public static ISafeTagSignature<CIEXYZ> LuminanceTag { get; } = new BlittableDataTag<CIEXYZ>(TagSignature.LuminanceTag);
|
||||
public static ISafeTagSignature<CIEXYZ> MediaBlackPointTag { get; } = new BlittableDataTag<CIEXYZ>(TagSignature.MediaBlackPointTag);
|
||||
public static ISafeTagSignature<CIEXYZ> RedColorantTag { get; } = new BlittableDataTag<CIEXYZ>(TagSignature.RedColorantTag);
|
||||
|
||||
public static ISafeTagSignature<double[,]> ChromaticAdaptationTag { get; } = new ChromaticAdaptationTagSignature();
|
||||
|
||||
public static ISafeTagSignature<ICCData> Mhc2Tag { get; } = new IccDataTagSignature(TagSignature.MHC2);
|
||||
|
||||
public static ISafeTagSignature<ICCData> DataTag { get; } = new IccDataTagSignature(TagSignature.DataTag);
|
||||
public static ISafeTagSignature<ICCData> Ps2CRD0Tag { get; } = new IccDataTagSignature(TagSignature.Ps2CRD0Tag);
|
||||
public static ISafeTagSignature<ICCData> Ps2CRD1Tag { get; } = new IccDataTagSignature(TagSignature.Ps2CRD1Tag);
|
||||
public static ISafeTagSignature<ICCData> Ps2CRD2Tag { get; } = new IccDataTagSignature(TagSignature.Ps2CRD2Tag);
|
||||
public static ISafeTagSignature<ICCData> Ps2CRD3Tag { get; } = new IccDataTagSignature(TagSignature.Ps2CRD3Tag);
|
||||
public static ISafeTagSignature<ICCData> Ps2CSATag { get; } = new IccDataTagSignature(TagSignature.Ps2CSATag);
|
||||
public static ISafeTagSignature<ICCData> Ps2RenderingIntentTag { get; } = new IccDataTagSignature(TagSignature.Ps2RenderingIntentTag);
|
||||
|
||||
public static ISafeTagSignature<ToneCurve> BlueTRCTag { get; } = new ToneCurveTagSignature(TagSignature.BlueTRCTag);
|
||||
public static ISafeTagSignature<ToneCurve> GrayTRCTag { get; } = new ToneCurveTagSignature(TagSignature.GrayTRCTag);
|
||||
public static ISafeTagSignature<ToneCurve> GreenTRCTag { get; } = new ToneCurveTagSignature(TagSignature.GreenTRCTag);
|
||||
public static ISafeTagSignature<ToneCurve> RedTRCTag { get; } = new ToneCurveTagSignature(TagSignature.RedTRCTag);
|
||||
|
||||
public static ISafeTagSignature<RgbToneCurve> VcgtTag { get; } = new VideoCardGammaTableTagSignature();
|
||||
|
||||
public static ISafeTagSignature<MLU> CharTargetTag { get; } = new MluTagSignature(TagSignature.CharTargetTag);
|
||||
public static ISafeTagSignature<MLU> CopyrightTag { get; } = new MluTagSignature(TagSignature.CopyrightTag);
|
||||
public static ISafeTagSignature<MLU> DeviceMfgDescTag { get; } = new MluTagSignature(TagSignature.DeviceMfgDescTag);
|
||||
public static ISafeTagSignature<MLU> DeviceModelDescTag { get; } = new MluTagSignature(TagSignature.DeviceModelDescTag);
|
||||
public static ISafeTagSignature<MLU> ProfileDescriptionTag { get; } = new MluTagSignature(TagSignature.ProfileDescriptionTag);
|
||||
public static ISafeTagSignature<MLU> ScreeningDescTag { get; } = new MluTagSignature(TagSignature.ScreeningDescTag);
|
||||
public static ISafeTagSignature<MLU> ViewingCondDescTag { get; } = new MluTagSignature(TagSignature.ViewingCondDescTag);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
public class TagNotFoundException : Exception
|
||||
{
|
||||
private const int hr = unchecked((int)0x80131577);
|
||||
public TagNotFoundException()
|
||||
{
|
||||
HResult = hr;
|
||||
}
|
||||
|
||||
public TagNotFoundException(string message) : base(message)
|
||||
{
|
||||
HResult = hr;
|
||||
|
||||
}
|
||||
public TagNotFoundException(string? message, Exception? innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
HResult = hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using static LittleCms.CmsNative;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
public class ToneCurve : CmsObject
|
||||
{
|
||||
#pragma warning disable CS0809
|
||||
[Obsolete("lcms2 don't expose API to get context of cmsToneCurve")]
|
||||
public override CmsContext Context => throw new NotImplementedException();
|
||||
#pragma warning restore CS0809
|
||||
|
||||
public ToneCurve(nint handle, bool moveOwnership) : base(handle, moveOwnership) { }
|
||||
|
||||
public ToneCurve(CmsContext context, double gamma)
|
||||
{
|
||||
AttachObject(CheckError(cmsBuildGamma(context.Handle, gamma)), true);
|
||||
}
|
||||
|
||||
public ToneCurve(CmsContext context, ReadOnlySpan<float> table)
|
||||
{
|
||||
AttachObject(CheckError(cmsBuildTabulatedToneCurveFloat(context.Handle, (uint)table.Length, in table[0])), true);
|
||||
}
|
||||
|
||||
public ToneCurve(CmsContext context, ReadOnlySpan<ushort> table)
|
||||
{
|
||||
AttachObject(CheckError(cmsBuildTabulatedToneCurve16(context.Handle, (uint)table.Length, in table[0])), true);
|
||||
}
|
||||
|
||||
public ToneCurve(double gamma) : this(CmsContext.Default, gamma) { }
|
||||
|
||||
public ToneCurve(ReadOnlySpan<float> table) : this(CmsContext.Default, table) { }
|
||||
|
||||
public ToneCurve(ReadOnlySpan<ushort> table) : this(CmsContext.Default, table) { }
|
||||
|
||||
public static ToneCurve CopyFromObject(nint copyFromObject)
|
||||
{
|
||||
var handle = CheckError(cmsDupToneCurve(copyFromObject));
|
||||
return new(handle, true);
|
||||
}
|
||||
protected override void FreeObject()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ToneCurve Reverse()
|
||||
{
|
||||
var handle = CheckError(cmsReverseToneCurve(Handle));
|
||||
return new(handle, true);
|
||||
}
|
||||
|
||||
public ToneCurve Reverse(uint sampleCount)
|
||||
{
|
||||
var handle = CheckError(cmsReverseToneCurveEx(sampleCount, Handle));
|
||||
return new(handle, true);
|
||||
}
|
||||
|
||||
public ushort EvalU16(ushort x) => cmsEvalToneCurve16(Handle, x);
|
||||
public float EvalF32(float x) => cmsEvalToneCurveFloat(Handle, x);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
internal record ToneCurveTagSignature(TagSignature TagSignature) : ISafeTagSignature<ToneCurve>
|
||||
{
|
||||
public unsafe ToneCurve ReadFromProfile(IccProfile profile)
|
||||
{
|
||||
var ptr = profile.ReadTag(TagSignature);
|
||||
if (ptr == null) throw new TagNotFoundException();
|
||||
return ToneCurve.CopyFromObject((IntPtr)ptr);
|
||||
}
|
||||
|
||||
public unsafe void WriteToProfile(IccProfile profile, ToneCurve data)
|
||||
{
|
||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||
profile.WriteTag(TagSignature, (void*)data.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleCms.Data
|
||||
{
|
||||
internal class VideoCardGammaTableTagSignature : ISafeTagSignature<RgbToneCurve>
|
||||
{
|
||||
public TagSignature TagSignature => TagSignature.VcgtTag;
|
||||
|
||||
public unsafe RgbToneCurve ReadFromProfile(IccProfile profile)
|
||||
{
|
||||
var ptr = (IntPtr*)profile.ReadTag(TagSignature);
|
||||
if (ptr == null) throw new TagNotFoundException();
|
||||
return new RgbToneCurve(
|
||||
ToneCurve.CopyFromObject(ptr[0]),
|
||||
ToneCurve.CopyFromObject(ptr[1]),
|
||||
ToneCurve.CopyFromObject(ptr[2])
|
||||
);
|
||||
}
|
||||
|
||||
public unsafe void WriteToProfile(IccProfile profile, RgbToneCurve obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
var handles = stackalloc IntPtr[] { obj.Red.Handle, obj.Green.Handle, obj.Blue.Handle };
|
||||
profile.WriteTag(TagSignature, handles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
using LittleCms.Data;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using static LittleCms.CmsNative;
|
||||
|
||||
namespace LittleCms
|
||||
{
|
||||
public class IccProfile : CmsObject
|
||||
{
|
||||
public override CmsContext Context { get; }
|
||||
public byte[] RawBytes { get; }
|
||||
|
||||
public IccProfile(IntPtr handle, bool moveOwnership) : base(handle, moveOwnership)
|
||||
{
|
||||
Context = CmsContext.GetFromHandle(cmsGetProfileContextID(handle));
|
||||
}
|
||||
public IccProfile(IntPtr handle, CmsContext context, ReadOnlySpan<byte> bytes) : base(handle, true)
|
||||
{
|
||||
Context = context;
|
||||
RawBytes = bytes.ToArray();
|
||||
}
|
||||
|
||||
public static IccProfile Create_sRGB(CmsContext context)
|
||||
{
|
||||
return new IccProfile(CheckError(cmsCreate_sRGBProfileTHR(context.Handle)), true);
|
||||
}
|
||||
|
||||
public static IccProfile Create_sRGB()
|
||||
{
|
||||
return new IccProfile(CheckError(cmsCreate_sRGBProfile()), true);
|
||||
}
|
||||
|
||||
public static IccProfile CreateXYZ(CmsContext context)
|
||||
{
|
||||
return new IccProfile(CheckError(cmsCreateXYZProfileTHR(context.Handle)), true);
|
||||
}
|
||||
|
||||
public static IccProfile CreateXYZ()
|
||||
{
|
||||
return new IccProfile(CheckError(cmsCreateXYZProfile()), true);
|
||||
}
|
||||
|
||||
public static IccProfile CreateRGB(CIExyY whitepoint, CIExyYTRIPLE primaries, RgbToneCurve transfer)
|
||||
{
|
||||
return CreateRGB(CmsContext.Default, whitepoint, primaries, transfer);
|
||||
}
|
||||
|
||||
public static unsafe IccProfile CreateRGB(CmsContext context, CIExyY whitepoint, CIExyYTRIPLE primaries, RgbToneCurve transfer)
|
||||
{
|
||||
Span<IntPtr> transferhandle = stackalloc IntPtr[] { transfer.Red.Handle, transfer.Green.Handle, transfer.Blue.Handle };
|
||||
var handle = CheckError(cmsCreateRGBProfile(whitepoint, primaries, ref transferhandle[0]));
|
||||
return new(handle, true);
|
||||
}
|
||||
|
||||
public static unsafe IccProfile Open(CmsContext context, ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
fixed (byte* ptr = bytes)
|
||||
{
|
||||
var handle = CheckError(cmsOpenProfileFromMemTHR(context.Handle, ptr, (uint)bytes.Length));
|
||||
return new IccProfile(handle, context, bytes);
|
||||
}
|
||||
}
|
||||
public static IccProfile Open(ReadOnlySpan<byte> bytes) => Open(CmsContext.Default, bytes);
|
||||
|
||||
|
||||
public unsafe byte[] GetBytes()
|
||||
{
|
||||
uint newlen = 0;
|
||||
CheckError(cmsSaveProfileToMem(Handle, null, ref newlen));
|
||||
var newicc = new byte[newlen];
|
||||
fixed (byte* ptr = newicc)
|
||||
CheckError(cmsSaveProfileToMem(Handle, ptr, ref newlen));
|
||||
return newicc;
|
||||
}
|
||||
|
||||
protected override void FreeObject()
|
||||
{
|
||||
cmsCloseProfile(Handle);
|
||||
}
|
||||
|
||||
public unsafe void* ReadTag(TagSignature sig)
|
||||
{
|
||||
return cmsReadTag(Handle, sig);
|
||||
}
|
||||
|
||||
public unsafe bool ContainsTag(TagSignature sig) => ReadTag(sig) != null;
|
||||
|
||||
public T ReadTag<T>(ISafeTagSignature<T> sig)
|
||||
{
|
||||
return sig.ReadFromProfile(this);
|
||||
}
|
||||
|
||||
[return: NotNullIfNotNull(nameof(defaultValue))]
|
||||
public T? ReadTagOrDefault<T>(ISafeTagSignature<T> sig, T? defaultValue = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
return sig.ReadFromProfile(this);
|
||||
}
|
||||
catch (TagNotFoundException)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryReadTag<T>(ISafeTagSignature<T> sig, [NotNullWhen(returnValue: true)] out T? value)
|
||||
{
|
||||
try
|
||||
{
|
||||
value = sig.ReadFromProfile(this)!;
|
||||
return true;
|
||||
}
|
||||
catch (TagNotFoundException)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void WriteTag(TagSignature sig, void* handle)
|
||||
{
|
||||
var result = cmsWriteTag(Handle, sig, handle);
|
||||
if (handle != null)
|
||||
{
|
||||
CheckError(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteTag<T>(ISafeTagSignature<T> sig, T value)
|
||||
{
|
||||
sig.WriteToProfile(this, value);
|
||||
}
|
||||
|
||||
public unsafe void RemoveTag(TagSignature sig)
|
||||
{
|
||||
CheckError(cmsWriteTag(Handle, sig, null));
|
||||
}
|
||||
|
||||
public unsafe void RemoveTag<T>(ISafeTagSignature<T> sig)
|
||||
{
|
||||
CheckError(cmsWriteTag(Handle, sig.TagSignature, null));
|
||||
}
|
||||
|
||||
public unsafe byte[]? ReadRawTag(TagSignature sig)
|
||||
{
|
||||
if (!cmsIsTag(Handle, sig)) return null;
|
||||
var len = cmsReadRawTag(Handle, sig, null, 0);
|
||||
var buf = new byte[len];
|
||||
fixed (byte* ptr = buf)
|
||||
len = cmsReadRawTag(Handle, sig, ptr, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public void WriteRawTag(TagSignature sig, ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
CheckError(cmsWriteRawTag(Handle, sig, in bytes[0], (uint)bytes.Length));
|
||||
}
|
||||
|
||||
public void ComputeProfileId()
|
||||
{
|
||||
CheckError(cmsMD5computeID(Handle));
|
||||
}
|
||||
|
||||
public HeaderFlags HeaderFlags
|
||||
{
|
||||
get => cmsGetHeaderFlags(Handle);
|
||||
set => cmsSetHeaderFlags(Handle, value);
|
||||
}
|
||||
|
||||
public unsafe string GetInfo(InfoType info, string languageCode = MLU.NoLanguage, string countryCode = MLU.NoCountry)
|
||||
{
|
||||
var (lang, cont) = MLU.EncodeLanguageCountryCode(languageCode, countryCode);
|
||||
var len = cmsGetProfileInfo(Handle, info, in lang, in cont, null, 0);
|
||||
if (len == 0) return "";
|
||||
var buf = new byte[len];
|
||||
fixed (byte* ptr = buf)
|
||||
len = cmsGetProfileInfo(Handle, info, in lang, in cont, ptr, len);
|
||||
var s = WcharEncoding.GetString(buf)[..^1];
|
||||
return s;
|
||||
}
|
||||
|
||||
public ulong HeaderAttributes
|
||||
{
|
||||
get
|
||||
{
|
||||
cmsGetHeaderAttributes(Handle, out var attr);
|
||||
return attr;
|
||||
}
|
||||
set => cmsSetHeaderAttributes(Handle, value);
|
||||
}
|
||||
|
||||
public Guid HeaderProfileId
|
||||
{
|
||||
get
|
||||
{
|
||||
cmsGetHeaderProfileID(Handle, out var attr);
|
||||
return attr;
|
||||
}
|
||||
set => cmsSetHeaderProfileID(Handle, value);
|
||||
}
|
||||
|
||||
public DateTime HeaderCreationDateTime
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckError(cmsGetHeaderCreationDateTime(Handle, out var tm));
|
||||
return tm.ToDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
public RenderingIntent HeaderRenderingIntent
|
||||
{
|
||||
get => (RenderingIntent)cmsGetHeaderRenderingIntent(Handle);
|
||||
set => cmsSetHeaderRenderingIntent(Handle, (uint)value);
|
||||
}
|
||||
|
||||
public uint HeaderManufacturer
|
||||
{
|
||||
get => cmsGetHeaderManufacturer(Handle);
|
||||
set => cmsSetHeaderManufacturer(Handle, value);
|
||||
}
|
||||
|
||||
public uint HeaderCreator
|
||||
{
|
||||
get => cmsGetHeaderCreator(Handle);
|
||||
}
|
||||
|
||||
public uint HeaderModel
|
||||
{
|
||||
get => cmsGetHeaderModel(Handle);
|
||||
set => cmsSetHeaderModel(Handle, value);
|
||||
}
|
||||
|
||||
public ColorSpaceSignature PCS
|
||||
{
|
||||
get => cmsGetPCS(Handle);
|
||||
set => cmsSetPCS(Handle, value);
|
||||
}
|
||||
|
||||
|
||||
public ColorSpaceSignature ColorSpace
|
||||
{
|
||||
get => cmsGetColorSpace(Handle);
|
||||
set => cmsSetColorSpace(Handle, value);
|
||||
}
|
||||
|
||||
public ProfileClassSignature DeviceClass
|
||||
{
|
||||
get => cmsGetDeviceClass(Handle);
|
||||
set => cmsSetDeviceClass(Handle, value);
|
||||
}
|
||||
|
||||
public double ProfileVersion
|
||||
{
|
||||
get => cmsGetProfileVersion(Handle);
|
||||
set => cmsSetProfileVersion(Handle, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<LangVersion>9</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="lcms2.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
|
||||
namespace MHC2Gen;
|
||||
|
||||
public static class CmsFunctions
|
||||
{
|
||||
|
||||
private const double PQ_M1 = 0.1593017578125;
|
||||
private const double PQ_M2 = 78.84375;
|
||||
private const double PQ_C1 = 0.8359375;
|
||||
private const double PQ_C2 = 18.8515625;
|
||||
private const double PQ_C3 = 18.6875;
|
||||
|
||||
public static double PqEotf(double signalValue)
|
||||
{
|
||||
var signalValuePow = Math.Pow(signalValue, 1D / PQ_M2);
|
||||
|
||||
var value1 = Math.Max(signalValuePow - PQ_C1, 0);
|
||||
var value2 = PQ_C2 - PQ_C3 * signalValuePow;
|
||||
|
||||
var luminance = 10000D * Math.Pow(value1 / value2, 1D / PQ_M1);
|
||||
|
||||
return luminance;
|
||||
}
|
||||
|
||||
public static double InvPqEotf(double luminance)
|
||||
{
|
||||
var normalizedLuminance = luminance / 10000D;
|
||||
|
||||
var luminancePow = Math.Pow(normalizedLuminance, PQ_M1);
|
||||
|
||||
var value1 = PQ_C1 + PQ_C2 * luminancePow;
|
||||
var value2 = 1 + PQ_C3 * luminancePow;
|
||||
|
||||
var signalValue = Math.Pow(value1 / value2, PQ_M2);
|
||||
|
||||
return signalValue;
|
||||
}
|
||||
|
||||
public static double SrgbInvEotf(double luminance, double whiteLuminance, double blackLuminance, double gamma = 2.4)
|
||||
{
|
||||
//const double X1 = 0.0404482362771082;
|
||||
const double X2 = 0.00313066844250063;
|
||||
|
||||
var x = whiteLuminance <= blackLuminance ? 0 : (luminance - blackLuminance) / (whiteLuminance - blackLuminance);
|
||||
|
||||
if (x > 1)
|
||||
{
|
||||
x = 1;
|
||||
}
|
||||
else if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
else if (x <= X2)
|
||||
{
|
||||
x *= 12.92;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 1.055 * Math.Pow(x, 1 / gamma) - 0.055;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public static (double, double) SrgbAcm(double signalValue, double whiteLuminance, double blackLuminance = 0, double gamma = 2.2, int divider = 1023)
|
||||
{
|
||||
var b = signalValue / divider;
|
||||
var c = PqEotf(b);
|
||||
var d = SrgbInvEotf(c, whiteLuminance, blackLuminance);
|
||||
var e = blackLuminance + (whiteLuminance - blackLuminance) * Math.Pow(d, gamma);
|
||||
var f = InvPqEotf(Math.Max(0, e));
|
||||
var x = f + Math.Min(1, c / whiteLuminance) * (b - f);
|
||||
|
||||
return (b, x);
|
||||
}
|
||||
|
||||
public static double Srgb(double signalValue)
|
||||
{
|
||||
var b = signalValue / 1023;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public static double GammaRgb(double signalValue, double gamma = 2.4)
|
||||
{
|
||||
return signalValue <= 0.0031308 ? signalValue * 12.92 : 1.055 * Math.Pow(signalValue, 1.0 / gamma) - 0.055;
|
||||
}
|
||||
|
||||
public static double RgbToLinear(double signalValue, double gamma = 2.4)
|
||||
{
|
||||
return signalValue <= 0.04045 ? signalValue / 12.92 : Math.Pow((signalValue + 0.055) / 1.055, gamma);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using LittleCms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MHC2Gen
|
||||
{
|
||||
internal static class Extension
|
||||
{
|
||||
|
||||
public static CIExy ToXY(in this CIExyY xyY)
|
||||
{
|
||||
return new() { x = xyY.x, y = xyY.y };
|
||||
}
|
||||
public static CIExy ToXY(in this CIEXYZ xyz)
|
||||
{
|
||||
return xyz.ToCIExyY().ToXY();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MHC2Gen
|
||||
{
|
||||
internal class ST2084
|
||||
{
|
||||
private const double m1 = 2610.0 / 16384.0;
|
||||
private const double m2 = 128.0 * 2523.0 / 4096.0;
|
||||
private const double c1 = 3424.0 / 4096.0;
|
||||
private const double c2 = 32.0 * 2413.0 / 4096.0;
|
||||
private const double c3 = 32.0 * 2392.0 / 4096.0;
|
||||
|
||||
public static double NitsToSignal(double nits)
|
||||
{
|
||||
var Ypowm1 = Math.Pow(nits / 10000.0, m1);
|
||||
return Math.Pow((c1 + c2 * Ypowm1) / (1 + c3 * Ypowm1), m2);
|
||||
}
|
||||
|
||||
public static double SignalToNits(double signal)
|
||||
{
|
||||
var Epow1divm2 = Math.Pow(signal, 1.0 / m2);
|
||||
return 10000 * Math.Pow(Math.Max(Epow1divm2 - c1, 0) / (c2 - c3 * Epow1divm2), 1 / m1);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,55 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MathNet.Numerics" Version="4.15.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '7.0'))">
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<UseNativeAot Condition="$(PublishDir) != ''">true</UseNativeAot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Optimize for size -->
|
||||
<PropertyGroup Condition="'$(UseNativeAot)' == 'true'">
|
||||
<PublishAot>true</PublishAot>
|
||||
<IlcOptimizationPreference>Size</IlcOptimizationPreference>
|
||||
<IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies>
|
||||
<IlcGenerateStackTraceData>true</IlcGenerateStackTraceData>
|
||||
<TrimUnusedDependencies>true</TrimUnusedDependencies>
|
||||
<RootPackageReference>false</RootPackageReference>
|
||||
<TrimMode>full</TrimMode>
|
||||
<!--DebuggerSupport Condition="'$(Configuration)'=='Release'">false</DebuggerSupport-->
|
||||
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
|
||||
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<!--UseSystemResourceKeys>true</UseSystemResourceKeys-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(UseNativeAot)' != 'true'">
|
||||
<None Include="$(SolutionDir)LittleCms\lcms2.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(UseNativeAot)' == 'true'">
|
||||
<DirectPInvoke Include="lcms2" />
|
||||
<NativeLibrary Include="$(MSBuildThisFileDirectory)..\lcms2\Projects\VC2022\lcms2_static\$(Configuration)\x64\lcms2_static.lib" Condition="$(RuntimeIdentifier.StartsWith('win')) and $(RuntimeIdentifier.EndsWith('x64'))" />
|
||||
<NativeLibrary Include="$(MSBuildThisFileDirectory)..\lcms2\Projects\VC2022\lcms2_static\$(Configuration)\ARM64\lcms2_static.lib" Condition="$(RuntimeIdentifier.StartsWith('win')) and $(RuntimeIdentifier.EndsWith('arm64'))" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="C:\Users\vinni\source\repos\ColorControl\LittleCms\lcms2.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LittleCms\LittleCms.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,26 @@
|
||||
using LittleCms;
|
||||
|
||||
namespace MHC2Gen;
|
||||
|
||||
public class MHC2Wrapper
|
||||
{
|
||||
public enum NamedGamut
|
||||
{
|
||||
sRGB,
|
||||
AdobeRGB,
|
||||
P3D65,
|
||||
BT2020
|
||||
}
|
||||
|
||||
public static byte[] GenerateSdrAcmProfile(GenerateProfileCommand command)
|
||||
{
|
||||
var profile = IccProfile.Create_sRGB();
|
||||
|
||||
var context = new DeviceIccContext(profile);
|
||||
|
||||
var newProfile = context.CreateIcc(command);
|
||||
|
||||
return newProfile.GetBytes();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using LittleCms;
|
||||
|
||||
namespace MHC2Gen
|
||||
{
|
||||
public class CIExy
|
||||
{
|
||||
public double x { get; set; }
|
||||
public double y { get; set; }
|
||||
|
||||
public CIExy() { }
|
||||
|
||||
public CIExy(CIExy source)
|
||||
{
|
||||
x = source.x;
|
||||
y = source.y;
|
||||
}
|
||||
|
||||
public CIEXYZ ToXYZ(double Y = 1.0)
|
||||
{
|
||||
return new() { X = x * Y / y, Y = Y, Z = (1 - x - y) * Y / y };
|
||||
}
|
||||
}
|
||||
public class RgbPrimaries
|
||||
{
|
||||
public CIExy Red { get; }
|
||||
public CIExy Green { get; }
|
||||
public CIExy Blue { get; }
|
||||
public CIExy White { get; }
|
||||
|
||||
public RgbPrimaries(RgbPrimaries primaries)
|
||||
{
|
||||
Red = new CIExy(primaries.Red);
|
||||
Green = new CIExy(primaries.Green);
|
||||
Blue = new CIExy(primaries.Blue);
|
||||
White = new CIExy(primaries.White);
|
||||
|
||||
}
|
||||
public RgbPrimaries(CIExy red, CIExy green, CIExy blue, CIExy white)
|
||||
{
|
||||
Red = red;
|
||||
Green = green;
|
||||
Blue = blue;
|
||||
White = white;
|
||||
}
|
||||
|
||||
public static RgbPrimaries sRGB { get; } = new RgbPrimaries(new() { x = 0.64, y = 0.33 }, new() { x = 0.30, y = 0.60 }, new() { x = 0.15, y = 0.06 }, new() { x = 0.3127, y = 0.3290 });
|
||||
public static RgbPrimaries AdobeRGB { get; } = new RgbPrimaries(new() { x = 0.64, y = 0.33 }, new() { x = 0.21, y = 0.71 }, new() { x = 0.15, y = 0.06 }, new() { x = 0.3127, y = 0.3290 });
|
||||
public static RgbPrimaries P3D65 { get; } = new RgbPrimaries(new() { x = 0.68, y = 0.32 }, new() { x = 0.265, y = 0.690 }, new() { x = 0.15, y = 0.06 }, new() { x = 0.3127, y = 0.3290 });
|
||||
public static RgbPrimaries Rec2020 { get; } = new RgbPrimaries(new() { x = 0.708, y = 0.292 }, new() { x = 0.170, y = 0.797 }, new() { x = 0.131, y = 0.046 }, new() { x = 0.3127, y = 0.3290 });
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MHC2Gen;
|
||||
|
||||
public enum SDRTransferFunction
|
||||
{
|
||||
[Description("BT.1886")]
|
||||
BT_1886 = 0,
|
||||
[Description("Pure Power")]
|
||||
PurePower = 1,
|
||||
[Description("Piecewise")]
|
||||
Piecewise = 2
|
||||
}
|
||||
|
||||
public enum ColorGamut
|
||||
{
|
||||
Native = 0,
|
||||
sRGB = 1,
|
||||
P3 = 2,
|
||||
Rec2020 = 3,
|
||||
AdobeRGB = 4
|
||||
}
|
||||
|
||||
public class GenerateProfileCommand
|
||||
{
|
||||
public string Description { get; set; }
|
||||
public RgbPrimaries DevicePrimaries { get; set; } = new RgbPrimaries(RgbPrimaries.sRGB);
|
||||
public SDRTransferFunction SDRTransferFunction { get; set; }
|
||||
public ColorGamut ColorGamut { get; set; }
|
||||
public double MinCLL { get; set; }
|
||||
public double MaxCLL { get; set; }
|
||||
public double WhiteLuminance { get; set; } = 2000;
|
||||
public double BlackLuminance { get; set; } = 0;
|
||||
public double SDRMinBrightness { get; set; } = 0;
|
||||
public double SDRMaxBrightness { get; set; } = 100;
|
||||
public double SDRBrightnessBoost { get; set; } = 0;
|
||||
public double Gamma { get; set; } = 2.2;
|
||||
}
|
||||
@@ -206,6 +206,11 @@ The best and suggested method to provide this is via a Windows Service. Only whe
|
||||
return name.Substring(0, 1).ToUpper() + name.Substring(1);
|
||||
}
|
||||
|
||||
public static Dictionary<T, string> EnumToDictionary<T>() where T : struct, Enum
|
||||
{
|
||||
return Enum.GetValues<T>().ToDictionary(k => k, e => e.GetDescription());
|
||||
}
|
||||
|
||||
public static string GetDescriptionByEnumName<T>(string value) where T : IConvertible
|
||||
{
|
||||
string description = null;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace ColorControl.Shared.Contracts.NVIDIA;
|
||||
|
||||
public class NvColorEnhancementSettings
|
||||
{
|
||||
public int DigitalVibranceLevel { get; set; } = 50;
|
||||
public int HueAngle { get; set; }
|
||||
|
||||
public NvColorEnhancementSettings()
|
||||
{
|
||||
}
|
||||
|
||||
public NvColorEnhancementSettings(NvColorEnhancementSettings settings)
|
||||
{
|
||||
settings ??= new NvColorEnhancementSettings();
|
||||
|
||||
DigitalVibranceLevel = settings.DigitalVibranceLevel;
|
||||
HueAngle = settings.HueAngle;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var value = string.Empty;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -250,6 +250,16 @@ namespace ColorControl.Shared.Forms
|
||||
return item;
|
||||
}
|
||||
|
||||
public static void BuildMenuItemAndSub(ToolStripMenuItem parent, string text, string subText, EventHandler onClick)
|
||||
{
|
||||
var itemName = $"{parent.Name}_{text}";
|
||||
var menuItem = BuildMenuItem(parent.DropDownItems, itemName, text);
|
||||
|
||||
var subItemName = $"{itemName}_SubItem";
|
||||
var subItem = BuildMenuItem(menuItem.DropDownItems, subItemName, "", onClick: onClick);
|
||||
subItem.Text = subText;
|
||||
}
|
||||
|
||||
public static void BuildComboBox<T>(ComboBox comboBox, params T[] skip) where T : IConvertible
|
||||
{
|
||||
if (comboBox.Items.Count == 0)
|
||||
|
||||
+177
-118
@@ -1,6 +1,7 @@
|
||||
using ColorControl.Shared.Forms;
|
||||
using NWin32;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ColorControl.Shared.Native
|
||||
@@ -8,7 +9,6 @@ namespace ColorControl.Shared.Native
|
||||
// This class takes care of wrapping "Connecting and Configuring Displays(CCD) Win32 API"
|
||||
public static class CCD
|
||||
{
|
||||
private static bool? IsHDRActive = null;
|
||||
delegate (T, bool) DisplayConfigModeInfoDelegate<T>(DisplayConfigModeInfo modeInfo);
|
||||
|
||||
public enum DisplayTopology
|
||||
@@ -62,66 +62,6 @@ namespace ColorControl.Shared.Native
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetHDRState(bool enabled, string displayName = null)
|
||||
{
|
||||
uint pathCount, modeCount;
|
||||
|
||||
var err = NativeMethods.GetDisplayConfigBufferSizes(QueryDisplayFlags.OnlyActivePaths, out pathCount, out modeCount);
|
||||
if (err == NativeConstants.ERROR_SUCCESS)
|
||||
{
|
||||
var pathsArray = new DisplayConfigPathInfo[pathCount];
|
||||
var modesArray = new DisplayConfigModeInfo[modeCount];
|
||||
|
||||
DisplayConfigTopologyId displayTopology;
|
||||
|
||||
err = NativeMethods.QueryDisplayConfig(QueryDisplayFlags.DatabaseCurrent, ref pathCount, pathsArray, ref modeCount, modesArray, out displayTopology);
|
||||
if (err == NativeConstants.ERROR_SUCCESS)
|
||||
{
|
||||
foreach (var path in pathsArray)
|
||||
{
|
||||
if (!MatchDisplayNames(path, displayName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var setpacket = new DISPLAYCONFIG_SET_ADVANCED_COLOR_INFO();
|
||||
setpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
setpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
|
||||
setpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_SET_ADVANCED_COLOR_INFO>();
|
||||
|
||||
var requestpacket = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
|
||||
requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
requestpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
|
||||
requestpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
|
||||
|
||||
for (int i = 0; i < modeCount; i++)
|
||||
{
|
||||
if (modesArray[i].infoType == DisplayConfigModeInfoType.Target)
|
||||
{
|
||||
setpacket.header.adapterId = modesArray[i].adapterId;
|
||||
setpacket.header.id = modesArray[i].id;
|
||||
requestpacket.header.adapterId = modesArray[i].adapterId;
|
||||
requestpacket.header.id = modesArray[i].id;
|
||||
|
||||
if (NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket) == NativeConstants.ERROR_SUCCESS && requestpacket.advancedColorSupported)
|
||||
{
|
||||
setpacket.enableAdvancedColor = enabled ? 1U : 0;
|
||||
NativeMethods.DisplayConfigSetDeviceInfo(ref setpacket);
|
||||
|
||||
IsHDRActive = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err != NativeConstants.ERROR_SUCCESS)
|
||||
{
|
||||
throw new Win32Exception(err);
|
||||
}
|
||||
}
|
||||
|
||||
public static LUID GetAdapterId(string displayName = null)
|
||||
{
|
||||
return ExecuteForModeConfig((modeInfo) =>
|
||||
@@ -164,6 +104,13 @@ namespace ColorControl.Shared.Native
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool UninstallColorProfile(string profileName)
|
||||
{
|
||||
var name = Path.GetFileName(profileName);
|
||||
return NativeMethods.UninstallColorProfileW(null, name, true);
|
||||
}
|
||||
|
||||
|
||||
private static bool MinRequiredVersion = true;
|
||||
|
||||
public static bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true)
|
||||
@@ -386,56 +333,22 @@ namespace ColorControl.Shared.Native
|
||||
);
|
||||
}
|
||||
|
||||
private static T ExecuteForModeConfig<T>(DisplayConfigModeInfoDelegate<T> infoDelegate, string displayName = null)
|
||||
public static ColorParams GetColorParams(string displayName = null)
|
||||
{
|
||||
uint pathCount, modeCount;
|
||||
|
||||
var err = NativeMethods.GetDisplayConfigBufferSizes(QueryDisplayFlags.OnlyActivePaths, out pathCount, out modeCount);
|
||||
if (err == NativeConstants.ERROR_SUCCESS)
|
||||
return ExecuteForModeConfig((modeInfo) =>
|
||||
{
|
||||
var pathsArray = new DisplayConfigPathInfo[pathCount];
|
||||
var modesArray = new DisplayConfigModeInfo[modeCount];
|
||||
|
||||
DisplayConfigTopologyId displayTopology;
|
||||
|
||||
err = NativeMethods.QueryDisplayConfig(QueryDisplayFlags.DatabaseCurrent, ref pathCount, pathsArray, ref modeCount, modesArray, out displayTopology);
|
||||
if (err == NativeConstants.ERROR_SUCCESS)
|
||||
if (modeInfo.infoType == DisplayConfigModeInfoType.Source)
|
||||
{
|
||||
foreach (var path in pathsArray)
|
||||
{
|
||||
if (!MatchDisplayNames(path, displayName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < modeCount; i++)
|
||||
{
|
||||
var result = infoDelegate(modesArray[i]);
|
||||
|
||||
if (!result.Item2)
|
||||
{
|
||||
return result.Item1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (GetColorParamsForDisplayConfig(modeInfo), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (err != NativeConstants.ERROR_SUCCESS)
|
||||
{
|
||||
throw new Win32Exception(err);
|
||||
}
|
||||
|
||||
return default;
|
||||
return (new ColorParams(), true);
|
||||
}, displayName
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsHDREnabled(string displayName = null)
|
||||
private static T ExecuteForModeConfig<T>(DisplayConfigModeInfoDelegate<T> infoDelegate, string displayName = null)
|
||||
{
|
||||
if (IsHDRActive.HasValue)
|
||||
{
|
||||
return IsHDRActive.Value;
|
||||
}
|
||||
|
||||
uint pathCount, modeCount;
|
||||
|
||||
var err = NativeMethods.GetDisplayConfigBufferSizes(QueryDisplayFlags.OnlyActivePaths, out pathCount, out modeCount);
|
||||
@@ -454,30 +367,116 @@ namespace ColorControl.Shared.Native
|
||||
continue;
|
||||
}
|
||||
|
||||
var requestpacket = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
|
||||
requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
requestpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
|
||||
requestpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
|
||||
var modes = modesArray.Where(m => m.id == path.sourceInfo.id || m.id == path.targetInfo.id);
|
||||
|
||||
for (int i = 0; i < modeCount; i++)
|
||||
foreach (var mode in modes)
|
||||
{
|
||||
if (modesArray[i].infoType == DisplayConfigModeInfoType.Target)
|
||||
var result = infoDelegate(mode);
|
||||
|
||||
if (!result.Item2)
|
||||
{
|
||||
requestpacket.header.adapterId = modesArray[i].adapterId;
|
||||
requestpacket.header.id = modesArray[i].id;
|
||||
|
||||
err = NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket);
|
||||
|
||||
IsHDRActive = err == NativeConstants.ERROR_SUCCESS && requestpacket.advancedColorEnabled;
|
||||
|
||||
return IsHDRActive.Value;
|
||||
return result.Item1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (err != NativeConstants.ERROR_SUCCESS)
|
||||
{
|
||||
throw new Win32Exception(err);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public static void SetHDRState(bool enabled, string displayName = null)
|
||||
{
|
||||
ExecuteForModeConfig((modeInfo) =>
|
||||
{
|
||||
if (modeInfo.infoType == DisplayConfigModeInfoType.Target)
|
||||
{
|
||||
var requestpacket = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
|
||||
requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
requestpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
|
||||
requestpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
|
||||
requestpacket.header.adapterId = modeInfo.adapterId;
|
||||
requestpacket.header.id = modeInfo.id;
|
||||
|
||||
if (NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket) == NativeConstants.ERROR_SUCCESS && requestpacket.advancedColorSupported)
|
||||
{
|
||||
var setpacket = new DISPLAYCONFIG_SET_ADVANCED_COLOR_INFO();
|
||||
setpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
setpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
|
||||
setpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_SET_ADVANCED_COLOR_INFO>();
|
||||
setpacket.header.adapterId = modeInfo.adapterId;
|
||||
setpacket.header.id = modeInfo.id;
|
||||
|
||||
setpacket.enableAdvancedColor = enabled ? 1U : 0;
|
||||
NativeMethods.DisplayConfigSetDeviceInfo(ref setpacket);
|
||||
|
||||
if (displayName != null)
|
||||
{
|
||||
_IsHDREnabledPerDisplay[displayName] = enabled;
|
||||
}
|
||||
_IsHDREnabledPerDisplay[""] = _IsHDREnabledPerDisplay.Any(kv => kv.Value);
|
||||
}
|
||||
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
return (false, true);
|
||||
}, displayName
|
||||
);
|
||||
}
|
||||
|
||||
public static (bool isSupported, bool isEnabled) GetAdvancedColorSupportedAndEnabled(string displayName = null)
|
||||
{
|
||||
return ExecuteForModeConfig((modeInfo) =>
|
||||
{
|
||||
if (modeInfo.infoType == DisplayConfigModeInfoType.Target)
|
||||
{
|
||||
var requestpacket = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
|
||||
requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
requestpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
|
||||
requestpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
|
||||
requestpacket.header.adapterId = modeInfo.adapterId;
|
||||
requestpacket.header.id = modeInfo.id;
|
||||
|
||||
var err = NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket);
|
||||
|
||||
var result = err == NativeConstants.ERROR_SUCCESS ? (requestpacket.advancedColorSupported, requestpacket.advancedColorEnabled) : (false, false);
|
||||
|
||||
return (result, false);
|
||||
}
|
||||
|
||||
return ((false, false), true);
|
||||
}, displayName
|
||||
);
|
||||
}
|
||||
|
||||
private static Dictionary<string, bool> _IsHDREnabledPerDisplay = new Dictionary<string, bool>();
|
||||
|
||||
public static bool IsHDREnabled(string displayName = null)
|
||||
{
|
||||
if (_IsHDREnabledPerDisplay.Any())
|
||||
{
|
||||
if (displayName == null)
|
||||
{
|
||||
return _IsHDREnabledPerDisplay.Any(kv => kv.Value);
|
||||
}
|
||||
|
||||
if (_IsHDREnabledPerDisplay.TryGetValue(displayName, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
var isEnabled = GetAdvancedColorSupportedAndEnabled(displayName).isEnabled;
|
||||
|
||||
_IsHDREnabledPerDisplay[displayName ?? ""] = isEnabled;
|
||||
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
private static bool MatchDisplayNames(DisplayConfigPathInfo path, string displayName)
|
||||
@@ -528,6 +527,30 @@ namespace ColorControl.Shared.Native
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static ColorParams GetColorParamsForDisplayConfig(DisplayConfigModeInfo displayConfigModeInfo)
|
||||
{
|
||||
var requestpacket = new DISPLAYCONFIG_GET_DISPLAY_INFO();
|
||||
requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
|
||||
unchecked
|
||||
{
|
||||
requestpacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DISPLAYCONFIG_DEVICE_INFO_GET_DISPLAY_INFO;
|
||||
}
|
||||
requestpacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_DISPLAY_INFO>();
|
||||
requestpacket.header.adapterId = displayConfigModeInfo.adapterId;
|
||||
requestpacket.header.id = displayConfigModeInfo.id;
|
||||
|
||||
var error = NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket);
|
||||
|
||||
if (error == NativeConstants.ERROR_SUCCESS)
|
||||
{
|
||||
return requestpacket.colorParams;
|
||||
}
|
||||
|
||||
//throw new Win32Exception(error);
|
||||
|
||||
return new ColorParams();
|
||||
}
|
||||
|
||||
private static bool EqualDisplayNames(string displayName1, string displayName2)
|
||||
{
|
||||
displayName1 = displayName1.Replace("\\", string.Empty);
|
||||
@@ -559,6 +582,8 @@ namespace ColorControl.Shared.Native
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_SDR_WHITE_LEVEL = 12,
|
||||
}
|
||||
|
||||
private const uint DISPLAYCONFIG_DEVICE_INFO_GET_DISPLAY_INFO = 0xFFFFFFFE;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct DISPLAYCONFIG_DEVICE_INFO_HEADER
|
||||
{
|
||||
@@ -880,6 +905,36 @@ namespace ColorControl.Shared.Native
|
||||
DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ColorParams
|
||||
{
|
||||
// to get actual values: divide by 2^10 (precision equivalent to edid values)
|
||||
// on newer w11, the divisor is 2^20 instead
|
||||
public uint RedPointX;
|
||||
public uint RedPointY;
|
||||
public uint GreenPointX;
|
||||
public uint GreenPointY;
|
||||
public uint BluePointX;
|
||||
public uint BluePointY;
|
||||
public uint WhitePointX;
|
||||
public uint WhitePointY;
|
||||
// rest stored as nits * 10000
|
||||
public uint MinLuminance;
|
||||
public uint MaxLuminance;
|
||||
public uint MaxFullFrameLuminance;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct DISPLAYCONFIG_GET_DISPLAY_INFO
|
||||
{
|
||||
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1964)]
|
||||
public byte[] Stuff1;
|
||||
public ColorParams colorParams;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]
|
||||
public byte[] Stuff2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO
|
||||
{
|
||||
@@ -1046,9 +1101,13 @@ namespace ColorControl.Shared.Native
|
||||
[DllImport("user32")]
|
||||
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SDR_WHITE_LEVEL requestPacket);
|
||||
|
||||
[DllImport("user32")]
|
||||
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_DISPLAY_INFO requestPacket);
|
||||
[DllImport("mscms", CharSet = CharSet.Unicode)]
|
||||
public static extern bool InstallColorProfileW(string machineName, string profilename);
|
||||
|
||||
[DllImport("mscms", CharSet = CharSet.Unicode)]
|
||||
public static extern bool UninstallColorProfileW(string machineName, string profilename, bool delete);
|
||||
[DllImport("mscms", CharSet = CharSet.Unicode)]
|
||||
public static extern int ColorProfileSetDisplayDefaultAssociation(WCS_PROFILE_MANAGEMENT_SCOPE scope, string profilename, COLORPROFILETYPE profiletype, COLORPROFILESUBTYPE profilesubtype, LUID targetadapterid, uint sourceid);
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
namespace ColorControl.Shared.Native;
|
||||
|
||||
public static class CmsFunctions
|
||||
{
|
||||
|
||||
private const double PQ_M1 = 0.1593017578125;
|
||||
private const double PQ_M2 = 78.84375;
|
||||
private const double PQ_C1 = 0.8359375;
|
||||
private const double PQ_C2 = 18.8515625;
|
||||
private const double PQ_C3 = 18.6875;
|
||||
|
||||
public static double PqEotf(double signalValue)
|
||||
{
|
||||
var signalValuePow = Math.Pow(signalValue, 1D / PQ_M2);
|
||||
|
||||
var value1 = Math.Max(signalValuePow - PQ_C1, 0);
|
||||
var value2 = PQ_C2 - PQ_C3 * signalValuePow;
|
||||
|
||||
var luminance = 10000D * Math.Pow(value1 / value2, 1D / PQ_M1);
|
||||
|
||||
return luminance;
|
||||
}
|
||||
|
||||
public static double InvPqEotf(double luminance)
|
||||
{
|
||||
var normalizedLuminance = luminance / 10000D;
|
||||
|
||||
var luminancePow = Math.Pow(normalizedLuminance, PQ_M1);
|
||||
|
||||
var value1 = PQ_C1 + PQ_C2 * luminancePow;
|
||||
var value2 = 1 + PQ_C3 * luminancePow;
|
||||
|
||||
var signalValue = Math.Pow(value1 / value2, PQ_M2);
|
||||
|
||||
return signalValue;
|
||||
}
|
||||
|
||||
public static double SrgbInvEotf(double luminance, double whiteLuminance, double blackLuminance, double gamma = 2.4)
|
||||
{
|
||||
//const double X1 = 0.0404482362771082;
|
||||
const double X2 = 0.00313066844250063;
|
||||
|
||||
var x = (luminance - blackLuminance) / (whiteLuminance - blackLuminance);
|
||||
|
||||
if (x > 1)
|
||||
{
|
||||
x = 1;
|
||||
}
|
||||
else if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
else if (x <= X2)
|
||||
{
|
||||
x *= 12.92;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 1.055 * Math.Pow(x, 1 / gamma) - 0.055;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public static (double, double) SrgbAcm(int signalValue, double whiteLuminance, double blackLuminance = 0, double gamma = 2.2)
|
||||
{
|
||||
var b = signalValue / 1023;
|
||||
var c = PqEotf(b);
|
||||
var d = SrgbInvEotf(c, whiteLuminance, blackLuminance);
|
||||
var e = blackLuminance + (whiteLuminance - blackLuminance) * Math.Pow(d, gamma);
|
||||
var f = InvPqEotf(Math.Max(0, e));
|
||||
var x = f + Math.Min(1, c / whiteLuminance) * (b - f);
|
||||
|
||||
return (b, x);
|
||||
}
|
||||
|
||||
public static double GammaRgb(double signalValue, double gamma = 2.4)
|
||||
{
|
||||
return signalValue <= 0.0031308 ? signalValue * 12.92 : 1.055 * Math.Pow(signalValue, 1.0 / gamma) - 0.055;
|
||||
}
|
||||
|
||||
public static double RgbToLinear(double signalValue, double gamma = 2.4)
|
||||
{
|
||||
return signalValue <= 0.04045 ? signalValue / 12.92 : Math.Pow((signalValue + 0.055) / 1.055, gamma);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using ColorControl.Shared.Contracts;
|
||||
using ColorControl.Shared.Native;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32.TaskScheduler;
|
||||
using NWin32;
|
||||
@@ -336,6 +337,18 @@ namespace ColorControl.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public bool UninstallColorProfile(string filename)
|
||||
{
|
||||
if (!_winApiService.IsAdministrator())
|
||||
{
|
||||
return _rpcService.Call<bool>(nameof(UninstallColorProfile), filename);
|
||||
}
|
||||
|
||||
var deleteResult = CCD.UninstallColorProfile(filename);
|
||||
|
||||
return deleteResult;
|
||||
}
|
||||
|
||||
private static bool UpdateShortcut(string path, string arguments, bool removeArguments = false)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ColorControl.Shared.XForms;
|
||||
|
||||
public abstract class BaseViewModel : IDataErrorInfo, INotifyPropertyChanged
|
||||
{
|
||||
public virtual string Error => null;
|
||||
public bool IsValid { get; set; }
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||||
|
||||
public virtual string this[string columnName]
|
||||
{
|
||||
get
|
||||
{
|
||||
var validationResults = new List<ValidationResult>();
|
||||
|
||||
var fieldValid = Validator.TryValidateProperty(GetType().GetProperty(columnName).GetValue(this)
|
||||
, new ValidationContext(this)
|
||||
{
|
||||
MemberName = columnName
|
||||
}
|
||||
, validationResults);
|
||||
|
||||
bool isValid;
|
||||
if (fieldValid)
|
||||
{
|
||||
var allValidationResults = new List<ValidationResult>();
|
||||
isValid = PreValidate() && Validator.TryValidateObject(this, new ValidationContext(this), allValidationResults, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
if (isValid != IsValid)
|
||||
{
|
||||
IsValid = isValid;
|
||||
OnPropertyChanged("IsValid");
|
||||
}
|
||||
|
||||
return fieldValid ? null : validationResults.First().ErrorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool PreValidate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -271,6 +271,10 @@ namespace novideo_srgb
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (display == null)
|
||||
{
|
||||
throw new InvalidOperationException("No display");
|
||||
}
|
||||
return new EDID(display.Output.PhysicalGPU.ReadEDIDData(display.Output));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user