Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6180387
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 24, 20262026-05-24T00:50:09+00:00 2026-05-24T00:50:09+00:00

I am trying to find all hyperlinks on a page in a PDF document

  • 0

I am trying to find all hyperlinks on a page in a PDF document and place a UIButton over them.

I have found and played around with the script below which should be able to do it. It finds the hyperlinks and places UIButtons bt they are not on top of the links. Can anyone tell me why that may be?

I have attached an image to show how the buttons are off. The uppermost buttons should be on top of the blue “METROPOLITAN” text and the lowermost buttons should be on top of the text saying “SÆSONEN 2008-2009”.

This is the code I am using to find the links and place the buttons.

    NSMutableArray *rectArrays;
    NSMutableArray *storeURLs;

    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(_pdf, pageNumber);
    CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(pdfPage);

    CGPDFArrayRef outputArray;
    if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray)) {
        //break;
    }

    int arrayCount = 0;
    arrayCount = CGPDFArrayGetCount(outputArray);
    if(arrayCount > 0) {
        for(int j = 0; j < arrayCount; ++j) {
            CGPDFObjectRef aDictObj;
            if(!CGPDFArrayGetObject(outputArray, j, &aDictObj)) {
                return;
            }

            CGPDFDictionaryRef annotDict;
            if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &annotDict)) {
                return;
            }

            CGPDFDictionaryRef aDict;
            if(!CGPDFDictionaryGetDictionary(annotDict, "A", &aDict)) {
                return;
            }

            CGPDFStringRef uriStringRef;
            if(!CGPDFDictionaryGetString(aDict, "URI", &uriStringRef)) {
                return;
            }

            CGPDFArrayRef rectArray;
            if(!CGPDFDictionaryGetArray(annotDict, "Rect", &rectArray)) {
                return;
            }

            int arrayCount = CGPDFArrayGetCount( rectArray );
            CGPDFReal coords[4];
            for(int k = 0; k < arrayCount; ++k) {
                CGPDFObjectRef rectObj;
                if(!CGPDFArrayGetObject(rectArray, k, &rectObj)) {
                    return;
                }

                CGPDFReal coord;
                if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &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]);

            NSLog(@"Found: %f ; %f => %f x %f", coords[0], coords[1], coords[2], coords[3]);

            CGPDFInteger pageRotate = 0;
            CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &pageRotate); 
            CGRect pageRect = CGRectIntegral( CGPDFPageGetBoxRect(pdfPage, 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.size.width - rect.origin.x;
            rect.size.height = 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);

            NSURL *url = [NSURL URLWithString:uri];
            [rectArrays addObject:[NSValue valueWithCGRect:rect]];
            [storeURLs addObject:url];

            for(int i = 0; i <= [rectArrays count]; i++) {
                UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
                [button setFrame:rect];
                [button setTitle:@"Link" forState:UIControlStateNormal];
                [[self view] addSubview:button];

                NSLog(@"Added: %f ; %f => %f x %f", button.frame.origin.x, button.frame.origin.y, button.frame.size.width, button.frame.size.height);
            }
        }
    }

enter image description here

EDIT: Trying to adjust for the scale factor but it is not working. The UIButtons are still placed wrong.

CGAffineTransform trans = CGAffineTransformIdentity;
trans = CGAffineTransformTranslate(trans, 0, pageRect.size.height * 1.5);
trans = CGAffineTransformScale(trans, 1.5, -1.5);

EDIT I took a look at the source code which iPDFDev is linking too and it seems that I have got the positioning working now. My buttons are now too long. Does anyone know why this may be? If I substract viewRext.origin.x from viewRect.size.width the buttons are too short.

