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

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

このコミットは、Go言語の標準ライブラリである image パッケージと image/color パッケージに、新しいカラーモデル RGB (24ビット) と RGB48 (48ビット) を追加するものです。これにより、より広範な画像フォーマットや色深度の表現が可能になり、特にアルファチャネルを持たない不透明なRGB画像を効率的に扱うための基盤が強化されます。

コミット

commit e5902fc70f1a50920ce0ac95ffbed3a9af2b80b5
Author: ChaiShushan <chaishushan@gmail.com>
Date:   Thu Dec 12 11:24:27 2013 -0800

    image: add RGB and RGB48
    
    R=golang-dev, r, nigeltao
    CC=golang-dev
    https://golang.org/cl/13239051

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

https://github.com/golang/go/commit/e5902fc70f1a50920ce0ac95ffbed3a9af2b80b5

元コミット内容

image: RGBおよびRGB48を追加

変更の背景

Go言語の image パッケージは、様々な画像フォーマットを扱うための基本的なインターフェースと実装を提供します。既存の image/color パッケージには、RGBA (32ビット、アルファチャネル付き) や RGBA64 (64ビット、アルファチャネル付き) といったカラーモデルが存在していましたが、アルファチャネルを持たない純粋なRGBカラーモデル、特に24ビット(各チャネル8ビット)や48ビット(各チャネル16ビット)の色深度を直接表現する型が不足していました。

多くの画像フォーマット(例: JPEG、BMPの一部、TIFFの一部)は、アルファチャネルを持たないRGB形式でピクセルデータを格納します。これらのフォーマットを効率的に読み書きし、メモリ上で表現するためには、アルファチャネルの処理オーバーヘッドなしにRGBデータのみを扱う専用の型が望ましいです。

このコミットは、以下のニーズに応えるために導入されました。

  1. 効率的なメモリ利用: アルファチャネルが不要な場合に、その分のメモリを節約し、よりコンパクトなデータ構造で画像を表現するため。
  2. 広範な画像フォーマットのサポート: 24ビットRGBや48ビットRGBといった一般的な色深度を持つ画像フォーマットとの互換性を高めるため。
  3. 色深度の柔軟性: 各チャネル8ビット(24ビットRGB)と16ビット(48ビットRGB)の両方に対応することで、より広い色域や高精度な色表現が求められる場面(例: プロフェッショナルな画像処理、HDR画像)にも対応できるようにするため。
  4. 既存のGoイメージングエコシステムとの統合: image.Image インターフェースと image/color.Color インターフェースに準拠した形で新しい型を提供し、既存の画像処理ツールやライブラリとのシームレスな連携を可能にするため。

前提知識の解説

このコミットの理解には、Go言語の image および image/color パッケージに関する基本的な知識が必要です。

  • image/color.Color インターフェース: Go言語における色の抽象化を表すインターフェースです。唯一のメソッド RGBA() (r, g, b, a uint32) を持ち、任意の色をRGBA形式(各チャネル16ビット、アルファ値は0x0000から0xFFFFの範囲)で表現できるようにします。これにより、異なるカラーモデル間での色の変換や比較が可能になります。

  • image/color.Model インターフェース: あるカラーモデルから別のカラーモデルへ色を変換するためのインターフェースです。Convert(c Color) Color メソッドを持ち、入力された Color をそのモデルが表現できる最も近い色に変換して返します。例えば、RGBA モデルは入力された色をアルファ値を持つ32ビットRGBAに変換します。

  • image.Image インターフェース: Go言語における画像の抽象化を表すインターフェースです。以下のメソッドを持ちます。

    • ColorModel() color.Model: 画像のカラーモデルを返します。
    • Bounds() image.Rectangle: 画像の論理的な境界(ピクセル座標の範囲)を返します。
    • At(x, y int) color.Color: 指定された座標 (x, y) のピクセルの色を color.Color インターフェースとして返します。
  • ピクセルデータ表現: Goの image パッケージでは、画像データは通常、Pix という []uint8 型のスライスに格納されます。このスライスには、各ピクセルの色チャネル値が特定の順序で並べられます。

  • Stride: Stride は、画像データにおいて、ある行のピクセルデータから次の行の同じX座標のピクセルデータまでのバイト数を表します。これにより、メモリ上の連続したデータから任意のピクセルを効率的に計算してアクセスできます。Stride は通常、幅 * ピクセルあたりのバイト数 で計算されますが、アライメントやパディングのためにこれより大きくなることもあります。

  • Rect (Rectangle): image.Rectangle は、画像の論理的な境界を定義する構造体で、Min (左上隅の点) と Max (右下隅の点) の2つの image.Point を持ちます。これにより、画像の全体または部分領域を表現します。

  • 色深度 (Bit Depth): 色深度は、各ピクセルが表現できる色の数を決定するビット数です。

    • 24ビットRGB: 各色チャネル(赤、緑、青)に8ビットずつ割り当てられ、合計24ビットで1ピクセルを表現します。各チャネルは0から255までの256段階の強度を持ち、約1670万色(2^24)を表現できます。
    • 48ビットRGB: 各色チャネルに16ビットずつ割り当てられ、合計48ビットで1ピクセルを表現します。各チャネルは0から65535までの65536段階の強度を持ち、非常に広い色域と滑らかなグラデーションを表現できます。これは、高精度な画像処理やHDR (High Dynamic Range) 画像で利用されます。
  • アルファチャネル: 色の透明度(不透明度)を表すチャネルです。アルファ値が0の場合は完全に透明、最大値の場合は完全に不透明です。このコミットで追加される RGB および RGB48 は、アルファチャネルを持たない「不透明な」色を扱います。

