Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 16717] ファイルの概要

コミット

commit 5e37154077ceca58edd185306498d6fa0cc56a59
Author: Nigel Tao <nigeltao@golang.org>
Date:   Tue Jul 9 19:17:17 2013 +1000

    image/color: add Plan9Palette and WebSafePalette.
    
    R=r, rsc, andybons
    CC=andybons, golang-dev
    https://golang.org/cl/10890045

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/5e37154077ceca58edd185306498d6fa0cc56a59

元コミット内容

image/color パッケージに Plan9PaletteWebSafePalette を追加します。

変更の背景

このコミットは、Go言語の標準ライブラリである image/color パッケージに、特定の用途で広く知られている2種類のカラーパレット、Plan9PaletteWebSafePalette を追加するものです。

デジタル画像処理やグラフィックスにおいて、表示可能な色の数は、ディスプレイの性能やファイル形式、アプリケーションの要件によって制限されることがあります。このような場合、限られた色数で画像を表現するために「カラーパレット」が用いられます。カラーパレットは、画像内で使用される色の集合を定義し、各ピクセルはそのパレット内のいずれかの色にマッピングされます。

Plan9PaletteWebSafePalette は、それぞれ異なる歴史的背景と目的を持つパレットです。これらを標準ライブラリに含めることで、Go言語で画像処理を行う開発者が、これらの一般的なパレットを容易に利用できるようになり、特にレガシーシステムとの互換性や、特定の視覚的特性を持つ画像を生成する際に役立ちます。

前提知識の解説

カラーパレットとは

カラーパレット(またはカラーマップ、ルックアップテーブル)は、デジタル画像やグラフィックスにおいて、使用可能な色の有限な集合を定義するものです。特に、インデックスカラー画像では、各ピクセルが直接色情報を保持するのではなく、パレット内の色のインデックス(番号)を保持します。これにより、ファイルサイズを削減したり、限られたハードウェアリソースで画像を効率的に表示したりすることが可能になります。

RGB色空間

RGBは、Red(赤)、Green(緑)、Blue(青)の3つの原色を混ぜ合わせることで、様々な色を表現する加法混色モデルです。各原色の強度を0から255(8ビットの場合)の範囲で指定することで、約1670万色(256^3)を表現できます。このコミットで扱われるパレットも、基本的にはRGB値の組み合わせで色が定義されています。

Plan 9 オペレーティングシステムとカラーパレット

Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。そのグラフィカル環境では、独自の256色パレットが使用されていました。このパレットは、単に256色をランダムに選んだものではなく、色の知覚的な均一性や、連続的なトーンの表現を重視して設計されています。特に、グレースケールや主要な色相のグラデーションが滑らかに表現されるように工夫されており、WebSafePaletteと比較して、より自然な画像表示に適しているとされています。このパレットは、24ビットRGB空間を4x4x4のサブディビジョンに分割し、各サブキューブ内で4つのシェードを持つことで、色の解像度を下げつつ、強度の解像度を高めるという思想に基づいています。

WebセーフカラーとWebSafePalette

Webセーフカラー(またはNetscape Color Cube)は、1990年代後半のWebブラウザが、限られた色数(通常256色)しか表示できない環境で、異なるプラットフォームやブラウザ間で一貫した色表示を保証するために考案された216色のパレットです。このパレットは、各RGB成分が0x00, 0x33, 0x66, 0x99, 0xCC, 0xFFのいずれかの値を取るように定義されており、これにより6x6x6 = 216色の組み合わせが生成されます。当時の多くのシステムでは、256色表示が一般的であり、Webセーフカラー以外の色を使用すると、ブラウザやOSによって色がディザリング(擬似的に色を表現するために異なる色のピクセルを混ぜて表示すること)されたり、意図しない色に変換されたりする可能性がありました。現代のシステムではフルカラー表示が一般的であるため、Webセーフカラーの必要性は薄れていますが、歴史的な経緯や特定のデザイン要件から、依然として参照されることがあります。

技術的詳細

このコミットでは、image/color パッケージに Plan9PaletteWebSafePalette という2つの新しいグローバル変数を追加しています。これらのパレットは、color.Color 型のスライスとして定義されており、それぞれ256色と216色のRGBA値を含んでいます。

特筆すべきは、これらのパレットが手動で定義されているのではなく、src/pkg/image/color/gen.go というGoプログラムによって自動生成されている点です。

gen.go の役割は以下の通りです。

  1. Plan9Palette の生成ロジック:
    • 24ビットRGB空間を4x4x4のサブディビジョンに分割するというPlan 9パレットの設計思想に基づき、各RGB成分の値を計算します。
    • 特に、グレースケール(R=G=B)や主要な色(赤、緑、青、シアン、マゼンタ、イエロー)のグラデーションが滑らかになるように、複雑な計算式を用いてRGBA値を生成しています。
    • fmt.Sprintf を用いて、Goのコードとして整形された RGBA 構造体の初期化コードを生成します。
  2. WebSafePalette の生成ロジック:
    • 各RGB成分が0x00, 0x33, 0x66, 0x99, 0xCC, 0xFFのいずれかになるように、単純なループで216色のRGBA値を生成します。
    • こちらも fmt.Sprintf を用いて、Goのコードとして整形された RGBA 構造体の初期化コードを生成します。