This is my code now.

    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(_pdf, pageNumber);
    CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(pdfPage);

    CGPDFArrayRef outputArray;
    if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray)) {
        //break;
    }

    int arrayCount = 0;
    arrayCount = CGPDFArrayGetCount(outputArray);
    if(arrayCount > 0) {
        for(int j = 0; j < arrayCount; ++j) {
            CGPDFObjectRef aDictObj;
            if(!CGPDFArrayGetObject(outputArray, j, &aDictObj)) {
                return;
            }

            CGPDFDictionaryRef annotDict;
            if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &annotDict)) {
                return;
            }

            CGPDFDictionaryRef aDict;
            if(!CGPDFDictionaryGetDictionary(annotDict, "A", &aDict)) {
                return;
            }

            CGPDFStringRef uriStringRef;
            if(!CGPDFDictionaryGetString(aDict, "URI", &uriStringRef)) {
                return;
            }

            CGPDFArrayRef rectArray;
            if(!CGPDFDictionaryGetArray(annotDict, "Rect", &rectArray)) {
                return;
            }

            int arrayCount = CGPDFArrayGetCount( rectArray );
            CGPDFReal coords[4];
            for(int k = 0; k < arrayCount; ++k) {
                CGPDFObjectRef rectObj;
                if(!CGPDFArrayGetObject(rectArray, k, &rectObj)) {
                    return;
                }

                CGPDFReal coord;
                if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &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]);

            CGPoint pdfPoint = CGPointMake(rect.origin.x, rect.origin.y);
            CGPoint viewPoint = CGPointMake(0, 0);

            CGRect cropBox = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);

            int rotation = CGPDFPageGetRotationAngle(pdfPage);

            CGRect pageRenderRect;
            switch (rotation) {
                case 90:
                case -270:
                    pageRenderRect = CGRectMake(0, 0, 1024, 768);

                    viewPoint.x = pageRenderRect.size.width * (pdfPoint.y - cropBox.origin.y) / cropBox.size.height;
                    viewPoint.y = pageRenderRect.size.height * (pdfPoint.x - cropBox.origin.x) / cropBox.size.width;
                    break;
                case 180:
                case -180:
                    pageRenderRect = CGRectMake(0, 0, 768, 1024);

                    viewPoint.x = pageRenderRect.size.width * (cropBox.size.width - (pdfPoint.x - cropBox.origin.x)) / cropBox.size.width;
                    viewPoint.y = pageRenderRect.size.height * (pdfPoint.y - cropBox.origin.y) / cropBox.size.height;
                    break;
                case -90:
                case 270:
                    pageRenderRect = CGRectMake(0, 0, 1024, 768);

                    viewPoint.x = pageRenderRect.size.width * (cropBox.size.height - (pdfPoint.y - cropBox.origin.y)) / cropBox.size.height;
                    viewPoint.y = pageRenderRect.size.height * (cropBox.size.width - (pdfPoint.x - cropBox.origin.x)) / cropBox.size.width;
                    break;
                case 0:
                default:
                    pageRenderRect = CGRectMake(0, 0, 768, 1024);

                    viewPoint.x = pageRenderRect.size.width * (pdfPoint.x - cropBox.origin.x) / cropBox.size.width;
                    viewPoint.y = pageRenderRect.size.height * (cropBox.size.height - pdfPoint.y) / cropBox.size.height;
                    break;
            }

            viewPoint.x = viewPoint.x + pageRenderRect.origin.x;
            viewPoint.y = viewPoint.y + pageRenderRect.origin.y;

            CGRect viewRect = CGRectMake(viewPoint.x, viewPoint.y, rect.size.width, rect.size.height - rect.origin.y);
            viewRect = CGRectMake(viewRect.origin.x, viewRect.origin.y - viewRect.size.height, viewRect.size.width, viewRect.size.height);

            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            [button setFrame:viewRect];
            [button setBackgroundColor:[UIColor greenColor]];
            [button setAlpha:0.65];
            [button setTag:kPDFLinkButton];
            [[self view] addSubview:button];
        }
    }

EDIT: This is my final code. See the answer from iPDFDev for more information.