技術的詳細

このコミットは、src/pkg/image/color/color.gosrc/pkg/image/image.go の2つの主要なファイルに変更を加えています。

src/pkg/image/color/color.go の変更

  1. RGB 構造体の追加:

    • type RGB struct { R, G, B uint8 }
    • 各チャネルが uint8 (8ビット) で表現される24ビットRGBカラーモデルを定義します。
    • RGBA() (r, g, b, a uint32) メソッドを実装し、color.Color インターフェースを満たします。この実装では、uint8 の値を uint32 に拡張し、アルファ値は常に 0xFFFF (完全に不透明) となります。r |= r << 8 のようにビットシフトとOR演算を行うことで、8ビット値を16ビット値に「複製」し、uint32 の上位16ビットと下位16ビットの両方に同じ値が入るようにしています。これは、color.Color インターフェースの RGBA() メソッドが16ビット精度を要求するためです。
  2. RGB48 構造体の追加:

    • type RGB48 struct { R, G, B uint16 }
    • 各チャネルが uint16 (16ビット) で表現される48ビットRGBカラーモデルを定義します。
    • RGBA() (r, g, b, a uint32) メソッドを実装し、color.Color インターフェースを満たします。uint16 の値をそのまま uint32 にキャストし、アルファ値は常に 0xFFFF (完全に不透明) となります。
  3. RGBModel および RGB48Model の追加:

    • var RGBModel Model = ModelFunc(rgbModel)
    • var RGB48Model Model = ModelFunc(rgb48Model)
    • 新しいカラーモデルに対応する color.Model インスタンスが追加されます。これらは ModelFunc を使用して、対応する変換関数 (rgbModel, rgb48Model) をラップしています。
  4. rgbModel および rgb48Model 関数の追加:

    • func rgbModel(c Color) Color: 入力された ColorRGB 型に変換します。もし入力が既に RGB 型であればそのまま返し、そうでなければ RGBA() メソッドで取得した uint32 値を8ビットに丸めて RGB を生成します。
    • func rgb48Model(c Color) Color: 入力された ColorRGB48 型に変換します。もし入力が既に RGB48 型であればそのまま返し、そうでなければ RGBA() メソッドで取得した uint32 値をそのまま uint16 にキャストして RGB48 を生成します。

src/pkg/image/image.go の変更

  1. RGB 構造体の追加:

    • type RGB struct { Pix []uint8; Stride int; Rect Rectangle }
    • 24ビットRGB画像をメモリ上で表現するための構造体です。
    • Pix: ピクセルデータを格納する []uint8 スライス。データはR, G, Bの順で並びます。
    • Stride: 各行のバイト数。幅 * 3 で計算されます。
    • Rect: 画像の境界。
    • ColorModel() color.Model: color.RGBModel を返します。
    • Bounds() Rectangle: Rect を返します。
    • At(x, y int) color.Color: 指定された座標のピクセル色を color.RGB 型で返します。
    • PixOffset(x, y int) int: 指定された座標のピクセルデータの開始インデックスを計算します。
    • Set(x, y int, c color.Color): 指定された座標のピクセル色を設定します。入力された color.Colorcolor.RGBModel で変換してから設定します。
    • SetRGB(x, y int, c color.RGB): Set と同様ですが、引数が直接 color.RGB 型であるため、変換が不要です。
    • SubImage(r Rectangle) Image: 指定された矩形領域のサブイメージを返します。元の画像とピクセルデータを共有します。
    • Opaque() bool: 常に true を返します。これは、RGB 画像がアルファチャネルを持たず、常に不透明であることを示します。
    • NewRGB(r Rectangle) *RGB: 指定された境界を持つ新しい RGB 画像を生成し、ピクセルデータ用のバッファを割り当てます。
  2. RGB48 構造体の追加:

    • type RGB48 struct { Pix []uint8; Stride int; Rect Rectangle }
    • 48ビットRGB画像をメモリ上で表現するための構造体です。
    • Pix: ピクセルデータを格納する []uint8 スライス。データはR, G, Bの順で、各チャネルがビッグエンディアン形式の2バイトで格納されます。つまり、1ピクセルあたり6バイト(R上位8ビット, R下位8ビット, G上位8ビット, G下位8ビット, B上位8ビット, B下位8ビット)です。
    • Stride: 各行のバイト数。幅 * 6 で計算されます。
    • Rect: 画像の境界。
    • ColorModel() color.Model: color.RGB48Model を返します。
    • Bounds() Rectangle: Rect を返します。
    • At(x, y int) color.Color: 指定された座標のピクセル色を color.RGB48 型で返します。ピクセルデータから uint16 値を再構築するために、バイトオーダー(ビッグエンディアン)を考慮したビットシフトとOR演算を行います。
    • PixOffset(x, y int) int: 指定された座標のピクセルデータの開始インデックスを計算します。
    • Set(x, y int, c color.Color): 指定された座標のピクセル色を設定します。入力された color.Colorcolor.RGB48Model で変換してから、各 uint16 チャネルを2バイトに分割して Pix に格納します。
    • SetRGB48(x, y int, c color.RGB48): Set と同様ですが、引数が直接 color.RGB48 型であるため、変換が不要です。
    • SubImage(r Rectangle) Image: 指定された矩形領域のサブイメージを返します。元の画像とピクセルデータを共有します。
    • Opaque() bool: 常に true を返します。
    • NewRGB48(r Rectangle) *RGB48: 指定された境界を持つ新しい RGB48 画像を生成し、ピクセルデータ用のバッファを割り当てます。

src/pkg/image/image_test.go の変更

  • 新しい RGB および RGB48 画像型がテストスイートに追加され、既存の画像インターフェースのテストがこれらの新しい型に対しても実行されるようにしています。これにより、新しい実装が既存の image.Image インターフェースの期待される振る舞いを満たしていることを確認します。

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

src/pkg/image/color/color.go

 // RGB represents a traditional 24-bit fully opaque color,
 // having 8 bits for each of red, green and blue.
 type RGB struct {
 	R, G, B uint8
 }
 
 func (c RGB) RGBA() (r, g, b, a uint32) {
 	r = uint32(c.R)
 	r |= r << 8
 	g = uint32(c.G)
 	g |= g << 8
 	b = uint32(c.B)
 	b |= b << 8
 	a = 0xFFFF
 	return
 }
 
 // RGB48 represents a 48-bit fully opaque color,
 // having 16 bits for each of red, green and blue.
 type RGB48 struct {
 	R, G, B uint16
 }
 
 func (c RGB48) RGBA() (r, g, b, a uint32) {
 	return uint32(c.R), uint32(c.G), uint32(c.B), 0xFFFF
 }

 // Models for the standard color types.
 var (
 	RGBModel     Model = ModelFunc(rgbModel)
 	RGB48Model   Model = ModelFunc(rgb48Model)
 	RGBAModel    Model = ModelFunc(rgbaModel)
 	RGBA64Model  Model = ModelFunc(rgba64Model)
 	NRGBAModel   Model = ModelFunc(nrgbaModel)
 	NRGBA64Model Model = ModelFunc(nrgba64Model)
 	AlphaModel   Model = ModelFunc(alphaModel)
 	Alpha16Model Model = ModelFunc(alpha16Model)
 	GrayModel    Model = ModelFunc(grayModel)
 	Gray16Model  Model = ModelFunc(gray16Model)
 )
 
 func rgbModel(c Color) Color {
 	if _, ok := c.(RGB); ok {
 		return c
 	}
 	r, g, b, _ := c.RGBA()
 	return RGB{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)}
 }
 
 func rgb48Model(c Color) Color {
 	if _, ok := c.(RGB48); ok {
 		return c
 	}
 	r, g, b, _ := c.RGBA()
 	return RGB48{uint16(r), uint16(g), uint16(b)}
 }

src/pkg/image/image.go

 // RGB is an in-memory image whose At method returns color.RGB values.
 type RGB struct {
 	// Pix holds the image's pixels, in R, G, B order. The pixel at
 	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*3].
 	Pix []uint8
 	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
 }
 
 func (p *RGB) ColorModel() color.Model { return color.RGBModel }
 func (p *RGB) Bounds() Rectangle { return p.Rect }
 func (p *RGB) At(x, y int) color.Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return color.RGB{}
 	}
 	i := p.PixOffset(x, y)
 	return color.RGB{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2]}
 }
 // ... (PixOffset, Set, SetRGB, SubImage, Opaque, NewRGB methods) ...

 // RGB48 is an in-memory image whose At method returns color.RGB48 values.
 type RGB48 struct {
 	// Pix holds the image's pixels, in R, G, B order and big-endian format. The pixel at
 	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*6].
 	Pix []uint8
 	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
 }
 
 func (p *RGB48) ColorModel() color.Model { return color.RGB48Model }
 func (p *RGB48) Bounds() Rectangle { return p.Rect }
 func (p *RGB48) At(x, y int) color.Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return color.RGB48{}
 	}
 	i := p.PixOffset(x, y)
 	return color.RGB48{
 		uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
 		uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
 		uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
 	}
 }
 // ... (PixOffset, Set, SetRGB48, SubImage, Opaque, NewRGB48 methods) ...

コアとなるコードの解説

image/color/color.go の解説

  • RGB および RGB48 構造体: これらは、それぞれ24ビットと48ビットのRGBカラーを表現するための基本的なデータ構造です。uint8uint16 を使用することで、各チャネルのビット深度を直接的に定義しています。

  • RGBA() メソッドの実装: color.Color インターフェースの要件を満たすために、これらの構造体は RGBA() メソッドを実装しています。

    • RGB.RGBA(): uint8 のR, G, B値を uint32 に変換する際に、r |= r << 8 のようにビットを複製しています。これは、color.Color インターフェースが uint32 で16ビット精度(0x0000から0xFFFF)を期待するためです。例えば、uint80xFFuint320xFFFF にマッピングされます。アルファ値は常に 0xFFFF (完全に不透明) です。
    • RGB48.RGBA(): uint16 のR, G, B値を直接 uint32 にキャストしています。これは、uint16 が既に16ビット精度であるため、追加のビット操作が不要だからです。アルファ値は同様に 0xFFFF です。
  • RGBModel および RGB48Model: これらの変数は、新しいカラーモデルへの変換を可能にする color.Model インスタンスを提供します。ModelFunc は、関数を color.Model インターフェースに適合させるためのヘルパーです。

  • rgbModel および rgb48Model 関数: これらの関数は、任意の color.Color をそれぞれの RGB または RGB48 モデルに変換するロジックを含んでいます。

    • 変換時には、入力された色の RGBA() メソッドを呼び出して uint32 値を取得し、それを適切なビット深度(8ビットまたは16ビット)に丸めて新しい RGB または RGB48 インスタンスを生成します。例えば、rgbModel では r >> 8 を使って上位8ビットを取得し、uint8 にキャストしています。

image/image.go の解説

  • RGB および RGB48 構造体 (画像表現): これらの構造体は、実際のピクセルデータをメモリ上に保持し、image.Image インターフェースを実装します。

    • Pix: 生のピクセルデータがバイトスライスとして格納されます。RGB では1ピクセルあたり3バイト(R, G, B)、RGB48 では1ピクセルあたり6バイト(R上位, R下位, G上位, G下位, B上位, B下位)です。
    • Stride: 画像の行ごとのバイトオフセットを定義します。これにより、Pix スライス内の任意のピクセルに効率的にアクセスできます。RGB では 幅 * 3RGB48 では 幅 * 6 となります。
  • At(x, y int) color.Color メソッド: 指定された座標のピクセル色を color.Color インターフェースとして返します。

    • RGB.At(): Pix スライスから3バイトを読み込み、それらを直接 color.RGB 構造体のR, G, Bフィールドに割り当てます。
    • RGB48.At(): Pix スライスから6バイトを読み込み、各チャネルの2バイトをビッグエンディアン形式で結合して uint16 値を再構築し、color.RGB48 構造体のR, G, Bフィールドに割り当てます。例えば、uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]) は、上位バイトを8ビット左シフトし、下位バイトとOR演算することで16ビット値を生成します。
  • Set(x, y int, c color.Color) および SetRGB(x, y int, c color.RGB) / SetRGB48(x, y int, c color.RGB48) メソッド: 指定された座標のピクセル色を設定します。

    • Set メソッドは、入力された color.Color を対応するカラーモデル(RGBModel または RGB48Model)で変換してからピクセルデータを書き込みます。
    • SetRGB および SetRGB48 は、引数が既に適切な型であるため、変換なしで直接ピクセルデータを書き込みます。RGB48.Set および SetRGB48 では、uint16 値を2つの uint8 バイト(上位バイトと下位バイト)に分割して Pix スライスに格納するロジックが含まれます。
  • Opaque() bool メソッド: これらの画像型はアルファチャネルを持たないため、常に true を返します。これは、画像が完全に不透明であることを示します。

  • NewRGB および NewRGB48 関数: これらのコンストラクタ関数は、指定された境界を持つ新しい画像インスタンスを生成し、ピクセルデータを格納するための適切なサイズの []uint8 スライスを初期化します。

これらの変更により、Goの image パッケージは、アルファチャネルを持たない一般的なRGB画像フォーマットをより効率的かつ自然に扱うことができるようになり、画像処理アプリケーションの柔軟性が向上しました。

関連リンク

参考にした情報源リンク

  • コミット情報: /home/orange/Project/comemo/commit_data/17969.txt
  • GitHubコミットページ: https://github.com/golang/go/commit/e5902fc70f1a50920ce0ac95ffbed3a9af2b80b5
  • Go言語の公式ドキュメント (image および image/color パッケージ)
  • 一般的な画像処理および色深度に関する知識
  • Go言語のビット操作に関する知識
  • Go言語のインターフェースと構造体の実装に関する知識
  • Go言語のテストコードの読み方# [インデックス 17969] ファイルの概要

このコミットは、Go言語の標準ライブラリである image パッケージと image/color パッケージに、新しいカラーモデル RGB (24ビット) と RGB48 (48ビット) を追加するものです。これにより、より広範な画像フォーマットや色深度の表現が可能になり、特にアルファチャネルを持たない不透明なRGB画像を効率的に扱うための基盤が強化されます。

コミット

commit e5902fc70f1a50920ce0ac95ffbed3a9af2b80b5
Author: ChaiShushan <chaishushan@gmail.com>
Date:   Thu Dec 12 11:24:27 2013 -0800

    image: add RGB and RGB48
    
    R=golang-dev, r, nigeltao
    CC=golang-dev
    https://golang.org/cl/13239051

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

https://github.com/golang/go/commit/e5902fc70f1a50920ce0ac95ffbed3a9af2b80b5

元コミット内容

image: RGBおよびRGB48を追加

変更の背景

Go言語の image パッケージは、様々な画像フォーマットを扱うための基本的なインターフェースと実装を提供します。既存の image/color パッケージには、RGBA (32ビット、アルファチャネル付き) や RGBA64 (64ビット、アルファチャネル付き) といったカラーモデルが存在していましたが、アルファチャネルを持たない純粋なRGBカラーモデル、特に24ビット(各チャネル8ビット)や48ビット(各チャネル16ビット)の色深度を直接表現する型が不足していました。

多くの画像フォーマット(例: JPEG、BMPの一部、TIFFの一部)は、アルファチャネルを持たないRGB形式でピクセルデータを格納します。これらのフォーマットを効率的に読み書きし、メモリ上で表現するためには、アルファチャネルの処理オーバーヘッドなしにRGBデータのみを扱う専用の型が望ましいです。

このコミットは、以下のニーズに応えるために導入されました。

  1. 効率的なメモリ利用: アルファチャネルが不要な場合に、その分のメモリを節約し、よりコンパクトなデータ構造で画像を表現するため。
  2. 広範な画像フォーマットのサポート: 24ビットRGBや48ビットRGBといった一般的な色深度を持つ画像フォーマットとの互換性を高めるため。
  3. 色深度の柔軟性: 各チャネル8ビット(24ビットRGB)と16ビット(48ビットRGB)の両方に対応することで、より広い色域や高精度な色表現が求められる場面(例: プロフェッショナルな画像処理、HDR画像)にも対応できるようにするため。
  4. 既存のGoイメージングエコシステムとの統合: image.Image インターフェースと image/color.Color インターフェースに準拠した形で新しい型を提供し、既存の画像処理ツールやライブラリとのシームレスな連携を可能にするため。

前提知識の解説

このコミットの理解には、Go言語の image および image/color パッケージに関する基本的な知識が必要です。

  • image/color.Color インターフェース: Go言語における色の抽象化を表すインターフェースです。唯一のメソッド RGBA() (r, g, b, a uint32) を持ち、任意の色をRGBA形式(各チャネル16ビット、アルファ値は0x0000から0xFFFFの範囲)で表現できるようにします。これにより、異なるカラーモデル間での色の変換や比較が可能になります。

  • image/color.Model インターフェース: あるカラーモデルから別のカラーモデルへ色を変換するためのインターフェースです。Convert(c Color) Color メソッドを持ち、入力された Color をそのモデルが表現できる最も近い色に変換して返します。例えば、RGBA モデルは入力された色をアルファ値を持つ32ビットRGBAに変換します。

  • image.Image インターフェース: Go言語における画像の抽象化を表すインターフェースです。以下のメソッドを持ちます。

    • ColorModel() color.Model: 画像のカラーモデルを返します。
    • Bounds() image.Rectangle: 画像の論理的な境界(ピクセル座標の範囲)を返します。
    • At(x, y int) color.Color: 指定された座標 (x, y) のピクセルの色を color.Color インターフェースとして返します。
  • ピクセルデータ表現: Goの image パッケージでは、画像データは通常、Pix という []uint8 型のスライスに格納されます。このスライスには、各ピクセルの色チャネル値が特定の順序で並べられます。

  • Stride: Stride は、画像データにおいて、ある行のピクセルデータから次の行の同じX座標のピクセルデータまでのバイト数を表します。これにより、メモリ上の連続したデータから任意のピクセルを効率的に計算してアクセスできます。Stride は通常、幅 * ピクセルあたりのバイト数 で計算されますが、アライメントやパディングのためにこれより大きくなることもあります。

  • Rect (Rectangle): image.Rectangle は、画像の論理的な境界を定義する構造体で、Min (左上隅の点) と Max (右下隅の点) の2つの image.Point を持ちます。これにより、画像の全体または部分領域を表現します。

  • 色深度 (Bit Depth): 色深度は、各ピクセルが表現できる色の数を決定するビット数です。

    • 24ビットRGB: 各色チャネル(赤、緑、青)に8ビットずつ割り当てられ、合計24ビットで1ピクセルを表現します。各チャネルは0から255までの256段階の強度を持ち、約1670万色(2^24)を表現できます。
    • 48ビットRGB: 各色チャネルに16ビットずつ割り当てられ、合計48ビットで1ピクセルを表現します。各チャネルは0から65535までの65536段階の強度を持ち、非常に広い色域と滑らかなグラデーションを表現できます。これは、高精度な画像処理やHDR (High Dynamic Range) 画像で利用されます。
  • アルファチャネル: 色の透明度(不透明度)を表すチャネルです。アルファ値が0の場合は完全に透明、最大値の場合は完全に不透明です。このコミットで追加される RGB および RGB48 は、アルファチャネルを持たない「不透明な」色を扱います。

技術的詳細

このコミットは、src/pkg/image/color/color.gosrc/pkg/image/image.go の2つの主要なファイルに変更を加えています。

src/pkg/image/color/color.go の変更

  1. RGB 構造体の追加:

    • type RGB struct { R, G, B uint8 }
    • 各チャネルが uint8 (8ビット) で表現される24ビットRGBカラーモデルを定義します。
    • RGBA() (r, g, b, a uint32) メソッドを実装し、color.Color インターフェースを満たします。この実装では、uint8 の値を uint32 に拡張し、アルファ値は常に 0xFFFF (完全に不透明) となります。r |= r << 8 のようにビットシフトとOR演算を行うことで、8ビット値を16ビット値に「複製」し、uint32 の上位16ビットと下位16ビットの両方に同じ値が入るようにしています。これは、color.Color インターフェースの RGBA() メソッドが16ビット精度を要求するためです。
  2. RGB48 構造体の追加:

    • type RGB48 struct { R, G, B uint16 }
    • 各チャネルが uint16 (16ビット) で表現される48ビットRGBカラーモデルを定義します。
    • RGBA() (r, g, b, a uint32) メソッドを実装し、color.Color インターフェースを満たします。uint16 の値をそのまま uint32 にキャストし、アルファ値は常に 0xFFFF (完全に不透明) となります。
  3. RGBModel および RGB48Model の追加:

    • var RGBModel Model = ModelFunc(rgbModel)
    • var RGB48Model Model = ModelFunc(rgb48Model)
    • 新しいカラーモデルに対応する color.Model インスタンスが追加されます。これらは ModelFunc を使用して、対応する変換関数 (rgbModel, rgb48Model) をラップしています。
  4. rgbModel および rgb48Model 関数の追加:

    • func rgbModel(c Color) Color: 入力された ColorRGB 型に変換します。もし入力が既に RGB 型であればそのまま返し、そうでなければ RGBA() メソッドで取得した uint32 値を8ビットに丸めて RGB を生成します。
    • func rgb48Model(c Color) Color: 入力された ColorRGB48 型に変換します。もし入力が既に RGB48 型であればそのまま返し、そうでなければ RGBA() メソッドで取得した uint32 値をそのまま uint16 にキャストして RGB48 を生成します。

src/pkg/image/image.go の変更

  1. RGB 構造体の追加:

    • type RGB struct { Pix []uint8; Stride int; Rect Rectangle }
    • 24ビットRGB画像をメモリ上で表現するための構造体です。
    • Pix: ピクセルデータを格納する []uint8 スライス。データはR, G, Bの順で並びます。
    • Stride: 各行のバイト数。幅 * 3 で計算されます。
    • Rect: 画像の境界。
    • ColorModel() color.Model: color.RGBModel を返します。
    • Bounds() Rectangle: Rect を返します。
    • At(x, y int) color.Color: 指定された座標のピクセル色を color.RGB 型で返します。
    • PixOffset(x, y int) int: 指定された座標のピクセルデータの開始インデックスを計算します。
    • Set(x, y int, c color.Color): 指定された座標のピクセル色を設定します。入力された color.Colorcolor.RGBModel で変換してから設定します。
    • SetRGB(x, y int, c color.RGB): Set と同様ですが、引数が直接 color.RGB 型であるため、変換が不要です。
    • SubImage(r Rectangle) Image: 指定された矩形領域のサブイメージを返します。元の画像とピクセルデータを共有します。
    • Opaque() bool: 常に true を返します。これは、RGB 画像がアルファチャネルを持たず、常に不透明であることを示します。
    • NewRGB(r Rectangle) *RGB: 指定された境界を持つ新しい RGB 画像を生成し、ピクセルデータ用のバッファを割り当てます。
  2. RGB48 構造体の追加:

    • type RGB48 struct { Pix []uint8; Stride int; Rect Rectangle }
    • 48ビットRGB画像をメモリ上で表現するための構造体です。
    • Pix: ピクセルデータを格納する []uint8 スライス。データはR, G, Bの順で、各チャネルがビッグエンディアン形式の2バイトで格納されます。つまり、1ピクセルあたり6バイト(R上位8ビット, R下位8ビット, G上位8ビット, G下位8ビット, B上位8ビット, B下位8ビット)です。
    • Stride: 各行のバイト数。幅 * 6 で計算されます。
    • Rect: 画像の境界。
    • ColorModel() color.Model: color.RGB48Model を返します。
    • Bounds() Rectangle: Rect を返します。
    • At(x, y int) color.Color: 指定された座標のピクセル色を color.RGB48 型で返します。ピクセルデータから uint16 値を再構築するために、バイトオーダー(ビッグエンディアン)を考慮したビットシフトとOR演算を行います。
    • PixOffset(x, y int) int: 指定された座標のピクセルデータの開始インデックスを計算します。
    • Set(x, y int, c color.Color): 指定された座標のピクセル色を設定します。入力された color.Colorcolor.RGB48Model で変換してから、各 uint16 チャネルを2バイトに分割して Pix に格納します。
    • SetRGB48(x, y int, c color.RGB48): Set と同様ですが、引数が直接 color.RGB48 型であるため、変換が不要です。
    • SubImage(r Rectangle) Image: 指定された矩形領域のサブイメージを返します。元の画像とピクセルデータを共有します。
    • Opaque() bool: 常に true を返します。
    • NewRGB48(r Rectangle) *RGB48: 指定された境界を持つ新しい RGB48 画像を生成し、ピクセルデータ用のバッファを割り当てます。

