// // PDFListView.m // PDFReader // // Copyright © 2014-2022 PDF Technologies, Inc. All Rights Reserved. // // The PDF Reader Sample applications are licensed with a modified BSD license. // Please see License for details. This notice may not be removed from this file. // #import "PDFListView.h" #import #import "PDFMagnifierView.h" typedef NS_ENUM(NSInteger, PDFAnnotationDraggingType) { PDFAnnotationDraggingNone = 0, PDFAnnotationDraggingCenter, PDFAnnotationDraggingTopLeft, PDFAnnotationDraggingTopRight, PDFAnnotationDraggingBottomLeft, PDFAnnotationDraggingBottomRight, PDFAnnotationDraggingStart, PDFAnnotationDraggingEnd }; @interface PDFListView () @property (nonatomic,assign) PDFAnnotationDraggingType draggingType; @property (nonatomic,assign) CGPoint draggingPoint; @property (nonatomic,assign) CGRect topLeftRect; @property (nonatomic,assign) CGRect bottomLeftRect; @property (nonatomic,assign) CGRect topRightRect; @property (nonatomic,assign) CGRect bottomRightRect; @property (nonatomic,assign) CGRect startPointRect; @property (nonatomic,assign) CGRect endPointRect; @property (nonatomic,assign) CGPoint addLinkPoint; @property (nonatomic,assign) CGRect addLinkRect; @property (nonatomic,retain) CPDFAnnotation *menuAnnotation; @property (nonatomic,assign) CGPoint menuPoint; @property (nonatomic,assign) CPDFPage *menuPage; @property (nonatomic,retain) PDFMagnifierView *magnifierView; @end @implementation PDFListView #pragma mark - Initializers - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { } return self; } - (void)dealloc { [_magnifierView release]; [_activeAnnotation release]; [_menuAnnotation release]; [_addAnnotation release]; [super dealloc]; } #pragma mark - Accessors - (void)setAnnotationMode:(PDFViewAnnotationMode)annotationMode { _annotationMode = annotationMode; if (PDFViewAnnotationModeHighlight == annotationMode || PDFViewAnnotationModeUnderline == annotationMode || PDFViewAnnotationModeStrikeout == annotationMode || PDFViewAnnotationModeSquiggly == annotationMode) { self.textSelectionMode = YES; } else { self.textSelectionMode = NO; } if (PDFViewAnnotationModeLink == annotationMode) { self.scrollEnabled = NO; [self endDrawing]; } else if (PDFViewAnnotationModeInk == annotationMode) { self.scrollEnabled = NO; [self beginDrawing]; } else { if (self.activeAnnotation) { self.scrollEnabled = NO; } else { self.scrollEnabled = YES; } [self endDrawing]; [self becomeFirstResponder]; } // 取消注释选中状态 if (PDFViewAnnotationModeNone != annotationMode) { CPDFPage *page = self.activeAnnotation.page; self.activeAnnotation = nil; [self setNeedsDisplayForPage:page]; } } - (void)updateScrollEnabled { if (self.activeAnnotation) { self.scrollEnabled = NO; } else { if (PDFViewAnnotationModeLink == self.annotationMode) { self.scrollEnabled = NO; } else { self.scrollEnabled = YES; } } } - (NSString *)annotationUserName { NSString *annotationUserName = CPDFKitShareConfig.annotationAuthor; if (!annotationUserName || [annotationUserName length] <= 0) { annotationUserName = [[UIDevice currentDevice] name]; } return annotationUserName ? : @""; } - (UIImage *)compressImage:(UIImage *)image size:(CGSize)size { CGFloat imageScale = 1.0; if (image.size.width > size.width || image.size.height > size.height) { imageScale = MIN(size.width / image.size.width, size.height / image.size.height); } CGSize newSize = CGSizeMake(image.size.width * imageScale, image.size.height * imageScale); UIGraphicsBeginImageContext(newSize); [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } - (void)goToPageIndex:(NSInteger)pageIndex animated:(BOOL)animated { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformWillGoTo:pageIndex:)]) { [self.performDelegate PDFViewPerformWillGoTo:self pageIndex:pageIndex]; } [super goToPageIndex:pageIndex animated:animated]; } #pragma mark - Magnifier - (void)addMagnifierAtPoint:(CGPoint)point forPage:(CPDFPage *)page { if (!_magnifierView) { _magnifierView = [[PDFMagnifierView alloc] init]; _magnifierView.style = PDFMagnifierViewStyleCircle; } point = [self convertPoint:point fromPage:page]; CGPoint center = [self convertPoint:point toView:self.superview]; self.magnifierView.scale = 1.0; self.magnifierView.pointToMagnify = point; self.magnifierView.viewToMagnify = self; self.magnifierView.center = CGPointMake(center.x, center.y - self.magnifierView.frame.size.height/2.0 - 20); if ([self.magnifierView superview]) { [self.magnifierView setNeedsDisplay]; } else { [self.superview addSubview:self.magnifierView]; } } - (void)removeMagnifier { [self.magnifierView removeFromSuperview]; self.magnifierView = nil; } #pragma mark - Rendering - (void)drawPage:(CPDFPage *)page toContext:(CGContextRef)context { if (PDFViewAnnotationModeLink == self.annotationMode) { CGContextSetLineWidth(context, 1.0); CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:255.0/255.f green:255.0/255.f blue:255.0/255.f alpha:0.8].CGColor); CGContextSetFillColorWithColor(context, [UIColor colorWithRed:100.0/255.f green:149.0/255.f blue:237.0/255.f alpha:0.4].CGColor); CGContextAddRect(context, self.addLinkRect); CGContextDrawPath(context, kCGPathFillStroke); } if (self.activeAnnotation.page != page) { return; } CGSize dragDotSize = CGSizeMake(30, 30); CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:72.0/255.0 green:183.0/255.0 blue:247.0/255.0 alpha:1.0].CGColor); if ([self.activeAnnotation isKindOfClass:[CPDFLineAnnotation class]]) { CPDFLineAnnotation *line = (CPDFLineAnnotation *)self.activeAnnotation; CGPoint startPoint = line.startPoint; CGPoint endPoint = line.endPoint; CGPoint tStartPoint = startPoint; CGPoint tEndPoint = endPoint; float final = 40; if (fabs(tStartPoint.x - tEndPoint.x) < 0.00001) { if (tStartPoint.y > tEndPoint.y) { tStartPoint.y += final; tEndPoint.y -= final; } else { tStartPoint.y -= final; tEndPoint.y += final; } } else if (fabs(tStartPoint.y - tEndPoint.y) < 0.00001) { if (tStartPoint.x > tEndPoint.x) { tStartPoint.x += final; tEndPoint.x -= final; } else { tStartPoint.x -= final; tEndPoint.x += final; } } else { double k = (tEndPoint.y - tStartPoint.y)/(tEndPoint.x - tStartPoint.x); double atank = atan(k); if (endPoint.x > startPoint.x) { tEndPoint.x += cos(atank) * final; tEndPoint.y += sin(atank) * final; tStartPoint.x -= cos(atank) * final; tStartPoint.y -= sin(atank) * final; } else { tEndPoint.x -= cos(atank) * final; tEndPoint.y -= sin(atank) * final; tStartPoint.x += cos(atank) * final; tStartPoint.y += sin(atank) * final; } } CGContextSetLineWidth(context, 1.0); CGFloat dashArray[] = {3,3}; CGContextSetLineDash(context, 0, dashArray, 2); CGContextMoveToPoint(context, tStartPoint.x, tStartPoint.y); CGContextAddLineToPoint(context, startPoint.x, startPoint.y); CGContextStrokePath(context); CGContextMoveToPoint(context, tEndPoint.x, tEndPoint.y); CGContextAddLineToPoint(context, endPoint.x, endPoint.y); CGContextStrokePath(context); CGRect startPointRect = CGRectMake(tStartPoint.x - dragDotSize.width/2.0, tStartPoint.y - dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); CGRect endPointRect = CGRectMake(tEndPoint.x - dragDotSize.width/2.0, tEndPoint.y - dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); UIImage *image = [UIImage imageNamed:@"annotation_drag_dot.png" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil]; CGImageRef dragDotImage = image.CGImage; CGContextDrawImage(context, startPointRect, dragDotImage); CGContextDrawImage(context, endPointRect, dragDotImage); self.startPointRect = startPointRect; self.endPointRect = endPointRect; } else if ([self.activeAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]]) { CGRect rect = CGRectInset(self.activeAnnotation.bounds, -dragDotSize.width/2.0, -dragDotSize.height/2.0); CGContextSetLineWidth(context, 1.0); CGFloat lengths[] = {6, 6}; CGContextSetLineDash(context, 0, lengths, 2); CGContextStrokeRect(context, rect); CGContextStrokePath(context); CGAffineTransform transform = [page transform]; if (CPDFKitShareConfig.enableAnnotationNoRotate) { rect = CGRectApplyAffineTransform(rect, transform); } CGRect leftCenterRect = CGRectMake(CGRectGetMinX(rect)-dragDotSize.width/2.0, CGRectGetMidY(rect)-dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); CGRect rightCenterRect = CGRectMake(CGRectGetMaxX(rect)-dragDotSize.width/2.0, CGRectGetMidY(rect)-dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); if (CPDFKitShareConfig.enableAnnotationNoRotate) { leftCenterRect = CGRectApplyAffineTransform(leftCenterRect, CGAffineTransformInvert(transform)); rightCenterRect = CGRectApplyAffineTransform(rightCenterRect, CGAffineTransformInvert(transform)); } UIImage *image = [UIImage imageNamed:@"annotation_drag_dot.png" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil]; CGImageRef dragDotImage = image.CGImage; CGContextDrawImage(context, leftCenterRect, dragDotImage); CGContextDrawImage(context, rightCenterRect, dragDotImage); self.startPointRect = leftCenterRect; self.endPointRect = rightCenterRect; } else { CGRect rect = CGRectInset(self.activeAnnotation.bounds, -dragDotSize.width/2.0, -dragDotSize.height/2.0); CGContextSetLineWidth(context, 1.0); CGFloat lengths[] = {6, 6}; CGContextSetLineDash(context, 0, lengths, 2); CGContextStrokeRect(context, rect); CGContextStrokePath(context); if ([self.activeAnnotation isKindOfClass:[CPDFSoundAnnotation class]] || [self.activeAnnotation isKindOfClass:[CPDFMovieAnnotation class]]) { return; } CGRect topLeftRect = CGRectMake(CGRectGetMinX(rect)-dragDotSize.width/2.0, CGRectGetMaxY(rect)-dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); CGRect bottomLeftRect = CGRectMake(CGRectGetMinX(rect)-dragDotSize.width/2.0, CGRectGetMinY(rect)-dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); CGRect topRightRect = CGRectMake(CGRectGetMaxX(rect)-dragDotSize.width/2.0, CGRectGetMaxY(rect)-dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); CGRect bottomRightRect = CGRectMake(CGRectGetMaxX(rect)-dragDotSize.width/2.0, CGRectGetMinY(rect)-dragDotSize.height/2.0, dragDotSize.width, dragDotSize.height); UIImage *image = [UIImage imageNamed:@"annotation_drag_dot.png" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil]; CGImageRef dragDotImage = image.CGImage; CGContextDrawImage(context, topLeftRect, dragDotImage); CGContextDrawImage(context, bottomLeftRect, dragDotImage); CGContextDrawImage(context, topRightRect, dragDotImage); CGContextDrawImage(context, bottomRightRect, dragDotImage); self.topLeftRect = topLeftRect; self.bottomLeftRect = bottomLeftRect; self.topRightRect = topRightRect; self.bottomRightRect = bottomRightRect; } } #pragma mark - Touch - (void)touchBeganAtPoint:(CGPoint)point forPage:(CPDFPage *)page { if (self.textSelectionMode) { // 文本选取模式 } else { self.addLinkPoint = point; self.addLinkRect = CGRectZero; self.draggingType = PDFAnnotationDraggingNone; if (!self.activeAnnotation || self.activeAnnotation.page != page) { return; } CGRect topLeftRect = CGRectInset(self.topLeftRect, -5, -5); CGRect bottomLeftRect = CGRectInset(self.bottomLeftRect, -5, -5); CGRect topRightRect = CGRectInset(self.topRightRect, -5, -5); CGRect bottomRightRect = CGRectInset(self.bottomRightRect, -5, -5); CGRect startPointRect = CGRectInset(self.startPointRect, -5, -5); CGRect endPointRect = CGRectInset(self.endPointRect, -5, -5); if (CGRectContainsPoint(topLeftRect, point)) { self.draggingType = PDFAnnotationDraggingTopLeft; } else if (CGRectContainsPoint(bottomLeftRect, point)) { self.draggingType = PDFAnnotationDraggingBottomLeft; } else if (CGRectContainsPoint(topRightRect, point)) { self.draggingType = PDFAnnotationDraggingTopRight; } else if (CGRectContainsPoint(bottomRightRect, point)) { self.draggingType = PDFAnnotationDraggingBottomRight; } else if (CGRectContainsPoint(startPointRect, point)) { self.draggingType = PDFAnnotationDraggingStart; } else if (CGRectContainsPoint(endPointRect, point)) { self.draggingType = PDFAnnotationDraggingEnd; } else if ([page annotation:self.activeAnnotation atPoint:point]) { self.draggingType = PDFAnnotationDraggingCenter; } self.draggingPoint = point; if (PDFAnnotationDraggingCenter == self.draggingType) { if ([self.activeAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]] || [self.activeAnnotation isKindOfClass:[CPDFSignatureAnnotation class]]) { [self addMagnifierAtPoint:point forPage:page]; } } } } - (void)touchMovedAtPoint:(CGPoint)point forPage:(CPDFPage *)page { if (self.textSelectionMode) { // 文本选取模式 } else if (PDFAnnotationDraggingNone != self.draggingType) { [self moveAnnotation:self.activeAnnotation fromPoint:self.draggingPoint toPoint:point forType:self.draggingType]; [self setNeedsDisplayForPage:page]; self.draggingPoint = point; if (PDFAnnotationDraggingCenter == self.draggingType) { if ([self.activeAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]] || [self.activeAnnotation isKindOfClass:[CPDFSignatureAnnotation class]]) { [self addMagnifierAtPoint:point forPage:page]; } } } else if (PDFViewAnnotationModeLink == self.annotationMode) { CGRect rect = CGRectZero; if (point.x > self.addLinkPoint.x) { rect.origin.x = self.addLinkPoint.x; rect.size.width = point.x-self.addLinkPoint.x; } else { rect.origin.x = point.x; rect.size.width = self.addLinkPoint.x-point.x; } if (point.y > self.addLinkPoint.y) { rect.origin.y = self.addLinkPoint.y; rect.size.height = point.y-self.addLinkPoint.y; } else { rect.origin.y = point.y; rect.size.height = self.addLinkPoint.y-point.y; } self.addLinkRect = rect; [self setNeedsDisplayForPage:page]; } } - (void)touchEndedAtPoint:(CGPoint)point forPage:(CPDFPage *)page { if (self.textSelectionMode) { // 文本选取模式,添加Markup注释 if (self.currentSelection) { [self addAnnotation:self.annotationMode atPoint:point forPage:page]; } else { CPDFAnnotation *annotation = [page annotationAtPoint:point]; if ([annotation isKindOfClass:[CPDFMarkupAnnotation class]]) { [self showMenuForAnnotation:annotation]; } } } else if (PDFAnnotationDraggingNone == self.draggingType) { if (self.activeAnnotation) { CPDFPage *previousPage = self.activeAnnotation.page; self.activeAnnotation = nil; [self setNeedsDisplayForPage:previousPage]; [self updateScrollEnabled]; } else { if (PDFViewAnnotationModeNone == self.annotationMode) { CPDFAnnotation *annotation = [page annotationAtPoint:point]; if ([annotation isKindOfClass:[CPDFTextAnnotation class]]) { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformOpenNote:forAnnotation:)]) { [self.performDelegate PDFViewPerformOpenNote:self forAnnotation:annotation]; } } else if ([annotation isKindOfClass:[CPDFMarkupAnnotation class]]) { if (CGRectContainsPoint(annotation.bounds, point)) { [self showMenuForAnnotation:annotation]; } else { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformPopup:forAnnotation:)]) { [self.performDelegate PDFViewPerformPopup:self forAnnotation:(CPDFMarkupAnnotation *)annotation]; } } } else if ([annotation isKindOfClass:[CPDFLinkAnnotation class]]) { [super touchEndedAtPoint:point forPage:page]; } else if ([annotation isKindOfClass:[CPDFMovieAnnotation class]]) { [super touchEndedAtPoint:point forPage:page]; } else if ([annotation isKindOfClass:[CPDFWidgetAnnotation class]]) { if ([annotation isKindOfClass:[CPDFSignatureWidgetAnnotation class]]) { if ([(CPDFSignatureWidgetAnnotation *)annotation isSigned]) { [self showMenuForAnnotation:annotation]; } else { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformSignatureWidget:forAnnotation:)]) { [self.performDelegate PDFViewPerformSignatureWidget:self forAnnotation:(CPDFSignatureWidgetAnnotation *)annotation]; } } } else { [super touchEndedAtPoint:point forPage:page]; } } else { self.activeAnnotation = annotation; [self setNeedsDisplayForPage:page]; [self updateScrollEnabled]; [self showMenuForAnnotation:annotation]; if (!self.activeAnnotation) { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformTouchEnded:)]) { [self.performDelegate PDFViewPerformTouchEnded:self]; } } } } else if (PDFViewAnnotationModeLink == self.annotationMode) { if (CGRectIsEmpty(self.addLinkRect)) { CPDFAnnotation *annotation = [page annotationAtPoint:point]; if ([annotation isKindOfClass:[CPDFLinkAnnotation class]]) { self.activeAnnotation = annotation; [self setNeedsDisplayForPage:page]; [self updateScrollEnabled]; [self showMenuForAnnotation:annotation]; } } else { [self addAnnotationLinkAtPoint:point forPage:page]; } } else if (PDFViewAnnotationModeFreeText == self.annotationMode) { [self addAnnotationFreeTextAtPoint:point forPage:page]; } else if (PDFViewAnnotationModeStamp == self.annotationMode) { [self addAnnotationAtPoint:point forPage:page]; if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformTouchEnded:)]) { [self.performDelegate PDFViewPerformTouchEnded:self]; } } else if (PDFViewAnnotationModeImage == self.annotationMode) { [self addAnnotationAtPoint:point forPage:page]; if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformTouchEnded:)]) { [self.performDelegate PDFViewPerformTouchEnded:self]; } } else { [self addAnnotation:self.annotationMode atPoint:point forPage:page]; } } } else { // 注释修改大小后,重新生成外观 if (PDFAnnotationDraggingCenter != self.draggingType) { if ([self.activeAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]] || [self.activeAnnotation isKindOfClass:[CPDFStampAnnotation class]] || [self.activeAnnotation isKindOfClass:[CPDFSignatureAnnotation class]]) { [self.activeAnnotation updateAppearanceStream]; [self setNeedsDisplayForPage:page]; } } self.draggingType = PDFAnnotationDraggingNone; [self showMenuForAnnotation:self.activeAnnotation]; } [self removeMagnifier]; } - (void)touchCancelledAtPoint:(CGPoint)point forPage:(CPDFPage *)page { self.draggingType = PDFAnnotationDraggingNone; [self removeMagnifier]; } #pragma mark - Annotation - (void)moveAnnotation:(CPDFAnnotation *)annotation fromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint forType:(PDFAnnotationDraggingType)draggingType { CGRect bounds = annotation.bounds; CGPoint offsetPoint = CGPointMake(toPoint.x - fromPoint.x, toPoint.y - fromPoint.y); CGFloat scale = bounds.size.height/bounds.size.width; if ([annotation isKindOfClass:[CPDFLineAnnotation class]]) { CPDFLineAnnotation *line = (CPDFLineAnnotation *)annotation; CGPoint startPoint = line.startPoint; CGPoint endPoint = line.endPoint; switch (draggingType) { case PDFAnnotationDraggingCenter: { startPoint.x += offsetPoint.x; startPoint.y += offsetPoint.y; endPoint.x += offsetPoint.x; endPoint.y += offsetPoint.y; } break; case PDFAnnotationDraggingStart: { startPoint.x += offsetPoint.x; startPoint.y += offsetPoint.y; } break; case PDFAnnotationDraggingEnd: { endPoint.x += offsetPoint.x; endPoint.y += offsetPoint.y; } break; default: break; } line.startPoint = startPoint; line.endPoint = endPoint; bounds = line.bounds; } else if ([annotation isKindOfClass:[CPDFFreeTextAnnotation class]]) { CGAffineTransform transform = [annotation.page transform]; if (CPDFKitShareConfig.enableAnnotationNoRotate) { bounds = CGRectApplyAffineTransform(bounds, transform); toPoint = CGPointApplyAffineTransform(toPoint, transform); fromPoint = CGPointApplyAffineTransform(fromPoint, transform); offsetPoint = CGPointMake(toPoint.x - fromPoint.x, toPoint.y - fromPoint.y); } CPDFFreeTextAnnotation *freeText = (CPDFFreeTextAnnotation *)annotation; NSDictionary *attributes = @{NSFontAttributeName : freeText.font}; switch (draggingType) { case PDFAnnotationDraggingCenter: { bounds.origin.x += offsetPoint.x; bounds.origin.y += offsetPoint.y; } break; case PDFAnnotationDraggingStart: { CGFloat x = CGRectGetMaxX(bounds); bounds.size.width -= offsetPoint.x; bounds.size.width = MAX(bounds.size.width, 5.0); bounds.origin.x = x - bounds.size.width; CGRect rect = [freeText.contents boundingRectWithSize:CGSizeMake(bounds.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; bounds.origin.y = CGRectGetMaxY(bounds) - rect.size.height; bounds.size.height = rect.size.height; } break; case PDFAnnotationDraggingEnd: { bounds.size.width += offsetPoint.x; bounds.size.width = MAX(bounds.size.width, 5.0); CGRect rect = [freeText.contents boundingRectWithSize:CGSizeMake(bounds.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; bounds.origin.y = CGRectGetMaxY(bounds) - rect.size.height; bounds.size.height = rect.size.height; } break; default: break; } if (CPDFKitShareConfig.enableAnnotationNoRotate) { bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(transform)); } } else { switch (draggingType) { case PDFAnnotationDraggingCenter: { bounds.origin.x += offsetPoint.x; bounds.origin.y += offsetPoint.y; } break; case PDFAnnotationDraggingTopLeft: { CGFloat x = CGRectGetMaxX(bounds); bounds.size.width -= offsetPoint.x; bounds.size.height += offsetPoint.y; if ([annotation isKindOfClass:[CPDFStampAnnotation class]] || [annotation isKindOfClass:[CPDFSignatureAnnotation class]] || [annotation isKindOfClass:[CPDFInkAnnotation class]]) { bounds.size.height = bounds.size.width*scale; bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0*scale); } else { bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0); } bounds.origin.x = x - bounds.size.width; } break; case PDFAnnotationDraggingBottomLeft: { CGFloat x = CGRectGetMaxX(bounds); CGFloat y = CGRectGetMaxY(bounds); bounds.size.width -= offsetPoint.x; bounds.size.height -= offsetPoint.y; if ([annotation isKindOfClass:[CPDFStampAnnotation class]] || [annotation isKindOfClass:[CPDFSignatureAnnotation class]] || [annotation isKindOfClass:[CPDFInkAnnotation class]]) { bounds.size.height = bounds.size.width*scale; bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0*scale); } else { bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0); } bounds.origin.x = x - bounds.size.width; bounds.origin.y = y - bounds.size.height; } break; case PDFAnnotationDraggingTopRight: { bounds.size.width += offsetPoint.x; bounds.size.height += offsetPoint.y; if ([annotation isKindOfClass:[CPDFStampAnnotation class]] || [annotation isKindOfClass:[CPDFSignatureAnnotation class]] || [annotation isKindOfClass:[CPDFInkAnnotation class]]) { bounds.size.height = bounds.size.width*scale; bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0*scale); } else { bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0); } } break; case PDFAnnotationDraggingBottomRight: { CGFloat y = CGRectGetMaxY(bounds); bounds.size.width += offsetPoint.x; bounds.size.height -= offsetPoint.y; if ([annotation isKindOfClass:[CPDFStampAnnotation class]] || [annotation isKindOfClass:[CPDFSignatureAnnotation class]] || [annotation isKindOfClass:[CPDFInkAnnotation class]]) { bounds.size.height = bounds.size.width*scale; bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0*scale); } else { bounds.size.width = MAX(bounds.size.width, 5.0); bounds.size.height = MAX(bounds.size.height, 5.0); } bounds.origin.y = y - bounds.size.height; } break; default: break; } if (CGRectGetMinX(bounds) < 0) { bounds.origin.x = 0; } if (CGRectGetMaxX(bounds) > CGRectGetWidth(annotation.page.bounds)) { bounds.origin.x = CGRectGetWidth(annotation.page.bounds) - CGRectGetWidth(bounds); } if (CGRectGetMinY(bounds) < 0) { bounds.origin.y = 0; } if (CGRectGetMaxY(bounds) > CGRectGetHeight(annotation.page.bounds)) { bounds.origin.y = CGRectGetHeight(annotation.page.bounds) - CGRectGetHeight(bounds); } } annotation.bounds = bounds; } - (void)addAnnotation:(PDFViewAnnotationMode)mode atPoint:(CGPoint)point forPage:(CPDFPage *)page { CPDFAnnotation *annotation = nil; switch (mode) { case PDFViewAnnotationModeNote: { CGFloat width = 57.0/1.5; annotation = [[[CPDFTextAnnotation alloc] initWithDocument:self.document] autorelease]; annotation.bounds = CGRectMake(point.x-width/2.0, point.y-width/2.0, width, width); } break; case PDFViewAnnotationModeHighlight: { if (!self.currentSelection) { return; } NSMutableArray *quadrilateralPoints = [NSMutableArray array]; annotation = [[[CPDFMarkupAnnotation alloc] initWithDocument:self.document markupType:CPDFMarkupTypeHighlight] autorelease]; for (CPDFSelection *selection in self.currentSelection.selectionsByLine) { CGRect bounds = selection.bounds; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMinY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMinY(bounds))]]; } [(CPDFMarkupAnnotation *)annotation setQuadrilateralPoints:quadrilateralPoints]; [(CPDFMarkupAnnotation *)annotation setMarkupText:self.currentSelection.string]; [self clearSelection]; } break; case PDFViewAnnotationModeUnderline: { if (!self.currentSelection) { return; } NSMutableArray *quadrilateralPoints = [NSMutableArray array]; annotation = [[[CPDFMarkupAnnotation alloc] initWithDocument:self.document markupType:CPDFMarkupTypeUnderline] autorelease]; for (CPDFSelection *selection in self.currentSelection.selectionsByLine) { CGRect bounds = selection.bounds; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMinY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMinY(bounds))]]; } [(CPDFMarkupAnnotation *)annotation setQuadrilateralPoints:quadrilateralPoints]; [(CPDFMarkupAnnotation *)annotation setMarkupText:self.currentSelection.string]; [self clearSelection]; } break; case PDFViewAnnotationModeStrikeout: { if (!self.currentSelection) { return; } NSMutableArray *quadrilateralPoints = [NSMutableArray array]; annotation = [[[CPDFMarkupAnnotation alloc] initWithDocument:self.document markupType:CPDFMarkupTypeStrikeOut] autorelease]; for (CPDFSelection *selection in self.currentSelection.selectionsByLine) { CGRect bounds = selection.bounds; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMinY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMinY(bounds))]]; } [(CPDFMarkupAnnotation *)annotation setQuadrilateralPoints:quadrilateralPoints]; [(CPDFMarkupAnnotation *)annotation setMarkupText:self.currentSelection.string]; [self clearSelection]; } break; case PDFViewAnnotationModeSquiggly: { if (!self.currentSelection) { return; } NSMutableArray *quadrilateralPoints = [NSMutableArray array]; annotation = [[[CPDFMarkupAnnotation alloc] initWithDocument:self.document markupType:CPDFMarkupTypeSquiggly] autorelease]; for (CPDFSelection *selection in self.currentSelection.selectionsByLine) { CGRect bounds = selection.bounds; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMinY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMinY(bounds))]]; } [(CPDFMarkupAnnotation *)annotation setQuadrilateralPoints:quadrilateralPoints]; [(CPDFMarkupAnnotation *)annotation setMarkupText:self.currentSelection.string]; [self clearSelection]; } break; case PDFViewAnnotationModeCircle: { annotation = [[[CPDFCircleAnnotation alloc] initWithDocument:self.document] autorelease]; annotation.bounds = CGRectMake(point.x-50, point.y-50, 100, 100); } break; case PDFViewAnnotationModeSquare: { annotation = [[[CPDFSquareAnnotation alloc] initWithDocument:self.document] autorelease]; annotation.bounds = CGRectMake(point.x-50, point.y-50, 100, 100); } break; case PDFViewAnnotationModeArrow: { annotation = [[[CPDFLineAnnotation alloc] initWithDocument:self.document] autorelease]; [(CPDFLineAnnotation *)annotation setStartPoint:CGPointMake(point.x-50, point.y)]; [(CPDFLineAnnotation *)annotation setEndPoint:CGPointMake(point.x+50, point.y)]; [(CPDFLineAnnotation *)annotation setEndLineStyle:CPDFLineStyleClosedArrow]; } break; case PDFViewAnnotationModeLine: { annotation = [[[CPDFLineAnnotation alloc] initWithDocument:self.document] autorelease]; [(CPDFLineAnnotation *)annotation setStartPoint:CGPointMake(point.x-50, point.y)]; [(CPDFLineAnnotation *)annotation setEndPoint:CGPointMake(point.x+50, point.y)]; } break; default: break; } if (!annotation) { return; } [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [page addAnnotation:annotation]; if ([annotation isKindOfClass:[CPDFTextAnnotation class]]) { [self setNeedsDisplayForPage:page]; if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformOpenNote:forAnnotation:)]) { [self.performDelegate PDFViewPerformOpenNote:self forAnnotation:annotation]; } } else if ([annotation isKindOfClass:[CPDFMarkupAnnotation class]]) { [self setNeedsDisplayForPage:page]; } else { self.activeAnnotation = annotation; [self setNeedsDisplayForPage:page]; [self updateScrollEnabled]; [self showMenuForAnnotation:annotation]; } } - (void)addAnnotationLinkAtPoint:(CGPoint)point forPage:(CPDFPage *)page { CPDFLinkAnnotation *annotation = [[[CPDFLinkAnnotation alloc] initWithDocument:self.document] autorelease]; annotation.bounds = self.addLinkRect; [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [page addAnnotation:annotation]; self.addLinkPoint = CGPointZero; self.addLinkRect = CGRectZero; [self setNeedsDisplayForPage:page]; if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformEditLink:forAnnotation:)]) { [self.performDelegate PDFViewPerformEditLink:self forAnnotation:annotation]; } } - (void)addAnnotationFreeTextAtPoint:(CGPoint)point forPage:(CPDFPage *)page { CPDFFreeTextAnnotation *annotation = [[[CPDFFreeTextAnnotation alloc] initWithDocument:self.document] autorelease]; if (CPDFKitShareConfig.enableAnnotationNoRotate) { CGFloat width; CGAffineTransform transform = [page transform]; point = CGPointApplyAffineTransform(point, transform); if (page.rotation == 90 || page.rotation == 270) { width = CGRectGetMaxY(page.bounds) - point.x - 20; } else { width = CGRectGetMaxX(page.bounds) - point.x - 20; } CGRect bounds = CGRectMake(point.x, point.y, width, annotation.font.pointSize); bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(transform)); annotation.bounds = bounds; } else { CGFloat width = CGRectGetMaxX(page.bounds) - point.x - 20; annotation.bounds = CGRectMake(point.x, point.y, width, annotation.font.pointSize); } [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [page addAnnotation:annotation]; [self editAnnotationFreeText:annotation]; } - (void)addAnnotationAtPoint:(CGPoint)point forPage:(CPDFPage *)page { CPDFAnnotation *annotation = self.addAnnotation; if (!annotation) { return; } annotation.bounds = CGRectMake(point.x-annotation.bounds.size.width/2.0, point.y-annotation.bounds.size.height/2.0, annotation.bounds.size.width, annotation.bounds.size.height); [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [page addAnnotation:annotation]; self.activeAnnotation = annotation; [self setNeedsDisplayForPage:page]; [self updateScrollEnabled]; [self showMenuForAnnotation:annotation]; self.addAnnotation = nil; } - (void)addAnnotation:(CPDFAnnotation *)annotation forPage:(CPDFPage *)page { if (!annotation || !page) { return; } [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [page addAnnotation:annotation]; self.activeAnnotation = annotation; [self setNeedsDisplayForPage:page]; [self updateScrollEnabled]; [self showMenuForAnnotation:annotation]; } - (void)addAnnotation:(CPDFAnnotation *)annotation { CPDFPage *page = [self.document pageAtIndex:self.currentPageIndex]; CGPoint center = [self convertPoint:self.center toPage:page]; if (CGPointEqualToPoint(center, CGPointZero)) { return; } CGRect bounds = annotation.bounds; bounds.origin.x = center.x-bounds.size.width/2.0; bounds.origin.y = center.y-bounds.size.height/2.0; bounds.origin.y = MIN(MAX(0, bounds.origin.y), page.bounds.size.height-bounds.size.height); annotation.bounds = bounds; [self addAnnotation:annotation forPage:page]; } #pragma mark - Annotation Menu - (BOOL)canBecomeFirstResponder { return YES; } - (void)showMenuForAnnotation:(CPDFAnnotation *)annotation { self.menuAnnotation = annotation; if (!annotation) { [UIMenuController sharedMenuController].menuItems = nil; [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES]; return; } NSMutableArray *menuItems = [NSMutableArray array]; UIMenuItem *colorItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Color", nil) action:@selector(colorItemAction:)] autorelease]; UIMenuItem *opacityItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Opacity", nil) action:@selector(opacityItemAction:)] autorelease]; UIMenuItem *copyItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy", nil) action:@selector(copyItemAction:)] autorelease]; UIMenuItem *noteItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Note", nil) action:@selector(noteItemAction:)] autorelease]; UIMenuItem *deleteItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Delete", nil) action:@selector(deleteItemAction:)] autorelease]; if ([annotation isKindOfClass:[CPDFMarkupAnnotation class]]) { UIMenuItem *shareItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Share", nil) action:@selector(shareItemAction:)] autorelease]; [menuItems addObject:colorItem]; [menuItems addObject:opacityItem]; [menuItems addObject:copyItem]; [menuItems addObject:shareItem]; [menuItems addObject:noteItem]; [menuItems addObject:deleteItem]; } else if ([annotation isKindOfClass:[CPDFStampAnnotation class]]) { if (CPDFStampTypeImage == [(CPDFStampAnnotation *)annotation stampType]) { UIMenuItem *saveItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Save", nil) action:@selector(saveItemAction:)] autorelease]; [menuItems addObject:saveItem]; [menuItems addObject:copyItem]; } [menuItems addObject:deleteItem]; } else if ([annotation isKindOfClass:[CPDFLinkAnnotation class]]) { UIMenuItem *editItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit", nil) action:@selector(editItemAction:)] autorelease]; [menuItems addObject:editItem]; [menuItems addObject:deleteItem]; } else if ([annotation isKindOfClass:[CPDFFreeTextAnnotation class]]) { UIMenuItem *editItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit", nil) action:@selector(editItemAction:)] autorelease]; [menuItems addObject:editItem]; [menuItems addObject:copyItem]; [menuItems addObject:deleteItem]; } else if ([annotation isKindOfClass:[CPDFSoundAnnotation class]] || [annotation isKindOfClass:[CPDFMovieAnnotation class]]) { [menuItems addObject:deleteItem]; } else if ([annotation isKindOfClass:[CPDFSignatureAnnotation class]]) { UIMenuItem *cancelItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Cancel", nil) action:@selector(deleteItemAction:)] autorelease]; UIMenuItem *addHereItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Add here", nil) action:@selector(addHereItemAction:)] autorelease]; [menuItems addObject:cancelItem]; [menuItems addObject:addHereItem]; } else if ([annotation isKindOfClass:[CPDFLineAnnotation class]] || [annotation isKindOfClass:[CPDFSquareAnnotation class]] || [annotation isKindOfClass:[CPDFCircleAnnotation class]] || [annotation isKindOfClass:[CPDFInkAnnotation class]]) { UIMenuItem *thicknessItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Thickness", nil) action:@selector(thicknessItemAction:)] autorelease]; [menuItems addObject:noteItem]; [menuItems addObject:colorItem]; [menuItems addObject:thicknessItem]; [menuItems addObject:opacityItem]; [menuItems addObject:deleteItem]; } else if ([annotation isKindOfClass:[CPDFSignatureWidgetAnnotation class]]) { UIMenuItem *deleteItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Delete", nil) action:@selector(signatureWidgetDeleteItemAction:)] autorelease]; [menuItems addObject:deleteItem]; } if (menuItems.count <= 0) { return; } CGRect bounds = annotation.bounds; bounds = CGRectInset(bounds, -15, -15); CGRect rect = [self convertRect:bounds fromPage:annotation.page]; [self becomeFirstResponder]; [UIMenuController sharedMenuController].menuItems = menuItems; [[UIMenuController sharedMenuController] setTargetRect:rect inView:self]; [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES]; } - (void)signatureWidgetDeleteItemAction:(id)sender { if ([self.menuAnnotation isKindOfClass:[CPDFSignatureWidgetAnnotation class]]) { [(CPDFSignatureWidgetAnnotation *)self.menuAnnotation reset]; [self setNeedsDisplayForPage:self.menuAnnotation.page]; } } - (void)colorItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformChangeColor:forAnnotation:)]) { [self.performDelegate PDFViewPerformChangeColor:self forAnnotation:self.menuAnnotation]; } } - (void)opacityItemAction:(id)sender { NSMutableArray *menuItems = [NSMutableArray array]; UIMenuItem *opacity25Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"25%", nil) action:@selector(opacity25ItemAction:)] autorelease]; UIMenuItem *opacity50Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"50%", nil) action:@selector(opacity50ItemAction:)] autorelease]; UIMenuItem *opacity75Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"75%", nil) action:@selector(opacity75ItemAction:)] autorelease]; UIMenuItem *opacity100Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"100%", nil) action:@selector(opacity100ItemAction:)] autorelease]; [menuItems addObject:opacity25Item]; [menuItems addObject:opacity50Item]; [menuItems addObject:opacity75Item]; [menuItems addObject:opacity100Item]; CGRect bounds = self.menuAnnotation.bounds; bounds = CGRectInset(bounds, -15, -15); CGRect rect = [self convertRect:bounds fromPage:self.menuAnnotation.page]; [self becomeFirstResponder]; [UIMenuController sharedMenuController].menuItems = menuItems; [[UIMenuController sharedMenuController] setTargetRect:rect inView:self]; [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES]; } - (void)opacity25ItemAction:(id)sender { self.menuAnnotation.opacity = 0.25; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)opacity50ItemAction:(id)sender { self.menuAnnotation.opacity = 0.50; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)opacity75ItemAction:(id)sender { self.menuAnnotation.opacity = 0.75; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)opacity100ItemAction:(id)sender { self.menuAnnotation.opacity = 1.0; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)copyItemAction:(id)sender { if ([self.menuAnnotation isKindOfClass:[CPDFMarkupAnnotation class]]) { NSString *string = [(CPDFMarkupAnnotation *)self.menuAnnotation markupText]; [[UIPasteboard generalPasteboard] setString:string]; } else if ([self.menuAnnotation isKindOfClass:[CPDFStampAnnotation class]]) { UIImage *image = [(CPDFStampAnnotation *)self.menuAnnotation stampImage]; [UIPasteboard generalPasteboard].image = image; } else if ([self.menuAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]]) { NSString *string = self.menuAnnotation.contents; [[UIPasteboard generalPasteboard] setString:string]; } } - (void)noteItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformOpenNote:forAnnotation:)]) { [self.performDelegate PDFViewPerformOpenNote:self forAnnotation:self.menuAnnotation]; } } - (void)deleteItemAction:(id)sender { self.activeAnnotation = nil; [self.menuAnnotation.page removeAnnotation:self.menuAnnotation]; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self updateScrollEnabled]; } - (void)shareItemAction:(id)sender { if ([self.menuAnnotation isKindOfClass:[CPDFMarkupAnnotation class]]) { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformShare:forAnnotation:)]) { [self.performDelegate PDFViewPerformShare:self forAnnotation:(CPDFMarkupAnnotation *)self.menuAnnotation]; } } } - (void)saveItemAction:(id)sender { if ([self.menuAnnotation isKindOfClass:[CPDFStampAnnotation class]]) { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformSave:forAnnotation:)]) { [self.performDelegate PDFViewPerformSave:self forAnnotation:(CPDFStampAnnotation *)self.menuAnnotation]; } } } - (void)editItemAction:(id)sender { if ([self.menuAnnotation isKindOfClass:[CPDFLinkAnnotation class]]) { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformEditLink:forAnnotation:)]) { [self.performDelegate PDFViewPerformEditLink:self forAnnotation:(CPDFLinkAnnotation *)self.menuAnnotation]; } } else if ([self.menuAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]]) { self.activeAnnotation = nil; [self editAnnotationFreeText:(CPDFFreeTextAnnotation *)self.menuAnnotation]; } } - (void)addHereItemAction:(id)sender { if ([self.menuAnnotation isKindOfClass:[CPDFSignatureAnnotation class]]) { [(CPDFSignatureAnnotation *)self.menuAnnotation signature]; self.activeAnnotation = nil; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self updateScrollEnabled]; } } - (void)thicknessItemAction:(id)sender { NSMutableArray *menuItems = [NSMutableArray array]; UIMenuItem *thickness0_5Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"0.5pt", nil) action:@selector(thickness0_5ItemAction:)] autorelease]; UIMenuItem *thickness1Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"1pt", nil) action:@selector(thickness1ItemAction:)] autorelease]; UIMenuItem *thickness1_5Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"1.5pt", nil) action:@selector(thickness1_5ItemAction:)] autorelease]; UIMenuItem *thickness2Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"2pt", nil) action:@selector(thickness2ItemAction:)] autorelease]; UIMenuItem *thickness3Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"3pt", nil) action:@selector(thickness3ItemAction:)] autorelease]; UIMenuItem *thickness5Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"5pt", nil) action:@selector(thickness5ItemAction:)] autorelease]; UIMenuItem *thickness9Item = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"9pt", nil) action:@selector(thickness9ItemAction:)] autorelease]; [menuItems addObject:thickness0_5Item]; [menuItems addObject:thickness1Item]; [menuItems addObject:thickness1_5Item]; [menuItems addObject:thickness2Item]; [menuItems addObject:thickness3Item]; [menuItems addObject:thickness5Item]; [menuItems addObject:thickness9Item]; CGRect bounds = self.menuAnnotation.bounds; bounds = CGRectInset(bounds, -15, -15); CGRect rect = [self convertRect:bounds fromPage:self.menuAnnotation.page]; [self becomeFirstResponder]; [UIMenuController sharedMenuController].menuItems = menuItems; [[UIMenuController sharedMenuController] setTargetRect:rect inView:self]; [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES]; } - (void)thickness0_5ItemAction:(id)sender { self.menuAnnotation.borderWidth = 0.5; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)thickness1ItemAction:(id)sender { self.menuAnnotation.borderWidth = 1.0; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)thickness1_5ItemAction:(id)sender { self.menuAnnotation.borderWidth = 1.5; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)thickness2ItemAction:(id)sender { self.menuAnnotation.borderWidth = 2.0; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)thickness3ItemAction:(id)sender { self.menuAnnotation.borderWidth = 3.0; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)thickness5ItemAction:(id)sender { self.menuAnnotation.borderWidth = 5.0; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } - (void)thickness9ItemAction:(id)sender { self.menuAnnotation.borderWidth = 9.0; [self setNeedsDisplayForPage:self.menuAnnotation.page]; [self showMenuForAnnotation:self.menuAnnotation]; } #pragma mark - Menu - (NSArray *)menuItemsAtPoint:(CGPoint)point forPage:(CPDFPage *)page { if (PDFViewAnnotationModeNone != self.annotationMode) { return nil; } NSArray *items = [super menuItemsAtPoint:point forPage:page]; self.menuPoint = point; self.menuPage = page; NSMutableArray *menuItems = [NSMutableArray arrayWithArray:items]; if (self.currentSelection) { UIMenuItem *textNoteItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Note", nil) action:@selector(textNoteItemAction:)] autorelease]; UIMenuItem *textShareItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Share", nil) action:@selector(textShareItemAction:)] autorelease]; UIMenuItem *defineItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Define", nil) action:@selector(defineItemAction:)] autorelease]; UIMenuItem *linkItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Link", nil) action:@selector(linkItemAction:)] autorelease]; UIMenuItem *searchItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Search", nil) action:@selector(searchItemAction:)] autorelease]; [menuItems insertObject:textNoteItem atIndex:0]; [menuItems addObject:textShareItem]; [menuItems addObject:defineItem]; [menuItems addObject:linkItem]; [menuItems addObject:searchItem]; } else { UIMenuItem *textNoteItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Note", nil) action:@selector(textNoteItemAction:)] autorelease]; UIMenuItem *textItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Text", nil) action:@selector(textItemAction:)] autorelease]; UIMenuItem *signatureItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Signature", nil) action:@selector(signatureItemAction:)] autorelease]; UIMenuItem *stampItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Stamp", nil) action:@selector(stampItemAction:)] autorelease]; UIMenuItem *imageItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Image", nil) action:@selector(imageItemAction:)] autorelease]; UIMenuItem *pasteItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Paste", nil) action:@selector(pasteItemAction:)] autorelease]; [menuItems addObject:textNoteItem]; [menuItems addObject:textItem]; [menuItems addObject:signatureItem]; [menuItems addObject:stampItem]; [menuItems addObject:imageItem]; if ([self isPasteboardValid]) { [menuItems addObject:pasteItem]; } } return menuItems; } - (BOOL)isPasteboardValid { NSString *textType = (NSString *)kUTTypeText; NSString *urlType = (NSString*)kUTTypeURL; NSString *urlFileType = (NSString*)kUTTypeFileURL; NSString *jpegImageType = (NSString *)kUTTypeJPEG; NSString *pngImageType = (NSString *)kUTTypePNG; NSString *rawImageType = @"com.apple.uikit.image"; return [[UIPasteboard generalPasteboard] containsPasteboardTypes:[NSArray arrayWithObjects:textType, urlType, urlFileType, jpegImageType, pngImageType, rawImageType, nil]]; } - (void)textNoteItemAction:(id)sender { if (self.currentSelection) { NSMutableArray *quadrilateralPoints = [NSMutableArray array]; CPDFMarkupAnnotation *annotation = [[[CPDFMarkupAnnotation alloc] initWithDocument:self.document markupType:CPDFMarkupTypeHighlight] autorelease]; for (CPDFSelection *selection in self.currentSelection.selectionsByLine) { CGRect bounds = selection.bounds; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMinY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMinY(bounds))]]; } [annotation setQuadrilateralPoints:quadrilateralPoints]; [annotation setMarkupText:self.currentSelection.string]; [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [self.currentSelection.page addAnnotation:annotation]; [annotation createPopup]; [self clearSelection]; [self setNeedsDisplayForPage:annotation.page]; if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformPopup:forAnnotation:)]) { [self.performDelegate PDFViewPerformPopup:self forAnnotation:annotation]; } } else { [self addAnnotation:PDFViewAnnotationModeNote atPoint:self.menuPoint forPage:self.menuPage]; } } - (void)textShareItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformShare:forSelection:)]) { [self.performDelegate PDFViewPerformShare:self forSelection:self.currentSelection]; } } - (void)defineItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformDefine:forSelection:)]) { [self.performDelegate PDFViewPerformDefine:self forSelection:self.currentSelection]; } } - (void)linkItemAction:(id)sender { if (self.currentSelection) { CPDFLinkAnnotation *annotation = [[[CPDFLinkAnnotation alloc] initWithDocument:self.document] autorelease]; annotation.bounds = self.currentSelection.bounds; [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; [self.currentSelection.page addAnnotation:annotation]; [self clearSelection]; [self setNeedsDisplayForPage:annotation.page]; if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformEditLink:forAnnotation:)]) { [self.performDelegate PDFViewPerformEditLink:self forAnnotation:annotation]; } } } - (void)searchItemAction:(id)sender { NSMutableArray *menuItems = [NSMutableArray array]; UIMenuItem *googleSearchItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Google", nil) action:@selector(googleSearchItemAction:)] autorelease]; UIMenuItem *wikiSearchItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Wiki", nil) action:@selector(wikiSearchItemAction:)] autorelease]; [menuItems addObject:googleSearchItem]; [menuItems addObject:wikiSearchItem]; CGRect rect = [self convertRect:self.currentSelection.bounds fromPage:self.currentSelection.page]; [self becomeFirstResponder]; [UIMenuController sharedMenuController].menuItems = menuItems; [[UIMenuController sharedMenuController] setTargetRect:rect inView:self]; [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES]; } - (void)googleSearchItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformGoogleSearch:forSelection:)]) { [self.performDelegate PDFViewPerformGoogleSearch:self forSelection:self.currentSelection]; } } - (void)wikiSearchItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformWikiSearch:forSelection:)]) { [self.performDelegate PDFViewPerformWikiSearch:self forSelection:self.currentSelection]; } } - (void)textItemAction:(id)sender { [self addAnnotationFreeTextAtPoint:self.menuPoint forPage:self.menuPage]; } - (void)signatureItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformAddSignture:atPoint:forPage:)]) { [self.performDelegate PDFViewPerformAddSignture:self atPoint:self.menuPoint forPage:self.menuPage]; } } - (void)stampItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformAddStamp:atPoint:forPage:)]) { [self.performDelegate PDFViewPerformAddStamp:self atPoint:self.menuPoint forPage:self.menuPage]; } } - (void)imageItemAction:(id)sender { if ([self.performDelegate respondsToSelector:@selector(PDFViewPerformAddImage:atPoint:forPage:)]) { [self.performDelegate PDFViewPerformAddImage:self atPoint:self.menuPoint forPage:self.menuPage]; } } - (void)pasteItemAction:(id)sender { NSString *textType = (NSString *)kUTTypeText; NSString *utf8TextType = (NSString *)kUTTypeUTF8PlainText; NSString *urlType = (NSString*)kUTTypeURL; NSString *urlFileType = (NSString*)kUTTypeFileURL; NSString *jpegImageType = (NSString *)kUTTypeJPEG; NSString *pngImageType = (NSString *)kUTTypePNG; NSString *rawImageType = @"com.apple.uikit.image"; NSArray *pasteArray = [UIPasteboard generalPasteboard].items; for (NSDictionary* dic in pasteArray) { if ([dic objectForKey:textType] || [dic objectForKey:utf8TextType] || [dic objectForKey:urlType] || [dic objectForKey:urlFileType]) { NSString *contents = nil; if ([dic objectForKey:textType] || [dic objectForKey:utf8TextType]) { contents = [UIPasteboard generalPasteboard].string; } else { contents = [[UIPasteboard generalPasteboard].URL absoluteString]; } UIFont *font = [UIFont systemFontOfSize:12.0]; NSDictionary *attributes = @{NSFontAttributeName : font}; CGRect bounds = [contents boundingRectWithSize:CGSizeMake(280, MAXFLOAT) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributes context:nil]; CPDFFreeTextAnnotation *annotation = [[[CPDFFreeTextAnnotation alloc] initWithDocument:self.document] autorelease]; [annotation setContents:contents]; [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; annotation.bounds = CGRectMake(self.menuPoint.x-bounds.size.width/2.0, self.menuPoint.y-bounds.size.height/2.0, bounds.size.width, bounds.size.height); [self.menuPage addAnnotation:annotation]; [self setNeedsDisplayForPage:self.menuPage]; } else if ([dic objectForKey:jpegImageType] || [dic objectForKey:pngImageType] || [dic objectForKey:rawImageType]) { UIImage *image = [UIPasteboard generalPasteboard].image; UIImage *compressImage = [self compressImage:image size:CGSizeMake(240.0, 240.0)]; CPDFStampAnnotation *annotation = [[[CPDFStampAnnotation alloc] initWithDocument:self.document image:compressImage] autorelease]; [annotation setModificationDate:[NSDate date]]; [annotation setUserName:[self annotationUserName]]; annotation.bounds = CGRectMake(self.menuPoint.x-compressImage.size.width/2.0, self.menuPoint.y-compressImage.size.height/2.0, compressImage.size.width, compressImage.size.height); [self.menuPage addAnnotation:annotation]; [self setNeedsDisplayForPage:self.menuPage]; } } } @end