You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XSLFFontInfo.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.xslf.usermodel;
  20. import java.awt.Font;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.io.OutputStream;
  24. import java.util.ArrayList;
  25. import java.util.Collections;
  26. import java.util.List;
  27. import java.util.stream.Collectors;
  28. import java.util.stream.Stream;
  29. import org.apache.poi.common.usermodel.fonts.FontCharset;
  30. import org.apache.poi.common.usermodel.fonts.FontFacet;
  31. import org.apache.poi.common.usermodel.fonts.FontFamily;
  32. import org.apache.poi.common.usermodel.fonts.FontHeader;
  33. import org.apache.poi.common.usermodel.fonts.FontInfo;
  34. import org.apache.poi.common.usermodel.fonts.FontPitch;
  35. import org.apache.poi.ooxml.POIXMLDocumentPart;
  36. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  37. import org.apache.poi.util.IOUtils;
  38. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
  39. import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontDataId;
  40. import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontList;
  41. import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontListEntry;
  42. import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation;
  43. @SuppressWarnings("WeakerAccess")
  44. public class XSLFFontInfo implements FontInfo {
  45. final XMLSlideShow ppt;
  46. final String typeface;
  47. final CTEmbeddedFontListEntry fontListEntry;
  48. public XSLFFontInfo(XMLSlideShow ppt, String typeface) {
  49. this.ppt = ppt;
  50. this.typeface = typeface;
  51. final CTPresentation pres = ppt.getCTPresentation();
  52. CTEmbeddedFontList fontList = pres.isSetEmbeddedFontLst()
  53. ? pres.getEmbeddedFontLst() : pres.addNewEmbeddedFontLst();
  54. for (CTEmbeddedFontListEntry fe : fontList.getEmbeddedFontArray()) {
  55. if (typeface.equalsIgnoreCase(fe.getFont().getTypeface())) {
  56. fontListEntry = fe;
  57. return;
  58. }
  59. }
  60. fontListEntry = fontList.addNewEmbeddedFont();
  61. fontListEntry.addNewFont().setTypeface(typeface);
  62. }
  63. public XSLFFontInfo(XMLSlideShow ppt, CTEmbeddedFontListEntry fontListEntry) {
  64. this.ppt = ppt;
  65. this.typeface = fontListEntry.getFont().getTypeface();
  66. this.fontListEntry = fontListEntry;
  67. }
  68. @Override
  69. public String getTypeface() {
  70. return getFont().getTypeface();
  71. }
  72. @Override
  73. public void setTypeface(String typeface) {
  74. getFont().setTypeface(typeface);
  75. }
  76. @Override
  77. public FontCharset getCharset() {
  78. return FontCharset.valueOf(getFont().getCharset());
  79. }
  80. @Override
  81. public void setCharset(FontCharset charset) {
  82. getFont().setCharset((byte)charset.getNativeId());
  83. }
  84. @Override
  85. public FontFamily getFamily() {
  86. return FontFamily.valueOfPitchFamily(getFont().getPitchFamily());
  87. }
  88. @Override
  89. public void setFamily(FontFamily family) {
  90. byte pitchAndFamily = getFont().getPitchFamily();
  91. FontPitch pitch = FontPitch.valueOfPitchFamily(pitchAndFamily);
  92. getFont().setPitchFamily(FontPitch.getNativeId(pitch, family));
  93. }
  94. @Override
  95. public FontPitch getPitch() {
  96. return FontPitch.valueOfPitchFamily(getFont().getPitchFamily());
  97. }
  98. @Override
  99. public void setPitch(FontPitch pitch) {
  100. byte pitchAndFamily = getFont().getPitchFamily();
  101. FontFamily family = FontFamily.valueOfPitchFamily(pitchAndFamily);
  102. getFont().setPitchFamily(FontPitch.getNativeId(pitch, family));
  103. }
  104. @Override
  105. public byte[] getPanose() {
  106. return getFont().getPanose();
  107. }
  108. @Override
  109. public List<FontFacet> getFacets() {
  110. List<FontFacet> facetList = new ArrayList<>();
  111. if (fontListEntry.isSetRegular()) {
  112. facetList.add(new XSLFFontFacet((fontListEntry.getRegular())));
  113. }
  114. if (fontListEntry.isSetItalic()) {
  115. facetList.add(new XSLFFontFacet((fontListEntry.getItalic())));
  116. }
  117. if (fontListEntry.isSetBold()) {
  118. facetList.add(new XSLFFontFacet((fontListEntry.getBold())));
  119. }
  120. if (fontListEntry.isSetBoldItalic()) {
  121. facetList.add(new XSLFFontFacet((fontListEntry.getBoldItalic())));
  122. }
  123. return facetList;
  124. }
  125. public FontFacet addFacet(InputStream fontData) throws IOException {
  126. FontHeader header = new FontHeader();
  127. InputStream is = header.bufferInit(fontData);
  128. final CTPresentation pres = ppt.getCTPresentation();
  129. pres.setEmbedTrueTypeFonts(true);
  130. pres.setSaveSubsetFonts(true);
  131. final CTEmbeddedFontDataId dataId;
  132. final int style =
  133. (header.getWeight() > 400 ? Font.BOLD : Font.PLAIN) |
  134. (header.isItalic() ? Font.ITALIC : Font.PLAIN);
  135. switch (style) {
  136. case Font.PLAIN:
  137. dataId = fontListEntry.isSetRegular()
  138. ? fontListEntry.getRegular() : fontListEntry.addNewRegular();
  139. break;
  140. case Font.BOLD:
  141. dataId = fontListEntry.isSetBold()
  142. ? fontListEntry.getBold() : fontListEntry.addNewBold();
  143. break;
  144. case Font.ITALIC:
  145. dataId = fontListEntry.isSetItalic()
  146. ? fontListEntry.getItalic() : fontListEntry.addNewItalic();
  147. break;
  148. default:
  149. dataId = fontListEntry.isSetBoldItalic()
  150. ? fontListEntry.getBoldItalic() : fontListEntry.addNewBoldItalic();
  151. break;
  152. }
  153. XSLFFontFacet facet = new XSLFFontFacet(dataId);
  154. facet.setFontData(is);
  155. return facet;
  156. }
  157. private final class XSLFFontFacet implements FontFacet {
  158. private final CTEmbeddedFontDataId fontEntry;
  159. private final FontHeader header = new FontHeader();
  160. private XSLFFontFacet(CTEmbeddedFontDataId fontEntry) {
  161. this.fontEntry = fontEntry;
  162. }
  163. @Override
  164. public int getWeight() {
  165. init();
  166. return header.getWeight();
  167. }
  168. @Override
  169. public boolean isItalic() {
  170. init();
  171. return header.isItalic();
  172. }
  173. @Override
  174. public XSLFFontData getFontData() {
  175. return ppt.getRelationPartById(fontEntry.getId()).getDocumentPart();
  176. }
  177. void setFontData(InputStream is) throws IOException {
  178. final XSLFRelation fntRel = XSLFRelation.FONT;
  179. final String relId = fontEntry.getId();
  180. final XSLFFontData fntData;
  181. if (relId == null || relId.isEmpty()) {
  182. final int fntDataIdx;
  183. try {
  184. fntDataIdx = ppt.getPackage().getUnusedPartIndex(fntRel.getDefaultFileName());
  185. } catch (InvalidFormatException e) {
  186. throw new RuntimeException(e);
  187. }
  188. POIXMLDocumentPart.RelationPart rp = ppt.createRelationship(fntRel, XSLFFactory.getInstance(), fntDataIdx, false);
  189. fntData = rp.getDocumentPart();
  190. fontEntry.setId(rp.getRelationship().getId());
  191. } else {
  192. fntData = (XSLFFontData)ppt.getRelationById(relId);
  193. }
  194. assert (fntData != null);
  195. try (OutputStream os = fntData.getOutputStream()) {
  196. IOUtils.copy(is, os);
  197. }
  198. }
  199. private void init() {
  200. if (header.getFamilyName() == null) {
  201. try (InputStream is = getFontData().getInputStream()) {
  202. byte[] buf = IOUtils.toByteArray(is, 1000);
  203. header.init(buf, 0, buf.length);
  204. } catch (IOException e) {
  205. // TODO: better exception class
  206. throw new RuntimeException(e);
  207. }
  208. }
  209. }
  210. }
  211. private CTTextFont getFont() {
  212. return fontListEntry.getFont();
  213. }
  214. /**
  215. * Adds or updates a (MTX-) font
  216. * @param ppt the slideshow which will contain the font
  217. * @param fontStream the (MTX) font data as stream
  218. * @return a font data object
  219. * @throws IOException if the font data can't be stored
  220. *
  221. * @since POI 4.1.0
  222. */
  223. public static XSLFFontInfo addFontToSlideShow(XMLSlideShow ppt, InputStream fontStream)
  224. throws IOException {
  225. FontHeader header = new FontHeader();
  226. InputStream is = header.bufferInit(fontStream);
  227. XSLFFontInfo fontInfo = new XSLFFontInfo(ppt, header.getFamilyName());
  228. fontInfo.addFacet(is);
  229. return fontInfo;
  230. }
  231. /**
  232. * Return all registered fonts
  233. * @param ppt the slideshow containing the fonts
  234. * @return the list of registered fonts
  235. */
  236. public static List<XSLFFontInfo> getFonts(XMLSlideShow ppt) {
  237. final CTPresentation pres = ppt.getCTPresentation();
  238. //noinspection deprecation
  239. return pres.isSetEmbeddedFontLst()
  240. ? Stream.of(pres.getEmbeddedFontLst().getEmbeddedFontArray())
  241. .map(fe -> new XSLFFontInfo(ppt, fe)).collect(Collectors.toList())
  242. : Collections.emptyList();
  243. }
  244. }