// // KMDocumentAIPDFView.m // PDF Master // // Created by 丁林圭 on 2023/2/2. // #import "KMDocumentAIPDFView.h" #import "NSEvent+PDFListView.h" #import "NSGeometry+PDFListView.h" #import "KMDocumentAIPopViewController.h" #define DOCUMENT_SIZE 30.0 @interface KMDocumentAIPDFView() //@property(nonatomic,retain) NSMutableArray * results; @property(nonatomic,assign) CGRect drawRecognitionEreaRect; @property(nonatomic,assign) CGRect recognitionEreaRect; @property (nonatomic, assign) NSUInteger selectionPageIndex; //@property (nonatomic, retain) COCRResult * activeResult; @property (nonatomic, assign) NSInteger activeResultIndex; @property (nonatomic, retain) CPDFPage * activeResultPage; @property (nonatomic, retain) NSPopover *popOver; @property (nonatomic, retain) KMDocumentAIPopViewController *documentAIPopViewController; @end @implementation KMDocumentAIPDFView - (NSPopover *)popOver { if(!_popOver) { _popOver = [[NSPopover alloc] init]; _popOver.delegate = self; self.documentAIPopViewController = [[KMDocumentAIPopViewController alloc] initWithNibName:@"KMDocumentAIPopViewController" bundle:[NSBundle mainBundle]]; _popOver.contentViewController = self.documentAIPopViewController; _popOver.animates = YES; __block typeof(self) blockSelf = self; self.documentAIPopViewController.callback = ^(NSInteger result) { if(result == 1) { // blockSelf.results[blockSelf.activeResultIndex].text = blockSelf.documentAIPopViewController.contentTextView.string?:@""; [blockSelf setNeedsDisplayAnnotationViewForPage:blockSelf.activeResultPage]; } if(blockSelf.popOver.isShown) [blockSelf.popOver performClose:nil]; }; _popOver.behavior = NSPopoverBehaviorTransient; } return _popOver; } - (void)mouseDown:(NSEvent *)event { // if ([self doOCRResultWithEvent:event]) { // if(self.popOver.isShown) { // [self.popOver performClose:nil]; // } else { // CGRect rect = [self convertRect:self.activeResult.textBounds fromPage:self.currentPage]; // [self.popOver showRelativeToRect:rect ofView:self preferredEdge:NSRectEdgeMinY]; // self.documentAIPopViewController.contentTextView.string = self.activeResult.text?:@""; // } // } else if ([self isRecognitionErea]) { // [self doSelectWithEvent:event]; // } } //- (COCRResult *)doOCRResultWithEvent:(NSEvent *)theEvent { // COCRResult *result = nil; // NSPoint point = NSZeroPoint; // CPDFPage *page = [self pageAndPoint:&point forEvent:theEvent nearest:YES]; // // for (NSInteger i = 0;i NSMaxX(initialRect) ? CMaxXEdgeMask : CMinXEdgeMask; if ((resizeHandle & CMaxYEdgeMask)) newEffectiveResizeHandle |= newPoint.y < NSMinY(initialRect) ? CMinYEdgeMask : CMaxYEdgeMask; else if ((resizeHandle & CMinYEdgeMask)) newEffectiveResizeHandle |= newPoint.y > NSMaxY(initialRect) ? CMaxYEdgeMask : CMinYEdgeMask; if (newEffectiveResizeHandle != effectiveResizeHandle) { effectiveResizeHandle = newEffectiveResizeHandle; [self setCursorForAreaOfInterest:CAreaOfInterestForResizeHandle(effectiveResizeHandle, page)]; } } if (resizeHandle == CEditInEdgeMask) { newRect.origin = CPDFListViewAddPoints(newRect.origin, delta); } else if (([theEvent modifierFlags] & NSEventModifierFlagShift)) { CGFloat width = NSWidth(newRect); CGFloat height = NSHeight(newRect); CGFloat square; if ((resizeHandle & CMaxXEdgeMask)) width += delta.x; else if ((resizeHandle & CMinXEdgeMask)) width -= delta.x; if ((resizeHandle & CMaxYEdgeMask)) height += delta.y; else if ((resizeHandle & CMinYEdgeMask)) height -= delta.y; if (0 == (resizeHandle & (CMinXEdgeMask | CMaxXEdgeMask))) square = fabs(height); else if (0 == (resizeHandle & (CMinYEdgeMask | CMaxYEdgeMask))) square = fabs(width); else square = fmax(fabs(width), fabs(height)); if ((resizeHandle & CMinXEdgeMask)) { if (width >= 0.0 && NSMaxX(newRect) - square < NSMinX(pageBounds)) square = NSMaxX(newRect) - NSMinX(pageBounds); else if (width < 0.0 && NSMaxX(newRect) + square > NSMaxX(pageBounds)) square = NSMaxX(pageBounds) - NSMaxX(newRect); } else { if (width >= 0.0 && NSMinX(newRect) + square > NSMaxX(pageBounds)) square = NSMaxX(pageBounds) - NSMinX(newRect); else if (width < 0.0 && NSMinX(newRect) - square < NSMinX(pageBounds)) square = NSMinX(newRect) - NSMinX(pageBounds); } if ((resizeHandle & CMinYEdgeMask)) { if (height >= 0.0 && NSMaxY(newRect) - square < NSMinY(pageBounds)) square = NSMaxY(newRect) - NSMinY(pageBounds); else if (height < 0.0 && NSMaxY(newRect) + square > NSMaxY(pageBounds)) square = NSMaxY(pageBounds) - NSMaxY(newRect); } else { if (height >= 0.0 && NSMinY(newRect) + square > NSMaxY(pageBounds)) square = NSMaxY(pageBounds) - NSMinY(newRect); if (height < 0.0 && NSMinY(newRect) - square < NSMinY(pageBounds)) square = NSMinY(newRect) - NSMinY(pageBounds); } if ((resizeHandle & CMinXEdgeMask)) newRect.origin.x = width < 0.0 ? NSMaxX(newRect) : NSMaxX(newRect) - square; else if (width < 0.0 && (resizeHandle & CMaxXEdgeMask)) newRect.origin.x = NSMinX(newRect) - square; if ((resizeHandle & CMinYEdgeMask)) newRect.origin.y = height < 0.0 ? NSMaxY(newRect) : NSMaxY(newRect) - square; else if (height < 0.0 && (resizeHandle & CMaxYEdgeMask)) newRect.origin.y = NSMinY(newRect) - square; newRect.size.width = newRect.size.height = square; } else { if ((resizeHandle & CMaxXEdgeMask)) { newRect.size.width += delta.x; if (NSWidth(newRect) < 0.0) { newRect.size.width *= -1.0; newRect.origin.x -= NSWidth(newRect); } } else if ((resizeHandle & CMinXEdgeMask)) { newRect.origin.x += delta.x; newRect.size.width -= delta.x; if (NSWidth(newRect) < 0.0) { newRect.size.width *= -1.0; newRect.origin.x -= NSWidth(newRect); } } if ((resizeHandle & CMaxYEdgeMask)) { newRect.size.height += delta.y; if (NSHeight(newRect) < 0.0) { newRect.size.height *= -1.0; newRect.origin.y -= NSHeight(newRect); } } else if ((resizeHandle & CMinYEdgeMask)) { newRect.origin.y += delta.y; newRect.size.height -= delta.y; if (NSHeight(newRect) < 0.0) { newRect.size.height *= -1.0; newRect.origin.y -= NSHeight(newRect); } } } newRect = CPDFListViewIntersectionRect(newRect, pageBounds); if (didSelect) { NSRect dirtyRect = NSUnionRect(NSInsetRect(self.recognitionEreaRect, -margin, -margin), NSInsetRect(newRect, -margin, -margin)); [self setNeedsDisplayAnnotationInRect:dirtyRect]; } else { [self setNeedsDisplayAnnotationViewForVisiblePages]; didSelect = YES; } @synchronized (self) { self.recognitionEreaRect = newRect; } } if (NSIsEmptyRect(self.recognitionEreaRect)) { @synchronized (self) { self.recognitionEreaRect = NSZeroRect; self.selectionPageIndex = NSNotFound; } [self setNeedsDisplay:YES]; } else if (resizeHandle) { [self setNeedsDisplayAnnotationInRect:NSInsetRect(self.recognitionEreaRect, -margin, -margin)]; } } - (CPDFPage *)pageAndPoint:(NSPoint *)point forEvent:(NSEvent *)event nearest:(BOOL)nearest { NSPoint p = [event locationInPDFListView:self]; CPDFPage *page = [self pageForPoint:p nearest:nearest]; if (page && point) *point = [self convertPoint:p toPage:page]; return page; } //- (void)updateResult:(NSArray *)results recognitionRect:(CGRect)recognitionRect { // self.results = [NSMutableArray arrayWithArray:results]; // self.drawRecognitionEreaRect = recognitionRect; // [self setNeedsDisplayAnnotationViewForPage:self.currentPage]; //} // //- (void)drawPage:(CPDFPage *)page toContext:(CGContextRef)context { // if(self.resultDics.count > 0) { // NSInteger currentIndex = [self.document indexForPage:page]; // NSArray *currentResults = @[]; // for (NSDictionary *dic in self.resultDics) { // if(dic[@"page"] && [dic[@"page"] integerValue] == currentIndex) { // if(dic[@"results"]) { // currentResults = dic[@"results"]; // break; // } // } // } // if (currentResults.count>0) { // [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:context flipped:NO]]; // // CGContextSaveGState(context); // CGContextAddRect(context, self.drawRecognitionEreaRect); // CGContextSetRGBFillColor(context, 1, 1, 1, 0.7); // CGContextFillPath(context); // CGContextRestoreGState(context); // // NSMutableDictionary *dic = [NSMutableDictionary dictionary]; // [dic setValue:[NSColor blackColor] forKey:NSForegroundColorAttributeName]; // // for (COCRResult * cOcrResult in currentResults) { // CGContextSaveGState(context); // // CGRect rect = cOcrResult.textBounds; // // NSString *strChar = cOcrResult.text; // CGFloat fontsize = 1.0; // NSFont *font = [NSFont systemFontOfSize:fontsize]; // CGSize strSize = [strChar sizeWithAttributes:@{NSFontAttributeName:font}]; // while ((fontsize<127) && !(strSize.width>=cOcrResult.textBounds.size.width || strSize.height>=cOcrResult.textBounds.size.height)) { // fontsize += 1.0; // font = [NSFont systemFontOfSize:fontsize]; // strSize = [strChar sizeWithAttributes:@{NSFontAttributeName:font}]; // } // NSFont *drawFont = [NSFont systemFontOfSize:fontsize-1]; // // strSize = [strChar sizeWithAttributes:@{NSFontAttributeName:drawFont}]; // CGFloat k = (cOcrResult.textBounds.size.width - strSize.width)/(strChar.length); // // NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; // // NSDictionary *attriDict = @{NSParagraphStyleAttributeName:style,NSKernAttributeName:@(k),NSFontAttributeName:drawFont}; // // NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:strChar attributes:attriDict]; // [attributeString drawInRect:rect]; // // CGContextAddRect(context, rect); // CGContextSetLineWidth(context, 1.0); // CGContextSetStrokeColorWithColor(context, [NSColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:1.0].CGColor); // CGContextStrokePath(context); // // CGContextRestoreGState(context); // } // } // // } // // if(!CGRectEqualToRect(self.recognitionEreaRect, CGRectZero)) { // @synchronized (self) { // CGContextSaveGState(context); // // CGFloat size = DOCUMENT_SIZE; // CGContextSetLineWidth(context, 5.0); // CGContextSetStrokeColorWithColor(context, [NSColor colorWithRed:23.0/255.0 green:112.0/255.0 blue:244.0/255.0 alpha:1.0].CGColor); // // CGContextMoveToPoint(context, CGRectGetMidX(self.recognitionEreaRect)-size/2, CGRectGetMaxY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMidX(self.recognitionEreaRect)+size/2, CGRectGetMaxY(self.recognitionEreaRect)); // // CGContextMoveToPoint(context, CGRectGetMidX(self.recognitionEreaRect)-size/2, CGRectGetMinY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMidX(self.recognitionEreaRect)+size/2, CGRectGetMinY(self.recognitionEreaRect)); // // CGContextMoveToPoint(context, CGRectGetMinX(self.recognitionEreaRect), CGRectGetMidY(self.recognitionEreaRect)-size/2); // CGContextAddLineToPoint(context, CGRectGetMinX(self.recognitionEreaRect), CGRectGetMidY(self.recognitionEreaRect)+size/2); // // CGContextMoveToPoint(context, CGRectGetMaxX(self.recognitionEreaRect), CGRectGetMidY(self.recognitionEreaRect)-size/2); // CGContextAddLineToPoint(context, CGRectGetMaxX(self.recognitionEreaRect), CGRectGetMidY(self.recognitionEreaRect)+size/2); // // CGContextMoveToPoint(context, CGRectGetMaxX(self.recognitionEreaRect)-size/2, CGRectGetMinY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMaxX(self.recognitionEreaRect), CGRectGetMinY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMaxX(self.recognitionEreaRect), CGRectGetMinY(self.recognitionEreaRect)+ size/2); // // CGContextMoveToPoint(context, CGRectGetMinX(self.recognitionEreaRect)+size/2, CGRectGetMinY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMinX(self.recognitionEreaRect), CGRectGetMinY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMinX(self.recognitionEreaRect), CGRectGetMinY(self.recognitionEreaRect)+ size/2); // // CGContextMoveToPoint(context, CGRectGetMinX(self.recognitionEreaRect)+size/2, CGRectGetMaxY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMinX(self.recognitionEreaRect), CGRectGetMaxY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMinX(self.recognitionEreaRect), CGRectGetMaxY(self.recognitionEreaRect) - size/2); // // CGContextMoveToPoint(context, CGRectGetMaxX(self.recognitionEreaRect)-size/2, CGRectGetMaxY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMaxX(self.recognitionEreaRect), CGRectGetMaxY(self.recognitionEreaRect)); // CGContextAddLineToPoint(context, CGRectGetMaxX(self.recognitionEreaRect), CGRectGetMaxY(self.recognitionEreaRect) - size/2); // // CGContextStrokePath(context); // // CGContextSetLineCap(context, kCGLineCapRound); // CGContextSetLineWidth(context, 2.0); // CGContextRestoreGState(context); // // CGContextSetStrokeColorWithColor(context, [NSColor colorWithRed:23.0/255.0 green:112.0/255.0 blue:244.0/255.0 alpha:1.0].CGColor); // CGContextBeginPath(context); // CGContextMoveToPoint(context, self.recognitionEreaRect.origin.x, self.recognitionEreaRect.origin.y); // CGContextAddLineToPoint(context, self.recognitionEreaRect.origin.x+ self.recognitionEreaRect.size.width,self.recognitionEreaRect.origin.y); // CGContextAddLineToPoint(context, self.recognitionEreaRect.origin.x + self.recognitionEreaRect.size.width,self.recognitionEreaRect.origin.y + + self.recognitionEreaRect.size.height); // CGContextAddLineToPoint(context, self.recognitionEreaRect.origin.x,self.recognitionEreaRect.origin.y + + self.recognitionEreaRect.size.height); // CGContextClosePath(context); // CGFloat lengths[] = {10,5}; // CGContextSetLineDash(context, 0, lengths,2); // CGContextStrokePath(context); // } // } //} #pragma Mark - menuForEvent -(NSMenu *)menuForEvent:(NSEvent *)event { NSMenu *menu = [[NSMenu alloc]init]; if(self.isRecognitionErea && !NSEqualRects(NSZeroRect, self.recognitionEreaRect)) { NSMenuItem * sureMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Start OCR text recognition", nil) action:@selector(menuItemClick_StartOCR:) keyEquivalent:@""]; [menu addItem:sureMenuItem]; } return menu; } -(void)menuItemClick_StartOCR:(NSMenuItem *)item { if (self.callback) { self.callback(self.recognitionEreaRect,self.currentPage); } self.recognitionEreaRect = CGRectZero; [self setNeedsDisplayAnnotationViewForPage:self.currentPage]; } @end