独自の画像プラグインの作成

Pillow はプラグインモデルを使用しており、ライブラリ自体を変更することなく、独自のデコーダーとエンコーダーをライブラリに追加できます。このようなプラグインの通常の名前は XxxImagePlugin.py のようになります。ここで Xxx は一意の形式名 (通常は略語) です。

警告

Pillow >= 2.1.0 では、ImagePlugin.py で終わる名前の Python パス内のファイルは自動的にインポートされなくなりました。画像プラグインを手動でインポートする必要があります。

Pillow はファイルを 2 つの段階でデコードします

  1. ロードされた順序で利用可能な画像プラグインをループ処理し、ファイルの最初の 16 バイトを使用してプラグインの _accept 関数を呼び出します。_accept 関数が true を返した場合、プラグインの _open メソッドが呼び出されて、画像メタデータと画像タイルが設定されます。_open メソッドは、実際の画像データをデコードするためのものではありません。

  2. 画像データが要求されると、ImageFile.load メソッドが呼び出され、各タイルのデコーダーを設定して、データがデコーダーに供給されます。

画像プラグインには、PIL.ImageFile.ImageFile 基本クラスから派生したフォーマットハンドラーが含まれている必要があります。このクラスは、ファイルヘッダーを読み取り、少なくとも内部 _size および _mode 属性を設定する _open メソッドを提供して、modesize が設定されるようにする必要があります。ファイルをロードできるようにするには、メソッドで tile 記述子のリストを作成する必要もあります。この記述子には、デコーダー名、タイルの範囲、およびデコーダー固有のデータが含まれます。フォーマットハンドラークラスは、Image モジュールへの呼び出しを介して、明示的に登録する必要があります。

パフォーマンス上の理由から、_open メソッドが、適切なコンテンツを持たないファイルをすばやく拒否することが重要です。

次のプラグインは、128 バイトのヘッダーを持つ単純な形式をサポートしています。ヘッダーは、単語 “SPAM” の後に、幅、高さ、およびピクセルサイズ (ビット単位) で構成されています。ヘッダーフィールドはスペースで区切られています。画像データは、ヘッダーの直後に続き、バイレベル、グレースケール、または 24 ビットのトゥルーカラーにすることができます。

SpamImagePlugin.py:

from PIL import Image, ImageFile


def _accept(prefix: bytes) -> bool:
    return prefix[:4] == b"SPAM"


class SpamImageFile(ImageFile.ImageFile):

    format = "SPAM"
    format_description = "Spam raster image"

    def _open(self) -> None:

        header = self.fp.read(128).split()

        # size in pixels (width, height)
        self._size = int(header[1]), int(header[2])

        # mode setting
        bits = int(header[3])
        if bits == 1:
            self._mode = "1"
        elif bits == 8:
            self._mode = "L"
        elif bits == 24:
            self._mode = "RGB"
        else:
            msg = "unknown number of bits"
            raise SyntaxError(msg)

        # data descriptor
        self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))]


Image.register_open(SpamImageFile.format, SpamImageFile, _accept)

Image.register_extensions(
    SpamImageFile.format,
    [
        ".spam",
        ".spa",  # DOS version
    ],
)

フォーマットハンドラーは、size および mode が設定されるように、常に内部 _size および _mode 属性を設定する必要があります。これらが設定されていない場合、ファイルを開くことはできません。プラグインを簡略化するために、呼び出しコードは、SyntaxErrorKeyErrorIndexErrorEOFError、および struct.error などの例外を、ファイルの識別失敗と見なします。

画像プラグインは、PIL.Image.register_open() を使用して明示的に登録する必要があることに注意してください。必須ではありませんが、この形式で使用される拡張子を登録することも良い考えです。

プラグインがインポートされると、使用できます

from PIL import Image
import SpamImagePlugin

with Image.open("hopper.spam") as im:
    pass

tile 属性

ファイルを識別するだけでなく、読み取ることもできるようにするには、tile 属性も設定する必要があります。この属性は、タイル記述子のリストで構成されます。各記述子では、画像内の特定の領域にデータをロードする方法を指定します。

