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;