Download CmykRgbColorConversion.zip, last updated 15/07/2018 (19.21 KB)

Download
  • md5: 1258961adc735c8388f9b35d867df7c6
  • sha1: 1e01eb8723aac6632f1c0fff5fb57f524116329c
  • sha256: cfc2141a0f0820962621bc35e10882e648c95496751b65ded610a0009faae5a6
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

/* Finding nearest colors using Euclidean distance
 * http://www.cyotek.com/blog/finding-nearest-colors-using-euclidean-distance
 *
 * Copyright © 2017 Cyotek Ltd.
 */

namespace Cyotek.Demo.CmykRgbColorConversion
{
  [DefaultProperty(nameof(Color))]
  [DefaultEvent(nameof(ColorChanged))]
  internal class ColorBox : Control, IButtonControl
  {
    #region Constants

    private static readonly object _eventColorChanged = new object();

    private static readonly object _eventShowNameChanged = new object();

    private static readonly object _eventTextAlignChanged = new object();

    #endregion

    #region Fields

    private Color _color;

    private DialogResult _dialogResult;

    private bool _showName;

    private ContentAlignment _textAlign;

    #endregion

    #region Constructors

    public ColorBox()
    {
      base.DoubleBuffered = true;

      _color = Color.White;
      _textAlign = ContentAlignment.BottomRight;
    }

    #endregion

    #region Events

    /// <summary>
    /// Occurs when the Color property value changes
    /// </summary>
    [Category("Property Changed")]
    public event EventHandler ColorChanged
    {
      add { this.Events.AddHandler(_eventColorChanged, value); }
      remove { this.Events.RemoveHandler(_eventColorChanged, value); }
    }

    /// <summary>
    /// Occurs when the ShowName property value changes
    /// </summary>
    [Category("Property Changed")]
    public event EventHandler ShowNameChanged
    {
      add { this.Events.AddHandler(_eventShowNameChanged, value); }
      remove { this.Events.RemoveHandler(_eventShowNameChanged, value); }
    }

    /// <summary>
    /// Occurs when the TextAlign property value changes
    /// </summary>
    [Category("Property Changed")]
    public event EventHandler TextAlignChanged
    {
      add { this.Events.AddHandler(_eventTextAlignChanged, value); }
      remove { this.Events.RemoveHandler(_eventTextAlignChanged, value); }
    }

    #endregion

    #region Properties

