java生成图片

前言:

  后台生成图片,我能想到的有可能有以下几种方式:

  1,使用图片相关api画图;

  2,使用pdf画图,然后pdf -> 图片;

  3,使用html画图(freemarker),然后html -> 图片;

  4,使用html画图(freemarker),然后html -> pdf -> 图片;

 

实现:

  本文章采用第4种方式画图

  1,读取企业证书图片的ftl模板

import freemarker.template.Configuration;
import freemarker.cache.TemplateLoader;
import org.springframework.ui.freemarker.SpringTemplateLoader;
import org.springframework.core.io.DefaultResourceLoader;
import freemarker.template.Template;
Configuration configuration = new Configuration();
// war包下,WEB-INFO/classes/
TemplateLoader templateLoader = new SpringTemplateLoader(new DefaultResourceLoader(), "注释目录下的某个文件夹,比如名叫:template");
configuration.setTemplateLoader(templateLoader);
configuration.setDefaultEncoding("utf-8");
// 读取war包下/WEB-INFO/classes/template/xxxtemplate.ftl,生成模板对象
Template template = configuration.getTemplate("xxxtemplate.ftl");

  2,ftl模板 -> html文件

File htmlFile = new File("html文件.html");
FileWriter htmlWriter = new FileWriter(htmlFile);
template.process(需要渲染进ftl模板的数据(Map类型), htmlWriter);
htmlWriter.flush();
templateLoader.closeTemplateSource(template);

  3,html -> pdf(不带背景图片)

import org.xhtmlrenderer.pdf.ITextRenderer;
import com.suning.secis.service.monitor.enterprisereport.impl.Base64ImgReplacedElementFactory;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import com.itextpdf.text.pdf.BaseFont;
File pdfFile = new File("pdf不带背景图片.pdf");
FileOutputStream os = new FileOutputStream(pdfFile);
ITextRenderer renderer = new ITextRenderer();
renderer.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory());
renderer.getSharedContext().getTextRenderer().setSmoothingThreshold(0);
String url = htmlFile.toURI().toURL().toString();
renderer.setDocument(url);
ITextFontResolver fontResolver = renderer.getFontResolver();
ClassLoader classLoaderToUse = ClassUtils.getDefaultClassLoader();
// war包下/WEB-INFO/classes/
Enumeration<URL> fontUrls = classLoaderToUse.getResources("font/simsun.ttf");
URL fontUrl;
if (fontUrls.hasMoreElements()) {
fontUrl = fontUrls.nextElement();
} else {
throw new 业务Exception(业务code, "获取pdf字体文件失败!");
}
// 字体文件如果运维人员安装好了,指定那个目录;如果放在项目的classes目录里,则打包时指定utf-8编码,可能会乱码;也可以从HttpServletRequest里面获得ip+port,然后网络请求这个文件;
fontResolver.addFont(fontUrl对应的路径, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.layout();
renderer.createPDF(os);
os.flush();

  4,pdf(不带背景图片) -> pdf(带背景图片)

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfContentByte;
File pdfWithBackgroundFile = new File("pdf带背景图片.pdf");
PdfReader pdfReader = new PdfReader(pdfFile.getCanonicalPath());
FileOutputStream osWithBackground = new FileOutputStream(pdfWithBackgroundFile);
PdfStamper pdfStamper = new PdfStamper(pdfReader, osWithBackground);
Enumeration<URL> backgroundPngUrls = classLoaderToUse.getResources("背景图片目录/background.png");
URL backgroundPngUrl;
if (backgroundPngUrls.hasMoreElements()) {
backgroundPngUrl = backgroundPngUrls.nextElement();
} else {
throw new 业务Exception(业务code, "获取背景图片失败!");
}
com.itextpdf.text.Image tImgCover = com.itextpdf.text.Image.getInstance(backgroundPngUrl);
tImgCover.setAbsolutePosition(-33, -42);
tImgCover.scaleAbsolute(660, 927);
// 两个pdf图层,哪个在上哪个在下,可以通过一下方法:getUnderContent(页数)、getOverContent(页数)
PdfContentByte content = pdfStamper.getUnderContent(1);
content.addImage(tImgCover);
content.stroke();
osWithBackground.flush();
pdfStamper.close();
pdfReader.close();

  5,pdf(带背景图片) -> png

import org.icepdf.core.pobjects.Document;
import java.awt.image.BufferedImage;
import org.icepdf.core.util.GraphicsRenderingHints;
File imageFile = new File("目标图片.png");
Document document = new Document();
document.setFile(pdfWithBackgroundFile.getCanonicalPath());
BufferedImage image = (BufferedImage) document.getPageImage(0, GraphicsRenderingHints.SCREEN, 1, 0f, 2.5f);
ImageIO.write(image, "png", imageFile);
image.flush();

  6,finally删除中间文件、关闭流

 

总结:

  1,在ftl文件里面,如下设置,能保证windows系统和linux系统的大小一致(按照你设置的大小),方便本地windows调试;

<style>
@page {
size: 210mm 297mm;
}
</style>

  2,在ftl的style里面也可以使用变量,如下;按需调整字体大小等;

.class名称 {
font-size: ${变量名?default(27)};
}

  3,itexpdf只认识html较少的标签和样式;

  如文字居中,使用:text-align: center;

  font-family: SimSun;需要和字体文件对应;

  如粗体、浮动效果都不行;浮动效果需要使用table标签:

 

  如要实现这个布局,不能使用浮动,使用table; 

posted @ 2020-07-31 14:53  seeAll  阅读(3225)  评论(0编辑  收藏  举报