title: Get PDF hyperlinks on iOS with Quartz
body: <p>I've spent all day trying to get hyperlinks metadata from PDFs in my iPad application. 
  The CGPDF* APIs are a true nightmare, and the only piece of information I've found on the net about all this is that I have to look for an "Annots" dictionary, but I just can't find it in my PDFs. </p>
  
  <p>I even used the old <a href="https://github.com/below/PDF-Voyeur/network" rel="nofollow noreferrer">Voyeur Xcode sample</a> to inspect my test PDF file, but no trace of this "Annots" dictionary...</p>
  
  <p>You know, this is a feature I see on every PDF reader - this same question has <a href="https://stackoverflow.com/questions/93297/newbie-wants-to-create-a-pdf-reader-for-ipod-touch-whats-the-best-approach">been</a> <a href="https://stackoverflow.com/questions/3257057/iphone-cgpdfdocument-pdf-links">asked</a> <a href="https://stackoverflow.com/questions/2609602/pdf-hyperlinks-on-iphone-ipad">multiple</a> <a href="https://stackoverflow.com/questions/1247792/how-to-access-hyperlinks-in-pdf-documents-iphone">times</a> here with no real practical answers. I usually never ask for sample code directly but apparently this time I really need it... anyone got this working, possibly with sample code?</p>
  
  <p><strong>Update</strong>: I just realized the guy who has done my testing PDF had just inserted an URL as text, and not a real annotation. He tried putting an annotation and my code works now... But that's not what I need, so it seems I'll have to analyze text and search for URLs. But that's another story... </p>
  
  <p><strong>Update 2</strong>: So I finally came up with some working code. I'm posting it here so hopefully it'll help someone. It assumes the PDF document actually contains annotations. </p>
  
  <pre><code>for(int i=0; i&lt;pageCount; i++) {
      CGPDFPageRef page = CGPDFDocumentGetPage(doc, i+1);
  
      CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(page);
  
      CGPDFArrayRef outputArray;
      if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &amp;outputArray)) {
          return;
      }
  
      int arrayCount = CGPDFArrayGetCount( outputArray );
      if(!arrayCount) {
          continue;
      }
  
      for( int j = 0; j &lt; arrayCount; ++j ) {
          CGPDFObjectRef aDictObj;
          if(!CGPDFArrayGetObject(outputArray, j, &amp;aDictObj)) {
              return;
          }
  
          CGPDFDictionaryRef annotDict;
          if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &amp;annotDict)) {
              return;
          }
  
          CGPDFDictionaryRef aDict;
          if(!CGPDFDictionaryGetDictionary(annotDict, "A", &amp;aDict)) {
              return;
          }
  
          CGPDFStringRef uriStringRef;
          if(!CGPDFDictionaryGetString(aDict, "URI", &amp;uriStringRef)) {
              return;
          }
  
          CGPDFArrayRef rectArray;
          if(!CGPDFDictionaryGetArray(annotDict, "Rect", &amp;rectArray)) {
              return;
          }
  
          int arrayCount = CGPDFArrayGetCount( rectArray );
          CGPDFReal coords[4];
          for( int k = 0; k &lt; arrayCount; ++k ) {
              CGPDFObjectRef rectObj;
              if(!CGPDFArrayGetObject(rectArray, k, &amp;rectObj)) {
                  return;
              }
  
              CGPDFReal coord;
              if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &amp;coord)) {
                  return;
              }
  
              coords[k] = coord;
          }               
  
          char *uriString = (char *)CGPDFStringGetBytePtr(uriStringRef);
  
          NSString *uri = [NSString stringWithCString:uriString encoding:NSUTF8StringEncoding];
          CGRect rect = CGRectMake(coords[0],coords[1],coords[2],coords[3]);
  
          CGPDFInteger pageRotate = 0;
          CGPDFDictionaryGetInteger( pageDictionary, "Rotate", &amp;pageRotate ); 
          CGRect pageRect = CGRectIntegral( CGPDFPageGetBoxRect( page, kCGPDFMediaBox ));
          if( pageRotate == 90 || pageRotate == 270 ) {
              CGFloat temp = pageRect.size.width;
              pageRect.size.width = pageRect.size.height;
              pageRect.size.height = temp;
          }
  
          rect.size.width -= rect.origin.x;
          rect.size.height -= rect.origin.y;
  
          CGAffineTransform trans = CGAffineTransformIdentity;
          trans = CGAffineTransformTranslate(trans, 0, pageRect.size.height);
          trans = CGAffineTransformScale(trans, 1.0, -1.0);
  
          rect = CGRectApplyAffineTransform(rect, trans);
  
          // do whatever you need with the coordinates.
          // e.g. you could create a button and put it on top of your page
          // and use it to open the URL with UIApplication's openURL
      }
  }
  </code></pre>