- (void)getLinksFromPDF:(CGPDFDocumentRef)_pdf withPageNumber:(NSUInteger)pageNumber
{
    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(_pdf, pageNumber);
    CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(pdfPage);

    CGPDFArrayRef outputArray;
    if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray)) {
        //break;
    }

    int arrayCount = 0;
    arrayCount = CGPDFArrayGetCount(outputArray);
    if(arrayCount > 0) {
        for(int j = 0; j < arrayCount; ++j) {
            CGPDFObjectRef aDictObj;
            if(!CGPDFArrayGetObject(outputArray, j, &aDictObj)) {
                return;
            }

            CGPDFDictionaryRef annotDict;
            if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &annotDict)) {
                return;
            }

            CGPDFDictionaryRef aDict;
            if(!CGPDFDictionaryGetDictionary(annotDict, "A", &aDict)) {
                return;
            }

            CGPDFStringRef uriStringRef;
            if(!CGPDFDictionaryGetString(aDict, "URI", &uriStringRef)) {
                return;
            }

            CGPDFArrayRef rectArray;
            if(!CGPDFDictionaryGetArray(annotDict, "Rect", &rectArray)) {
                return;
            }

            int arrayCount = CGPDFArrayGetCount( rectArray );
            CGPDFReal coords[4];
            for(int k = 0; k < arrayCount; ++k) {
                CGPDFObjectRef rectObj;
                if(!CGPDFArrayGetObject(rectArray, k, &rectObj)) {
                    return;
                }

                CGPDFReal coord;
                if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &coord)) {
                    return;
                }

                coords[k] = coord;
            }

            char *uriString = (char *)CGPDFStringGetBytePtr(uriStringRef);

            NSString *uri = [NSString stringWithCString:uriString encoding:NSUTF8StringEncoding];

            CGPoint lowerLeft = [self convertPDFPointToViewPoint:CGPointMake(coords[0], coords[1])];
            CGPoint upperRight = [self convertPDFPointToViewPoint:CGPointMake(coords[2], coords[3])];

            // This is the rectangle positioned under the link
            CGRect viewRect = CGRectMake(lowerLeft.x, lowerLeft.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);

            // Now adjusting the rectangle to be on top of the link
            viewRect = CGRectMake(viewRect.origin.x, viewRect.origin.y - viewRect.size.height, viewRect.size.width, viewRect.size.height);

            NSLog(@"%@", uri);

            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            [button setFrame:viewRect];
            [button setBackgroundColor:[UIColor greenColor]];
            [button setAlpha:0.65];
            [button setTag:kPDFLinkButton];
            [[self view] addSubview:button];
        }
    }   
}

