使用PHP實(shí)現(xiàn)將jpg/png轉(zhuǎn)成.wbmp/.bmp格式圖片后再轉(zhuǎn)為16進(jìn)制字符串(單色位圖取模)

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格式圖片
  1. 使用畫(huà)圖工具打開(kāi)一張事先準(zhǔn)備好的圖片,另存為.bmp單色位圖,這樣我們就得到了一張.bmp格式的圖片,白色背景,只有黑色
    打開(kāi)圖片

    另存為

    .bmp格式
  2. 或者我們自己動(dòng)手來(lái)畫(huà)一張,打開(kāi)畫(huà)圖工具,調(diào)整畫(huà)布大小為你需要的尺寸,示例為100*70像素,取消勾選保持縱橫比,調(diào)整好后點(diǎn)擊確定,然后我們可以用刷子隨便畫(huà)些什么在畫(huà)布上,你喜歡就好,然后重復(fù)前面的另存為.bmp單色位圖步驟
    image.png
  3. pctoLCD2002也可以新建一幅.bmp圖片,并且非常簡(jiǎn)單


    pctoLCD2002新建bmp文件
二. 使用pctoLCD2002取模

找到PCtoLCD2002.exe并雙擊打開(kāi)

1. 規(guī)則解析,及本文配置項(xiàng)參考

在取字模之前我們先來(lái)說(shuō)下PCtoLCD2002設(shè)置項(xiàng)和取模規(guī)則

  • 配置信息:

    pctoLCD2002設(shè)置項(xiàng)

  • 取模說(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)制串,如圖:


image.png

但是這還不是我最后想要的格式,需要處理一下:

  • 去掉開(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)有查到閥值到底是什么意思...

threshold

生成.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格式
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(),感謝前輩

gd_info()

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;
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末墓塌,一起剝皮案震驚了整個(gè)濱河市苫幢,隨后出現(xiàn)的幾起案子垫挨,更是在濱河造成了極大的恐慌,老刑警劉巖哀峻,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剩蟀,死亡現(xiàn)場(chǎng)離奇詭異切威,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)缰冤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怀薛,“玉大人乾戏,你說(shuō)我怎么就攤上這事三热【脱” “怎么了念搬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵朗徊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我有缆,道長(zhǎng)温亲,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任袖外,我火速辦了婚禮曼验,結(jié)果婚禮上粘姜,老公的妹妹穿的比我還像新娘。我一直安慰自己颖杏,他們只是感情好坛芽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著获讳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪量愧。 梳的紋絲不亂的頭發(fā)上帅矗,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天浑此,我揣著相機(jī)與錄音,去河邊找鬼紊馏。 笑死蒲犬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赫编。 我是一名探鬼主播篇裁,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼达布,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了躺苦?” 一聲冷哼從身側(cè)響起产还,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤脐区,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后炕柔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陵刹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年衰琐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炼蹦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辛辨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出指攒,到底是詐尸還是另有隱情,我是刑警寧澤膝擂,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布架馋,位于F島的核電站全闷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏总珠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一钓瞭、第九天 我趴在偏房一處隱蔽的房頂上張望山涡。 院中可真熱鬧,春花似錦竞穷、人聲如沸系吩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)科盛。三九已至,卻和暖如春厉萝,著一層夾襖步出監(jiān)牢的瞬間榨崩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工翩剪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留前弯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓恕出,卻偏偏與公主長(zhǎng)得像浙巫,于是被迫代替她去往敵國(guó)和親前方。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容