php使用gd绘制小票单面单

<?php

namespace Libraries\common;

use Picqer\Barcode\BarcodeGeneratorPNG;

/**
 * 生成面单图片
composer require picqer/php-barcode-generator
 * ! 使用:
$make_img = new MakeImg();
$make_img->drawCenteredText(80, "淘宝面单", 20, $make_img->getBlackColor());
// 绘制第一个条形码
// $generator = new BarcodeGeneratorPNG();
$code = 'SF0000';
$make_img->drawBarcode(20, $code);
$make_img->drawCenteredText(25, $code, 14, $make_img->getBlackColor());
$make_img->drawCenteredText(60, '该面单请联系快递员打印', 32, $make_img->getBlackColor());
$make_img->drawAlignedRow(40, "需求鉴别单号:", "1212121", 16, $make_img->getBlackColor());
$make_img->drawAlignedRow(46, "需求鉴别单号:", "1212121", 16, $make_img->getBlackColor());
$make_img->drawWrappedText(40, '1212121', 16, $make_img->getBlackColor(), 40);
$res = $make_img->getImg();
file_put_contents(BASE_PATH . '/1.html', '<img style="display: inline-block;" src="' . $res . '"/>');
 * @author lxx
 */
class MakeImg
{
    private $config = [
        'image_width' => (76 - 0) * 8,// 1mm≈8px
        'image_height' => (130 - 0) * 8,// 1mm≈8px
        'padding' => 130,
        'font' =>  BASE_PATH . '/public/simsun.ttf'
    ];
    private $image = null;
    private $y = 0; // 距离顶部的总距离, 每次设置
    public function __construct($_config = [])
    {
        $this->config = array_merge($this->config, $_config);
        $this->image = imagecreatetruecolor($this->config['image_width'], $this->config['image_height']);
        // 背景
        imagefill($this->image, 0, 0, $this->getWhiteColor());
    }
    /**
     * 每次设置y的值更新总的y顶部距离
     *
     * @param int $_y
     * @return int 总的y顶部距离
     * @author lxx
     */
    public function addY($_y)
    {
        $this->y = $this->y + $_y;
        return $this->y;
    }
    /**
     * 黑色
     *
     * @return int
     * @author lxx
     */
    public function getBlackColor()
    {
        return imagecolorallocate($this->image, 0, 0, 0);
    }
    /**
     * 白色
     *
     * @return int
     * @author lxx
     */
    public function getWhiteColor()
    {
        return imagecolorallocate($this->image, 255, 255, 255);
    }
    /**
     * 获取生成的图片
     *
     * @param resource $im imagecreatetruecolor 数据
     * @param bool $get_base64 是否获取base64字符串
     * @return string|resource base64字符串或者图片资源
     * @author lxx
     */
    public function getImg($get_base64 = true)
    {
        ob_start();
        imagepng($this->image);
        $imageData = ob_get_contents();  // 获取图像数据
        ob_end_clean();  // 关闭并清空输出缓冲区
        // 将图像数据转换为 BASE64
        $base64 = base64_encode($imageData);
        // 清理资源
        imagedestroy($this->image);
        if ($get_base64) {
            return 'data:image/png;base64,' . $base64;
        } else {
            return $imageData;
        }
    }
    // 添加文本换行函数
    public function wrapText($text, $font_size, $max_width)
    {
        $lines = [];
        $current_line = '';
        foreach (preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY) as $char) {
            $testline = $current_line . $char;
            $bbox = imagettfbbox($font_size, 0, $this->config['font'], $testline);
            $text_width = $bbox[2] - $bbox[0];
            if ($text_width > $max_width) {
                $lines[] = $current_line;
                $current_line = $char;
            } else {
                $current_line .= $char;
            }
        }

        if ($current_line !== '') {
            $lines[] = $current_line;
        }

        return $lines;
    }

    // 修改绘制对齐行的函数,支持长文本换行
    public function drawAlignedRow($padding_top, $label, $content, $size, $color, $padding_lr = 40)
    {
        $this->addY($padding_top);
        $y = $this->y;
        $image_width = $this->config['image_width'];
        // ! 计算内容最大宽度(图片宽度的60%)
        $content_max_width = ($image_width - (3 * $padding_lr)) * 0.6;

        // 绘制左对齐的标签
        imagettftext($this->image, $size, 0, $padding_lr, $y, $color, $this->config['font'], $label);

        // 如果内容需要换行
        $bbox = imagettfbbox($size, 0, $this->config['font'], $content);
        $text_width = $bbox[2] - $bbox[0];

        if ($text_width > $content_max_width) {
            // 换行处理
            $lines = $this->wrapText($content, $size, $content_max_width);
            foreach ($lines as $index => $line) {
                // var_dump($size);
                $bbox = imagettfbbox($size, 0, $this->config['font'], $line);
                $line_width = $bbox[2] - $bbox[0];
                $x = $image_width - $line_width - $padding_lr;
                imagettftext($this->image, $size, 0, $x, $y + ($index * ($size + 5)), $color, $this->config['font'], $line);
            }
            // 返回最后一行的Y坐标
            return $y + (count($lines) - 1) * ($size + 5);
        } else {
            // 单行处理,右边靠
            $x = $image_width - $text_width - $padding_lr;
            imagettftext($this->image, $size, 0, $x, $y, $color, $this->config['font'], $content);
            return $y;
        }
    }

    // 修改普通文本绘制函数,支持换行
    public function drawWrappedText($padding_top, $text, $size, $color, $padding_lr)
    {
        $y = $this->addY($padding_top);
        $image_width = $this->config['image_width'];
        $max_width = $image_width - (2 * $padding_lr);
        $lines = $this->wrapText($text, $size, $max_width);

        foreach ($lines as $index => $line) {
            imagettftext($this->image, $size, 0, $padding_lr, $y + ($index * ($size + 10)), $color, $this->config['font'], $line);
        }

        $this->addY($y + (count($lines) - 1) * ($size + 5));
    }

    // 绘制居中文本
    public function drawCenteredText($padding_top, $text, $size, $color)
    {
        $y = $this->addY($padding_top);
        $bbox = imagettfbbox($size, 0, $this->config['font'], $text);
        $text_width = $bbox[2] - $bbox[0];
        $x = (int)(($this->config['image_width'] - $text_width) / 2);
        imagettftext($this->image, $size, 0, $x, $y, $color, $this->config['font'], $text);
    }

    // 绘制条形码
    public function drawBarcode($padding_top, $code, $height = 120, $code_one_width = 3)
    {
        $y = $this->addY($padding_top);
        // 生成条形码
        $generator = new BarcodeGeneratorPNG();
        $barcode = $generator->getBarcode($code, $generator::TYPE_CODE_128, $code_one_width, $height);
        $barcodeWidth = imagesx(imagecreatefromstring($barcode));
        $barcodeHeight = imagesy(imagecreatefromstring($barcode));
        $barcode_img = imagecreatefromstring($barcode);
        // 合并图层
        if ($this->config['image_width'] - $barcodeWidth < 0) {
            throw new \Exception('条形码内容太长了!');
        }
        $x = ($this->config['image_width'] - $barcodeWidth) / 2;
        imagecopy($this->image, $barcode_img, intval($x), $y, 0, 0, $barcodeWidth, $barcodeHeight);
        imagedestroy($barcode_img);
        $this->addY($height);
    }
}