- (CGPoint)convertPDFPointToViewPoint:(CGPoint)pdfPoint
{
    CGPoint viewPoint = CGPointMake(0, 0);

    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, currentPage);

    CGRect cropBox = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);

    int rotation = CGPDFPageGetRotationAngle(pdfPage);

    CGRect pageRenderRect;
    switch (rotation) {
        case 90:
        case -270:
            pageRenderRect = CGRectMake(0, 0, 1024, 768);

            viewPoint.x = pageRenderRect.size.width * (pdfPoint.y - cropBox.origin.y) / cropBox.size.height;
            viewPoint.y = pageRenderRect.size.height * (pdfPoint.x - cropBox.origin.x) / cropBox.size.width;
            break;
        case 180:
        case -180:
            pageRenderRect = CGRectMake(0, 0, 768, 1024);

            viewPoint.x = pageRenderRect.size.width * (cropBox.size.width - (pdfPoint.x - cropBox.origin.x)) / cropBox.size.width;
            viewPoint.y = pageRenderRect.size.height * (pdfPoint.y - cropBox.origin.y) / cropBox.size.height;
            break;
        case -90:
        case 270:
            pageRenderRect = CGRectMake(0, 0, 1024, 768);

            viewPoint.x = pageRenderRect.size.width * (cropBox.size.height - (pdfPoint.y - cropBox.origin.y)) / cropBox.size.height;
            viewPoint.y = pageRenderRect.size.height * (cropBox.size.width - (pdfPoint.x - cropBox.origin.x)) / cropBox.size.width;
            break;
        case 0:
        default:
            pageRenderRect = CGRectMake(0, 0, 768, 1024);

            viewPoint.x = pageRenderRect.size.width * (pdfPoint.x - cropBox.origin.x) / cropBox.size.width;
            viewPoint.y = pageRenderRect.size.height * (cropBox.size.height - pdfPoint.y) / cropBox.size.height;
            break;
    }

    viewPoint.x = viewPoint.x + pageRenderRect.origin.x;
    viewPoint.y = viewPoint.y + pageRenderRect.origin.y;

    return viewPoint;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-24T00:50:09+00:00Added an answer on May 24, 2026 at 12:50 am

    The links are stored in the Annots array in the page dictionary. When you loop through the Annots array, you locate the link annotations by verifying the Subtype key in the annotation dictionary, it must be “Link” (name object). If you have a link annotation, you verify if it has an action stored in the A entry. If it has an action, you verify if it is a web link, the S entry in the action dictionary must have the value “URI” (name object). If you have an URI action, then you retrieve the link from the URI entry in the action dictionary.

    The annotation position on the PDF page is stored in the Rect array. These are 4 values for 2 opposite corners, usually lower left x, lower left y, upper right x, upper right y. These values are relative to bottom left corner of page’s media box. These values must be transformed in view coordinates based on these variables: 1. position in the view where the page is displayed; 2. size in the view of the displayed page (current scaling factor * PDF page size); 3. page crop box; 4. page rotation.

    The conversion method looks like this:

    - (CGPoint)convertPDFPointToViewPoint:(CGPoint)pdfPoint {
        CGPoint viewPoint = CGPointMake(0, 0);
    
        CGRect cropBox = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
    
        int rotation = CGPDFPageGetRotationAngle(pdfPage);
    
        switch (rotation) {
            case 90:
            case -270:
                viewPoint.x = pageRenderRect.size.width * (pdfPoint.y - cropBox.origin.y) / cropBox.size.height;
                viewPoint.y = pageRenderRect.size.height * (pdfPoint.x - cropBox.origin.x) / cropBox.size.width;
                break;
            case 180:
            case -180:
                viewPoint.x = pageRenderRect.size.width * (cropBox.size.width - (pdfPoint.x - cropBox.origin.x)) / cropBox.size.width;
                viewPoint.y = pageRenderRect.size.height * (pdfPoint.y - cropBox.origin.y) / cropBox.size.height;
                break;
            case -90:
            case 270:
                viewPoint.x = pageRenderRect.size.width * (cropBox.size.height - (pdfPoint.y - cropBox.origin.y)) / cropBox.size.height;
                viewPoint.y = pageRenderRect.size.height * (cropBox.size.width - (pdfPoint.x - cropBox.origin.x)) / cropBox.size.width;
                break;
            case 0:
            default:
                viewPoint.x = pageRenderRect.size.width * (pdfPoint.x - cropBox.origin.x) / cropBox.size.width;
                viewPoint.y = pageRenderRect.size.height * (cropBox.size.height - pdfPoint.y) / cropBox.size.height;
                break;
        }
    
        viewPoint.x = viewPoint.x + pageRenderRect.origin.x;
        viewPoint.y = viewPoint.y + pageRenderRect.origin.y;
    
        return viewPoint;
    }
    

    where the pageRenderRect is the rectangle in the view where the page is displayed.
    You can find additional reference source code here: http://ipdfdev.com/2011/06/21/links-navigation-in-a-pdf-document-on-iphone-and-ipad/

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm trying to find all data items that have long/lats that are contained by
I'm trying to find all permutations of a string and sort them alphabetically. This
I'm trying to use XPath to find all elements that have an element in
I'm trying to find all text files which have the encoding iso-8859-1 and convert
I am trying to find all of the conversations that have only a set
I'm trying to find all letters and dashes and dollar signs and remove them
I'm trying to find all elements on a page whose element ID contains a
I'm trying to find all subfolders in a file's path that have 'others exec'
I'm trying to find all text nodes on the page using jquery. But no
I'm trying to find all occurrences of items in HTML page that are in

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.