PHP 生成bmp图 并取模点阵数据

  1. 把文字生成1位深度的bmp图 并保存服务器 获取到地址

    /**
     * 生成bmp格式图片
     * @param $input_text 文字
     * @param $font_file 字体
     * @param $width 宽度
     * @param $height 高度
     * @param $fontSize 字体大小
     * @return array|string[]
     */
    function createBmpImage($input_text,$font_file="public/assets/fonts/simsun.ttc",$width=128,$height=32,$fontSize=12)
    {
        $bmp = imagecreate($width, $height);
        // 设置白色和黑色
        $white = imagecolorallocate($bmp, 255, 255, 255);
        $text_color = imagecolorallocate($bmp, 0, 0, 0);
        // 填充背景为白色
        imagefill($bmp, 0, 0, $white);
        // 获取用户输入的内容(假设输入内容为字符串"Hello World!")
        $font_file  =ROOT_PATH. $font_file; // 你的 TrueType 字体文件路径

        // 在图片上写入文字
        // imagestring($bmp, 4, 10, 10, $input_text, $black);
        // imagettftext($bmp, 12, 0, 10, 20, $text_color, $font_file, $input_text);
        $textX = ($width - imagettfbbox($fontSize, 0, $font_file, $input_text)[4]) / 2; // 计算字符串的x坐标
        $textY = ($height - imagettfbbox($fontSize, 0, $font_file, $input_text)[7]) / 2; // 计算字符串的y坐标
        // 在画布上添加文本
        imagettftext($bmp, $fontSize, 0, $textX, $textY, $text_color, $font_file, $input_text); // 在图片上写入字符串

        // 保存图片到指定目录
        $savekey = "/uploads/".date('Y').date('m').date('d')."/";

        $savekey = '/' . ltrim($savekey, '/');
        $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);

        $fileName = uniqueNo().'.bmp';

        $destDir = ROOT_PATH . 'public' . str_replace('/', DS, $uploadDir);

        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }
        $destFile = $destDir . $fileName;

        imagebmp_custom($bmp,$destFile,1);

        $url=['url'=>$savekey.$fileName,'root_url'=>$destFile];

        return $url??[];
    }


    /**
     * 转自:https://www.cnblogs.com/mengdejun/p/imagecreatefrombmp_imagebmp.html
     * 格式组成典型的BMP图像文件由四部分组成:
     * 1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;
     * 2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;
     * 3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
     * 4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。
     * @param object $im bmp文件内容
     * @param string $filename 转换后文件保存名称
     * @param int $bit 位深度
     * @param int $compression 是否压缩
     * @return bool
     */
    function imagebmp_custom(&$im, $filename = '', $bit = 8, $compression = 0)
    {
        if (!in_array($bit, array(1, 4, 8, 16, 24, 32))) {
            $bit = 8;  //记录每个像素所占计算机字节的位数,默认为8位
        } else if ($bit == 32) // todo:32 bit
        {
            $bit = 24;
        }
        $bits = pow(2, $bit); //表示待创建的图像一共由$bits种颜色组成

        // 将图像调整为调色板图像,便于以后绘图,如果是24位BMP位图,那么就不需要这一步
        /*调色板是被保存在一个RGBQUAD结构的数组中,该结构指出了每一种颜色的红、绿、蓝的分量值。
         *位数组中的每一个索引都对应于一个调色板项(即一个RGBQUAD结构),应用程序将根据这种对
         *应关系,将像素索引值转换为像素RGB值(真实的像素颜色)
         * */
        imagetruecolortopalette($im, true, $bits);
        $width = imagesx($im);
        $height = imagesy($im);
        $colors_num = imagecolorstotal($im); //返回的一般都是256
        // 颜色索引
        $rgb_quad = '';
        if ($bit <= 8)//仅针对1,4,8位BMP位图建立颜色索引
        {

            for ($i = 0; $i < $colors_num; $i++) {
                $colors = imagecolorsforindex($im, $i);//每一幅图的索引表都是不一样的!
                $rgb_quad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
            }

            // 位图数据
            $bmp_data = '';

            // 非压缩,即对RGB值不进行压缩,读取时顺序为BGR,高位在前,低位在后
            if ($compression == 0 || $bit < 8) {
                $compression = 0;

                // 每行字节数必须为4的倍数,补齐。
                $extra = '';
                $padding = 32 - ($width * $bit) % 32;
                if ($padding % 32 != 0) {
                    $extra = str_repeat("\0", $padding);
                }

                for ($j = $height - 1; $j >= 0; $j--) {
                    $i = 0;
                    while ($i < $width) {
                        $bin = 0;
                        $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0;

                        for ($k = 8 - $bit; $k >= $limit; $k -= $bit) {
                            $index = imagecolorat($im, $i, $j);
                            $bin |= $index << $k;
                            $i++;
                        }

                        $bmp_data .= chr($bin);
                    }

                    $bmp_data .= $extra;
                }
            } // RLE8 压缩
            else if ($compression == 1 && $bit == 8) {
                for ($j = $height - 1; $j >= 0; $j--) {
                    $last_index = "\0";
                    $same_num = 0;
                    for ($i = 0; $i <= $width; $i++) {
                        $index = imagecolorat($im, $i, $j);
                        if ($index !== $last_index || $same_num > 255) {
                            if ($same_num != 0) {
                                $bmp_data .= chr($same_num) . chr($last_index);
                            }

                            $last_index = $index;
                            $same_num = 1;
                        } else {
                            $same_num++;
                        }
                    }

                    $bmp_data .= "\0\0";
                }

                $bmp_data .= "\0\1";
            }
            $size_quad = strlen($rgb_quad);
            $size_data = strlen($bmp_data);
        } else {
            // 每行字节数必须为4的倍数,补齐。
            $extra = '';
            $padding = 4 - ($width * ($bit / 8)) % 4;
            if ($padding % 4 != 0) {
                $extra = str_repeat("\0", $padding);
            }
            // 位图数据
            $bmp_data = '';
            for ($j = $height - 1; $j >= 0; $j--) {
                for ($i = 0; $i < $width; $i++) {
                    $index = imagecolorat($im, $i, $j);
                    $colors = imagecolorsforindex($im, $index);
                    if ($bit == 16) {
                        $bin = 0 << $bit;

                        $bin |= ($colors['red'] >> 3) << 10;
                        $bin |= ($colors['green'] >> 3) << 5;
                        $bin |= $colors['blue'] >> 3;
                        $bmp_data .= pack("v", $bin);
                    } else {
                        $bmp_data .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
                    }

                    // todo: 32bit;
                }
                $bmp_data .= $extra;
            }
            $size_quad = 0;
            $size_data = strlen($bmp_data);
            $colors_num = 0;
        }

        // 位图文件头
        $file_header = "BM" . pack("V3", 54 + $size_quad + $size_data, 0, 54 + $size_quad);

        // 位图信息头
        $info_header = pack("V3v2V*", 0x28, $width, $height, 1, $bit, $compression, $size_data, 0, 0, $colors_num, 0);

        // 写入文件
        if ($filename != '') {
            $fp = fopen($filename, "wb");
            fwrite($fp, $file_header);
            fwrite($fp, $info_header);
            if ($rgb_quad !== '')
                fwrite($fp, $rgb_quad);
            fwrite($fp, $bmp_data);
            fclose($fp);
            return true;
        }

        // // 浏览器输出
        // header("Content-Type: image/bmp");
        // echo $file_header . $info_header;
        // echo $rgb_quad;
        // echo $bmp_data;

    }
