如何在iPad屏幕上触摸时获取PDF注释

2024-01-10

我开发了一个使用 CATiled Layer 在 ipad 上显示 PDF 的应用程序。到目前为止,一切都很好&但是有一个问题确实让我剪掉了最后的头发。我有一个带有嵌入注释的 PDF。每个注释都有一个 URL。我可以找到触摸区域的坐标,但问题是如何找到我的手指下是否有注释以及如何提取 URL 以在浏览器中打开它?

如果有人可以分享有关如何做到这一点的任何想法,我将非常感谢您的帮助!

提前致谢


使用 CGPDF 获取注释并不是很困难,尽管一开始对我来说需要一些摆弄。

//Get the current page ref 
CGPDFPageRef currentPdfPage = CGPDFDocumentGetPage(pdfDocumentRef, page);

//Get the page dictionary
CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(currentPdfPage);
CGPDFArrayRef annotsArray;

//Get the Annots array
if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &annotsArray)) {
    //DLog(@"No Annots found for page %d", page);
    [self updateProgress];
    return;
}

int annotsArrayCount = CGPDFArrayGetCount(annotsArray);
//DLog(@"%d annots found for page %d in file %@", annotsArrayCount, page, _fileName);
NSMutableArray* touchRectsArray = [[NSMutableArray alloc] initWithCapacity:annotsArrayCount];
for (int j=annotsArrayCount; j >= 0; j--) {
    int destPageNumber = 0;
    NSString* uri = nil;

    //DLog(@"%d/%d", j+1, annotsArrayCount);

    CGPDFObjectRef aDictObj;
    if(!CGPDFArrayGetObject(annotsArray, j, &aDictObj)) {
        //DLog(@"%@", @"can't get dictionary object");
        continue;
    }

    CGPDFDictionaryRef annotDict;
    if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &annotDict)) {
        //DLog(@"%@", @"can't get annotDict");
        continue;
    }

    //------------
    CGPDFDictionaryRef aDict;
    CGPDFArrayRef destArray;
    if(CGPDFDictionaryGetDictionary(annotDict, "A", &aDict)) {
        CGPDFStringRef uriStringRef;
        if(CGPDFDictionaryGetString(aDict, "URI", &uriStringRef)) {
            char* uriString = (char *)CGPDFStringGetBytePtr(uriStringRef);
            uri = [NSString stringWithCString:uriString encoding:NSUTF8StringEncoding];
        }
    } else {
        continue;
    }

这将为您提供 URL。 获取直方图:

CGPDFArrayRef rectArray;
    if(!CGPDFDictionaryGetArray(annotDict, "Rect", &rectArray)) {
        DLog(@"%@", @"can't get Rect");
    }

    int arrayCount = CGPDFArrayGetCount(rectArray);
    CGPDFReal coords[4];
    for (int k = 0; k < arrayCount; k++) {
        CGPDFObjectRef rectObj;
        if(!CGPDFArrayGetObject(rectArray, k, &rectObj)) {
            DLog(@"%@", @"can't get rect data");
        }

        CGPDFReal coord;
        if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &coord)) {
            DLog(@"%@", @"can't get coords");
        }

        coords[k] = coord;
    }

    CGRect drawRect = [[SharedConfig valueForKey:@"screenSize"] CGRectValue];
    BOOL drawBoxIsLandscape = NO;
    if (1 < drawRect.size.width/drawRect.size.height) {
        drawBoxIsLandscape = YES;
    }

    CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(currentPdfPage, kCGPDFMediaBox));
    landscape = NO;
    if (1 < pageRect.size.width/pageRect.size.height) {
        landscape = YES;
    }

    float ratio = 0.0;

    //Get the rect of the clickable area
    //CGRect coordsRect = CGRectMake(coords[0], coords[1], coords[2], coords[3]);
    //Transform to new coordinate system
    CGRect originalRect = CGRectMake(coords[0], (pageRect.size.height-(coords[3]-coords[1]))-coords[1], coords[2]-coords[0], coords[3]-coords[1]);

    CGPDFInteger pageRotate = 0;
    CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &pageRotate);

    if (pageRotate == 90 || pageRotate == 270) {
        CGFloat temp = pageRect.size.width;
        pageRect.size.width = pageRect.size.height;
        pageRect.size.height = temp;
        ratio = drawRect.size.height / pageRect.size.height;
    }       

    if (drawBoxIsLandscape) {
        ratio = landscape ? (drawRect.size.height/pageRect.size.height) : (drawRect.size.height/pageRect.size.width);

        if (landscape && drawRect.size.width < pageRect.size.width*ratio) {
            ratio = drawRect.size.width/pageRect.size.width;
        } else if (!landscape && drawRect.size.height < pageRect.size.width*ratio) {
            ratio = drawRect.size.height/pageRect.size.width;
        }
    } else {
        ratio = landscape ? (drawRect.size.height/pageRect.size.width) : (drawRect.size.height/pageRect.size.height);

        if (landscape && drawRect.size.width < pageRect.size.height*ratio) {
            ratio = drawRect.size.width/pageRect.size.height;
        } else if (!landscape && drawRect.size.height < pageRect.size.height*ratio) {
            ratio = drawRect.size.height/pageRect.size.height;
        }
    }

    CGRect calculatedRect = CGRectMake(originalRect.origin.x*ratio, originalRect.origin.y*ratio, originalRect.size.width*ratio, originalRect.size.height*ratio);

    if ((landscape && !drawBoxIsLandscape) || (!landscape && drawBoxIsLandscape)) {
        CGFloat width = calculatedRect.size.width;
        calculatedRect.size.width = calculatedRect.size.height;
        calculatedRect.size.height = width;

        CGFloat yModifier = drawRect.size.height-(pageRect.size.width*ratio);

        CGFloat x = calculatedRect.origin.x;
        calculatedRect.origin.x = calculatedRect.origin.y;
        calculatedRect.origin.y = drawRect.size.height-(x+calculatedRect.size.height)-yModifier;

    }

    if (nil != uri) {
        [touchRectsArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithCGRect:calculatedRect], @"rect", uri, @"targetUrl", nil]];
    }

