// // KMDocumentAIViewController.m // PDF Master // // Created by 丁林圭 on 2023/1/30. // #import "KMDocumentAIViewController.h" #import "KMOCRBox.h" #import "KMDocumentAIManager.h" #import "KMOCRComboBox.h" #import #import #define kIndicatorWidth 32.0 #define kIndicatorHeight 32.0 #pragma mark - KMBookletMaskView @interface KMBookletMaskView : NSView @property (nonatomic, retain) NSProgressIndicator *progressIndicator; @end @implementation KMBookletMaskView - (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; self.wantsLayer = YES; self.layer.backgroundColor = [NSColor clearColor].CGColor; } - (instancetype)initWithFrame:(NSRect)frameRect { self = [super initWithFrame:frameRect]; if (self) { NSProgressIndicator *indicator = [[NSProgressIndicator alloc] initWithFrame:CGRectMake((frameRect.size.width - kIndicatorWidth)/2, (frameRect.size.height - kIndicatorHeight)/2, kIndicatorWidth, kIndicatorHeight)]; indicator.style = NSProgressIndicatorStyleSpinning; self.progressIndicator = indicator; [indicator startAnimation:nil]; [self addSubview:indicator]; } return self; } - (void)mouseDown:(NSEvent *)event { } - (void)mouseUp:(NSEvent *)event { } @end #pragma mark - KMDocumentAIViewController #define kDocumentAIFileSavePath [[[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier] stringByAppendingPathComponent:@"documentAI.pdf"] @interface KMDocumentAIViewController () @property(nonatomic,assign) IBOutlet KMDocumentAIPDFView *pdfPreView; //@property(nonatomic,assign) COCRModelType modelType; @property(nonatomic,retain) CPDFDocument *orgDocument; @property(nonatomic,retain) CPDFDocument *preDocument; @property (nonatomic,retain) KMBookletMaskView *posterMaskView; @property (nonatomic,retain) NSMutableArray *datas; @property (nonatomic,retain) NSMutableArray *resultDics; @property (nonatomic,assign) CGRect recognitionRect; @property (nonatomic,assign) BOOL isContinusOCR; @property (weak) IBOutlet NSView *rightView; @property (weak) IBOutlet NSTextField *rightTitleLabel; @property (weak) IBOutlet KMOCRBox *pageRecognitionBox; @property (weak) IBOutlet NSTextField *pageRecognitionTitle; @property (weak) IBOutlet NSImageView *pageRecognitionImageView; @property (weak) IBOutlet KMOCRBox *areaRecognitionBox; @property (weak) IBOutlet NSTextField *areaRecognitionTitle; @property (weak) IBOutlet NSImageView *areaRecognitionImageView; @property (weak) IBOutlet NSTextField *textRecognitionSetLabel; @property (weak) IBOutlet KMOCRComboBox *languagePopButton; @property (weak) IBOutlet NSTextField *pageRecognitionSetLabel; @property (weak) IBOutlet KMOCRComboBox *pageRangePopButton; @property (weak) IBOutlet NSButton *OCRButton; @property (weak) IBOutlet NSView *languageSetView; @property (weak) IBOutlet NSView *rangeSetView; @property (nonatomic,copy) NSString *pagesString; @property (weak) IBOutlet NSLayoutConstraint *tipConstraint; @property (weak) IBOutlet NSTextField *topTitleLabel; @property (weak) IBOutlet NSView *topView; @property (weak) IBOutlet NSView *scanView; @property (weak) IBOutlet NSTextField *scanTipLabel; @property (weak) IBOutlet NSProgressIndicator *progressIndicator; @property (weak) IBOutlet NSView *ocrTipView; @property (weak) IBOutlet NSTextField *ocrTipLabel; @end @implementation KMDocumentAIViewController static inline NSFont * FontWithSize(NSString *strChar, CGSize size) { CGFloat fontsize = 1.0; NSFont *font = [NSFont systemFontOfSize:fontsize]; CGSize strSize = [strChar sizeWithAttributes:@{NSFontAttributeName:font}]; while ((fontsize<127) && (strSize.width>size.width && strSize.height>size.height)) { fontsize += 1.0; font = [NSFont systemFontOfSize:fontsize]; strSize = [strChar sizeWithAttributes:@{NSFontAttributeName:font}]; } return [NSFont systemFontOfSize:fontsize-1]; } - (void)dealloc { [KMDocumentAIManager defaultManager].delegate = nil; } - (instancetype)initWithPDFView:(CPDFView *)pdfView { if(self = [super initWithNibName:@"KMDocumentAIViewController" bundle:nil]) { self.orgDocument = pdfView.document; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [pdfView.document writeToURL:[NSURL fileURLWithPath:kDocumentAIFileSavePath]]; self.preDocument = [[CPDFDocument alloc]initWithURL:[NSURL fileURLWithPath:kDocumentAIFileSavePath]]; [self.preDocument unlockWithPassword:pdfView.document.password]; dispatch_async(dispatch_get_main_queue(), ^{ self.pdfPreView.delegate = self; self.pdfPreView.displayDirection = CPDFDisplayDirectionHorizontal; self.pdfPreView.scaleFactor = pdfView.scaleFactor; self.pdfPreView.displayTwoUp = NO; self.pdfPreView.autoScales = YES; self.pdfPreView.document = self.preDocument; NSInteger pageIndex = pdfView.currentPageIndex; [self.pdfPreView goToPageIndex:pageIndex animated:NO]; }); }); } return self; } - (void)loadView { [super loadView]; [self initUI]; } - (void)viewDidLoad { [super viewDidLoad]; self.datas = [NSMutableArray array]; self.resultDics = [NSMutableArray array]; __block typeof(self) blockSelf = self; [KMDocumentAIManager defaultManager].delegate = self; self.pdfPreView.callback = ^(NSRect recognitionRect, CPDFPage *page) { if (!CGRectEqualToRect(recognitionRect, CGRectZero) && blockSelf.pdfPreView.isRecognitionErea) { [blockSelf.datas removeAllObjects]; [blockSelf.datas addObject:page]; blockSelf.recognitionRect = recognitionRect; CPDFPage *copyPage = [page copy]; [copyPage setBounds:recognitionRect forBox:CPDFDisplayCropBox]; NSImage * image = [[NSImage alloc] initWithSize:recognitionRect.size]; [image lockFocus]; [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh]; CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; [copyPage drawWithBox:CPDFDisplayCropBox toContext:context]; [image unlockFocus]; // [[KMDocumentAIManager defaultManager] recognitionImages:@[image] withModelType:blockSelf.modelType]; } }; } - (void)initUI { self.scanView.hidden = YES; self.scanView.frame = CGRectMake(CGRectGetWidth(self.view.bounds),20, 226, 53); self.scanView.wantsLayer = YES; self.scanView.layer.backgroundColor = [NSColor colorWithSRGBRed:54/255.0 green:56/255.0 blue:59/255.0 alpha:1].CGColor; self.scanView.layer.cornerRadius = 4; self.scanTipLabel.textColor = [NSColor whiteColor]; [self.view addSubview:self.scanView]; [self.scanView mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.right.equalTo(self.view.mas_right).offset(-20); make.width.offset(226); make.height.offset(53); }]; self.rightView.hidden = YES; self.rightTitleLabel.stringValue = NSLocalizedString(@"OCR Text Recognition", nil); self.pageRecognitionTitle.stringValue = NSLocalizedString(@"Page Recognition", nil); self.areaRecognitionTitle.stringValue = NSLocalizedString(@"Area Recognition", nil); self.textRecognitionSetLabel.stringValue = NSLocalizedString(@"Text Recognition Settings", nil); self.pageRecognitionSetLabel.stringValue = NSLocalizedString(@"Page Range", nil); self.topTitleLabel.stringValue = NSLocalizedString(@"This file is an image file, do you need to perform OCR?", nil); self.languagePopButton.type = KMOCRComboBoxType_None; self.pageRangePopButton.type = KMOCRComboBoxType_None; self.languagePopButton.cell.focusRingType = NSFocusRingTypeNone; self.pageRangePopButton.cell.focusRingType = NSFocusRingTypeNone; self.OCRButton.wantsLayer = self.topView.wantsLayer = self.rightView.wantsLayer = YES; self.rightView.layer.backgroundColor = [NSColor colorWithSRGBRed:247.0/255.0 green:248.0/255.0 blue:250.0/255.0 alpha:1].CGColor; self.topView.layer.backgroundColor = [NSColor colorWithSRGBRed:189.0/255.0 green:223.0/255.0 blue:253.0/255.0 alpha:1].CGColor; self.pageRecognitionBox.fillColor = self.areaRecognitionBox.fillColor = [NSColor whiteColor]; self.pageRecognitionBox.borderColor = self.areaRecognitionBox.borderColor = [NSColor colorWithSRGBRed:223.0/255.0 green:225.0/255.0 blue:229.0/255.0 alpha:1]; self.languageSetView.hidden = self.rangeSetView.hidden = YES; self.OCRButton.layer.backgroundColor = [NSColor blueColor].CGColor; self.OCRButton.layer.cornerRadius = 4; [self.OCRButton setTitle:NSLocalizedString(@"OCR", nil)]; [self.OCRButton setTitleColorWithColor:[NSColor whiteColor] font:nil]; self.OCRButton.enabled = NO; self.ocrTipView.hidden = YES; self.ocrTipView.wantsLayer = YES; self.ocrTipView.layer.backgroundColor = [NSColor colorWithSRGBRed:255.0/255.0 green:241.0/255.0 blue:193.0/255.0 alpha:1].CGColor; self.ocrTipLabel.stringValue = NSLocalizedString(@"A page will only record the last OCR result and will not display multiple results.", nil); [self.languagePopButton removeAllItems]; NSArray *languages = @[@"Chinese Simplified",@"Chinese Traditional",@"English",@"Japanese",@"Korean"]; for (NSString *language in languages) { [self.languagePopButton addItemWithObjectValue:language]; } [self.languagePopButton selectItemAtIndex:0]; [self.languagePopButton setEditable:NO]; self.pageRangePopButton.delegate = nil; [self.pageRangePopButton removeAllItems]; [self.pageRangePopButton addItemsWithObjectValues:@[NSLocalizedString(@"All Pages", nil), NSLocalizedString(@"Odd Pages Only", nil), NSLocalizedString(@"Even Pages Only",nil), NSLocalizedString(@"e.g. 1,3-5,10",nil)]]; [self.pageRangePopButton.cell setPlaceholderString:NSLocalizedString(@"e.g. 1,3-5,10", nil)]; [self.pageRangePopButton selectItemAtIndex:0]; [self.pageRangePopButton setEditable:NO]; self.pageRangePopButton.delegate = self; self.pageRecognitionBox.mouseDownCallback = ^(BOOL downEntered, KMOCRBox *mouseBox) { if (downEntered) { if (self.languageSetView.hidden || self.rangeSetView.hidden) { self.pageRecognitionBox.borderColor = [NSColor colorWithSRGBRed:23.0/255.0 green:12.0/255.0 blue:244.0/255.0 alpha:1]; self.areaRecognitionBox.borderColor = [NSColor colorWithSRGBRed:223.0/255.0 green:225.0/255.0 blue:229.0/255.0 alpha:1]; self.pageRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRPageSelect"]; self.areaRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRArea"]; self.languageSetView.hidden = self.rangeSetView.hidden = NO; self.OCRButton.enabled = YES; self.ocrTipView.hidden = NO; } else { self.pageRecognitionBox.borderColor = self.areaRecognitionBox.borderColor = [NSColor colorWithSRGBRed:223.0/255.0 green:225.0/255.0 blue:229.0/255.0 alpha:1]; self.areaRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRArea"]; self.pageRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRPage"]; self.languageSetView.hidden = self.rangeSetView.hidden = YES; self.OCRButton.enabled = NO; self.ocrTipView.hidden = YES; } self.pdfPreView.isRecognitionErea = NO; } }; self.areaRecognitionBox.mouseDownCallback = ^(BOOL downEntered, KMOCRBox *mouseBox) { if (downEntered) { if(!self.languageSetView.hidden && self.rangeSetView.hidden) { self.pageRecognitionBox.borderColor = self.areaRecognitionBox.borderColor = [NSColor colorWithSRGBRed:223.0/255.0 green:225.0/255.0 blue:229.0/255.0 alpha:1]; self.areaRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRArea"]; self.pageRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRPage"]; self.languageSetView.hidden = self.rangeSetView.hidden = YES; self.OCRButton.enabled = NO; self.ocrTipView.hidden = YES; self.pdfPreView.isRecognitionErea = NO; } else { self.areaRecognitionBox.borderColor = [NSColor colorWithSRGBRed:23.0/255.0 green:12.0/255.0 blue:244.0/255.0 alpha:1]; self.pageRecognitionBox.borderColor = [NSColor colorWithSRGBRed:223.0/255.0 green:225.0/255.0 blue:229.0/255.0 alpha:1]; self.pageRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRPage"]; self.areaRecognitionImageView.image = [NSImage imageNamed:@"KMImageNameOCRAreaSelect"]; self.languageSetView.hidden = NO; // [self recognitionPartModelWithModelType:self.languagePopButton.indexOfSelectedItem+1]; self.rangeSetView.hidden = YES; self.OCRButton.enabled = NO; self.ocrTipView.hidden = NO; } } }; self.pdfPreView.delegate = self; [self closeTopViewAction:nil]; } - (void)updateToolState:(BOOL)isOCR { self.rightView.hidden = !isOCR; self.isContinusOCR = !self.rightView.hidden; } - (IBAction)closeScanViewAction:(id)sender { } - (IBAction)closeTopViewAction:(id)sender { self.topView.hidden = YES; self.tipConstraint.constant = 0; } - (IBAction)seleclanguageAction:(id)sender { if(!self.languageSetView.hidden && self.rangeSetView.hidden) { // [self recognitionPartModelWithModelType:self.languagePopButton.indexOfSelectedItem+1]; } } - (IBAction)selectPageRangeAction:(KMOCRComboBox *)sender { if (sender.indexOfSelectedItem == 3) { self.pageRangePopButton.stringValue = @""; [self.pageRangePopButton setEditable:YES]; } else { [self.pageRangePopButton setEditable:NO]; } } - (IBAction)OCRDone:(id)sender { //避免范围提示弹框弹2次 NSMutableArray * pages = [NSMutableArray array]; if(0 == [_pageRangePopButton indexOfSelectedItem]){ for (NSUInteger i = 0; i0) { self.pagesString = [pages componentsJoinedByString:@","]; } else { self.pagesString = nil; } if (self.pagesString) { // [self recognitionPageString:self.pagesString withModelType:self.languagePopButton.indexOfSelectedItem+1]; } } - (void)enteredIncreaseAllPage { NSMutableArray *images = [NSMutableArray array]; for(NSInteger i = 0;i=result.textBounds.size.width || strSize.height>=result.textBounds.size.height)) { // fontsize += 1.0; // font = [NSFont systemFontOfSize:fontsize]; // strSize = [strChar sizeWithAttributes:@{NSFontAttributeName:font}]; // } // NSFont *drawFont = [NSFont systemFontOfSize:fontsize-1]; // // NSDictionary *dic = @{NSFontAttributeName:drawFont}; // // [page addStringBounds:result.textBounds withString:result.text withAttributes:dic]; // } } } } - (void)controlTextDidEndEditing:(NSNotification *)obj { if ([obj.object isEqual:self.pageRangePopButton]) { if (self.pageRangePopButton.indexOfSelectedItem == -1) { if (![self checkPageRangeValidate:self.pageRangePopButton.stringValue]) { NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:[NSString stringWithFormat:@"%@ %@",[self.pdfPreView.document.documentURL.lastPathComponent lastPathComponent],NSLocalizedString(@"Invalid page range or the page number is out of range. Please try again.", nil)]]; [alert runModal]; [self.view.window makeFirstResponder:self.pageRangePopButton]; return; } else { self.pagesString = self.pageRangePopButton.stringValue; } } } } - (BOOL)checkPageRangeValidate:(NSString *)pageRangeString { KMFileAttribute *fileAttribute = [[KMFileAttribute alloc] init]; fileAttribute.filePath = [self.pdfPreView.document.documentURL path]; fileAttribute.bAllPage = NO; fileAttribute.pagesString = self.pageRangePopButton.stringValue; if (!fileAttribute.fetchSelectPages) { return NO; } return YES; } #pragma mark - CPDFViewDelegate - (void)PDFViewDocumentDidLoaded:(CPDFView *)pdfView { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ BOOL isImageDocument = [self.pdfPreView.document isImageDocument]; if(isImageDocument) { dispatch_async(dispatch_get_main_queue(), ^{ self.topView.hidden = NO; self.tipConstraint.constant = 32; }); } }); } #pragma mark - KMDocumentAIManagerDelegate - (void)documentAIManagerDidStart:(KMDocumentAIManager *)manager { if(self.isContinusOCR) { self.rightView.hidden = YES; } self.scanView.hidden = NO; [self.pdfPreView clearOCRResult]; [self showWaitting]; } - (void)documentAIDidFinish:(KMDocumentAIManager *)manager { if(self.isContinusOCR) { self.rightView.hidden = NO; } self.scanView.hidden = YES; [self hideWaitting]; } - (void)documentAIManager:(KMDocumentAIManager *)manager didStartImageAtIndex:(NSInteger)index { } //- (void)documentAIManager:(KMDocumentAIManager *)manager didFinishOCRImageAtIndex:(NSInteger)index results:(NSArray *)results { // CPDFPage *page = self.datas[index]; // NSInteger pageIndex = [self.preDocument indexForPage:page]; // // NSMutableDictionary *dic = [NSMutableDictionary dictionary]; // [dic setValue:@(pageIndex) forKey:@"page"]; // NSMutableDictionary *recognitionDic = [NSMutableDictionary dictionary]; // // CGRect recognitionRect = page.bounds; // if(self.pdfPreView.isRecognitionErea) { // NSMutableArray *tResults = [NSMutableArray array]; // for (COCRResult * result in results) { // CGRect rect = result.textBounds; // rect.origin.x += self.recognitionRect.origin.x; // rect.origin.y += self.recognitionRect.origin.y; // result.textBounds = rect; // [tResults addObject:result]; // } // recognitionRect = self.recognitionRect; // results = tResults; // } // // NSValue *value = [NSValue valueWithRect:recognitionRect]; // [dic setValue:value forKey:@"recognitionRect"]; // [dic setValue:results forKey:@"results"]; // // [self.resultDics addObject:dic]; // self.pdfPreView.resultDics = self.resultDics; // if(pageIndex == self.pdfPreView.currentPageIndex) { // [self.pdfPreView updateResult:results recognitionRect:recognitionRect]; // } // float allPages = [[NSString stringWithFormat:@"%lu",(unsigned long)self.datas.count] floatValue]; // self.progressIndicator.doubleValue = (index / allPages) * 100 ; // [self hideWaitting]; //} - (void)imageEngineManager:(KMDocumentAIManager *)manager didFinishCIImageAtIndex:(NSInteger)index outImage:(NSString *)filePath { NSImage *image = [[NSImage alloc]initWithContentsOfURL:[NSURL fileURLWithPath:filePath]]; BOOL success = [self.preDocument insertPage:image.size withImage:filePath atIndex:index]; CPDFPage *page = [self.preDocument pageAtIndex:index]; [self.datas replaceObjectAtIndex:index withObject:page]; if(success) { [self.preDocument removePageAtIndex:index+1]; } self.pdfPreView.document = self.preDocument; [self.pdfPreView layoutDocumentView]; [self hideWaitting]; } - (void)documentAIManager:(KMDocumentAIManager *)manager didFailureImageAtIndex:(NSInteger)index error:(NSError *)error { [self hideWaitting]; } #pragma mark - CPDFViewDelegate - (void)PDFViewCurrentPageDidChanged:(CPDFView *)pdfView { if ([self.documentAIViewDelegate respondsToSelector:@selector(documentAIViewController:currentPageDidChanged:)]) { [self.documentAIViewDelegate documentAIViewController:self currentPageDidChanged:pdfView]; } for (NSDictionary *dic in self.resultDics) { NSNumber *num = [dic objectForKey:@"page"]; if(num.integerValue == self.pdfPreView.currentPageIndex) { NSValue *value = [dic objectForKey:@"recognitionRect"]; // [self.pdfPreView updateResult:[dic objectForKey:@"results"] recognitionRect:value.rectValue]; } } } - (void)PDFViewScaleDidChanged:(CPDFView *)pdfView { if ([self.documentAIViewDelegate respondsToSelector:@selector(documentAIViewController:scaleDidChanged:)]) { [self.documentAIViewDelegate documentAIViewController:self scaleDidChanged:pdfView]; } } #pragma mark - show / hide Waiting - (void)showWaitting { if (!_posterMaskView) { _posterMaskView = [[KMBookletMaskView alloc] initWithFrame:NSMakeRect(0, 0, self.view.window.frame.size.width, self.view.window.frame.size.height)]; } [self.view.window.contentView addSubview:self.posterMaskView]; } - (void)hideWaitting{ [self.posterMaskView removeFromSuperview]; } @end