ほとんどの場合、画像全体をカバーする単一の記述子のみが使用されます。PsdImagePlugin.PsdImageFile は、チャネルが 1 つずつ連続して保存されているため、単一レイヤー内のチャネルを結合するために複数のタイルを使用します。

タイル記述子は、次の内容を持つ 4 タプルです

(decoder, region, offset, parameters)

フィールドは次のように使用されます

デコーダー

使用するデコーダーを指定します。ここで使用されるrawデコーダーは、さまざまなピクセル形式の非圧縮データをサポートします。このデコーダーの詳細については、以下の説明を参照してください。

Cデコーダーのリストは、_imaging.c の関数配列の codecs セクションにあります。Python デコーダーは、関連するプラグイン内で登録されています。

region

画像内のデータを格納する場所を指定する4タプル。

offset

ファイル先頭から画像データまでのバイトオフセット。

parameters

デコーダーへのパラメーター。このフィールドの内容は、タイル記述子タプルの最初のフィールドで指定されたデコーダーによって異なります。デコーダーがパラメーターを必要としない場合は、このフィールドに None を使用します。

tile 属性には、単一の記述子だけでなく、タイル記述子のリストが含まれていることに注意してください。

デコーダー

raw デコーダー

raw デコーダーは、画像ファイルから非圧縮データを読み取るために使用されます。PPM、BMP、非圧縮TIFFなど、ほとんどの非圧縮ファイル形式で使用できます。PIL.Image.frombytes() 関数で raw デコーダーを使用するには、次の構文を使用します

image = Image.frombytes(
    mode, size, data, "raw",
    raw_mode, stride, orientation
    )

タイル記述子で使用する場合、パラメーターフィールドは次のようになります。

(raw_mode, stride, orientation)

フィールドは次のように使用されます

raw_mode

ファイルで使用されるピクセルレイアウトであり、データを PIL の内部レイアウトに適切に変換するために使用されます。利用可能な形式の概要については、以下の表を参照してください。

stride

画像内の連続する2行の間のバイト単位の距離。0の場合、画像はパックされている(行間にパディングがない)と見なされます。省略した場合、ストライドはデフォルトで0になります。

orientation

画像内の最初の行が画面上の最上行(1)か、最下行(-1)か。省略した場合、向きはデフォルトで1になります。

raw モードフィールドは、PIL の内部ピクセルレイアウトに一致するようにデータをどのようにアンパックするかを決定するために使用されます。PIL は多数の raw モードをサポートしています。完全なリストについては、Unpack.c モジュールの表を参照してください。次の表は、一般的な raw モードをいくつか説明しています。

mode

説明

1

1ビットのバイレベルで、最上位ビットに左端のピクセルが格納されます。
0は黒、1は白を意味します。

1;I

1ビットの反転バイレベルで、最上位ビットに左端のピクセルが格納されます。
0は白、1は黒を意味します。

1;R

1ビットの反転バイレベルで、最下位ビットに左端のピクセルが格納されます。
0は黒、1は白を意味します。

L

8ビットのグレースケール。0は黒、255は白を意味します。

L;I

8ビットの反転グレースケール。0は白、255は黒を意味します。

P

8ビットのパレットマップされた画像。

RGB

24ビットのトゥルーカラーで、(赤、緑、青)として格納されます。

BGR

24ビットのトゥルーカラーで、(青、緑、赤)として格納されます。

RGBX

24ビットのトゥルーカラーで、(赤、緑、青、パッド)として格納されます。パッド
ピクセルは異なる場合があります。

RGB;L

24ビットのトゥルーカラーで、ラインインターリーブされます(最初にすべての赤ピクセル、次に
すべての緑ピクセル、最後にすべての青ピクセル)。

ほとんどの場合、raw モードは単純にモードと同じであることに注意してください。

Python Imaging Library は、JPEG、PNG、PackBits など、他の多くのデコーダーをサポートしています。詳細については、decode.c ソースファイル、およびライブラリに付属の標準プラグイン実装を参照してください。

浮動小数点データのデコード

PIL は、さまざまな形式をモード F (浮動小数点)イメージメモリにロードできる特別なメカニズムを提供します。

raw デコーダーを使用して、次のいずれかの raw モードを使用して、標準のマシンデータ型でデータがパックされた画像を読み取ることができます。

