项目需求是这样的:用户签订合同,并读取用户信息生成合同,将合同保存为png图片保存
环境:windows(2012,linux要配置java环境,偷懒)+ apache(2.4.48) + php(7.1) + mysql(5.5.62)
框架:tp5.0.24,网站目录在public下面,环境直接用宝塔塔建的,phpenv 本地测试了也可以,其他的没有测试
第一步:向word写入用户信息
1. 将 PhpOffice 整个文件夹复制到 extend 文件夹下(如下图)
2. 接下来就是代码了,直接上:
// 文字写入world
public function word_write()
{
import('PhpOffice\PhpWord\TemplateProcessor', '.php');
// 1.创建模板对象
$temp_path = $_SERVER['DOCUMENT_ROOT'] . '/xieyi_fuwu_copy.docx'; // 模板文件路径
$document = new \PhpOffice\PhpWord\TemplateProcessor($temp_path);
// 2.插入数据 : word中的变量 ${name} ${idcard} ${phone} {$time}
$data = [
['key' => 'name', 'value' => '小度哇'],
['key' => 'idcard', 'value' => '341022188810222345'],
['key' => 'phone', 'value' => '18888888888'],
['key' => 'time', 'value' => date('Y年m月d日')],
];
foreach ($data as $k => $v) {
$document->setValue($v['key'], $v['value']);
}
// 3.保存文件
$file_path = $_SERVER['DOCUMENT_ROOT'] . '/file/' . date('Ymd');
if (!file_exists($file_path)) {
mkdir($file_path, '0777');
}
$document->saveAs($file_path.'/'.time().'.docx');
}
第二步:world 转为 pdf
-
修改php.ini
添加:extension=php_com_dotnet.dll
去除注释:com.allow_dcom = true
重启php环境 -
安装office,一定要安装office,(office 2007 需要手动安装
Microsoft Save as PDF and XPS
)【https://files-cdn.cnblogs.com/files/XiaoMingBlingBling/SaveAsPDFandXPS.rar】 -
配置office组件服务:win+R打开运行菜单,输入dcomcnfg
找到 [组件服务] — [计算机]— [我的电脑] — [DCOM配置] — [Microsoft Wrord 97-2003文档]
右键 [Microsoft Wrord 97-2003文档] 设置属性 [标识] 为 [交互式用户] -
可以写代码了
// world 转为 pdf
function index3()
{
$filenamedoc = $_SERVER['DOCUMENT_ROOT'] . '/xieyi_fuwu_copy.docx'; // word 文件地址
$filenamepdf = $_SERVER['DOCUMENT_ROOT'] . '/xieyi_fuwu_copy.pdf'; // 生成的 PDF 文件保存地址
if (!file_exists($filenamedoc )) {
return 'word原文件不存在';
}
// 删除已有同名文件
if (file_exists($filenamepdf)) {
unlink($filenamepdf);
}
// 执行转换操作
$word = new \COM("word.Application") or die("Could not initialise Object");
$word->Documents->Open($filenamedoc);
$word->ActiveDocument->ExportAsFixedFormat($filenamepdf, 17, false, 0, 0, 0, 0, 7, true, true, 2, true, true, false);
$word->Quit(false);
unset($word);
return '转换成功';
}
第三步:PDF 转为图片
-
安装 ImageMagic 扩展,可以参考:https://www.cnblogs.com/jinxiblog/p/8053008.html,这个链接里面写的,我的就是按照这个来的,宝塔的话就不需要了,直接在 [软件管理]—[php7.1]—[安装扩展] 找到imagemagick,直接安装就可以了,如下图
-
安装 ghostscript.exe (ghostscript.exe安装好之后需要添加到环境变量里面,并且将 gs9.54.0\bin\gswin64.exe 复制一份修改为gs.exe),我的上篇文章里面有提到过 ghostscript.exe 的坑,采坑的可以参考下
-
上代码
// pdf 转为图片
public function index4()
{
$from_path = $outPath = $_SERVER['DOCUMENT_ROOT'] . '/xieyi_fuwu_copy.pdf'; // PDF文件位置
$target_path = $_SERVER['DOCUMENT_ROOT'] . '/xieyi_fuwu_copy.png'; // 图片文件位置
try {
$img = new Imagick();
$img->setCompressionQuality(100);
$img->setResolution(120, 120);
$img->readImage($from_path);
$canvas = new Imagick();
$imgNum = $img->getNumberImages();
foreach ($img as $k => $sub) {
$sub->setImageFormat('png');
$sub->stripImage();
$sub->trimImage(0);
$width = $sub->getImageWidth() + 10;
$height = $sub->getImageHeight() + 10;
if ($k + 1 == $imgNum) $height += 10;
$canvas->newImage($width, $height, new ImagickPixel('white'));
$canvas->compositeImage($sub, Imagick::COMPOSITE_DEFAULT, 5, 5);
}
$canvas->resetIterator();
$canvas->appendImages(true)->writeImage($target_path);
return '转化成功';
} catch (\Exception $e) {
return '转化失败:'.$e->getMessage();
}
}
第四步:添加签名
这里我直接用tp添加图片水印的方式处理了
// 添加签名
public function add_sign()
{
$image = \think\Image::open($_SERVER['DOCUMENT_ROOT'] . '/xieyi_fuwu_copy.png');
$image->water($_SERVER['DOCUMENT_ROOT'].'/qianming.png')->save($_SERVER['DOCUMENT_ROOT'].'/xieyi_fuwu_copy2.png');
}
第五步:整合
最后,整合了上述代码,封装成类,直接上代码,我就放在了index模块下面了,放在其他地方及得改命名空间,上代码
<?php
/* Author: kaolagogo Create time: 2021/9/9 0008 17:02 */
namespace app\index\controller;
use Imagick;
use ImagickPixel;
class Word2img
{
protected $sign_img; // 签名图片
protected $user_id; // 用户ID
protected $file_name; // 统一保存的文件名,不含文件后缀
protected $data; // word 文档中需要替换的参数
public function __construct($sign_img, $user_id, $data)
{
$this->sign_img = $sign_img;
$this->user_id = $user_id;
$this->file_name = $user_id . time();
$this->data = $data;
}
public function get_img()
{
$save_path = $this->word_write();
if (!$save_path) {
return json_encode(['code' => -1, 'msg' => '文字写入word失败']);
}
$pdf_path = $this->word2pdf($save_path);
if ($pdf_path == -1) {
return json_encode(['code' => -1, 'msg' => 'world转为pdf失败']);
}
$img_path = $this->pdf2img($pdf_path);
if ($img_path == -1) {
return json_encode(['code' => -1, 'msg' => 'pdf转为图片失败']);
}
$age_path = $this->add_water($img_path);
if ($age_path == -1) {
return json_encode(['code' => -1, 'msg' => '添加签名失败']);
}
return json_encode(['code' => 1, 'msg' => '生成签名图片成功', 'data' => $age_path]);
}
// 文字写入word
public function word_write()
{
// ${name} ${idcard} ${phone} ${time}
import('PhpOffice\PhpWord\TemplateProcessor', '.php');
// 1.创建模板对象
$temp_path = $_SERVER['DOCUMENT_ROOT'] . '/temp/agreement_free.docx'; // 模板文件路径
$document = new \PhpOffice\PhpWord\TemplateProcessor($temp_path);
// 2.插入数据
foreach ($this->data as $k => $v) {
$document->setValue($v['key'], $v['value']);
}
// 3.保存文件
$file_path = $_SERVER['DOCUMENT_ROOT'] . '/file/' . date('Ymd');
if (!file_exists($file_path)) {
mkdir($file_path, '0777', true);
}
$save_path = $file_path . '/' . $this->file_name . '.docx';
$document->saveAs($save_path);
return $save_path;
}
// world 转为 pdf
function word2pdf($word_path)
{
if (!file_exists($word_path)) {
return -1;
}
$pdf_file = $_SERVER['DOCUMENT_ROOT'] . '/file/' . date('Ymd'); // pdf 存储目录
if (!file_exists($pdf_file)) {
mkdir($pdf_file, 0777, true);
}
// 删除已有同名文件
$pdf_path = $pdf_file . '/' . $this->file_name . '.pdf';
if (file_exists($pdf_path)) {
unlink($pdf_path);
}
// 执行转换操作
$word = new \COM("word.Application") or die("Could not initialise Object");
$word->Documents->Open($word_path);
$word->ActiveDocument->ExportAsFixedFormat($pdf_path, 17, false, 0, 0, 0, 0, 7, true, true, 2, true, true, false);
$word->Quit(false);
unset($word);
return $pdf_path;
}
// pdf 转为图片
public function pdf2img($pdf_path)
{
if (!file_exists($pdf_path)) {
return -1;
}
$img_file = $_SERVER['DOCUMENT_ROOT'] . '/file/' . date('Ymd'); // img 存储目录
if (!file_exists($img_file)) {
mkdir($img_file, 0777, true);
}
$img_path = $img_file . '/' . $this->file_name . '.png'; // 图片文件位置
try {
$img = new Imagick();
$img->setCompressionQuality(100);
$img->setResolution(120, 120);
$img->readImage($pdf_path);
$canvas = new Imagick();
$imgNum = $img->getNumberImages();
foreach ($img as $k => $sub) {
$sub->setImageFormat('png');
$sub->stripImage();
$sub->trimImage(0);
$width = $sub->getImageWidth() + 20;
$height = $sub->getImageHeight() + 100;
if ($k + 1 == $imgNum) $height += 10;
$canvas->newImage($width, $height, new ImagickPixel('white'));
$canvas->compositeImage($sub, Imagick::COMPOSITE_DEFAULT, 5, 5);
}
$canvas->resetIterator();
$canvas->appendImages(true)->writeImage($img_path);
} catch (\Exception $e) {
return -1;
}
return $img_path;
}
// 图片添加水印
public function add_water($img_path)
{
if (!file_exists($img_path)) {
return -1;
}
$date = date('Ymd');
$save_file = $_SERVER['DOCUMENT_ROOT'] . '/file/' . $date; // 添加水印后 img 存储目录
if (!file_exists($save_file)) {
mkdir($save_file, 0777, true);
}
// 给原图左上角添加水印并保存water_image.png
$water_path = $_SERVER['DOCUMENT_ROOT'] . $this->sign_img; // 水印图片位置,绝对路径
if (!file_exists($water_path)) {
return -1;
}
$save_path = $save_file . '/' . $this->file_name . '_end.png'; // 图片文件位置
$image = \think\Image::open($img_path);
$image->water($water_path, \think\Image::WATER_SOUTHWEST)->save($save_path);
// return $save_path; // 绝对路径
return '/file/' . $date. '/' . $this->file_name . '_end.png'; // 返回相对路径
}
}
调用代码
function get_img()
{
$sign_img = '你的签名图片路径';
$user_id = 1;
$user_data = [
['key' => 'name', 'value' => '十三'],
['key' => 'idcard', 'value' => '341022199909092525'],
['key' => 'phone', 'value' => '18888888888'],
['key' => 'time', 'value' => date('Y年m月d日')],
];
$word2img = new Word2img($sign_img, $user_id, $user_data);
$get_agreement_img = json_decode($word2img->get_img(), true);
if ($get_agreement_img['code'] != 1) {
return ajax_return(-1, $get_agreement_img['msg']);
}
$agreement_img = $get_agreement_img['data'];
}
注意,用宝塔搭建环境的话,防跨站攻击一定不要勾选,不要勾选,不要勾选。。。。。。
结束