正如您所看到的,这段代码首先获取注释的矩形,将其转换为设备坐标系,然后根据页面与屏幕的比例、旋转系数等进行一些重新计算、调整大小和重新定位。最后您将具有该页面的触摸活动区域数组。为了处理触摸,可以使用以下简单的解决方案:

- (void) tapGesture:(UIGestureRecognizer*)sender
{
if (UIGestureRecognizerStateEnded == sender.state) {
    CGPoint touchPoint = [sender locationInView:self.view];

    if (nil != self.touchRects) for (int i=0; i<[self.touchRects count]; i++) {
        if (CGRectContainsPoint([[[self.touchRects objectAtIndex:i] objectForKey:@"rect"] CGRectValue], touchPoint)) {
            if ([[self.touchRects objectAtIndex:i] objectForKey:@"targetUrl"]) {
                NSString* targetUrl = [[self.touchRects objectAtIndex:i] objectForKey:@"targetUrl"];
                DLog(@"Hit found for target url: %@", targetUrl);
                NSURL* url = [NSURL URLWithString:targetUrl];
                [[UIApplication sharedApplication] openURL:url];
            }               return;
        }       
    }
    DLog(@"No hit found for touch at %@", NSStringFromCGPoint(touchPoint));
}
} 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在iPad屏幕上触摸时获取PDF注释 的相关文章