mode

説明

F

32ビットのネイティブ浮動小数点。

F;8

8ビットの符号なし整数。

F;8S

8ビットの符号付き整数。

F;16

16ビットのリトルエンディアン符号なし整数。

F;16S

16ビットのリトルエンディアン符号付き整数。

F;16B

16ビットのビッグエンディアン符号なし整数。

F;16BS

16ビットのビッグエンディアン符号付き整数。

F;16N

16ビットのネイティブ符号なし整数。

F;16NS

16ビットのネイティブ符号付き整数。

F;32

32ビットのリトルエンディアン符号なし整数。

F;32S

32ビットのリトルエンディアン符号付き整数。

F;32B

32ビットのビッグエンディアン符号なし整数。

F;32BS

32ビットのビッグエンディアン符号付き整数。

F;32N

32ビットのネイティブ符号なし整数。

F;32NS

32ビットのネイティブ符号付き整数。

F;32F

32ビットのリトルエンディアン浮動小数点。

F;32BF

32ビットのビッグエンディアン浮動小数点。

F;32NF

32ビットのネイティブ浮動小数点。

F;64F

64ビットのリトルエンディアン浮動小数点。

F;64BF

64ビットのビッグエンディアン浮動小数点。

F;64NF

64ビットのネイティブ浮動小数点。

bit デコーダー

raw デコーダーが形式を処理できない場合、PIL は、さまざまなパック形式を浮動小数点イメージメモリに読み込むために使用できる特別な「bit」デコーダーも提供します。

PIL.Image.frombytes() 関数で bit デコーダーを使用するには、次の構文を使用します。

image = Image.frombytes(
    mode, size, data, "bit",
    bits, pad, fill, sign, orientation
    )

タイル記述子で使用する場合、パラメーターフィールドは次のようになります。

(bits, pad, fill, sign, orientation)

フィールドは次のように使用されます

bits

ピクセルあたりのビット数 (2-32)。デフォルトはありません。

pad

行間のパディング(ビット単位)。パディングがない場合は0、行がフルバイトにパディングされている場合は8です。省略した場合、pad 値はデフォルトで8になります。

fill

デコーダービットバッファーへのデータの追加方法と保存方法を制御します。

fill=0

デコーダーバッファーの LSB 端にバイトを追加します。MSB 端からピクセルを保存します。

fill=1

デコーダーバッファーの MSB 端にバイトを追加します。MSB 端からピクセルを保存します。

fill=2

デコーダーバッファーの LSB 端にバイトを追加します。LSB 端からピクセルを保存します。

fill=3

デコーダーバッファーの MSB 端にバイトを追加します。LSB 端からピクセルを保存します。

省略した場合、fill の順序はデフォルトで 0 になります。

sign

ゼロ以外の場合、ビットフィールドは符号拡張されます。ゼロまたは省略した場合、ビットフィールドは符号なしになります。

orientation

画像内の最初の行が画面上の最上行(1)か、最下行(-1)か。省略した場合、向きはデフォルトで1になります。

C で独自のファイルコーデックを作成する

ファイルコーデックのライフサイクルには3つの段階があります。

  1. セットアップ:Pillow は、デコーダーまたはエンコーダーレジストリで関数を探し、内部コアイメージオブジェクトで [codecname]_decoder または [codecname]_encoder という名前の関数にフォールバックします。その関数は、tile からの args タプルで呼び出されます。

  2. 変換:コーデックの decode または encode 関数は、イメージデータのチャンクで繰り返し呼び出されます。

  3. クリーンアップ:コーデックがクリーンアップ関数を登録している場合、例外が発生した場合でも、変換プロセスの最後に呼び出されます。

セットアップ

現在の規則では、コーデックセットアップ関数は PyImaging_[codecname]DecoderNew または PyImaging_[codecname]EncoderNew という名前であり、decode.c または encode.c で定義されています。それに対する Python バインディングは [codecname]_decoder または [codecname]_encoder という名前で、_imaging.c ファイルの関数配列のコーデックセクション内から設定されます。

