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: import java.util.Map;
038:
039: import org.pdfbox.cos.COSArray;
040: import org.pdfbox.cos.COSBase;
041: import org.pdfbox.cos.COSDictionary;
042: import org.pdfbox.cos.COSInteger;
043: import org.pdfbox.cos.COSName;
044: import org.pdfbox.cos.COSNumber;
045: import org.pdfbox.pdmodel.common.PDRectangle;
046:
047: /**
048: * This is implementation for the CIDFontType0/CIDFontType2 Fonts.
049: *
050: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
051: * @version $Revision: 1.10 $
052: */
053: public abstract class PDCIDFont extends PDFont {
054: private Map widthCache = new HashMap();
055:
056: /**
057: * Constructor.
058: */
059: public PDCIDFont() {
060: super ();
061: }
062:
063: /**
064: * Constructor.
065: *
066: * @param fontDictionary The font dictionary according to the PDF specification.
067: */
068: public PDCIDFont(COSDictionary fontDictionary) {
069: super (fontDictionary);
070: }
071:
072: /**
073: * Get the font descriptor associated with this CID font.
074: *
075: * @return The font descriptor.
076: */
077: public PDFontDescriptor getFontDescriptor() {
078: PDFontDescriptor desc = null;
079: COSDictionary dict = (COSDictionary) font
080: .getDictionaryObject("FontDescriptor");
081: if (dict != null) {
082: desc = new PDFontDescriptorDictionary(dict);
083: }
084: return desc;
085: }
086:
087: /**
088: * Set the font descriptor associated with this CID Font.
089: *
090: * @param desc The font descriptor.
091: */
092: public void setFontDescriptor(PDFontDescriptorDictionary desc) {
093: font.setItem("FontDescriptor", desc);
094: }
095:
096: /**
097: * {@inheritDoc}
098: */
099: public void drawString(String string, Graphics g, float fontSize,
100: float xScale, float yScale, float x, float y) {
101: throw new RuntimeException("Not yet implemented");
102: }
103:
104: /**
105: * This will get the fonts bouding box.
106: *
107: * @return The fonts bouding box.
108: *
109: * @throws IOException If there is an error getting the font bounding box.
110: */
111: public PDRectangle getFontBoundingBox() throws IOException {
112: throw new RuntimeException("Not yet implemented");
113: }
114:
115: /**
116: * This will get the default width. The default value for the default width is 1000.
117: *
118: * @return The default width for the glyphs in this font.
119: */
120: public long getDefaultWidth() {
121: long dw = 1000;
122: COSNumber number = (COSNumber) font.getDictionaryObject(COSName
123: .getPDFName("DW"));
124: if (number != null) {
125: dw = number.intValue();
126: }
127: return dw;
128: }
129:
130: /**
131: * This will set the default width for the glyphs of this font.
132: *
133: * @param dw The default width.
134: */
135: public void setDefaultWidth(long dw) {
136: font.setItem(COSName.getPDFName("DW"), new COSInteger(dw));
137: }
138:
139: /**
140: * This will get the font width for a character.
141: *
142: * @param c The character code to get the width for.
143: * @param offset The offset into the array.
144: * @param length The length of the data.
145: *
146: * @return The width is in 1000 unit of text space, ie 333 or 777
147: *
148: * @throws IOException If an error occurs while parsing.
149: */
150: public float getFontWidth(byte[] c, int offset, int length)
151: throws IOException {
152:
153: float retval = 0.0f;
154: int code = getCodeFromArray(c, offset, length);
155:
156: Float widthFloat = (Float) widthCache.get(new Integer(code));
157: if (widthFloat == null) {
158: COSArray widths = (COSArray) font
159: .getDictionaryObject(COSName.getPDFName("W"));
160:
161: if (widths != null) {
162: boolean foundWidth = false;
163: for (int i = 0; !foundWidth && i < widths.size(); i++) {
164: COSNumber firstCode = (COSNumber) widths
165: .getObject(i++);
166: COSBase next = widths.getObject(i);
167: if (next instanceof COSArray) {
168: COSArray array = (COSArray) next;
169: if (code >= firstCode.intValue()
170: && code < firstCode.intValue()
171: + array.size()) {
172: COSNumber rangeWidth = (COSNumber) array
173: .get(code - firstCode.intValue());
174: retval = rangeWidth.floatValue();
175: foundWidth = true;
176: }
177: } else {
178: COSNumber secondCode = (COSNumber) next;
179: i++;
180: COSNumber rangeWidth = (COSNumber) widths
181: .getObject(i);
182: if (code >= firstCode.intValue()
183: && code <= secondCode.intValue()) {
184: retval = rangeWidth.floatValue();
185: foundWidth = true;
186: }
187: }
188: }
189: widthCache.put(new Integer(code), new Float(retval));
190: }
191: } else {
192: retval = widthFloat.floatValue();
193: }
194: return retval;
195: }
196:
197: /**
198: * This will get the font height for a character.
199: *
200: * @param c The character code to get the height for.
201: * @param offset The offset into the array.
202: * @param length The length of the data.
203: *
204: * @return The width is in 1000 unit of text space, ie 333 or 777
205: *
206: * @throws IOException If an error occurs while parsing.
207: */
208: public float getFontHeight(byte[] c, int offset, int length)
209: throws IOException {
210: float retval = 0;
211: PDFontDescriptor desc = getFontDescriptor();
212: float xHeight = desc.getXHeight();
213: float capHeight = desc.getCapHeight();
214: if (xHeight != 0f && capHeight != 0) {
215: //do an average of these two. Can we do better???
216: retval = (xHeight + capHeight) / 2f;
217: } else if (xHeight != 0) {
218: retval = xHeight;
219: } else if (capHeight != 0) {
220: retval = capHeight;
221: } else {
222: retval = 0;
223: }
224: return retval;
225: }
226:
227: /**
228: * This will get the average font width for all characters.
229: *
230: * @return The width is in 1000 unit of text space, ie 333 or 777
231: *
232: * @throws IOException If an error occurs while parsing.
233: */
234: public float getAverageFontWidth() throws IOException {
235: float totalWidths = 0.0f;
236: float characterCount = 0.0f;
237: float defaultWidth = getDefaultWidth();
238: COSArray widths = (COSArray) font.getDictionaryObject(COSName
239: .getPDFName("W"));
240:
241: if (widths != null) {
242: for (int i = 0; i < widths.size(); i++) {
243: COSNumber firstCode = (COSNumber) widths.getObject(i++);
244: COSBase next = widths.getObject(i);
245: if (next instanceof COSArray) {
246: COSArray array = (COSArray) next;
247: for (int j = 0; j < array.size(); j++) {
248: COSNumber width = (COSNumber) array.get(j);
249: totalWidths += width.floatValue();
250: characterCount += 1;
251: }
252: } else {
253: i++;
254: COSNumber rangeWidth = (COSNumber) widths
255: .getObject(i);
256: if (rangeWidth.floatValue() > 0) {
257: totalWidths += rangeWidth.floatValue();
258: characterCount += 1;
259: }
260: }
261: }
262: }
263: float average = totalWidths / characterCount;
264: if (average <= 0) {
265: average = defaultWidth;
266: }
267: return average;
268: }
269: }
|