001/* 002 * $Id: DocumentFont.java 4859 2011-05-08 11:02:19Z psoares33 $ 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.IOException; 047import java.util.HashMap; 048 049import com.itextpdf.text.DocumentException; 050import com.itextpdf.text.ExceptionConverter; 051import com.itextpdf.text.pdf.fonts.cmaps.CMap; 052import com.itextpdf.text.pdf.fonts.cmaps.CMapParser; 053import java.io.ByteArrayInputStream; 054 055/** 056 * 057 * @author psoares 058 */ 059public class DocumentFont extends BaseFont { 060 // code, [glyph, width] 061 private HashMap<Integer, int[]> metrics = new HashMap<Integer, int[]>(); 062 private String fontName; 063 private PRIndirectReference refFont; 064 private PdfDictionary font; 065 private IntHashtable uni2byte = new IntHashtable(); 066 private IntHashtable diffmap; 067 private float Ascender = 800; 068 private float CapHeight = 700; 069 private float Descender = -200; 070 private float ItalicAngle = 0; 071 private float llx = -50; 072 private float lly = -200; 073 private float urx = 100; 074 private float ury = 900; 075 private boolean isType0 = false; 076 077 private BaseFont cjkMirror; 078 079 private static String cjkNames[] = {"HeiseiMin-W3", "HeiseiKakuGo-W5", "STSong-Light", "MHei-Medium", 080 "MSung-Light", "HYGoThic-Medium", "HYSMyeongJo-Medium", "MSungStd-Light", "STSongStd-Light", 081 "HYSMyeongJoStd-Medium", "KozMinPro-Regular"}; 082 083 private static String cjkEncs[] = {"UniJIS-UCS2-H", "UniJIS-UCS2-H", "UniGB-UCS2-H", "UniCNS-UCS2-H", 084 "UniCNS-UCS2-H", "UniKS-UCS2-H", "UniKS-UCS2-H", "UniCNS-UCS2-H", "UniGB-UCS2-H", 085 "UniKS-UCS2-H", "UniJIS-UCS2-H"}; 086 087 private static String cjkNames2[] = {"MSungStd-Light", "STSongStd-Light", "HYSMyeongJoStd-Medium", "KozMinPro-Regular"}; 088 089 private static String cjkEncs2[] = {"UniCNS-UCS2-H", "UniGB-UCS2-H", "UniKS-UCS2-H", "UniJIS-UCS2-H", 090 "UniCNS-UTF16-H", "UniGB-UTF16-H", "UniKS-UTF16-H", "UniJIS-UTF16-H"}; 091 092 private static final int stdEnc[] = { 093 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 094 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 095 32,33,34,35,36,37,38,8217,40,41,42,43,44,45,46,47, 096 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, 097 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 098 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, 099 8216,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, 100 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,0, 101 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 102 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 103 0,161,162,163,8260,165,402,167,164,39,8220,171,8249,8250,64257,64258, 104 0,8211,8224,8225,183,0,182,8226,8218,8222,8221,187,8230,8240,0,191, 105 0,96,180,710,732,175,728,729,168,0,730,184,0,733,731,711, 106 8212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 107 0,198,0,170,0,0,0,0,321,216,338,186,0,0,0,0, 108 0,230,0,0,0,305,0,0,322,248,339,223,0,0,0,0}; 109 110 /** Creates a new instance of DocumentFont */ 111 DocumentFont(PRIndirectReference refFont) { 112 encoding = ""; 113 fontSpecific = false; 114 this.refFont = refFont; 115 fontType = FONT_TYPE_DOCUMENT; 116 font = (PdfDictionary)PdfReader.getPdfObject(refFont); 117 PdfName baseFont = font.getAsName(PdfName.BASEFONT); 118 fontName = baseFont != null ? PdfName.decodeName(baseFont.toString()) : "Unspecified Font Name"; 119 PdfName subType = font.getAsName(PdfName.SUBTYPE); 120 if (PdfName.TYPE1.equals(subType) || PdfName.TRUETYPE.equals(subType)) 121 doType1TT(); 122 else { 123 for (int k = 0; k < cjkNames.length; ++k) { 124 if (fontName.startsWith(cjkNames[k])) { 125 fontName = cjkNames[k]; 126 try { 127 cjkMirror = BaseFont.createFont(fontName, cjkEncs[k], false); 128 } 129 catch (Exception e) { 130 throw new ExceptionConverter(e); 131 } 132 return; 133 } 134 } 135 PdfName encodingName = font.getAsName(PdfName.ENCODING); 136 if (encodingName != null){ 137 String enc = PdfName.decodeName(encodingName.toString()); 138 for (int k = 0; k < cjkEncs2.length; ++k) { 139 if (enc.startsWith(cjkEncs2[k])) { 140 try { 141 if (k > 3) 142 k -= 4; 143 cjkMirror = BaseFont.createFont(cjkNames2[k], cjkEncs2[k], false); 144 } 145 catch (Exception e) { 146 throw new ExceptionConverter(e); 147 } 148 return; 149 } 150 } 151 if (PdfName.TYPE0.equals(subType) && enc.equals("Identity-H")) { 152 processType0(font); 153 isType0 = true; 154 } 155 } 156 } 157 } 158 159 private void processType0(PdfDictionary font) { 160 try { 161 PdfObject toUniObject = PdfReader.getPdfObjectRelease(font.get(PdfName.TOUNICODE)); 162 PdfArray df = (PdfArray)PdfReader.getPdfObjectRelease(font.get(PdfName.DESCENDANTFONTS)); 163 PdfDictionary cidft = (PdfDictionary)PdfReader.getPdfObjectRelease(df.getPdfObject(0)); 164 PdfNumber dwo = (PdfNumber)PdfReader.getPdfObjectRelease(cidft.get(PdfName.DW)); 165 int dw = 1000; 166 if (dwo != null) 167 dw = dwo.intValue(); 168 IntHashtable widths = readWidths((PdfArray)PdfReader.getPdfObjectRelease(cidft.get(PdfName.W))); 169 PdfDictionary fontDesc = (PdfDictionary)PdfReader.getPdfObjectRelease(cidft.get(PdfName.FONTDESCRIPTOR)); 170 fillFontDesc(fontDesc); 171 if (toUniObject instanceof PRStream){ 172 fillMetrics(PdfReader.getStreamBytes((PRStream)toUniObject), widths, dw); 173 } 174 175 } catch (Exception e) { 176 throw new ExceptionConverter(e); 177 } 178 } 179 180 private IntHashtable readWidths(PdfArray ws) { 181 IntHashtable hh = new IntHashtable(); 182 if (ws == null) 183 return hh; 184 for (int k = 0; k < ws.size(); ++k) { 185 int c1 = ((PdfNumber)PdfReader.getPdfObjectRelease(ws.getPdfObject(k))).intValue(); 186 PdfObject obj = PdfReader.getPdfObjectRelease(ws.getPdfObject(++k)); 187 if (obj.isArray()) { 188 PdfArray a2 = (PdfArray)obj; 189 for (int j = 0; j < a2.size(); ++j) { 190 int c2 = ((PdfNumber)PdfReader.getPdfObjectRelease(a2.getPdfObject(j))).intValue(); 191 hh.put(c1++, c2); 192 } 193 } 194 else { 195 int c2 = ((PdfNumber)obj).intValue(); 196 int w = ((PdfNumber)PdfReader.getPdfObjectRelease(ws.getPdfObject(++k))).intValue(); 197 for (; c1 <= c2; ++c1) 198 hh.put(c1, w); 199 } 200 } 201 return hh; 202 } 203 204 private String decodeString(PdfString ps) { 205 if (ps.isHexWriting()) 206 return PdfEncodings.convertToString(ps.getBytes(), "UnicodeBigUnmarked"); 207 else 208 return ps.toUnicodeString(); 209 } 210 211 private void fillMetrics(byte[] touni, IntHashtable widths, int dw) { 212 try { 213 PdfContentParser ps = new PdfContentParser(new PRTokeniser(touni)); 214 PdfObject ob = null; 215 boolean notFound = true; 216 int nestLevel = 0; 217 while ((notFound || nestLevel > 0) && (ob = ps.readPRObject()) != null) { 218 if (ob.type() == PdfContentParser.COMMAND_TYPE) { 219 if (ob.toString().equals("begin")) { 220 notFound = false; 221 nestLevel++; 222 } 223 else if (ob.toString().equals("end")) { 224 nestLevel--; 225 } 226 else if (ob.toString().equals("beginbfchar")) { 227 while (true) { 228 PdfObject nx = ps.readPRObject(); 229 if (nx.toString().equals("endbfchar")) 230 break; 231 String cid = decodeString((PdfString)nx); 232 String uni = decodeString((PdfString)ps.readPRObject()); 233 if (uni.length() == 1) { 234 int cidc = cid.charAt(0); 235 int unic = uni.charAt(uni.length() - 1); 236 int w = dw; 237 if (widths.containsKey(cidc)) 238 w = widths.get(cidc); 239 metrics.put(Integer.valueOf(unic), new int[]{cidc, w}); 240 } 241 } 242 } 243 else if (ob.toString().equals("beginbfrange")) { 244 while (true) { 245 PdfObject nx = ps.readPRObject(); 246 if (nx.toString().equals("endbfrange")) 247 break; 248 String cid1 = decodeString((PdfString)nx); 249 String cid2 = decodeString((PdfString)ps.readPRObject()); 250 int cid1c = cid1.charAt(0); 251 int cid2c = cid2.charAt(0); 252 PdfObject ob2 = ps.readPRObject(); 253 if (ob2.isString()) { 254 String uni = decodeString((PdfString)ob2); 255 if (uni.length() == 1) { 256 int unic = uni.charAt(uni.length() - 1); 257 for (; cid1c <= cid2c; cid1c++, unic++) { 258 int w = dw; 259 if (widths.containsKey(cid1c)) 260 w = widths.get(cid1c); 261 metrics.put(Integer.valueOf(unic), new int[]{cid1c, w}); 262 } 263 } 264 } 265 else { 266 PdfArray a = (PdfArray)ob2; 267 for (int j = 0; j < a.size(); ++j, ++cid1c) { 268 String uni = decodeString(a.getAsString(j)); 269 if (uni.length() == 1) { 270 int unic = uni.charAt(uni.length() - 1); 271 int w = dw; 272 if (widths.containsKey(cid1c)) 273 w = widths.get(cid1c); 274 metrics.put(Integer.valueOf(unic), new int[]{cid1c, w}); 275 } 276 } 277 } 278 } 279 } 280 } 281 } 282 } 283 catch (Exception e) { 284 throw new ExceptionConverter(e); 285 } 286 } 287 288 private void doType1TT() { 289 PdfObject enc = PdfReader.getPdfObject(font.get(PdfName.ENCODING)); 290 if (enc == null) 291 fillEncoding(null); 292 else { 293 if (enc.isName()) 294 fillEncoding((PdfName)enc); 295 else { 296 PdfDictionary encDic = (PdfDictionary)enc; 297 enc = PdfReader.getPdfObject(encDic.get(PdfName.BASEENCODING)); 298 if (enc == null) 299 fillEncoding(null); 300 else 301 fillEncoding((PdfName)enc); 302 PdfArray diffs = encDic.getAsArray(PdfName.DIFFERENCES); 303 if (diffs != null) { 304 CMap toUnicode = null; 305 diffmap = new IntHashtable(); 306 int currentNumber = 0; 307 for (int k = 0; k < diffs.size(); ++k) { 308 PdfObject obj = diffs.getPdfObject(k); 309 if (obj.isNumber()) 310 currentNumber = ((PdfNumber)obj).intValue(); 311 else { 312 int c[] = GlyphList.nameToUnicode(PdfName.decodeName(((PdfName)obj).toString())); 313 if (c != null && c.length > 0) { 314 uni2byte.put(c[0], currentNumber); 315 diffmap.put(c[0], currentNumber); 316 } 317 else { 318 if (toUnicode == null) { 319 toUnicode = processToUnicode(); 320 if (toUnicode == null) { 321 toUnicode = new CMap(); 322 } 323 } 324 final String unicode = toUnicode.lookup(new byte[]{(byte) currentNumber}, 0, 1); 325 if ((unicode != null) && (unicode.length() == 1)) { 326 this.uni2byte.put(unicode.charAt(0), currentNumber); 327 this.diffmap.put(unicode.charAt(0), currentNumber); 328 } 329 } 330 ++currentNumber; 331 } 332 } 333 } 334 } 335 } 336 PdfArray newWidths = font.getAsArray(PdfName.WIDTHS); 337 PdfNumber first = font.getAsNumber(PdfName.FIRSTCHAR); 338 PdfNumber last = font.getAsNumber(PdfName.LASTCHAR); 339 if (BuiltinFonts14.containsKey(fontName)) { 340 BaseFont bf; 341 try { 342 bf = BaseFont.createFont(fontName, WINANSI, false); 343 } 344 catch (Exception e) { 345 throw new ExceptionConverter(e); 346 } 347 int e[] = uni2byte.toOrderedKeys(); 348 for (int k = 0; k < e.length; ++k) { 349 int n = uni2byte.get(e[k]); 350 widths[n] = bf.getRawWidth(n, GlyphList.unicodeToName(e[k])); 351 } 352 if (diffmap != null) { //widths for diffmap must override existing ones 353 e = diffmap.toOrderedKeys(); 354 for (int k = 0; k < e.length; ++k) { 355 int n = diffmap.get(e[k]); 356 widths[n] = bf.getRawWidth(n, GlyphList.unicodeToName(e[k])); 357 } 358 diffmap = null; 359 } 360 Ascender = bf.getFontDescriptor(ASCENT, 1000); 361 CapHeight = bf.getFontDescriptor(CAPHEIGHT, 1000); 362 Descender = bf.getFontDescriptor(DESCENT, 1000); 363 ItalicAngle = bf.getFontDescriptor(ITALICANGLE, 1000); 364 llx = bf.getFontDescriptor(BBOXLLX, 1000); 365 lly = bf.getFontDescriptor(BBOXLLY, 1000); 366 urx = bf.getFontDescriptor(BBOXURX, 1000); 367 ury = bf.getFontDescriptor(BBOXURY, 1000); 368 } 369 if (first != null && last != null && newWidths != null) { 370 int f = first.intValue(); 371 for (int k = 0; k < newWidths.size(); ++k) { 372 widths[f + k] = newWidths.getAsNumber(k).intValue(); 373 } 374 } 375 fillFontDesc(font.getAsDict(PdfName.FONTDESCRIPTOR)); 376 } 377 378 private CMap processToUnicode() { 379 CMap cmapRet = null; 380 PdfObject toUni = PdfReader.getPdfObjectRelease(this.font.get(PdfName.TOUNICODE)); 381 if (toUni instanceof PRStream) { 382 try { 383 byte[] touni = PdfReader.getStreamBytes((PRStream)toUni); 384 CMapParser cmapParser = new CMapParser(); 385 cmapRet = cmapParser.parse(new ByteArrayInputStream(touni)); 386 } catch (Exception e) { 387 } 388 } 389 return cmapRet; 390 } 391 392 private void fillFontDesc(PdfDictionary fontDesc) { 393 if (fontDesc == null) 394 return; 395 PdfNumber v = fontDesc.getAsNumber(PdfName.ASCENT); 396 if (v != null) 397 Ascender = v.floatValue(); 398 v = fontDesc.getAsNumber(PdfName.CAPHEIGHT); 399 if (v != null) 400 CapHeight = v.floatValue(); 401 v = fontDesc.getAsNumber(PdfName.DESCENT); 402 if (v != null) 403 Descender = v.floatValue(); 404 v = fontDesc.getAsNumber(PdfName.ITALICANGLE); 405 if (v != null) 406 ItalicAngle = v.floatValue(); 407 PdfArray bbox = fontDesc.getAsArray(PdfName.FONTBBOX); 408 if (bbox != null) { 409 llx = bbox.getAsNumber(0).floatValue(); 410 lly = bbox.getAsNumber(1).floatValue(); 411 urx = bbox.getAsNumber(2).floatValue(); 412 ury = bbox.getAsNumber(3).floatValue(); 413 if (llx > urx) { 414 float t = llx; 415 llx = urx; 416 urx = t; 417 } 418 if (lly > ury) { 419 float t = lly; 420 lly = ury; 421 ury = t; 422 } 423 } 424 } 425 426 private void fillEncoding(PdfName encoding) { 427 if (PdfName.MAC_ROMAN_ENCODING.equals(encoding) || PdfName.WIN_ANSI_ENCODING.equals(encoding)) { 428 byte b[] = new byte[256]; 429 for (int k = 0; k < 256; ++k) 430 b[k] = (byte)k; 431 String enc = WINANSI; 432 if (PdfName.MAC_ROMAN_ENCODING.equals(encoding)) 433 enc = MACROMAN; 434 String cv = PdfEncodings.convertToString(b, enc); 435 char arr[] = cv.toCharArray(); 436 for (int k = 0; k < 256; ++k) { 437 uni2byte.put(arr[k], k); 438 } 439 } 440 else { 441 for (int k = 0; k < 256; ++k) { 442 uni2byte.put(stdEnc[k], k); 443 } 444 } 445 } 446 447 /** Gets the family name of the font. If it is a True Type font 448 * each array element will have {Platform ID, Platform Encoding ID, 449 * Language ID, font name}. The interpretation of this values can be 450 * found in the Open Type specification, chapter 2, in the 'name' table.<br> 451 * For the other fonts the array has a single element with {"", "", "", 452 * font name}. 453 * @return the family name of the font 454 * 455 */ 456 @Override 457 public String[][] getFamilyFontName() { 458 return getFullFontName(); 459 } 460 461 /** Gets the font parameter identified by <CODE>key</CODE>. Valid values 462 * for <CODE>key</CODE> are <CODE>ASCENT</CODE>, <CODE>CAPHEIGHT</CODE>, <CODE>DESCENT</CODE>, 463 * <CODE>ITALICANGLE</CODE>, <CODE>BBOXLLX</CODE>, <CODE>BBOXLLY</CODE>, <CODE>BBOXURX</CODE> 464 * and <CODE>BBOXURY</CODE>. 465 * @param key the parameter to be extracted 466 * @param fontSize the font size in points 467 * @return the parameter in points 468 * 469 */ 470 @Override 471 public float getFontDescriptor(int key, float fontSize) { 472 if (cjkMirror != null) 473 return cjkMirror.getFontDescriptor(key, fontSize); 474 switch (key) { 475 case AWT_ASCENT: 476 case ASCENT: 477 return Ascender * fontSize / 1000; 478 case CAPHEIGHT: 479 return CapHeight * fontSize / 1000; 480 case AWT_DESCENT: 481 case DESCENT: 482 return Descender * fontSize / 1000; 483 case ITALICANGLE: 484 return ItalicAngle; 485 case BBOXLLX: 486 return llx * fontSize / 1000; 487 case BBOXLLY: 488 return lly * fontSize / 1000; 489 case BBOXURX: 490 return urx * fontSize / 1000; 491 case BBOXURY: 492 return ury * fontSize / 1000; 493 case AWT_LEADING: 494 return 0; 495 case AWT_MAXADVANCE: 496 return (urx - llx) * fontSize / 1000; 497 } 498 return 0; 499 } 500 501 /** Gets the full name of the font. If it is a True Type font 502 * each array element will have {Platform ID, Platform Encoding ID, 503 * Language ID, font name}. The interpretation of this values can be 504 * found in the Open Type specification, chapter 2, in the 'name' table.<br> 505 * For the other fonts the array has a single element with {"", "", "", 506 * font name}. 507 * @return the full name of the font 508 * 509 */ 510 @Override 511 public String[][] getFullFontName() { 512 return new String[][]{{"", "", "", fontName}}; 513 } 514 515 /** Gets all the entries of the names-table. If it is a True Type font 516 * each array element will have {Name ID, Platform ID, Platform Encoding ID, 517 * Language ID, font name}. The interpretation of this values can be 518 * found in the Open Type specification, chapter 2, in the 'name' table.<br> 519 * For the other fonts the array has a single element with {"4", "", "", "", 520 * font name}. 521 * @return the full name of the font 522 * @since 2.0.8 523 */ 524 @Override 525 public String[][] getAllNameEntries() { 526 return new String[][]{{"4", "", "", "", fontName}}; 527 } 528 529 /** Gets the kerning between two Unicode chars. 530 * @param char1 the first char 531 * @param char2 the second char 532 * @return the kerning to be applied 533 * 534 */ 535 @Override 536 public int getKerning(int char1, int char2) { 537 return 0; 538 } 539 540 /** Gets the postscript font name. 541 * @return the postscript font name 542 * 543 */ 544 @Override 545 public String getPostscriptFontName() { 546 return fontName; 547 } 548 549 /** Gets the width from the font according to the Unicode char <CODE>c</CODE> 550 * or the <CODE>name</CODE>. If the <CODE>name</CODE> is null it's a symbolic font. 551 * @param c the unicode char 552 * @param name the glyph name 553 * @return the width of the char 554 * 555 */ 556 @Override 557 int getRawWidth(int c, String name) { 558 return 0; 559 } 560 561 /** Checks if the font has any kerning pairs. 562 * @return <CODE>true</CODE> if the font has any kerning pairs 563 * 564 */ 565 @Override 566 public boolean hasKernPairs() { 567 return false; 568 } 569 570 /** Outputs to the writer the font dictionaries and streams. 571 * @param writer the writer for this document 572 * @param ref the font indirect reference 573 * @param params several parameters that depend on the font type 574 * @throws IOException on error 575 * @throws DocumentException error in generating the object 576 * 577 */ 578 @Override 579 void writeFont(PdfWriter writer, PdfIndirectReference ref, Object[] params) throws DocumentException, IOException { 580 } 581 582 /** 583 * Always returns null. 584 * @return null 585 * @since 2.1.3 586 */ 587 @Override 588 public PdfStream getFullFontStream() { 589 return null; 590 } 591 592 /** 593 * Gets the width of a <CODE>char</CODE> in normalized 1000 units. 594 * @param char1 the unicode <CODE>char</CODE> to get the width of 595 * @return the width in normalized 1000 units 596 */ 597 @Override 598 public int getWidth(int char1) { 599 if (cjkMirror != null) 600 return cjkMirror.getWidth(char1); 601 else if (isType0) { 602 int[] ws = metrics.get(Integer.valueOf(char1)); 603 if (ws != null) 604 return ws[1]; 605 else 606 return 0; 607 } 608 else 609 return super.getWidth(char1); 610 } 611 612 @Override 613 public int getWidth(String text) { 614 if (cjkMirror != null) 615 return cjkMirror.getWidth(text); 616 else if (isType0) { 617 char[] chars = text.toCharArray(); 618 int len = chars.length; 619 int total = 0; 620 for (int k = 0; k < len; ++k) { 621 int[] ws = metrics.get(Integer.valueOf(chars[k])); 622 if (ws != null) 623 total += ws[1]; 624 } 625 return total; 626 } 627 else 628 return super.getWidth(text); 629 } 630 631 @Override 632 byte[] convertToBytes(String text) { 633 if (cjkMirror != null) 634 return PdfEncodings.convertToBytes(text, CJKFont.CJK_ENCODING); 635 else if (isType0) { 636 char[] chars = text.toCharArray(); 637 int len = chars.length; 638 byte[] b = new byte[len * 2]; 639 int bptr = 0; 640 for (int k = 0; k < len; ++k) { 641 int[] ws = metrics.get(Integer.valueOf(chars[k])); 642 if (ws != null) { 643 int g = ws[0]; 644 b[bptr++] = (byte)(g / 256); 645 b[bptr++] = (byte)g; 646 } 647 } 648 if (bptr == b.length) 649 return b; 650 else { 651 byte[] nb = new byte[bptr]; 652 System.arraycopy(b, 0, nb, 0, bptr); 653 return nb; 654 } 655 } 656 else { 657 char cc[] = text.toCharArray(); 658 byte b[] = new byte[cc.length]; 659 int ptr = 0; 660 for (int k = 0; k < cc.length; ++k) { 661 if (uni2byte.containsKey(cc[k])) 662 b[ptr++] = (byte)uni2byte.get(cc[k]); 663 } 664 if (ptr == b.length) 665 return b; 666 else { 667 byte[] b2 = new byte[ptr]; 668 System.arraycopy(b, 0, b2, 0, ptr); 669 return b2; 670 } 671 } 672 } 673 674 @Override 675 byte[] convertToBytes(int char1) { 676 if (cjkMirror != null) 677 return PdfEncodings.convertToBytes((char)char1, CJKFont.CJK_ENCODING); 678 else if (isType0) { 679 int[] ws = metrics.get(Integer.valueOf(char1)); 680 if (ws != null) { 681 int g = ws[0]; 682 return new byte[]{(byte)(g / 256), (byte)g}; 683 } 684 else 685 return new byte[0]; 686 } 687 else { 688 if (uni2byte.containsKey(char1)) 689 return new byte[]{(byte)uni2byte.get(char1)}; 690 else 691 return new byte[0]; 692 } 693 } 694 695 PdfIndirectReference getIndirectReference() { 696 return refFont; 697 } 698 699 @Override 700 public boolean charExists(int c) { 701 if (cjkMirror != null) 702 return cjkMirror.charExists(c); 703 else if (isType0) { 704 return metrics.containsKey(Integer.valueOf(c)); 705 } 706 else 707 return super.charExists(c); 708 } 709 710 /** 711 * Sets the font name that will appear in the pdf font dictionary. 712 * It does nothing in this case as the font is already in the document. 713 * @param name the new font name 714 */ 715 @Override 716 public void setPostscriptFontName(String name) { 717 } 718 719 @Override 720 public boolean setKerning(int char1, int char2, int kern) { 721 return false; 722 } 723 724 @Override 725 public int[] getCharBBox(int c) { 726 return null; 727 } 728 729 @Override 730 protected int[] getRawCharBBox(int c, String name) { 731 return null; 732 } 733 734 /** 735 * Exposes the unicode - > CID map that is constructed from the font's encoding 736 * @return the unicode to CID map 737 * @since 2.1.7 738 */ 739 IntHashtable getUni2Byte(){ 740 return uni2byte; 741 } 742 743 /** 744 * Gets the difference map 745 * @return the difference map 746 * @since 5.0.5 747 */ 748 IntHashtable getDiffmap() { 749 return diffmap; 750 } 751}