解决思路就是修改源码,过滤掉mstmc.ttf文件读取,具体操作如下:

1、在自己的项目中新建包结构为:org.apache.pdfbox.pdmodel.font

2、新建FileSystemFontProvider.java文件,将下方代码复制进去即可

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pdfbox.pdmodel.font;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fontbox.FontBoxFont;
import org.apache.fontbox.cff.CFFCIDFont;
import org.apache.fontbox.cff.CFFFont;
import org.apache.fontbox.ttf.NamingTable;
import org.apache.fontbox.ttf.OS2WindowsMetricsTable;
import org.apache.fontbox.ttf.OTFParser;
import org.apache.fontbox.ttf.OpenTypeFont;
import org.apache.fontbox.ttf.TTFParser;
import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.fontbox.ttf.TrueTypeCollection.TrueTypeFontProcessor;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.fontbox.type1.Type1Font;
import org.apache.fontbox.util.autodetect.FontFileFinder;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.util.Charsets;

/**
 * A FontProvider which searches for fonts on the local filesystem.
 *
 * @author John Hewson
 */
final class FileSystemFontProvider extends FontProvider {
	private static final Log LOG = LogFactory.getLog(FileSystemFontProvider.class);

	private final List<FSFontInfo> fontInfoList = new ArrayList<FSFontInfo>();
	private final FontCache cache;

	private static class FSFontInfo extends FontInfo {
		private final String postScriptName;
		private final FontFormat format;
		private final CIDSystemInfo cidSystemInfo;
		private final int usWeightClass;
		private final int sFamilyClass;
		private final int ulCodePageRange1;
		private final int ulCodePageRange2;
		private final int macStyle;
		private final PDPanoseClassification panose;
		private final File file;
		private final FileSystemFontProvider parent;

		private FSFontInfo(File file, FontFormat format, String postScriptName, CIDSystemInfo cidSystemInfo,
				int usWeightClass, int sFamilyClass, int ulCodePageRange1, int ulCodePageRange2, int macStyle,
				byte[] panose, FileSystemFontProvider parent) {
			this.file = file;
			this.format = format;
			this.postScriptName = postScriptName;
			this.cidSystemInfo = cidSystemInfo;
			this.usWeightClass = usWeightClass;
			this.sFamilyClass = sFamilyClass;
			this.ulCodePageRange1 = ulCodePageRange1;
			this.ulCodePageRange2 = ulCodePageRange2;
			this.macStyle = macStyle;
			this.panose = panose != null && panose.length >= PDPanoseClassification.LENGTH
					? new PDPanoseClassification(panose)
					: null;
			this.parent = parent;
		}

		@Override
		public String getPostScriptName() {
			return postScriptName;
		}

		@Override
		public FontFormat getFormat() {
			return format;
		}

		@Override
		public CIDSystemInfo getCIDSystemInfo() {
			return cidSystemInfo;
		}

		/**
		 * {@inheritDoc}
		 * <p>
		 * The method returns null if there is there was an error opening the font.
		 * 
		 */
		@Override
		public synchronized FontBoxFont getFont() {
			// synchronized to avoid race condition on cache access,
			// which could result in an unreferenced but open font
			FontBoxFont cached = parent.cache.getFont(this);
			if (cached != null) {
				return cached;
			} else {
				FontBoxFont font;
				switch (format) {
				case PFB:
					font = getType1Font(postScriptName, file);
					break;
				case TTF:
					font = getTrueTypeFont(postScriptName, file);
					break;
				case OTF:
					font = getOTFFont(postScriptName, file);
					break;
				default:
					throw new RuntimeException("can't happen");
				}
				if (font != null) {
					parent.cache.addFont(this, font);
				}
				return font;
			}
		}

		@Override
		public int getFamilyClass() {
			return sFamilyClass;
		}

		@Override
		public int getWeightClass() {
			return usWeightClass;
		}

		@Override
		public int getCodePageRange1() {
			return ulCodePageRange1;
		}

		@Override
		public int getCodePageRange2() {
			return ulCodePageRange2;
		}

		@Override
		public int getMacStyle() {
			return macStyle;
		}

		@Override
		public PDPanoseClassification getPanose() {
			return panose;
		}

		@Override
		public String toString() {
			return super.toString() + " " + file;
		}

		private TrueTypeFont getTrueTypeFont(String postScriptName, File file) {
			try {
				TrueTypeFont ttf = readTrueTypeFont(postScriptName, file);

				if (LOG.isDebugEnabled()) {
					LOG.debug("Loaded " + postScriptName + " from " + file);
				}
				return ttf;
			} catch (IOException e) {
				LOG.warn("Could not load font file: " + file, e);
			}
			return null;
		}

