使用Quartz获取iOS上的PDF超链接

我花了整整一天的时间尝试在我的iPad应用程序中从PDF获取超链接元数据。 CGPDF * API是一个真正的噩梦,我在网上发现的唯一信息就是我必须查找一个“Annots”字典,但是我无法在我的PDF中find它。

我什至使用旧的偷窥Xcode示例来检查我的testingPDF文件,但没有这个“Annots”字典的痕迹…

你知道,这是我在每个PDF阅读器上看到的一个function – 同样的问题在这里被多次 询问 ,没有真正的实际答案。 我通常不会直接要求示例代码,但显然这次我真的需要它…任何人得到这个工作,可能与示例代码?

更新 :我刚刚意识到那个做我的testing的人PDF只是插入了一个URL作为文本,而不是一个真正的注释。 他试着把注释和我的代码现在工作…但这不是我所需要的,所以我似乎必须分析文本和searchURL。 但是这是另一个故事

更新2 :所以我终于想出了一些工作代码。 我在这里张贴,所以希望它会帮助别人。 它假定PDF文档实际上包含注释。

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. // eg you could create a button and put it on top of your page // and use it to open the URL with UIApplication's openURL } } 

inheritance人的基本思想,以获得每个页面至less每个页面的注释CGPDFDictionary。 之后,您应该能够从Adobe的PDF规范中获得帮助。

1.)获取CGPDFDocumentRef。

2.)获取每个页面。

3.)在每个页面上,使用CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray) outputArray CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray) ,其中pageDictionary是表示CGPDFPage的CGPDFDictionary,outputArray是存储该页面的Annots数组的variables(CGPDFArrayRef)。

伟大的代码,但我有一点麻烦,把它工作到我的项目。 它获得所有的URL正确,但是当我点击它没有任何反应。 这里是我的代码,我不得不稍微修改你的工作与我的项目)。 有什么缺失:

 - (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. // eg 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); } } } 

感谢和伟大的工作BrainFeeder!

更新:

对于任何人在你的应用程序中使用叶子项目,这是我得到的PDF链接工作(这并不完美,因为正义似乎填满整个屏幕,但这是一个开始):

 - (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. // eg 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); } //} 

最终更新以下是我在应用程序中使用的最终代码。

 - (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]; } } 

我一定很困惑,因为如果我使用这一切,

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

我以后会滥用什么吗? PDF提供angular落,CGRect想要一个angular落和一个大小。