使用PHP实现将jpg/png转成.wbmp/.bmp格式图片后再转为16进制字符串(单色位图取模)
2018-11-27日更新:
??由于没有找到生成.bmp
格式图片的好办法,改为使用.wbmp
格式,转换和读取都改为.wbmp
格式,原来的bmp2hex
函数逻辑没有变化,改名为wbmp2hex
,并不再使用ImageCreateFromBMP
函数,可以收藏一下这个函数还是有用的,最新的代码我也提供了下载在文章末尾
准备阶段:
- pctoLCD2002
网上找到的一款取模软件,可以读取.bmp
图片并生成字模,当然我们还是要用代码来完成,这个只是起到了一个对照作用,我将它放在了我的网盘下供大家下载
链接:点我下载pctoLCD2002 密码:2lyl
- PHP GD扩展
强大的PHP图像生成和处理扩展
- Windows自带画图工具
主要用来生成.bpm
格式的图片,目前我还没有找到好的用PHP将.jpg
和.png
图片转为单色.bmp
格式图片的办法,暂时只好用画图工具来生成
- 使用画图工具打开一张事先准备好的图片,另存为
.bmp
单色位图,这样我们就得到了一张.bmp
格式的图片,白色背景,只有黑色
文章图片
打开图片
文章图片
另存为
文章图片
.bmp格式 - 或者我们自己动手来画一张,打开画图工具,调整画布大小为你需要的尺寸,示例为100*70像素,取消勾选保持纵横比,调整好后点击确定,然后我们可以用刷子随便画些什么在画布上,你喜欢就好,然后重复前面的另存为.bmp单色位图步骤
文章图片
image.png - pctoLCD2002也可以新建一幅.bmp图片,并且非常简单
文章图片
pctoLCD2002新建bmp文件
pctoLCD2002
取模
找到PCtoLCD2002.exe并双击打开1. 规则解析,及本文配置项参考 在取字模之前我们先来说下PCtoLCD2002设置项和取模规则
- 配置信息:
文章图片
pctoLCD2002设置项
- 取模说明:
a. 逐行式逐列式:顾名思义就是读取每张图片时取点时是逐行还是逐列的
b. 取模走向:
逆向:从低位到高位
顺向:从高位到低位
举例:
*
星号代表图中非空白的像素点,_
代表空白的像素点,取八位为一个字节
* _ _ _ _ _ _ _
代表一个字节(为了方便查看,每个符号键我加入了一个空格,实际是没有的)
逆向即是从后往前写,表示为00000001
顺向即是从前往后写,表示为10000000
c. 输出数制:
这里选择十六进制,因需选择,不够我需要的是十六进制,后面的代码也只有十六进制的
- 本文取模规则:
逐行式
顺向
十六进制
从第一行开始,每行每隔8个像素点为一个字节,每行结尾最后不足8位,用0补满
文章图片
image.png
但是这还不是我最后想要的格式,需要处理一下:
- 去掉开始处和结束处的文件路径
- 去掉所有的标点符号
,
和'{' '}'
- 去掉十六进制的标识部分,所有的
0x
0000000000000007F8000000000000000000000000003FFC00000000000000000000000000000003FF80000000
这就是我们最终需要的部分了!下面我们用代码来实现这个功能:
问题解决: 一. 实现过程及思路 0. 生成单色位图 卡在这里好久,钻进了死胡同,其实.wbmp的图片完全符合我的要求:
GD库就可以将
jpg/png
转换成wbmp
格式,使用时可以调节threshold
参数,解释如下,我理解为精度不知道准不准确,也没有查到阀值到底是什么意思...文章图片
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时,和给的软件转换后结果完全一致
图片样式:
文章图片
.wbmp格式 1. 读取.wbmp格式图片(原读取.bmp格式) 使用gd库的imagecreatefromwbmp函数:
$filename = 'static/img/11.wbmp';
$im = imagecreatefromwbmp($filename);
安装好GD库扩展后,我发现gd库只能读取.wbmp文件,并不支持.bmp文件,我的gd库版本信息如下
gd_info()
,经过一番google,找到了一个可以使用的读取.bmp的函数ImageCreateFromBMP()
,感谢前辈文章图片
gd_info()
2. 逐个像素读取 可以读取.wbmp格式了,我们该如何能得出每个像素的颜色值呢?
通过查看gd库文档过程,我发现一个函数
imagecolorat()
,可以根据传入的位置,获取每个像素的索引值使用示例:
// 取得一点的颜色
$file_name = '';
//wbmp图片路径
$im = imagecreatefromwbmp($file_name);
//读取wbmp格式
$start_x = 5;
//行,从0开始
$start_y = 10;
//列,从0开始
$color_index = imagecolorat($im, $start_x, $start_y);
print_r($color_index);
3. 获取图片宽高 第2步中可以获取每个像素中的值了,但是我们总不能每个点都手动传入,这时我们就需要获取图片的宽高了
gd库中有获取图片宽高的函数
imagesx()
和imagesy()
,代码示例:$im = imagecreatefromwbmp($file_name);
//读取bmp格式,非gd库
$width = imagesx($im);
$height = imagesy($im);
echo $width.'*'.$height;
到这里,最主要的部分都已经可以获取到了,后面就是逻辑部分了(代码中可以看到具体实现方式):
- 根据图片的宽高,逐行逐点读取每个像素的值,每8位组合成1个字节,然后取模,再转为16进制
- 检测每一行的最后是否满足8个像素,不足则用0补满
- 最终将每一行组合到一起,组成16进制字符串
- 将普通
jpg/png
格式转为.wbmp
$filename = 'static/img/1.jpg';
$path = 'static/img/11.wbmp';
$image = getimagesize($filename);
jpeg2wbmp($filename, $path, $image[1], $image[0], 5);
//threshold == 5时,和给的软件转换后结果完全一致
- 读取
.wbmp
格式图片
$filename = 'static/img/11.wbmp';
$im = imagecreatefromwbmp($filename);
- 将
.wbmp
转为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位转换1次
$hex = (string)dechex(bindec($binary_str));
$hex = strlen($hex) == 1 ? '0' . $hex : $hex;
//补0
$hex_str .= $hex;
$binary_str = '';
}
}//这时如果$binary_str不为空,说明需要向后补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;
//补0
$hex_str .= $hex;
}
}$hex_str = strtoupper($hex_str);
//转为大写
return $hex_str;
}
【使用PHP实现将jpg/png转成.wbmp/.bmp格式图片后再转为16进制字符串(单色位图取模)】最后附上读取
.bmp
格式图片的函数:= 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;
}}
推荐阅读
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 科学养胃,别被忽悠,其实真的很简单
- 其实你就是个普通人
- 海院(实干是海院风景(上))