1 50 51 package com.lowagie.text.pdf; 52 53 import java.io.IOException ; 54 import java.util.ArrayList ; 55 import java.util.Arrays ; 56 import java.util.HashMap ; 57 58 import com.lowagie.text.DocumentException; 59 import com.lowagie.text.ExceptionConverter; 60 61 66 class TrueTypeFontSubSet { 67 static final String tableNamesSimple[] = {"cvt ", "fpgm", "glyf", "head", 68 "hhea", "hmtx", "loca", "maxp", "prep"}; 69 static final String tableNamesCmap[] = {"cmap", "cvt ", "fpgm", "glyf", "head", 70 "hhea", "hmtx", "loca", "maxp", "prep"}; 71 static final String tableNamesExtra[] = {"OS/2", "cmap", "cvt ", "fpgm", "glyf", "head", 72 "hhea", "hmtx", "loca", "maxp", "name, prep"}; 73 static final int entrySelectors[] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4}; 74 static final int TABLE_CHECKSUM = 0; 75 static final int TABLE_OFFSET = 1; 76 static final int TABLE_LENGTH = 2; 77 static final int HEAD_LOCA_FORMAT_OFFSET = 51; 78 79 static final int ARG_1_AND_2_ARE_WORDS = 1; 80 static final int WE_HAVE_A_SCALE = 8; 81 static final int MORE_COMPONENTS = 32; 82 static final int WE_HAVE_AN_X_AND_Y_SCALE = 64; 83 static final int WE_HAVE_A_TWO_BY_TWO = 128; 84 85 86 91 protected HashMap tableDirectory; 92 94 protected RandomAccessFileOrArray rf; 95 97 protected String fileName; 98 protected boolean includeCmap; 99 protected boolean includeExtras; 100 protected boolean locaShortTable; 101 protected int locaTable[]; 102 protected HashMap glyphsUsed; 103 protected ArrayList glyphsInList; 104 protected int tableGlyphOffset; 105 protected int newLocaTable[]; 106 protected byte newLocaTableOut[]; 107 protected byte newGlyfTable[]; 108 protected int glyfTableRealSize; 109 protected int locaTableRealSize; 110 protected byte outFont[]; 111 protected int fontPtr; 112 protected int directoryOffset; 113 114 120 TrueTypeFontSubSet(String fileName, RandomAccessFileOrArray rf, HashMap glyphsUsed, int directoryOffset, boolean includeCmap, boolean includeExtras) { 121 this.fileName = fileName; 122 this.rf = rf; 123 this.glyphsUsed = glyphsUsed; 124 this.includeCmap = includeCmap; 125 this.includeExtras = includeExtras; 126 this.directoryOffset = directoryOffset; 127 glyphsInList = new ArrayList (glyphsUsed.keySet()); 128 } 129 130 135 byte[] process() throws IOException , DocumentException { 136 try { 137 rf.reOpen(); 138 createTableDirectory(); 139 readLoca(); 140 flatGlyphs(); 141 createNewGlyphTables(); 142 locaTobytes(); 143 assembleFont(); 144 return outFont; 145 } 146 finally { 147 try { 148 rf.close(); 149 } 150 catch (Exception e) { 151 } 153 } 154 } 155 156 protected void assembleFont() throws IOException { 157 int tableLocation[]; 158 int fullFontSize = 0; 159 String tableNames[]; 160 if (includeExtras) 161 tableNames = tableNamesExtra; 162 else { 163 if (includeCmap) 164 tableNames = tableNamesCmap; 165 else 166 tableNames = tableNamesSimple; 167 } 168 int tablesUsed = 2; 169 int len = 0; 170 for (int k = 0; k < tableNames.length; ++k) { 171 String name = tableNames[k]; 172 if (name.equals("glyf") || name.equals("loca")) 173 continue; 174 tableLocation = (int[])tableDirectory.get(name); 175 if (tableLocation == null) 176 continue; 177 ++tablesUsed; 178 fullFontSize += (tableLocation[TABLE_LENGTH] + 3) & (~3); 179 } 180 fullFontSize += newLocaTableOut.length; 181 fullFontSize += newGlyfTable.length; 182 int ref = 16 * tablesUsed + 12; 183 fullFontSize += ref; 184 outFont = new byte[fullFontSize]; 185 fontPtr = 0; 186 writeFontInt(0x00010000); 187 writeFontShort(tablesUsed); 188 int selector = entrySelectors[tablesUsed]; 189 writeFontShort((1 << selector) * 16); 190 writeFontShort(selector); 191 writeFontShort((tablesUsed - (1 << selector)) * 16); 192 for (int k = 0; k < tableNames.length; ++k) { 193 String name = tableNames[k]; 194 tableLocation = (int[])tableDirectory.get(name); 195 if (tableLocation == null) 196 continue; 197 writeFontString(name); 198 if (name.equals("glyf")) { 199 writeFontInt(calculateChecksum(newGlyfTable)); 200 len = glyfTableRealSize; 201 } 202 else if (name.equals("loca")) { 203 writeFontInt(calculateChecksum(newLocaTableOut)); 204 len = locaTableRealSize; 205 } 206 else { 207 writeFontInt(tableLocation[TABLE_CHECKSUM]); 208 len = tableLocation[TABLE_LENGTH]; 209 } 210 writeFontInt(ref); 211 writeFontInt(len); 212 ref += (len + 3) & (~3); 213 } 214 for (int k = 0; k < tableNames.length; ++k) { 215 String name = tableNames[k]; 216 tableLocation = (int[])tableDirectory.get(name); 217 if (tableLocation == null) 218 continue; 219 if (name.equals("glyf")) { 220 System.arraycopy(newGlyfTable, 0, outFont, fontPtr, newGlyfTable.length); 221 fontPtr += newGlyfTable.length; 222 newGlyfTable = null; 223 } 224 else if (name.equals("loca")) { 225 System.arraycopy(newLocaTableOut, 0, outFont, fontPtr, newLocaTableOut.length); 226 fontPtr += newLocaTableOut.length; 227 newLocaTableOut = null; 228 } 229 else { 230 rf.seek(tableLocation[TABLE_OFFSET]); 231 rf.readFully(outFont, fontPtr, tableLocation[TABLE_LENGTH]); 232 fontPtr += (tableLocation[TABLE_LENGTH] + 3) & (~3); 233 } 234 } 235 } 236 237 protected void createTableDirectory() throws IOException , DocumentException { 238 tableDirectory = new HashMap (); 239 rf.seek(directoryOffset); 240 int id = rf.readInt(); 241 if (id != 0x00010000) 242 throw new DocumentException(fileName + " is not a true type file."); 243 int num_tables = rf.readUnsignedShort(); 244 rf.skipBytes(6); 245 for (int k = 0; k < num_tables; ++k) { 246 String tag = readStandardString(4); 247 int tableLocation[] = new int[3]; 248 tableLocation[TABLE_CHECKSUM] = rf.readInt(); 249 tableLocation[TABLE_OFFSET] = rf.readInt(); 250 tableLocation[TABLE_LENGTH] = rf.readInt(); 251 tableDirectory.put(tag, tableLocation); 252 } 253 } 254 255 protected void readLoca() throws IOException , DocumentException { 256 int tableLocation[]; 257 tableLocation = (int[])tableDirectory.get("head"); 258 if (tableLocation == null) 259 throw new DocumentException("Table 'head' does not exist in " + fileName); 260 rf.seek(tableLocation[TABLE_OFFSET] + HEAD_LOCA_FORMAT_OFFSET); 261 locaShortTable = (rf.readUnsignedShort() == 0); 262 tableLocation = (int[])tableDirectory.get("loca"); 263 if (tableLocation == null) 264 throw new DocumentException("Table 'loca' does not exist in " + fileName); 265 rf.seek(tableLocation[TABLE_OFFSET]); 266 if (locaShortTable) { 267 int entries = tableLocation[TABLE_LENGTH] / 2; 268 locaTable = new int[entries]; 269 for (int k = 0; k < entries; ++k) 270 locaTable[k] = rf.readUnsignedShort() * 2; 271 } 272 else { 273 int entries = tableLocation[TABLE_LENGTH] / 4; 274 locaTable = new int[entries]; 275 for (int k = 0; k < entries; ++k) 276 locaTable[k] = rf.readInt(); 277 } 278 } 279 280 protected void createNewGlyphTables() throws IOException { 281 newLocaTable = new int[locaTable.length]; 282 int activeGlyphs[] = new int[glyphsInList.size()]; 283 for (int k = 0; k < activeGlyphs.length; ++k) 284 activeGlyphs[k] = ((Integer )glyphsInList.get(k)).intValue(); 285 Arrays.sort(activeGlyphs); 286 int glyfSize = 0; 287 for (int k = 0; k < activeGlyphs.length; ++k) { 288 int glyph = activeGlyphs[k]; 289 glyfSize += locaTable[glyph + 1] - locaTable[glyph]; 290 } 291 glyfTableRealSize = glyfSize; 292 glyfSize = (glyfSize + 3) & (~3); 293 newGlyfTable = new byte[glyfSize]; 294 int glyfPtr = 0; 295 int listGlyf = 0; 296 for (int k = 0; k < newLocaTable.length; ++k) { 297 newLocaTable[k] = glyfPtr; 298 if (listGlyf < activeGlyphs.length && activeGlyphs[listGlyf] == k) { 299 ++listGlyf; 300 newLocaTable[k] = glyfPtr; 301 int start = locaTable[k]; 302 int len = locaTable[k + 1] - start; 303 if (len > 0) { 304 rf.seek(tableGlyphOffset + start); 305 rf.readFully(newGlyfTable, glyfPtr, len); 306 glyfPtr += len; 307 } 308 } 309 } 310 } 311 312 protected void locaTobytes() { 313 if (locaShortTable) 314 locaTableRealSize = newLocaTable.length * 2; 315 else 316 locaTableRealSize = newLocaTable.length * 4; 317 newLocaTableOut = new byte[(locaTableRealSize + 3) & (~3)]; 318 outFont = newLocaTableOut; 319 fontPtr = 0; 320 for (int k = 0; k < newLocaTable.length; ++k) { 321 if (locaShortTable) 322 writeFontShort(newLocaTable[k] / 2); 323 else 324 writeFontInt(newLocaTable[k]); 325 } 326 327 } 328 329 protected void flatGlyphs() throws IOException , DocumentException { 330 int tableLocation[]; 331 tableLocation = (int[])tableDirectory.get("glyf"); 332 if (tableLocation == null) 333 throw new DocumentException("Table 'glyf' does not exist in " + fileName); 334 Integer glyph0 = new Integer (0); 335 if (!glyphsUsed.containsKey(glyph0)) { 336 glyphsUsed.put(glyph0, null); 337 glyphsInList.add(glyph0); 338 } 339 tableGlyphOffset = tableLocation[TABLE_OFFSET]; 340 for (int k = 0; k < glyphsInList.size(); ++k) { 341 int glyph = ((Integer )glyphsInList.get(k)).intValue(); 342 checkGlyphComposite(glyph); 343 } 344 } 345 346 protected void checkGlyphComposite(int glyph) throws IOException { 347 int start = locaTable[glyph]; 348 if (start == locaTable[glyph + 1]) return; 350 rf.seek(tableGlyphOffset + start); 351 int numContours = rf.readShort(); 352 if (numContours >= 0) 353 return; 354 rf.skipBytes(8); 355 for(;;) { 356 int flags = rf.readUnsignedShort(); 357 Integer cGlyph = new Integer (rf.readUnsignedShort()); 358 if (!glyphsUsed.containsKey(cGlyph)) { 359 glyphsUsed.put(cGlyph, null); 360 glyphsInList.add(cGlyph); 361 } 362 if ((flags & MORE_COMPONENTS) == 0) 363 return; 364 int skip; 365 if ((flags & ARG_1_AND_2_ARE_WORDS) != 0) 366 skip = 4; 367 else 368 skip = 2; 369 if ((flags & WE_HAVE_A_SCALE) != 0) 370 skip += 2; 371 else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) 372 skip += 4; 373 if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0) 374 skip += 8; 375 rf.skipBytes(skip); 376 } 377 } 378 379 385 protected String readStandardString(int length) throws IOException { 386 byte buf[] = new byte[length]; 387 rf.readFully(buf); 388 try { 389 return new String (buf, BaseFont.WINANSI); 390 } 391 catch (Exception e) { 392 throw new ExceptionConverter(e); 393 } 394 } 395 396 protected void writeFontShort(int n) { 397 outFont[fontPtr++] = (byte)(n >> 8); 398 outFont[fontPtr++] = (byte)(n); 399 } 400 401 protected void writeFontInt(int n) { 402 outFont[fontPtr++] = (byte)(n >> 24); 403 outFont[fontPtr++] = (byte)(n >> 16); 404 outFont[fontPtr++] = (byte)(n >> 8); 405 outFont[fontPtr++] = (byte)(n); 406 } 407 408 protected void writeFontString(String s) { 409 byte b[] = PdfEncodings.convertToBytes(s, BaseFont.WINANSI); 410 System.arraycopy(b, 0, outFont, fontPtr, b.length); 411 fontPtr += b.length; 412 } 413 414 protected int calculateChecksum(byte b[]) { 415 int len = b.length / 4; 416 int v0 = 0; 417 int v1 = 0; 418 int v2 = 0; 419 int v3 = 0; 420 int ptr = 0; 421 for (int k = 0; k < len; ++k) { 422 v3 += (int)b[ptr++] & 0xff; 423 v2 += (int)b[ptr++] & 0xff; 424 v1 += (int)b[ptr++] & 0xff; 425 v0 += (int)b[ptr++] & 0xff; 426 } 427 return v0 + (v1 << 8) + (v2 << 16) + (v3 << 24); 428 } 429 } 430 | Popular Tags |