001/* 002 * $Id: CFFFont.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 */ 044 045/* 046 * Comments by the original author, Sivan Toledo: 047 * I created this class in order to add to iText the ability to utilize 048 * OpenType fonts with CFF glyphs (these usually have an .otf extension). 049 * The CFF font within the CFF table of the OT font might be either a CID 050 * or a Type1 font. (CFF fonts may also contain multiple fonts; I do not 051 * know if this is allowed in an OT table). The PDF spec, however, only 052 * allow a CID font with an Identity-H or Identity-V encoding. Otherwise, 053 * you are limited to an 8-bit encoding. 054 * Adobe fonts come in both flavors. That is, the OTFs sometimes have 055 * a CID CFF inside (for Japanese fonts), and sometimes a Type1 CFF 056 * (virtually all the others, Latin/Greek/Cyrillic). So to easily use 057 * all the glyphs in the latter, without creating multiple 8-bit encoding, 058 * I wrote this class, whose main purpose is to convert a Type1 font inside 059 * a CFF container (which might include other fonts) into a CID CFF font 060 * that can be directly embeded in the PDF. 061 * 062 * Limitations of the current version: 063 * 1. It does not extract a single CID font from a CFF that contains that 064 * particular CID along with other fonts. The Adobe Japanese OTF's that 065 * I have only have one font in the CFF table, so these can be 066 * embeded in the PDF as is. 067 * 2. It does not yet subset fonts. 068 * 3. It may or may not work on CFF fonts that are not within OTF's. 069 * I didn't try that. In any case, that would probably only be 070 * useful for subsetting CID fonts, not for CFF Type1 fonts (I don't 071 * think there are any available. 072 * I plan to extend the class to support these three features at some 073 * future time. 074 */ 075 076package com.itextpdf.text.pdf; 077 078import java.util.Iterator; 079import java.util.LinkedList; 080 081import com.itextpdf.text.ExceptionConverter; 082 083public class CFFFont { 084 085 static final String operatorNames[] = { 086 "version", "Notice", "FullName", "FamilyName", 087 "Weight", "FontBBox", "BlueValues", "OtherBlues", 088 "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", 089 "UNKNOWN_12", "UniqueID", "XUID", "charset", 090 "Encoding", "CharStrings", "Private", "Subrs", 091 "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23", 092 "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27", 093 "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31", 094 "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", 095 "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", 096 "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz", 097 "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15", 098 "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed", 099 "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", 100 "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27", 101 "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion", 102 "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", 103 "FDArray", "FDSelect", "FontName" 104 }; 105 106 static final String standardStrings[] = { 107 // Automatically generated from Appendix A of the CFF specification; do 108 // not edit. Size should be 391. 109 ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", 110 "percent", "ampersand", "quoteright", "parenleft", "parenright", 111 "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", 112 "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", 113 "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", 114 "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", 115 "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", 116 "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", 117 "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", 118 "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", 119 "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", 120 "florin", "section", "currency", "quotesingle", "quotedblleft", 121 "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", 122 "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", 123 "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", 124 "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", 125 "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", 126 "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", 127 "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", 128 "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", 129 "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", 130 "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", 131 "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", 132 "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", 133 "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", 134 "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", 135 "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", 136 "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", 137 "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", 138 "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", 139 "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", 140 "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", 141 "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", 142 "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", 143 "parenleftsuperior", "parenrightsuperior", "twodotenleader", 144 "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", 145 "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", 146 "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", 147 "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", 148 "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", 149 "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", 150 "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", 151 "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", 152 "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", 153 "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", 154 "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", 155 "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", 156 "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", 157 "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", 158 "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", 159 "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", 160 "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", 161 "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", 162 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", 163 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", 164 "threeinferior", "fourinferior", "fiveinferior", "sixinferior", 165 "seveninferior", "eightinferior", "nineinferior", "centinferior", 166 "dollarinferior", "periodinferior", "commainferior", "Agravesmall", 167 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", 168 "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", 169 "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", 170 "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", 171 "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", 172 "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", 173 "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", 174 "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", 175 "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" 176 }; 177 178 //private String[] strings; 179 public String getString(char sid) { 180 if (sid < standardStrings.length) return standardStrings[sid]; 181 if (sid >= standardStrings.length+stringOffsets.length-1) return null; 182 int j = sid - standardStrings.length; 183 //java.lang.System.err.println("going for "+j); 184 int p = getPosition(); 185 seek(stringOffsets[j]); 186 StringBuffer s = new StringBuffer(); 187 for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) { 188 s.append(getCard8()); 189 } 190 seek(p); 191 return s.toString(); 192 } 193 194 char getCard8() { 195 try { 196 byte i = buf.readByte(); 197 return (char)(i & 0xff); 198 } 199 catch (Exception e) { 200 throw new ExceptionConverter(e); 201 } 202 } 203 204 char getCard16() { 205 try { 206 return buf.readChar(); 207 } 208 catch (Exception e) { 209 throw new ExceptionConverter(e); 210 } 211 } 212 213 int getOffset(int offSize) { 214 int offset = 0; 215 for (int i=0; i<offSize; i++) { 216 offset *= 256; 217 offset += getCard8(); 218 } 219 return offset; 220 } 221 222 void seek(int offset) { 223 try { 224 buf.seek(offset); 225 } 226 catch (Exception e) { 227 throw new ExceptionConverter(e); 228 } 229 } 230 231 short getShort() { 232 try { 233 return buf.readShort(); 234 } 235 catch (Exception e) { 236 throw new ExceptionConverter(e); 237 } 238 } 239 240 int getInt() { 241 try { 242 return buf.readInt(); 243 } 244 catch (Exception e) { 245 throw new ExceptionConverter(e); 246 } 247 } 248 249 int getPosition() { 250 try { 251 return buf.getFilePointer(); 252 } 253 catch (Exception e) { 254 throw new ExceptionConverter(e); 255 } 256 } 257 int nextIndexOffset; 258 // read the offsets in the next index 259 // data structure, convert to global 260 // offsets, and return them. 261 // Sets the nextIndexOffset. 262 int[] getIndex(int nextIndexOffset) { 263 int count, indexOffSize; 264 265 seek(nextIndexOffset); 266 count = getCard16(); 267 int[] offsets = new int[count+1]; 268 269 if (count==0) { 270 offsets[0] = -1; 271 nextIndexOffset += 2; // TODO death store to local var .. should this be this.nextIndexOffset ? 272 return offsets; 273 } 274 275 indexOffSize = getCard8(); 276 277 for (int j=0; j<=count; j++) { 278 //nextIndexOffset = ofset to relative segment 279 offsets[j] = nextIndexOffset 280 //2-> count in the index header. 1->offset size in index header 281 + 2+1 282 //offset array size * offset size 283 + (count+1)*indexOffSize 284 //???zero <-> one base 285 - 1 286 // read object offset relative to object array base 287 + getOffset(indexOffSize); 288 } 289 //nextIndexOffset = offsets[count]; 290 return offsets; 291 } 292 293 protected String key; 294 protected Object[] args = new Object[48]; 295 protected int arg_count = 0; 296 297 protected void getDictItem() { 298 for (int i=0; i<arg_count; i++) args[i]=null; 299 arg_count = 0; 300 key = null; 301 boolean gotKey = false; 302 303 while (!gotKey) { 304 char b0 = getCard8(); 305 if (b0 == 29) { 306 int item = getInt(); 307 args[arg_count] = Integer.valueOf(item); 308 arg_count++; 309 //System.err.println(item+" "); 310 continue; 311 } 312 if (b0 == 28) { 313 short item = getShort(); 314 args[arg_count] = Integer.valueOf(item); 315 arg_count++; 316 //System.err.println(item+" "); 317 continue; 318 } 319 if (b0 >= 32 && b0 <= 246) { 320 byte item = (byte) (b0-139); 321 args[arg_count] = Integer.valueOf(item); 322 arg_count++; 323 //System.err.println(item+" "); 324 continue; 325 } 326 if (b0 >= 247 && b0 <= 250) { 327 char b1 = getCard8(); 328 short item = (short) ((b0-247)*256+b1+108); 329 args[arg_count] = Integer.valueOf(item); 330 arg_count++; 331 //System.err.println(item+" "); 332 continue; 333 } 334 if (b0 >= 251 && b0 <= 254) { 335 char b1 = getCard8(); 336 short item = (short) (-(b0-251)*256-b1-108); 337 args[arg_count] = Integer.valueOf(item); 338 arg_count++; 339 //System.err.println(item+" "); 340 continue; 341 } 342 if (b0 == 30) { 343 StringBuilder item = new StringBuilder(""); 344 boolean done = false; 345 char buffer = 0; 346 byte avail = 0; 347 int nibble = 0; 348 while (!done) { 349 // get a nibble 350 if (avail==0) { buffer = getCard8(); avail=2; } 351 if (avail==1) { nibble = buffer / 16; avail--; } 352 if (avail==2) { nibble = buffer % 16; avail--; } 353 switch (nibble) { 354 case 0xa: item.append(".") ; break; 355 case 0xb: item.append("E") ; break; 356 case 0xc: item.append("E-"); break; 357 case 0xe: item.append("-") ; break; 358 case 0xf: done=true ; break; 359 default: 360 if (nibble >= 0 && nibble <= 9) 361 item.append(String.valueOf(nibble)); 362 else { 363 item.append("<NIBBLE ERROR: ").append(nibble).append('>'); 364 done = true; 365 } 366 break; 367 } 368 } 369 args[arg_count] = item.toString(); 370 arg_count++; 371 //System.err.println(" real=["+item+"]"); 372 continue; 373 } 374 if (b0 <= 21) { 375 gotKey=true; 376 if (b0 != 12) key = operatorNames[b0]; 377 else key = operatorNames[32 + getCard8()]; 378 //for (int i=0; i<arg_count; i++) 379 // System.err.print(args[i].toString()+" "); 380 //System.err.println(key+" ;"); 381 continue; 382 } 383 } 384 } 385 386 /** List items for the linked list that builds the new CID font. 387 */ 388 389 protected static abstract class Item { 390 protected int myOffset = -1; 391 /** remember the current offset and increment by item's size in bytes. */ 392 public void increment(int[] currentOffset) { 393 myOffset = currentOffset[0]; 394 } 395 /** Emit the byte stream for this item. */ 396 public void emit(byte[] buffer) {} 397 /** Fix up cross references to this item (applies only to markers). */ 398 public void xref() {} 399 } 400 401 protected static abstract class OffsetItem extends Item { 402 public int value; 403 /** set the value of an offset item that was initially unknown. 404 * It will be fixed up latex by a call to xref on some marker. 405 */ 406 public void set(int offset) { this.value = offset; } 407 } 408 409 410 /** A range item. 411 */ 412 413 protected static final class RangeItem extends Item { 414 public int offset, length; 415 private RandomAccessFileOrArray buf; 416 public RangeItem(RandomAccessFileOrArray buf, int offset, int length) { 417 this.offset = offset; 418 this.length = length; 419 this.buf = buf; 420 } 421 @Override 422 public void increment(int[] currentOffset) { 423 super.increment(currentOffset); 424 currentOffset[0] += length; 425 } 426 @Override 427 public void emit(byte[] buffer) { 428 //System.err.println("range emit offset "+offset+" size="+length); 429 try { 430 buf.seek(offset); 431 for (int i=myOffset; i<myOffset+length; i++) 432 buffer[i] = buf.readByte(); 433 } 434 catch (Exception e) { 435 throw new ExceptionConverter(e); 436 } 437 //System.err.println("finished range emit"); 438 } 439 } 440 441 /** An index-offset item for the list. 442 * The size denotes the required size in the CFF. A positive 443 * value means that we need a specific size in bytes (for offset arrays) 444 * and a negative value means that this is a dict item that uses a 445 * variable-size representation. 446 */ 447 static protected final class IndexOffsetItem extends OffsetItem { 448 public final int size; 449 public IndexOffsetItem(int size, int value) {this.size=size; this.value=value;} 450 public IndexOffsetItem(int size) {this.size=size; } 451 452 @Override 453 public void increment(int[] currentOffset) { 454 super.increment(currentOffset); 455 currentOffset[0] += size; 456 } 457 @Override 458 public void emit(byte[] buffer) { 459 int i=0; 460 switch (size) { 461 case 4: 462 buffer[myOffset+i] = (byte) (value >>> 24 & 0xff); 463 i++; 464 case 3: 465 buffer[myOffset+i] = (byte) (value >>> 16 & 0xff); 466 i++; 467 case 2: 468 buffer[myOffset+i] = (byte) (value >>> 8 & 0xff); 469 i++; 470 case 1: 471 buffer[myOffset+i] = (byte) (value >>> 0 & 0xff); 472 i++; 473 } 474 /* 475 int mask = 0xff; 476 for (int i=size-1; i>=0; i--) { 477 buffer[myOffset+i] = (byte) (value & mask); 478 mask <<= 8; 479 } 480 */ 481 } 482 } 483 484 static protected final class IndexBaseItem extends Item { 485 public IndexBaseItem() {} 486 } 487 488 static protected final class IndexMarkerItem extends Item { 489 private OffsetItem offItem; 490 private IndexBaseItem indexBase; 491 public IndexMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { 492 this.offItem = offItem; 493 this.indexBase = indexBase; 494 } 495 @Override 496 public void xref() { 497 //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); 498 offItem.set(this.myOffset-indexBase.myOffset+1); 499 } 500 } 501 /** 502 * TODO To change the template for this generated type comment go to 503 * Window - Preferences - Java - Code Generation - Code and Comments 504 */ 505 static protected final class SubrMarkerItem extends Item { 506 private OffsetItem offItem; 507 private IndexBaseItem indexBase; 508 public SubrMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { 509 this.offItem = offItem; 510 this.indexBase = indexBase; 511 } 512 @Override 513 public void xref() { 514 //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); 515 offItem.set(this.myOffset-indexBase.myOffset); 516 } 517 } 518 519 520 /** an unknown offset in a dictionary for the list. 521 * We will fix up the offset later; for now, assume it's large. 522 */ 523 static protected final class DictOffsetItem extends OffsetItem { 524 public final int size; 525 public DictOffsetItem() {this.size=5; } 526 527 @Override 528 public void increment(int[] currentOffset) { 529 super.increment(currentOffset); 530 currentOffset[0] += size; 531 } 532 // this is incomplete! 533 @Override 534 public void emit(byte[] buffer) { 535 if (size==5) { 536 buffer[myOffset] = 29; 537 buffer[myOffset+1] = (byte) (value >>> 24 & 0xff); 538 buffer[myOffset+2] = (byte) (value >>> 16 & 0xff); 539 buffer[myOffset+3] = (byte) (value >>> 8 & 0xff); 540 buffer[myOffset+4] = (byte) (value >>> 0 & 0xff); 541 } 542 } 543 } 544 545 /** Card24 item. 546 */ 547 548 static protected final class UInt24Item extends Item { 549 public int value; 550 public UInt24Item(int value) {this.value=value;} 551 552 @Override 553 public void increment(int[] currentOffset) { 554 super.increment(currentOffset); 555 currentOffset[0] += 3; 556 } 557 // this is incomplete! 558 @Override 559 public void emit(byte[] buffer) { 560 buffer[myOffset+0] = (byte) (value >>> 16 & 0xff); 561 buffer[myOffset+1] = (byte) (value >>> 8 & 0xff); 562 buffer[myOffset+2] = (byte) (value >>> 0 & 0xff); 563 } 564 } 565 566 /** Card32 item. 567 */ 568 569 static protected final class UInt32Item extends Item { 570 public int value; 571 public UInt32Item(int value) {this.value=value;} 572 573 @Override 574 public void increment(int[] currentOffset) { 575 super.increment(currentOffset); 576 currentOffset[0] += 4; 577 } 578 // this is incomplete! 579 @Override 580 public void emit(byte[] buffer) { 581 buffer[myOffset+0] = (byte) (value >>> 24 & 0xff); 582 buffer[myOffset+1] = (byte) (value >>> 16 & 0xff); 583 buffer[myOffset+2] = (byte) (value >>> 8 & 0xff); 584 buffer[myOffset+3] = (byte) (value >>> 0 & 0xff); 585 } 586 } 587 588 /** A SID or Card16 item. 589 */ 590 591 static protected final class UInt16Item extends Item { 592 public char value; 593 public UInt16Item(char value) {this.value=value;} 594 595 @Override 596 public void increment(int[] currentOffset) { 597 super.increment(currentOffset); 598 currentOffset[0] += 2; 599 } 600 // this is incomplete! 601 @Override 602 public void emit(byte[] buffer) { 603 buffer[myOffset+0] = (byte) (value >>> 8 & 0xff); 604 buffer[myOffset+1] = (byte) (value >>> 0 & 0xff); 605 } 606 } 607 608 /** A Card8 item. 609 */ 610 611 static protected final class UInt8Item extends Item { 612 public char value; 613 public UInt8Item(char value) {this.value=value;} 614 615 @Override 616 public void increment(int[] currentOffset) { 617 super.increment(currentOffset); 618 currentOffset[0] += 1; 619 } 620 // this is incomplete! 621 @Override 622 public void emit(byte[] buffer) { 623 buffer[myOffset+0] = (byte) (value >>> 0 & 0xff); 624 } 625 } 626 627 static protected final class StringItem extends Item { 628 public String s; 629 public StringItem(String s) {this.s=s;} 630 631 @Override 632 public void increment(int[] currentOffset) { 633 super.increment(currentOffset); 634 currentOffset[0] += s.length(); 635 } 636 @Override 637 public void emit(byte[] buffer) { 638 for (int i=0; i<s.length(); i++) 639 buffer[myOffset+i] = (byte) (s.charAt(i) & 0xff); 640 } 641 } 642 643 644 /** A dictionary number on the list. 645 * This implementation is inefficient: it doesn't use the variable-length 646 * representation. 647 */ 648 649 static protected final class DictNumberItem extends Item { 650 public final int value; 651 public int size = 5; 652 public DictNumberItem(int value) {this.value=value;} 653 @Override 654 public void increment(int[] currentOffset) { 655 super.increment(currentOffset); 656 currentOffset[0] += size; 657 } 658 // this is incomplete! 659 @Override 660 public void emit(byte[] buffer) { 661 if (size==5) { 662 buffer[myOffset] = 29; 663 buffer[myOffset+1] = (byte) (value >>> 24 & 0xff); 664 buffer[myOffset+2] = (byte) (value >>> 16 & 0xff); 665 buffer[myOffset+3] = (byte) (value >>> 8 & 0xff); 666 buffer[myOffset+4] = (byte) (value >>> 0 & 0xff); 667 } 668 } 669 } 670 671 /** An offset-marker item for the list. 672 * It is used to mark an offset and to set the offset list item. 673 */ 674 675 static protected final class MarkerItem extends Item { 676 OffsetItem p; 677 public MarkerItem(OffsetItem pointerToMarker) {p=pointerToMarker;} 678 @Override 679 public void xref() { 680 p.set(this.myOffset); 681 } 682 } 683 684 /** a utility that creates a range item for an entire index 685 * 686 * @param indexOffset where the index is 687 * @return a range item representing the entire index 688 */ 689 690 protected RangeItem getEntireIndexRange(int indexOffset) { 691 seek(indexOffset); 692 int count = getCard16(); 693 if (count==0) { 694 return new RangeItem(buf,indexOffset,2); 695 } else { 696 int indexOffSize = getCard8(); 697 seek(indexOffset+2+1+count*indexOffSize); 698 int size = getOffset(indexOffSize)-1; 699 return new RangeItem(buf,indexOffset, 700 2+1+(count+1)*indexOffSize+size); 701 } 702 } 703 704 705 /** get a single CID font. The PDF architecture (1.4) 706 * supports 16-bit strings only with CID CFF fonts, not 707 * in Type-1 CFF fonts, so we convert the font to CID if 708 * it is in the Type-1 format. 709 * Two other tasks that we need to do are to select 710 * only a single font from the CFF package (this again is 711 * a PDF restriction) and to subset the CharStrings glyph 712 * description. 713 */ 714 715 716 public byte[] getCID(String fontName) 717 //throws java.io.FileNotFoundException 718 { 719 int j; 720 for (j=0; j<fonts.length; j++) 721 if (fontName.equals(fonts[j].name)) break; 722 if (j==fonts.length) return null; 723 724 LinkedList<Item> l = new LinkedList<Item>(); 725 726 // copy the header 727 728 seek(0); 729 730 int major = getCard8(); 731 int minor = getCard8(); 732 int hdrSize = getCard8(); 733 int offSize = getCard8(); 734 nextIndexOffset = hdrSize; 735 736 l.addLast(new RangeItem(buf,0,hdrSize)); 737 738 int nglyphs=-1, nstrings=-1; 739 if ( ! fonts[j].isCID ) { 740 // count the glyphs 741 seek(fonts[j].charstringsOffset); 742 nglyphs = getCard16(); 743 seek(stringIndexOffset); 744 nstrings = getCard16()+standardStrings.length; 745 //System.err.println("number of glyphs = "+nglyphs); 746 } 747 748 // create a name index 749 750 l.addLast(new UInt16Item((char)1)); // count 751 l.addLast(new UInt8Item((char)1)); // offSize 752 l.addLast(new UInt8Item((char)1)); // first offset 753 l.addLast(new UInt8Item((char)( 1+fonts[j].name.length() ))); 754 l.addLast(new StringItem(fonts[j].name)); 755 756 // create the topdict Index 757 758 759 l.addLast(new UInt16Item((char)1)); // count 760 l.addLast(new UInt8Item((char)2)); // offSize 761 l.addLast(new UInt16Item((char)1)); // first offset 762 OffsetItem topdictIndex1Ref = new IndexOffsetItem(2); 763 l.addLast(topdictIndex1Ref); 764 IndexBaseItem topdictBase = new IndexBaseItem(); 765 l.addLast(topdictBase); 766 767 /* 768 int maxTopdictLen = (topdictOffsets[j+1]-topdictOffsets[j]) 769 + 9*2 // at most 9 new keys 770 + 8*5 // 8 new integer arguments 771 + 3*2;// 3 new SID arguments 772 */ 773 774 //int topdictNext = 0; 775 //byte[] topdict = new byte[maxTopdictLen]; 776 777 OffsetItem charsetRef = new DictOffsetItem(); 778 OffsetItem charstringsRef = new DictOffsetItem(); 779 OffsetItem fdarrayRef = new DictOffsetItem(); 780 OffsetItem fdselectRef = new DictOffsetItem(); 781 782 if ( !fonts[j].isCID ) { 783 // create a ROS key 784 l.addLast(new DictNumberItem(nstrings)); 785 l.addLast(new DictNumberItem(nstrings+1)); 786 l.addLast(new DictNumberItem(0)); 787 l.addLast(new UInt8Item((char)12)); 788 l.addLast(new UInt8Item((char)30)); 789 // create a CIDCount key 790 l.addLast(new DictNumberItem(nglyphs)); 791 l.addLast(new UInt8Item((char)12)); 792 l.addLast(new UInt8Item((char)34)); 793 // What about UIDBase (12,35)? Don't know what is it. 794 // I don't think we need FontName; the font I looked at didn't have it. 795 } 796 797 // create an FDArray key 798 l.addLast(fdarrayRef); 799 l.addLast(new UInt8Item((char)12)); 800 l.addLast(new UInt8Item((char)36)); 801 // create an FDSelect key 802 l.addLast(fdselectRef); 803 l.addLast(new UInt8Item((char)12)); 804 l.addLast(new UInt8Item((char)37)); 805 // create an charset key 806 l.addLast(charsetRef); 807 l.addLast(new UInt8Item((char)15)); 808 // create a CharStrings key 809 l.addLast(charstringsRef); 810 l.addLast(new UInt8Item((char)17)); 811 812 seek(topdictOffsets[j]); 813 while (getPosition() < topdictOffsets[j+1]) { 814 int p1 = getPosition(); 815 getDictItem(); 816 int p2 = getPosition(); 817 if (key=="Encoding" 818 || key=="Private" 819 || key=="FDSelect" 820 || key=="FDArray" 821 || key=="charset" 822 || key=="CharStrings" 823 ) { 824 // just drop them 825 } else { 826 l.add(new RangeItem(buf,p1,p2-p1)); 827 } 828 } 829 830 l.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase)); 831 832 // Copy the string index and append new strings. 833 // We need 3 more strings: Registry, Ordering, and a FontName for one FD. 834 // The total length is at most "Adobe"+"Identity"+63 = 76 835 836 if (fonts[j].isCID) { 837 l.addLast(getEntireIndexRange(stringIndexOffset)); 838 } else { 839 String fdFontName = fonts[j].name+"-OneRange"; 840 if (fdFontName.length() > 127) 841 fdFontName = fdFontName.substring(0,127); 842 String extraStrings = "Adobe"+"Identity"+fdFontName; 843 844 int origStringsLen = stringOffsets[stringOffsets.length-1] 845 - stringOffsets[0]; 846 int stringsBaseOffset = stringOffsets[0]-1; 847 848 byte stringsIndexOffSize; 849 if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1; 850 else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2; 851 else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3; 852 else stringsIndexOffSize = 4; 853 854 l.addLast(new UInt16Item((char)(stringOffsets.length-1+3))); // count 855 l.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize 856 for (int stringOffset : stringOffsets) 857 l.addLast(new IndexOffsetItem(stringsIndexOffSize, 858 stringOffset-stringsBaseOffset)); 859 int currentStringsOffset = stringOffsets[stringOffsets.length-1] 860 - stringsBaseOffset; 861 //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 862 currentStringsOffset += "Adobe".length(); 863 l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 864 currentStringsOffset += "Identity".length(); 865 l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 866 currentStringsOffset += fdFontName.length(); 867 l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 868 869 l.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen)); 870 l.addLast(new StringItem(extraStrings)); 871 } 872 873 // copy the global subroutine index 874 875 l.addLast(getEntireIndexRange(gsubrIndexOffset)); 876 877 // deal with fdarray, fdselect, and the font descriptors 878 879 if (fonts[j].isCID) { 880 // copy the FDArray, FDSelect, charset 881 } else { 882 // create FDSelect 883 l.addLast(new MarkerItem(fdselectRef)); 884 l.addLast(new UInt8Item((char)3)); // format identifier 885 l.addLast(new UInt16Item((char)1)); // nRanges 886 887 l.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph 888 l.addLast(new UInt8Item((char)0)); // Range[0].fd 889 890 l.addLast(new UInt16Item((char)nglyphs)); // sentinel 891 892 // recreate a new charset 893 // This format is suitable only for fonts without subsetting 894 895 l.addLast(new MarkerItem(charsetRef)); 896 l.addLast(new UInt8Item((char)2)); // format identifier 897 898 l.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef) 899 l.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft 900 // now all are covered, the data structure is complete. 901 902 // create a font dict index (fdarray) 903 904 l.addLast(new MarkerItem(fdarrayRef)); 905 l.addLast(new UInt16Item((char)1)); 906 l.addLast(new UInt8Item((char)1)); // offSize 907 l.addLast(new UInt8Item((char)1)); // first offset 908 909 OffsetItem privateIndex1Ref = new IndexOffsetItem(1); 910 l.addLast(privateIndex1Ref); 911 IndexBaseItem privateBase = new IndexBaseItem(); 912 l.addLast(privateBase); 913 914 // looking at the PS that acrobat generates from a PDF with 915 // a CFF opentype font embedded with an identity-H encoding, 916 // it seems that it does not need a FontName. 917 //l.addLast(new DictNumberItem((standardStrings.length+(stringOffsets.length-1)+2))); 918 //l.addLast(new UInt8Item((char)12)); 919 //l.addLast(new UInt8Item((char)38)); // FontName 920 921 l.addLast(new DictNumberItem(fonts[j].privateLength)); 922 OffsetItem privateRef = new DictOffsetItem(); 923 l.addLast(privateRef); 924 l.addLast(new UInt8Item((char)18)); // Private 925 926 l.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase)); 927 928 // copy the private index & local subroutines 929 930 l.addLast(new MarkerItem(privateRef)); 931 // copy the private dict and the local subroutines. 932 // the length of the private dict seems to NOT include 933 // the local subroutines. 934 l.addLast(new RangeItem(buf,fonts[j].privateOffset,fonts[j].privateLength)); 935 if (fonts[j].privateSubrs >= 0) { 936 //System.err.println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength); 937 l.addLast(getEntireIndexRange(fonts[j].privateSubrs)); 938 } 939 } 940 941 // copy the charstring index 942 943 l.addLast(new MarkerItem(charstringsRef)); 944 l.addLast(getEntireIndexRange(fonts[j].charstringsOffset)); 945 946 // now create the new CFF font 947 948 int[] currentOffset = new int[1]; 949 currentOffset[0] = 0; 950 951 Iterator<Item> listIter = l.iterator(); 952 while ( listIter.hasNext() ) { 953 Item item = listIter.next(); 954 item.increment(currentOffset); 955 } 956 957 listIter = l.iterator(); 958 while ( listIter.hasNext() ) { 959 Item item = listIter.next(); 960 item.xref(); 961 } 962 963 int size = currentOffset[0]; 964 byte[] b = new byte[size]; 965 966 listIter = l.iterator(); 967 while ( listIter.hasNext() ) { 968 Item item = listIter.next(); 969 item.emit(b); 970 } 971 972 return b; 973 } 974 975 976 public boolean isCID(String fontName) { 977 int j; 978 for (j=0; j<fonts.length; j++) 979 if (fontName.equals(fonts[j].name)) return fonts[j].isCID; 980 return false; 981 } 982 983 public boolean exists(String fontName) { 984 int j; 985 for (j=0; j<fonts.length; j++) 986 if (fontName.equals(fonts[j].name)) return true; 987 return false; 988 } 989 990 991 public String[] getNames() { 992 String[] names = new String[ fonts.length ]; 993 for (int i=0; i<fonts.length; i++) 994 names[i] = fonts[i].name; 995 return names; 996 } 997 /** 998 * A random Access File or an array 999 */ 1000 protected RandomAccessFileOrArray buf; 1001 private int offSize; 1002 1003 protected int nameIndexOffset; 1004 protected int topdictIndexOffset; 1005 protected int stringIndexOffset; 1006 protected int gsubrIndexOffset; 1007 protected int[] nameOffsets; 1008 protected int[] topdictOffsets; 1009 protected int[] stringOffsets; 1010 protected int[] gsubrOffsets; 1011 1012 /** 1013 * TODO Changed from private to protected by Ygal&Oren 1014 */ 1015 protected final class Font { 1016 public String name; 1017 public String fullName; 1018 public boolean isCID = false; 1019 public int privateOffset = -1; // only if not CID 1020 public int privateLength = -1; // only if not CID 1021 public int privateSubrs = -1; 1022 public int charstringsOffset = -1; 1023 public int encodingOffset = -1; 1024 public int charsetOffset = -1; 1025 public int fdarrayOffset = -1; // only if CID 1026 public int fdselectOffset = -1; // only if CID 1027 public int[] fdprivateOffsets; 1028 public int[] fdprivateLengths; 1029 public int[] fdprivateSubrs; 1030 1031 // Added by Oren & Ygal 1032 public int nglyphs; 1033 public int nstrings; 1034 public int CharsetLength; 1035 public int[] charstringsOffsets; 1036 public int[] charset; 1037 public int[] FDSelect; 1038 public int FDSelectLength; 1039 public int FDSelectFormat; 1040 public int CharstringType = 2; 1041 public int FDArrayCount; 1042 public int FDArrayOffsize; 1043 public int[] FDArrayOffsets; 1044 public int[] PrivateSubrsOffset; 1045 public int[][] PrivateSubrsOffsetsArray; 1046 public int[] SubrsOffsets; 1047 } 1048 // Changed from private to protected by Ygal&Oren 1049 protected Font[] fonts; 1050 1051 public CFFFont(RandomAccessFileOrArray inputbuffer) { 1052 1053 //System.err.println("CFF: nStdString = "+standardStrings.length); 1054 buf = inputbuffer; 1055 seek(0); 1056 1057 int major, minor; 1058 major = getCard8(); 1059 minor = getCard8(); 1060 1061 //System.err.println("CFF Major-Minor = "+major+"-"+minor); 1062 1063 int hdrSize = getCard8(); 1064 1065 offSize = getCard8(); 1066 1067 //System.err.println("offSize = "+offSize); 1068 1069 //int count, indexOffSize, indexOffset, nextOffset; 1070 1071 nameIndexOffset = hdrSize; 1072 nameOffsets = getIndex(nameIndexOffset); 1073 topdictIndexOffset = nameOffsets[nameOffsets.length-1]; 1074 topdictOffsets = getIndex(topdictIndexOffset); 1075 stringIndexOffset = topdictOffsets[topdictOffsets.length-1]; 1076 stringOffsets = getIndex(stringIndexOffset); 1077 gsubrIndexOffset = stringOffsets[stringOffsets.length-1]; 1078 gsubrOffsets = getIndex(gsubrIndexOffset); 1079 1080 fonts = new Font[nameOffsets.length-1]; 1081 1082 // now get the name index 1083 1084 /* 1085 names = new String[nfonts]; 1086 privateOffset = new int[nfonts]; 1087 charsetOffset = new int[nfonts]; 1088 encodingOffset = new int[nfonts]; 1089 charstringsOffset = new int[nfonts]; 1090 fdarrayOffset = new int[nfonts]; 1091 fdselectOffset = new int[nfonts]; 1092 */ 1093 1094 for (int j=0; j<nameOffsets.length-1; j++) { 1095 fonts[j] = new Font(); 1096 seek(nameOffsets[j]); 1097 fonts[j].name = ""; 1098 for (int k=nameOffsets[j]; k<nameOffsets[j+1]; k++) { 1099 fonts[j].name += getCard8(); 1100 } 1101 //System.err.println("name["+j+"]=<"+fonts[j].name+">"); 1102 } 1103 1104 // string index 1105 1106 //strings = new String[stringOffsets.length-1]; 1107 /* 1108 System.err.println("std strings = "+standardStrings.length); 1109 System.err.println("fnt strings = "+(stringOffsets.length-1)); 1110 for (char j=0; j<standardStrings.length+(stringOffsets.length-1); j++) { 1111 //seek(stringOffsets[j]); 1112 //strings[j] = ""; 1113 //for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) { 1114 // strings[j] += (char)getCard8(); 1115 //} 1116 System.err.println("j="+(int)j+" <? "+(standardStrings.length+(stringOffsets.length-1))); 1117 System.err.println("strings["+(int)j+"]=<"+getString(j)+">"); 1118 } 1119 */ 1120 1121 // top dict 1122 1123 for (int j=0; j<topdictOffsets.length-1; j++) { 1124 seek(topdictOffsets[j]); 1125 while (getPosition() < topdictOffsets[j+1]) { 1126 getDictItem(); 1127 if (key=="FullName") { 1128 //System.err.println("getting fullname sid = "+((Integer)args[0]).intValue()); 1129 fonts[j].fullName = getString((char)((Integer)args[0]).intValue()); 1130 //System.err.println("got it"); 1131 } else if (key=="ROS") 1132 fonts[j].isCID = true; 1133 else if (key=="Private") { 1134 fonts[j].privateLength = ((Integer)args[0]).intValue(); 1135 fonts[j].privateOffset = ((Integer)args[1]).intValue(); 1136 } 1137 else if (key=="charset"){ 1138 fonts[j].charsetOffset = ((Integer)args[0]).intValue(); 1139 1140 } 1141// else if (key=="Encoding"){ 1142// int encOffset = ((Integer)args[0]).intValue(); 1143// if (encOffset > 0) { 1144// fonts[j].encodingOffset = encOffset; 1145// ReadEncoding(fonts[j].encodingOffset); 1146// } 1147// } 1148 else if (key=="CharStrings") { 1149 fonts[j].charstringsOffset = ((Integer)args[0]).intValue(); 1150 //System.err.println("charstrings "+fonts[j].charstringsOffset); 1151 // Added by Oren & Ygal 1152 int p = getPosition(); 1153 fonts[j].charstringsOffsets = getIndex(fonts[j].charstringsOffset); 1154 seek(p); 1155 } else if (key=="FDArray") 1156 fonts[j].fdarrayOffset = ((Integer)args[0]).intValue(); 1157 else if (key=="FDSelect") 1158 fonts[j].fdselectOffset = ((Integer)args[0]).intValue(); 1159 else if (key=="CharstringType") 1160 fonts[j].CharstringType = ((Integer)args[0]).intValue(); 1161 } 1162 1163 // private dict 1164 if (fonts[j].privateOffset >= 0) { 1165 //System.err.println("PRIVATE::"); 1166 seek(fonts[j].privateOffset); 1167 while (getPosition() < fonts[j].privateOffset+fonts[j].privateLength) { 1168 getDictItem(); 1169 if (key=="Subrs") 1170 //Add the private offset to the lsubrs since the offset is 1171 // relative to the beginning of the PrivateDict 1172 fonts[j].privateSubrs = ((Integer)args[0]).intValue()+fonts[j].privateOffset; 1173 } 1174 } 1175 1176 // fdarray index 1177 if (fonts[j].fdarrayOffset >= 0) { 1178 int[] fdarrayOffsets = getIndex(fonts[j].fdarrayOffset); 1179 1180 fonts[j].fdprivateOffsets = new int[fdarrayOffsets.length-1]; 1181 fonts[j].fdprivateLengths = new int[fdarrayOffsets.length-1]; 1182 1183 //System.err.println("FD Font::"); 1184 1185 for (int k=0; k<fdarrayOffsets.length-1; k++) { 1186 seek(fdarrayOffsets[k]); 1187 while (getPosition() < fdarrayOffsets[k+1]) { 1188 getDictItem(); 1189 if (key=="Private") { 1190 fonts[j].fdprivateLengths[k] = ((Integer)args[0]).intValue(); 1191 fonts[j].fdprivateOffsets[k] = ((Integer)args[1]).intValue(); 1192 } 1193 } 1194 } 1195 } 1196 } 1197 //System.err.println("CFF: done"); 1198 } 1199 1200 // ADDED BY Oren & Ygal 1201 1202 void ReadEncoding(int nextIndexOffset){ 1203 int format; 1204 seek(nextIndexOffset); 1205 format = getCard8(); 1206 } 1207}