php实现一个分享海报,本类是生成背景透明的png模式,支持多张商品图片

可以用于商品分享、代理分享、海报宣传等,这个版本是生成png透明背景的,生成白色背景的在文末。

效果:

aa.png

<?php

class PosterPng
{
    //图片质量,0~9
    private $quality = 9;
    //字体路径
    //private static $font_path = 'C:/Windows/Fonts/simfang.ttf';
    private $font_path = '';
    //背景图片
    private $backgroud_img = '';
    //二维码/水印图片
    private $code_img = '';

    public function __construct($config = [])
    {
        if (!empty($config['font_path'])) {
            $this->font_path = $config['font_path'];
        }
        if (!empty($config['backgroud_img'])) {
            $this->backgroud_img = $config['backgroud_img'];
        }
        if (!empty($config['code_img'])) {
            $this->code_img = $config['code_img'];
        }
    }

    /**
     * 开始制作
     * 一个原则:在某张背景图上面添加图片、文字等
     * @param $data
     * @return mixed
     */
    public function start($data)
    {
        if (!empty($data['quality'])) {
            $this->quality = $data['quality'];
        }
        if (!empty($data['qrcode'])) {
            $this->code_img = $data['qrcode'];
        }
        if (!empty($data['bg_img'])) {
            $this->backgroud_img = $data['bg_img'];
        }
        //输入文件的路径和名称
        $output_file = $data['output_file'];
        //商品图片
        $goods_img = $data['goods_img'];

        if (empty($this->backgroud_img)) {
            $bgH = 700;
            $bgW = 375;
            $image = imagecreatetruecolor($bgW, $bgH);
            $transparent = imagecolorallocatealpha($image, 0, 0, 0, 127); // 创建透明颜色
            imagealphablending($image, false); // 关闭混合模式
            imagesavealpha($image, true); // 保存透明通道
            imagefill($image, 0, 0, $transparent);
            imagepng($image, $output_file); // 保存为 PNG 格式,以保留透明通道
            imagedestroy($image);
            $this->backgroud_img = $output_file;
            // 添加二维码
            $this->addPic($this->backgroud_img, $this->code_img, 100, 100, 275, 400, $output_file);
            // 添加文字描述
            $this->addWord('长按识别', 280, 522, 16, 'grey1', $output_file);
        }

        // 添加产品
        $this->addPic($this->backgroud_img, $goods_img, 375, 400, 0, 0, $output_file);
        // 添加产品描述,对描述进行分行
        $theTitle = $this->cn_row_substr($data['title'], 2, 11);

        //左右距离
        $this->addWord($theTitle[1], 10, 425, 16, 'black', $output_file);


        $this->addWord($theTitle[2], 10, 450, 16, 'black', $output_file);
        // 文字1
        $this->addWord('原价' . $data['price_member'], 20, 480, 16, 'black', $output_file);
        // 文字2
        $this->addWord('————', 65, 480, 16, 'red', $output_file);
        $this->addWord('————', 65, 481, 16, 'red', $output_file);
        $this->addWord('————', 65, 482, 16, 'red', $output_file);
        // 文字3
        $this->addWord('现价' . $data['price_market'], 20, 510, 18, 'red', $output_file);

        //商品小图 todo 动态化来自$data 数组
        if (!empty($data['imgs'])) {
            $w = $h = 100;//小图宽高
            $dst_y = 538;//距离海报顶部的距离
            $margin_left = 20;//左边距
            foreach ($data['imgs'] as $k => $thumb) {
                //计算x轴坐标
                if ($k == 0) {
                    $dst_x = $margin_left;
                } else {
                    $dst_x = ($k + 1) * $margin_left + $w * $k;
                }

                //只取3张
                if ($k >= 3) {
                    break;
                }
                //添加小图
                $this->addPic($output_file, $thumb, $w, $h, $dst_x, $dst_y, $output_file);
            }
        }

        // 文字3
        $this->addWord('一个有血性的程序猿520单身快乐', 10, 670, 16, 'black', $output_file);

        return $output_file;
    }


