Skip to content

Instantly share code, notes, and snippets.

@mstefarov
Created June 9, 2014 00:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mstefarov/3b59867705350c3c32ca to your computer and use it in GitHub Desktop.
Save mstefarov/3b59867705350c3c32ca to your computer and use it in GitHub Desktop.
// Copyright 2013 Matvei Stefarov <me@matvei.org>
using System;
using JetBrains.Annotations;
using RgbColor = System.Drawing.Color;
namespace fCraft.Drawing {
/// <summary> Represents a palette of Minecraft blocks,
/// that allows matching RGB colors to their closest block equivalents. </summary>
public class BlockPalette {
// XN/YN/ZN are illuminant D65 tristimulus values
const double XN = 95.047,
YN = 100.000,
ZN = 108.883;
// these constant are used in CIEXYZ -> CIELAB conversion
const double LinearThreshold = (6/29d)*(6/29d)*(6/29d),
LinearMultiplier = (1/3d)*(29/6d)*(29/6d),
LinearConstant = (4/29d);
// CIE76 formula for Delta-E, over CIELAB color space
static double ColorDifference( LabColor color1, LabColor color2 ) {
return
// NOTE: multiplying delta-L by 1.2 is optional and not part of vanilla deltaE formula.
// It is done here subjectively to emphasize luminance difference over hue/saturation difference.
Math.Sqrt( (color2.L - color1.L)*(color2.L - color1.L)*1.2 +
(color2.a - color1.a)*(color2.a - color1.a) +
(color2.b - color1.b)*(color2.b - color1.b) );
}
// Conversion from RGB to CIELAB, using illuminant D65.
static LabColor RgbToLab( RgbColor color ) {
// RGB are assumed to be in [0...255] range
double R = color.R/255d;
double G = color.G/255d;
double B = color.B/255d;
// CIEXYZ coordinates are normalized to [0...1]
double x = 0.4124564*R + 0.3575761*G + 0.1804375*B;
double y = 0.2126729*R + 0.7151522*G + 0.0721750*B;
double z = 0.0193339*R + 0.1191920*G + 0.9503041*B;
double xRatio = x/XN;
double yRatio = y/YN;
double zRatio = z/ZN;
LabColor result = new LabColor {
// L is normalized to [0...100]
L = 116*XyzToLab( yRatio ) - 16,
a = 500*(XyzToLab( xRatio ) - XyzToLab( yRatio )),
b = 200*(XyzToLab( yRatio ) - XyzToLab( zRatio ))
};
return result;
}
static double XyzToLab( double ratio ) {
if( ratio > LinearThreshold ) {
return Math.Pow( ratio, 1/3d );
} else {
return LinearMultiplier*ratio + LinearConstant;
}
}
protected struct LabColor {
public double L, a, b;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment