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

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

このコミットは、Go言語の標準ライブラリにおける画像処理関連パッケージの重要なリファクタリングを目的としています。具体的には、image/ycbcr パッケージに存在していたY'CbCr色空間に関連する型と関数を、より適切なパッケージである image および image/color へと移動させています。これにより、Goの画像処理ライブラリの構造が整理され、各パッケージの責務が明確化されます。また、既存のコードベースがこの変更に容易に対応できるよう、gofix ツールに自動修正機能が追加されています。

コミット

image/ycbcr: move the Y'CbCr types into image and image/color.

R=r, rsc
CC=golang-dev
https://golang.org/cl/5493084

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

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

元コミット内容

commit d13ce8115d650e598f5fd35975f8188f493c2f96
Author: Nigel Tao <nigeltao@golang.org>
Date:   Wed Dec 21 10:29:21 2011 +1100

    image/ycbcr: move the Y'CbCr types into image and image/color.

    R=r, rsc
    CC=golang-dev
    https://golang.org/cl/5493084

変更の背景

この変更の背景には、Go言語の標準ライブラリにおけるパッケージ設計の原則があります。Goの標準ライブラリは、各パッケージが明確な責務を持ち、互いに疎結合であるように設計されています。image/ycbcr パッケージはY'CbCr色空間に特化したものでしたが、その中に色変換ロジック(RGBToYCbCrなど)と色モデルの定義、そしてY'CbCr形式の画像構造体(YCbCr struct)が混在していました。

理想的なパッケージ構造としては、色モデルの定義や色空間間の変換関数は image/color パッケージに、そして特定の画像形式のデータ構造は image パッケージに配置されるべきです。このコミットは、この設計原則に沿って、Y'CbCr関連の要素をより論理的な場所に再配置することで、ライブラリ全体の整合性と保守性を向上させることを目的としています。

また、このような大規模な型移動は既存のコードベースに影響を与えるため、Go言語の進化をサポートする gofix ツールが活用され、ユーザーが容易にコードを更新できるよう配慮されています。

前提知識の解説

Go言語のパッケージとインポートパス

Go言語では、コードは「パッケージ」という単位で管理されます。パッケージは関連する機能の集合であり、他のパッケージから利用する際には import キーワードを使ってインポートパスを指定します。例えば、"image""image/color" は標準ライブラリのパッケージを指します。

Y'CbCr色空間

Y'CbCr(またはYUV、YCbCr)は、主にデジタルビデオや画像圧縮(JPEGなど)で用いられる色空間です。人間の視覚が輝度(明るさ)の変化に敏感で、色相や彩度(色の情報)の変化には比較的鈍感であるという特性を利用しています。

  • Y' (Luma): 輝度成分。画像の明るさを表します。
  • Cb (Chroma Blue): 青色差成分。青と輝度の差を表します。
  • Cr (Chroma Red): 赤色差成分。赤と輝度の差を表します。

この色空間では、色情報を間引く「クロマサブサンプリング」という技術がよく用いられます。これにより、画質の劣化を抑えつつデータ量を削減できます。一般的なサブサンプリング形式には、4:4:4(フルサンプル)、4:2:2(水平方向に半分)、4:2:0(水平・垂直方向に半分)などがあります。

Goの image および image/color パッケージ

  • image パッケージ: Go言語における基本的な画像インターフェースとデータ構造を提供します。image.Image インターフェースは、あらゆる種類の画像を抽象化し、image.Rectangleimage.Point などの幾何学的な型も定義されています。
  • image/color パッケージ: 色モデルと色の表現に関する型と関数を提供します。color.Color インターフェースは単一の色を表し、color.Model インターフェースは色空間間の変換を定義します。RGB、RGBA、Grayなどの標準的な色モデルがここに定義されています。

gofix ツール

gofix は、Go言語のバージョンアップやAPIの変更に伴うコードの自動修正を支援するコマンドラインツールです。Go言語の進化の過程で、APIの変更があった場合でも、開発者が手動で大量のコードを修正する手間を省くために提供されました。gofix はAST(抽象構文木)を解析し、定義されたルールに基づいてコードを書き換えます。

技術的詳細

