2018-11-27日更新:
??由于沒(méi)有找到生成.bmp
格式圖片的好辦法,改為使用.wbmp
格式,轉(zhuǎn)換和讀取都改為.wbmp
格式,原來(lái)的bmp2hex
函數(shù)邏輯沒(méi)有變化,改名為wbmp2hex
,并不再使用ImageCreateFromBMP
函數(shù),可以收藏一下這個(gè)函數(shù)還是有用的,最新的代碼我也提供了下載在文章末尾
準(zhǔn)備階段:
pctoLCD2002
網(wǎng)上找到的一款取模軟件,可以讀取.bmp
圖片并生成字模,當(dāng)然我們還是要用代碼來(lái)完成,這個(gè)只是起到了一個(gè)對(duì)照作用,我將它放在了我的網(wǎng)盤(pán)下供大家下載
鏈接:點(diǎn)我下載pctoLCD2002 密碼:2lyl
PHP GD擴(kuò)展
強(qiáng)大的PHP圖像生成和處理擴(kuò)展Windows自帶畫(huà)圖工具
主要用來(lái)生成.bpm
格式的圖片,目前我還沒(méi)有找到好的用PHP將.jpg
和.png
圖片轉(zhuǎn)為單色.bmp
格式圖片的辦法,暫時(shí)只好用畫(huà)圖工具來(lái)生成
操作步驟分解演示
一. 使用畫(huà)圖工具獲得.bmp格式圖片
- 使用畫(huà)圖工具打開(kāi)一張事先準(zhǔn)備好的圖片,另存為
.bmp
單色位圖,這樣我們就得到了一張.bmp
格式的圖片,白色背景,只有黑色
- 或者我們自己動(dòng)手來(lái)畫(huà)一張,打開(kāi)畫(huà)圖工具,調(diào)整畫(huà)布大小為你需要的尺寸,示例為100*70像素,取消勾選保持縱橫比,調(diào)整好后點(diǎn)擊確定,然后我們可以用刷子隨便畫(huà)些什么在畫(huà)布上,你喜歡就好,然后重復(fù)前面的另存為.bmp單色位圖步驟
-
pctoLCD2002也可以新建一幅.bmp圖片,并且非常簡(jiǎn)單
二. 使用pctoLCD2002
取模
找到PCtoLCD2002.exe并雙擊打開(kāi)
1. 規(guī)則解析,及本文配置項(xiàng)參考
在取字模之前我們先來(lái)說(shuō)下PCtoLCD2002設(shè)置項(xiàng)和取模規(guī)則
-
配置信息:
取模說(shuō)明:
a. 逐行式逐列式:顧名思義就是讀取每張圖片時(shí)取點(diǎn)時(shí)是逐行還是逐列的
b. 取模走向:
逆向:從低位到高位
順向:從高位到低位
舉例:
*
星號(hào)代表圖中非空白的像素點(diǎn),_
代表空白的像素點(diǎn),取八位為一個(gè)字節(jié)
* _ _ _ _ _ _ _
代表一個(gè)字節(jié)(為了方便查看,每個(gè)符號(hào)鍵我加入了一個(gè)空格,實(shí)際是沒(méi)有的)
逆向即是從后往前寫(xiě),表示為00000001
順向即是從前往后寫(xiě),表示為10000000
c. 輸出數(shù)制:
這里選擇十六進(jìn)制,因需選擇,不夠我需要的是十六進(jìn)制,后面的代碼也只有十六進(jìn)制的本文取模規(guī)則:
逐行式
順向
十六進(jìn)制
從第一行開(kāi)始,每行每隔8個(gè)像素點(diǎn)為一個(gè)字節(jié),每行結(jié)尾最后不足8位,用0補(bǔ)滿(mǎn)
2. 生成字模
設(shè)置好規(guī)則后,打開(kāi)之前制作的.bmp圖片,點(diǎn)擊生成字模,這時(shí)下方會(huì)生成出十六進(jìn)制串,如圖:
但是這還不是我最后想要的格式,需要處理一下:
- 去掉開(kāi)始處和結(jié)束處的文件路徑
- 去掉所有的標(biāo)點(diǎn)符號(hào)
,
和'{' '}'
- 去掉十六進(jìn)制的標(biāo)識(shí)部分,所有的
0x
最后得到一串連貫的字符串,類(lèi)似:
0000000000000007F8000000000000000000000000003FFC00000000000000000000000000000003FF80000000
這就是我們最終需要的部分了!下面我們用代碼來(lái)實(shí)現(xiàn)這個(gè)功能:
問(wèn)題解決:
一. 實(shí)現(xiàn)過(guò)程及思路
0. 生成單色位圖
卡在這里好久,鉆進(jìn)了死胡同,其實(shí).wbmp的圖片完全符合我的要求:
GD庫(kù)就可以將jpg/png
轉(zhuǎn)換成wbmp
格式,使用時(shí)可以調(diào)節(jié)threshold
參數(shù),解釋如下,我理解為精度不知道準(zhǔn)不準(zhǔn)確,也沒(méi)有查到閥值到底是什么意思...
生成.wbmp
格式圖片代碼示例:
$filename = 'static/img/1.jpg';
$path = 'static/img/11.wbmp';
$image = getimagesize($filename);
jpeg2wbmp($filename, $path, $image[1], $image[0], 5);//threshold == 5時(shí),和給的軟件轉(zhuǎn)換后結(jié)果完全一致
圖片樣式:
1. 讀取.wbmp格式圖片(原讀取.bmp格式)
使用gd庫(kù)的imagecreatefromwbmp函數(shù):
$filename = 'static/img/11.wbmp';
$im = imagecreatefromwbmp($filename);
安裝好GD庫(kù)擴(kuò)展后,我發(fā)現(xiàn)gd庫(kù)只能讀取.wbmp文件,并不支持.bmp文件,我的gd庫(kù)版本信息如下gd_info()
,經(jīng)過(guò)一番google,找到了一個(gè)可以使用的讀取.bmp的函數(shù)ImageCreateFromBMP()
,感謝前輩
2. 逐個(gè)像素讀取
可以讀取.wbmp格式了,我們?cè)撊绾文艿贸雒總€(gè)像素的顏色值呢?
通過(guò)查看gd庫(kù)文檔過(guò)程,我發(fā)現(xiàn)一個(gè)函數(shù)imagecolorat()
,可以根據(jù)傳入的位置,獲取每個(gè)像素的索引值
使用示例:
// 取得一點(diǎn)的顏色
$file_name = '';//wbmp圖片路徑
$im = imagecreatefromwbmp($file_name);//讀取wbmp格式
$start_x = 5;//行,從0開(kāi)始
$start_y = 10;//列,從0開(kāi)始
$color_index = imagecolorat($im, $start_x, $start_y);
print_r($color_index);
3. 獲取圖片寬高
第2步中可以獲取每個(gè)像素中的值了,但是我們總不能每個(gè)點(diǎn)都手動(dòng)傳入,這時(shí)我們就需要獲取圖片的寬高了
gd庫(kù)中有獲取圖片寬高的函數(shù)imagesx()
和imagesy()
,代碼示例:
$im = imagecreatefromwbmp($file_name);//讀取bmp格式,非gd庫(kù)
$width = imagesx($im);
$height = imagesy($im);
echo $width.'*'.$height;
到這里,最主要的部分都已經(jīng)可以獲取到了,后面就是邏輯部分了(代碼中可以看到具體實(shí)現(xiàn)方式):
- 根據(jù)圖片的寬高,逐行逐點(diǎn)讀取每個(gè)像素的值,每8位組合成1個(gè)字節(jié),然后取模,再轉(zhuǎn)為16進(jìn)制
- 檢測(cè)每一行的最后是否滿(mǎn)足8個(gè)像素,不足則用0補(bǔ)滿(mǎn)
- 最終將每一行組合到一起,組成16進(jìn)制字符串
二. 源碼
整個(gè)過(guò)程可以大概分為三步完成,你可以根據(jù)自己的需求參考或者直接copy使用,如果對(duì)你有幫助,希望可以點(diǎn)個(gè)贊,轉(zhuǎn)載請(qǐng)注明本篇文章鏈接地址及作者,謝謝!
- 將普通
jpg/png
格式轉(zhuǎn)為.wbmp
$filename = 'static/img/1.jpg';
$path = 'static/img/11.wbmp';
$image = getimagesize($filename);
jpeg2wbmp($filename, $path, $image[1], $image[0], 5);//threshold == 5時(shí),和給的軟件轉(zhuǎn)換后結(jié)果完全一致
- 讀取
.wbmp
格式圖片
$filename = 'static/img/11.wbmp';
$im = imagecreatefromwbmp($filename);
- 將
.wbmp
轉(zhuǎn)為hex_str
/**
* @param $im
* @return string
* Commented by liu
*/
public function wbmp2hex($im)
{
$width = imagesx($im);
$height = imagesy($im);
$num = $width % 8;
$hex_str = '';
for ($start_y = 0; $start_y < $height; $start_y++) {
$binary_str = '';
for ($start_x = 0; $start_x < $width; $start_x++) {
$color_index = imagecolorat($im, $start_x, $start_y);//指定像素的索引值
$binary_str .= $color_index == 1 ? 1 : 0;
if ((1 + $start_x) % 8 == 0 && $start_x != 0) {//每隔8位轉(zhuǎn)換1次
$hex = (string)dechex(bindec($binary_str));
$hex = strlen($hex) == 1 ? '0' . $hex : $hex;//補(bǔ)0
$hex_str .= $hex;
$binary_str = '';
}
}
//這時(shí)如果$binary_str不為空,說(shuō)明需要向后補(bǔ)0
if ($num) {
for ($i = 0; $i < 8 - $num; $i++) {
$binary_str .= 0;
}
$hex = (string)dechex(bindec($binary_str));
$hex = strlen($hex) == 1 ? '0' . $hex : $hex;//補(bǔ)0
$hex_str .= $hex;
}
}
$hex_str = strtoupper($hex_str);//轉(zhuǎn)為大寫(xiě)
return $hex_str;
}
最后附上讀取.bmp
格式圖片的函數(shù):
<?php
/**
* Commented by liu
* Create on 2018/11/23 17:51
* Class Image_api
*/
class Image_api
{
function __construct (){
}
/**
* ImageCreateFromBMP函數(shù),讀取bmp格式圖片
* 注:phpGD擴(kuò)展中沒(méi)有ImageCreateFromBMP函數(shù),只有ImageCreateFromWBMP
* @param $filename
* @return bool|resource
* Commented by liu
*/
function ImageCreateFromBMP($filename)
{
//Ouverture du fichier en mode binaire
if (!$f1 = fopen($filename, "rb"))
return FALSE;
//1 : Chargement des ent?tes FICHIER
$FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1, 14));
if ($FILE['file_type'] != 19778)
return FALSE;
//2 : Chargement des ent?tes BMP
$BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel' .
'/Vcompression/Vsize_bitmap/Vhoriz_resolution' .
'/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1, 40));
$BMP['colors'] = pow(2, $BMP['bits_per_pixel']);
if ($BMP['size_bitmap'] == 0)
$BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
$BMP['bytes_per_pixel'] = $BMP['bits_per_pixel'] / 8;
$BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
$BMP['decal'] = ($BMP['width'] * $BMP['bytes_per_pixel'] / 4);
$BMP['decal'] -= floor($BMP['width'] * $BMP['bytes_per_pixel'] / 4);
$BMP['decal'] = 4 - (4 * $BMP['decal']);
if ($BMP['decal'] == 4)
$BMP['decal'] = 0;
//3 : Chargement des couleurs de la palette
$PALETTE = array();
if ($BMP['colors'] < 16777216) {
$PALETTE = unpack('V' . $BMP['colors'], fread($f1, $BMP['colors'] * 4));
}
//4 : Cr?ation de l'image
$IMG = fread($f1, $BMP['size_bitmap']);
$VIDE = chr(0);
$res = imagecreatetruecolor($BMP['width'], $BMP['height']);
$P = 0;
$Y = $BMP['height'] - 1;
while ($Y >= 0) {
$X = 0;
while ($X < $BMP['width']) {
if ($BMP['bits_per_pixel'] == 24)
$COLOR = unpack("V", substr($IMG, $P, 3) . $VIDE);
elseif ($BMP['bits_per_pixel'] == 16) {
$COLOR = unpack("n", substr($IMG, $P, 2));
$COLOR[1] = $PALETTE[$COLOR[1] + 1];
} elseif ($BMP['bits_per_pixel'] == 8) {
$COLOR = unpack("n", $VIDE . substr($IMG, $P, 1));
$COLOR[1] = $PALETTE[$COLOR[1] + 1];
} elseif ($BMP['bits_per_pixel'] == 4) {
$COLOR = unpack("n", $VIDE . substr($IMG, floor($P), 1));
if (($P * 2) % 2 == 0)
$COLOR[1] = ($COLOR[1] >> 4);
else
$COLOR[1] = ($COLOR[1] & 0x0F);
$COLOR[1] = $PALETTE[$COLOR[1] + 1];
} elseif ($BMP['bits_per_pixel'] == 1) {
$COLOR = unpack("n", $VIDE . substr($IMG, floor($P), 1));
if (($P * 8) % 8 == 0)
$COLOR[1] = $COLOR[1] >> 7;
elseif (($P * 8) % 8 == 1)
$COLOR[1] = ($COLOR[1] & 0x40) >> 6;
elseif (($P * 8) % 8 == 2)
$COLOR[1] = ($COLOR[1] & 0x20) >> 5;
elseif (($P * 8) % 8 == 3)
$COLOR[1] = ($COLOR[1] & 0x10) >> 4;
elseif (($P * 8) % 8 == 4)
$COLOR[1] = ($COLOR[1] & 0x8) >> 3;
elseif (($P * 8) % 8 == 5)
$COLOR[1] = ($COLOR[1] & 0x4) >> 2;
elseif (($P * 8) % 8 == 6)
$COLOR[1] = ($COLOR[1] & 0x2) >> 1;
elseif (($P * 8) % 8 == 7)
$COLOR[1] = ($COLOR[1] & 0x1);
$COLOR[1] = $PALETTE[$COLOR[1] + 1];
} else
return FALSE;
imagesetpixel($res, $X, $Y, $COLOR[1]);
$X++;
$P += $BMP['bytes_per_pixel'];
}
$Y--;
$P += $BMP['decal'];
}
//Fermeture du fichier
fclose($f1);
return $res;
}
}