#!python # -*- mode: python; Encoding: utf-8; coding: utf-8 -*- # Last updated: <2026/03/22 15:24:10 +0900> """ パイプ経由で親スクリプトから画像データを受け取り 何らかの画像処理をして結果を標準出力に送るスクリプト。 Windows11 x64 25H2 + Python 3.10.10 64bit """ import sys import struct def process_image_real_progress(): # Windows環境などで改行コードの自動変換(\n -> \r\n)を防ぐため、 # .buffer を使用してバイナリモードでストリームを扱います。 stdin = sys.stdin.buffer stdout = sys.stdout.buffer stderr = sys.stderr # 1. ヘッダー読み込み。画像の幅と高さを取得 # 親側で struct.pack('ii', w, h) して送られてくることを想定(4byte * 2 = 8byte) header = stdin.read(8) if not header: return # 'i'はsigned int (4byte)。リトルエンディアンで展開されます width, height = struct.unpack("ii", header) # 2. 全データ読み込み(一気に読み込んでメモリ上で保持) # RGBA 32bit (4byte) 前提の計算: width * height * 4 # 大容量画像の場合はメモリ負荷に注意が必要ですが、1枚単位ならこの手法が高速です raw_data = stdin.read(width * height * 4) # 処理後のデータを格納するためのバッファを先に確保(不変なbytesではなく可変なbytearrayを使用) processed_data = bytearray(len(raw_data)) # 3. 行単位でループ処理を行い、計算と進捗の書き出しを両立させる for y in range(height): # 処理対象の行のバイト配列上の開始・終了インデックスを計算 row_start = y * width * 4 row_end = row_start + (width * 4) # 1行分のピクセルを走査。4バイト刻み(R, G, B, A)で処理 for i in range(row_start, row_end, 4): # RGBAの各要素を抽出 r = raw_data[i] g = raw_data[i + 1] b = raw_data[i + 2] a = raw_data[i + 3] # 輝度計算 (ITU-R BT.601) に基づくグレースケール変換 # 重み付け: R=0.299, G=0.587, B=0.114 v = int(0.299 * r + 0.587 * g + 0.114 * b) # 処理結果を格納。RGBすべてに同じ輝度値を代入し、Alphaは元の値を維持 processed_data[i] = v processed_data[i + 1] = v processed_data[i + 2] = v processed_data[i + 3] = a # 標準エラー出力(stderr)を使って進捗を表示 # stdoutは画像データ用に使用しているため、混ざらないようstderrを使います。 # 20行ごともしくは最終行で進捗を出力(頻繁なIOによる速度低下を防止) if y % 20 == 0 or y == height - 1: progress = int((y + 1) / height * 100) # \n を含めて書き出すことで、親プロセス側で readline() して取得可能 stderr.write(f"Processing: {progress}%\n") stderr.flush() # 4. 変換済みの画像バイナリを一括して標準出力へ書き出し stdout.write(processed_data) # 明示的にフラッシュし、パイプの先(親プロセス)へデータを送り出す stdout.flush() if __name__ == "__main__": process_image_real_progress()