//调用方法
createBmpImage("张三疯");//如果有指定的字体库 对应传入即可 但不是所有的字体都适用
  1. 取模方法
//这里把方法单独写在了一个类里 使用的时候直接调用即可
<?php
namespace app\common\service;
class BmpDelivery
{

    /**
     * @param $targetFile
     * @param $horizontal
     * @param $leftToRight
     * @param $topToBottom
     * @param $highBitFirst
     * @param $pixelReverse
     * @return mixed
     */
    public function getData($targetFile,$horizontal=false,$leftToRight=true,$topToBottom=true,$highBitFirst=false,$pixelReverse=true){
        // 示例使用
        $modOptions = [
            // 可以在这里根据需要调整取模参数
            'horizontal' =>$horizontal, // 横向取模
            'leftToRight' =>$leftToRight, // 从左到右
            'topToBottom' => $topToBottom, // 从上到下
            'highBitFirst' => $highBitFirst, // 高位在前
            'invertPixel' => $pixelReverse, // 像素数据不反转
        ];
        return $this->imageToBitmap($targetFile, $modOptions);
    }

    protected function imageToBitmap($imagePath, $options = []) {
        // 设置默认取模参数
        $defaults = [
            'horizontal' => true, // 横向取模
            'leftToRight' => true, // 从左到右
            'topToBottom' => true, // 从上到下
            'highBitFirst' => true, // 高位在前
            'invertPixel' => false, // 像素数据不反转
        ];
        $settings = array_merge($defaults, $options);


        //	// php5.6
        //	//按顺序点阵数据
        //	$pixels = $this->readMonochromeBmpPixels($imagePath);
        //	$hexString = "char Msk[] = {\n";
        //	// 输出像素值
        //	foreach ($pixels as $row) {
        //		foreach ($row as $pixel) {
        //			$hexString.= $pixel;
        //		}
        //		$hexString.= "\n"; // 换行,用于分隔图像的每一行
        //	}
        //	return $hexString;


        $pixels = $this->readMonochromeBmpPixels($imagePath);
        // 输出像素值
        $bitmapData = [];
        if ($settings['horizontal']) {
            foreach ($pixels as $row) {
                for ($x = 0; $x < sizeof($row); $x += 8) {
                    $byte = 0;
                    for ($bit = 0; $bit < 8; $bit++) {
                        if ($x + $bit < $row) {
                            $bitValue = $row[$x + $bit];
                            if ($settings['invertPixel']) {
                                $bitValue = $bitValue ? 0 : 1; // 反转像素数据
                            }
                            if ($settings['highBitFirst']) {
                                $byte |= ($bitValue << (7 - $bit));
                            } else {
                                $byte |= ($bitValue << $bit);
                            }
                        }
                    }
                    $bitmapData[] = $byte;
                }
                //echo "\n"; // 换行,用于分隔图像的每一行
            }
        }
        else // 数据排列:3纵向从左到右从上到下
        {
            //echo "col len=".count($pixels[0])."row len=".count($pixels);
            for ($y = 0; $y < count($pixels); $y += 8) { //16
                for($x=0;$x<count($pixels[0]);$x++) { //行长8
                    $byte = 0;
                    for ($bit = 0; $bit < 8; $bit++) {
                        //echo "x=".$x."y=".($y + $bit);
                        if ($y + $bit < count($pixels)) {
                            $bitValue = $pixels[ $y + $bit][$x];

                            if ($settings['invertPixel']) {
                                $bitValue = $bitValue ? 0 : 1; // 反转像素数据
                            }
                            if ($settings['highBitFirst']) {
                                $byte |= ($bitValue << (7 - $bit));
                            } else {
                                $byte |= ($bitValue << $bit);
                            }
                        }
                    }
                    $bitmapData[] = $byte;
                }
                //echo "\n"; // 换行,用于分隔图像的每一行
            }
        }
        // else
        // {
        // //echo "col len=".count($pixels[0])."row len=".count($pixels);
        // for($x=0;$x<count($pixels[0]);$x++) { //行长8
        // for ($y = 0; $y < count($pixels); $y += 8) { //16
        // $byte = 0;
        // for ($bit = 0; $bit < 8; $bit++) {
        // //echo "x=".$x."y=".($y + $bit);
        // if ($y + $bit < count($pixels)) {
        // $bitValue = $pixels[ $y + $bit][$x];

        // if ($settings['invertPixel']) {
        // $bitValue = $bitValue ? 0 : 1; // 反转像素数据
        // }
        // if ($settings['highBitFirst']) {
        // $byte |= ($bitValue << (7 - $bit));
        // } else {
        // $byte |= ($bitValue << $bit);
        // }
        // }
        // }
        // $bitmapData[] = $byte;
        // }
        // //echo "\n"; // 换行,用于分隔图像的每一行
        // }
        // }






        php7.2及以上
         读取图片并转换为灰度图像
        //$img = imagecreatefrombmp($imagePath);
        //$width = imagesx($img);
        //$height = imagesy($img);
        //
        //$bitmapData = [];
        //for ($y = 0; $y < $height; $y++) {
        //    for ($x = 0; $x < $width; $x += 8) {
        //        $byte = 0;
        //        for ($bit = 0; $bit < 8; $bit++) {
        //            if ($x + $bit < $width) {
        //                $color = imagecolorat($img, $x + $bit, $y);
        //                $gray = ($color >> 16) & 0xFF; // 取红色通道作为灰度值
        //                $bitValue = $gray < 128 ? 1 : 0; // 简化处理:亮度低于50%视为黑色
        //                if ($settings['invertPixel']) {
        //                    $bitValue = $bitValue ? 0 : 1; // 反转像素数据
        //                }
        //                if ($settings['highBitFirst']) {
        //                    $byte |= ($bitValue << (7 - $bit));
        //                } else {
        //                    $byte |= ($bitValue << $bit);
        //                }
        //            }
        //        }
        //        $bitmapData[] = $byte;
        //    }
        //}
        // 生成16进制格式的字符串
        $hexString = '';
        $string='';
        $strArr = [];
        foreach ($bitmapData as $index => $byte) {

            $string .= sprintf("%02X", $byte);
            $hexString .= sprintf("0x%02X", $byte);
            if ($index < count($bitmapData) - 1) {
                $string .= "";
                $hexString .= ",";
            }
        }
        $strArr['string']= $string;
        $strArr['hexString']= $hexString;
        return $strArr;
    }


