public static unsafe ImageSource RenderLinearGamutLuv(int width, int height, ColorTransformMatrix XYZtoRGB, float leftU, float rightU, float topV, float bottomV)
        {
            if (width == 0 || height == 0)
            {
                return(null);
            }

            const float minVisibleU = 0.001423f;
            const float maxVisibleU = 0.6234f;

            const float minVisibleV = 0.01592f;
            const float maxVisibleV = 0.5868f;

            float widthU  = rightU - leftU;
            float heightV = bottomV - topV;

            float uPerPixel = widthU / width;
            float vPerPixel = heightV / height;

            int pxMinVisibleU = 0; if (uPerPixel != 0)
            {
                pxMinVisibleU = Math.Max(0, (int)((minVisibleU - leftU) / uPerPixel));
            }
            int pxMaxVisibleU = width; if (uPerPixel != 0)
            {
                pxMaxVisibleU = Math.Min(width, (int)((maxVisibleU - leftU) / uPerPixel));
            }

            int pxMinVisibleV = height; if (vPerPixel != 0)
            {
                pxMinVisibleV = Math.Min(height, (int)((minVisibleV - topV) / vPerPixel));
            }
            int pxMaxVisibleV = 0; if (uPerPixel != 0)

            {
                pxMaxVisibleV = Math.Max(0, (int)((maxVisibleV - topV) / vPerPixel));
            }

            byte[] data = new byte[width * height * 4];

            float R, G, B;
            float u, v, x, y;
            float X, Y = 1f, Z;

            fixed(byte *pData = data)
            {
                for (int pxV = pxMaxVisibleV; pxV <= pxMinVisibleV; pxV++)
                {
                    for (int pxU = pxMinVisibleU; pxU <= pxMaxVisibleU; pxU++)
                    {
                        u = leftU + pxU * uPerPixel;
                        v = topV + pxV * vPerPixel;

                        ConvertColor.Fastuv2xy(u, v, out x, out y);
                        ConvertColor.FastxyY2XYZ(x, y, Y, out X, out Z);

                        XYZtoRGB.Transform(X, Y, Z, out R, out G, out B);

                        if (R >= 0 && G >= 0 && B >= 0)
                        {
                            byte *pBGR = pData + (pxV * width + pxU) * 4;

                            pBGR[0] = (byte)Math.Min(255, ConvertColor.scRGBtosRGB(B) * 255); // TODO: handle negative
                            pBGR[1] = (byte)Math.Min(255, ConvertColor.scRGBtosRGB(G) * 255);
                            pBGR[2] = (byte)Math.Min(255, ConvertColor.scRGBtosRGB(R) * 255);
                            pBGR[3] = 255;
                        }
                    }
                }
            }

            return(BitmapSource.Create(width, height, 96, 96, PixelFormats.Pbgra32, null, data, width * 4));
        }
 public Color1931XYZ ToXYZ(ColorMatchingFunctions.XYZ cmf)
 {
     return(ConvertColor.ToXYZ(Samples, FirstNanometers, StepNanometers, cmf));
 }