このコミットでは、image/ycbcr パッケージの機能が以下のように再配置されました。

  1. image/color パッケージへの移動:

    • RGBToYCbCr 関数: RGBからY'CbCrへの色変換ロジック。
    • YCbCrToRGB 関数: Y'CbCrからRGBへの色変換ロジック。
    • YCbCr 構造体(color.YCbCr): Y'CbCr色空間における単一の色を表す型。
    • YCbCrModel 変数(color.YCbCrModel): color.Model インターフェースを実装し、Y'CbCr色空間の色モデルを定義。
  2. image パッケージへの移動:

    • YCbCrSubsampleRatio 型と関連定数(image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio422, image.YCbCrSubsampleRatio420): クロマサブサンプリングの比率を定義する型と定数。
    • YCbCr 構造体(image.YCbCr): Y'CbCr形式の画像データ構造。輝度(Y)、青色差(Cb)、赤色差(Cr)の各成分のバイトスライス、ストライド、サブサンプリング比率、画像の矩形領域などの情報を含みます。
  3. gofix ツールの更新:

    • src/cmd/gofix/imageycbcr.go および src/cmd/gofix/imageycbcr_test.go が追加されました。
    • この gofix の修正は、既存の image/ycbcr パッケージへの参照を、新しい image または image/color パッケージへの参照に自動的に書き換えます。例えば、ycbcr.RGBToYCbCrcolor.RGBToYCbCr に、ycbcr.YCbCrColorcolor.YCbCr に、ycbcr.YCbCr (画像型) は image.YCbCr に変更されます。

この変更により、image/ycbcr パッケージは完全に削除され、その機能は imageimage/color に統合されました。

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

このコミットのコアとなる変更は、主に以下のファイルの追加、削除、および修正に集約されます。

  • src/pkg/image/ycbcr/ycbcr.go の削除: 以前のY'CbCr色空間の定義と画像構造体が含まれていたファイルが削除されました。
  • src/pkg/image/ycbcr/Makefile の削除: 削除されたパッケージに対応するMakefileも削除されました。
  • src/pkg/image/color/ycbcr.go の新規追加:
    • RGBToYCbCr および YCbCrToRGB 関数がここに移動されました。これらの関数は、RGBとY'CbCr間の色変換ロジックを実装しています。
    • type YCbCr struct { Y, Cb, Cr uint8 } が定義され、これは単一のY'CbCr色を表す color.Color インターフェースを実装する型となります。
    • var YCbCrModel Model = ModelFunc(...) が定義され、Y'CbCr色モデルを提供します。
  • src/pkg/image/ycbcr.go の新規追加:
    • type YCbCrSubsampleRatio int とその定数(YCbCrSubsampleRatio444 など)が定義されました。
    • type YCbCr struct { ... } が定義され、これはY'CbCr形式の画像データ構造を表す image.Image インターフェースを実装する型となります。以前の image/ycbcr.YCbCr とは異なる、画像データとしてのYCbCrを表現します。
  • src/cmd/gofix/imageycbcr.go の新規追加:
    • このファイルには、image/ycbcr パッケージから image および image/color パッケージへの型や関数の移動に対応するための gofix ルールが実装されています。
    • image/ycbcr のインポートを検出し、ycbcr.RGBToYCbCr のような参照を color.RGBToYCbCr に、ycbcr.YCbCr (画像型) を image.YCbCr に自動的に書き換えるロジックが含まれています。
  • 既存ファイルの修正:
    • src/pkg/Makefilesrc/pkg/image/Makefilesrc/pkg/image/color/Makefile が、パッケージの追加・削除に合わせて更新されました。
    • src/pkg/image/draw/bench_test.gosrc/pkg/image/draw/draw.gosrc/pkg/image/draw/draw_test.gosrc/pkg/image/jpeg/reader.gosrc/pkg/image/jpeg/writer.go など、image/ycbcr パッケージを参照していた既存のファイルが、新しい image または image/color パッケージのパスに更新されました。

コアとなるコードの解説

src/pkg/image/color/ycbcr.go (抜粋)

package color

// RGBToYCbCr converts an RGB triple to a Y'CbCr triple.
func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
    // ... 変換ロジック ...
}