src/pkg/image/image_test.go の変更

  • 新しい RGB および RGB48 画像型がテストスイートに追加され、既存の画像インターフェースのテストがこれらの新しい型に対しても実行されるようにしています。これにより、新しい実装が既存の image.Image インターフェースの期待される振る舞いを満たしていることを確認します。

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

src/pkg/image/color/color.go

 // RGB represents a traditional 24-bit fully opaque color,
 // having 8 bits for each of red, green and blue.
 type RGB struct {
 	R, G, B uint8
 }
 
 func (c RGB) RGBA() (r, g, b, a uint32) {
 	r = uint32(c.R)
 	r |= r << 8
 	g = uint32(c.G)
 	g |= g << 8
 	b = uint32(c.B)
 	b |= b << 8
 	a = 0xFFFF
 	return
 }
 
 // RGB48 represents a 48-bit fully opaque color,
 // having 16 bits for each of red, green and blue.
 type RGB48 struct {
 	R, G, B uint16
 }
 
 func (c RGB48) RGBA() (r, g, b, a uint32) {
 	return uint32(c.R), uint32(c.G), uint32(c.B), 0xFFFF
 }

 // Models for the standard color types.
 var (
 	RGBModel     Model = ModelFunc(rgbModel)
 	RGB48Model   Model = ModelFunc(rgb48Model)
 	RGBAModel    Model = ModelFunc(rgbaModel)
 	RGBA64Model  Model = ModelFunc(rgba64Model)
 	NRGBAModel   Model = ModelFunc(nrgbaModel)
 	NRGBA64Model Model = Model = ModelFunc(nrgba64Model)
 	AlphaModel   Model = ModelFunc(alphaModel)
 	Alpha16Model Model = ModelFunc(alpha16Model)
 	GrayModel    Model = ModelFunc(grayModel)
 	Gray16Model  Model = ModelFunc(gray16Model)
 )
 
 func rgbModel(c Color) Color {
 	if _, ok := c.(RGB); ok {
 		return c
 	}
 	r, g, b, _ := c.RGBA()
 	return RGB{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)}
 }
 
 func rgb48Model(c Color) Color {
 	if _, ok := c.(RGB48); ok {
 		return c
 	}
 	r, g, b, _ := c.RGBA()
 	return RGB48{uint16(r), uint16(g), uint16(b)}
 }

src/pkg/image/image.go

 // RGB is an in-memory image whose At method returns color.RGB values.
 type RGB struct {
 	// Pix holds the image's pixels, in R, G, B order. The pixel at
 	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*3].
 	Pix []uint8
 	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
 }
 
 func (p *RGB) ColorModel() color.Model { return color.RGBModel }
 func (p *RGB) Bounds() Rectangle { return p.Rect }
 func (p *RGB) At(x, y int) color.Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return color.RGB{}
 	}
 	i := p.PixOffset(x, y)
 	return color.RGB{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2]}
 }
 // ... (PixOffset, Set, SetRGB, SubImage, Opaque, NewRGB methods) ...

 // RGB48 is an in-memory image whose At method returns color.RGB48 values.
 type RGB48 struct {
 	// Pix holds the image's pixels, in R, G, B order and big-endian format. The pixel at
 	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*6].
 	Pix []uint8
 	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
 }
 
 func (p *RGB48) ColorModel() color.Model { return color.RGB48Model }
 func (p *RGB48) Bounds() Rectangle { return p.Rect }
 func (p *RGB48) At(x, y int) color.Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return color.RGB48{}
 	}
 	i := p.PixOffset(x, y)
 	return color.RGB48{
 		uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
 		uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
 		uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
 	}
 }
 // ... (PixOffset, Set, SetRGB48, SubImage, Opaque, NewRGB48 methods) ...

