网站开发交接协议书国外被动收入网站做的好的
news/
2025/9/30 1:44:56/
文章来源:
网站开发交接协议书,国外被动收入网站做的好的,做网站至少要花多少钱,网络科技公司骗术来源#xff1a;xhtmlrenderer 将html转换成pdf#xff0c;完美css#xff0c;带图片#xff0c;手动分页#xff0c;解决内容断开的问题 - 煮过的花朵 - 博客园
之前用itext7将html导出为pdf#xff0c;比较方便#xff0c;代码较少#xff0c;而且支持base64的图片。…来源xhtmlrenderer 将html转换成pdf完美css带图片手动分页解决内容断开的问题 - 煮过的花朵 - 博客园
之前用itext7将html导出为pdf比较方便代码较少而且支持base64的图片。但是itext7是收费的所以换成了xhtmlrenderer。
xhtmlrenderer自动引入依赖包itext2.0.8而且不能再引入其他版本的itext因为itext2.0.8是已经被废弃的里面的很多方法在新版本已经没有了。
itext导出pdf最重要的4个难点
1.css样式
2.中文不显示
3.图片itext7支持比较好不过要收费
4.分页时内容断开的问题itext7不会出现这种问题不过要收费
一、首先引入包
只需要这个就够了它会自动引入itext2.0.8
dependencygroupIdorg.xhtmlrenderer/groupIdartifactIdcore-renderer/artifactIdversionR8/version
/dependency
二、页面css样式的采集 看过很多篇itext的文章都没有达到想象中要求。大多是说将css路径改为绝对路径或者将css写在页面中这都不现实。真正的项目中你的项目经理是不会让你这么做的。
所以我找到一个能将页面所有css采集起来的js方法。传入你的标签的id返回一个包含该id的区域的所有css样式 加上htmlhead和body标签组成一个html的字符串。将字符串传给后台去生成pdf。值得注意的是我加了这个字体body{font-family: SimSun;}这个字符是中文字体后端必须与前端一致。且看后面。
function getElementChildrenAndStyles(selector) {var html $(selector).prop(outerHTML);selector selector.split(,).map(function(subselector){return subselector , subselector *;}).join(,);elts $(selector);var rulesUsed [];//文档的所有样式表sheets document.styleSheets;for(var c 0; c sheets.length; c) {// rules 和 cssRules 的计数方法也是不一样的rules 是第几个选择器cssRules 是第几条规则,// 分别用于IE7和chromevar rules sheets[c].rules || sheets[c].cssRules;for(var r 0; r rules.length; r) {//selectorText: $节点var selectorText rules[r].selectorText;var matchedElts $(selectorText);//找到dom节点里所有节点并将其push到数组里for (var i 0; i elts.length; i) {if (matchedElts.index(elts[i]) ! -1) {rulesUsed.push(rules[r]); break;} }}}//重组stylevar style rulesUsed.map(function(cssRule){if (cssRule.style) {var cssText cssRule.selectorText{cssRule.style.cssText.toLowerCase()};} else {var cssText cssRule.selectorText{cssRule.cssText};}return cssText;}).join(\n);return htmlheadmeta charsetUTF-8/ style\n style \n td{background:white!important;} \n body{font-family: SimSun;} \n/style\n\n/headbody html/body/html;} 今天解决了分页的时候会断开内容的问题解决方案就是手动分页用js计算高度然后超过页面高度的就换页这样就不会出现自动换页的时候内容断开了。
1.我将需要显示的元素都添加class ‘pdf-page-range’
2. classpageNext .pageNext{page-break-after: always;} 这个css表示下一个元素将会换页转pdf的时候itext会自动识别。
3.在前面的基础上插入以下代码即可需要图片转换之后执行
注意这个修改了网页内容如果想保留原网页内容自行想办法 -。-
//后端低版本的itext对分页的处理非常不友好所以前端页面强制分页。//我将需要显示的元素都添加class ‘pdf-page-range’//classpageNext .pageNext{page-break-after: always;} 这个css表示下一个元素将会换页。function pdfPageRange(){var heigth 0; $(.pdf-page-range).each(function(){var $this $(this);var $table $this.find(table);var $next $this.next();var $prevPage $this.prev(.pageNext);index $(.pageNext).length;var tagName $this[0].tagName;var element_tag;if($table$table.length0){element_tag $table[0];}if(tagNametable||tagNameTABLE){element_tag $this[0];}if(element_tag){heigth tablePage($(element_tag),heigth)return true;}//不是table的处理heigth $this[0].offsetHeight;if(heigth1000){$this.before(div classpageNext /div );heigth $this[0].offsetHeight;}});}//table单独算高度function tablePage($table,heigth){var $trList $table.find(tr);var $thead $table.find(tr.thead);$trList.each(function(){heigth $(this)[0].offsetHeight;if(heigth1000){$(this).before($thead.prop(outerHTML));$thead_add $(this).prev().prev();$thead_add.addClass(pageNext);heigth $(this)[0].offsetHeight$thead_add[0].offsetHeight;}});return heigth;}
});
三、图片的支持 项目中有很多Echarts做的图表这个生成的图表都是canvas标签而itext是不支持canvas标签的。所以要把图表全部换成base64的img标签。这里引入一个js。
html2canvas.js它能将制定区域截图。请看以下。
注意
1.html2canvas方法返回的是Promise类型为什么要将所有 html2canvas方法的返回值集中起来然后使用Promise.all(canvasArray).then方法。因为html2canvas是异步的你的下面的js已经处理完了它可能还没截图完成。Promise.all(canvasArray).then方法会在所有截图已经完成之后执行。所以我把ajax请求放在里面。请看代码
2. img标签闭合的问题img标签是自闭合标签。正常情况下浏览器不会去识别你的img的闭合标签即使你的img标签有/img或img src /,浏览器最后显示还是img, 所以我用一个字符串代替“/” 后台再用“/”代替这个字符串你也可以前端就替换。请看代码
3.必须给img加上宽度和高度不然被后台转换之后尺寸会变得很小。
$(#itextpdf).click(function(){var canvasArray [];$(.charts).each(function(){var $this$(this);var canvasIndex html2canvas($this,{ scale: 5,background: #FFFFFF,onrendered:function(canvas){var imgBase64 canvas.toDataURL(image/jpeg, 1.0);$this.html();// 标签被jquery获取后自定义属性closingtags会变成closingtags你可以加个css将图片隐藏起来然后在html字符串里面再加一个显示的css。$this.append (img class“hidden” alt src imgBase64 closingtags ) } });canvasArray.push(canvasIndex);}); Promise.all(canvasArray).then(function () {var str getElementChildrenAndStyles(#basket);$.post(/ecloud/sa/saerrorquestions/exportpdf.do,{str:str },function(r){}); });});
$(#itextpdf).click(function(){var canvasArray [];$(.charts).each(function(){var $this$(this);var canvasIndex html2canvas($this,{ scale: 5,background: #FFFFFF,onrendered:function(canvas){var imgBase64 canvas.toDataURL(image/jpeg, 1.0);$this.html();// 标签被jquery获取后自定义属性closingtags会变成closingtags你可以加个css将图片隐藏起来然后在html字符串里面再加一个显示的css。$this.append (img class“hidden” alt src imgBase64 closingtags ) } });canvasArray.push(canvasIndex);}); Promise.all(canvasArray).then(function () {var str getElementChildrenAndStyles(#basket);$.post(/ecloud/sa/saerrorquestions/exportpdf.do,{str:str },function(r){}); });}); 四、后台代码 项目中引入中文字体html字符串中也必须引入。我的字体css是 body{font-family: SimSun;}
package cn.myc.ykt3.util;import java.io.FileOutputStream;
import java.io.OutputStream;import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import com.lowagie.text.pdf.BaseFont;public class ItextHtmlTopdf {/*** * param htmlStr html字符串* return* throws Exception*/public String exportpdf(String htmlStr ) throws Exception {if (StringUtils.isBlank(htmlStr)) {return null;}htmlStr htmlStr.trim().replaceAll(,).replaceAll( ,).replaceAll(br/,\n|\r\n|\r ).replaceAll( , );htmlStr htmlStr.replace(closingtags\\, /);String classpath this.getClass().getResource(/).getPath().replaceFirst(/, );String webappRoot classpath.replaceAll(/target/classes, /src/main/webapp);//-----版本2.0.8ITextRenderer renderer new ITextRenderer();OutputStream os new FileOutputStream(C:/Users/Administrator/Desktop/createSamplePDF3.pdf);// 如果携带图片则加上以下两行代码,将图片标签转换为Itext自己的图片对象Base64ImgReplacedElementFactory为图片处理类renderer.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory());renderer.getSharedContext().getTextRenderer().setSmoothingThreshold(1);renderer.setDocumentFromString(htmlStr);ITextFontResolver fontResolver renderer.getFontResolver();// 解决中文支持问题参数为字体的路径html页面也必须引入字体fontResolver.addFont(webappRootstatic/sanalysis/simsun.ttf, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.layout();renderer.createPDF(os);os.close();return null;}
}
Base64ImgReplacedElementFactory图片处理类
package cn.myc.ykt3.util;import java.io.IOException ;
import org.w3c.dom.Element ;
import org.xhtmlrenderer.extend.FSImage ;
import org.xhtmlrenderer.extend.ReplacedElement ;
import org.xhtmlrenderer.extend.ReplacedElementFactory ;
import org.xhtmlrenderer.extend.UserAgentCallback ;
import org.xhtmlrenderer.layout.LayoutContext ;
import org.xhtmlrenderer.pdf.ITextFSImage ;
import org.xhtmlrenderer.pdf.ITextImageElement ;
import org.xhtmlrenderer.render.BlockBox ;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener ;
import com.lowagie.text.BadElementException ;
import com.lowagie.text.Image ;
import com.lowagie.text.pdf.codec.Base64 ;public class Base64ImgReplacedElementFactory implements ReplacedElementFactory {/*** 实现createReplacedElement 替换html中的Img标签* * param c 上下文* param box 盒子* param uac 回调* param cssWidth css宽* param cssHeight css高* return ReplacedElement*/public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac,int cssWidth, int cssHeight) {Element e box.getElement();if (e null) {return null;}String nodeName e.getNodeName();// 找到img标签if (nodeName.equals(img)) {String attribute e.getAttribute(src);FSImage fsImage;try {// 生成itext图像fsImage buildImage(attribute, uac);} catch (BadElementException e1) {fsImage null;} catch (IOException e1) {fsImage null;}if (fsImage ! null) {// 对图像进行缩放if (cssWidth ! -1 || cssHeight ! -1) {fsImage.scale(cssWidth, cssHeight);}return new ITextImageElement(fsImage);}}return null;}/*** 将base64编码解码并生成itext图像* * param srcAttr 属性* param uac 回调* return FSImage* throws IOException io异常* throws BadElementException BadElementException*/protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException,BadElementException {FSImage fsImage;if (srcAttr.startsWith(data:image/)) {String b64encoded srcAttr.substring(srcAttr.indexOf(base64,) base64,.length(),srcAttr.length());// 解码byte[] decodedBytes Base64.decode(b64encoded);fsImage new ITextFSImage(Image.getInstance(decodedBytes));} else {fsImage uac.getImageResource(srcAttr).getImage();}return fsImage;}/*** 实现reset*/public void reset() {}Overridepublic void remove(Element arg0) {}Overridepublic void setFormSubmissionListener(FormSubmissionListener arg0) {}
}
我的页面 导出的pdf效果自动分页并且分页不会强制裁剪图片区域。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/922399.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!