// YCbCrToRGB converts a Y'CbCr triple to an RGB triple.
func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
    // ... 変換ロジック ...
}

// YCbCr represents a fully opaque 24-bit Y'CbCr color.
type YCbCr struct {
    Y, Cb, Cr uint8
}

func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
    r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
    return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
}

// YCbCrModel is the Model for Y'CbCr colors.
var YCbCrModel Model = ModelFunc(func(c Color) Color {
    // ... Colorインターフェースの実装 ...
})

このファイルは、Y'CbCr色空間における単一の色の表現と、RGBとの間の変換ロジックを提供します。color.YCbCr 型は color.Color インターフェースを満たし、color.YCbCrModel はこの色モデルをGoの画像処理システムに統合します。

src/pkg/image/ycbcr.go (抜粋)

package image

import (
    "image/color"
)

// YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
type YCbCrSubsampleRatio int

const (
    YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
    YCbCrSubsampleRatio422
    YCbCrSubsampleRatio420
)

// YCbCr is an in-memory image of Y'CbCr colors.
type YCbCr struct {
    Y              []uint8
    Cb             []uint8
    Cr             []uint8
    YStride        int
    CStride        int
    SubsampleRatio YCbCrSubsampleRatio
    Rect           Rectangle
}

func (p *YCbCr) ColorModel() color.Model {
    return color.YCbCrModel
}

func (p *YCbCr) Bounds() Rectangle {
    return p.Rect
}

func (p *YCbCr) At(x, y int) color.Color {
    // ... ピクセルデータへのアクセスロジック ...
}

func (p *YCbCr) SubImage(r Rectangle) Image {
    // ... 部分画像の取得ロジック ...
}

func (p *YCbCr) Opaque() bool {
    return true
}

このファイルは、Y'CbCr形式の画像データ構造を定義します。image.YCbCr 型は image.Image インターフェースを満たし、Y、Cb、Crの各成分のバイトスライス、ストライド、サブサンプリング比率、画像の境界情報などを保持します。At メソッドは指定された座標のピクセル色を color.YCbCr として返します。

src/cmd/gofix/imageycbcr.go (抜粋)

package main

import (
    "go/ast"
)

func init() {
    register(imageycbcrFix)
}

var imageycbcrFix = fix{
    "imageycbcr",
    "2011-12-20",
    imageycbcr,
    `Adapt code to types moved from image/ycbcr to image and image/color.`,
}

func imageycbcr(f *ast.File) (fixed bool) {
    if !imports(f, "image/ycbcr") {
        return
    }

    walk(f, func(n interface{}) {
        s, ok := n.(*ast.SelectorExpr)
        if !ok || !isTopName(s.X, "ycbcr") {
            return
        }

        switch s.Sel.String() {
        case "RGBToYCbCr", "YCbCrToRGB":
            addImport(f, "image/color")
            s.X.(*ast.Ident).Name = "color"
        case "YCbCrColor":
            addImport(f, "image/color")
            s.X.(*ast.Ident).Name = "color"
            s.Sel.Name = "YCbCr"
        case "YCbCrColorModel":
            addImport(f, "image/color")
            s.X.(*ast.Ident).Name = "color"
            s.Sel.Name = "YCbCrModel"
        case "SubsampleRatio", "SubsampleRatio444", "SubsampleRatio422", "SubsampleRatio420":
            addImport(f, "image")
            s.X.(*ast.Ident).Name = "image"
            s.Sel.Name = "YCbCr" + s.Sel.Name // 例: image.YCbCrSubsampleRatio444
        case "YCbCr": // 画像型
            addImport(f, "image")
            s.X.(*ast.Ident).Name = "image"
        default:
            return
        }
        fixed = true
    })

    deleteImport(f, "image/ycbcr")
    return
}

この gofix ルールは、image/ycbcr パッケージをインポートしているGoのソースファイルを走査し、ycbcr. プレフィックスを持つ識別子を新しいパッケージ(image または image/color)の適切な識別子に書き換えます。これにより、ユーザーは手動で大量のコードを修正することなく、新しいAPIに移行できます。

関連リンク

参考にした情報源リンク