// // KMGOCRManager.m // // // // // #import "KMGOCRManager.h" #import #import #import #import #define KMImageScale 4.0 //#import "KMOCRPreferences.h" //恢复OCR架上版本样式 /* https://cloud.google.com/vision/reference/rest/v1/images/annotate#AnnotateImageResponse languageHints[] List of languages to use for TEXT_DETECTION. In most cases, an empty value yields the best results since it enables automatic language detection. For languages based on the Latin alphabet, setting languageHints is not needed. In rare cases, when the language of the text in the image is known, setting a hint will help get better results (although it will be a significant hindrance if the hint is wrong). Text detection returns an error if one or more of the specified languages is not one of the supported languages. */ NSString * KMGOCRLanguageCodeKey = @"KMGOCRLanguageCodeKey"; NSString * KMGOCRLanguageStringKey = @"KMGOCRLanguageStringKey"; #pragma mark - KMGOCRResult @class KMOCROperationQueue; @interface KMGOCRResult () @end @implementation KMGOCRResult - (void)dealloc { } @end #pragma mark - KMGOCRManager @interface KMGOCRManager () @property (nonatomic, retain) NSMutableArray *languages; @property (nonatomic, assign) NSString *fileType; @property (nonatomic, retain) NSMutableArray *ocrPath; @property (nonatomic, retain) NSURL *filePath; @property (nonatomic, assign) NSUInteger finishIndex; //@property (nonatomic, retain) KMOCRPreferences *ocrPreferences; //恢复OCR架上版本样式 @property (nonatomic,retain) VNRecognizeTextRequest *appleRequest; @property (nonatomic, assign) VNRequestTextRecognitionLevel appleRecognitionMode; @property (nonatomic,retain) NSMutableArray *images; @end @implementation KMGOCRManager #pragma mark - Init Methods - (id)init { if (self = [super init]) { } return self; } - (void)dealloc { _delegate = nil; if (@available(macOS 10.15, *)) { } } #pragma mark - Public Methods + (KMGOCRManager *)defaultManager { static KMGOCRManager *singleton = nil; static dispatch_once_t pred; dispatch_once(&pred, ^{ singleton = [[KMGOCRManager alloc] init]; singleton.OCRType = KMOCRType_Google; }); return singleton; } + (NSArray *)languages { if ([KMGOCRManager defaultManager].OCRType == KMOCRType_Google) { return @[@{KMGOCRLanguageCodeKey:@"af", KMGOCRLanguageStringKey:@"Afrikaans"}, @{KMGOCRLanguageCodeKey:@"sq", KMGOCRLanguageStringKey:@"Albanian"}, @{KMGOCRLanguageCodeKey:@"ar", KMGOCRLanguageStringKey:@"Arabic"}, @{KMGOCRLanguageCodeKey:@"hy", KMGOCRLanguageStringKey:@"Armenian"}, @{KMGOCRLanguageCodeKey:@"az", KMGOCRLanguageStringKey:@"Azerbaijani"}, @{KMGOCRLanguageCodeKey:@"eu", KMGOCRLanguageStringKey:@"Basque"}, @{KMGOCRLanguageCodeKey:@"be", KMGOCRLanguageStringKey:@"Belarusian"}, @{KMGOCRLanguageCodeKey:@"bn", KMGOCRLanguageStringKey:@"Bengali"}, @{KMGOCRLanguageCodeKey:@"bs", KMGOCRLanguageStringKey:@"Bosnian"}, @{KMGOCRLanguageCodeKey:@"bg", KMGOCRLanguageStringKey:@"Bulgarian"}, @{KMGOCRLanguageCodeKey:@"ca", KMGOCRLanguageStringKey:@"Catalan"}, @{KMGOCRLanguageCodeKey:@"ceb", KMGOCRLanguageStringKey:@"Cebuano"}, @{KMGOCRLanguageCodeKey:@"ny", KMGOCRLanguageStringKey:@"Chichewa"}, @{KMGOCRLanguageCodeKey:@"zh-CN", KMGOCRLanguageStringKey:@"Chinese Simplified"}, @{KMGOCRLanguageCodeKey:@"zh-TW", KMGOCRLanguageStringKey:@"Chinese Traditional"}, @{KMGOCRLanguageCodeKey:@"hr", KMGOCRLanguageStringKey:@"Croatian"}, @{KMGOCRLanguageCodeKey:@"cs", KMGOCRLanguageStringKey:@"Czech"}, @{KMGOCRLanguageCodeKey:@"da", KMGOCRLanguageStringKey:@"Danish"}, @{KMGOCRLanguageCodeKey:@"nl", KMGOCRLanguageStringKey:@"Dutch"}, @{KMGOCRLanguageCodeKey:@"en", KMGOCRLanguageStringKey:@"English"}, @{KMGOCRLanguageCodeKey:@"eo", KMGOCRLanguageStringKey:@"Esperanto"}, @{KMGOCRLanguageCodeKey:@"et", KMGOCRLanguageStringKey:@"Estonian"}, @{KMGOCRLanguageCodeKey:@"tl", KMGOCRLanguageStringKey:@"Filipino"}, @{KMGOCRLanguageCodeKey:@"fi", KMGOCRLanguageStringKey:@"Finnish"}, @{KMGOCRLanguageCodeKey:@"fr", KMGOCRLanguageStringKey:@"French"}, @{KMGOCRLanguageCodeKey:@"gl", KMGOCRLanguageStringKey:@"Galician"}, @{KMGOCRLanguageCodeKey:@"ka", KMGOCRLanguageStringKey:@"Georgian"}, @{KMGOCRLanguageCodeKey:@"de", KMGOCRLanguageStringKey:@"German"}, @{KMGOCRLanguageCodeKey:@"el", KMGOCRLanguageStringKey:@"Greek"}, @{KMGOCRLanguageCodeKey:@"gu", KMGOCRLanguageStringKey:@"Gujarati"}, @{KMGOCRLanguageCodeKey:@"ht", KMGOCRLanguageStringKey:@"Haitian Creole"}, @{KMGOCRLanguageCodeKey:@"ha", KMGOCRLanguageStringKey:@"Hausa"}, @{KMGOCRLanguageCodeKey:@"iw", KMGOCRLanguageStringKey:@"Hebrew"}, @{KMGOCRLanguageCodeKey:@"hi", KMGOCRLanguageStringKey:@"Hindi"}, @{KMGOCRLanguageCodeKey:@"hmn", KMGOCRLanguageStringKey:@"Hmong"}, @{KMGOCRLanguageCodeKey:@"hu", KMGOCRLanguageStringKey:@"Hungarian"}, @{KMGOCRLanguageCodeKey:@"is", KMGOCRLanguageStringKey:@"Icelandic"}, @{KMGOCRLanguageCodeKey:@"ig", KMGOCRLanguageStringKey:@"Igbo"}, @{KMGOCRLanguageCodeKey:@"id", KMGOCRLanguageStringKey:@"Indonesian"}, @{KMGOCRLanguageCodeKey:@"ga", KMGOCRLanguageStringKey:@"Irish"}, @{KMGOCRLanguageCodeKey:@"it", KMGOCRLanguageStringKey:@"Italian"}, @{KMGOCRLanguageCodeKey:@"ja", KMGOCRLanguageStringKey:@"Japanese"}, @{KMGOCRLanguageCodeKey:@"jw", KMGOCRLanguageStringKey:@"Javanese"}, @{KMGOCRLanguageCodeKey:@"kn", KMGOCRLanguageStringKey:@"Kannada"}, @{KMGOCRLanguageCodeKey:@"kk", KMGOCRLanguageStringKey:@"Kazakh"}, @{KMGOCRLanguageCodeKey:@"km", KMGOCRLanguageStringKey:@"Khmer"}, @{KMGOCRLanguageCodeKey:@"ko", KMGOCRLanguageStringKey:@"Korean"}, @{KMGOCRLanguageCodeKey:@"lo", KMGOCRLanguageStringKey:@"Lao"}, @{KMGOCRLanguageCodeKey:@"la", KMGOCRLanguageStringKey:@"Latin"}, @{KMGOCRLanguageCodeKey:@"lv", KMGOCRLanguageStringKey:@"Latvian"}, @{KMGOCRLanguageCodeKey:@"lt", KMGOCRLanguageStringKey:@"Lithuanian"}, @{KMGOCRLanguageCodeKey:@"mk", KMGOCRLanguageStringKey:@"Macedonian"}, @{KMGOCRLanguageCodeKey:@"mg", KMGOCRLanguageStringKey:@"Malagasy"}, @{KMGOCRLanguageCodeKey:@"ms", KMGOCRLanguageStringKey:@"Malay"}, @{KMGOCRLanguageCodeKey:@"ml", KMGOCRLanguageStringKey:@"Malayalam"}, @{KMGOCRLanguageCodeKey:@"mt", KMGOCRLanguageStringKey:@"Maltese"}, @{KMGOCRLanguageCodeKey:@"mi", KMGOCRLanguageStringKey:@"Maori"}, @{KMGOCRLanguageCodeKey:@"mr", KMGOCRLanguageStringKey:@"Marathi"}, @{KMGOCRLanguageCodeKey:@"mn", KMGOCRLanguageStringKey:@"Mongolian"}, @{KMGOCRLanguageCodeKey:@"my", KMGOCRLanguageStringKey:@"Myanmar (Burmese)"}, @{KMGOCRLanguageCodeKey:@"ne", KMGOCRLanguageStringKey:@"Nepali"}, @{KMGOCRLanguageCodeKey:@"no", KMGOCRLanguageStringKey:@"Norwegian"}, @{KMGOCRLanguageCodeKey:@"fa", KMGOCRLanguageStringKey:@"Persian"}, @{KMGOCRLanguageCodeKey:@"pl", KMGOCRLanguageStringKey:@"Polish"}, @{KMGOCRLanguageCodeKey:@"pt", KMGOCRLanguageStringKey:@"Portuguese"}, @{KMGOCRLanguageCodeKey:@"ma", KMGOCRLanguageStringKey:@"Punjabi"}, @{KMGOCRLanguageCodeKey:@"ro", KMGOCRLanguageStringKey:@"Romanian"}, @{KMGOCRLanguageCodeKey:@"ru", KMGOCRLanguageStringKey:@"Russian"}, @{KMGOCRLanguageCodeKey:@"sr", KMGOCRLanguageStringKey:@"Serbian"}, @{KMGOCRLanguageCodeKey:@"st", KMGOCRLanguageStringKey:@"Sesotho"}, @{KMGOCRLanguageCodeKey:@"si", KMGOCRLanguageStringKey:@"Sinhala"}, @{KMGOCRLanguageCodeKey:@"sk", KMGOCRLanguageStringKey:@"Slovak"}, @{KMGOCRLanguageCodeKey:@"sl", KMGOCRLanguageStringKey:@"Slovenian"}, @{KMGOCRLanguageCodeKey:@"so", KMGOCRLanguageStringKey:@"Somali"}, @{KMGOCRLanguageCodeKey:@"es", KMGOCRLanguageStringKey:@"Spanish"}, @{KMGOCRLanguageCodeKey:@"su", KMGOCRLanguageStringKey:@"Sudanese"}, @{KMGOCRLanguageCodeKey:@"sw", KMGOCRLanguageStringKey:@"Swahili"}, @{KMGOCRLanguageCodeKey:@"sv", KMGOCRLanguageStringKey:@"Swedish"}, @{KMGOCRLanguageCodeKey:@"tg", KMGOCRLanguageStringKey:@"Tajik"}, @{KMGOCRLanguageCodeKey:@"ta", KMGOCRLanguageStringKey:@"Tamil"}, @{KMGOCRLanguageCodeKey:@"te", KMGOCRLanguageStringKey:@"Telugu"}, @{KMGOCRLanguageCodeKey:@"th", KMGOCRLanguageStringKey:@"Thai"}, @{KMGOCRLanguageCodeKey:@"tr", KMGOCRLanguageStringKey:@"Turkish"}, @{KMGOCRLanguageCodeKey:@"uk", KMGOCRLanguageStringKey:@"Ukrainian"}, @{KMGOCRLanguageCodeKey:@"ur", KMGOCRLanguageStringKey:@"Urdu"}, @{KMGOCRLanguageCodeKey:@"uz", KMGOCRLanguageStringKey:@"Uzbek"}, @{KMGOCRLanguageCodeKey:@"vi", KMGOCRLanguageStringKey:@"Vietnamese"}, @{KMGOCRLanguageCodeKey:@"cy", KMGOCRLanguageStringKey:@"Welsh"}, @{KMGOCRLanguageCodeKey:@"yi", KMGOCRLanguageStringKey:@"Yiddish"}, @{KMGOCRLanguageCodeKey:@"yo", KMGOCRLanguageStringKey:@"Yoruba"}, @{KMGOCRLanguageCodeKey:@"zu", KMGOCRLanguageStringKey:@"Zulu"}]; } else if ([KMGOCRManager defaultManager].OCRType == KMOCRType_ComPDFKit_Conversion) { return @[@{KMGOCRLanguageCodeKey:@"0", KMGOCRLanguageStringKey:@"Chinese"}, @{KMGOCRLanguageCodeKey:@"1", KMGOCRLanguageStringKey:@"ChineseTraditional"}, @{KMGOCRLanguageCodeKey:@"2", KMGOCRLanguageStringKey:@"English"}, @{KMGOCRLanguageCodeKey:@"3", KMGOCRLanguageStringKey:@"Japanese"}, @{KMGOCRLanguageCodeKey:@"4", KMGOCRLanguageStringKey:@"Korean"}, @{KMGOCRLanguageCodeKey:@"5", KMGOCRLanguageStringKey:@"Serbian"}, @{KMGOCRLanguageCodeKey:@"6", KMGOCRLanguageStringKey:@"Occitan"}, @{KMGOCRLanguageCodeKey:@"7", KMGOCRLanguageStringKey:@"Danish"}, @{KMGOCRLanguageCodeKey:@"8", KMGOCRLanguageStringKey:@"German"}, @{KMGOCRLanguageCodeKey:@"9", KMGOCRLanguageStringKey:@"French"}, @{KMGOCRLanguageCodeKey:@"10", KMGOCRLanguageStringKey:@"Italian"}, @{KMGOCRLanguageCodeKey:@"11", KMGOCRLanguageStringKey:@"Spanish"}, @{KMGOCRLanguageCodeKey:@"12", KMGOCRLanguageStringKey:@"Portuguese"}, @{KMGOCRLanguageCodeKey:@"13", KMGOCRLanguageStringKey:@"Maori"}, @{KMGOCRLanguageCodeKey:@"14", KMGOCRLanguageStringKey:@"Malay"}, @{KMGOCRLanguageCodeKey:@"15", KMGOCRLanguageStringKey:@"Maltese"}, @{KMGOCRLanguageCodeKey:@"16", KMGOCRLanguageStringKey:@"Dutch"}, @{KMGOCRLanguageCodeKey:@"17", KMGOCRLanguageStringKey:@"Norwegian"}, @{KMGOCRLanguageCodeKey:@"18", KMGOCRLanguageStringKey:@"Polish"}, @{KMGOCRLanguageCodeKey:@"19", KMGOCRLanguageStringKey:@"Romanian"}, @{KMGOCRLanguageCodeKey:@"20", KMGOCRLanguageStringKey:@"Slovak"}, @{KMGOCRLanguageCodeKey:@"21", KMGOCRLanguageStringKey:@"Slovenian"}, @{KMGOCRLanguageCodeKey:@"22", KMGOCRLanguageStringKey:@"Albanian"}, @{KMGOCRLanguageCodeKey:@"23", KMGOCRLanguageStringKey:@"Swedish"}, @{KMGOCRLanguageCodeKey:@"24", KMGOCRLanguageStringKey:@"Swahili"}, @{KMGOCRLanguageCodeKey:@"25", KMGOCRLanguageStringKey:@"Tagalog"}, @{KMGOCRLanguageCodeKey:@"26", KMGOCRLanguageStringKey:@"Turish"}, @{KMGOCRLanguageCodeKey:@"27", KMGOCRLanguageStringKey:@"Uzbek"}, @{KMGOCRLanguageCodeKey:@"28", KMGOCRLanguageStringKey:@"Vietnamese"}, @{KMGOCRLanguageCodeKey:@"29", KMGOCRLanguageStringKey:@"Afrikaans"}, @{KMGOCRLanguageCodeKey:@"30", KMGOCRLanguageStringKey:@"Azerbaijani"}, @{KMGOCRLanguageCodeKey:@"31", KMGOCRLanguageStringKey:@"Bosnian"}, @{KMGOCRLanguageCodeKey:@"32", KMGOCRLanguageStringKey:@"Czech"}, @{KMGOCRLanguageCodeKey:@"33", KMGOCRLanguageStringKey:@"Welsh"}, @{KMGOCRLanguageCodeKey:@"34", KMGOCRLanguageStringKey:@"Estonian"}, @{KMGOCRLanguageCodeKey:@"35", KMGOCRLanguageStringKey:@"Irish"}, @{KMGOCRLanguageCodeKey:@"36", KMGOCRLanguageStringKey:@"Croatian"}, @{KMGOCRLanguageCodeKey:@"37", KMGOCRLanguageStringKey:@"Hungarian"}, @{KMGOCRLanguageCodeKey:@"38", KMGOCRLanguageStringKey:@"Indonesian"}, @{KMGOCRLanguageCodeKey:@"39", KMGOCRLanguageStringKey:@"Icelandic"}, @{KMGOCRLanguageCodeKey:@"40", KMGOCRLanguageStringKey:@"Kurdish"}, @{KMGOCRLanguageCodeKey:@"41", KMGOCRLanguageStringKey:@"Lithuanian"}, @{KMGOCRLanguageCodeKey:@"42", KMGOCRLanguageStringKey:@"Latvian"}, @{KMGOCRLanguageCodeKey:@"43", KMGOCRLanguageStringKey:@"Marathi"}, @{KMGOCRLanguageCodeKey:@"44", KMGOCRLanguageStringKey:@"Nepali"}, @{KMGOCRLanguageCodeKey:@"45", KMGOCRLanguageStringKey:@"Hindi"}, @{KMGOCRLanguageCodeKey:@"46", KMGOCRLanguageStringKey:@"Bihari"}, @{KMGOCRLanguageCodeKey:@"47", KMGOCRLanguageStringKey:@"Maithili"}, @{KMGOCRLanguageCodeKey:@"48", KMGOCRLanguageStringKey:@"Angika"}, @{KMGOCRLanguageCodeKey:@"49", KMGOCRLanguageStringKey:@"Bhojpuri"}, @{KMGOCRLanguageCodeKey:@"50", KMGOCRLanguageStringKey:@"Magahi"}, @{KMGOCRLanguageCodeKey:@"51", KMGOCRLanguageStringKey:@"Nagpur"}, @{KMGOCRLanguageCodeKey:@"52", KMGOCRLanguageStringKey:@"Newari"}, @{KMGOCRLanguageCodeKey:@"53", KMGOCRLanguageStringKey:@"GoanKonkani"}, @{KMGOCRLanguageCodeKey:@"54", KMGOCRLanguageStringKey:@"SaudiArabia"}]; } return @[@{KMGOCRLanguageCodeKey:@"en-US", KMGOCRLanguageStringKey:@"English"}, @{KMGOCRLanguageCodeKey:@"fr-FR", KMGOCRLanguageStringKey:@"French"}, @{KMGOCRLanguageCodeKey:@"it-IT", KMGOCRLanguageStringKey:@"Italian"}, @{KMGOCRLanguageCodeKey:@"de-DE", KMGOCRLanguageStringKey:@"German"}, @{KMGOCRLanguageCodeKey:@"es-ES", KMGOCRLanguageStringKey:@"Spanish"}, @{KMGOCRLanguageCodeKey:@"pt-BR", KMGOCRLanguageStringKey:@"Portuguese"}, @{KMGOCRLanguageCodeKey:@"zh-Hant", KMGOCRLanguageStringKey:@"Chinese Traditional"}, @{KMGOCRLanguageCodeKey:@"zh-Hans", KMGOCRLanguageStringKey:@"Chinese Simplified"}]; } //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 0) { for (KMGOCROperation *op in queue.operations) { op.operationDelegate = nil; } [queue cancelAll]; } if ([self.delegate respondsToSelector:@selector(GOCRManager:didCancelOCRImageAtIndex:)]) { [self.delegate GOCRManager:self didCancelOCRImageAtIndex:self.finishIndex]; } self.delegate = nil; } #pragma mark - Apple OCR - (void)recognitionAppleImageAtIndex:(NSUInteger)index { if (index >= self.images.count) { if (@available(macOS 10.15, *)) { [_appleRequest cancel]; } _appleRequest = nil; if ([self.delegate respondsToSelector:@selector(GOCRManagerDidFinishOCR:)]) { [self.delegate GOCRManagerDidFinishOCR:self]; } return; } self.finishIndex = index; if ([self.delegate respondsToSelector:@selector(GOCRManager:didStartOCRImageAtIndex:)]) { [self.delegate GOCRManager:self didStartOCRImageAtIndex:self.finishIndex]; } if([self.images[self.finishIndex] isKindOfClass:[NSImage class]]) { [self recognitionAppleImage:self.images[self.finishIndex]]; } else { NSData *data = self.images[self.finishIndex]; NSImage *s = [[NSImage alloc] initWithData:data]; if(_appleRequest) { [_appleRequest cancel]; _appleRequest = nil; } [self recognitionAppleImage:s]; } } - (void)recognitionAppleImage:(NSImage *)image { dispatch_async(dispatch_get_global_queue(0, 0), ^{ if(self->_appleRequest) { [self->_appleRequest cancel]; self->_appleRequest = nil; } __weak typeof(self) weakSelf = self; self->_appleRequest = [[VNRecognizeTextRequest alloc] initWithCompletionHandler:^(VNRequest * _Nonnull request, NSError * _Nullable error) { __strong typeof(weakSelf) strongSelf = weakSelf; NSArray *results = nil; if (request.results.count > 0) { results = [strongSelf responseDataRequest:request dictionary:nil imageSize:image.size]; } NSMutableArray *resultArray = [[NSMutableArray alloc] init]; for (KMGOCRResult *result in results) { NSDictionary *dic = @{@"x":@(result.textBounds.origin.x), @"y":@(result.textBounds.origin.y), @"width":@(result.textBounds.size.width), @"height":@(result.textBounds.size.height), @"text":result.text }; [resultArray addObject:dic]; } dispatch_async(dispatch_get_main_queue(), ^{ if (error || !results) { if (strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(GOCRManager:didFailureOCRImageAtIndex:error:)]) { [strongSelf.delegate GOCRManager:strongSelf didFailureOCRImageAtIndex:strongSelf.finishIndex error:error]; } } else { if (strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(GOCRManager:didFinishOCRImageAtIndex:results:)]) { [strongSelf.delegate GOCRManager:strongSelf didFinishOCRImageAtIndex:strongSelf.finishIndex results:results]; } } [strongSelf recognitionAppleImageAtIndex:strongSelf.finishIndex+1]; }); }]; self->_appleRequest.usesCPUOnly = YES; self->_appleRequest.recognitionLevel = self.appleRecognitionMode; if (self.languages.count > 0) { NSMutableArray *array = [[NSMutableArray alloc] initWithArray:self.languages]; if ([self.languages containsObject:@"zh-Hant"]) { [array removeObject:@"zh-Hant"]; [array insertObject:@"zh-Hant" atIndex:0]; } if ([self.languages containsObject:@"zh-Hans"]) { [array removeObject:@"zh-Hans"]; [array insertObject:@"zh-Hans" atIndex:0]; } self.languages = array; self->_appleRequest.recognitionLanguages = self.languages; }else{ self->_appleRequest.recognitionLanguages = @[@"zh-Hans",@"zh-Hant"]; } NSError *error = nil; CGImageRef imageRef = [self nsImageToCGImageRef:image]; VNImageRequestHandler *handle = [[VNImageRequestHandler alloc] initWithCGImage:imageRef options:@{}]; if (self->_appleRequest){ [handle performRequests:@[self->_appleRequest] error:&error]; } CGImageRelease(imageRef); }); } #pragma mark - GOCRManager Methods - (void)gocrRecognitionImages:(NSArray *)images withLanguages:(NSArray *)languages { if (!images || images.count == 0) { return; } if ([self.delegate respondsToSelector:@selector(GOCRManagerDidStartOCR:)]) { [self.delegate GOCRManagerDidStartOCR:self]; } for (NSUInteger i=0; i 0) { KMGOCRResult *result = [[KMGOCRResult alloc] init]; result.text = OCRStr; if (self.languages.count > 0) { result.locale = self.languages[0]; } result.textBounds = CGRectZero; [results insertObject:result atIndex:0]; } } return results; } - (CGImageRef)nsImageToCGImageRef:(NSImage*)image { NSData *imageData = [image TIFFRepresentation]; CGImageRef imageRef = NULL; if (imageData) { CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL); if (imageSource) { imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); CFRelease(imageSource); // 释放 imageSource } } return imageRef; // 调用者负责释放 } @end @interface KMOCROperationQueue () @end @implementation KMOCROperationQueue - (void)dealloc { } + (instancetype)sharedInstance { static KMOCROperationQueue *sharedInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [KMOCROperationQueue new]; }); return sharedInstance; } - (void)addOCROperation:(NSOperation *)op { [self addOperation:op]; } - (void)cancelAll { [self cancelAllOperations]; } @end