| /* |
| * ==================================================================== |
| * 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.poi.xslf.usermodel; |
| |
| import java.awt.Font; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| import org.apache.poi.common.usermodel.fonts.FontCharset; |
| import org.apache.poi.common.usermodel.fonts.FontFacet; |
| import org.apache.poi.common.usermodel.fonts.FontFamily; |
| import org.apache.poi.common.usermodel.fonts.FontHeader; |
| import org.apache.poi.common.usermodel.fonts.FontInfo; |
| import org.apache.poi.common.usermodel.fonts.FontPitch; |
| import org.apache.poi.ooxml.POIXMLDocumentPart; |
| import org.apache.poi.openxml4j.exceptions.InvalidFormatException; |
| import org.apache.poi.util.IOUtils; |
| import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontDataId; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontList; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontListEntry; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation; |
| |
| @SuppressWarnings("WeakerAccess") |
| public class XSLFFontInfo implements FontInfo { |
| final XMLSlideShow ppt; |
| final String typeface; |
| final CTEmbeddedFontListEntry fontListEntry; |
| |
| public XSLFFontInfo(XMLSlideShow ppt, String typeface) { |
| this.ppt = ppt; |
| this.typeface = typeface; |
| |
| final CTPresentation pres = ppt.getCTPresentation(); |
| CTEmbeddedFontList fontList = pres.isSetEmbeddedFontLst() |
| ? pres.getEmbeddedFontLst() : pres.addNewEmbeddedFontLst(); |
| |
| for (CTEmbeddedFontListEntry fe : fontList.getEmbeddedFontArray()) { |
| if (typeface.equalsIgnoreCase(fe.getFont().getTypeface())) { |
| fontListEntry = fe; |
| return; |
| } |
| } |
| |
| fontListEntry = fontList.addNewEmbeddedFont(); |
| fontListEntry.addNewFont().setTypeface(typeface); |
| } |
| |
| public XSLFFontInfo(XMLSlideShow ppt, CTEmbeddedFontListEntry fontListEntry) { |
| this.ppt = ppt; |
| this.typeface = fontListEntry.getFont().getTypeface(); |
| this.fontListEntry = fontListEntry; |
| } |
| |
| @Override |
| public String getTypeface() { |
| return getFont().getTypeface(); |
| } |
| |
| @Override |
| public void setTypeface(String typeface) { |
| getFont().setTypeface(typeface); |
| } |
| |
| @Override |
| public FontCharset getCharset() { |
| return FontCharset.valueOf(getFont().getCharset()); |
| } |
| |
| @Override |
| public void setCharset(FontCharset charset) { |
| getFont().setCharset((byte)charset.getNativeId()); |
| } |
| |
| @Override |
| public FontFamily getFamily() { |
| return FontFamily.valueOfPitchFamily(getFont().getPitchFamily()); |
| } |
| |
| @Override |
| public void setFamily(FontFamily family) { |
| byte pitchAndFamily = getFont().getPitchFamily(); |
| FontPitch pitch = FontPitch.valueOfPitchFamily(pitchAndFamily); |
| getFont().setPitchFamily(FontPitch.getNativeId(pitch, family)); |
| } |
| |
| @Override |
| public FontPitch getPitch() { |
| return FontPitch.valueOfPitchFamily(getFont().getPitchFamily()); |
| } |
| |
| @Override |
| public void setPitch(FontPitch pitch) { |
| byte pitchAndFamily = getFont().getPitchFamily(); |
| FontFamily family = FontFamily.valueOfPitchFamily(pitchAndFamily); |
| getFont().setPitchFamily(FontPitch.getNativeId(pitch, family)); |
| } |
| |
| @Override |
| public byte[] getPanose() { |
| return getFont().getPanose(); |
| } |
| |
| @Override |
| public List<FontFacet> getFacets() { |
| List<FontFacet> facetList = new ArrayList<>(); |
| if (fontListEntry.isSetRegular()) { |
| facetList.add(new XSLFFontFacet((fontListEntry.getRegular()))); |
| } |
| if (fontListEntry.isSetItalic()) { |
| facetList.add(new XSLFFontFacet((fontListEntry.getItalic()))); |
| } |
| if (fontListEntry.isSetBold()) { |
| facetList.add(new XSLFFontFacet((fontListEntry.getBold()))); |
| } |
| if (fontListEntry.isSetBoldItalic()) { |
| facetList.add(new XSLFFontFacet((fontListEntry.getBoldItalic()))); |
| } |
| return facetList; |
| } |
| |
| public FontFacet addFacet(InputStream fontData) throws IOException { |
| FontHeader header = new FontHeader(); |
| InputStream is = header.bufferInit(fontData); |
| |
| final CTPresentation pres = ppt.getCTPresentation(); |
| pres.setEmbedTrueTypeFonts(true); |
| pres.setSaveSubsetFonts(true); |
| |
| final CTEmbeddedFontDataId dataId; |
| final int style = |
| (header.getWeight() > 400 ? Font.BOLD : Font.PLAIN) | |
| (header.isItalic() ? Font.ITALIC : Font.PLAIN); |
| switch (style) { |
| case Font.PLAIN: |
| dataId = fontListEntry.isSetRegular() |
| ? fontListEntry.getRegular() : fontListEntry.addNewRegular(); |
| break; |
| case Font.BOLD: |
| dataId = fontListEntry.isSetBold() |
| ? fontListEntry.getBold() : fontListEntry.addNewBold(); |
| break; |
| case Font.ITALIC: |
| dataId = fontListEntry.isSetItalic() |
| ? fontListEntry.getItalic() : fontListEntry.addNewItalic(); |
| break; |
| default: |
| dataId = fontListEntry.isSetBoldItalic() |
| ? fontListEntry.getBoldItalic() : fontListEntry.addNewBoldItalic(); |
| break; |
| } |
| |
| XSLFFontFacet facet = new XSLFFontFacet(dataId); |
| facet.setFontData(is); |
| return facet; |
| } |
| |
| private final class XSLFFontFacet implements FontFacet { |
| private final CTEmbeddedFontDataId fontEntry; |
| private final FontHeader header = new FontHeader(); |
| |
| private XSLFFontFacet(CTEmbeddedFontDataId fontEntry) { |
| this.fontEntry = fontEntry; |
| } |
| |
| @Override |
| public int getWeight() { |
| init(); |
| return header.getWeight(); |
| } |
| |
| @Override |
| public boolean isItalic() { |
| init(); |
| return header.isItalic(); |
| } |
| |
| @Override |
| public XSLFFontData getFontData() { |
| return ppt.getRelationPartById(fontEntry.getId()).getDocumentPart(); |
| } |
| |
| void setFontData(InputStream is) throws IOException { |
| final XSLFRelation fntRel = XSLFRelation.FONT; |
| final String relId = fontEntry.getId(); |
| final XSLFFontData fntData; |
| if (relId == null || relId.isEmpty()) { |
| final int fntDataIdx; |
| try { |
| fntDataIdx = ppt.getPackage().getUnusedPartIndex(fntRel.getDefaultFileName()); |
| } catch (InvalidFormatException e) { |
| throw new IllegalStateException(e); |
| } |
| |
| POIXMLDocumentPart.RelationPart rp = ppt.createRelationship(fntRel, XSLFFactory.getInstance(), fntDataIdx, false); |
| fntData = rp.getDocumentPart(); |
| fontEntry.setId(rp.getRelationship().getId()); |
| } else { |
| fntData = (XSLFFontData)ppt.getRelationById(relId); |
| } |
| |
| assert (fntData != null); |
| try (OutputStream os = fntData.getOutputStream()) { |
| IOUtils.copy(is, os); |
| } |
| } |
| |
| private void init() { |
| if (header.getFamilyName() == null) { |
| try (InputStream is = getFontData().getInputStream()) { |
| byte[] buf = IOUtils.toByteArray(is, 1000); |
| header.init(buf, 0, buf.length); |
| } catch (IOException e) { |
| // TODO: better exception class |
| throw new IllegalStateException(e); |
| } |
| } |
| } |
| } |
| |
| |
| private CTTextFont getFont() { |
| return fontListEntry.getFont(); |
| } |
| |
| |
| |
| /** |
| * Adds or updates a (MTX-) font |
| * @param ppt the slideshow which will contain the font |
| * @param fontStream the (MTX) font data as stream |
| * @return a font data object |
| * @throws IOException if the font data can't be stored |
| * |
| * @since POI 4.1.0 |
| */ |
| public static XSLFFontInfo addFontToSlideShow(XMLSlideShow ppt, InputStream fontStream) |
| throws IOException { |
| FontHeader header = new FontHeader(); |
| InputStream is = header.bufferInit(fontStream); |
| |
| XSLFFontInfo fontInfo = new XSLFFontInfo(ppt, header.getFamilyName()); |
| fontInfo.addFacet(is); |
| return fontInfo; |
| } |
| |
| /** |
| * Return all registered fonts |
| * @param ppt the slideshow containing the fonts |
| * @return the list of registered fonts |
| */ |
| public static List<XSLFFontInfo> getFonts(XMLSlideShow ppt) { |
| final CTPresentation pres = ppt.getCTPresentation(); |
| |
| //noinspection deprecation |
| return pres.isSetEmbeddedFontLst() |
| ? Stream.of(pres.getEmbeddedFontLst().getEmbeddedFontArray()) |
| .map(fe -> new XSLFFontInfo(ppt, fe)).collect(Collectors.toList()) |
| : Collections.emptyList(); |
| } |
| |
| } |