001: /**
002: * Copyright (c) 2003-2006, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.font;
031:
032: import java.awt.Graphics;
033:
034: import java.io.IOException;
035:
036: import java.util.HashMap;
037:
038: import org.fontbox.afm.FontMetric;
039:
040: import org.pdfbox.cos.COSArray;
041: import org.pdfbox.cos.COSDictionary;
042: import org.pdfbox.cos.COSName;
043: import org.pdfbox.cos.COSNumber;
044: import org.pdfbox.cos.COSInteger;
045: import org.pdfbox.encoding.Encoding;
046:
047: import org.pdfbox.pdmodel.common.PDRectangle;
048: import org.pdfbox.pdmodel.common.PDStream;
049:
050: /**
051: * This class contains implementation details of the simple pdf fonts.
052: *
053: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
054: * @version $Revision: 1.17 $
055: */
056: public abstract class PDSimpleFont extends PDFont {
057: private HashMap mFontSizes = new HashMap(128);
058: private float avgFontWidth = 0.0f;
059:
060: /**
061: * Constructor.
062: */
063: public PDSimpleFont() {
064: super ();
065: }
066:
067: /**
068: * Constructor.
069: *
070: * @param fontDictionary The font dictionary according to the PDF specification.
071: */
072: public PDSimpleFont(COSDictionary fontDictionary) {
073: super (fontDictionary);
074: }
075:
076: /**
077: * {@inheritDoc}
078: */
079: public void drawString(String string, Graphics g, float fontSize,
080: float xScale, float yScale, float x, float y)
081: throws IOException {
082: System.err.println("Not yet implemented:"
083: + getClass().getName());
084: }
085:
086: /**
087: * This will get the font width for a character.
088: *
089: * @param c The character code to get the width for.
090: * @param offset The offset into the array.
091: * @param length The length of the data.
092: *
093: * @return The width is in 1000 unit of text space, ie 333 or 777
094: *
095: * @throws IOException If an error occurs while parsing.
096: */
097: public float getFontHeight(byte[] c, int offset, int length)
098: throws IOException {
099: float retval = 0;
100: int code = getCodeFromArray(c, offset, length);
101: FontMetric metric = getAFM();
102: if (metric != null) {
103: Encoding encoding = getEncoding();
104: COSName characterName = encoding.getName(code);
105: retval = metric.getCharacterHeight(characterName.getName());
106: } else {
107: PDFontDescriptor desc = getFontDescriptor();
108: if (desc != null) {
109: float xHeight = desc.getXHeight();
110: float capHeight = desc.getCapHeight();
111: if (xHeight != 0f && capHeight != 0) {
112: //do an average of these two. Can we do better???
113: retval = (xHeight + capHeight) / 2f;
114: } else if (xHeight != 0) {
115: retval = xHeight;
116: } else if (capHeight != 0) {
117: retval = capHeight;
118: } else {
119: retval = 0;
120: }
121: }
122: }
123: return retval;
124: }
125:
126: /**
127: * This will get the font width for a character.
128: *
129: * @param c The character code to get the width for.
130: * @param offset The offset into the array.
131: * @param length The length of the data.
132: *
133: * @return The width is in 1000 unit of text space, ie 333 or 777
134: *
135: * @throws IOException If an error occurs while parsing.
136: */
137: public float getFontWidth(byte[] c, int offset, int length)
138: throws IOException {
139: float fontWidth = 0;
140: int code = getCodeFromArray(c, offset, length);
141:
142: Integer codeI = new Integer(code);
143: if (mFontSizes.containsKey(codeI)) {
144: Float fontWidthF = (Float) mFontSizes.get(codeI);
145: fontWidth = fontWidthF.floatValue();
146: } else {
147: //hmm should this be in a subclass??
148: COSInteger firstChar = (COSInteger) font
149: .getDictionaryObject(COSName.FIRST_CHAR);
150: COSInteger lastChar = (COSInteger) font
151: .getDictionaryObject(COSName.LAST_CHAR);
152: if (firstChar != null && lastChar != null) {
153: long first = firstChar.intValue();
154: long last = lastChar.intValue();
155: if (code >= first
156: && code <= last
157: && font.getDictionaryObject(COSName.WIDTHS) != null) {
158: COSArray widthArray = (COSArray) font
159: .getDictionaryObject(COSName.WIDTHS);
160: COSNumber fontWidthObject = (COSNumber) widthArray
161: .getObject((int) (code - first));
162: fontWidth = fontWidthObject.floatValue();
163: } else {
164: fontWidth = getFontWidthFromAFMFile(code);
165: }
166: } else {
167: fontWidth = getFontWidthFromAFMFile(code);
168: }
169: mFontSizes.put(codeI, new Float(fontWidth));
170: }
171: return fontWidth;
172: }
173:
174: /**
175: * This will get the average font width for all characters.
176: *
177: * @return The width is in 1000 unit of text space, ie 333 or 777
178: *
179: * @throws IOException If an error occurs while parsing.
180: */
181: public float getAverageFontWidth() throws IOException {
182: float average = 0.0f;
183:
184: //AJW
185: if (avgFontWidth != 0.0f) {
186: average = avgFontWidth;
187: } else {
188: float totalWidth = 0.0f;
189: float characterCount = 0.0f;
190: COSArray widths = (COSArray) font
191: .getDictionaryObject(COSName.WIDTHS);
192: if (widths != null) {
193: for (int i = 0; i < widths.size(); i++) {
194: COSNumber fontWidth = (COSNumber) widths
195: .getObject(i);
196: if (fontWidth.floatValue() > 0) {
197: totalWidth += fontWidth.floatValue();
198: characterCount += 1;
199: }
200: }
201: }
202:
203: if (totalWidth > 0) {
204: average = totalWidth / characterCount;
205: } else {
206: average = getAverageFontWidthFromAFMFile();
207: }
208: avgFontWidth = average;
209: }
210: return average;
211: }
212:
213: /**
214: * This will get the font descriptor for this font.
215: *
216: * @return The font descriptor for this font.
217: *
218: * @throws IOException If there is an error parsing an AFM file, or unable to
219: * create a PDFontDescriptor object.
220: */
221: public PDFontDescriptor getFontDescriptor() throws IOException {
222: PDFontDescriptor retval = null;
223: COSDictionary fd = (COSDictionary) font
224: .getDictionaryObject(COSName
225: .getPDFName("FontDescriptor"));
226: if (fd == null) {
227: FontMetric afm = getAFM();
228: if (afm != null) {
229: retval = new PDFontDescriptorAFM(afm);
230: }
231: } else {
232: retval = new PDFontDescriptorDictionary(fd);
233: }
234:
235: return retval;
236: }
237:
238: /**
239: * This will set the font descriptor.
240: *
241: * @param fontDescriptor The font descriptor.
242: */
243: public void setFontDescriptor(
244: PDFontDescriptorDictionary fontDescriptor) {
245: COSDictionary dic = null;
246: if (fontDescriptor != null) {
247: dic = fontDescriptor.getCOSDictionary();
248: }
249: font.setItem(COSName.getPDFName("FontDescriptor"), dic);
250: }
251:
252: /**
253: * This will get the ToUnicode stream.
254: *
255: * @return The ToUnicode stream.
256: * @throws IOException If there is an error getting the stream.
257: */
258: public PDStream getToUnicode() throws IOException {
259: return PDStream.createFromCOS(font
260: .getDictionaryObject("ToUnicode"));
261: }
262:
263: /**
264: * This will set the ToUnicode stream.
265: *
266: * @param unicode The unicode stream.
267: */
268: public void setToUnicode(PDStream unicode) {
269: font.setItem("ToUnicode", unicode);
270: }
271:
272: /**
273: * This will get the fonts bounding box.
274: *
275: * @return The fonts bouding box.
276: *
277: * @throws IOException If there is an error getting the bounding box.
278: */
279: public PDRectangle getFontBoundingBox() throws IOException {
280: return getFontDescriptor().getFontBoundingBox();
281: }
282: }
|