title: Extracting Text from a PDF with CID fonts
body: <p>I'm writing a web app that extracts a line at the top of each page in a PDF. The PDFs come from different versions of a product and could go through a number of PDF printers, also in different versions and also different settings.</p>
  
  <p>So far using PDFSharp and iTextSharp I have managed to get it to work for all versions of PDFs. My hang-up is with documents that have CID fonts (Identity-H).</p>
  
  <p>I have written a partial parser to find the font table reference and the text blocks, but converting these to readable text is beating me.</p>
  
  <p>Does anyone have either:
  - a parser (like this one <a href="https://stackoverflow.com/a/1732265/5169050">https://stackoverflow.com/a/1732265/5169050</a>) that copes with CID fonts; or
  - some example code for how to parse a pages resource dictionary to find the pages fonts and get its ToUnicode stream to help finish off this example (<a href="https://stackoverflow.com/a/4048328/5169050">https://stackoverflow.com/a/4048328/5169050</a>)</p>
  
  <p>We have to use iTextSharp 4.1 to retain the free-to-use license.</p>
  
  <p>Here's my partial parser.</p>
  
  <pre><code>public string ExtractTextFromCIDPDFBytes(byte[] input)
  {
      if (input == null || input.Length == 0) return "";
  
      try
      {
          // Holds the final result to be returned
          string resultString = "";
          // Are we in a block of text or not
          bool blnInText = false;
          // Holds each line of text before written to resultString
          string phrase = "";
          // Holds the 4-character hex codes as they are built
          string hexCode = "";
          // Are we in a font reference or not (much like a code block)
          bool blnInFontRef = false;
          // Holds the last font reference and therefore the CMAP table
          // to be used for any text found after it
          string currentFontRef = "";
  
          for (int i = 0; i &lt; input.Length; i++)
          {
              char c = (char)input[i];
  
              switch (c)
              {
                  case '&lt;':
                      {
                          blnInText = true;
                          break;
                      }
                  case '&gt;':
                      {
                          resultString = resultString + Environment.NewLine + phrase;
                          phrase = "";
                          blnInText = false;
                          break;
                      }
                  case 'T':
                      {
                          switch (((char)input[i + 1]).ToString().ToLower())
                          {
                              case "f":
                                  {
                                      // Tf represents the start of a font table reference
                                      blnInFontRef = true;
                                      currentFontRef = "";
                                      break;
                                  }
                              case "d":
                                  {
                                      // Td represents the end of a font table reference or
                                      // the start of a text block
                                      blnInFontRef = false;
                                      break;
                                  }
                          }
                          break;
                      }
                  default:
                      {
                          if (blnInText)
                          {
                              // We are looking for 4-character blocks of hex characters
                              // These will build up a number which refers to the index
                              // of the glyph in the CMAP table, which will give us the
                              // character
                              hexCode = hexCode + c;
                              if (hexCode.Length == 4)
                              {
                                  // TODO - translate code to character
                                  char translatedHexCode = c;
  
  
  
                                  phrase = phrase + translatedHexCode;
                                  // Blank it out ready for the next 4
                                  hexCode = "";
                              }
                          }
                          else
                          {
                              if (blnInFontRef)
                              {
                                  currentFontRef = currentFontRef + c;
                              }
                          }
                          break;
                      }
              }
          }
  
          return resultString;
      }
      catch
      {
          return "";
      }
  }
  </code></pre>