Rumah >pembangunan bahagian belakang >masalah PHP >Ajar anda helah untuk menjana imej menggunakan aksara ASCII
ASCII ialah sistem pengekodan komputer berdasarkan abjad Latin, terutamanya digunakan untuk memaparkan bahasa Inggeris moden dan bahasa Eropah Barat yang lain. Malah, aksara ASCII bukan sahaja boleh digunakan sebagai standard pertukaran maklumat, tetapi juga boleh digunakan untuk menjana imej Hari ini kami akan memperkenalkannya.
Selalunya terdapat gambar yang dibuat daripada watak-watak di Internet, seperti ini:
Fikirkanlah, yang utama di sini Beberapa pengetahuan digunakan, termasuk:
Menghuraikan warna piksel daripada imej (juga dikenali sebagai nilai RGB)
Pemprosesan penyahwarnaan
Pemetaan piksel kepada aksara
Sebagai bahasa terbaik di dunia, mudah untuk melaksanakan fungsi menarik dengan PHP. Pelaksanaan khusus diterangkan di bawah.
Untuk menganalisis warna piksel dalam imej, kita perlu memahami format storan imej Di sini kita mengambil imej BMP sebagai contoh. apa? Tidak dapat mencari gambar BMP dalam talian? Hanya gunakan QQ untuk mengambil tangkapan skrin dan simpan sebagai BMP.
Imej BMP tidak mengandungi data piksel bermula dari bait pertama fail, tetapi setiap pengepala fail 14 bait, yang menyimpan maklumat meta fail. Di sebelahnya ialah struktur pengepala imej 40-bait, yang menyimpan maklumat meta yang berkaitan dengan imej.
Menyenaraikan setiap medan pengepala fail dan struktur pengepala imej secara terperinci agak terlalu membosankan (lihat lampiran untuk maklumat pengepala terperinci). Untuk menghuraikan piksel imej, anda hanya memerlukan 4 maklumat ini:
Saiz keseluruhan fail imej (bait ke-3 hingga ke-6 fail)
Di mana dalam fail data piksel bermula (11~14 bait)
Lebar dan tinggi imej (lebar: 19~22 bait, ketinggian: 23 ~26 bait)
Berapa banyak bait yang diduduki oleh satu piksel imej (pada 29~30 bait)
Ingin menghuraikan Ke dapatkan data dalam binari, anda boleh menggunakan unpack() digabungkan dengan 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, * ); */
Seperti yang anda boleh ketahui dari bahagian sebelumnya, kami mahu Untuk gambar yang diproses, data piksel bermula dari bait ke-54 fail, dan setiap data piksel menduduki 24 bit. Di antara 24 bit ini, nilai R (merah), G (hijau), dan B (biru) masing-masing menempati 8 bit (1 bait).
Jika saya ingin mendapatkan nilai RGB bagi baris x dan lajur y gambar, maka kedudukan nilai RGB yang sepadan hendaklah dikira seperti ini:
像素(x, y)的 B 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) 像素(x, y)的 G 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 1 像素(x, y)的 R 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 2
Cari nilai daripada tiga warna utama daripada formula Ia disusun dalam susunan BGR, bukan susunan RGB biasa.
Jika anda mengikuti kaedah ini dan melukis piksel satu demi satu pada kanvas mengikut urutan, anda akan mendapati gambar yang terhasil adalah terbalik Ini kerana maklumat piksel gambar disimpan secara terbalik piksel di penjuru kiri sebelah atas sebenarnya berada di hujung fail, jadi jika anda ingin mendapatkan gambar lurus ke hadapan, data piksel harus diambil seperti ini:
像素(x, y)的 B 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 3 像素(x, y)的 G 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 2 像素(x, y)的 R 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 1
Warna piksel diambil, tetapi imej ASCII terakhir adalah hitam dan putih. Bagaimana untuk membuang warna? Terdapat banyak algoritma untuk penyingkiran warna, berikut adalah yang paling mudah dan paling kasar:
新的R、G、B值 = [min(R, G, B) + max(R, G, B)] / 2;
Piksel hitam dan putih, R, G dan B semuanya mempunyai nilai yang sama. Nilai ini boleh dipanggil kecerahan piksel
Akhir sekali, operasi mengambil piksel boleh ditakrifkan sebagai fungsi:
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; }
Dalam langkah terakhir, kami telah untuk memetakan setiap piksel imej Tukar cahaya kepada aksara ascii. Watak ASCII sendiri tidak mempunyai warna warna. Tetapi jika anda menyusun "#" dan "." menjadi petak 100x100, secara visual "#" akan menjadi lebih gelap daripada ".".
Kita boleh mengambil beberapa aksara untuk mewakili kecerahan piksel yang berbeza Apabila kecerahan piksel tertentu berada dalam julat tertentu, gantikannya dengan tahap aksara yang sepadan:
function getChar($colorValue) { $map = '@#mdohsy+/-:.` '; return $map[(int) ($colorValue / 18)]; }
dan Satu masalah: Jika setiap piksel digantikan dengan aksara, peta aksara output akan menjadi sangat besar. Jadi yang terbaik adalah menggunakan aksara untuk menggantikan blok piksel NxN dalam imej asal. Kecerahan keseluruhan blok piksel ialah purata kecerahan setiap piksel dalam blok.
Masalah di atas telah selesai Akhirnya, saya mengambil senyuman Mona Lisa untuk menguji:
Kesannya. cukup bagus :-). Jika latar belakang terminal berwarna putih, jujukan aksara yang mewakili kecerahan boleh diterbalikkan:
// $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视频教程
Atas ialah kandungan terperinci Ajar anda helah untuk menjana imej menggunakan aksara ASCII. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!