1 17 18 19 20 package org.apache.fop.render.afp.fonts; 21 22 import java.io.File ; 23 import java.io.FileNotFoundException ; 24 import java.io.FilenameFilter ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.net.MalformedURLException ; 28 import java.net.URL ; 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 32 import org.apache.commons.logging.Log; 33 import org.apache.commons.logging.LogFactory; 34 import org.apache.fop.render.afp.exceptions.FontRuntimeException; 35 import org.apache.fop.render.afp.modca.AFPConstants; 36 import org.apache.fop.render.afp.tools.StructuredFieldReader; 37 38 55 public final class AFPFontReader { 56 57 60 protected static final Log log = LogFactory.getLog("org.apache.fop.render.afp.fonts"); 61 62 65 private static final CharacterSetOrientation[] EMPTY_CSO_ARRAY = new CharacterSetOrientation[0]; 66 67 68 private static final byte[] CODEPAGE_SF = new byte[] { (byte) 0xD3, 69 (byte) 0xA8, (byte) 0x87 }; 70 71 72 private static final byte[] CHARACTER_TABLE_SF = new byte[] { (byte) 0xD3, 73 (byte) 0x8C, (byte) 0x87 }; 74 75 76 private static final byte[] FONT_CONTROL_SF = new byte[] { (byte) 0xD3, 77 (byte) 0xA7, (byte) 0x89 }; 78 79 80 private static final byte[] FONT_ORIENTATION_SF = new byte[] { (byte) 0xD3, 81 (byte) 0xAE, (byte) 0x89 }; 82 83 84 private static final byte[] FONT_POSITION_SF = new byte[] { (byte) 0xD3, 85 (byte) 0xAC, (byte) 0x89 }; 86 87 88 private static final byte[] FONT_INDEX_SF = new byte[] { (byte) 0xD3, 89 (byte) 0x8C, (byte) 0x89 }; 90 91 94 private static final int FOP_100_DPI_FACTOR = 1; 95 96 99 private static final int FOP_240_DPI_FACTOR = 300000; 100 101 104 private static final int FOP_300_DPI_FACTOR = 240000; 105 106 109 private static final String ASCII_ENCODING = "UTF8"; 110 111 114 private static HashMap _codePages = new HashMap (); 115 116 123 public static void loadCharacterSetMetric(CharacterSet characterSet) { 124 125 InputStream inputStream = null; 126 127 try { 128 129 134 String cp = new String (characterSet.getCodePage()); 135 String path = characterSet.getPath(); 136 137 HashMap codepage = (HashMap ) _codePages.get(cp); 138 139 if (codepage == null) { 140 codepage = loadCodePage(cp, characterSet.getEncoding(), path); 141 _codePages.put(cp, codepage); 142 } 143 144 149 final String characterset = characterSet.getName(); 150 151 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 152 if (classLoader == null) { 153 classLoader = AFPFontReader.class.getClassLoader(); 154 } 155 156 URL url = classLoader.getResource(path); 157 if (url == null) { 158 try { 159 File file = new File (path); 160 url = file.toURL(); 161 if (url == null) { 162 String msg = "CharacterSet file not found for " 163 + characterset + " in classpath: " + path; 164 log.error(msg); 165 throw new FileNotFoundException (msg); 166 } 167 } catch (MalformedURLException ex) { 168 String msg = "CharacterSet file not found for " 169 + characterset + " in classpath: " + path; 170 log.error(msg); 171 throw new FileNotFoundException (msg); 172 } 173 174 } 175 176 File directory = new File (url.getPath()); 177 178 final String filterpattern = characterset.trim(); 179 FilenameFilter filter = new FilenameFilter () { 180 public boolean accept(File dir, String name) { 181 return name.startsWith(filterpattern); 182 } 183 }; 184 185 File [] csfont = directory.listFiles(filter); 186 if (csfont.length < 1) { 187 String msg = "CharacterSet file search for " + characterset 188 + " located " + csfont.length + " files"; 189 log.error(msg); 190 throw new FileNotFoundException (msg); 191 } else if (csfont.length > 1) { 192 String msg = "CharacterSet file search for " + characterset 193 + " located " + csfont.length + " files"; 194 log.warn(msg); 195 } 196 197 inputStream = inputStream = csfont[0].toURL().openStream(); 198 if (inputStream == null) { 199 String msg = "Failed to open character set resource " 200 + characterset; 201 log.error(msg); 202 throw new FileNotFoundException (msg); 203 } 204 205 StructuredFieldReader sfr = new StructuredFieldReader(inputStream); 206 207 FontControl fnc = processFontControl(sfr); 209 210 CharacterSetOrientation[] csoArray = processFontOrientation(sfr); 212 213 processFontPosition(sfr, csoArray, fnc.getDpi()); 215 216 for (int i = 0; i < csoArray.length; i++) { 218 processFontIndex(sfr, csoArray[i], codepage, fnc.getDpi()); 219 characterSet.addCharacterSetOrientation(csoArray[i]); 220 } 221 222 } catch (Exception ex) { 223 throw new FontRuntimeException( 224 "Failed to load the character set metrics for code page " 225 + characterSet.getCodePage(), ex); 226 } finally { 227 try { 228 inputStream.close(); 229 } catch (Exception ex) { 230 } 232 } 233 234 } 235 236 245 private static HashMap loadCodePage(String codePage, String encoding, 246 String path) throws IOException , FileNotFoundException { 247 248 HashMap codepages = new HashMap (); 250 251 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 252 if (classLoader == null) { 253 classLoader = AFPFontReader.class.getClassLoader(); 254 } 255 256 URL url = classLoader.getResource(path); 257 258 if (url == null) { 259 try { 260 File file = new File (path); 261 url = file.toURL(); 262 if (url == null) { 263 String msg = "CodePage file not found for " + codePage 264 + " in classpath: " + path; 265 log.error(msg); 266 throw new FileNotFoundException (msg); 267 } 268 } catch (MalformedURLException ex) { 269 String msg = "CodePage file not found for " + codePage 270 + " in classpath: " + path; 271 log.error(msg); 272 throw new FileNotFoundException (msg); 273 } 274 275 } 276 277 File directory = new File (url.getPath()); 278 279 final String filterpattern = codePage.trim(); 280 FilenameFilter filter = new FilenameFilter () { 281 public boolean accept(File dir, String name) { 282 return name.startsWith(filterpattern); 283 } 284 }; 285 286 File [] codepage = directory.listFiles(filter); 287 288 if (codepage.length < 1) { 289 String msg = "CodePage file search for " + codePage + " located " 290 + codepage.length + " files"; 291 log.error(msg); 292 throw new FileNotFoundException (msg); 293 } else if (codepage.length > 1) { 294 String msg = "CodePage file search for " + codePage + " located " 295 + codepage.length + " files"; 296 log.warn(msg); 297 } 298 299 InputStream is = codepage[0].toURL().openStream(); 300 301 if (is == null) { 302 String msg = "AFPFontReader:: loadCodePage(String):: code page file not found for " 303 + codePage; 304 log.error(msg); 305 throw new FileNotFoundException (msg); 306 } 307 308 StructuredFieldReader sfr = new StructuredFieldReader(is); 309 byte[] data = sfr.getNext(CHARACTER_TABLE_SF); 310 311 int position = 0; 312 byte[] gcgiBytes = new byte[8]; 313 byte[] charBytes = new byte[1]; 314 315 for (int index = 3; index < data.length; index++) { 317 if (position < 8) { 318 gcgiBytes[position] = data[index]; 320 position++; 321 } else if (position == 9) { 322 position = 0; 323 charBytes[0] = data[index]; 325 String gcgiString = new String (gcgiBytes, 326 AFPConstants.EBCIDIC_ENCODING); 327 String charString = new String (charBytes, encoding); 328 int value = charString.charAt(0); 329 codepages.put(gcgiString, charString); 330 } else { 331 position++; 332 } 333 } 334 335 try { 336 is.close(); 337 } catch (Exception ex) { 338 } 340 341 return codepages; 342 343 } 344 345 351 private static FontControl processFontControl(StructuredFieldReader sfr) 352 throws IOException { 353 354 byte[] fncData = sfr.getNext(FONT_CONTROL_SF); 355 356 int position = 0; 357 358 FontControl fontControl = new AFPFontReader().new FontControl(); 359 360 if (fncData[7] == (byte) 0x02) { 361 fontControl.setRelative(true); 362 } 363 364 int dpi = (((fncData[9] & 0xFF) << 8) + (fncData[10] & 0xFF)) / 10; 365 366 fontControl.setDpi(dpi); 367 368 return fontControl; 369 370 } 371 372 379 private static CharacterSetOrientation[] processFontOrientation( 380 StructuredFieldReader sfr) throws IOException { 381 382 byte[] data = sfr.getNext(FONT_ORIENTATION_SF); 383 384 int position = 0; 385 byte[] fnoData = new byte[26]; 386 387 ArrayList orientations = new ArrayList (); 388 389 for (int index = 3; index < data.length; index++) { 391 fnoData[position] = data[index]; 393 position++; 394 395 if (position == 26) { 396 397 position = 0; 398 399 int orientation = 0; 400 401 switch (fnoData[2]) { 402 case 0x00: 403 orientation = 0; 404 break; 405 case 0x2D: 406 orientation = 90; 407 break; 408 case 0x5A: 409 orientation = 180; 410 break; 411 case (byte) 0x87: 412 orientation = 270; 413 break; 414 default: 415 System.out.println("ERROR: Oriantation"); 416 } 417 418 CharacterSetOrientation cso = new CharacterSetOrientation( 419 orientation); 420 orientations.add(cso); 421 422 } 423 } 424 425 return (CharacterSetOrientation[]) orientations 426 .toArray(EMPTY_CSO_ARRAY); 427 } 428 429 438 private static void processFontPosition(StructuredFieldReader sfr, 439 CharacterSetOrientation[] csoArray, int dpi) throws IOException { 440 441 byte[] data = sfr.getNext(FONT_POSITION_SF); 442 443 int position = 0; 444 byte[] fpData = new byte[26]; 445 446 int csoIndex = 0; 447 int fopFactor = 0; 448 449 switch (dpi) { 450 case 100: 451 fopFactor = FOP_100_DPI_FACTOR; 452 break; 453 case 240: 454 fopFactor = FOP_240_DPI_FACTOR; 455 break; 456 case 300: 457 fopFactor = FOP_300_DPI_FACTOR; 458 break; 459 default: 460 String msg = "Unsupported font resolution of " + dpi + " dpi."; 461 log.error(msg); 462 throw new IOException (msg); 463 } 464 465 for (int index = 3; index < data.length; index++) { 467 if (position < 22) { 468 fpData[position] = data[index]; 470 } else if (position == 22) { 471 472 position = 0; 473 474 CharacterSetOrientation cso = csoArray[csoIndex]; 475 476 int xHeight = ((fpData[2] & 0xFF) << 8) + (fpData[3] & 0xFF); 477 int capHeight = ((fpData[4] & 0xFF) << 8) + (fpData[5] & 0xFF); 478 int ascHeight = ((fpData[6] & 0xFF) << 8) + (fpData[7] & 0xFF); 479 int dscHeight = ((fpData[8] & 0xFF) << 8) + (fpData[9] & 0xFF); 480 481 dscHeight = dscHeight * -1; 482 483 cso.setXHeight(xHeight * fopFactor); 484 cso.setCapHeight(capHeight * fopFactor); 485 cso.setAscender(ascHeight * fopFactor); 486 cso.setDescender(dscHeight * fopFactor); 487 488 csoIndex++; 489 490 fpData[position] = data[index]; 491 492 } 493 494 position++; 495 } 496 497 } 498 499 509 private static void processFontIndex(StructuredFieldReader sfr, 510 CharacterSetOrientation cso, HashMap codepage, int dpi) 511 throws IOException { 512 513 byte[] data = sfr.getNext(FONT_INDEX_SF); 514 515 int fopFactor = 0; 516 517 switch (dpi) { 518 case 100: 519 fopFactor = FOP_100_DPI_FACTOR; 520 break; 521 case 240: 522 fopFactor = FOP_240_DPI_FACTOR; 523 break; 524 case 300: 525 fopFactor = FOP_300_DPI_FACTOR; 526 break; 527 default: 528 String msg = "Unsupported font resolution of " + dpi + " dpi."; 529 log.error(msg); 530 throw new IOException (msg); 531 } 532 533 int position = 0; 534 535 byte[] gcgid = new byte[8]; 536 byte[] fiData = new byte[20]; 537 538 int lowest = 255; 539 int highest = 0; 540 541 for (int index = 3; index < data.length; index++) { 543 if (position < 8) { 544 gcgid[position] = (byte) data[index]; 545 position++; 546 } else if (position < 27) { 547 fiData[position - 8] = (byte) data[index]; 548 position++; 549 } else if (position == 27) { 550 551 fiData[position - 8] = (byte) data[index]; 552 553 position = 0; 554 555 String gcgiString = new String (gcgid, AFPConstants.EBCIDIC_ENCODING); 556 557 String idx = (String ) codepage.get(gcgiString); 558 559 if (idx != null) { 560 561 int cidx = idx.charAt(0); 562 int width = ((fiData[0] & 0xFF) << 8) + (fiData[1] & 0xFF); 563 564 if (cidx < lowest) { 565 lowest = cidx; 566 } 567 568 if (cidx > highest) { 569 highest = cidx; 570 } 571 572 int a = (width * fopFactor); 573 574 cso.setWidth(cidx, a); 575 576 } 577 578 } 579 } 580 581 cso.setFirstChar(lowest); 582 cso.setLastChar(highest); 583 584 } 585 586 private class FontControl { 587 588 private int _dpi; 589 590 private boolean isRelative = false; 591 592 public int getDpi() { 593 return _dpi; 594 } 595 596 public void setDpi(int i) { 597 _dpi = i; 598 } 599 600 public boolean isRelative() { 601 return isRelative; 602 } 603 604 public void setRelative(boolean b) { 605 isRelative = b; 606 } 607 } 608 609 } | Popular Tags |