825 lines
25 KiB
C#
825 lines
25 KiB
C#
|
#region PDFsharp - A .NET library for processing PDF
|
||
|
//
|
||
|
// Authors:
|
||
|
// Stefan Lange
|
||
|
//
|
||
|
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
|
||
|
//
|
||
|
// http://www.pdfsharp.com
|
||
|
// http://sourceforge.net/projects/pdfsharp
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
// copy of this software and associated documentation files (the "Software"),
|
||
|
// to deal in the Software without restriction, including without limitation
|
||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||
|
// Software is furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included
|
||
|
// in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
// DEALINGS IN THE SOFTWARE.
|
||
|
#endregion
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Globalization;
|
||
|
using System.ComponentModel;
|
||
|
#if GDI
|
||
|
using System.Drawing;
|
||
|
#endif
|
||
|
#if WPF
|
||
|
using WpfColor = System.Windows.Media.Color;
|
||
|
#endif
|
||
|
#if UWP
|
||
|
using UwpColor = Windows.UI.Color;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// ReSharper disable RedundantNameQualifier
|
||
|
|
||
|
namespace PdfSharp.Drawing
|
||
|
{
|
||
|
///<summary>
|
||
|
/// Represents a RGB, CMYK, or gray scale color.
|
||
|
/// </summary>
|
||
|
[DebuggerDisplay("clr=(A={A}, R={R}, G={G}, B={B} C={C}, M={M}, Y={Y}, K={K})")]
|
||
|
public struct XColor
|
||
|
{
|
||
|
XColor(uint argb)
|
||
|
{
|
||
|
_cs = XColorSpace.Rgb;
|
||
|
_a = (byte)((argb >> 24) & 0xff) / 255f;
|
||
|
_r = (byte)((argb >> 16) & 0xff);
|
||
|
_g = (byte)((argb >> 8) & 0xff);
|
||
|
_b = (byte)(argb & 0xff);
|
||
|
_c = 0;
|
||
|
_m = 0;
|
||
|
_y = 0;
|
||
|
_k = 0;
|
||
|
_gs = 0;
|
||
|
RgbChanged();
|
||
|
//_cs.GetType(); // Suppress warning
|
||
|
}
|
||
|
|
||
|
XColor(byte alpha, byte red, byte green, byte blue)
|
||
|
{
|
||
|
_cs = XColorSpace.Rgb;
|
||
|
_a = alpha / 255f;
|
||
|
_r = red;
|
||
|
_g = green;
|
||
|
_b = blue;
|
||
|
_c = 0;
|
||
|
_m = 0;
|
||
|
_y = 0;
|
||
|
_k = 0;
|
||
|
_gs = 0;
|
||
|
RgbChanged();
|
||
|
//_cs.GetType(); // Suppress warning
|
||
|
}
|
||
|
|
||
|
XColor(double alpha, double cyan, double magenta, double yellow, double black)
|
||
|
{
|
||
|
_cs = XColorSpace.Cmyk;
|
||
|
_a = (float)(alpha > 1 ? 1 : (alpha < 0 ? 0 : alpha));
|
||
|
_c = (float)(cyan > 1 ? 1 : (cyan < 0 ? 0 : cyan));
|
||
|
_m = (float)(magenta > 1 ? 1 : (magenta < 0 ? 0 : magenta));
|
||
|
_y = (float)(yellow > 1 ? 1 : (yellow < 0 ? 0 : yellow));
|
||
|
_k = (float)(black > 1 ? 1 : (black < 0 ? 0 : black));
|
||
|
_r = 0;
|
||
|
_g = 0;
|
||
|
_b = 0;
|
||
|
_gs = 0f;
|
||
|
CmykChanged();
|
||
|
}
|
||
|
|
||
|
XColor(double cyan, double magenta, double yellow, double black)
|
||
|
: this(1.0, cyan, magenta, yellow, black)
|
||
|
{ }
|
||
|
|
||
|
XColor(double gray)
|
||
|
{
|
||
|
_cs = XColorSpace.GrayScale;
|
||
|
if (gray < 0)
|
||
|
_gs = 0;
|
||
|
else if (gray > 1)
|
||
|
_gs = 1;
|
||
|
else
|
||
|
_gs = (float)gray;
|
||
|
|
||
|
_a = 1;
|
||
|
_r = 0;
|
||
|
_g = 0;
|
||
|
_b = 0;
|
||
|
_c = 0;
|
||
|
_m = 0;
|
||
|
_y = 0;
|
||
|
_k = 0;
|
||
|
GrayChanged();
|
||
|
}
|
||
|
|
||
|
#if GDI
|
||
|
XColor(System.Drawing.Color color)
|
||
|
: this(color.A, color.R, color.G, color.B)
|
||
|
{ }
|
||
|
#endif
|
||
|
|
||
|
#if WPF
|
||
|
XColor(WpfColor color)
|
||
|
: this(color.A, color.R, color.G, color.B)
|
||
|
{ }
|
||
|
#endif
|
||
|
|
||
|
#if GDI
|
||
|
XColor(KnownColor knownColor)
|
||
|
: this(System.Drawing.Color.FromKnownColor(knownColor))
|
||
|
{ }
|
||
|
#endif
|
||
|
|
||
|
#if UWP
|
||
|
XColor(UwpColor color)
|
||
|
: this(color.A, color.R, color.G, color.B)
|
||
|
{ }
|
||
|
#endif
|
||
|
|
||
|
internal XColor(XKnownColor knownColor)
|
||
|
: this(XKnownColorTable.KnownColorToArgb(knownColor))
|
||
|
{ }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from a 32-bit ARGB value.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int argb)
|
||
|
{
|
||
|
return new XColor((byte)(argb >> 24), (byte)(argb >> 16), (byte)(argb >> 8), (byte)(argb));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from a 32-bit ARGB value.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(uint argb)
|
||
|
{
|
||
|
return new XColor((byte)(argb >> 24), (byte)(argb >> 16), (byte)(argb >> 8), (byte)(argb));
|
||
|
}
|
||
|
|
||
|
// from System.Drawing.Color
|
||
|
//public static XColor FromArgb(int alpha, Color baseColor);
|
||
|
//public static XColor FromArgb(int red, int green, int blue);
|
||
|
//public static XColor FromArgb(int alpha, int red, int green, int blue);
|
||
|
//public static XColor FromKnownColor(KnownColor color);
|
||
|
//public static XColor FromName(string name);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified 8-bit color values (red, green, and blue).
|
||
|
/// The alpha value is implicitly 255 (fully opaque).
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int red, int green, int blue)
|
||
|
{
|
||
|
CheckByte(red, "red");
|
||
|
CheckByte(green, "green");
|
||
|
CheckByte(blue, "blue");
|
||
|
return new XColor(255, (byte)red, (byte)green, (byte)blue);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the four ARGB component (alpha, red, green, and blue) values.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int alpha, int red, int green, int blue)
|
||
|
{
|
||
|
CheckByte(alpha, "alpha");
|
||
|
CheckByte(red, "red");
|
||
|
CheckByte(green, "green");
|
||
|
CheckByte(blue, "blue");
|
||
|
return new XColor((byte)alpha, (byte)red, (byte)green, (byte)blue);
|
||
|
}
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified System.Drawing.Color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(System.Drawing.Color color)
|
||
|
{
|
||
|
return new XColor(color);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if WPF
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified System.Drawing.Color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(WpfColor color)
|
||
|
{
|
||
|
return new XColor(color);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if UWP
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified Windows.UI.Color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(UwpColor color)
|
||
|
{
|
||
|
return new XColor(color);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified alpha value and color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int alpha, XColor color)
|
||
|
{
|
||
|
color.A = ((byte)alpha) / 255.0;
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified alpha value and color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int alpha, System.Drawing.Color color)
|
||
|
{
|
||
|
// Cast required to use correct constructor.
|
||
|
return new XColor((byte)alpha, color.R, color.G, color.B);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if WPF
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified alpha value and color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int alpha, WpfColor color)
|
||
|
{
|
||
|
// Cast required to use correct constructor.
|
||
|
return new XColor((byte)alpha, color.R, color.G, color.B);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if UWP
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified alpha value and color.
|
||
|
/// </summary>
|
||
|
public static XColor FromArgb(int alpha, UwpColor color)
|
||
|
{
|
||
|
// Cast required to use correct constructor.
|
||
|
return new XColor((byte)alpha, color.R, color.G, color.B);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified CMYK values.
|
||
|
/// </summary>
|
||
|
public static XColor FromCmyk(double cyan, double magenta, double yellow, double black)
|
||
|
{
|
||
|
return new XColor(cyan, magenta, yellow, black);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified CMYK values.
|
||
|
/// </summary>
|
||
|
public static XColor FromCmyk(double alpha, double cyan, double magenta, double yellow, double black)
|
||
|
{
|
||
|
return new XColor(alpha, cyan, magenta, yellow, black);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor structure from the specified gray value.
|
||
|
/// </summary>
|
||
|
public static XColor FromGrayScale(double grayScale)
|
||
|
{
|
||
|
return new XColor(grayScale);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor from the specified pre-defined color.
|
||
|
/// </summary>
|
||
|
public static XColor FromKnownColor(XKnownColor color)
|
||
|
{
|
||
|
return new XColor(color);
|
||
|
}
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Creates an XColor from the specified pre-defined color.
|
||
|
/// </summary>
|
||
|
public static XColor FromKnownColor(KnownColor color)
|
||
|
{
|
||
|
return new XColor(color);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an XColor from the specified name of a pre-defined color.
|
||
|
/// </summary>
|
||
|
public static XColor FromName(string name)
|
||
|
{
|
||
|
#if GDI
|
||
|
// The implementation in System.Drawing.dll is interesting. It uses a ColorConverter
|
||
|
// with hash tables, locking mechanisms etc. I'm not sure what problems that solves.
|
||
|
// So I don't use the source, but the reflection.
|
||
|
try
|
||
|
{
|
||
|
return new XColor((KnownColor)Enum.Parse(typeof(KnownColor), name, true));
|
||
|
}
|
||
|
// ReSharper disable EmptyGeneralCatchClause
|
||
|
catch { }
|
||
|
// ReSharper restore EmptyGeneralCatchClause
|
||
|
#endif
|
||
|
return Empty;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the color space to be used for PDF generation.
|
||
|
/// </summary>
|
||
|
public XColorSpace ColorSpace
|
||
|
{
|
||
|
get { return _cs; }
|
||
|
set
|
||
|
{
|
||
|
if (!Enum.IsDefined(typeof(XColorSpace), value))
|
||
|
throw new InvalidEnumArgumentException("value", (int)value, typeof(XColorSpace));
|
||
|
_cs = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates whether this XColor structure is uninitialized.
|
||
|
/// </summary>
|
||
|
public bool IsEmpty
|
||
|
{
|
||
|
get { return this == Empty; }
|
||
|
}
|
||
|
|
||
|
#if GDI
|
||
|
#if UseGdiObjects
|
||
|
/// <summary>
|
||
|
/// Implicit conversion from Color to XColor
|
||
|
/// </summary>
|
||
|
public static implicit operator XColor(Color color)
|
||
|
{
|
||
|
return new XColor(color);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
///<summary>
|
||
|
/// Creates a System.Drawing.Color object from this color.
|
||
|
/// </summary>
|
||
|
public System.Drawing.Color ToGdiColor()
|
||
|
{
|
||
|
return System.Drawing.Color.FromArgb((int)(_a * 255), _r, _g, _b);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if WPF
|
||
|
///<summary>
|
||
|
/// Creates a WpfColor object from this color.
|
||
|
/// </summary>
|
||
|
public WpfColor ToWpfColor()
|
||
|
{
|
||
|
return WpfColor.FromArgb((byte)(_a * 255), _r, _g, _b);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if UWP
|
||
|
///<summary>
|
||
|
/// Creates a Windows.UI.Color object from this color.
|
||
|
/// </summary>
|
||
|
public UwpColor ToUwpColor()
|
||
|
{
|
||
|
return UwpColor.FromArgb((byte)(_a * 255), _r, _g, _b);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the specified object is a Color structure and is equivalent to this
|
||
|
/// Color structure.
|
||
|
/// </summary>
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||
|
if (obj is XColor)
|
||
|
{
|
||
|
XColor color = (XColor)obj;
|
||
|
if (_r == color._r && _g == color._g && _b == color._b &&
|
||
|
_c == color._c && _m == color._m && _y == color._y && _k == color._k &&
|
||
|
_gs == color._gs)
|
||
|
{
|
||
|
return _a == color._a;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the hash code for this instance.
|
||
|
/// </summary>
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
// ReSharper disable NonReadonlyFieldInGetHashCode
|
||
|
return ((byte)(_a * 255)) ^ _r ^ _g ^ _b;
|
||
|
// ReSharper restore NonReadonlyFieldInGetHashCode
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether two colors are equal.
|
||
|
/// </summary>
|
||
|
public static bool operator ==(XColor left, XColor right)
|
||
|
{
|
||
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||
|
if (left._r == right._r && left._g == right._g && left._b == right._b &&
|
||
|
left._c == right._c && left._m == right._m && left._y == right._y && left._k == right._k &&
|
||
|
left._gs == right._gs)
|
||
|
{
|
||
|
return left._a == right._a;
|
||
|
}
|
||
|
return false;
|
||
|
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether two colors are not equal.
|
||
|
/// </summary>
|
||
|
public static bool operator !=(XColor left, XColor right)
|
||
|
{
|
||
|
return !(left == right);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets a value indicating whether this color is a known color.
|
||
|
/// </summary>
|
||
|
public bool IsKnownColor
|
||
|
{
|
||
|
get { return XKnownColorTable.IsKnownColor(Argb); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the hue-saturation-brightness (HSB) hue value, in degrees, for this color.
|
||
|
/// </summary>
|
||
|
/// <returns>The hue, in degrees, of this color. The hue is measured in degrees, ranging from 0 through 360, in HSB color space.</returns>
|
||
|
public double GetHue()
|
||
|
{
|
||
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||
|
if ((_r == _g) && (_g == _b))
|
||
|
return 0;
|
||
|
|
||
|
double value1 = _r / 255.0;
|
||
|
double value2 = _g / 255.0;
|
||
|
double value3 = _b / 255.0;
|
||
|
double value7 = 0;
|
||
|
double value4 = value1;
|
||
|
double value5 = value1;
|
||
|
if (value2 > value4)
|
||
|
value4 = value2;
|
||
|
|
||
|
if (value3 > value4)
|
||
|
value4 = value3;
|
||
|
|
||
|
if (value2 < value5)
|
||
|
value5 = value2;
|
||
|
|
||
|
if (value3 < value5)
|
||
|
value5 = value3;
|
||
|
|
||
|
double value6 = value4 - value5;
|
||
|
if (value1 == value4)
|
||
|
value7 = (value2 - value3) / value6;
|
||
|
else if (value2 == value4)
|
||
|
value7 = 2f + ((value3 - value1) / value6);
|
||
|
else if (value3 == value4)
|
||
|
value7 = 4f + ((value1 - value2) / value6);
|
||
|
|
||
|
value7 *= 60;
|
||
|
if (value7 < 0)
|
||
|
value7 += 360;
|
||
|
return value7;
|
||
|
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the hue-saturation-brightness (HSB) saturation value for this color.
|
||
|
/// </summary>
|
||
|
/// <returns>The saturation of this color. The saturation ranges from 0 through 1, where 0 is grayscale and 1 is the most saturated.</returns>
|
||
|
public double GetSaturation()
|
||
|
{
|
||
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||
|
double value1 = _r / 255.0;
|
||
|
double value2 = _g / 255.0;
|
||
|
double value3 = _b / 255.0;
|
||
|
double value7 = 0;
|
||
|
double value4 = value1;
|
||
|
double value5 = value1;
|
||
|
if (value2 > value4)
|
||
|
value4 = value2;
|
||
|
|
||
|
if (value3 > value4)
|
||
|
value4 = value3;
|
||
|
|
||
|
if (value2 < value5)
|
||
|
value5 = value2;
|
||
|
|
||
|
if (value3 < value5)
|
||
|
value5 = value3;
|
||
|
|
||
|
if (value4 == value5)
|
||
|
return value7;
|
||
|
|
||
|
double value6 = (value4 + value5) / 2;
|
||
|
if (value6 <= 0.5)
|
||
|
return (value4 - value5) / (value4 + value5);
|
||
|
return (value4 - value5) / ((2f - value4) - value5);
|
||
|
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the hue-saturation-brightness (HSB) brightness value for this color.
|
||
|
/// </summary>
|
||
|
/// <returns>The brightness of this color. The brightness ranges from 0 through 1, where 0 represents black and 1 represents white.</returns>
|
||
|
public double GetBrightness()
|
||
|
{
|
||
|
double value1 = _r / 255.0;
|
||
|
double value2 = _g / 255.0;
|
||
|
double value3 = _b / 255.0;
|
||
|
double value4 = value1;
|
||
|
double value5 = value1;
|
||
|
if (value2 > value4)
|
||
|
value4 = value2;
|
||
|
|
||
|
if (value3 > value4)
|
||
|
value4 = value3;
|
||
|
|
||
|
if (value2 < value5)
|
||
|
value5 = value2;
|
||
|
|
||
|
if (value3 < value5)
|
||
|
value5 = value3;
|
||
|
|
||
|
return (value4 + value5) / 2;
|
||
|
}
|
||
|
|
||
|
///<summary>
|
||
|
/// One of the RGB values changed; recalculate other color representations.
|
||
|
/// </summary>
|
||
|
void RgbChanged()
|
||
|
{
|
||
|
// ReSharper disable LocalVariableHidesMember
|
||
|
_cs = XColorSpace.Rgb;
|
||
|
int c = 255 - _r;
|
||
|
int m = 255 - _g;
|
||
|
int y = 255 - _b;
|
||
|
int k = Math.Min(c, Math.Min(m, y));
|
||
|
if (k == 255)
|
||
|
_c = _m = _y = 0;
|
||
|
else
|
||
|
{
|
||
|
float black = 255f - k;
|
||
|
_c = (c - k) / black;
|
||
|
_m = (m - k) / black;
|
||
|
_y = (y - k) / black;
|
||
|
}
|
||
|
_k = _gs = k / 255f;
|
||
|
// ReSharper restore LocalVariableHidesMember
|
||
|
}
|
||
|
|
||
|
///<summary>
|
||
|
/// One of the CMYK values changed; recalculate other color representations.
|
||
|
/// </summary>
|
||
|
void CmykChanged()
|
||
|
{
|
||
|
_cs = XColorSpace.Cmyk;
|
||
|
float black = _k * 255;
|
||
|
float factor = 255f - black;
|
||
|
_r = (byte)(255 - Math.Min(255f, _c * factor + black));
|
||
|
_g = (byte)(255 - Math.Min(255f, _m * factor + black));
|
||
|
_b = (byte)(255 - Math.Min(255f, _y * factor + black));
|
||
|
_gs = (float)(1 - Math.Min(1.0, 0.3f * _c + 0.59f * _m + 0.11 * _y + _k));
|
||
|
}
|
||
|
|
||
|
///<summary>
|
||
|
/// The gray scale value changed; recalculate other color representations.
|
||
|
/// </summary>
|
||
|
void GrayChanged()
|
||
|
{
|
||
|
_cs = XColorSpace.GrayScale;
|
||
|
_r = (byte)(_gs * 255);
|
||
|
_g = (byte)(_gs * 255);
|
||
|
_b = (byte)(_gs * 255);
|
||
|
_c = 0;
|
||
|
_m = 0;
|
||
|
_y = 0;
|
||
|
_k = 1 - _gs;
|
||
|
}
|
||
|
|
||
|
// Properties
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the alpha value the specifies the transparency.
|
||
|
/// The value is in the range from 1 (opaque) to 0 (completely transparent).
|
||
|
/// </summary>
|
||
|
public double A
|
||
|
{
|
||
|
get { return _a; }
|
||
|
set
|
||
|
{
|
||
|
if (value < 0)
|
||
|
_a = 0;
|
||
|
else if (value > 1)
|
||
|
_a = 1;
|
||
|
else
|
||
|
_a = (float)value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the red value.
|
||
|
/// </summary>
|
||
|
public byte R
|
||
|
{
|
||
|
get { return _r; }
|
||
|
set { _r = value; RgbChanged(); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the green value.
|
||
|
/// </summary>
|
||
|
public byte G
|
||
|
{
|
||
|
get { return _g; }
|
||
|
set { _g = value; RgbChanged(); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the blue value.
|
||
|
/// </summary>
|
||
|
public byte B
|
||
|
{
|
||
|
get { return _b; }
|
||
|
set { _b = value; RgbChanged(); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the RGB part value of the color. Internal helper function.
|
||
|
/// </summary>
|
||
|
internal uint Rgb
|
||
|
{
|
||
|
get { return ((uint)_r << 16) | ((uint)_g << 8) | _b; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the ARGB part value of the color. Internal helper function.
|
||
|
/// </summary>
|
||
|
internal uint Argb
|
||
|
{
|
||
|
get { return ((uint)(_a * 255) << 24) | ((uint)_r << 16) | ((uint)_g << 8) | _b; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the cyan value.
|
||
|
/// </summary>
|
||
|
public double C
|
||
|
{
|
||
|
get { return _c; }
|
||
|
set
|
||
|
{
|
||
|
if (value < 0)
|
||
|
_c = 0;
|
||
|
else if (value > 1)
|
||
|
_c = 1;
|
||
|
else
|
||
|
_c = (float)value;
|
||
|
CmykChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the magenta value.
|
||
|
/// </summary>
|
||
|
public double M
|
||
|
{
|
||
|
get { return _m; }
|
||
|
set
|
||
|
{
|
||
|
if (value < 0)
|
||
|
_m = 0;
|
||
|
else if (value > 1)
|
||
|
_m = 1;
|
||
|
else
|
||
|
_m = (float)value;
|
||
|
CmykChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the yellow value.
|
||
|
/// </summary>
|
||
|
public double Y
|
||
|
{
|
||
|
get { return _y; }
|
||
|
set
|
||
|
{
|
||
|
if (value < 0)
|
||
|
_y = 0;
|
||
|
else if (value > 1)
|
||
|
_y = 1;
|
||
|
else
|
||
|
_y = (float)value;
|
||
|
CmykChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the black (or key) value.
|
||
|
/// </summary>
|
||
|
public double K
|
||
|
{
|
||
|
get { return _k; }
|
||
|
set
|
||
|
{
|
||
|
if (value < 0)
|
||
|
_k = 0;
|
||
|
else if (value > 1)
|
||
|
_k = 1;
|
||
|
else
|
||
|
_k = (float)value;
|
||
|
CmykChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the gray scale value.
|
||
|
/// </summary>
|
||
|
// ReSharper disable InconsistentNaming
|
||
|
public double GS
|
||
|
// ReSharper restore InconsistentNaming
|
||
|
{
|
||
|
get { return _gs; }
|
||
|
set
|
||
|
{
|
||
|
if (value < 0)
|
||
|
_gs = 0;
|
||
|
else if (value > 1)
|
||
|
_gs = 1;
|
||
|
else
|
||
|
_gs = (float)value;
|
||
|
GrayChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Represents the null color.
|
||
|
/// </summary>
|
||
|
public static XColor Empty;
|
||
|
|
||
|
///<summary>
|
||
|
/// Special property for XmlSerializer only.
|
||
|
/// </summary>
|
||
|
public string RgbCmykG
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return String.Format(CultureInfo.InvariantCulture,
|
||
|
"{0};{1};{2};{3};{4};{5};{6};{7};{8}", _r, _g, _b, _c, _m, _y, _k, _gs, _a);
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
string[] values = value.Split(';');
|
||
|
_r = byte.Parse(values[0], CultureInfo.InvariantCulture);
|
||
|
_g = byte.Parse(values[1], CultureInfo.InvariantCulture);
|
||
|
_b = byte.Parse(values[2], CultureInfo.InvariantCulture);
|
||
|
_c = float.Parse(values[3], CultureInfo.InvariantCulture);
|
||
|
_m = float.Parse(values[4], CultureInfo.InvariantCulture);
|
||
|
_y = float.Parse(values[5], CultureInfo.InvariantCulture);
|
||
|
_k = float.Parse(values[6], CultureInfo.InvariantCulture);
|
||
|
_gs = float.Parse(values[7], CultureInfo.InvariantCulture);
|
||
|
_a = float.Parse(values[8], CultureInfo.InvariantCulture);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void CheckByte(int val, string name)
|
||
|
{
|
||
|
if (val < 0 || val > 0xFF)
|
||
|
throw new ArgumentException(PSSR.InvalidValue(val, name, 0, 255));
|
||
|
}
|
||
|
|
||
|
XColorSpace _cs;
|
||
|
|
||
|
float _a; // alpha
|
||
|
|
||
|
byte _r; // \
|
||
|
byte _g; // |--- RGB
|
||
|
byte _b; // /
|
||
|
|
||
|
float _c; // \
|
||
|
float _m; // |--- CMYK
|
||
|
float _y; // |
|
||
|
float _k; // /
|
||
|
|
||
|
float _gs; // >--- gray scale
|
||
|
}
|
||
|
}
|