    /**
     * 添加图片
     * @param $path_base string    原图
     * @param $path_logo  string   添加图
     * @param $imgWidth  int   添加图宽
     * @param $imgHeight  int   添加图高
     * @param $dst_x    int     在原图宽x处添加
     * @param $dst_y     int    在原图高y处添加
     * @param $output_file    string         生成图
     * return resource    返回图片image资源
     */
    private function addPic($path_base, $path_logo, $imgWidth, $imgHeight, $dst_x, $dst_y, $output_file)
    {
        if (empty($path_logo)) {
            exit('图片不存在:' . $path_logo);
        } elseif (empty($path_base)) {
            exit('背景图不存在:' . $path_base);
        }

        $image_base = $this->ImgInfo($path_base);
        $image_logo = $this->ImgInfo($path_logo);

        //重采样拷贝部分图像并调整大小
        imagecopyresampled($image_base, $image_logo, $dst_x, $dst_y, 0, 0, $imgWidth, $imgHeight, imagesx($image_logo), imagesy($image_logo));

        $bgWidth = imagesx($image_base);
        $bgHeight = imagesy($image_base);

        $merged_image = imagecreatetruecolor($bgWidth, $bgHeight);
        $transparent = imagecolorallocatealpha($merged_image, 0, 0, 0, 127); // 创建透明颜色
        imagealphablending($merged_image, false); // 关闭混合模式
        imagesavealpha($merged_image, true); // 保存透明通道
        imagefill($merged_image, 0, 0, $transparent);

        imagecopyresampled($merged_image, $image_base, 0, 0, 0, 0, $bgWidth, $bgHeight, $bgWidth, $bgHeight);
        imagecopyresampled($merged_image, $image_logo, $dst_x, $dst_y, 0, 0, $imgWidth, $imgHeight, imagesx($image_logo), imagesy($image_logo));

        // 生成一个合并后的新图
        imagepng($merged_image, $output_file); // 保存为 PNG 格式,以保留透明通道
        imagedestroy($merged_image);

    }


    /**
     * 从图片文件创建Image资源
     * @param $img string 图片文件,支持url
     * @return bool|resource    成功返回图片image资源,失败返回false
     */
    private function ImgInfo($img)
    {

        if (is_resource($img)) {
            return $img;
        } elseif (preg_match('/http(s)?:\/\//', $img)) {
            $fileSuffix = $this->getNetworkImgType($img);
        } else {
            $fileSuffix = pathinfo($img, PATHINFO_EXTENSION);

        }

        if (!$fileSuffix) {
            return false;
        }


        switch ($fileSuffix) {
            case 'jpeg':
            case 'jpg':
                $theImage = @imagecreatefromjpeg($img);
                break;
            case 'png':
                $theImage = imagecreatefromstring(file_get_contents($img));
                //imagecreatefrompng($img);
                break;
            case 'gif':
                $theImage = @imagecreatefromgif($img);
                break;
            default:
                $theImage = @imagecreatefromstring(file_get_contents($img));
                break;
        }
        return $theImage;
    }

