1. 程式人生 > 實用技巧 >java生成圖片

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;