Skip to content

Commit

Permalink
If user navigates away from a page before OCR completes, then cancel …
Browse files Browse the repository at this point in the history
…the OCR task. Tested on 13 page Japanese document.
  • Loading branch information
DavidPhillipOster authored and MaddTheSane committed Jun 5, 2022
1 parent bb5e1de commit 39eb54e
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
15 changes: 12 additions & 3 deletions Classes/Session/OCRVision/OCRTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ @interface OCRDatum : NSObject

@property(weak) NSImage *image;

/// non-nil while this is actively OCRing.
@property OCRVision *activeOCR API_AVAILABLE(macos(10.15));

@property(weak) CALayer *selectionLayer;

/// <VNRecognizedTextObservation *> - 10.15 and newer
Expand Down Expand Up @@ -317,16 +320,18 @@ - (CGRect)boundBoxOfPiece:(VNRecognizedTextObservation *)piece range:(NSRange)ch
- (void)ocrDidFinish:(id<OCRVisionResults>)results image:(NSImage *)image index:(NSInteger)index
{
NSArray *textPieces = @[];
NSError *error = results.ocrError;
if (@available(macOS 10.15, *)) {
self.datums[index].activeOCR = nil;
textPieces = results.textObservations;
}
// Since we are changing state that affects the U.I., we do it on the main thread in the future,
// but `complete` isn't guaranteed to exist then, so we assign to locals so it will be captured
// by the block.
dispatch_async(dispatch_get_main_queue(), ^{
OCRDatum *datum = self.datums[index];
datum.image = image;
datum.textPieces = textPieces;
datum.image = (error == nil) ? image : nil;
datum.textPieces = (error == nil) ? textPieces : @[];
[datum.selectionPieces removeAllObjects];
[self.view setNeedsDisplay:YES];
self.needsInvalidateCursorRects = YES;
Expand All @@ -338,14 +343,18 @@ - (void)ocrImage:(NSImage *)image index:(NSInteger)index
if (@available(macOS 10.15, *)) {
OCRDatum *datum = self.datums[index];
datum.image = nil;
[datum.activeOCR cancel];
datum.activeOCR = nil;
datum.textPieces = @[];
[datum.selectionPieces removeAllObjects];
if (image)
{
__block OCRVision *ocrVision = [[OCRVision alloc] init];
datum.activeOCR = ocrVision;
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
[ocrVision ocrImage:image completion:^(id<OCRVisionResults> _Nonnull complete) {
[self ocrDidFinish:complete image:image index:index];
[weakSelf ocrDidFinish:complete image:image index:index];
ocrVision = nil;
}];
});
Expand Down
3 changes: 3 additions & 0 deletions Classes/Session/OCRVision/OCRVision.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ API_AVAILABLE(macos(10.15))
/// @param completion - a block passed an object that corresponds to the OCRVision protocol.
- (void)ocrCGImage:(CGImageRef)cgImage completion:(void (^)(id<OCRVisionResults> _Nonnull ocrResults))completion;

/// if an OCR task is currently running, attempt to cancel it. Always safe to call.
- (void)cancel;

@end

NS_ASSUME_NONNULL_END
18 changes: 17 additions & 1 deletion Classes/Session/OCRVision/OCRVision.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

/// Rather than allocate a new object to pass the results, just make the OCRVision object do double duty.
@interface OCRVision()<OCRVisionResults>

/// non nil while processing the request
///
/// Assumes caller will create a new OCRVision for each image to analyze.
@property(nullable) VNRecognizeTextRequest *activeTextRequest;

@property(readwrite) NSArray<VNRecognizedTextObservation *> *textObservations;
@property(readwrite, nullable, setter=setOCRError:) NSError *ocrError;
@end
Expand Down Expand Up @@ -110,6 +116,10 @@ - (void)handleTextRequest:(nullable VNRequest *)request
else if ([request isKindOfClass:[VNRecognizeTextRequest class]])
{
VNRecognizeTextRequest *textRequests = (VNRecognizeTextRequest *)request;
if (textRequests == self.activeTextRequest)
{
self.activeTextRequest = nil;
}
NSMutableArray<VNRecognizedTextObservation *> *pieces = [NSMutableArray array];
NSArray *results = textRequests.results;
for (id rawResult in results)
Expand Down Expand Up @@ -152,9 +162,10 @@ - (void)ocrCGImage:(CGImageRef)cgImage completion:(void (^)(id<OCRVisionResults>
}
NSError *error = nil;
VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithCGImage:cgImage options:@{}];
self.activeTextRequest = textRequest;
if (![handler performRequests:@[textRequest] error:&error])
{
[self callCompletion:completion observations:@[] error:error];
[weakSelf callCompletion:completion observations:@[] error:error];
}
} else {
NSString *desc = @"Could not create text request";
Expand Down Expand Up @@ -184,4 +195,9 @@ - (void)ocrImage:(NSImage *)image completion:(void (^)(id<OCRVisionResults> _Non
}
}

- (void)cancel
{
[self.activeTextRequest cancel];
}

@end

0 comments on commit 39eb54e

Please sign in to comment.