		private TrueTypeFont readTrueTypeFont(String postScriptName, File file) throws IOException {
			if (file.getName().toLowerCase().endsWith(".ttc")) {
				@SuppressWarnings("squid:S2095")
				// ttc not closed here because it is needed later when ttf is accessed,
				// e.g. rendering PDF with non-embedded font which is in ttc file in our font
				// directory
				TrueTypeCollection ttc = new TrueTypeCollection(file);
				TrueTypeFont ttf;
				try {
					ttf = ttc.getFontByName(postScriptName);
				} catch (IOException ex) {
					ttc.close();
					throw ex;
				}
				if (ttf == null) {
					ttc.close();
					throw new IOException("Font " + postScriptName + " not found in " + file);
				}
				return ttf;
			} else {
				TTFParser ttfParser = new TTFParser(false, true);
				return ttfParser.parse(file);
			}
		}

		private OpenTypeFont getOTFFont(String postScriptName, File file) {
			try {
				if (file.getName().toLowerCase().endsWith(".ttc")) {
					@SuppressWarnings("squid:S2095")
					// ttc not closed here because it is needed later when ttf is accessed,
					// e.g. rendering PDF with non-embedded font which is in ttc file in our font
					// directory
					TrueTypeCollection ttc = new TrueTypeCollection(file);
					TrueTypeFont ttf;
					try {
						ttf = ttc.getFontByName(postScriptName);
					} catch (IOException ex) {
						LOG.error(ex.getMessage(), ex);
						ttc.close();
						return null;
					}
					if (ttf == null) {
						ttc.close();
						throw new IOException("Font " + postScriptName + " not found in " + file);
					}
					return (OpenTypeFont) ttf;
				}

				OTFParser parser = new OTFParser(false, true);
				OpenTypeFont otf = parser.parse(file);

				if (LOG.isDebugEnabled()) {
					LOG.debug("Loaded " + postScriptName + " from " + file);
				}
				return otf;
			} catch (IOException e) {
				LOG.warn("Could not load font file: " + file, e);
			}
			return null;
		}

		private Type1Font getType1Font(String postScriptName, File file) {
			InputStream input = null;
			try {
				input = new FileInputStream(file);
				Type1Font type1 = Type1Font.createWithPFB(input);

				if (LOG.isDebugEnabled()) {
					LOG.debug("Loaded " + postScriptName + " from " + file);
				}
				return type1;
			} catch (IOException e) {
				LOG.warn("Could not load font file: " + file, e);
			} finally {
				IOUtils.closeQuietly(input);
			}
			return null;
		}
	}

	/**
	 * Represents ignored fonts (i.e. bitmap fonts).
	 */
	private static final class FSIgnored extends FSFontInfo {
		private FSIgnored(File file, FontFormat format, String postScriptName) {
			super(file, format, postScriptName, null, 0, 0, 0, 0, 0, null, null);
		}
	}

	/**
	 * Constructor.
	 */
	FileSystemFontProvider(FontCache cache) {
		this.cache = cache;
		try {
			if (LOG.isTraceEnabled()) {
				LOG.trace("Will search the local system for fonts");
			}

			// scan the local system for font files
			FontFileFinder fontFileFinder = new FontFileFinder();
			List<URI> fonts = fontFileFinder.find();
			List<File> files = new ArrayList<File>(fonts.size());
			for (URI font : fonts) {
				files.add(new File(font));
			}

			if (LOG.isTraceEnabled()) {
				LOG.trace("Found " + files.size() + " fonts on the local system");
			}

			if (!files.isEmpty()) {
				// load cached FontInfo objects
				List<FSFontInfo> cachedInfos = loadDiskCache(files);
				if (cachedInfos != null && !cachedInfos.isEmpty()) {
					fontInfoList.addAll(cachedInfos);
				} else {
					LOG.warn("Building on-disk font cache, this may take a while");
					scanFonts(files);
					saveDiskCache();
					LOG.warn("Finished building on-disk font cache, found " + fontInfoList.size() + " fonts");
				}
			}
		} catch (AccessControlException e) {
			LOG.error("Error accessing the file system", e);
		}
	}

