您的当前位置:首页>全部文章>文章详情

php生成海报

发表于:2024-04-16 14:12:12浏览:163次TAG: #PHP #海报 #画图 #画布

前言

本文将详细介绍如何使用php生成海报,并提供整理的源码和通过示例代码进行说明。

一、了解画布坐标

画布坐标是以“最左上角”开始作为坐标的起点。要在画布上面哪个添加图片、文字等都是通过坐标来定位。
我们把每个要添加的文字或图片称为元素,每个元素的“最左上角”为坐标开始的点。

图片alt

开始编码

<?php

namespace app\common\utils;
/**
 * 生成海报
 * 需安装扩展:exif
 */
class Poster
{
    protected $bg;
    protected $font;
    protected $images = [];
    public function __construct($options = [])
    {
        $this->font = $options['font'] ?? ROOT_PATH . 'public' . DS . 'assets'. DS .'fonts'. DS . 'SourceHanSansOLD-Light-2.otf';
    }

    /**
     * 设置背景图
     * @param $path
     * @return $this
     */
    public function setBg($path)
    {
        $this->bg = $this->createImage($path);
        return $this;
    }

    /**
     * 渲染文字
     * @param $text
     * @param $x
     * @param $y
     * @param $rgb
     * @param $size
     * @return $this
     */
    public function setText($text,$x,$y,$rgb = '0,0,0',$size = 18)
    {
        $rgb = explode(',',$rgb);
        $color = imagecolorallocate($this->bg, $rgb[0],$rgb[1],$rgb[2]);
        imagettftext($this->bg, $size, 0, $x, $y, $color, $this->font, $text);
        return $this;
    }

    /**
     * 渲染图片
     * @param $path
     * @param $x
     * @param $y
     * @param $width
     * @param $height
     * @return $this
     */
    public function setImage($path,$x,$y,$width = null,$height = null)
    {
        $image = $this->createImage($path);
        $image = $this->notRotate($image,$path);
        if (!is_null($width) && !is_null($height)) {
            $image = $this->editSize($image,$width,$height);
        }
        else {
            $width  = imagesx($image);
            $height = imagesy($image);
        }
        imagecopy($this->bg, $image, $x, $y, 0, 0, $width, $height);
        array_push($this->images,$image);
        return $this;
    }

    /**
     * 生成
     * @param $savename
     * @return void
     */
    public function build($savename = null)
    {
        $image = $this->getBg();
        if (is_null($savename)) {
            $savename = 'poster.png';
            // 禁用PHP输出缓冲
            ob_end_clean();
            // 发送合适的头部信息
            header('Content-Type: image/png');
            header('Content-Disposition: inline; filename="'.$savename.'"');
            $suffix = $this->getSuffix($savename);
            $savename = null;
        }
        else {
            $suffix = $this->getSuffix($savename);
        }
        switch ($suffix){
            case 'png':
                imagepng($image,$savename);
                break;
            case 'jpg':
            case 'jpeg':
                imagejpeg($image,$savename);
                break;
            case 'webp':
                imagewebp($image,$savename);
                break;
            case 'gif':
                imagegif($image,$savename);
                break;
            case 'bmp':
                imagebmp($image,$savename);
                break;
        }
        $this->destroy();
    }

    /**
     * 获取后缀
     * @param $str
     * @return string
     */
    private function getSuffix($str)
    {
        return strtolower(substr(strrchr($str,'.'),1));
    }
    /**
     * 获取背景图
     * @return mixed
     */
    private function getBg()
    {
        return $this->bg;
    }

    /**
     * 修改图片尺寸
     * @param $image
     * @param int $new_width
     * @param int $new_height
     * @return false|\GdImage|resource
     */
    private function editSize($image,int $new_width,int $new_height)
    {
        // 获取原始尺寸
        $width  = imagesx($image);
        $height = imagesy($image);
        // 创建目标图片
        $new_image = imagecreatetruecolor($new_width, $new_height);
        // 调整图片分辨率
        imagecopyresampled(
            $new_image,
            $image,
            0,
            0,
            0,
            0,
            $new_width,
            $new_height,
            $width,
            $height
        );
        return $new_image;
    }

    /**
     * 旋转回正
     * EXIF 信息只在 JPG 、 TIFF 等类型的图片格式中存在,所以 PNG 图片是无法获取到 EXIF 信息的。
     * 如果对 PNG 图片使用 exif_read_data() 就会报出警告。而对于 JPG 来说,就会返回完整的全部的 EXIF 内容。
     * @param $image
     * @param $image_path
     * @return false|\GdImage|mixed|resource
     */
    private function notRotate($image,$image_path)
    {
        if (!in_array($this->getSuffix($image_path),['jpg','jpeg'])) {
            return $image;
        }
        $exif = exif_read_data($image_path);
        if(!empty($exif['Orientation'])) {
            switch($exif['Orientation']) {
                case 8: // 水平翻转
                    $image = imagerotate($image, 90, 0);
                    break;
                case 3: // 180度旋转
                    $image = imagerotate($image, 180, 0);
                    break;
                case 6: // 垂直翻转
                    $image = imagerotate($image, -90, 0);
                    break;
            }
        }
        return $image;
    }
    /**
     * 创建图片对象
     * @param $image_path
     * @return false|\GdImage|resource
     */
    private function createImage($image_path)
    {
        $suffix = pathinfo($image_path,PATHINFO_EXTENSION);
        switch ($suffix){
            case 'png':
                $image = imagecreatefrompng($image_path);
                break;
            case 'jpg':
            case 'jpeg':
                $image = imagecreatefromjpeg($image_path);
                break;
            case 'webp':
                $image = imagecreatefromwebp($image_path);
                break;
            case 'gif':
                $image = imagecreatefromgif($image_path);
                break;
            case 'bmp':
                $image = imagecreatefrombmp($image_path);
                break;
        }
        return $image;
    }

    /**
     * 销毁资源/释放内存
     * @return void
     */
    private function destroy()
    {
        $images = $this->images;
        if ($images) {
            foreach ($images as $image) {
                imagedestroy($image);
            }
        }
    }
}
// 调用
$ps = new \app\common\utils\Poster();
$ps->setBg(ROOT_PATH . 'public' . DS . 'assets'. DS. 'img'. DS . 'cert-bg.png')
   ->setText('你好:李四',600,303,'255,90,90')
   ->setImage(ROOT_PATH . 'public' . DS . 'assets'. DS. 'img'. DS . 'signet1.png',760,420)
   ->setImage(ROOT_PATH . 'public' . DS . 'assets'. DS. 'img'. DS . 'signet2.png',500,420)
   ->build(ROOT_PATH . 'public' . DS . 'poster_test.png');