    /**
     * 获取网络图片类型
     * @param $url string 网络图片url,支持不带后缀名url
     * @return bool
     */
    private function getNetworkImgType($url)
    {
        $ch = curl_init(); //初始化curl
        curl_setopt($ch, CURLOPT_URL, $url); //设置需要获取的URL
        curl_setopt($ch, CURLOPT_NOBODY, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);//设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, 3);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //支持https
        curl_exec($ch);//执行curl会话
        $http_code = curl_getinfo($ch);//获取curl连接资源句柄信息
        curl_close($ch);//关闭资源连接

        if ($http_code['http_code'] == 200) {
            $theImgType = explode('/', $http_code['content_type']);

            if ($theImgType[0] == 'image') {
                return $theImgType[1];
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 分行连续截取字符串
     * @param $str string  需要截取的字符串,UTF-8
     * @param int $row 截取的行数
     * @param int $number 每行截取的字数,中文长度
     * @param bool $suffix 最后行是否添加‘...’后缀
     * @return array    返回数组共$row个元素,下标1到$row
     */
    private function cn_row_substr($str, $row = 1, $number = 10, $suffix = true)
    {
        $result = array();
        for ($r = 1; $r <= $row; $r++) {
            $result[$r] = '';
        }

        $str = trim($str);
        if (!$str) return $result;

        $theStrlen = strlen($str);

        //每行实际字节长度
        $oneRowNum = $number * 3;
        for ($r = 1; $r <= $row; $r++) {
            if ($r == $row and $theStrlen > $r * $oneRowNum and $suffix) {
                $result[$r] = $this->mg_cn_substr($str, $oneRowNum - 6, ($r - 1) * $oneRowNum) . '...';
            } else {
                $result[$r] = $this->mg_cn_substr($str, $oneRowNum, ($r - 1) * $oneRowNum);
            }
            if ($theStrlen < $r * $oneRowNum) break;
        }

        return $result;
    }

    /**
     * 按字节截取utf-8字符串
     * 识别汉字全角符号,全角中文3个字节,半角英文1个字节
     * @param $str string  需要切取的字符串
     * @param $len int  截取长度[字节]
     * @param int $start 截取开始位置,默认0
     * @return string
     */
    private function mg_cn_substr($str, $len, $start = 0)
    {
        $q_str = '';
        $q_strlen = ($start + $len) > strlen($str) ? strlen($str) : ($start + $len);

        //如果start不为起始位置,若起始位置为乱码就按照UTF-8编码获取新start
        if ($start and json_encode(substr($str, $start, 1)) === false) {
            for ($a = 0; $a < 3; $a++) {
                $new_start = $start + $a;
                $m_str = substr($str, $new_start, 3);
                if (json_encode($m_str) !== false) {
                    $start = $new_start;
                    break;
                }
            }
        }

        //切取内容
        for ($i = $start; $i < $q_strlen; $i++) {
            //ord()函数取得substr()的第一个字符的ASCII码,如果大于0xa0的话则是中文字符
            if (ord(substr($str, $i, 1)) > 0xa0) {
                $q_str .= substr($str, $i, 3);
                $i += 2;
            } else {
                $q_str .= substr($str, $i, 1);
            }
        }
        return $q_str;
    }


    /**
     * @param string $str 文字
     * @param float 位置x,左上角为0
     * @param float $poxY 位置y,左上角为0
     * @param int $font 字体大小
     * @param string $color 自定义颜色,可以自行扩展
     * @param string $output_file 输出文件
     * @param int $tilt 角度制表示的角度,0 度为从左向右读的文本。更高数值表示逆时针旋转。例如 90 度表示从下向上读的文本
     */
    private function addWord($str, $posX, $poxY, $font, $color, $output_file, $tilt = 0)
    {
        $ori_img = $output_file;    //原图
        $new_img = $output_file;    //生成水印后的图片

        $s_original = $this->ImgInfo($ori_img);

        imagealphablending($s_original, false); // 关闭混合模式
        imagesavealpha($s_original, true); // 保存透明通道


        $ImgColor = [
            //为一幅图像分配颜色
            'black' => imagecolorallocate($s_original, 0, 0, 0),
            'red' => imagecolorallocate($s_original, 255, 0, 0),
            'grey1' => imagecolorallocate($s_original, 31, 31, 18),
        ];

        imagettftext($s_original, $font, $tilt, $posX, $poxY, $ImgColor[$color], $this->font_path, $str);

        imagepng($s_original, $new_img, $this->quality);
        imagedestroy($s_original);
    }


}

调用实例;

<?php
//引入类库
require("PosterPng.php");

//定义入参
$img = 'abc.png';
$data = [
    'title' => '一个不算长得不算太丑有信仰的代码写手...',
    'price_market' => '¥0.99',
    'price_member' => '¥99.99',
    'goods_img' => 'https://store.mp.video.tencent-cloud.com/161/20304/snscosdownload/SH/reserved/6066d1500000815100000000b61f9d09000000a000004f50',
    'output_file' => __DIR__ . '/'.$img,
    'quality' => 9,
    'qrcode' => __DIR__ . '/qr.png',
    //'bg_img' => __DIR__.'/bg1.png',
    'imgs' => [
        __DIR__ . '/goods.jpeg',
        __DIR__ . '/goods.jpeg',
        __DIR__ . '/goods.jpeg',
    ]

];
//注意哈
$set = [
    'font_path' => __DIR__ . '/simkai.ttf',

];
$poster = new PosterPng($set);
$newImg = $poster->start($data);
echo "<img style='width: 100%' src='{$img}' />";


生成白色背景的教程:php生成海报优化版,php生成商品海报分享图,php用GD扩展制作海报

评论/留言