ホームページ >バックエンド開発 >PHPの問題 >ASCII 文字を使用して画像を生成するコツを教えます

ASCII 文字を使用して画像を生成するコツを教えます

醉折花枝作酒筹
醉折花枝作酒筹転載
2021-07-22 15:50:093308ブラウズ

ASCII は、ラテン文字をベースにしたコンピュータ コード システムで、主に現代英語やその他の西ヨーロッパ言語を表示するために使用されます。実は、ASCII 文字は情報交換の標準としてだけでなく、画像の生成にも使用できるので、今日はそれを紹介します。

ASCII 文字を使用して画像を生成するコツを教えます

インターネット上には、次のような文字で構成された画像がよくあります。

ASCII 文字を使用して画像を生成するコツを教えます

よく考えてみてください。ここで重要なのは、次のようないくつかの知識が使用されることです。

  • 画像からピクセル カラーを解析する (通常は RGB 値)

  • 脱色

  • 文字へのピクセル マッピング

世界最高の言語である PHP では、興味深い関数を簡単に実装できます。具体的な実装については以下で説明します。

1. 画像のピクセル カラーを分析する

画像のピクセル カラーを分析するには、画像ストレージの形式を理解する必要があります。ここでは BMP 画像を例に挙げます。 。何? BMP 画像がオンラインで見つかりませんか? QQ を使用してスクリーンショットを撮り、BMP として保存するだけです。

BMP 画像には、ファイルの最初のバイトから始まるピクセル データはありませんが、ファイルのメタ情報を保存する 14 バイトの各ファイル ヘッダーがあります。その隣には 40 バイトの画像ヘッダー構造があり、画像に関連するメタ情報が格納されます。

ファイル ヘッダーと画像ヘッダー構造の各フィールドを詳細にリストするのは少し退屈です (詳細なヘッダー情報については、付録を参照してください)。画像のピクセルを解析するには、次の 4 つの情報だけが必要です:

  • #画像ファイル全体のサイズ (ファイルの 3 番目から 6 番目のバイト)

  • ファイル内のピクセルデータの開始位置(11~14バイト)

  • 画像の幅と高さ(幅:19~22バイト、高さ) : 23 ~26 バイト)

  • 画像の 1 ピクセルは何バイトを占めますか (29 ~ 30 バイト)

解析したいのは次のとおりですデータをバイナリで取得するには、unpack() と substr() を組み合わせて使用​​します:

$data = file_get_contents('image.bmp');$ret = unpack('v/Vsize/v/v/VpixelStart/V/Vwidth/Vheight/v/vbytePerPixel/V*6',
    substr($data, 0x0, 54));/**
 * $ret的内容:
 * array (
 *     'size' => 706554,
 *     'pixelStart' => 54,
 *     'width' => 500,
 *     'height' => 471,
 *     'bytePerPixel' => 24,
 * );
 */

2. ピクセル カラーの取得とカラーの削除

前のセクションからわかるように、写真の場合、ファイルの 54 バイト目からピクセル データが始まり、各ピクセル データは 24 ビットを占めます。この24ビットのうち、R(赤)、G(緑)、B(青)の値がそれぞれ8ビット(1バイト)を占めます。

画像の行 x と列 y の RGB 値を取得したい場合、対応する RGB 値の位置は次のように計算する必要があります。

像素(x, y)的 B 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y)
像素(x, y)的 G 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 1
像素(x, y)的 R 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 2

これは、三原色の値を求める式 BGR の順序は通常の RGB の順序ではありません。

この方法に従って、キャンバス上にピクセルを 1 つずつ順番に描画すると、結果として得られる絵が上下逆さまになることがわかります。これは、絵のピクセル情報が上下逆さまに保存されているためです。左上隅のピクセルは実際にはファイルの最後にあるため、単純な画像を取得したい場合は、次のようにピクセル データを取得する必要があります。

像素(x, y)的 B 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 3
像素(x, y)的 G 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 2
像素(x, y)的 R 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 1

ピクセルの色が取得されます。 , しかし、最終的な ASCII 画像は白黒です。どうすればよいですか? 色の除去はどうすればよいですか?色の除去には多くのアルゴリズムがありますが、最も単純で粗雑なアルゴリズムを次に示します:

新的R、G、B值 = [min(R, G, B) + max(R, G, B)] / 2;

黒と白のピクセルの場合、R、G、B はすべて同じ値を持ちます。この値は、ピクセルの明るさと呼ぶことができます。ピクセル

最後に、ピクセルを取得する操作は関数として定義できます:

