php中网页生成图片的方式,类似长微博图片生成器「建议收藏」

php中网页生成图片的方式,类似长微博图片生成器「建议收藏」导读:因媒体站微博传播需要,需在转发文章至新浪微博时能将文章正文已图片形式传播出去,用以提高微博内容转发积极性,顾需要在原有php项目代码中加入网页转图片功能。 在java中网页转图片有已经开源的转换工具,较为简单,php中网页转图片的开源工具很少,少到只有一个半成品(只能通过命令行调用,无法使用php代码生成)html2image(http://www.guangmingsoft.n…

大家好,又见面了,我是你们的朋友全栈君。

导读:因媒体站微博传播需要,需在转发文章至新浪微博时能将文章正文已图片形式传播出去,用以提高微博内容转发积极性,顾需要在原有php项目代码中加入网页转图片功能。

 

在java中网页转图片有已经开源的转换工具,较为简单,php中网页转图片的开源工具很少,少到只有一个半成品(只能通过命令行调用,无法使用php代码生成)html2image(http://www.guangmingsoft.net/htmlsnapshot/html2image.htm),没办法,习惯直接在代码中统一使用纯语言代码实现,所以继续google,然后找到了一个方案:html》pdf》image(来源:http://buffernow.com/),不得不说此方案是在对php非常熟悉的情况下才能想得到。

 

原本打算直接使用他的开源方案,但在应用过程中发现有问题:无中文字体,添加中文字体后网页中整段的中文在图片中只显示一行,其他内容无法显示。

 

这是要逼着我去研究他的开源代码的节凑啊,不过好在这个开源项目的意义是证实了html》pdf》image方案是可行的。

 

把他的代码拆开来看,发现问题出在html网页生成pdf阶段,由于作者改写了tcpdf方案形成了html2pdf开源包,但是改写得并不好,对中文支持不够,于是抛弃了该作者的开源框架,直接采用稳定的tcpdf以及imagick转换html至pdf再转至image。

 

这个过程略显艰辛啊(php没有正式学习过,一般都是拿起项目就开工,用到什么查什么的),从中午一直持续到晚上2点,整整14个小时啊,我的神,我认为有必要进行总结下,避免下次碰到同样的场景又忘掉了。

 

现在开始吧:

 

1.项目采用的成熟的开源方案:tcpdf(http://www.tcpdf.org/index.php)、imagick(php的一个库,类似gd库,需要在操作系统层面安装库文件,同时需要在php.ini中加入动态链接库)。

 

2.首先需要将html生成pdf:这里要注意的是中文的处理,中文乱码在无数的地方出现过,需要确保的一点是所有的数据交换都采用utf8字符集,这里html采用fckeditor通过post提交的,首先是需要设置web服务器接收字符为utf8,其次new tcpdf时需要设置编码为中文,

$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

 

 

3.tcpdf默认不包含中文字库(中国人要崛起啊,得做点大的世界通用项目,到时候不放日文字库、德国字库啥的,哈哈),可供使用的中文字库很多,网传用得最多的是Droid Sans Fallback字体,所以我采用的是可以Droid Sans Fallback字库,既可以直接下载该字体的tcpdf版本(三个文件),也可以下载ttf字体,然后用tcpdf的工具生成三个文件,方式见http://www.5eyi.com/php-to-generate-pdf-the-perfect-support-for-the-chinese-to-address-the-garbage-tcpdf/

 

4.字体准备好了,编码正确了,准备开工了,但是官方只有案例,没有文档,并且案例中大部分都是多段html代码一点点的往tcpdf对象中写入,而我需要的是直接写入一段html,然后生成pdf文档,所以需要参照案例精简下代码

 

5.html生成pdf时设置字体时需要注意,字体设置不当会影响到后边pdf生成图片的过程,在本次改造项目中就因此困扰了4个小时,Droid Sans是一个字体集,设置pdf字体时有两种方式,一种是只把字体描述信息写入pdf文档中,pdf阅读工具解析的时候会从工具自身字体库或者系统引入对应的字体以显示文档,因此pdf文档会比较小,此时设置字体为‘stsongstdlight’;另外一种设置字体时把字体文件同时保存到pdf文档中,即使pdf阅读工具或者系统中没有该字体时仍然能够解析并显示文档,因此文档会比较大,此时设置字体为‘droidsansfallback’;因为刚开始字体设置‘stsongstdlight’,导致后边使用imagick从pdf生成图片时始终无法生成;接着各种控制变量法,一步一步的找原因,最终定位到字体位置,字体stsongstdlight’导致无法生成图片,经完成的google指引,发现了Droid Sans字体有两种设置方式,再尝试两种设置字体的设置方式发现当字体设置为‘droidsansfallback’时生成的pdf文档才能生成图片【这里我感觉是服务器上缺少Droid Sans字体库,如果把Droid Sans字体库安装到服务器上是否也能生成图片呢?由于项目结束已经很晚了,所以没有去调研

 

6.写入tcpdf对象的html代码必须是无错误的并且符合html规范的代码,否则tcpdf会报错,通常由fckeditor生成的html代码都会对双引号转义,会导致”变成了\”,这个转义不能被tcpdf识别,所以需要去掉转义字符\

 

7.图片版权:生成的图片上需要加上产品的水印,既可以在pdf生成图片环节添加,也可以在html生成pdf阶段添加,个人认为pdf创建阶段添加会更简单,此项目中由于时间关系,我只是在html结尾部分简单的增加了一个网站标识(因为pdf是按照html格式生成的,所以可以修改html格式使得生成的pdf更美观、水印切合度更高)。

 

好了,至此html生成pdf文档成功了,代码如下:

$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->AddPage();
$pdf->SetFont('droidsansfallback', '', 16);
$testhtml=str_replace("\\","",$html).'<br/><div align="right">地歌网:www.diggg.com.cn</div>';
$pdf->writeHTML($testhtml, true, 0, true, true);
$pdf->lastPage();
$pdf->Output($config['webroot'].'/temp/temp'.$id.'.pdf','f');

 接下来我们就开始采用imagick将pdf生成image

 

8.首先得准备imagick系统环境,得安装imagick系统安装包(window见http://www.gretheer.com/2013/09/installing-imagemagick-on-windows-and-using-with-php-imagick.html,linux直接使用yum安装),安装成功后打开命令行输入convert 查看是否正常执行;其次得安装php动态链接库,这是最麻烦的阶段,动态链接库必须和操作系统版本、php版本一致,否则无法使用,悲剧的是楼主用的php是wampp3.2.1中的带的php,版本是5.4.16,操作系统是window7 64位,找遍了google都没能找到能正常安装的imagick动态库,花了2小时后,我放弃了在window7上本地调试工作,直接在centos6的服务器上安装imagick,结果centos上imagick动态库成功集成到php中。在此吐槽下:这个php的动态库真是麻烦,兼容性太差了

 

9.imagick的官方教程地址(http://www.php.net/manual/zh/book.imagick.php),其实imagick的功能非常强大,但是相关的功能介绍文档资料太少了,时间关系无法一个方法一个方法的尝试,只能google得到我需要的东东,一开始用最简单的代码实现功能如

 

$img = new imagick($pdf_file);
$img->setImageFormat('jpg');
$img->writeImage($save_to);

 可以正常生成图片,但是图片中只包含pdf的最后一页的内容;如果pdf是单页的可以这样操作,但是如果pdf是多页的,这种方式就不适用了,因为没有相关文档,一开始想既然可以把pdf最后一页的内容生成图片,那么一定可以把所有页面都生成图片,然后再利用图片库把图片拼接起来

 

代码思路 写道
1.获取pdf的页数 [$Image = new Imagick($pdfpath.’.pdf’); $num_page = $Image->getnumberimages();]

2.把每一页都生成图片[ $Image = new Imagick($pdfpath.’.pdf'[i])]

3.获取每一页图片的高度并相加得到后续拼合图片时需要用到的画布的高度

4.新建一个画布

5.依次把图片写入画布,注意图片在画布中的起始坐标,横坐标是0,纵坐标是前边几张图片的高度之和

6.关闭画布,并输出图片文件

 写好代码后发现居然有直接把多页pdf直接生成图片的方法,悲剧啊,花了那么长时间,居然有更简单的方法,好吧当然采用简单的思路啦

 

$pdfpath=$config['webroot'].'/temp/temp'.$id.'.pdf';
$im = new Imagick();
$im->readImage($pdfpath);
$im -> resetIterator();
$imgs = $im->appendImages(true);
$imgs->setImageFormat( "jpg" );
$img_name = $id.'.jpg';
$imgs->writeImage( $config['webroot']."/temp/".$img_name);
$imgs->clear();
$imgs->destroy();
$im->clear();
$im->destroy();

 

 

 

好了,到此html生成图片全过程完成

 完整的代码:

//缓存正文的图片
include_once($config['webroot']."/tcpdf/tcpdf.php");
                $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->AddPage();
$pdf->SetFont('droidsansfallback', '', 16);
$testhtml=str_replace("\\","",$con).'<br/><div align="right">地歌网:www.diggg.com.cn</div>';
$pdf->writeHTML($testhtml, true, 0, true, true);
$pdf->lastPage();
$pdf->Output($config['webroot'].'/temp/temp'.$id.'.pdf','f');

$pdfpath=$config['webroot'].'/temp/temp'.$id.'.pdf';
$im = new Imagick();
$im->readImage($pdfpath);
$im -> resetIterator();
$imgs = $im->appendImages(true);
$imgs->setImageFormat( "jpg" );
$img_name = $id.'.jpg';
$imgs->writeImage( $config['webroot']."/temp/".$img_name);
$imgs->clear();
$imgs->destroy();
$im->clear();
$im->destroy();
unlink($pdfpath);
//缓存结束

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143571.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月21日 上午11:20
下一篇 2022年5月21日 上午11:40


相关推荐

  • 字典序排列算法解析

    字典序排列算法解析字典序全排列算法分析 给定一组字符串 s 首先将字符串转化为字符数组 c 将字符数组 c 中的元素从小到大排序 得到的即为字典序全排列的第一个排列 因为每个字符的大小是按照他的 Ascii 码对应的数字比较大小的 所以这里以一串数字为例 例如 15432 其实可以将字典序全排列看作数字进位的过程 例如 从后往前数 倒数第四位的数达到了最大值 即从后往前找 后面的数总是小于或等于前面的数 满足从尾部向前递增

    2026年3月16日
    2
  • js截取字符串的方法(介绍3种常用的)

    js截取字符串的方法(介绍3种常用的)js 截取字符串常用的字符截取函数有 slice substring 和 substr 这 3 个 我们前端人必会这 3 种方法 我们将从这 3 个函数出发 看看在 js 中 这些函数是如何通过 js 截取字符串的 1 slice 说明 该 slice start end 方法返回 start 和 end 索引之间的字符串部分 slice 像 substring 第一个参数代表开始位置 第二个参数代表结束位置的下一个位置 截取出来的字符串的长度为第二个参数与第一个参数之间的差 若参数值为负数 则将该值加上字符串长度后转为正值 若第一个

    2026年3月18日
    2
  • Coze开发30分钟入门指南-工作流

    Coze开发30分钟入门指南-工作流

    2026年3月12日
    2
  • slf4j与log4j、log4j2

    slf4j与log4j、log4j2nbsp nbsp 最近公司项目系统需要将日志从 log4j slf4j 升级为 log4j2 然后彻彻底底的把它们研究了一遍 在网上查找相关资源 发现并没有一篇文章能够很完整的把它们之间的关联和区别写出来 所以我在这里做一个总结 log4j nbsp nbsp 如果在我们系统中单独使用 log4j 的话 我们只需要引入 log4j 的核心包就可以了 我这里用的是 log4j 1 2 17 jar 然后在系统中使用如下代码输出日志 pu

    2026年3月19日
    3
  • 抽象类VS接口

    抽象类VS接口抽象类VS接口

    2022年4月24日
    35
  • slam技术前景_无人机航拍技术毕业论文

    slam技术前景_无人机航拍技术毕业论文过去几年,扫地机的出现使得SLAM名声大噪,这个被业界认为是实现机器人自主移动的关键技术,已逐渐进入人们的视野,而随着无人驾驶、AGV等行业的兴起,又使其找到了另一片广阔天地。SLAM的前世今生对于定位、定向等需求人们其实在千年前就有了,最早时期,古人提出了夜观天象,基于遥远恒星的方位推断自身所处的位置,进而演变出一门博大精深的学科“牵星术”,用牵星板测量星星实现纬度估计。直到1964…

    2026年4月15日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号