mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-21 08:09:49 -05:00
260 lines
7.8 KiB
C#
260 lines
7.8 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|