    [Category("Appearance")]
    [DefaultValue(typeof(Color), "White")]
    public Color Color
    {
      get { return _color; }
      set
      {
        if (_color != value)
        {
          _color = value;

          this.OnColorChanged(EventArgs.Empty);
        }
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public override Font Font
    {
      get { return base.Font; }
      set { base.Font = value; }
    }

    [Category("Appearance")]
    [DefaultValue(false)]
    public bool ShowName
    {
      get { return _showName; }
      set
      {
        if (_showName != value)
        {
          _showName = value;

          this.OnShowNameChanged(EventArgs.Empty);
        }
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public override string Text
    {
      get { return base.Text; }
      set { base.Text = value; }
    }

    [Category("Appearance")]
    [DefaultValue(typeof(ContentAlignment), "BottomRight")]
    public ContentAlignment TextAlign
    {
      get { return _textAlign; }
      set
      {
        if (_textAlign != value)
        {
          _textAlign = value;

          this.OnTextAlignChanged(EventArgs.Empty);
        }
      }
    }

    #endregion

    #region Methods

    /// <summary>
    /// Raises the <see cref="ColorChanged" /> event.
    /// </summary>
    /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
    protected virtual void OnColorChanged(EventArgs e)
    {
      EventHandler handler;

      this.Invalidate();

      handler = (EventHandler)this.Events[_eventColorChanged];

      handler?.Invoke(this, e);
    }

    protected override void OnGotFocus(EventArgs e)
    {
      base.OnGotFocus(e);

      this.Invalidate();
    }

    protected override void OnKeyUp(KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Space && e.Modifiers == Keys.None)
      {
        e.Handled = true;
        this.PerformClick();
      }

      base.OnKeyUp(e);
    }

    protected override void OnLostFocus(EventArgs e)
    {
      base.OnLostFocus(e);

      this.Invalidate();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      Graphics g;
      Rectangle bounds;

      base.OnPaint(e);

      bounds = new Rectangle(0, 0, this.Width - 1, this.Height - 1);

      g = e.Graphics;

      this.DrawColor(g, bounds);
      this.DrawName(g, bounds);
      this.DrawFocus(g, bounds);
      g.DrawRectangle(SystemPens.WindowFrame, bounds);
    }

    /// <summary>
    /// Raises the <see cref="ShowNameChanged" /> event.
    /// </summary>
    /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
    protected virtual void OnShowNameChanged(EventArgs e)
    {
      EventHandler handler;

      this.Invalidate();

      handler = (EventHandler)this.Events[_eventShowNameChanged];

      handler?.Invoke(this, e);
    }

    /// <summary>
    /// Raises the <see cref="TextAlignChanged" /> event.
    /// </summary>
    /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
    protected virtual void OnTextAlignChanged(EventArgs e)
    {
      EventHandler handler;

      this.Invalidate();

      handler = (EventHandler)this.Events[_eventTextAlignChanged];

      handler?.Invoke(this, e);
    }

    private void DrawColor(Graphics g, Rectangle bounds)
    {
      if (_color.A != 255)
      {
        using (Brush brush = new HatchBrush(HatchStyle.DiagonalCross, Color.Silver, Color.White))
        {
          g.FillRectangle(brush, bounds);
        }
      }

      using (Brush brush = new SolidBrush(_color))
      {
        g.FillRectangle(brush, bounds);
      }
    }

    private void DrawFocus(Graphics g, Rectangle bounds)
    {
      if (this.ShowFocusCues && this.Focused)
      {
        NativeMethods.RECT rect;

        rect = new NativeMethods.RECT(3, 3, bounds.Width - 2, bounds.Height - 2);

        // The Win32 API DrawFocusRect draws using an inverted brush and so works on black,
        // whereas ControlPaint.DrawFocusRect decidedly does not
        NativeMethods.DrawFocusRect(g.GetHdc(), ref rect);
        g.ReleaseHdc();
      }
    }

    private void DrawName(Graphics g, Rectangle bounds)
    {
      if (_showName)
      {
        string name;
        TextFormatFlags flags;

        bounds = Rectangle.Inflate(bounds, -3, -3);

        name = _color.R + ", " + _color.G + ", " + _color.B;
        flags = TextFormatFlags.NoPadding | this.GetAlignmentFlags();

        TextRenderer.DrawText(g, name, this.Font, bounds, this.GetFixedContrast(_color), _color, flags);
      }
    }

    private TextFormatFlags GetAlignmentFlags()
    {
      TextFormatFlags result;

      result = 0;

      // ReSharper disable once ConvertIfStatementToSwitchStatement
      if (_textAlign == ContentAlignment.BottomLeft || _textAlign == ContentAlignment.MiddleLeft || _textAlign == ContentAlignment.TopLeft)
      {
        result |= TextFormatFlags.Left;
      }
      else if (_textAlign == ContentAlignment.BottomRight || _textAlign == ContentAlignment.MiddleRight || _textAlign == ContentAlignment.TopRight)
      {
        result |= TextFormatFlags.Right;
      }
      else
      {
        result |= TextFormatFlags.HorizontalCenter;
      }

      // ReSharper disable once ConvertIfStatementToSwitchStatement
      if (_textAlign == ContentAlignment.TopLeft || _textAlign == ContentAlignment.TopCenter || _textAlign == ContentAlignment.TopRight)
      {
        result |= TextFormatFlags.Top;
      }
      else if (_textAlign == ContentAlignment.BottomLeft || _textAlign == ContentAlignment.BottomCenter || _textAlign == ContentAlignment.BottomRight)
      {
        result |= TextFormatFlags.Bottom;
      }
      else
      {
        result |= TextFormatFlags.VerticalCenter;
      }

      return result;
    }

    private Color GetFixedContrast(Color color)
    {
      int threshold;
      int grayscale;
      Color result;

      threshold = 105;
      grayscale = Convert.ToInt32(color.R * 0.299 + color.G * 0.587 + color.B * 0.114);
      result = 255 - grayscale < threshold ? Color.Black : Color.White;

      return result;
    }

    #endregion

    #region IButtonControl Interface

    public void NotifyDefault(bool value)
    {
      this.Invalidate();
    }

    public void PerformClick()
    {
      this.OnClick(EventArgs.Empty);
    }

    DialogResult IButtonControl.DialogResult
    {
      get { return _dialogResult; }
      set { _dialogResult = value; }
    }

    #endregion
  }
}

Donate

Donate