/** * <summary>Parses the character-code-to-unicode mapping [PDF:1.6:5.9.1].</summary> */ public IDictionary <ByteArray, int> Parse( ) { Stream.Seek(0); IDictionary <ByteArray, int> codes = new Dictionary <ByteArray, int>(); { IList <object> operands = new List <object>(); string cmapName = null; while (MoveNext()) { switch (TokenType) { case TokenTypeEnum.Keyword: { string @operator = (string)Token; if (@operator.Equals(BeginBaseFontCharOperator) || @operator.Equals(BeginCIDCharOperator)) { /* * NOTE: The first element on each line is the input code of the template font; * the second element is the code or name of the character. */ for (int itemIndex = 0, itemCount = (int)operands[0]; itemIndex < itemCount; itemIndex++) { MoveNext(); ByteArray inputCode = new ByteArray(ParseInputCode()); MoveNext(); // FIXME: Unicode character sequences (such as ligatures) have not been supported yet [BUG:72]. try { codes[inputCode] = ParseUnicode(); } catch (OverflowException) { Debug.WriteLine(String.Format("WARN: Unable to process Unicode sequence from {0} CMap: {1}", cmapName, Token)); } } } else if (@operator.Equals(BeginBaseFontRangeOperator) || @operator.Equals(BeginCIDRangeOperator)) { /* * NOTE: The first and second elements in each line are the beginning and * ending valid input codes for the template font; the third element is * the beginning character code for the range. */ for (int itemIndex = 0, itemCount = (int)operands[0]; itemIndex < itemCount; itemIndex++) { // 1. Beginning input code. MoveNext(); byte[] beginInputCode = ParseInputCode(); // 2. Ending input code. MoveNext(); byte[] endInputCode = ParseInputCode(); // 3. Character codes. MoveNext(); switch (TokenType) { case TokenTypeEnum.ArrayBegin: { byte[] inputCode = beginInputCode; while (MoveNext() && TokenType != TokenTypeEnum.ArrayEnd) { // FIXME: Unicode character sequences (such as ligatures) have not been supported yet [BUG:72]. try { codes[new ByteArray(inputCode)] = ParseUnicode(); } catch (OverflowException) { Debug.WriteLine(String.Format("WARN: Unable to process Unicode sequence from {0} CMap: {1}", cmapName, Token)); } OperationUtils.Increment(inputCode); } break; } default: { byte[] inputCode = beginInputCode; int charCode = ParseUnicode(); int endCharCode = charCode + (ConvertUtils.ByteArrayToInt(endInputCode) - ConvertUtils.ByteArrayToInt(beginInputCode)); while (true) { codes[new ByteArray(inputCode)] = charCode; if (charCode == endCharCode) { break; } OperationUtils.Increment(inputCode); charCode++; } break; } } } } else if (@operator.Equals(UseCMapOperator)) { codes = CMap.Get((string)operands[0]); } else if (@operator.Equals(DefOperator) && operands.Count != 0) { if (CMapName.Equals(operands[0])) { cmapName = (string)operands[1]; } } operands.Clear(); break; } case TokenTypeEnum.ArrayBegin: case TokenTypeEnum.DictionaryBegin: { // Skip. while (MoveNext()) { if (TokenType == TokenTypeEnum.ArrayEnd || TokenType == TokenTypeEnum.DictionaryEnd) { break; } } break; } case TokenTypeEnum.Comment: // Skip. break; default: { operands.Add(Token); break; } } } } return(codes); }
protected void LoadEncoding( ) { PdfDataObject encodingObject = BaseDataObject.Resolve(PdfName.Encoding); // CMap [PDF:1.6:5.6.4]. IDictionary <ByteArray, int> cmap = CMap.Get(encodingObject); // 1. Unicode. if (codes == null) { codes = new BiDictionary <ByteArray, int>(); if (encodingObject is PdfName && !(encodingObject.Equals(PdfName.IdentityH) || encodingObject.Equals(PdfName.IdentityV))) { /* * NOTE: According to [PDF:1.6:5.9.1], the fallback method to retrieve * the character-code-to-Unicode mapping implies getting the UCS2 CMap * (Unicode value to CID) corresponding to the font's one (character code to CID); * CIDs are the bridge from character codes to Unicode values. */ BiDictionary <ByteArray, int> ucs2CMap; { PdfDictionary cidSystemInfo = (PdfDictionary)CIDFontDictionary.Resolve(PdfName.CIDSystemInfo); String registry = (String)((PdfTextString)cidSystemInfo[PdfName.Registry]).Value; String ordering = (String)((PdfTextString)cidSystemInfo[PdfName.Ordering]).Value; String ucs2CMapName = registry + "-" + ordering + "-" + "UCS2"; ucs2CMap = new BiDictionary <ByteArray, int>(CMap.Get(ucs2CMapName)); } if (ucs2CMap.Count > 0) { foreach (KeyValuePair <ByteArray, int> cmapEntry in cmap) { codes[cmapEntry.Key] = ConvertUtils.ByteArrayToInt(ucs2CMap.GetKey(cmapEntry.Value).Data); } } } if (codes.Count == 0) { /* * NOTE: In case no clue is available to determine the Unicode resolution map, * the font is considered symbolic and an identity map is synthesized instead. */ symbolic = true; foreach (KeyValuePair <ByteArray, int> cmapEntry in cmap) { codes[cmapEntry.Key] = ConvertUtils.ByteArrayToInt(cmapEntry.Key.Data); } } } // 2. Glyph indexes. /* * TODO: gids map for glyph indexes as glyphIndexes is used to map cids!!! */ // Character-code-to-CID mapping [PDF:1.6:5.6.4,5]. glyphIndexes = new Dictionary <int, int>(); foreach (KeyValuePair <ByteArray, int> cmapEntry in cmap) { if (!codes.ContainsKey(cmapEntry.Key)) { continue; } glyphIndexes[codes[cmapEntry.Key]] = cmapEntry.Value; } }