我正在做一个需要做lab->rgb的项目。 我正在使用一个名为lcms2的颜色管理库,链接:https://github.com/mm2/Little-CMS
我的项目是用 c# 的,我使用互操作与 dll 进行通信。该项目必须在Linux Ubuntu Core 16上运行,大多数c#颜色管理库不支持它,这就是我使用lcms2的原因。
尝试转换 LAB L:99、A:-122、B:-66 时,我得到非常奇怪的结果,带有值的 RGB:
R: -3769.14044380188 G: 304.88466560840607 B: 378.99470329284668
这是(简化的)数据类,测试中使用的扩展方法,当然还有测试:
[Test()]
public void LabThatGaveWeirdResultDoesntDoItAnymore()
{
var lab = new LabColor(99, -112, -66);
var rgb = lab.ToRgb();
Assert.IsTrue(new[] { rgb.R, rgb.G, rgb.B }.All(v => v >= 0 && v <= 255));
}
public class LabColor
{
public double L { get; }
public double A { get; }
public double B { get; }
public LabColor(int l, int a, int b)
{
L = l;
A = a;
B = b;
}
}
public class RgbColor
{
public double R { get; }
public double G { get; }
public double B { get; }
public RgbColor(double r, double g, double b)
{
R = r;
G = g;
B = b;
}
}
public static RgbColor ToRgb(this LabColor lab, Intent intent = Intent.Perceptual)
{
var labProfile = Lcms2.GetLabProfile();
var hRgbProfile = Lcms2.GetRgbProfile();
var transform = Lcms2.GetTransform(labProfile, hRgbProfile, intent);
var rgbBuffer = new double[3];
var labBuffer = new[]
{
lab.L,
lab.A,
lab.B
};
Lcms2.Transform(transform, labBuffer, ref rgbBuffer, 1);
Lcms2.FreeMemory(labProfile);
Lcms2.FreeMemory(hRgbProfile);
Lcms2.FreeMemory(transform);
return new RgbColor(rgbBuffer[0] * 255, rgbBuffer[1] * 255, rgbBuffer[2] * 255);
}
lcms2 包装器代码:
internal enum ProfileFormat
{
Rgb = 4456472,
Cmyk = 4587552,
Lab = 4849688
}
public enum Intent
{
Perceptual = 0,
RelativeColorimetric = 1,
Saturation = 2,
AbsoluteColorimetric = 3
}
internal sealed class Profile
{
public Profile(IntPtr pointer, ProfileFormat format)
{
Pointer = pointer;
Format = format;
}
internal ProfileFormat Format { get; }
internal IntPtr Pointer { get; }
}
internal sealed class Transform
{
public Transform(IntPtr pointer)
{
Pointer = pointer;
}
internal IntPtr Pointer { get; }
}
internal sealed class Lcms2
{
[DllImport("lcms2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cmsCreate_sRGBProfile")]
static extern IntPtr cmsCreate_sRGBProfile();
public static Profile GetRgbProfile()
{
return new Profile(cmsCreate_sRGBProfile(), ProfileFormat.Rgb);
}
[DllImport("lcms2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cmsCreateLab4Profile")]
static extern IntPtr cmsCreateLab4Profile();
public static Profile GetLabProfile()
{
return new Profile(cmsCreateLab4Profile(), ProfileFormat.Lab);
}
[DllImport("lcms2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cmsCreateTransform")]
static extern IntPtr cmsCreateTransform(IntPtr inProfilePtr, uint inputFormat, IntPtr outPutProfilePtr, uint outputFormat, uint intent, uint dword);
public static Transform GetTransform(Profile inProfile, Profile outProfile, Intent intent)
{
return new Transform(cmsCreateTransform(inProfile.Pointer, (uint)inProfile.Format, outProfile.Pointer, (uint)outProfile.Format, (uint)intent, 0));
}
[DllImport("lcms2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cmsDoTransform")]
static extern void cmsDoTransform(IntPtr transformPtr, double[] inputBuffer, double[] outputBuffer, uint size);
public static void Transform(Transform transform, double[] inputBuffer, ref double[] outputBuffer, uint size)
{
cmsDoTransform(transform.Pointer, inputBuffer, outputBuffer, size);
}
[DllImport("lcms2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cmsDeleteTransform")]
static extern void cmsDeleteTransform(IntPtr transformPtr);
public static void FreeMemory(Transform transform)
{
cmsDeleteTransform(transform.Pointer);
}
[DllImport("lcms2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cmsCloseProfile")]
static extern void cmsCloseProfile(IntPtr profilePtr);
public static void FreeMemory(Profile profile)
{
cmsCloseProfile(profile.Pointer);
}
我通过在 c++ lcms2 项目中重新创建代码来计算配置文件格式整数。 它们被定义为
#define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
#define TYPE_Lab_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0))
我模仿代码,创建:
uint FLOAT_SH(uint i) => (i) << 22;
uint COLORSPACE_SH(uint i) => (i) << 16;
uint PT_Lab = 10;
uint PT_RGB = 4;
uint CHANNELS_SH(uint i) => (i) << 3;
uint BYTES_SH(uint i) => (i);
var TYPE_RGB_DBL = (FLOAT_SH(1) | COLORSPACE_SH(PT_RGB) | CHANNELS_SH(3) | BYTES_SH(0)); //4456472
var TYPE_Lab_DBL = (FLOAT_SH(1) | COLORSPACE_SH(PT_Lab) | CHANNELS_SH(3) | BYTES_SH(0)); //4849688
碰巧Lab(99,-122,-66)超出了sRGB色域。不能在 sRGB 中表示此颜色。如果裁剪值,则为 RGB=(0, 255, 255),但这不是您要求的颜色。
否则,sRGB 的无界值为:
C:\github\Little-CMS\bin>transicc -t1 -i*Lab 小CMS色彩空间转换计算器 - 4.3 [小CMS 2.08]
输入值,"q"退出 L*?99 一个*?-122 b*?-66
R=-4111.8278 G=307.7362 B=378.8372