1 26 27 package it.stefanochizzolini.clown.documents.contents.fonts; 28 29 import it.stefanochizzolini.clown.bytes.Buffer; 30 import it.stefanochizzolini.clown.bytes.IInputStream; 31 import it.stefanochizzolini.clown.documents.Document; 32 import it.stefanochizzolini.clown.objects.PdfArray; 33 import it.stefanochizzolini.clown.objects.PdfDictionary; 34 import it.stefanochizzolini.clown.objects.PdfDirectObject; 35 import it.stefanochizzolini.clown.objects.PdfIndirectObject; 36 import it.stefanochizzolini.clown.objects.PdfInteger; 37 import it.stefanochizzolini.clown.objects.PdfName; 38 import it.stefanochizzolini.clown.objects.PdfReal; 39 import it.stefanochizzolini.clown.objects.PdfRectangle; 40 import it.stefanochizzolini.clown.objects.PdfStream; 41 import it.stefanochizzolini.clown.util.NotImplementedException; 42 43 import java.io.BufferedReader ; 44 import java.io.InputStreamReader ; 45 import java.util.EnumSet ; 46 import java.util.Hashtable ; 47 import java.util.regex.Matcher ; 48 import java.util.regex.Pattern ; 49 50 56 public class Type1Font 58 extends Font 59 { 60 65 private static final class FontMetrics 66 { 67 public boolean isCustomEncoding; 68 public String fontName; 69 public String weight; 70 public float italicAngle; 71 public boolean isFixedPitch; 72 public short xMin; 73 public short yMin; 74 public short xMax; 75 public short yMax; 76 public short underlinePosition; 77 public short underlineThickness; 78 public short capHeight; 79 public short xHeight; 80 public short ascender; 81 public short descender; 82 public short stemH; 83 public short stemV; 84 } 85 86 89 private final class Parser 90 { 91 private BufferedReader fontMetricsData; 92 93 private Parser( 94 BufferedReader fontMetricsData 95 ) 96 { 97 this.fontMetricsData = fontMetricsData; 98 99 load(); 100 } 101 102 private void load( 103 ) 104 { 105 Type1Font.this.metrics = new FontMetrics(); 106 107 load_fontHeader(); 108 load_charMetrics(); 109 load_kerningData(); 110 } 111 112 115 private void load_fontHeader( 116 ) 117 { 118 String line; 119 Pattern linePattern = Pattern.compile("(\\S+)\\s+(.+)"); 120 try 121 { 122 while((line = fontMetricsData.readLine()) != null) 123 { 124 Matcher lineMatcher = linePattern.matcher(line); 125 if(!lineMatcher.find()) 126 continue; 127 128 String key = lineMatcher.group(1); 129 if(key.equals("FontName")) 130 {metrics.fontName = lineMatcher.group(2);} 131 else if (key.equals("Weight")) 132 {metrics.weight = lineMatcher.group(2);} 133 else if (key.equals("ItalicAngle")) 134 {metrics.italicAngle = Float.valueOf(lineMatcher.group(2));} 135 else if (key.equals("IsFixedPitch")) 136 {metrics.isFixedPitch = lineMatcher.group(2).equals("true");} 137 else if (key.equals("FontBBox")) 138 { 139 String [] coordinates = lineMatcher.group(2).split("\\s+"); 140 metrics.xMin = Short.valueOf(coordinates[0]); 141 metrics.yMin = Short.valueOf(coordinates[1]); 142 metrics.xMax = Short.valueOf(coordinates[2]); 143 metrics.yMax = Short.valueOf(coordinates[3]); 144 } 145 else if (key.equals("UnderlinePosition")) 146 {metrics.underlinePosition = Short.valueOf(lineMatcher.group(2));} 147 else if (key.equals("UnderlineThickness")) 148 {metrics.underlineThickness = Short.valueOf(lineMatcher.group(2));} 149 else if (key.equals("EncodingScheme")) 150 {metrics.isCustomEncoding = lineMatcher.group(2).equals("FontSpecific");} 151 else if (key.equals("CapHeight")) 152 {metrics.capHeight = Short.valueOf(lineMatcher.group(2));} 153 else if (key.equals("XHeight")) 154 {metrics.xHeight = Short.valueOf(lineMatcher.group(2));} 155 else if (key.equals("Ascender")) 156 {metrics.ascender = Short.valueOf(lineMatcher.group(2));} 157 else if (key.equals("Descender")) 158 {metrics.descender = Short.valueOf(lineMatcher.group(2));} 159 else if (key.equals("StdHW")) 160 {metrics.stemH = Short.valueOf(lineMatcher.group(2));} 161 else if (key.equals("StdVW")) 162 {metrics.stemV = Short.valueOf(lineMatcher.group(2));} 163 else if (key.equals("StartCharMetrics")) 164 {break;} 165 } 166 } 167 catch(Exception e) 168 {throw new RuntimeException (e);} 169 } 170 171 174 private void load_charMetrics( 175 ) 176 { 177 Type1Font.this.widths = new Hashtable <Integer ,Integer >(); 178 179 try 180 { 181 185 if(metrics.isCustomEncoding) { 187 String line; 188 Pattern linePattern = Pattern.compile("C (\\S+) ; WX (\\S+)"); 189 while((line = fontMetricsData.readLine()) != null) 190 { 191 Matcher lineMatcher = linePattern.matcher(line); 192 if(!lineMatcher.find()) 193 { 194 if(line.equals("EndCharMetrics")) 195 break; 196 197 continue; 198 } 199 200 int code = Integer.valueOf(lineMatcher.group(1)); 201 int width = Integer.valueOf(lineMatcher.group(2)); 202 203 widths.put(code,width); 204 } 205 } 206 else { 208 String line; 209 Pattern linePattern = Pattern.compile(" WX (\\S+) ; N (\\S+)"); 210 while((line = fontMetricsData.readLine()) != null) 211 { 212 Matcher lineMatcher = linePattern.matcher(line); 213 if(!lineMatcher.find()) 214 { 215 if(line.equals("EndCharMetrics")) 216 break; 217 218 continue; 219 } 220 221 String name = lineMatcher.group(2); 222 int width = Integer.valueOf(lineMatcher.group(1)); 223 224 widths.put( 225 GlyphMapping.nameToCode(name), 226 width 227 ); 228 } 229 } 230 } 231 catch(Exception e) 232 {throw new RuntimeException (e);} 233 } 234 235 238 private void load_kerningData( 239 ) 240 { 241 Type1Font.this.kernings = new Hashtable <Integer ,Integer >(); 242 243 try 244 { 245 String line; 246 while((line = fontMetricsData.readLine()) != null) 247 { 248 if(line.startsWith("StartKernPairs")) 249 break; 250 } 251 252 Pattern linePattern = Pattern.compile("KPX (\\S+) (\\S+) (\\S+)"); 253 while((line = fontMetricsData.readLine()) != null) 254 { 255 Matcher lineMatcher = linePattern.matcher(line); 256 if(!lineMatcher.find()) 257 { 258 if(line.equals("EndKernPairs")) 259 break; 260 261 continue; 262 } 263 264 int code1 = GlyphMapping.nameToCode(lineMatcher.group(1)); 265 int code2 = GlyphMapping.nameToCode(lineMatcher.group(2)); 266 int value = Integer.valueOf(lineMatcher.group(3)); 267 int pair = code1 << 16 + code2; 268 269 kernings.put(pair,value); 270 } 271 } 272 catch(Exception e) 273 {throw new RuntimeException (e);} 274 } 275 } 276 277 280 private static final class GlyphMapping 281 { 282 private static Hashtable <String ,Integer > codes = new Hashtable <String ,Integer >(); 283 284 static 285 {load();} 286 287 public static int nameToCode( 288 String name 289 ) 290 {return codes.get(name);} 291 292 295 private static void load( 296 ) 297 { 298 BufferedReader glyphListStream = null; 299 try 300 { 301 306 glyphListStream = new BufferedReader ( 307 new InputStreamReader ( 308 GlyphMapping.class.getResourceAsStream("/fonts/AGL20.scsv") 309 ) 310 ); 311 312 String line; 314 Pattern linePattern = Pattern.compile("^(\\w+);([A-F0-9]+)$"); 315 while((line = glyphListStream.readLine()) != null) 316 { 317 Matcher lineMatcher = linePattern.matcher(line); 318 if(!lineMatcher.find()) 319 continue; 320 321 String name = lineMatcher.group(1); 322 int code = Integer.parseInt(lineMatcher.group(2),16); 323 324 codes.put(name,code); 326 } 327 } 328 catch(Exception e) 329 {throw new RuntimeException (e);} 330 finally 331 { 332 try 333 { 334 if(glyphListStream != null) 336 {glyphListStream.close();} 337 } 338 catch(Exception e) 339 {throw new RuntimeException (e);} 340 } 341 } 342 } 343 345 private FontMetrics metrics; 348 349 private Hashtable <Integer ,Integer > kernings; 350 private Hashtable <Integer ,Integer > widths; 351 353 367 371 public Type1Font( 373 PdfDirectObject baseObject 374 ) 375 {super(baseObject);} 376 377 protected Type1Font( 378 Document context 379 ) 380 {super(context);} 381 383 public Object clone( 386 Document context 387 ) 388 {throw new NotImplementedException();} 389 390 @Override 391 public double getAscent( 392 double size 393 ) 394 { 395 399 if(getBaseDataObject().containsKey(PdfName.FontDescriptor)) 400 {return super.getAscent(size);} 401 else 402 {return (metrics.ascender * getScalingFactor(size));} 403 } 404 405 @Override 406 public double getDescent( 407 double size 408 ) 409 { 410 414 if(getBaseDataObject().containsKey(PdfName.FontDescriptor)) 415 {return super.getDescent(size);} 416 else 417 {return (metrics.descender * getScalingFactor(size));} 418 } 419 420 @Override 421 public EnumSet <FlagsEnum> getFlags( 422 ) 423 { 424 428 if(getBaseDataObject().containsKey(PdfName.FontDescriptor)) 429 {return super.getFlags();} 430 else 431 { 432 return EnumSet.noneOf(FlagsEnum.class); 434 } 435 } 436 437 @Override 438 public int getKerning( 439 char textChar1, 440 char textChar2 441 ) 442 { 443 try 444 { 445 return kernings.get( 446 ((int)textChar1) << 16 + ((int)textChar2) ); 449 } 450 catch(Exception e) 451 {return 0;} 452 } 453 454 @Override 455 public int getKerning( 456 String text 457 ) 458 { 459 int kerning = 0; 460 if(kernings != null) 462 { 463 char textChars[] = text.toCharArray(); 464 for( 465 int index = 0, 466 length = text.length() - 1; 467 index < length; 468 index++ 469 ) 470 { 471 kerning += getKerning( 472 textChars[index], 473 textChars[index + 1] 474 ); 475 } 476 } 477 478 return kerning; 479 } 480 481 @Override 482 public double getLineHeight( 483 double size 484 ) 485 { 486 490 if(getBaseDataObject().containsKey(PdfName.FontDescriptor)) 491 {return super.getLineHeight(size);} 492 else 493 {return ((metrics.ascender + Math.abs(metrics.descender)) * getScalingFactor(size));} 494 } 495 496 @Override 497 public int getWidth( 498 char textChar 499 ) 500 {return widths.get((int)textChar);} 501 502 @Override 503 public int getWidth( 504 String text 505 ) 506 { 507 int width = 0; 508 char textChars[] = text.toCharArray(); 509 for( 510 int index = 0, 511 length = text.length(); 512 index < length; 513 index++ 514 ) 515 {width += getWidth(textChars[index]);} 516 517 return width; 518 } 519 521 525 protected void load( 526 BufferedReader fontMetricsData, 527 boolean standard 528 ) 529 { 530 try 531 { 532 Parser parser = new Parser(fontMetricsData); 533 534 getBaseDataObject().put( 536 PdfName.Subtype, 537 PdfName.Type1 538 ); 539 getBaseDataObject().put( 541 PdfName.BaseFont, 542 new PdfName(metrics.fontName) 543 ); 544 545 549 if(standard) 550 return; 551 552 throw new NotImplementedException("Extended font descriptions are currently not supported."); 553 } 559 catch(Exception e) 560 {throw new RuntimeException (e);} 561 } 562 563 } | Popular Tags |