1
24 package net.sf.jasperreports.engine.fonts;
25
26 import java.awt.Font;
27 import java.awt.FontFormatException;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.lang.ref.ReferenceQueue;
31 import java.lang.ref.WeakReference;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.StandardCopyOption;
35 import java.util.Map;
36 import java.util.concurrent.ConcurrentHashMap;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 import net.sf.jasperreports.engine.JRException;
42 import net.sf.jasperreports.engine.JasperReportsContext;
43 import net.sf.jasperreports.repo.RepositoryUtil;
44
45
48 public class AwtFontManager
49 {
50
51 private static final Log log = LogFactory.getLog(AwtFontManager.class);
52
53 private static final AwtFontManager INSTANCE = new AwtFontManager();
54
55 public static AwtFontManager instance()
56 {
57 return INSTANCE;
58 }
59
60 private Map<FontFileReference, Object> fontFileReferences;
61 private ReferenceQueue<Font> fontFilesQueue;
62
63 public AwtFontManager()
64 {
65 fontFileReferences = new ConcurrentHashMap<>();
66 fontFilesQueue = new ReferenceQueue<>();
67 }
68
69 public Font getAwtFont(JasperReportsContext jasperReportsContext, String ttfLocation)
70 {
71 purgeFontFiles();
72
73 InputStream is = null;
74 Path fontFile;
75 try
76 {
77 is = RepositoryUtil.getInstance(jasperReportsContext).getInputStreamFromLocation(ttfLocation);
78
79 fontFile = Files.createTempFile("jr-font", ".ttf");
80 fontFile.toFile().deleteOnExit();
81
82 if (log.isDebugEnabled())
83 {
84 log.debug("created font file " + fontFile + " for " + ttfLocation);
85 }
86
87 Files.copy(is, fontFile, StandardCopyOption.REPLACE_EXISTING);
88
89 Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile.toFile());
90
91 FontFileReference fontFileReference = new FontFileReference(font, fontFilesQueue, fontFile);
92 fontFileReferences.put(fontFileReference, Boolean.TRUE);
93
94 return font;
95 }
96 catch (JRException | IOException | FontFormatException e)
97 {
98 throw new InvalidFontException(ttfLocation, e);
99 }
100 finally
101 {
102 try
103 {
104 if (is != null)
105 {
106 is.close();
107 }
108 }
109 catch (IOException e)
110 {
111 }
112 }
113 }
114
115 public void purgeFontFiles()
116 {
117 FontFileReference fontFileRef;
118 while ((fontFileRef = (FontFileReference) fontFilesQueue.poll()) != null)
119 {
120 fontFileReferences.remove(fontFileRef);
121
122 try
123 {
124 Files.deleteIfExists(fontFileRef.fontFile);
125 }
126 catch (IOException e)
127 {
128 if (log.isDebugEnabled())
129 {
130 log.debug("Failed to delete font file " + fontFileRef.fontFile);
131 }
132 }
133 }
134 }
135
136 private static class FontFileReference extends WeakReference<Font>
137 {
138 Path fontFile;
139
140 FontFileReference(Font font, ReferenceQueue<Font> queue, Path fontFile)
141 {
142 super(font, queue);
143
144 this.fontFile = fontFile;
145 }
146 }
147
148 }
149