   protected function readMonochromeBmpPixels($filePath) {
        $file = fopen($filePath, 'rb');
        if (!$file) {
            die("Cannot open file.");
        }

        // 跳过文件头和信息头
        fseek($file, 10); // BMP 点阵数据的位置
        $dataPosition = unpack('V', fread($file, 4))[1];
        // 读取图像宽度和高度
        fseek($file, 18); // 宽度位于文件的18字节处
        $width = unpack('V', fread($file, 4))[1];
        $height = unpack('V', fread($file, 4))[1];


        // 计算实际每行的字节数,考虑到行必须以4字节为单位对齐
        $rowSize = ceil($width / 8);
        $paddedRowSize = (ceil($rowSize / 4) * 4);
        $pixelArray = [];

        // 回到像素数据的开始位置
        //fseek($file, 54);

        for ($y = 0; $y < $height; $y++) {
            // 回到像素数据的开始位置
            fseek($file, $dataPosition + ($height-1-$y)*$paddedRowSize);//倒序
            $row = fread($file, $paddedRowSize);
            //for ($d = 0; $d < $width/8; $d++)
            //{
            //echo ord($row[$d]);
            //}
            //echo "/n";
            for ($x = 0; $x < $width; $x++) {
                $byteIndex = (int)($x / 8);
                $bitIndex = 7 - ($x % 8);
                $byteValue = ord($row[$byteIndex]);
                $bitValue = ($byteValue >> $bitIndex) & 1;
                // 输出像素值,0为白色,1为黑色
                $pixelArray[$y][$x] = ($bitValue?0:1);
            }
        }

        fclose($file);
        return $pixelArray;
    }





}
  1. 把存在服务器的图片地址拿到以后进行取模

  $imagesData= new BmpDelivery();

 $data=$imagesData->getData($imageArr['root_url']);

//会返回一个数组 取模结果是512个字节
array(2) {
  ["string"] => string(1024) "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090121C10F0101000F00000FE00000000F8888888F88A8C0888F88888880000040404040404C44424140C040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000804020130C33C00000001F8000FF000080601F201806FF0428100CFF0418200001010101018101FF0101010101010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000010000000001000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  ["hexString"] => string(2559) "0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x50,0x90,0x12,0x1C,0x10,0xF0,0x10,0x10,0x00,0xF0,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0xF8,0x88,0x88,0x88,0xF8,0x8A,0x8C,0x08,0x88,0xF8,0x88,0x88,0x88,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0xC4,0x44,0x24,0x14,0x0C,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x13,0x0C,0x33,0xC0,0x00,0x00,0x00,0x1F,0x80,0x00,0xFF,0x00,0x00,0x80,0x60,0x1F,0x20,0x18,0x06,0xFF,0x04,0x28,0x10,0x0C,0xFF,0x04,0x18,0x20,0x00,0x01,0x01,0x01,0x01,0x01,0x81,0x01,0xFF,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值