教你一招使用ASCII字元產生圖片
ASCII是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其他西歐語言。其實ASCII字元不只可以作為資訊交換標準,還可以用它來產生圖片,今天我們就來介紹介紹。
網路上常有一些字元做成的圖片,例如這樣:
細想一下,這裡面主要運用到了幾個知識,有:
從圖片解析出像素顏色(也就是通常說的RGB值)
去色處理
像素映射到字元
作為世界上最好的語言,用PHP實現有趣功能也是易如反掌。下面講解一下具體實作。
1. 解析圖片中的像素顏色
解析圖片中的像素顏色,我們需要了解圖片儲存的格式,這裡就以BMP圖片為例。什麼?網路上找不到BMP圖片?用QQ的截張圖,存成BMP就行了。
BMP圖片並不是從檔案的第1個位元組開始就是像素數據,而是一個個14位元組的檔案頭,保存著檔案的元資訊。緊鄰的是一個40位元組的圖片頭結構,保存圖片相關的元資料。
詳細列出文件頭和圖片頭結構的每個字段,就有些太無聊了(詳細的頭信息可以參見附錄)。想要解析圖片的像素,只需要這4 個資訊:
圖片檔案的總體大小(檔案的第3~6個位元組)
-
#像素資料從檔案的哪裡開始(11~14個位元組)
#圖片的寬度和高度(寬:19~22位元組處、高:23 ~26位元組處)
圖片的一個像素佔幾個位元組(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 bit。這24 bit中R(紅)、G(綠)、B(藍)的值各佔8 bit(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順序。
如果你按照這個方法,將像素按順序一個個畫在一張畫布上,你會發現得到的圖片是顛倒的,這是因為圖片的像素資訊是倒過來儲存的,最左上角的像素實際上位於檔案的最末尾,所以想得到一張正過來的圖片,像素資料應該這麼取:
像素(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字元本身沒有顏色深淺一說。但是如果你把”#”和”.”分別排列成100x100的正方形,從視覺上”#”會比”.”顏色更暗一點。
我們可以取若干個字元代表不同像素的明亮度,某個像素的明亮度處於某個區間時,就以對應等級的字元替換:
function getChar($colorValue) { $map = '@#mdohsy+/-:.` '; return $map[(int) ($colorValue / 18)]; }
還有一個問題:如果把每個像素都用一個字元替換的話,那麼輸出的字元圖將會非常巨大。所以最好是用一個字元取代原圖中 NxN 的像素區塊。整個像素區塊的明亮度,就取區塊中每個像素明亮度的平均值。
以上問題都解決了,最後拿一張蒙娜麗莎的微笑來測試:
效果還不錯:-)。如果終端背景是白色的,可以將表示明亮度的字元序列反過來:
// $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)]; }
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中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。
