001/* 002 * $Id: FontDetails.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.io.UnsupportedEncodingException; 047import java.util.HashMap; 048 049import com.itextpdf.text.ExceptionConverter; 050import com.itextpdf.text.Utilities; 051 052/** 053 * Each font in the document will have an instance of this class 054 * where the characters used will be represented. 055 * 056 * @author Paulo Soares 057 */ 058class FontDetails { 059 060 /** 061 * The indirect reference to this font 062 */ 063 PdfIndirectReference indirectReference; 064 /** 065 * The font name that appears in the document body stream 066 */ 067 PdfName fontName; 068 /** 069 * The font 070 */ 071 BaseFont baseFont; 072 /** 073 * The font if it's an instance of <CODE>TrueTypeFontUnicode</CODE> 074 */ 075 TrueTypeFontUnicode ttu; 076 /** 077 * The font if it's an instance of <CODE>CJKFont</CODE> 078 */ 079 CJKFont cjkFont; 080 /** 081 * The array used with single byte encodings 082 */ 083 byte shortTag[]; 084 /** 085 * The map used with double byte encodings. The key is Integer(glyph) and 086 * the value is int[]{glyph, width, Unicode code} 087 */ 088 HashMap<Integer, int[]> longTag; 089 /** 090 * IntHashtable with CIDs of CJK glyphs that are used in the text. 091 */ 092 IntHashtable cjkTag; 093 /** 094 * The font type 095 */ 096 int fontType; 097 /** 098 * <CODE>true</CODE> if the font is symbolic 099 */ 100 boolean symbolic; 101 /** 102 * Indicates if only a subset of the glyphs and widths for that particular 103 * encoding should be included in the document. 104 */ 105 protected boolean subset = true; 106 107 /** 108 * Each font used in a document has an instance of this class. 109 * This class stores the characters used in the document and other 110 * specifics unique to the current working document. 111 * @param fontName the font name 112 * @param indirectReference the indirect reference to the font 113 * @param baseFont the <CODE>BaseFont</CODE> 114 */ 115 FontDetails(PdfName fontName, PdfIndirectReference indirectReference, BaseFont baseFont) { 116 this.fontName = fontName; 117 this.indirectReference = indirectReference; 118 this.baseFont = baseFont; 119 fontType = baseFont.getFontType(); 120 switch (fontType) { 121 case BaseFont.FONT_TYPE_T1: 122 case BaseFont.FONT_TYPE_TT: 123 shortTag = new byte[256]; 124 break; 125 case BaseFont.FONT_TYPE_CJK: 126 cjkTag = new IntHashtable(); 127 cjkFont = (CJKFont)baseFont; 128 break; 129 case BaseFont.FONT_TYPE_TTUNI: 130 longTag = new HashMap<Integer, int[]>(); 131 ttu = (TrueTypeFontUnicode)baseFont; 132 symbolic = baseFont.isFontSpecific(); 133 break; 134 } 135 } 136 137 /** 138 * Gets the indirect reference to this font. 139 * @return the indirect reference to this font 140 */ 141 PdfIndirectReference getIndirectReference() { 142 return indirectReference; 143 } 144 145 /** 146 * Gets the font name as it appears in the document body. 147 * @return the font name 148 */ 149 PdfName getFontName() { 150 return fontName; 151 } 152 153 /** 154 * Gets the <CODE>BaseFont</CODE> of this font. 155 * @return the <CODE>BaseFont</CODE> of this font 156 */ 157 BaseFont getBaseFont() { 158 return baseFont; 159 } 160 161 /** 162 * Converts the text into bytes to be placed in the document. 163 * The conversion is done according to the font and the encoding and the characters 164 * used are stored. 165 * @param text the text to convert 166 * @return the conversion 167 */ 168 byte[] convertToBytes(String text) { 169 byte b[] = null; 170 switch (fontType) { 171 case BaseFont.FONT_TYPE_T3: 172 return baseFont.convertToBytes(text); 173 case BaseFont.FONT_TYPE_T1: 174 case BaseFont.FONT_TYPE_TT: { 175 b = baseFont.convertToBytes(text); 176 int len = b.length; 177 for (int k = 0; k < len; ++k) 178 shortTag[b[k] & 0xff] = 1; 179 break; 180 } 181 case BaseFont.FONT_TYPE_CJK: { 182 int len = text.length(); 183 for (int k = 0; k < len; ++k) 184 cjkTag.put(cjkFont.getCidCode(text.charAt(k)), 0); 185 b = baseFont.convertToBytes(text); 186 break; 187 } 188 case BaseFont.FONT_TYPE_DOCUMENT: { 189 b = baseFont.convertToBytes(text); 190 break; 191 } 192 case BaseFont.FONT_TYPE_TTUNI: { 193 try { 194 int len = text.length(); 195 int metrics[] = null; 196 char glyph[] = new char[len]; 197 int i = 0; 198 if (symbolic) { 199 b = PdfEncodings.convertToBytes(text, "symboltt"); 200 len = b.length; 201 for (int k = 0; k < len; ++k) { 202 metrics = ttu.getMetricsTT(b[k] & 0xff); 203 if (metrics == null) 204 continue; 205 longTag.put(Integer.valueOf(metrics[0]), new int[]{metrics[0], metrics[1], ttu.getUnicodeDifferences(b[k] & 0xff)}); 206 glyph[i++] = (char)metrics[0]; 207 } 208 } 209 else { 210 for (int k = 0; k < len; ++k) { 211 int val; 212 if (Utilities.isSurrogatePair(text, k)) { 213 val = Utilities.convertToUtf32(text, k); 214 k++; 215 } 216 else { 217 val = text.charAt(k); 218 } 219 metrics = ttu.getMetricsTT(val); 220 if (metrics == null) 221 continue; 222 int m0 = metrics[0]; 223 Integer gl = Integer.valueOf(m0); 224 if (!longTag.containsKey(gl)) 225 longTag.put(gl, new int[]{m0, metrics[1], val}); 226 glyph[i++] = (char)m0; 227 } 228 } 229 String s = new String(glyph, 0, i); 230 b = s.getBytes(CJKFont.CJK_ENCODING); 231 } 232 catch (UnsupportedEncodingException e) { 233 throw new ExceptionConverter(e); 234 } 235 break; 236 } 237 } 238 return b; 239 } 240 241 /** 242 * Writes the font definition to the document. 243 * @param writer the <CODE>PdfWriter</CODE> of this document 244 */ 245 void writeFont(PdfWriter writer) { 246 try { 247 switch (fontType) { 248 case BaseFont.FONT_TYPE_T3: 249 baseFont.writeFont(writer, indirectReference, null); 250 break; 251 case BaseFont.FONT_TYPE_T1: 252 case BaseFont.FONT_TYPE_TT: { 253 int firstChar; 254 int lastChar; 255 for (firstChar = 0; firstChar < 256; ++firstChar) { 256 if (shortTag[firstChar] != 0) 257 break; 258 } 259 for (lastChar = 255; lastChar >= firstChar; --lastChar) { 260 if (shortTag[lastChar] != 0) 261 break; 262 } 263 if (firstChar > 255) { 264 firstChar = 255; 265 lastChar = 255; 266 } 267 baseFont.writeFont(writer, indirectReference, new Object[]{Integer.valueOf(firstChar), Integer.valueOf(lastChar), shortTag, Boolean.valueOf(subset)}); 268 break; 269 } 270 case BaseFont.FONT_TYPE_CJK: 271 baseFont.writeFont(writer, indirectReference, new Object[]{cjkTag}); 272 break; 273 case BaseFont.FONT_TYPE_TTUNI: 274 baseFont.writeFont(writer, indirectReference, new Object[]{longTag, Boolean.valueOf(subset)}); 275 break; 276 } 277 } 278 catch(Exception e) { 279 throw new ExceptionConverter(e); 280 } 281 } 282 283 /** 284 * Indicates if all the glyphs and widths for that particular 285 * encoding should be included in the document. 286 * @return <CODE>false</CODE> to include all the glyphs and widths. 287 */ 288 public boolean isSubset() { 289 return subset; 290 } 291 292 /** 293 * Indicates if all the glyphs and widths for that particular 294 * encoding should be included in the document. Set to <CODE>false</CODE> 295 * to include all. 296 * @param subset new value of property subset 297 */ 298 public void setSubset(boolean subset) { 299 this.subset = subset; 300 } 301}