问题背景

在系统中需要对PDF模板填充数据内容并生成临时PDF,再将临时PDF文档转换为图片格式并保存(此过程无论成功还是失败都会把临时生成的PDF删除,减少不必要的存储空间)。PDF模板部分内容截图如下:        

但是最终生成的图片中,却缺失了填充内容的中文信息,如下图所示:

查找问题

一开始一直怀疑是使用因为使用itextpdf的jar包在填充PDF模板生成PDF的时候出问题的,因为当时搜了一下网上确实有很多因为使用了这种jar包而导致中文缺失或是乱码的问题。因此花了一段时间一直在这个方面查找和解决问题,包括引入itextpdf的字体包itext-asian来解决此问题,但最终生成的图片还是没有中文。最终,个人把代码中删除临时PDF该操作放开(个人愚钝当时未想到把此步骤拆开来查找问题),来将生成好的临时PDF和最后图片进行比对。最后终于发现是PDF转图片的过程中丢失了填充内容的中文。

解决问题

1.在将PDF转为图片时,个人使用的是apache开源pdfbox的jar包(问题出在此)。

2.查找各相关文档,发现大部分解决方法都是复写源码来指定字体库,当然还有其他方案,就是本地系统安装相关字体库,亦能解决问题。

代码实现

现贴出解决该需求(根据PDF模板生成PDF,再将PDF转为图片)以及解决相关问题(PDF转图片丢失中文)的相关代码。

1.maven配置:

说明:1.itextpdf的两个包是用于PDF模板生成PDF用的,itext-asian可使能兼容中文内容。

2.pdfbox是用于PDF转图片的(亦是我们要解决不能显示中文内容的问题)。

2.根据PDF模板生成PDF工具类

public class PdfUtils {private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);public static ByteArrayOutputStream generatePdf(String templatePath, Map<String, String> dataMap, Map<String, String> imgMap) {try {FileInputStream inputStream = new FileInputStream(templatePath);Throwable var4 = null;ByteArrayOutputStream var5;try {var5 = generatePdf((InputStream)inputStream, dataMap, imgMap);} catch (Throwable var15) {var4 = var15;throw var15;} finally {if (inputStream != null) {if (var4 != null) {try {inputStream.close();} catch (Throwable var14) {var4.addSuppressed(var14);}} else {inputStream.close();}}}return var5;} catch (IOException var17) {logger.error("生成PDF异常, e:", var17);throw new PDFException("生成PDF异常");}}public static ByteArrayOutputStream generatePdf(InputStream templateInputStream, Map<String, String> dataMap, Map<String, String> imgMap) {try {ByteArrayOutputStream bos = new ByteArrayOutputStream();Throwable var6 = null;ByteArrayOutputStream var29;try {PdfReader reader = new PdfReader(templateInputStream);PdfStamper stamper = new PdfStamper(reader, bos);AcroFields form = stamper.getAcroFields();BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);form.addSubstitutionFont(bfChinese);Iterator var9;String key;String value;if (dataMap != null) {var9 = dataMap.keySet().iterator();while(var9.hasNext()) {key = (String)var9.next();value = (String)dataMap.get(key);form.setField(key, value);}}if (imgMap != null) {var9 = imgMap.keySet().iterator();while(var9.hasNext()) {key = (String)var9.next();value = (String)imgMap.get(key);int pageNo = ((AcroFields.FieldPosition)form.getFieldPositions(key).get(0)).page;Rectangle signRect = ((AcroFields.FieldPosition)form.getFieldPositions(key).get(0)).position;float x = signRect.getLeft();float y = signRect.getBottom();Image image = Image.getInstance(value);PdfContentByte under = stamper.getOverContent(pageNo);image.scaleToFit(signRect.getWidth(), signRect.getHeight());image.setAbsolutePosition(x, y);under.addImage(image);}}stamper.setFormFlattening(true);stamper.close();var29 = bos;} catch (Throwable var26) {var6 = var26;throw var26;} finally {if (bos != null) {if (var6 != null) {try {bos.close();} catch (Throwable var25) {var6.addSuppressed(var25);}} else {bos.close();}}}return var29;} catch (Exception var28) {logger.error("生成PDF异常, e:", var28);throw new PDFException("生成PDF异常");}}public static void generatePdfFile(String templatePath, Map<String, String> dataMap, Map<String, String> imgMap, String newPdfPath) {try {FileOutputStream out = new FileOutputStream(newPdfPath);Throwable var5 = null;try {ByteArrayOutputStream bos = generatePdf(templatePath, dataMap, imgMap);Throwable var7 = null;try {Document doc = new Document();PdfCopy copy = new PdfCopy(doc, out);doc.open();PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);copy.addPage(importPage);doc.close();} catch (Throwable var34) {var7 = var34;throw var34;} finally {if (bos != null) {if (var7 != null) {try {bos.close();} catch (Throwable var33) {var7.addSuppressed(var33);}} else {bos.close();}}}} catch (Throwable var36) {var5 = var36;throw var36;} finally {if (out != null) {if (var5 != null) {try {out.close();} catch (Throwable var32) {var5.addSuppressed(var32);}} else {out.close();}}}} catch (Exception var38) {logger.error("生成PDF异常, e:", var38);throw new PDFException("生成PDF异常");}}public static InputStream generatePdfIntoInputStream(InputStream templateInputStream, Map<String, String> dataMap, Map<String, String> imgMap) {byte[] fileBytes = generatePdfIntoByte(templateInputStream, dataMap, imgMap);return new ByteArrayInputStream(fileBytes);}public static byte[] generatePdfIntoByte(InputStream templateInputStream, Map<String, String> dataMap, Map<String, String> imgMap) {ByteArrayOutputStream outputStream = generatePdf(templateInputStream, dataMap, imgMap);return outputStream.toByteArray();}}

