基本的なやりかたは、イメージをグレースケールのパレットフォーマットに変換してから、色相を変更するパレットを与えるだけです。私はそれらすべてのツールセットを手に入れました。私は関連するコードを見つけることができるかどうかがわかります。
グレースケールのパレット画像を作成するには、元の画像のピクセルを何とか得ることができます。すでに灰色の場合、R/G/Bコンポーネントのいずれかが行います。これらをバイト配列に格納し、パレット画像をその中から焼きます。これを行う最も簡単な方法は、Image.LockBits
関数を使用することです。この関数は、画像を保持する配列に直接アクセスできます。ここに私のツール機能があります:
/// <summary>
/// Creates a bitmap based on data, width, height, stride and pixel format.
/// </summary>
/// <param name="sourceData">Byte array of raw source data</param>
/// <param name="width">Width of the image</param>
/// <param name="height">Height of the image</param>
/// <param name="stride">Scanline length inside the data</param>
/// <param name="pixelFormat">Pixel format</param>
/// <param name="palette">Color palette</param>
/// <param name="defaultColor">Default color to fill in on the palette if the given colors don't fully fill it.</param>
/// <returns>The new image</returns>
public static Bitmap BuildImage(Byte[] sourceData, Int32 width, Int32 height, Int32 stride, PixelFormat pixelFormat, Color[] palette, Color? defaultColor)
{
Bitmap newImage = new Bitmap(width, height, pixelFormat);
BitmapData targetData = newImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, newImage.PixelFormat);
CopyToMemory(targetData.Scan0, sourceData, 0, sourceData.Length, stride, targetData.Stride);
newImage.UnlockBits(targetData);
// For indexed images, set the palette.
if ((pixelFormat & PixelFormat.Indexed) != 0 && palette != null)
{
ColorPalette pal = newImage.Palette;
for (Int32 i = 0; i < pal.Entries.Length; i++)
{
if (i < palette.Length)
pal.Entries[i] = palette[i];
else if (defaultColor.HasValue)
pal.Entries[i] = defaultColor.Value;
else
break;
}
newImage.Palette = pal;
}
return newImage;
}
public static void CopyToMemory(IntPtr target, Byte[] bytes, Int32 startPos, Int32 length, Int32 origStride, Int32 targetStride)
{
Int32 sourcePos = startPos;
IntPtr destPos = target;
Int32 minStride = Math.Min(origStride, targetStride);
while (length >= targetStride)
{
Marshal.Copy(bytes, sourcePos, destPos, minStride);
length -= origStride;
sourcePos += origStride;
destPos = new IntPtr(destPos.ToInt64() + targetStride);
}
if (length > 0)
{
Marshal.Copy(bytes, sourcePos, destPos, length);
}
}
ここで素晴らしい色を得るためには、もちろんパレットが必要です。私はこのコードを少し適応を行い、代わりに簡単にアクセスするためのpublic static「SCALE」に民間のconst「スケール」を作っ
https://richnewman.wordpress.com/about/code-listings-and-diagrams/hslcolor-class/
注:このため、私はリッチニューマンのHSLColorクラスを使用します私の操作のために。
/// <summary>
/// Generates a colour palette of the given bits per pixel containing a hue rotation of the given range.
/// </summary>
/// <param name="bpp">Bits per pixel of the image the palette is for.</param>
/// <param name="blackOnZero">Replace the first colour on the palette with black.</param>
/// <param name="addTransparentZero">Make the first colour on the palette transparent.</param>
/// <param name="reverseGenerated">Reverse the generated range. This happens after the generating, and before the operations on the first index/</param>
/// <param name="startHue">Start hue range. Value from 0 to 240.</param>
/// <param name="endHue">End hue range. Value from 0 to 240. Must be higher then startHue.</param>
/// <param name="inclusiveEnd">True to include the end hue in the palette. If you generate a full hue range, this can be set to False to avoid getting a duplicate red colour on it.</param>
/// <returns>The generated palette, as array of System.Drawing.Color objects.</returns>
public static Color[] GenerateRainbowPalette(Int32 bpp, Boolean blackOnZero, Boolean addTransparentZero, Boolean reverseGenerated, Int32 startHue, Int32 endHue, Boolean inclusiveEnd)
{
Int32 colors = 1 << bpp;
Color[] pal = new Color[colors];
Double step = (Double)(endHue - startHue)/(inclusiveEnd ? colors - 1 : colors);
Double start = startHue;
Double satValue = ColorHSL.SCALE;
Double lumValue = 0.5 * ColorHSL.SCALE;
for (Int32 i = 0; i < colors; i++)
{
Double curStep = start + step * i;
pal[i] = new ColorHSL(curStep, satValue, lumValue);
}
if (reverseGenerated)
{
Color[] entries = pal.Reverse().ToArray();
for (Int32 i = 0; i < pal.Length; i++)
pal[i] = entries[i];
}
if (blackOnZero)
pal[0] = Color.Black;
// make color 0 transparent
if (addTransparentZero)
pal[0] = Color.FromArgb(0, pal[0]);
return pal;
}
完全な色相の回転は、赤から黄、シアンから緑、青から紫、および赤に戻ります。しかし、偽色に良い効果を出すには、最も高い値が最も低い値に似ていることを望まないので、青から赤に行く方が良いです。これは、生成された範囲を制限し、最終的なパレットを反転することを意味します。そのため、これらのオプションを関数に追加しました。
青色〜赤色虹のための最終的な呼び出しは、このあった:ゲームの地形の高さマップに適用されるように、結果
Color[] heightmap = PaletteUtils.GenerateRainbowPalette(8, false, false, true, 0, 160, true);
: