diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPFont.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPFont.java new file mode 100755 index 000000000..8b4de9050 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPFont.java @@ -0,0 +1,243 @@ +/* ==================================================================== + 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.hslf.model; + +import org.apache.poi.hslf.record.FontEntityAtom; + +/** + * Represents a Font used in a presenation. + *

+ * In PowerPoint Font is a shared resource and can be shared among text object in the presentation. + *

+ * Some commonly used fonts are predefined in static constants. + * + * @author Yegor Kozlov + */ +public class PPFont { + /** + * ANSI character set + */ + public final static byte ANSI_CHARSET = 0; + + /** + * Default character set. + */ + public final static byte DEFAULT_CHARSET = 1; + + /** + * Symbol character set + */ + public final static byte SYMBOL_CHARSET = 2; + + + /** + * Constants for the pitch and family of the font. + * The two low-order bits specify the pitch of the font and can be one of the following values + */ + public final static byte DEFAULT_PITCH = 0; + public final static byte FIXED_PITCH = 1; + public final static byte VARIABLE_PITCH = 2; + + /** + * Don't care or don't know. + */ + public final static byte FF_DONTCARE = 0; + /** + * Fonts with variable stroke width (proportional) and with serifs. Times New Roman is an example. + */ + public final static byte FF_ROMAN = 16; + /** + * Fonts with variable stroke width (proportional) and without serifs. Arial is an example. + */ + public final static byte FF_SWISS = 32; + /** + * Fonts designed to look like handwriting. Script and Cursive are examples. + */ + public final static byte FF_SCRIPT = 64; + /** + * Fonts with constant stroke width (monospace), with or without serifs. + * Monospace fonts are usually modern. CourierNew is an example + */ + public final static byte FF_MODERN = 48; + /** + * Novelty fonts. Old English is an example + */ + public final static byte FF_DECORATIVE = 80; + + + protected int charset; + protected int type; + protected int flags; + protected int pitch; + protected String name; + + /** + * Creates a new instance of PPFont + */ + public PPFont(){ + + } + + /** + * Creates a new instance of PPFont and initialize it from the supplied font atom + */ + public PPFont(FontEntityAtom fontAtom){ + name = fontAtom.getFontName(); + charset = fontAtom.getCharSet(); + type = fontAtom.getFontType(); + flags = fontAtom.getFontFlags(); + pitch = fontAtom.getPitchAndFamily(); + } + + /** + * set the name for the font (i.e. Arial) + * + * @param val String representing the name of the font to use + */ + public void setFontName(String val){ + name = val; + } + + /** + * get the name for the font (i.e. Arial) + * + * @return String representing the name of the font to use + */ + public String getFontName(){ + return name; + } + + /** + * set the character set + * + * @param val - characterset + */ + public void setCharSet(int val){ + charset = val; + } + + /** + * get the character set + * + * @return charset - characterset + */ + public int getCharSet(){ + return charset; + } + + /** + * set the font flags + * Bit 1: If set, font is subsetted + * + * @param val - the font flags + */ + public void setFontFlags(int val){ + flags = val; + } + + /** + * get the character set + * Bit 1: If set, font is subsetted + * + * @return the font flags + */ + public int getFontFlags(){ + return flags; + } + + /** + * set the font type + *

+ * Bit 1: Raster Font + * Bit 2: Device Font + * Bit 3: TrueType Font + *

+ * + * @param val - the font type + */ + public void setFontType(int val){ + type = val; + } + + /** + * get the font type + *

+ * Bit 1: Raster Font + * Bit 2: Device Font + * Bit 3: TrueType Font + *

+ * + * @return the font type + */ + public int getFontType(){ + return type; + } + + /** + * set lfPitchAndFamily + * + * + * @param val - Corresponds to the lfPitchAndFamily field of the Win32 API LOGFONT structure + */ + public void setPitchAndFamily(int val){ + pitch = val; + } + + /** + * get lfPitchAndFamily + * + * @return corresponds to the lfPitchAndFamily field of the Win32 API LOGFONT structure + */ + public int getPitchAndFamily(){ + return pitch; + } + + public static final PPFont ARIAL; + public static final PPFont TIMES_NEW_ROMAN ; + public static final PPFont COURIER_NEW; + public static final PPFont WINGDINGS; + static { + ARIAL = new PPFont(); + ARIAL.setFontName("Arial"); + ARIAL.setCharSet(ANSI_CHARSET); + ARIAL.setFontType(4); + ARIAL.setFontFlags(0); + ARIAL.setPitchAndFamily(VARIABLE_PITCH | FF_SWISS); + + TIMES_NEW_ROMAN = new PPFont(); + TIMES_NEW_ROMAN.setFontName("Times New Roman"); + TIMES_NEW_ROMAN.setCharSet(ANSI_CHARSET); + TIMES_NEW_ROMAN.setFontType(4); + TIMES_NEW_ROMAN.setFontFlags(0); + TIMES_NEW_ROMAN.setPitchAndFamily(VARIABLE_PITCH | FF_ROMAN); + + COURIER_NEW = new PPFont(); + COURIER_NEW.setFontName("Courier New"); + COURIER_NEW.setCharSet(ANSI_CHARSET); + COURIER_NEW.setFontType(4); + COURIER_NEW.setFontFlags(0); + COURIER_NEW.setPitchAndFamily(FIXED_PITCH | FF_MODERN); + + WINGDINGS = new PPFont(); + WINGDINGS.setFontName("Wingdings"); + WINGDINGS.setCharSet(SYMBOL_CHARSET); + WINGDINGS.setFontType(4); + WINGDINGS.setFontFlags(0); + WINGDINGS.setPitchAndFamily(VARIABLE_PITCH | FF_DONTCARE); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java index 521e8468b..c0d55ac0e 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java @@ -75,16 +75,20 @@ public class FontCollection extends RecordContainer { * @return zero based index of the font in the collection */ public int addFont(String name) { - for (int i = 0; i < fonts.size(); i++) { - if(fonts.get(i).equals(name)){ - //if the font is already present return its index - return i; - } - } + int idx = getFontIndex(name); + if(idx != -1) return idx; + return addFont(name, 0, 0, 4, 34); + } + + public int addFont(String name, int charset, int flags, int type, int pitch) { FontEntityAtom fnt = new FontEntityAtom(); fnt.setFontIndex(fonts.size() << 4); fnt.setFontName(name); + fnt.setCharSet(charset); + fnt.setFontFlags(flags); + fnt.setFontType(type); + fnt.setPitchAndFamily(pitch); fonts.add(name); // Append new child to the end @@ -92,8 +96,25 @@ public class FontCollection extends RecordContainer { return fonts.size()-1; //the added font is the last in the list } - - /** + + /** + * @return zero based index of the font in the collection or -1 if not found + */ + public int getFontIndex(String name) { + for (int i = 0; i < fonts.size(); i++) { + if(fonts.get(i).equals(name)){ + //if the font is already present return its index + return i; + } + } + return -1; + } + + public int getNumberOfFonts() { + return fonts.size(); + } + + /** * Get the name of the font at the given ID, or null if there is * no font at that ID. * @param id diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java index e4899bd6e..76cb4c264 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java @@ -61,7 +61,7 @@ public class FontEntityAtom extends RecordAtom { /** * Create a new instance of FontEntityAtom */ - protected FontEntityAtom() { + public FontEntityAtom() { _recdata = new byte[68]; _header = new byte[8]; @@ -124,15 +124,100 @@ public class FontEntityAtom extends RecordAtom { } } - protected void setFontIndex(int idx){ + public void setFontIndex(int idx){ LittleEndian.putShort(_header, 0, (short)idx); } - protected int getFontIndex(){ - return LittleEndian.getShort(_header, 0); + public int getFontIndex(){ + return LittleEndian.getShort(_header, 0) >> 4; } - /** + /** + * set the character set + * + * @param charset - characterset + */ + public void setCharSet(int charset){ + _recdata[64] = (byte)charset; + } + + /** + * get the character set + * + * @return charset - characterset + */ + public int getCharSet(){ + return _recdata[64]; + } + + /** + * set the font flags + * Bit 1: If set, font is subsetted + * + * @param flags - the font flags + */ + public void setFontFlags(int flags){ + _recdata[65] = (byte)flags; + } + + /** + * get the character set + * Bit 1: If set, font is subsetted + * + * @return the font flags + */ + public int getFontFlags(){ + return _recdata[65]; + } + + /** + * set the font type + *

+ * Bit 1: Raster Font + * Bit 2: Device Font + * Bit 3: TrueType Font + *

+ * + * @param type - the font type + */ + public void setFontType(int type){ + _recdata[66] = (byte)type; + } + + /** + * get the font type + *

+ * Bit 1: Raster Font + * Bit 2: Device Font + * Bit 3: TrueType Font + *

+ * + * @return the font type + */ + public int getFontType(){ + return _recdata[66]; + } + + /** + * set lfPitchAndFamily + * + * + * @param val - Corresponds to the lfPitchAndFamily field of the Win32 API LOGFONT structure + */ + public void setPitchAndFamily(int val){ + _recdata[67] = (byte)val; + } + + /** + * get lfPitchAndFamily + * + * @return corresponds to the lfPitchAndFamily field of the Win32 API LOGFONT structure + */ + public int getPitchAndFamily(){ + return _recdata[67]; + } + + /** * Write the contents of the record back, so it can be written to disk */ public void writeOut(OutputStream out) throws IOException { diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java index 9ce9a12c9..21e30ac2a 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java @@ -757,4 +757,50 @@ public class SlideShow } return addPicture(data, format); } + + /** + * Add a font in this presentation + * + * @param font the font to add + * @return 0-based index of the font + */ + public int addFont(PPFont font) { + FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection(); + int idx = fonts.getFontIndex(font.getFontName()); + if(idx == -1){ + idx = fonts.addFont(font.getFontName(), font.getCharSet(), font.getFontFlags(), font.getFontType(), font.getPitchAndFamily()); + } + return idx; + } + + /** + * Get a font by index + * + * @param idx 0-based index of the font + * @return of an instance of PPFont or null if not found + */ + public PPFont getFont(int idx) { + PPFont font = null; + FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection(); + Record[] ch = fonts.getChildRecords(); + for (int i = 0; i < ch.length; i++) { + if(ch[i] instanceof FontEntityAtom) { + FontEntityAtom atom = (FontEntityAtom)ch[i]; + if(atom.getFontIndex() == idx){ + font = new PPFont(atom); + break; + } + } + } + return font; + } + + /** + * get the number of fonts in the presentation + * + * @return number of fonts + */ + public int getNumberOfFonts() { + return getDocumentRecord().getEnvironment().getFontCollection().getNumberOfFonts(); + } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/empty.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/empty.ppt index 23e1e94ca..20d2398e3 100644 Binary files a/src/scratchpad/testcases/org/apache/poi/hslf/data/empty.ppt and b/src/scratchpad/testcases/org/apache/poi/hslf/data/empty.ppt differ diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java new file mode 100755 index 000000000..b6864ea16 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java @@ -0,0 +1,56 @@ + +/* ==================================================================== + 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.hslf.model; + +import junit.framework.TestCase; +import org.apache.poi.hslf.usermodel.SlideShow; + +import java.io.IOException; + +/** + * Test adding fonts to the presenataion resources + * + * @author Yegor Kozlov + */ +public class TestPPFont extends TestCase{ + + public void testCreate() throws IOException { + SlideShow ppt = new SlideShow(); + assertEquals(1, ppt.getNumberOfFonts()); + assertEquals("Arial", ppt.getFont(0).getFontName()); + + //adding the same font twice + assertEquals(0, ppt.addFont(PPFont.ARIAL)); + assertEquals(1, ppt.getNumberOfFonts()); + + assertEquals(1, ppt.addFont(PPFont.TIMES_NEW_ROMAN)); + assertEquals(2, ppt.addFont(PPFont.COURIER_NEW)); + assertEquals(3, ppt.addFont(PPFont.WINGDINGS)); + + assertEquals(4, ppt.getNumberOfFonts()); + + assertEquals(PPFont.TIMES_NEW_ROMAN.getFontName(), ppt.getFont(1).getFontName()); + assertEquals(PPFont.COURIER_NEW.getFontName(), ppt.getFont(2).getFontName()); + + PPFont font3 = ppt.getFont(3); + assertEquals(PPFont.WINGDINGS.getFontName(), font3.getFontName()); + assertEquals(PPFont.SYMBOL_CHARSET, font3.getCharSet()); + assertEquals(PPFont.VARIABLE_PITCH, font3.getPitchAndFamily()); + } +}