はじめに
小さな印刷工房が、色の格子から作るポストカードを必要としています。まず完成済みの 4 行 4 列のサンプルを実行し、インクを暖色に変えます。その後、長方形の文字の図案を実際の画像ファイルにする C プログラムを完成させます。
C の変数、条件分岐、ループ、配列、関数と、基本的な端末の移動操作を知っていることが前提です。2 次元の添字と画像出力はここで説明します。準備済みのブラウザー環境には Workspace 端末と Postcard Preview があります。画像は P3 PPM ファイルで、読み取れる数値を使い、PNG とは異なります。読解と練習の所要時間は作者の見積もりであり、初心者による実測値ではありません。
小さなサンプルを出力して色を変える
このステップでは、完成済みの C サンプルが画像になる様子を確認してから、インクの色を 1 つ変えます。
Workspace タブを開きます。端末の作業場所は /home/labex/project/postcards です。以下の明示的な cd は、別のディレクトリーに移動した後に戻る場合にも使えます。pwd は現在のディレクトリーを表示し、ls はその中のファイルを一覧表示します。
cd /home/labex/project/postcards
pwd
ls
準備されているのは sample.c、未完成の card.c、提供済みの art.h です。変更するのは sample.c と card.c だけで、art.h はそのまま保ちます。cat はファイルを編集せずに表示します。
cat sample.c
サンプルは 4 行 4 列の格子を使います。grid[row][col] の最初の添字は上から下へ行を選び、次の添字は左から右へ列を選びます。どちらも 0 から始まります。各要素は 0 または 1 で、color 内の RGB の 3 成分を選びます。RGB は赤、緑、青を表し、各成分は 0 から 255 の整数です。color[c][0] の 2 番目の添字が赤を、[1] が緑を、[2] が青を選びます。
printf は標準出力に文字を書きます。通常、その出力先はこの端末です。\n は改行を表します。P3 ファイルは P3、幅と高さ、成分の最大値 255 の順に始まります。その後に RGB の 3 成分が続き、各行は左から右へ、全体は上の行から下の行へ読み取られます。数値は空白文字で区切るため、1 行に 1 ピクセル分の RGB を書いても有効です。P3 では # コメントも使用できます。
サンプルをコンパイルします。gcc は C コンパイラーです。-std=c11 は C11 を選び、-Wall -Wextra は役立つ警告を有効にし、-o sample は実行ファイルの名前を sample にします。
gcc -std=c11 -Wall -Wextra sample.c -o sample
./sample は現在のディレクトリーにある実行ファイルを起動します。> は標準出力を端末ではなくファイルにリダイレクトします。シェルはプログラムを実行する前にそのファイルを開くか上書きします。ここで示す新しい名前を使ってください。
./sample > sample.ppm
Postcard Preview タブに切り替えます。Refresh files をクリックし、Postcard file で sample.ppm を選び、Open postcard をクリックします。状態には 4 × 4 pixels · sample.ppm と表示されます。クリーム色の背景に暗い非対称の図形が見えるはずです。プレビューは今作成したファイルを表示し、欠けたピクセルを補いません。
Workspace に戻ります。暗いインクを {30, 76, 64} から暖色の {170, 70, 45} に変えます。以下のテキスト編集コマンド sed は s/old/new/ でその文字列を正確に置換し、-i で変更を sample.c に保存します。単一引用符により、置換式を変更されない 1 つの引数として sed に渡します。
sed -i 's/{30, 76, 64}/{170, 70, 45}/' sample.c
ソースを編集した後は再コンパイルが必要です。古い実行ファイルは自動では変わりません。
gcc -std=c11 -Wall -Wextra sample.c -o sample
./sample > sample.ppm
Postcard Preview に切り替え、sample.ppm を選んだまま、もう一度 Open postcard をクリックします。前景の色だけが変わり、寸法とクリーム色のピクセルは同じままのはずです。
端末にファイルが見つからないと表示されたら、学んだ cd と ls を使って作業場所に戻ります。プレビューでファイルが存在しないと表示されたら Workspace に戻り、コンパイルが成功したことを確認してから ./sample > sample.ppm を実行します。コンパイルエラーの場合、新しい実行ファイルは作られていません。指摘されたソースの行を直して、再コンパイルしてください。
長方形の図案を RGB ピクセルに変換する
このステップでは、カード生成プログラムを完成させ、その実際の出力を開きます。
Workspace の /home/labex/project/postcards から始めます。提供された図案と未完成の生成プログラムを読みます。
cd /home/labex/project/postcards
cat art.h
cat card.c
#include "art.h" によって、これらの準備済みの定義を card.c のコンパイル時に使えます。#define WIDTH 5 と #define HEIGHT 3 は寸法に名前を付けます。pattern は 3 行で、各行に 5 つの数字の文字があります。C は見える文字の後に値が 0 の終端文字を保存するため、各文字列の行は WIDTH + 1 文字分を確保します。ループで使うのは見える 5 つの位置だけです。
最初の行 "10000" はパレットの色 1 で始まり、その後に色 0 のピクセルが 4 つ続きます。文字 '2' は整数 2 ではありません。文字 '0' を引くと、提供された数字の文字をパレットの添字に変換できます。'2' - '0' は 2 です。図案には 0 から 3 の数字だけがあり、パレットの 4 行に対応します。図案、寸法、色は変更しません。ループでは WIDTH と HEIGHT を使い、同じパレット添字 0 から 3 を使う、幅と高さがそれぞれ 1 から 16 の提供済みの長方形図案でも、再コンパイルして動くようにします。
未完成のプログラムはヘッダーを書きますが、ピクセルは書きません。ヘッダーだけでは画像になりません。y(行)を進める外側のループと、x(列)を進める内側のループを追加します。pattern[y][x] が文字を選び、palette[c][0..2] が RGB の各成分を選びます。printf の %d は、並べた順に整数の引数を出力するための指定です。
次の完全なソースを使います。cat > card.c はそのファイルを置き換えます。<<'EOF' はヒアドキュメントの開始です。シェルは、EOF だけの行が現れるまで、後の行をそのままコピーします。区切りを引用符で囲むことで、C ソース内でのシェルの展開を防ぎます。最後の EOF を含め、ブロック全体をコピーしてください。
cat > card.c <<'EOF'
#include <stdio.h>
#include "art.h"
int main(void) {
printf("P3\n%d %d\n255\n", WIDTH, HEIGHT);
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int c = pattern[y][x] - '0';
printf("%d %d %d\n", palette[c][0], palette[c][1], palette[c][2]);
}
}
return 0;
}
EOF
コンパイルし、新しい出力ファイルを生成します。
gcc -std=c11 -Wall -Wextra card.c -o card
./card > original.ppm
提供された確認ツールはファイルをデコードするだけで、カードを生成したり修復したりしません。ファイル名を引数として実行します。
python3 /home/labex/.local/share/pixel-postcards/inspect.py original.ppm
期待する出力:
5 x 3 pixels; 15 RGB triples; max value 255
なぜこの数値が役立つのでしょうか。正方形だと、幅と高さを入れ替えても気付きにくい場合があります。この 5 列 3 行の図案は横長で、暗い帯が左側にある必要があります。WIDTH は内側のループ、HEIGHT は外側のループを制御します。入れ替えると、行の範囲外にアクセスしたり、ピクセルを出力し忘れたりする可能性があります。
Postcard Preview に切り替えます。Refresh files をクリックし、original.ppm を選んで Open postcard をクリックします。5 × 3 の状態表示を確認し、各行を art.h と比べます。Download PPM をクリックすると実際の画像ファイルを保存できます。ブラウザーは PPM を直接表示せずダウンロードすることがあります。表示にはこのプレビューを使ってください。ラボのチェックを行うため Workspace に戻ります。
スクリーンショットでは original.ppm が選ばれ、保存された寸法 5 × 3 と、画像の下の Download PPM が見えます。左の暗い帯と 3 行すべてを比べてください。
![]()
card.c、実行ファイル card、art.h、original.ppm をこの作業場所に残します。
プレビューでピクセル数のエラーが出る場合、ファイルは存在しますが中身が不完全です。2 つのループの上限を確認し、card.c を保存して再コンパイルし、original.ppm をもう一度生成します。プレビューが画面上で拡大しても、保存された寸法は変わりません。次のラボでは、実際に拡大した画像ファイルを作ります。
まとめ
小さなサンプルをコンパイルして色を変え、長方形の文字配列を RGB の 3 成分に対応付けました。C プログラムが実際の P3 ファイルを作り、そのファイルをデコード、表示、ダウンロードしました。行を先に指定する添字と標準出力のリダイレクトも練習しました。