function getPixelColor($x, $y) {
    global $width, $size, $data;
    $b = ord($data[$size - 3 * ($width * $x + $y) - 3]);
    $g = ord($data[$size - 3 * ($width * $x + $y) - 2]);
    $r = ord($data[$size - 3 * ($width * $x + $y) - 1]);
    return (min($r, $g, $b) + max($r, $g, $b)) >> 1;
}

3. ピクセルから文字へのマッピング

最後のステップでは、画像の各ピクセルの深さを ASCII 文字に変換します。 ASCII 文字自体には色合いがありません。しかし、「#」と「.」を100×100の正方形に配置すると、視覚的には「#」の方が「.」よりも暗くなります。

さまざまなピクセルの明るさを表すために複数の文字を使用できます。特定のピクセルの明るさが特定の範囲にある場合は、対応するレベルの文字に置き換えます:

function getChar($colorValue) {
    $map = '@#mdohsy+/-:.` ';
    return $map[(int) ($colorValue / 18)];
}

別の質問: 各ピクセルを文字に置き換えると、出力される文字画像は非常に巨大になります。したがって、文字を使用して元の画像の NxN ピクセル ブロックを置き換えるのが最善です。ピクセル ブロック全体の明るさは、ブロック内の各ピクセルの平均明るさです。

上記の問題は解決されました。最後に、モナリザの笑顔を撮ってテストしてみました:

ASCII 文字を使用して画像を生成するコツを教えます

ASCII 文字を使用して画像を生成するコツを教えます

その効果かなり良いです:-)。端末の背景が白の場合、明るさを表す文字列を

のように反転できます。

// $map = '@#mdohsy+/-:.` ';
$map = ' `.:-/+yshodm#@'; // 反过来

附录

完整代码

<?php $data = file_get_contents(&#39;timg.bmp&#39;);$ret = unpack(&#39;v/Vsize/v/v/VpixelStart/V/Vwidth/Vheight/v/vbytePerPixel/V*6&#39;, substr($data, 0x0, 54));$size = $ret[&#39;size&#39;];$offset = $ret[&#39;pixelStart&#39;];$width = $ret[&#39;width&#39;];$height = $ret[&#39;height&#39;];$bitDepth = $ret[&#39;bytePerPixel&#39;];$pixelLenPerChar = 4;$charImgWidth = (int) ($width / $pixelLenPerChar);$charImgHeight = (int) ($height / $pixelLenPerChar);for ($i = 0; $i !== $charImgHeight; $i++) {    $buf = &#39;&#39;;    for ($j = 0; $j !== $charImgWidth; $j++) {        $sum = 0;        for ($k = 0; $k !== $pixelLenPerChar; $k++) {            for ($l = 0; $l !== $pixelLenPerChar; $l++) {                $sum += getPixelColor($pixelLenPerChar * $i + $k, $pixelLenPerChar * $j + $l);
            }
        }        $sum = (int) ($sum / $pixelLenPerChar / $pixelLenPerChar);        $buf = getChar($sum) . $buf;
    }    echo $buf . PHP_EOL;
}function getPixelColor($x, $y) {
    global $width, $size, $data;    $b = ord($data[$size - 3 * ($width * $x + $y) - 3]);    $g = ord($data[$size - 3 * ($width * $x + $y) - 2]);    $r = ord($data[$size - 3 * ($width * $x + $y) - 1]);    return (min($r, $g, $b) + max($r, $g, $b)) >> 1;
}function getChar($colorValue) {
    $map = '@#mdohsy+/-:.` ';    return $map[(int) ($colorValue / 18)];
}

BMP文件头格式

偏移 大小(字节) 含义 本文中图片示例值
0 2 固定为”BM”两个字符的编码 0x42 0x4d
2 4 文件大小 0x000ac7fa
6 4 保留字段,一般为 0 0x00000000
10 4 像素数据起始处偏移 0x00000036

BMP图片头格式

偏移 大小(字节) 含义 本文中图片示例值
14 4 图片头的大小(字节) 0x00000028
18 4 图片的宽度 0x000001f4
22 4 图片的高度 0x000001d7
26 2 图像的帧数(静态图都是1) 0x0001
28 2 一个像素占的比特位数 0x0018
30 4 保留字段,一般为 0 0x000000
34 4 像素数据占用的总字节数 0x000ac7c4
38 4 保留字段,一般为 0 0x000000
42 4 保留字段,一般为 0 0x000000
46 4 保留字段,一般为 0 0x000000
50 4 保留字段,一般为 0 0x000000

推荐学习:php视频教程

以上がASCII 文字を使用して画像を生成するコツを教えますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。