Heim >Backend-Entwicklung >PHP-Problem >Bringen Sie Ihnen einen Trick bei, um Bilder mit ASCII-Zeichen zu generieren
ASCII ist ein Computerkodierungssystem, das auf dem lateinischen Alphabet basiert und hauptsächlich zur Darstellung von modernem Englisch und anderen westeuropäischen Sprachen verwendet wird. Tatsächlich können ASCII-Zeichen nicht nur als Standard für den Informationsaustausch verwendet werden, sondern auch zum Generieren von Bildern. Heute werden wir sie vorstellen.
Es gibt oft Bilder von Charakteren im Internet, wie zum Beispiel dieses:
Denken Sie darüber nach, hier werden hauptsächlich mehrere Kenntnisse verwendet, darunter:
Parsen Sie die Pixelfarbe aus dem Bild (Wird allgemein auch als RGB-Werte bezeichnet)
Entfärbung
Pixelzuordnung zu Zeichen
Als beste Sprache der Welt ist es einfach, interessante Funktionen mit PHP zu implementieren. Die konkrete Umsetzung wird im Folgenden erläutert.
Um die Pixelfarbe im Bild zu analysieren, müssen wir das Format der Bildspeicherung verstehen. Hier nehmen wir BMP-Bilder als Beispiel. Was? Sie können keine BMP-Bilder online finden? Verwenden Sie einfach QQ, um einen Screenshot zu erstellen und ihn als BMP zu speichern.
BMP-Bilder enthalten keine Pixeldaten ab dem ersten Byte der Datei, sondern jeden 14-Byte-Dateiheader, in dem die Metainformationen der Datei gespeichert sind. Daneben befindet sich eine 40-Byte-Bildheaderstruktur, in der Metainformationen zum Bild gespeichert sind.
Es wäre etwas zu langweilig, jedes Feld der Datei-Header- und Bild-Header-Struktur im Detail aufzulisten (detaillierte Header-Informationen finden Sie im Anhang). Um die Pixel eines Bildes zu analysieren, benötigen Sie nur diese 4 Informationen:
Die Gesamtgröße der Bilddatei (3. bis 6. Byte der Datei)
Wo in der Datei die Pixeldaten beginnen ( 11 bis 14 Bytes)
Die Breite und Höhe des Bildes (Breite: 19~22 Bytes, Höhe: 23~26 Bytes)
Wie viele Bytes belegt ein Pixel des Bildes (29~30 Zeichen). Abschnitt)
Wenn Sie die Daten im Binärformat analysieren möchten, können Sie unpack() in Kombination mit 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, * ); */
Wie Sie aus dem vorherigen Abschnitt wissen können , wir wollen Für das verarbeitete Bild beginnen die Pixeldaten ab dem 54. Byte der Datei und jede Pixeldaten belegt 24 Bit. Unter diesen 24 Bits belegen die Werte von R (rot), G (grün) und B (blau) jeweils 8 Bits (1 Byte).
Wenn ich den RGB-Wert der x-ten Zeile und der y-ten Spalte des Bildes erhalten möchte, sollte die Position des entsprechenden RGB-Werts wie folgt berechnet werden:
像素(x, y)的 B 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) 像素(x, y)的 G 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 1 像素(x, y)的 R 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 2
Aus der Formel wird ermittelt, dass der Die Werte der drei Primärfarben sind in der BGR-Reihenfolge angeordnet, was nicht der üblichen RGB-Reihenfolge entspricht.
Wenn Sie dieser Methode folgen und die Pixel der Reihe nach auf eine Leinwand zeichnen, werden Sie feststellen, dass das resultierende Bild auf dem Kopf steht. Dies liegt daran, dass die Pixelinformationen des Bildes verkehrt herum gespeichert sind Die linke Ecke befindet sich tatsächlich am Ende der Datei. Wenn Sie also ein direktes Bild erhalten möchten, sollten die Pixeldaten wie folgt abgerufen werden:
像素(x, y)的 B 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 3 像素(x, y)的 G 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 2 像素(x, y)的 R 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 1
Die Farbe des Pixels wird abgerufen, aber das endgültige ASCII Das Bild ist schwarzweiß. Wie entferne ich die Farbe? Es gibt viele Algorithmen zur Farbentfernung. Hier ist der einfachste und gröbste:
新的R、G、B值 = [min(R, G, B) + max(R, G, B)] / 2;
Schwarze und weiße Pixel, R, G und B haben alle den gleichen Wert. Dieser Wert kann als Helligkeit des Pixels bezeichnet werden. Die Operation zum Aufnehmen des Pixels kann als Funktion definiert werden:
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. Pixel-zu-Zeichen-Zuordnung
Wir können mehrere Zeichen verwenden, um die Helligkeit verschiedener Pixel darzustellen. Wenn die Helligkeit eines bestimmten Pixels in einem bestimmten Bereich liegt, ersetzen Sie sie durch die entsprechende Zeichenebene:
function getChar($colorValue) { $map = '@#mdohsy+/-:.` '; return $map[(int) ($colorValue / 18)]; }
Es gibt noch eine andere Frage: ob jedes Pixel verwendet wird Wenn ein Zeichen ersetzt wird, ist das ausgegebene Zeichenbild sehr groß. Daher ist es am besten, die NxN-Pixelblöcke im Originalbild durch ein Zeichen zu ersetzen. Die Helligkeit des gesamten Pixelblocks ist die durchschnittliche Helligkeit jedes Pixels im Block.
Die oben genannten Probleme wurden gelöst. Machen Sie zum Schluss ein Foto von Mona Lisas Lächeln:
Der Effekt ist nicht schlecht :-). Wenn der Hintergrund des Terminals weiß ist, kann die Reihenfolge der Zeichen, die die Helligkeit darstellen, umgekehrt werden:
// $map = '@#mdohsy+/-:.` '; $map = ' `.:-/+yshodm#@'; // 反过来
<?php $data = file_get_contents('timg.bmp');$ret = unpack('v/Vsize/v/v/VpixelStart/V/Vwidth/Vheight/v/vbytePerPixel/V*6', substr($data, 0x0, 54));$size = $ret['size'];$offset = $ret['pixelStart'];$width = $ret['width'];$height = $ret['height'];$bitDepth = $ret['bytePerPixel'];$pixelLenPerChar = 4;$charImgWidth = (int) ($width / $pixelLenPerChar);$charImgHeight = (int) ($height / $pixelLenPerChar);for ($i = 0; $i !== $charImgHeight; $i++) { $buf = ''; 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)]; }
偏移 | 大小(字节) | 含义 | 本文中图片示例值 |
---|---|---|---|
0 | 2 | 固定为”BM”两个字符的编码 | 0x42 0x4d |
2 | 4 | 文件大小 | 0x000ac7fa |
6 | 4 | 保留字段,一般为 0 | 0x00000000 |
10 | 4 | 像素数据起始处偏移 | 0x00000036 |
偏移 | 大小(字节) | 含义 | 本文中图片示例值 |
---|---|---|---|
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视频教程
Das obige ist der detaillierte Inhalt vonBringen Sie Ihnen einen Trick bei, um Bilder mit ASCII-Zeichen zu generieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!