28
28
29
29
import org .apache .commons .logging .Log ;
30
30
import org .apache .commons .logging .LogFactory ;
31
+ import org .apache .fontbox .ttf .FontHeaders ;
31
32
import org .apache .pdfbox .io .RandomAccessRead ;
32
33
33
34
@@ -106,13 +107,61 @@ public List<CFFFont> parse(RandomAccessRead randomAccessRead) throws IOException
106
107
}
107
108
108
109
/**
109
- * Parse CFF font using a DataInput as input .
110
+ * Extract "Registry", "Ordering" and "Supplement" properties from the first CFF subfont .
110
111
*
111
- * @param input the source to be parsed
112
+ * @param randomAccessRead the source to be parsed
113
+ * @param outHeaders where to put results
112
114
* @return the parsed CFF fonts
113
115
* @throws IOException If there is an error reading from the stream
114
116
*/
115
- private List <CFFFont > parse (DataInput input ) throws IOException
117
+ public void parseFirstSubFontROS (RandomAccessRead randomAccessRead , FontHeaders outHeaders ) throws IOException
118
+ {
119
+ // this method is a simplified and merged version of parse(RandomAccessRead) > parse(DataInput) > parseFont(...)
120
+
121
+ // start code from parse(RandomAccessRead)
122
+ randomAccessRead .seek (0 );
123
+ DataInput input = new DataInputRandomAccessRead (randomAccessRead );
124
+
125
+ // start code from parse(DataInput)
126
+ input = skipHeader (input );
127
+ String [] nameIndex = readStringIndexData (input );
128
+ if (nameIndex .length == 0 )
129
+ {
130
+ outHeaders .setError ("Name index missing in CFF font" );
131
+ return ;
132
+ }
133
+ byte [][] topDictIndex = readIndexData (input );
134
+ if (topDictIndex .length == 0 )
135
+ {
136
+ outHeaders .setError ("Top DICT INDEX missing in CFF font" );
137
+ return ;
138
+ }
139
+
140
+ // 'stringIndex' is required by 'parseROS() > readString()'
141
+ stringIndex = readStringIndexData (input );
142
+
143
+ // start code from parseFont(...)
144
+ DataInputByteArray topDictInput = new DataInputByteArray (topDictIndex [0 ]);
145
+ DictData topDict = readDictData (topDictInput );
146
+
147
+ DictData .Entry syntheticBaseEntry = topDict .getEntry ("SyntheticBase" );
148
+ if (syntheticBaseEntry != null )
149
+ {
150
+ outHeaders .setError ("Synthetic Fonts are not supported" );
151
+ return ;
152
+ }
153
+
154
+ CFFCIDFont cffCIDFont = parseROS (topDict );
155
+ if (cffCIDFont != null )
156
+ {
157
+ outHeaders .setOtfROS (
158
+ cffCIDFont .getRegistry (),
159
+ cffCIDFont .getOrdering (),
160
+ cffCIDFont .getSupplement ());
161
+ }
162
+ }
163
+
164
+ private DataInput skipHeader (DataInput input ) throws IOException
116
165
{
117
166
String firstTag = readTagName (input );
118
167
// try to determine which kind of font we have
@@ -132,6 +181,19 @@ private List<CFFFont> parse(DataInput input) throws IOException
132
181
133
182
@ SuppressWarnings ("unused" )
134
183
Header header = readHeader (input );
184
+ return input ;
185
+ }
186
+
187
+ /**
188
+ * Parse CFF font using a DataInput as input.
189
+ *
190
+ * @param input the source to be parsed
191
+ * @return the parsed CFF fonts
192
+ * @throws IOException If there is an error reading from the stream
193
+ */
194
+ private List <CFFFont > parse (DataInput input ) throws IOException
195
+ {
196
+ input = skipHeader (input );
135
197
String [] nameIndex = readStringIndexData (input );
136
198
if (nameIndex .length == 0 )
137
199
{
@@ -463,6 +525,28 @@ private static Double readRealNumber(DataInput input) throws IOException
463
525
}
464
526
}
465
527
528
+ /**
529
+ * Extracts Registry, Ordering and Supplement from {@code topDict["ROS"]}.
530
+ */
531
+ private CFFCIDFont parseROS (DictData topDict ) throws IOException
532
+ {
533
+ // determine if this is a Type 1-equivalent font or a CIDFont
534
+ DictData .Entry rosEntry = topDict .getEntry ("ROS" );
535
+ if (rosEntry != null )
536
+ {
537
+ if (rosEntry .size () < 3 )
538
+ {
539
+ throw new IOException ("ROS entry must have 3 elements" );
540
+ }
541
+ CFFCIDFont cffCIDFont = new CFFCIDFont ();
542
+ cffCIDFont .setRegistry (readString (rosEntry .getNumber (0 ).intValue ()));
543
+ cffCIDFont .setOrdering (readString (rosEntry .getNumber (1 ).intValue ()));
544
+ cffCIDFont .setSupplement (rosEntry .getNumber (2 ).intValue ());
545
+ return cffCIDFont ;
546
+ }
547
+ return null ;
548
+ }
549
+
466
550
private CFFFont parseFont (DataInput input , String name , byte [] topDictIndex ) throws IOException
467
551
{
468
552
// top dict
@@ -476,21 +560,12 @@ private CFFFont parseFont(DataInput input, String name, byte[] topDictIndex) thr
476
560
throw new IOException ("Synthetic Fonts are not supported" );
477
561
}
478
562
479
- // determine if this is a Type 1-equivalent font or a CIDFont
480
563
CFFFont font ;
481
- boolean isCIDFont = topDict .getEntry ("ROS" ) != null ;
482
- if (isCIDFont )
564
+ CFFCIDFont cffCIDFont = parseROS (topDict );
565
+ // determine if this is a Type 1-equivalent font or a CIDFont
566
+ boolean isCIDFont = cffCIDFont != null ;
567
+ if (cffCIDFont != null )
483
568
{
484
- CFFCIDFont cffCIDFont = new CFFCIDFont ();
485
- DictData .Entry rosEntry = topDict .getEntry ("ROS" );
486
- if (rosEntry == null || rosEntry .size () < 3 )
487
- {
488
- throw new IOException ("ROS entry must have 3 elements" );
489
- }
490
- cffCIDFont .setRegistry (readString (rosEntry .getNumber (0 ).intValue ()));
491
- cffCIDFont .setOrdering (readString (rosEntry .getNumber (1 ).intValue ()));
492
- cffCIDFont .setSupplement (rosEntry .getNumber (2 ).intValue ());
493
-
494
569
font = cffCIDFont ;
495
570
}
496
571
else
0 commit comments