/// <summary> /// Transforms a color value assumed to be in the default CS_sRGB /// color space into this ColorSpace. /// <para> /// This method transforms color values using algorithms designed /// to produce the best perceptual match between input and output /// colors. In order to do colorimetric conversion of color values, /// you should use the <code>toCIEXYZ</code> /// method of the CS_sRGB color space to first convert from the input /// color space to the CS_CIEXYZ color space, and then use the /// <code>fromCIEXYZ</code> method of this color space to /// convert from CS_CIEXYZ to the output color space. /// See <seealso cref="#toCIEXYZ(float[]) toCIEXYZ"/> and /// <seealso cref="#fromCIEXYZ(float[]) fromCIEXYZ"/> for further information. /// </para> /// <para> /// </para> /// </summary> /// <param name="rgbvalue"> a float array with length of at least 3. </param> /// <returns> a float array with length equal to the number of /// components in this ColorSpace. </returns> /// <exception cref="ArrayIndexOutOfBoundsException"> if array length is not /// at least 3. </exception> public override float[] FromRGB(float[] rgbvalue) { if (Srgb2this == null) { ColorTransform[] transformList = new ColorTransform [2]; ICC_ColorSpace srgbCS = (ICC_ColorSpace)ColorSpace.GetInstance(CS_sRGB_Renamed); PCMM mdl = CMSManager.Module; transformList[0] = mdl.createTransform(srgbCS.Profile, ColorTransform.Any, ColorTransform.In); transformList[1] = mdl.createTransform(ThisProfile, ColorTransform.Any, ColorTransform.Out); Srgb2this = mdl.createTransform(transformList); if (NeedScaleInit) { SetComponentScaling(); } } short[] tmp = new short[3]; for (int i = 0; i < 3; i++) { tmp[i] = (short)((rgbvalue[i] * 65535.0f) + 0.5f); } tmp = Srgb2this.colorConvert(tmp, null); int nc = this.NumComponents; float[] result = new float [nc]; for (int i = 0; i < nc; i++) { result[i] = (((float)(tmp[i] & 0xffff)) / 65535.0f) * DiffMinMax[i] + MinVal[i]; } return(result); }
/// <summary> /// Transforms a color value assumed to be in the CS_CIEXYZ conversion /// color space into this ColorSpace. /// <para> /// This method transforms color values using relative colorimetry, /// as defined by the ICC Specification. This /// means that the XYZ argument values taken by this method are represented /// relative to the D50 white point of the CS_CIEXYZ color space. /// This representation is useful in a two-step color conversion /// process in which colors are transformed from an input color /// space to CS_CIEXYZ and then to an output color space. The color /// values returned by this method are not those that would produce /// the XYZ value passed to the method when measured by a colorimeter. /// If you have XYZ values corresponding to measurements made using /// current CIE recommended practices, they must be converted to D50 /// relative values before being passed to this method. /// The paragraphs below explain this in more detail. /// </para> /// <para> /// The ICC standard uses a device independent color space (DICS) as the /// mechanism for converting color from one device to another device. In /// this architecture, colors are converted from the source device's color /// space to the ICC DICS and then from the ICC DICS to the destination /// device's color space. The ICC standard defines device profiles which /// contain transforms which will convert between a device's color space /// and the ICC DICS. The overall conversion of colors from a source /// device to colors of a destination device is done by connecting the /// device-to-DICS transform of the profile for the source device to the /// DICS-to-device transform of the profile for the destination device. /// For this reason, the ICC DICS is commonly referred to as the profile /// connection space (PCS). The color space used in the methods /// toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC /// Specification. This is also the color space represented by /// ColorSpace.CS_CIEXYZ. /// </para> /// <para> /// The XYZ values of a color are often represented as relative to some /// white point, so the actual meaning of the XYZ values cannot be known /// without knowing the white point of those values. This is known as /// relative colorimetry. The PCS uses a white point of D50, so the XYZ /// values of the PCS are relative to D50. For example, white in the PCS /// will have the XYZ values of D50, which is defined to be X=.9642, /// Y=1.000, and Z=0.8249. This white point is commonly used for graphic /// arts applications, but others are often used in other applications. /// </para> /// <para> /// To quantify the color characteristics of a device such as a printer /// or monitor, measurements of XYZ values for particular device colors /// are typically made. For purposes of this discussion, the term /// device XYZ values is used to mean the XYZ values that would be /// measured from device colors using current CIE recommended practices. /// </para> /// <para> /// Converting between device XYZ values and the PCS XYZ values taken as /// arguments by this method corresponds to converting between the device's /// color space, as represented by CIE colorimetric values, and the PCS. /// There are many factors involved in this process, some of which are quite /// subtle. The most important, however, is the adjustment made to account /// for differences between the device's white point and the white point of /// the PCS. There are many techniques for doing this and it is the /// subject of much current research and controversy. Some commonly used /// methods are XYZ scaling, the von Kries transform, and the Bradford /// transform. The proper method to use depends upon each particular /// application. /// </para> /// <para> /// The simplest method is XYZ scaling. In this method each device XYZ /// value is converted to a PCS XYZ value by multiplying it by the ratio /// of the PCS white point (D50) to the device white point. /// <pre> /// /// Xd, Yd, Zd are the device XYZ values /// Xdw, Ydw, Zdw are the device XYZ white point values /// Xp, Yp, Zp are the PCS XYZ values /// Xd50, Yd50, Zd50 are the PCS XYZ white point values /// /// Xp = Xd * (Xd50 / Xdw) /// Yp = Yd * (Yd50 / Ydw) /// Zp = Zd * (Zd50 / Zdw) /// /// </pre> /// </para> /// <para> /// Conversion from the PCS to the device would be done by inverting these /// equations: /// <pre> /// /// Xd = Xp * (Xdw / Xd50) /// Yd = Yp * (Ydw / Yd50) /// Zd = Zp * (Zdw / Zd50) /// /// </pre> /// </para> /// <para> /// Note that the media white point tag in an ICC profile is not the same /// as the device white point. The media white point tag is expressed in /// PCS values and is used to represent the difference between the XYZ of /// device illuminant and the XYZ of the device media when measured under /// that illuminant. The device white point is expressed as the device /// XYZ values corresponding to white displayed on the device. For /// example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device /// will result in a measured device XYZ value of D65. This will not /// be the same as the media white point tag XYZ value in the ICC /// profile for an sRGB device. /// </para> /// <para> /// </para> /// </summary> /// <param name="colorvalue"> a float array with length of at least 3. </param> /// <returns> a float array with length equal to the number of /// components in this ColorSpace. </returns> /// <exception cref="ArrayIndexOutOfBoundsException"> if array length is not /// at least 3. </exception> public override float[] FromCIEXYZ(float[] colorvalue) { if (Xyz2this == null) { ColorTransform[] transformList = new ColorTransform [2]; ICC_ColorSpace xyzCS = (ICC_ColorSpace)ColorSpace.GetInstance(CS_CIEXYZ); PCMM mdl = CMSManager.Module; transformList[0] = mdl.createTransform(xyzCS.Profile, ColorTransform.Any, ColorTransform.In); try { transformList[1] = mdl.createTransform(ThisProfile, ICC_Profile.IcRelativeColorimetric, ColorTransform.Out); } catch (CMMException) { transformList[1] = CMSManager.Module.createTransform(ThisProfile, ColorTransform.Any, ColorTransform.Out); } Xyz2this = mdl.createTransform(transformList); if (NeedScaleInit) { SetComponentScaling(); } } short[] tmp = new short[3]; float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f); float factor = 65535.0f / ALMOST_TWO; // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components for (int i = 0; i < 3; i++) { tmp[i] = (short)((colorvalue[i] * factor) + 0.5f); } tmp = Xyz2this.colorConvert(tmp, null); int nc = this.NumComponents; float[] result = new float [nc]; for (int i = 0; i < nc; i++) { result[i] = (((float)(tmp[i] & 0xffff)) / 65535.0f) * DiffMinMax[i] + MinVal[i]; } return(result); }