コアとなるコードの解説

image/color/color.go の解説

  • RGB および RGB48 構造体: これらは、それぞれ24ビットと48ビットのRGBカラーを表現するための基本的なデータ構造です。uint8uint16 を使用することで、各チャネルのビット深度を直接的に定義しています。

  • RGBA() メソッドの実装: color.Color インターフェースの要件を満たすために、これらの構造体は RGBA() メソッドを実装しています。

    • RGB.RGBA(): uint8 のR, G, B値を uint32 に変換する際に、r |= r << 8 のようにビットを複製しています。これは、color.Color インターフェースが uint32 で16ビット精度(0x0000から0xFFFF)を期待するためです。例えば、uint80xFFuint320xFFFF にマッピングされます。アルファ値は常に 0xFFFF (完全に不透明) です。
    • RGB48.RGBA(): uint16 のR, G, B値を直接 uint32 にキャストしています。これは、uint16 が既に16ビット精度であるため、追加のビット操作が不要だからです。アルファ値は同様に 0xFFFF です。
  • RGBModel および RGB48Model: これらの変数は、新しいカラーモデルへの変換を可能にする color.Model インスタンスを提供します。ModelFunc は、関数を color.Model インターフェースに適合させるためのヘルパーです。

  • rgbModel および rgb48Model 関数: これらの関数は、任意の color.Color をそれぞれの RGB または RGB48 モデルに変換するロジックを含んでいます。

    • 変換時には、入力された色の RGBA() メソッドを呼び出して uint32 値を取得し、それを適切なビット深度(8ビットまたは16ビット)に丸めて新しい RGB または RGB48 インスタンスを生成します。例えば、rgbModel では r >> 8 を使って上位8ビットを取得し、uint8 にキャストしています。

image/image.go の解説

  • RGB および RGB48 構造体 (画像表現): これらの構造体は、実際のピクセルデータをメモリ上に保持し、image.Image インターフェースを実装します。

    • Pix: 生のピクセルデータがバイトスライスとして格納されます。RGB では1ピクセルあたり3バイト(R, G, B)、RGB48 では1ピクセルあたり6バイト(R上位, R下位, G上位, G下位, B上位, B下位)です。
    • Stride: 画像の行ごとのバイトオフセットを定義します。これにより、Pix スライス内の任意のピクセルに効率的にアクセスできます。RGB では 幅 * 3RGB48 では 幅 * 6 となります。
  • At(x, y int) color.Color メソッド: 指定された座標のピクセル色を color.Color インターフェースとして返します。

    • RGB.At(): Pix スライスから3バイトを読み込み、それらを直接 color.RGB 構造体のR, G, Bフィールドに割り当てます。
    • RGB48.At(): Pix スライスから6バイトを読み込み、各チャネルの2バイトをビッグエンディアン形式で結合して uint16 値を再構築し、color.RGB48 構造体のR, G, Bフィールドに割り当てます。例えば、uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]) は、上位バイトを8ビット左シフトし、下位バイトとOR演算することで16ビット値を生成します。
  • Set(x, y int, c color.Color) および SetRGB(x, y int, c color.RGB) / SetRGB48(x, y int, c color.RGB48) メソッド: 指定された座標のピクセル色を設定します。

    • Set メソッドは、入力された color.Color を対応するカラーモデル(RGBModel または RGB48Model)で変換してからピクセルデータを書き込みます。
    • SetRGB および SetRGB48 は、引数が既に適切な型であるため、変換なしで直接ピクセルデータを書き込みます。RGB48.Set および SetRGB48 では、uint16 値を2つの uint8 バイト(上位バイトと下位バイト)に分割して Pix スライスに格納するロジックが含まれます。
  • Opaque() bool メソッド: これらの画像型はアルファチャネルを持たないため、常に true を返します。これは、画像が完全に不透明であることを示します。

  • NewRGB および NewRGB48 関数: これらのコンストラクタ関数は、指定された境界を持つ新しい画像インスタンスを生成し、ピクセルデータを格納するための適切なサイズの []uint8 スライスを初期化します。

これらの変更により、Goの image パッケージは、アルファチャネルを持たない一般的なRGB画像フォーマットをより効率的かつ自然に扱うことができるようになり、画像処理アプリケーションの柔軟性が向上しました。

関連リンク

参考にした情報源リンク

  • コミット情報: /home/orange/Project/comemo/commit_data/17969.txt
  • GitHubコミットページ: https://github.com/golang/go/commit/e5902fc70f1a50920ce0ac95ffbed3a9af2b80b5
  • Go言語の公式ドキュメント (image および image/color パッケージ)
  • 一般的な画像処理および色深度に関する知識
  • Go言語のビット操作に関する知識
  • Go言語のインターフェースと構造体の実装に関する知識
  • Go言語のテストコードの読み方