2010-11-02 30 views
54

Tôi đã dành cả ngày để tìm siêu dữ liệu siêu liên kết từ tệp PDF trong ứng dụng iPad của mình. Các CGPDF * API là một cơn ác mộng thực sự, và thông tin duy nhất tôi tìm thấy trên mạng về tất cả điều này là tôi phải tìm một từ điển "Annots", nhưng tôi không thể tìm thấy nó trong các tệp PDF của tôi .Nhận siêu liên kết PDF trên iOS với Quartz

Tôi thậm chí còn sử dụng cái cũ Voyeur Xcode sample để kiểm tra tập tin thử nghiệm PDF của tôi, nhưng không có dấu vết của "Annots" từ điển này ...

Bạn biết đấy, đây là một tính năng tôi nhìn thấy trên mỗi chương trình đọc PDF - câu hỏi này tương tự có beenaskedmultipletimes ở đây không có câu trả lời thực tế nào. Tôi thường không bao giờ yêu cầu mã mẫu trực tiếp nhưng dường như thời gian này tôi thực sự cần nó ... bất cứ ai đã làm việc này, có thể với mã mẫu?

Cập nhật: Tôi vừa nhận ra rằng người đã thực hiện thử nghiệm PDF của tôi vừa chèn URL dưới dạng văn bản chứ không phải chú thích thực. Anh ấy đã thử đặt chú thích và mã của tôi hoạt động ngay bây giờ ... Nhưng đó không phải là những gì tôi cần, vì vậy có vẻ như tôi sẽ phải phân tích văn bản và tìm kiếm các URL. Nhưng đó là một câu chuyện khác ...

Cập nhật 2: Vì vậy, cuối cùng tôi đã đưa ra một số mã làm việc. Tôi đăng nó ở đây để hy vọng nó sẽ giúp ai đó. Nó giả định tài liệu PDF thực sự chứa các chú thích.

for(int i=0; i<pageCount; i++) { 
    CGPDFPageRef page = CGPDFDocumentGetPage(doc, i+1); 

    CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(page); 

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

    int arrayCount = CGPDFArrayGetCount(outputArray); 
    if(!arrayCount) { 
     continue; 
    } 

    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]); 

     CGPDFInteger pageRotate = 0; 
     CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &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 
    } 
} 
+0

dòng 6, không nên là 'tiếp tục' thay vì' trả lại'? - tại sao bạn quay trở lại sau khi kiểm tra đối tượng, giá trị, dict, chuỗi, mảng vv –

+0

Đó chỉ là mã ví dụ mà không có bất kỳ kiểm tra lỗi nào. – pt2ph8

+0

PDF rects không dịch sang tiếng bản địa, xem chuỗi của tôi để biết chi tiết: cuộn xuống: 'Các tính năng PDF khác', 'Nhận liên kết bên trong một tệp PDF', 'Hiểu PDF Rect để định vị liên kết' http://stackoverflow.com/question/3889634/fast-and-lean-pdf-viewer-cho-iphone-ipad-ios-tips-and-gợi ý –

Trả lời

14

heres ý tưởng cơ bản để truy cập vào các cụm từ CGPDFDictionary cho mỗi trang ít nhất. sau đó bạn sẽ có thể tìm ra nó với sự trợ giúp từ thông số PDF từ Adobe.

1.) lấy CGPDFDocumentRef.

2.) nhận mỗi trang.

3.) trên mỗi trang, sử dụng CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray) nơi pageDictionary là CGPDFDictionary đại diện cho CGPDFPage, và outputArray là biến (CGPDFArrayRef) để lưu trữ các mảng Annots của trang đó vào.

+0

@ Jesse Naugher: Cảm ơn rất nhiều câu trả lời của bạn, nhưng: "sau đó bạn sẽ có thể tìm ra với sự trợ giúp từ thông số PDF từ Adobe" Tôi không thể tìm thấy bất kỳ thông tin hữu ích nào từ đống lộn xộn đó là của Adobe Thông số PDF. Phần duy nhất của nó mà từ "chú thích" xuất hiện là phần 8, nhưng một lần nữa, tôi không thể thấy bất kỳ thông tin nào có thể giúp tôi ở đây ... * thất vọng * – pt2ph8

+1

có toàn bộ phần về mọi loại chú thích có thể trong tài liệu pdf, bao gồm chú thích liên kết. Về cơ bản, khi bạn nhận được Annotations Array, bạn lặp lại nó, và mỗi mục là một từ điển * là * một chú thích. Những từ điển này có một khóa gọi là 'Subtype' xác định loại chú thích, và "Link" là một trong số chúng, và được định nghĩa trong thông số pdf. –

+0

@ Jesse Naugher: Thật tuyệt vời, tôi vừa mới nhận ra mình đang nhìn chằm chằm vào tài liệu sai - bây giờ tôi có tài liệu đặc tả PDF ** thật **. Tôi sẽ kiểm tra nó bây giờ, cảm ơn (yeah, đó là những gì sẽ xảy ra khi bạn đang mệt mỏi/thất vọng). – pt2ph8

9

lớn mã nhưng tôi đang gặp khó một chút rắc rối khi làm việc trong dự án của tôi. Nó nhận được tất cả các URL chính xác nhưng khi tôi nhấp vào nó không có gì xảy ra. Đây là mã của tôi tôi đã phải sửa đổi của bạn một chút để làm việc với dự án của tôi). Có nội dung nào đó bị thiếu:

- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 
//CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index+1); 

CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index+1); 
CGAffineTransform transform1 = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox), 
             CGContextGetClipBoundingBox(ctx)); 
CGContextConcatCTM(ctx, transform1); 
CGContextDrawPDFPage(ctx, page); 

int pageCount = CGPDFDocumentGetNumberOfPages(pdf); 
int i = 0; 
while (i<pageCount) { 
    i++; 
    CGPDFPageRef page = CGPDFDocumentGetPage(pdf, i+1); 

    CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(page); 

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

    int arrayCount = CGPDFArrayGetCount(outputArray); 
    if(!arrayCount) { 
     continue; 
    } 

    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]); 

     CGPDFInteger pageRotate = 0; 
     CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &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 
     NSURL *url = [NSURL URLWithString:uri]; 
     NSLog(@"URL: %@", url); 
     CGPDFContextSetURLForRect(ctx, (CFURLRef)url, rect); 
     // CFRelease(url); 
     } 
    } 


} 

Cảm ơn & công việc tuyệt vời BrainFeeder!

UPDATE:

Đối với bất cứ ai sử dụng dự án lá trong ứng dụng của bạn này là làm thế nào tôi có các liên kết PDF để làm việc (nó không hoàn hảo như rect dường như lấp đầy toàn bộ màn hình nhưng đó là một sự khởi đầu):

- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 

CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index+1); 
CGAffineTransform transform1 = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox), 
             CGContextGetClipBoundingBox(ctx)); 
CGContextConcatCTM(ctx, transform1); 
CGContextDrawPDFPage(ctx, page); 


    CGPDFPageRef pageAd = CGPDFDocumentGetPage(pdf, index); 

    CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(pageAd); 

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

    int arrayCount = CGPDFArrayGetCount(outputArray); 
    if(!arrayCount) { 
     //continue; 
    } 

    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]); 

     CGPDFInteger pageRotate = 0; 
     CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &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 
      NSURL *url = [NSURL URLWithString:uri]; 
      NSLog(@"URL: %@", url); 
//   CGPDFContextSetURLForRect(ctx, (CFURLRef)url, rect); 
      UIButton *button = [[UIButton alloc] initWithFrame:rect]; 
      [button setTitle:@"LINK" forState:UIControlStateNormal]; 
      [button addTarget:self action:@selector(openLink:) forControlEvents:UIControlEventTouchUpInside]; 
      [self.view addSubview:button]; 
      // CFRelease(url); 
     } 
    //} 

Cập nhật cuối cùng Dưới đây là mã cuối cùng tôi đã sử dụng trong ứng dụng của mình.

- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 
//If the view already contains a button control remove it 
if ([[self.view subviews] containsObject:button]) { 
    [button removeFromSuperview]; 
} 

CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index+1); 
CGAffineTransform transform1 = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox), 
             CGContextGetClipBoundingBox(ctx)); 
CGContextConcatCTM(ctx, transform1); 
CGContextDrawPDFPage(ctx, page); 


CGPDFPageRef pageAd = CGPDFDocumentGetPage(pdf, index); 

CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(pageAd); 

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

int arrayCount = CGPDFArrayGetCount(outputArray); 
if(!arrayCount) { 
    //continue; 
} 

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]); 
    CGPDFInteger pageRotate = 0; 
    CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &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, 35, pageRect.size.height+150); 
    trans = CGAffineTransformScale(trans, 1.15, -1.15); 

    rect = CGRectApplyAffineTransform(rect, trans); 

    urlLink = [NSURL URLWithString:uri]; 
    [urlLink retain]; 

    //Create a button to get link actions 
    button = [[UIButton alloc] initWithFrame:rect]; 
    [button setBackgroundImage:[UIImage imageNamed:@"link_bg.png"] forState:UIControlStateHighlighted]; 
    [button addTarget:self action:@selector(openLink:) forControlEvents:UIControlEventTouchUpInside]; 
    [self.view addSubview:button]; 
} 
[leavesView reloadData]; 
} 

} 
+0

@ user470763: Vâng, thêm một nút là giải pháp rõ ràng nhất :) – pt2ph8

+0

@Brainfeeder Vấn đề duy nhất tôi thực sự có bây giờ là kích thước rect chỉ quy mô cho iPhone không iPad. Ngoài ra, trên các liên kết trang đầy đủ, tôi không thể vuốt để thay đổi trang. –

+0

@kmcg: Cảm ơn bạn đã viết mã, tôi cũng có thể mở rộng kích cỡ trực tuyến trong ipad, điều duy nhất bạn cần là thay đổi giá trị của x và y, có thể nó có thể giúp bạn. Cũng muốn hỏi xem bạn có thể tìm thấy bất kỳ từ nào từ tệp pdf không phải là URL.Thanks. – Sarah

0

tôi phải bối rối, bởi vì đây mọi công việc nếu tôi sử dụng:

CGRect rect = CGRectMake(coords[0],coords[1],coords[2]-coords[0]+1,coords[3]-coords[1]+1); 

Tôi lợi dụng một cái gì đó về sau, có lẽ?PDF cung cấp các góc, và CGRect muốn một góc và kích thước.

Các vấn đề liên quan