3.根据PDF转换为图片工具类

public class PdfToImagesUtil{public static final String PNG = "png";private static final Logger logger = LoggerFactory.getLogger(PdfToImagesUtil.class);/*** 转换全部的pdf* @param fileAddress 文件地址* @param filename PDF文件名* @param type 图片类型*/public static boolean pdf2png(String fileAddress,String filename,String type) {boolean isSuccess = false;// 将pdf装图片 并且自定义图片得格式大小File file = new File(fileAddress + "/" + filename + ".pdf");try {PDDocument pDoc = PDDocument.load(file);PDFRenderer renderer = new PDFRenderer(pDoc);BufferedImage image = renderer.renderImageWithDPI(0, 144); // Windows native DPI// BufferedImage srcImage = resize(image, 240, 240);//产生缩略图isSuccess = ImageIO.write(image, type, new File(fileAddress + "/" + filename + "." + type));pDoc.close();return isSuccess;} catch (IOException e) {logger.error("pdf转换为图片失败:", e);return isSuccess;}}/***自由确定起始页和终止页* @param fileAddress 文件地址* @param filename pdf文件名* @param indexOfStart 开始页  开始转换的页码,从0开始* @param indexOfEnd 结束页  停止转换的页码,-1为全部* @param type 图片类型*/public static void pdf2png(String fileAddress,String filename,int indexOfStart,int indexOfEnd,String type) {// 将pdf装图片 并且自定义图片得格式大小File file = new File(fileAddress+"\\"+filename+".pdf");try {PDDocument doc = PDDocument.load(file);PDFRenderer renderer = new PDFRenderer(doc);int pageCount = doc.getNumberOfPages();for (int i = indexOfStart; i < indexOfEnd; i++) {BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI// BufferedImage srcImage = resize(image, 240, 240);//产生缩略图ImageIO.write(image, type, new File(fileAddress+"\\"+filename+"_"+(i+1)+"."+type));}} catch (IOException e) {logger.error("pdf转换为图片失败:", e);}}}

4.开始解决PDF转图片不能显示中文的问题。

1.在项目里建一个与源码包名一样的路径及文件FontMapperImpl.java

说明:个人是把字体库和pdf模板文件放在resources下,放在此文件夹下,maven还需再加一个配置,来防止maven打包时将字体库和pdf模板文件编码打包,导致字体包和pdf模板被编译转码破坏不可用。   

2.复写源码的FontMapperImpl.java文件

代码如下:

package org.apache.pdfbox.pdmodel.font;import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;import org.apache.fontbox.FontBoxFont;
import org.apache.fontbox.ttf.OpenTypeFont;
import org.apache.fontbox.ttf.TTFParser;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.fontbox.type1.Type1Font;final class FontMapperImpl implements FontMapper {private static final FontCache fontCache = new FontCache();private FontProvider fontProvider;private Map<String, FontInfo> fontInfoByName;private final TrueTypeFont lastResortFont;private final Map<String, List<String>> substitutes = new HashMap();FontMapperImpl() {this.substitutes.put("Courier", Arrays.asList("CourierNew", "CourierNewPSMT", "LiberationMono", "NimbusMonL-Regu"));this.substitutes.put("Courier-Bold", Arrays.asList("CourierNewPS-BoldMT", "CourierNew-Bold", "LiberationMono-Bold", "NimbusMonL-Bold"));this.substitutes.put("Courier-Oblique", Arrays.asList("CourierNewPS-ItalicMT", "CourierNew-Italic", "LiberationMono-Italic", "NimbusMonL-ReguObli"));this.substitutes.put("Courier-BoldOblique", Arrays.asList("CourierNewPS-BoldItalicMT", "CourierNew-BoldItalic", "LiberationMono-BoldItalic", "NimbusMonL-BoldObli"));this.substitutes.put("Helvetica", Arrays.asList("ArialMT", "Arial", "LiberationSans", "NimbusSanL-Regu"));this.substitutes.put("Helvetica-Bold", Arrays.asList("Arial-BoldMT", "Arial-Bold", "LiberationSans-Bold", "NimbusSanL-Bold"));this.substitutes.put("Helvetica-Oblique", Arrays.asList("Arial-ItalicMT", "Arial-Italic", "Helvetica-Italic", "LiberationSans-Italic", "NimbusSanL-ReguItal"));this.substitutes.put("Helvetica-BoldOblique", Arrays.asList("Arial-BoldItalicMT", "Helvetica-BoldItalic", "LiberationSans-BoldItalic", "NimbusSanL-BoldItal"));this.substitutes.put("Times-Roman", Arrays.asList("TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS", "LiberationSerif", "NimbusRomNo9L-Regu"));this.substitutes.put("Times-Bold", Arrays.asList("TimesNewRomanPS-BoldMT", "TimesNewRomanPS-Bold", "TimesNewRoman-Bold", "LiberationSerif-Bold", "NimbusRomNo9L-Medi"));this.substitutes.put("Times-Italic", Arrays.asList("TimesNewRomanPS-ItalicMT", "TimesNewRomanPS-Italic", "TimesNewRoman-Italic", "LiberationSerif-Italic", "NimbusRomNo9L-ReguItal"));this.substitutes.put("Times-BoldItalic", Arrays.asList("TimesNewRomanPS-BoldItalicMT", "TimesNewRomanPS-BoldItalic", "TimesNewRoman-BoldItalic", "LiberationSerif-BoldItalic", "NimbusRomNo9L-MediItal"));this.substitutes.put("Symbol", Arrays.asList("Symbol", "SymbolMT", "StandardSymL"));this.substitutes.put("ZapfDingbats", Arrays.asList("ZapfDingbatsITC", "Dingbats", "MS-Gothic"));this.substitutes.put("STSong-Light", Arrays.asList("STSONG-light","DengXian"));//自己加的Iterator var1 = Standard14Fonts.getNames().iterator();while(var1.hasNext()) {String baseName = (String)var1.next();if (!this.substitutes.containsKey(baseName)) {String mappedName = Standard14Fonts.getMappedFontName(baseName);this.substitutes.put(baseName, this.copySubstitutes(mappedName));}}try {String ttfName = "/pdftemplates/font/STSONG-light.ttf";InputStream ttfStream = FontMapperImpl.class.getResourceAsStream(ttfName);TTFParser ttfParser = new TTFParser();System.out.println("----->>读取自定义字体:" + ttfName);this.lastResortFont = ttfParser.parse(ttfStream);} catch (IOException var5) {throw new RuntimeException(var5);}}public synchronized void setProvider(FontProvider fontProvider) {this.fontInfoByName = this.createFontInfoByName(fontProvider.getFontInfo());this.fontProvider = fontProvider;}public synchronized FontProvider getProvider() {if (this.fontProvider == null) {this.setProvider(FontMapperImpl.DefaultFontProvider.INSTANCE);}return this.fontProvider;}public FontCache getFontCache() {return fontCache;}private Map<String, FontInfo> createFontInfoByName(List<? extends FontInfo> fontInfoList) {Map<String, FontInfo> map = new LinkedHashMap();Iterator var3 = fontInfoList.iterator();while(var3.hasNext()) {FontInfo info = (FontInfo)var3.next();Iterator var5 = this.getPostScriptNames(info.getPostScriptName()).iterator();while(var5.hasNext()) {String name = (String)var5.next();map.put(name, info);}}return map;}private Set<String> getPostScriptNames(String postScriptName) {Set<String> names = new HashSet();names.add(postScriptName);names.add(postScriptName.replaceAll("-", ""));return names;}private List<String> copySubstitutes(String postScriptName) {return new ArrayList((Collection)this.substitutes.get(postScriptName));}public void addSubstitute(String match, String replace) {if (!this.substitutes.containsKey(match)) {this.substitutes.put(match, new ArrayList());}((List)this.substitutes.get(match)).add(replace);}private List<String> getSubstitutes(String postScriptName) {List<String> subs = (List)this.substitutes.get(postScriptName.replaceAll(" ", ""));return subs != null ? subs : Collections.emptyList();}private String getFallbackFontName(PDFontDescriptor fontDescriptor) {String fontName;if (fontDescriptor != null) {boolean isBold = false;String name = fontDescriptor.getFontName();if (name != null) {String lower = fontDescriptor.getFontName().toLowerCase();isBold = lower.contains("bold") || lower.contains("black") || lower.contains("heavy");}if (fontDescriptor.isFixedPitch()) {fontName = "Courier";if (isBold && fontDescriptor.isItalic()) {fontName = fontName + "-BoldOblique";} else if (isBold) {fontName = fontName + "-Bold";} else if (fontDescriptor.isItalic()) {fontName = fontName + "-Oblique";}} else if (fontDescriptor.isSerif()) {fontName = "Times";if (isBold && fontDescriptor.isItalic()) {fontName = fontName + "-BoldItalic";} else if (isBold) {fontName = fontName + "-Bold";} else if (fontDescriptor.isItalic()) {fontName = fontName + "-Italic";} else {fontName = fontName + "-Roman";}} else {fontName = "Helvetica";if (isBold && fontDescriptor.isItalic()) {fontName = fontName + "-BoldOblique";} else if (isBold) {fontName = fontName + "-Bold";} else if (fontDescriptor.isItalic()) {fontName = fontName + "-Oblique";}}} else {fontName = "Times-Roman";}return fontName;}public FontMapping<TrueTypeFont> getTrueTypeFont(String baseFont, PDFontDescriptor fontDescriptor) {TrueTypeFont ttf = (TrueTypeFont)this.findFont(FontFormat.TTF, baseFont);if (ttf != null) {return new FontMapping(ttf, false);} else {String fontName = this.getFallbackFontName(fontDescriptor);ttf = (TrueTypeFont)this.findFont(FontFormat.TTF, fontName);if (ttf == null) {ttf = this.lastResortFont;}return new FontMapping(ttf, true);}}public FontMapping<FontBoxFont> getFontBoxFont(String baseFont, PDFontDescriptor fontDescriptor) {FontBoxFont font = this.findFontBoxFont(baseFont);if (font != null) {return new FontMapping(font, false);} else {String fallbackName = this.getFallbackFontName(fontDescriptor);FontBoxFont font2 = this.findFontBoxFont(fallbackName);if (font2 == null) {font = this.lastResortFont;}else {font= font2;}return new FontMapping((FontBoxFont)font, true);}}private FontBoxFont findFontBoxFont(String postScriptName) {Type1Font t1 = (Type1Font)this.findFont(FontFormat.PFB, postScriptName);if (t1 != null) {return t1;} else {TrueTypeFont ttf = (TrueTypeFont)this.findFont(FontFormat.TTF, postScriptName);if (ttf != null) {return ttf;} else {OpenTypeFont otf = (OpenTypeFont)this.findFont(FontFormat.OTF, postScriptName);return otf != null ? otf : null;}}}private FontBoxFont findFont(FontFormat format, String postScriptName) {if (postScriptName == null) {return null;} else {if (this.fontProvider == null) {this.getProvider();}FontInfo info = this.getFont(format, postScriptName);if (info != null) {return info.getFont();} else {info = this.getFont(format, postScriptName.replaceAll("-", ""));if (info != null) {return info.getFont();} else {Iterator var4 = this.getSubstitutes(postScriptName).iterator();do {if (!var4.hasNext()) {info = this.getFont(format, postScriptName.replaceAll(",", "-"));if (info != null) {return info.getFont();}info = this.getFont(format, postScriptName + "-Regular");if (info != null) {return info.getFont();}return null;}String substituteName = (String)var4.next();info = this.getFont(format, substituteName);} while(info == null);return info.getFont();}}}}private FontInfo getFont(FontFormat format, String postScriptName) {if (postScriptName.contains("+")) {postScriptName = postScriptName.substring(postScriptName.indexOf(43) + 1);}FontInfo info = (FontInfo)this.fontInfoByName.get(postScriptName);return info != null && info.getFormat() == format ? info : null;}public CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor, PDCIDSystemInfo cidSystemInfo) {OpenTypeFont otf1 = (OpenTypeFont)this.findFont(FontFormat.OTF, baseFont);if (otf1 != null) {return new CIDFontMapping(otf1, (FontBoxFont)null, false);} else {TrueTypeFont ttf = (TrueTypeFont)this.findFont(FontFormat.TTF, baseFont);if (ttf != null) {return new CIDFontMapping((OpenTypeFont)null, ttf, false);} else {/*if (cidSystemInfo != null) {String collection = cidSystemInfo.getRegistry() + "-" + cidSystemInfo.getOrdering();if (collection.equals("Adobe-GB1") || collection.equals("Adobe-CNS1") || collection.equals("Adobe-Japan1") || collection.equals("Adobe-Korea1")) {PriorityQueue<FontMapperImpl.FontMatch> queue = this.getFontMatches(fontDescriptor, cidSystemInfo);FontMapperImpl.FontMatch bestMatch = (FontMapperImpl.FontMatch)queue.poll();if (bestMatch != null) {FontBoxFont font = bestMatch.info.getFont();if (font instanceof OpenTypeFont) {return new CIDFontMapping((OpenTypeFont)font, (FontBoxFont)null, true);}if (font != null) {return new CIDFontMapping((OpenTypeFont)null, font, true);}}}}*/return new CIDFontMapping((OpenTypeFont)null, this.lastResortFont, true);}}}private PriorityQueue<FontMapperImpl.FontMatch> getFontMatches(PDFontDescriptor fontDescriptor, PDCIDSystemInfo cidSystemInfo) {PriorityQueue<FontMapperImpl.FontMatch> queue = new PriorityQueue(20);Iterator var4 = this.fontInfoByName.values().iterator();while(true) {FontMapperImpl.FontMatch match;while(true) {FontInfo info;do {if (!var4.hasNext()) {return queue;}info = (FontInfo)var4.next();} while(cidSystemInfo != null && !this.isCharSetMatch(cidSystemInfo, info));match = new FontMapperImpl.FontMatch(info);if (fontDescriptor.getPanose() != null && info.getPanose() != null) {PDPanoseClassification panose = fontDescriptor.getPanose().getPanose();if (panose.getFamilyKind() != info.getPanose().getFamilyKind()) {break;}if (panose.getFamilyKind() == 0 && (info.getPostScriptName().toLowerCase().contains("barcode") || info.getPostScriptName().startsWith("Code")) && !this.probablyBarcodeFont(fontDescriptor)) {continue;}if (panose.getSerifStyle() == info.getPanose().getSerifStyle()) {match.score += 2.0D;} else if (panose.getSerifStyle() >= 2 && panose.getSerifStyle() <= 5 && info.getPanose().getSerifStyle() >= 2 && info.getPanose().getSerifStyle() <= 5) {++match.score;} else if (panose.getSerifStyle() >= 11 && panose.getSerifStyle() <= 13 && info.getPanose().getSerifStyle() >= 11 && info.getPanose().getSerifStyle() <= 13) {++match.score;} else if (panose.getSerifStyle() != 0 && info.getPanose().getSerifStyle() != 0) {--match.score;}int weight = info.getPanose().getWeight();int weightClass = info.getWeightClassAsPanose();if (Math.abs(weight - weightClass) > 2) {weight = weightClass;}if (panose.getWeight() == weight) {match.score += 2.0D;} else if (panose.getWeight() > 1 && weight > 1) {float dist = (float)Math.abs(panose.getWeight() - weight);match.score += 1.0D - (double)dist * 0.5D;}break;}if (fontDescriptor.getFontWeight() > 0.0F && info.getWeightClass() > 0) {float dist = Math.abs(fontDescriptor.getFontWeight() - (float)info.getWeightClass());match.score += 1.0D - (double)(dist / 100.0F) * 0.5D;}break;}queue.add(match);}}private boolean probablyBarcodeFont(PDFontDescriptor fontDescriptor) {String ff = fontDescriptor.getFontFamily();if (ff == null) {ff = "";}String fn = fontDescriptor.getFontName();if (fn == null) {fn = "";}return ff.startsWith("Code") || ff.toLowerCase().contains("barcode") || fn.startsWith("Code") || fn.toLowerCase().contains("barcode");}private boolean isCharSetMatch(PDCIDSystemInfo cidSystemInfo, FontInfo info) {if (info.getCIDSystemInfo() != null) {return info.getCIDSystemInfo().getRegistry().equals(cidSystemInfo.getRegistry()) && info.getCIDSystemInfo().getOrdering().equals(cidSystemInfo.getOrdering());} else {long codePageRange = info.getCodePageRange();long JIS_JAPAN = 131072L;long CHINESE_SIMPLIFIED = 262144L;long KOREAN_WANSUNG = 524288L;long CHINESE_TRADITIONAL = 1048576L;long KOREAN_JOHAB = 2097152L;if (cidSystemInfo.getOrdering().equals("GB1") && (codePageRange & CHINESE_SIMPLIFIED) == CHINESE_SIMPLIFIED) {return true;} else if (cidSystemInfo.getOrdering().equals("CNS1") && (codePageRange & CHINESE_TRADITIONAL) == CHINESE_TRADITIONAL) {return true;} else if (cidSystemInfo.getOrdering().equals("Japan1") && (codePageRange & JIS_JAPAN) == JIS_JAPAN) {return true;} else {return cidSystemInfo.getOrdering().equals("Korea1") && (codePageRange & KOREAN_WANSUNG) == KOREAN_WANSUNG || (codePageRange & KOREAN_JOHAB) == KOREAN_JOHAB;}}}private FontMapperImpl.FontMatch printMatches(PriorityQueue<FontMapperImpl.FontMatch> queue) {FontMapperImpl.FontMatch bestMatch = (FontMapperImpl.FontMatch)queue.peek();System.out.println("-------");while(!queue.isEmpty()) {FontMapperImpl.FontMatch match = (FontMapperImpl.FontMatch)queue.poll();FontInfo info = match.info;System.out.println(match.score + " | " + info.getMacStyle() + " " + info.getFamilyClass() + " " + info.getPanose() + " " + info.getCIDSystemInfo() + " " + info.getPostScriptName() + " " + info.getFormat());}System.out.println("-------");return bestMatch;}private static class FontMatch implements Comparable<FontMapperImpl.FontMatch> {double score;final FontInfo info;FontMatch(FontInfo info) {this.info = info;}public int compareTo(FontMapperImpl.FontMatch match) {return Double.compare(match.score, this.score);}}private static class DefaultFontProvider {private static final FontProvider INSTANCE;private DefaultFontProvider() {}static {INSTANCE = new FileSystemFontProvider(FontMapperImpl.fontCache);}}
}

说明:中间还注释了一段代码,即没有字体库会使用系统默认字体库的代码。各位看情况决定在各自系统中是否放开。

5.最终效果如下:

总结说明

1.个人非常不建议使用这种方式,因为此方式,一是乱了自己项目的结构,项目结构很难看,要是再遇到其他问题也是这么做,加各种开源项目的包名路径,大家可以想象最终项目结构了;二是需要在项目里使用字体包,字体包也很大,一般都是10~15m左右,若是使用多个字体包,那最后打的包也很大。好处是不是所有服务器都有对应的字体包,那运行在各环境也能正常显示中文字体,可以不需要麻烦运维在生产上去安装各种字体包(个人也是因为这原因才使用这种方式)。

2.个人推荐的方式,一是重写需要修改的源码部分并重新打包,使用特殊的版本号上传至maven私服,仅供自己项目使用;二是在对应系统环境安装所需字体包,这种亦是最方便的。

生成PDF并转图片丢失中文显示的问题相关推荐

  1. 使用itextpdf生成pdf,设置图片和中文

    依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artif ...

  2. java中生成pdf,插入图片,页眉、页脚、表格

    全栈工程师开发手册 (作者:栾鹏) java教程全解 java中生成pdf,插入图片,页眉.页脚.表格 import com.lowagie.text.*; import com.lowagie.te ...

  3. JAVA 使用Itext模板生成pdf,解决图片插入,文本域超出字体缩放,半自动换行

    1.前言 前一段时间遇到一个制作Pdf的业务,自己下来摸索了一下,基本上解决.将其中遇到的几个问题及解决方法做以记录,仅供大家参考. 首先在这里对于刚接触该类型业务的同学说明下,ItexPdf支持使用 ...

  4. itext生成pdf文档加载中文字体解决方法

    最近接手一个任务,在网页中通过用户的输入的信息生成一个pdf文档并且下载到用户本地.iText是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML. ...

  5. python 生成pdf 文字和图片_Python系列—PDF文本与图片抽取

    PDF是人们日常使用最多的跨平台文档.其是一种用独立于应用程序.硬件.操作系统的方式呈现文档的文件格式.每个PDF文件包含固定布局的平面文档的完整描述,包括文本.字形.图形及其他需要显示的信息.具有良 ...

  6. FreeMarker 模板生成 PDF电子凭证/图片

    一.场景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打印.目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户. ...

  7. 图片如何生成pdf格式?图片怎么生成pdf格式文件?

    图片如何生成pdf格式?平时的工作中我们在处理pdf文件的时候,难免会遇到各种各样的问题.有时候我们需要把图片生成pdf.可能还有些小伙伴不知道该怎么做,图片生成pdf其实很简单,下面给大家分享一个图 ...

  8. 使用Tcpdf生成pdf时没有图片的问题

    在生成pdf插入图片时使用了 $pdf->image方法进行渲染,发现图片渲染不了,解决方法是在用image方法之前使用 $pdf->AddPage(); 但是这样会使图片和文字重叠,所以 ...

  9. qt生成pdf(用图片qgrabwidget抓取图片生成PDF;用文字生成pdf)

    1.用图片生成PDF: QPrinter printerPixmap(QPrinter::HighResolution);printerPixmap.setPageSize(QPrinter::A4) ...

最新文章

  1. 深入分析Java单例模式的各种方案
  2. 2020牛客多校第5场B-Graph完全图异或最小生成树
  3. 块级元素 Vs 内联元素
  4. 4E4 models
  5. [BZOJ 1047] [HAOI2007] 理想的正方形 【单调队列】
  6. Android—内存泄漏、GC及LeakCanary源码解析
  7. linux命令编写,编写简单的linux命令
  8. ubuntu 10.4非法关机后上不了网
  9. python 保留顺序去重_Python入门很简单,只要掌握3456点
  10. 【语音去噪】基于matlab GUI傅立叶变换语音降噪混频【含Matlab源码 297期】
  11. html embed自动播放,embed嵌入多个优酷视频并自动播放
  12. WEBSHELL 提权方法总结
  13. 第一章 核磁共振的物理学基础
  14. Mr. Panda and Fantastic Beasts(EC2016 后缀数组)
  15. JMF(java media framework)综述
  16. 生育指南(写给临产准妈妈)
  17. 如何用TensorFlow图像处理函数裁剪图像?
  18. Java基础361问第5问——equals和==的区别
  19. 终于明白了异地恋为什么那么难
  20. 这应该是关于GPS定位写得最详实清晰的文章之一

热门文章

  1. 有了这些互动小游戏,知识竞赛更精彩了
  2. 小程序音视频背后的故事
  3. [QQ机器人]nonebot2土味情话插件
  4. pandas 数据输出不对齐
  5. KMPlayer 去广告
  6. 网络原理课设——IP协议分析
  7. NFS网络文件共享服务
  8. C语言程序设计之恶搞关机程序
  9. IDEA必备插件、阿里巴巴规范插件(代码格式化,注释模板化)的安装及使用和快捷键设置
  10. 【Unity3D】二、制作滚球游戏学习Unity3D(下)