セットアップ関数は PyImaging_DecoderNew または PyImaging_EncoderNew を呼び出す必要があり、少なくとも decode または encode 関数ポインターを設定する必要があります。このオブジェクトで関心のあるフィールドは次のとおりです。

decode/encode

デコードまたはエンコード関数への関数ポインター。これらは、imstate、および変換されるデータのバッファーにアクセスできます。

cleanup

クリーンアップ関数への関数ポインター。これらは state にアクセスできます。

im

ターゲットイメージ。Pillow によって設定されます。

state

ImagingCodecStateInstance。Pillow によって設定されます。context メンバーは、コーデックが特定の形式の状態またはオプションを格納するために使用できる不透明な構造体です。

pulls_fd/pushes_fd

デコーダーのpulls_fdまたはエンコーダーのpushes_fdが1に設定されている場合、state->fdはPythonのファイルライクオブジェクトへのポインターになります。コーデックは、バッファを介してデータをプッシュするのではなく、codec_fd.cの関数を使用して、ファイルライクオブジェクトと直接読み書きできます。

バージョン 3.3.0 で追加。

変換

デコードまたはエンコード関数は、ターゲット(コア)イメージ、コーデック状態構造体、および変換されるデータのバッファとともに呼び出されます。

バッファからできるだけ多くのデータを取り出し、消費したバイト数を返すのはコーデックの責任です。コーデックへの次の呼び出しには、以前の未消費の末尾が含まれます。コーデック関数は、処理されたデータとして複数回呼び出されます。

あるいは、pulls_fdまたはpushes_fdが設定されている場合、デコードまたはエンコード関数は空のバッファとともに一度だけ呼び出されます。その1回の呼び出しでタイル全体を変換するのは、コーデックの責任です。これを使用すると、コーデックに自由度が増しますが、コーデックによってタイル全体が一度にメモリに保持される場合、その自由度がメモリ使用量の増加につながる可能性があります。

エラーが発生した場合は、state->errcodeを設定し、-1を返します。

エラーコードを設定せずに、成功した場合は-1を返します。

クリーンアップ

クリーンアップ関数は、コーデックが負の値を返すか、エラーが発生した場合に呼び出されます。この関数は、割り当てられたメモリを解放し、外部ライブラリからのリソースを解放する必要があります。

Pythonで独自のファイルコーデックを作成する

Pythonファイルデコーダーとエンコーダーは、それぞれPIL.ImageFile.PyDecoderPIL.ImageFile.PyEncoderから派生する必要があり、少なくともデコードまたはエンコードメソッドをオーバーライドする必要があります。PIL.Image.register_decoder()PIL.Image.register_encoder()を使用して登録する必要があります。ファイルコーデックのC実装と同様に、Pythonベースのファイルコーデックのライフサイクルには3つの段階があります。

  1. セットアップ:Pillowは、デコーダーまたはエンコーダーレジストリでコーデックを検索し、クラスをインスタンス化します。

  2. 変換:インスタンスのdecodeメソッドは、解釈されるデータのバッファとともに繰り返し呼び出されるか、encodeメソッドは、出力されるデータのサイズとともに繰り返し呼び出されます。

    あるいは、デコーダーの_pulls_fdプロパティ(またはエンコーダーの_pushes_fdプロパティ)がTrueに設定されている場合、decodeおよびencodeは一度だけ呼び出されます。デコーダーでは、self.fdを使用して、ファイルライクオブジェクトにアクセスできます。これを使用すると、コーデックの自由度が増しますが、コーデックによってファイル全体が一度にメモリに保持される場合、その自由度がメモリ使用量の増加につながる可能性があります。

    decodeで、データが解釈されると、set_as_rawを使用してイメージを埋めることができます。

  3. クリーンアップ:変換が完了すると、インスタンスのcleanupメソッドが呼び出されます。これは、コーデックで使用されるリソースをクリーンアップするために使用できます。

    _pulls_fdまたは_pushes_fdTrueに設定した場合、decodeまたはencodeの最後にクリーンアップタスクを実行することを選択した可能性があります。

PIL.ImageFile.PyDecoderの例については、DdsImagePluginを参照してください。PIL.ImageFile.PyDecoderPIL.ImageFile.PyEncoderの両方を使用するプラグインについては、BlpImagePluginを参照してください。