随机推荐

  • PayPal mc_gross 格式号码?

    我正在编写 php iPN 脚本 但我被 mc gross 检查困住了 我以这种格式 不是数字格式 将金额存储在数据库中 1000 100 10000 paypal 如何将 mc gross 值发回给我 以数字格式 我的意思是这样的 1 0
  • IE 11 中的 Bootstrap 4 对齐

    我正在将我的网站之一从 AngularJs Bootstrap 3 转换为 Angular 6 Bootstrap 在 Chrome 和 Firefox 以及 edige 中 我的模式如下所示 然而 在IE11中 代码 div class
  • 为什么C++中找不到向量

    还有什么选择 我应该自己写吗 有的是std find 算法 它在迭代器范围内执行线性搜索 例如 std vector
  • 设置 JFree Chart 图例边框颜色

    问题已在标题中阐述 细节 我在类主题中有代码 用于为图例框架的边框设置特定的非默认颜色 LegendTitle legend jFreeChart getLegend legend setWidth 100 之后我需要设置图例边框的颜色 但
  • PHP 是否有“命名参数”,以便可以省略前面的参数并可以写入后面的参数? [复制]

    这个问题在这里已经有答案了 在 PHP 中 您可以调用不传入任何参数的函数 只要参数具有如下所示的默认值 function test t1 test1 t2 test2 t3 test3 echo t1 t2 t3 test 但是 假设我希
  • SOAP 方法参数中的数组通过 JAX-WS 生成?

    我正在使用 JAX WS 注释用 Java 构建 SOAP 服务 除此之外 我想知道如何在我的方法中注释数组参数 当我从带注释的接口生成 wsdl 然后再次从该 wsdl 生成 java 类时 我这样做是为了测试 在这两种情况下都使用 Ap
  • 使用 D3.min 查找非 0 的最小值

    我正在尝试使用 D3 来查找数据集中的最低值 但是 我也有 0 的值 但我希望 D3 找到非 0 的最小值 目前我正在使用 d3 min data function d return d houseValues 但显然 当找到 0 时 有时
  • 每次安装组件时,React hook useEffect 都会导致初始渲染

    我是 React hooks 的新手 所以 我想用 React hooks 实现 componentWillReceiveProps 我像这样使用 React useEffect React useEffect gt console log
  • 漂亮的打印 XML 文件

    原始问题 我正在尝试在没有任何外部库的情况下漂亮地打印 XML 文件 但无法让 Java 执行我想要的操作 这是到目前为止我的代码 我添加了类似问题的任何解决方案 TransformerFactory tfactory Transforme
  • 如何使用 SMTP 发送附件?

    我想编写一个使用Python发送电子邮件的程序smtplib http docs python org library smtplib html 我搜索了文档和 RFC 但找不到任何与附件相关的内容 因此 我确信我错过了一些更高层次的概念
  • 更改 iOS 7 中 UIToolbar 的高度

    我试图在新的 iOS 7 项目中更改 UIToolbar 的高度 但我无法做到 我正在使用 UINavigationController 来管理几个 UIViewController 我尝试通过导航控制器设置工具栏的框架 但遗憾的是 工具栏
  • 如何使用 Selenium Java 2.8 获取当前 DOM?

    我正在使用最新版本的 Selenium 和chromedriver测试 ZK 应用程序 在测试期间 我想转储 DOM 或其中的一部分 以帮助我找到所需的元素 并且可能帮助必须维护测试的人 方法WebDriver getPageSource
  • 查找适用于某个元素的所有 CSS 规则

    许多工具 API 提供了选择特定类或ID 的元素的方法 还可以检查浏览器加载的原始样式表 但是 为了让浏览器呈现元素 它们将编译所有 CSS 规则 可能来自不同的样式表文件 并将其应用到该元素 这就是您在 Firebug 或 WebKit
  • 使用 angular-ui-grid 预选加载行

    我想在页面加载时选择某些行 工作日 这是笨蛋plnkr co edit 48NyxngWNGIlOps1Arew p preview 有什么建议吗 将以下属性添加到您的 scope gridOptions目的 onRegisterApi f
  • 我什么时候应该将 Angular2 App 与 SystemJS 方法相反?

    我什么时候应该连接我的 Angular2 应用程序 什么时候应该保留 SystemJS 原始方法 将不同的模块保留在不同的文件中 主要取决于浏览器的支持 HTTP2 之前的旧方法是将所有内容捆绑到一个大文件中 现在我们已经有了 http2
  • 承诺履行处理程序未定义

    看起来非常基本 基于 Promise 的实现的实现没有返回我期望看到的值 数据 这就是我期望这个界面的工作方式 sdk request options gt Promise Response Object JSON 这是我的模型中的代码 r
  • 将 SDK 工具和 ADT 更新至 17,现在出现VerifyErrors

    我有一个引用两个图书馆项目的项目 升级ADT和SDK工具后版本17 http android developers blogspot com 2012 03 updated sdk tools and adt revision 17 htm
  • gnuplot:在交互模式下设置 link 和 x2tics

    在交互模式下 x2tics 在放大时很快就会消失 这个例子被展示了here https stackoverflow com a 60373156 11769765 set tics nomirror set x2tics set link
  • 双问号,它是如何工作的?

    我正在学习 Swift 作为这个过程的一部分 我试图弄清楚这里到底发生了什么 我有一个自定义 Segue 我想在其中放置模态视图控制器以消除转换 Objective c 中以前的内容是 UIViewController sourceView
  • 如何在iPad屏幕上触摸时获取PDF注释

    我开发了一个使用 CATiled Layer 在 ipad 上显示 PDF 的应用程序 到目前为止 一切都很好 但是有一个问题确实让我剪掉了最后的头发 我有一个带有嵌入注释的 PDF 每个注释都有一个 URL 我可以找到触摸区域的坐标 但问