	private void scanFonts(List<File> files) {
		for (File file : files) {
			try {
				String filePath = file.getPath().toLowerCase();
				// 解决pdfbox Could not load font file: C:\WINDOWS\FONTS\mstmc.ttf
				// java.io.EOFException
				if (filePath.contains("mstmc.ttf")) {
					continue;
				} else if (filePath.endsWith(".ttf") || filePath.endsWith(".otf")) {
					addTrueTypeFont(file);
				} else if (filePath.endsWith(".ttc") || filePath.endsWith(".otc")) {
					addTrueTypeCollection(file);
				} else if (filePath.endsWith(".pfb")) {
					addType1Font(file);
				}
			} catch (IOException e) {
				LOG.warn("Error parsing font " + file.getPath(), e);
			}
		}
	}

	private File getDiskCacheFile() {
		String path = System.getProperty("pdfbox.fontcache");
		if (path == null || !new File(path).isDirectory() || !new File(path).canWrite()) {
			path = System.getProperty("user.home");
			if (path == null || !new File(path).isDirectory() || !new File(path).canWrite()) {
				path = System.getProperty("java.io.tmpdir");
			}
		}
		return new File(path, ".pdfbox.cache");
	}

	/**
	 * Saves the font metadata cache to disk.
	 */
	private void saveDiskCache() {
		BufferedWriter writer = null;
		try {
			try {
				File file = getDiskCacheFile();
				writer = new BufferedWriter(new FileWriter(file));
			} catch (SecurityException e) {
				return;
			}

			for (FSFontInfo fontInfo : fontInfoList) {
				writer.write(fontInfo.postScriptName.trim());
				writer.write("|");
				writer.write(fontInfo.format.toString());
				writer.write("|");
				if (fontInfo.cidSystemInfo != null) {
					writer.write(fontInfo.cidSystemInfo.getRegistry() + '-' + fontInfo.cidSystemInfo.getOrdering() + '-'
							+ fontInfo.cidSystemInfo.getSupplement());
				}
				writer.write("|");
				if (fontInfo.usWeightClass > -1) {
					writer.write(Integer.toHexString(fontInfo.usWeightClass));
				}
				writer.write("|");
				if (fontInfo.sFamilyClass > -1) {
					writer.write(Integer.toHexString(fontInfo.sFamilyClass));
				}
				writer.write("|");
				writer.write(Integer.toHexString(fontInfo.ulCodePageRange1));
				writer.write("|");
				writer.write(Integer.toHexString(fontInfo.ulCodePageRange2));
				writer.write("|");
				if (fontInfo.macStyle > -1) {
					writer.write(Integer.toHexString(fontInfo.macStyle));
				}
				writer.write("|");
				if (fontInfo.panose != null) {
					byte[] bytes = fontInfo.panose.getBytes();
					for (int i = 0; i < 10; i++) {
						String str = Integer.toHexString(bytes[i]);
						if (str.length() == 1) {
							writer.write('0');
						}
						writer.write(str);
					}
				}
				writer.write("|");
				writer.write(fontInfo.file.getAbsolutePath());
				writer.newLine();
			}
		} catch (IOException e) {
			LOG.warn("Could not write to font cache", e);
			LOG.warn("Installed fonts information will have to be reloaded for each start");
			LOG.warn("You can assign a directory to the 'pdfbox.fontcache' property");
		} finally {
			IOUtils.closeQuietly(writer);
		}
	}

	/**
	 * Loads the font metadata cache from disk.
	 */
	private List<FSFontInfo> loadDiskCache(List<File> files) {
		Set<String> pending = new HashSet<String>(files.size());
		for (File file : files) {
			pending.add(file.getAbsolutePath());
		}

		List<FSFontInfo> results = new ArrayList<FSFontInfo>();

		// Get the disk cache
		File file = null;
		boolean fileExists = false;
		try {
			file = getDiskCacheFile();
			fileExists = file.exists();
		} catch (SecurityException e) {
		}

		if (fileExists) {
			BufferedReader reader = null;
			try {
				reader = new BufferedReader(new FileReader(file));
				String line;
				while ((line = reader.readLine()) != null) {
					String[] parts = line.split("\\|", 10);
					if (parts.length < 10) {
						LOG.warn("Incorrect line '" + line + "' in font disk cache is skipped");
						continue;
					}

					String postScriptName;
					FontFormat format;
					CIDSystemInfo cidSystemInfo = null;
					int usWeightClass = -1;
					int sFamilyClass = -1;
					int ulCodePageRange1;
					int ulCodePageRange2;
					int macStyle = -1;
					byte[] panose = null;
					File fontFile;

					postScriptName = parts[0];
					format = FontFormat.valueOf(parts[1]);
					if (parts[2].length() > 0) {
						String[] ros = parts[2].split("-");
						cidSystemInfo = new CIDSystemInfo(ros[0], ros[1], Integer.parseInt(ros[2]));
					}
					if (parts[3].length() > 0) {
						usWeightClass = (int) Long.parseLong(parts[3], 16);
					}
					if (parts[4].length() > 0) {
						sFamilyClass = (int) Long.parseLong(parts[4], 16);
					}
					ulCodePageRange1 = (int) Long.parseLong(parts[5], 16);
					ulCodePageRange2 = (int) Long.parseLong(parts[6], 16);
					if (parts[7].length() > 0) {
						macStyle = (int) Long.parseLong(parts[7], 16);
					}
					if (parts[8].length() > 0) {
						panose = new byte[10];
						for (int i = 0; i < 10; i++) {
							String str = parts[8].substring(i * 2, i * 2 + 2);
							int b = Integer.parseInt(str, 16);
							panose[i] = (byte) (b & 0xff);
						}
					}
					fontFile = new File(parts[9]);
					if (fontFile.exists()) {
						FSFontInfo info = new FSFontInfo(fontFile, format, postScriptName, cidSystemInfo, usWeightClass,
								sFamilyClass, ulCodePageRange1, ulCodePageRange2, macStyle, panose, this);
						results.add(info);
					} else {
						LOG.debug("Font file " + fontFile.getAbsolutePath() + " not found, skipped");
					}
					pending.remove(fontFile.getAbsolutePath());
				}
			} catch (IOException e) {
				LOG.warn("Error loading font cache, will be re-built", e);
				return null;
			} finally {
				IOUtils.closeQuietly(reader);
			}
		}

		if (!pending.isEmpty()) {
			// re-build the entire cache if we encounter un-cached fonts (could be
			// optimised)
			LOG.warn("New fonts found, font cache will be re-built");
			return null;
		}

		return results;
	}

	/**
	 * Adds a TTC or OTC to the file cache. To reduce memory, the parsed font is not
	 * cached.
	 */
	private void addTrueTypeCollection(final File ttcFile) throws IOException {
		TrueTypeCollection ttc = null;
		try {
			ttc = new TrueTypeCollection(ttcFile);
			ttc.processAllFonts(new TrueTypeFontProcessor() {
				@Override
				public void process(TrueTypeFont ttf) throws IOException {
					addTrueTypeFontImpl(ttf, ttcFile);
				}
			});
		} catch (IOException e) {
			LOG.warn("Could not load font file: " + ttcFile, e);
		} finally {
			if (ttc != null) {
				ttc.close();
			}
		}
	}

	/**
	 * Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font
	 * is not cached.
	 */
	private void addTrueTypeFont(File ttfFile) throws IOException {
		try {
			if (ttfFile.getPath().toLowerCase().endsWith(".otf")) {
				OTFParser parser = new OTFParser(false, true);
				OpenTypeFont otf = parser.parse(ttfFile);
				addTrueTypeFontImpl(otf, ttfFile);
			} else {
				TTFParser parser = new TTFParser(false, true);
				TrueTypeFont ttf = parser.parse(ttfFile);
				addTrueTypeFontImpl(ttf, ttfFile);
			}
		} catch (IOException e) {
			LOG.warn("Could not load font file: " + ttfFile, e);
		}
	}

	/**
	 * Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font
	 * is not cached.
	 */
	private void addTrueTypeFontImpl(TrueTypeFont ttf, File file) throws IOException {
		try {
			// read PostScript name, if any
			if (ttf.getName() != null && ttf.getName().contains("|")) {
				fontInfoList.add(new FSIgnored(file, FontFormat.TTF, "*skippipeinname*"));
				LOG.warn("Skipping font with '|' in name " + ttf.getName() + " in file " + file);
			} else if (ttf.getName() != null) {
				// ignore bitmap fonts
				if (ttf.getHeader() == null) {
					fontInfoList.add(new FSIgnored(file, FontFormat.TTF, ttf.getName()));
					return;
				}
				int macStyle = ttf.getHeader().getMacStyle();

				int sFamilyClass = -1;
				int usWeightClass = -1;
				int ulCodePageRange1 = 0;
				int ulCodePageRange2 = 0;
				byte[] panose = null;
				OS2WindowsMetricsTable os2WindowsMetricsTable = ttf.getOS2Windows();
				// Apple's AAT fonts don't have an OS/2 table
				if (os2WindowsMetricsTable != null) {
					sFamilyClass = os2WindowsMetricsTable.getFamilyClass();
					usWeightClass = os2WindowsMetricsTable.getWeightClass();
					ulCodePageRange1 = (int) os2WindowsMetricsTable.getCodePageRange1();
					ulCodePageRange2 = (int) os2WindowsMetricsTable.getCodePageRange2();
					panose = os2WindowsMetricsTable.getPanose();
				}

				String format;
				if (ttf instanceof OpenTypeFont && ((OpenTypeFont) ttf).isPostScript()) {
					format = "OTF";
					CFFFont cff = ((OpenTypeFont) ttf).getCFF().getFont();
					CIDSystemInfo ros = null;
					if (cff instanceof CFFCIDFont) {
						CFFCIDFont cidFont = (CFFCIDFont) cff;
						String registry = cidFont.getRegistry();
						String ordering = cidFont.getOrdering();
						int supplement = cidFont.getSupplement();
						ros = new CIDSystemInfo(registry, ordering, supplement);
					}
					fontInfoList.add(new FSFontInfo(file, FontFormat.OTF, ttf.getName(), ros, usWeightClass,
							sFamilyClass, ulCodePageRange1, ulCodePageRange2, macStyle, panose, this));
				} else {
					CIDSystemInfo ros = null;
					if (ttf.getTableMap().containsKey("gcid")) {
						// Apple's AAT fonts have a "gcid" table with CID info
						byte[] bytes = ttf.getTableBytes(ttf.getTableMap().get("gcid"));
						String reg = new String(bytes, 10, 64, Charsets.US_ASCII);
						String registryName = reg.substring(0, reg.indexOf('\0'));
						String ord = new String(bytes, 76, 64, Charsets.US_ASCII);
						String orderName = ord.substring(0, ord.indexOf('\0'));
						int supplementVersion = bytes[140] << 8 & (bytes[141] & 0xFF);
						ros = new CIDSystemInfo(registryName, orderName, supplementVersion);
					}

					format = "TTF";
					fontInfoList.add(new FSFontInfo(file, FontFormat.TTF, ttf.getName(), ros, usWeightClass,
							sFamilyClass, ulCodePageRange1, ulCodePageRange2, macStyle, panose, this));
				}

				if (LOG.isTraceEnabled()) {
					NamingTable name = ttf.getNaming();
					if (name != null) {
						LOG.trace(format + ": '" + name.getPostScriptName() + "' / '" + name.getFontFamily() + "' / '"
								+ name.getFontSubFamily() + "'");
					}
				}
			} else {
				fontInfoList.add(new FSIgnored(file, FontFormat.TTF, "*skipnoname*"));
				LOG.warn("Missing 'name' entry for PostScript name in font " + file);
			}
		} catch (IOException e) {
			fontInfoList.add(new FSIgnored(file, FontFormat.TTF, "*skipexception*"));
			LOG.warn("Could not load font file: " + file, e);
		} finally {
			ttf.close();
		}
	}

	/**
	 * Adds a Type 1 font to the file cache. To reduce memory, the parsed font is
	 * not cached.
	 */
	private void addType1Font(File pfbFile) throws IOException {
		InputStream input = new FileInputStream(pfbFile);
		try {
			Type1Font type1 = Type1Font.createWithPFB(input);
			if (type1.getName() == null) {
				fontInfoList.add(new FSIgnored(pfbFile, FontFormat.PFB, "*skipnoname*"));
				LOG.warn("Missing 'name' entry for PostScript name in font " + pfbFile);
				return;
			}
			if (type1.getName().contains("|")) {
				fontInfoList.add(new FSIgnored(pfbFile, FontFormat.PFB, "*skippipeinname*"));
				LOG.warn("Skipping font with '|' in name " + type1.getName() + " in file " + pfbFile);
				return;
			}
			fontInfoList
					.add(new FSFontInfo(pfbFile, FontFormat.PFB, type1.getName(), null, -1, -1, 0, 0, -1, null, this));

			if (LOG.isTraceEnabled()) {
				LOG.trace("PFB: '" + type1.getName() + "' / '" + type1.getFamilyName() + "' / '" + type1.getWeight()
						+ "'");
			}
		} catch (IOException e) {
			LOG.warn("Could not load font file: " + pfbFile, e);
		} finally {
			input.close();
		}
	}

	@Override
	public String toDebugString() {
		StringBuilder sb = new StringBuilder();
		for (FSFontInfo info : fontInfoList) {
			sb.append(info.getFormat());
			sb.append(": ");
			sb.append(info.getPostScriptName());
			sb.append(": ");
			sb.append(info.file.getPath());
			sb.append('\n');
		}
		return sb.toString();
	}

	@Override
	public List<? extends FontInfo> getFontInfo() {
		return fontInfoList;
	}
}

如:

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