Как получить аннотации PDF, когда я касаюсь на экране Ipad - PullRequest
5 голосов
/ 18 марта 2011

Я разработал приложение, которое отображает PDF на iPad с использованием CATiled Layer.Пока все хорошо, но есть проблема, которая действительно заставляет меня постричься.У меня есть PDF со встроенными аннотациями.Каждая аннотация имеет URL.Я могу найти координаты области касания, но вопрос в том, как мне узнать, есть ли под моим пальцем аннотация и как извлечь URL, чтобы открыть его в браузере?можно сделать, я буду очень признателен за вашу помощь!

Заранее спасибо

1 Ответ

7 голосов
/ 02 июля 2011

Получение аннотаций не очень сложно с 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));
}
} 
...