gen.go は、go run gen.go | gofmt > palette.go というコマンドで実行されることを想定しており、生成された palette.go ファイルは、手動で編集されるべきではないことを示すコメント // generated by go run gen.go; DO NOT EDIT が付与されています。これにより、パレットの定義の一貫性と正確性が保証されます。

コアとなるコードの変更箇所

このコミットで追加された主要なファイルは以下の2つです。

  1. src/pkg/image/color/gen.go (新規追加)
    • Plan9PaletteWebSafePalette のGoコードを生成するためのプログラム。
  2. src/pkg/image/color/palette.go (新規追加)
    • gen.go によって生成される、Plan9PaletteWebSafePalette の実際の定義が含まれるファイル。

gen.gomain 関数内で printPlan9()printWebSafe() が呼び出され、それぞれ Plan9PaletteWebSafePalette の定義を標準出力に出力します。この出力がリダイレクトされて palette.go ファイルが作成されます。

コアとなるコードの解説

src/pkg/image/color/gen.go

このファイルは、palette.go を生成するためのユーティリティプログラムです。

printPlan9() 関数

func printPlan9() {
	c, lines := [3]int{}, [256]string{}
	for r, i := 0, 0; r != 4; r++ {
		for v := 0; v != 4; v, i = v+1, i+16 {
			for g, j := 0, v-r; g != 4; g++ {
				for b := 0; b != 4; b, j = b+1, j+1 {
					den := r
					if g > den {
						den = g
					}
					if b > den {
						den = b
					}
					if den == 0 {
						c[0] = 0x11 * v
						c[1] = 0x11 * v
						c[2] = 0x11 * v
					} else {
						num := 17 * (4*den + v)
						c[0] = r * num / den
						c[1] = g * num / den
						c[2] = b * num / den
					}
					lines[i+(j&0x0f)] =
						fmt.Sprintf("\tRGBA{0x%02x, 0x%02x, 0x%02x, 0xff},", c[0], c[1], c[2])
				}
			}
		}
	}
	// ... (コメントと出力ロジック)
}

この関数は、Plan 9パレットの256色を生成する複雑なロジックを含んでいます。

  • r, v, g, b の4重ループで、色の各成分の組み合わせを探索します。
  • den (denominator) は、色の正規化に使用される最大成分値です。
  • den == 0 の場合は、グレースケール(R=G=B)の計算を行います。
  • den != 0 の場合は、Plan 9パレットの特性である、色の知覚的な均一性を考慮した計算式 num := 17 * (4*den + v) を用いて、各RGB成分の値を決定します。この計算により、色の解像度を下げつつ、強度の解像度を高めるというPlan 9パレットの設計思想が実現されています。
  • 生成されたRGBA値は fmt.Sprintf を使ってGoのコード文字列に変換され、lines スライスに格納されます。
  • 最後に、パレットのGoコードと説明コメントが標準出力に出力されます。

printWebSafe() 関数

func printWebSafe() {
	lines := [6 * 6 * 6]string{}
	for r := 0; r < 6; r++ {
		for g := 0; g < 6; g++ {
			for b := 0; b < 6; b++ {
				lines[36*r+6*g+b] =
					fmt.Sprintf("\tRGBA{0x%02x, 0x%02x, 0x%02x, 0xff},", 0x33*r, 0x33*g, 0x33*b)
			}
		}
	}
	// ... (コメントと出力ロジック)
}

この関数は、Webセーフパレットの216色を生成します。

  • r, g, b の3重ループで、各RGB成分が0から5の範囲で変化します。
  • 各成分の値は 0x33 (10進数で51) の倍数として計算されます。これにより、0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF の6段階の値が生成され、6x6x6 = 216色のWebセーフカラーが定義されます。
  • 生成されたRGBA値は fmt.Sprintf を使ってGoのコード文字列に変換され、lines スライスに格納されます。
  • 最後に、パレットのGoコードと説明コメントが標準出力に出力されます。

src/pkg/image/color/palette.go

このファイルは gen.go によって生成されるため、手動での変更は意図されていません。ファイルの内容は、Plan9PaletteWebSafePalette という2つの []Color 型のグローバル変数の定義です。それぞれの変数には、対応するパレットのすべての色が color.RGBA 構造体のスライスとしてハードコードされています。

例:

var Plan9Palette = []Color{
	RGBA{0x00, 0x00, 0x00, 0xff},
	RGBA{0x00, 0x00, 0x44, 0xff},
	// ... 256色
}

var WebSafePalette = []Color{
	RGBA{0x00, 0x00, 0x00, 0xff},
	RGBA{0x00, 0x00, 0x33, 0xff},
	// ... 216色
}

これらのパレットは、image/color パッケージをインポートすることで、Goのプログラムから直接利用できるようになります。例えば、画像を特定のパレットに減色する際などに活用できます。

関連リンク

参考にした情報源リンク