Skip to content

Commit 3a93dbd

Browse files
Move analyzer to parent, only use one object for analysis
1 parent 5416918 commit 3a93dbd

File tree

5 files changed

+96
-25
lines changed

5 files changed

+96
-25
lines changed

BFRImageViewController/BFRImageContainerViewController.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//
88

99
#import <UIKit/UIKit.h>
10+
#import "BFRImageViewer-Swift.h"
1011

1112
typedef NS_ENUM(NSUInteger, BFRImageAssetType) {
1213
BFRImageAssetTypeImage,
@@ -42,6 +43,11 @@ typedef NS_ENUM(NSUInteger, BFRImageAssetType) {
4243

4344
/*! Assigning YES to this property will disable autoplay for live photos when it used with 3DTouch peek feature */
4445
@property (nonatomic, getter=shouldDisableAutoplayForLivePhoto) BOOL disableAutoplayForLivePhoto;
46+
47+
/*! The max scale the image can be maginified at. */
4548
@property (nonatomic, assign) CGFloat imageMaxScale;
4649

50+
/*! Kicks off image analysis if the image has been properly loaded. */
51+
- (void)analyzeImageIfPossible:(LiveTextManager * _Nonnull)manager API_AVAILABLE(ios(16));
52+
4753
@end

BFRImageViewController/BFRImageContainerViewController.m

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#import "BFRBackLoadedImageSource.h"
1111
#import "BFRImageViewerDownloadProgressView.h"
1212
#import "BFRImageViewerConstants.h"
13-
#import "BFRImageViewer-Swift.h"
1413
#import <Photos/Photos.h>
1514
#import <PhotosUI/PhotosUI.h>
1615
#import <PINRemoteImage/PINAnimatedImageView.h>
@@ -50,8 +49,6 @@ @interface BFRImageContainerViewController () <UIScrollViewDelegate, UIGestureRe
5049
/*! Currently, this only shows if a live photo is displayed to avoid gesture recognizer conflicts with playback and sharing. */
5150
@property (strong, nonatomic, nullable) UIBarButtonItem *shareBarButtonItem;
5251

53-
@property (strong, nonatomic, nullable) LiveTextManager *liveTextManager API_AVAILABLE(ios(16));
54-
5552
@end
5653

5754
@implementation BFRImageContainerViewController
@@ -153,6 +150,15 @@ - (void)dealloc {
153150
[[NSNotificationCenter defaultCenter] removeObserver:self];
154151
}
155152

153+
#pragma mark - Public Methods
154+
155+
- (void)analyzeImageIfPossible:(LiveTextManager *)manager {
156+
if (self.imgLoaded && self.imgView) {
157+
[manager analyzeImageViewWithView:self.imgView
158+
image:self.imgLoaded];
159+
}
160+
}
161+
156162
#pragma mark - UI Methods
157163

158164
- (void)createProgressView {
@@ -243,17 +249,6 @@ - (void)createActiveAssetView {
243249
} else {
244250
self.imgView = (PINAnimatedImageView *)resizableImageView;
245251
}
246-
247-
// Live Text
248-
if (@available(iOS 16.0, *)) {
249-
if ([LiveTextManager isLiveTextAvailable] &&
250-
(self.assetType == BFRImageAssetTypeImage || self.assetType == BFRImageAssetTypeRemoteImage)) {
251-
self.liveTextManager = [LiveTextManager new];
252-
[self.liveTextManager analyzeImageViewWithView:self.imgView image:(UIImage *)self.imgLoaded completionHandler:^{
253-
254-
}];
255-
}
256-
}
257252
}
258253

259254
- (void)addImageToScrollView {

BFRImageViewController/BFRImageViewController.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@
3939
/*! Retrieve the index of the currently showing image. */
4040
@property (nonatomic, assign, readonly) NSInteger currentIndex;
4141

42-
/*! Allows you to enable autoplay for peek&play feature on photo live view. Default to YES */
42+
/*! Allows you to enable autoplay for peek&play feature on photo live view. Defaults to YES */
4343
@property (nonatomic, getter=shouldDisableAutoplayForLivePhoto) BOOL disableAutoplayForLivePhoto;
4444

45+
/*! Performs Live Text analysis on the image. Defaults to YES */
46+
@property (nonatomic, getter=shouldPerformLiveTextAnalysis) BOOL performLiveTextAnalysis;
47+
4548
/*! Allows you to set image max scale */
4649
@property (nonatomic, assign) CGFloat maxScale;
4750

BFRImageViewController/BFRImageViewController.m

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#import "BFRImageViewerLocalizations.h"
1212
#import "BFRImageTransitionAnimator.h"
1313
#import "BFRImageViewerConstants.h"
14+
#import "BFRImageViewer-Swift.h"
1415

1516
@interface BFRImageViewController () <UIPageViewControllerDataSource, UIScrollViewDelegate>
1617

@@ -38,6 +39,9 @@ @interface BFRImageViewController () <UIPageViewControllerDataSource, UIScrollVi
3839
/*! This creates the parallax scrolling effect by essentially clipping the scrolled images and moving with the touch point in scrollViewDidScroll. */
3940
@property (strong, nonatomic, nonnull) UIView *parallaxView;
4041

42+
/*! Analyzes images for Live Text detectors. */
43+
@property (strong, nonatomic, nullable) LiveTextManager *liveTextManager API_AVAILABLE(ios(16));
44+
4145
@end
4246

4347
@implementation BFRImageViewController
@@ -75,7 +79,13 @@ - (void)commonInit {
7579
self.enableDoneButton = YES;
7680
self.showDoneButtonOnLeft = YES;
7781
self.disableAutoplayForLivePhoto = YES;
82+
self.performLiveTextAnalysis = YES;
7883
self.parallaxView = [UIView new];
84+
85+
// Add Live Text analysis
86+
if (@available(iOS 16.0, *)) {
87+
self.liveTextManager = [LiveTextManager new];
88+
}
7989
}
8090

8191
#pragma mark - View Lifecycle
@@ -273,6 +283,32 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
273283
[self updateParallaxViewFrame:scrollView];
274284
}
275285

286+
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
287+
// Live Text Interaction
288+
if (@available(iOS 16.0, *)) {
289+
BFRImageContainerViewController *activeVC = (BFRImageContainerViewController *)self.imageViewControllers[self.currentIndex];
290+
291+
BOOL hasAnalyzeableType = (activeVC.assetType == BFRImageAssetTypeImage || activeVC.assetType == BFRImageAssetTypeRemoteImage);
292+
293+
if (self.shouldPerformLiveTextAnalysis && hasAnalyzeableType) {
294+
[activeVC analyzeImageIfPossible:self.liveTextManager];
295+
}
296+
}
297+
}
298+
299+
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
300+
// Live Text checks
301+
CGPoint windowPoint = [gestureRecognizer locationInView:nil];
302+
if (@available(iOS 16, *)) {
303+
if (self.shouldPerformLiveTextAnalysis &&
304+
[self.liveTextManager hasLiveTextInteractionAtPoint:windowPoint]) {
305+
return NO;
306+
}
307+
}
308+
309+
return YES;
310+
}
311+
276312
- (void)updateParallaxViewFrame:(UIScrollView *)scrollView {
277313
CGRect bounds = scrollView.bounds;
278314
CGRect parallaxSeparatorFrame = self.parallaxView.frame;

BFRImageViewController/Live Text/LiveTextManager.swift

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,54 @@ import Foundation
1010
import VisionKit
1111

1212
@available(iOS 16.0, *)
13-
@objc @MainActor class LiveTextManager: NSObject {
14-
private var interaction = ImageAnalysisInteraction()
13+
@objc @MainActor class LiveTextManager: NSObject, ImageAnalysisInteractionDelegate {
14+
private let interaction = ImageAnalysisInteraction()
15+
private let analyzer = ImageAnalyzer()
16+
private let configuration = ImageAnalyzer.Configuration([.text, .machineReadableCode])
17+
private var analyzedImage: UIImage? = nil
18+
19+
override init() {
20+
super.init()
21+
interaction.delegate = self
22+
}
1523

1624
@objc
1725
static func isLiveTextAvailable() -> Bool {
1826
return ImageAnalyzer.isSupported
1927
}
2028

2129
@objc
22-
func analyzeImageView(view: UIView, image: UIImage) async {
23-
interaction = ImageAnalysisInteraction()
24-
interaction.preferredInteractionTypes = .automatic
25-
view.addInteraction(interaction)
30+
func analyzeImageView(view: UIView, image: UIImage) {
31+
if let inFlightView = interaction.view {
32+
inFlightView.removeInteraction(interaction)
33+
}
2634

27-
let configuration = ImageAnalyzer.Configuration([.text, .machineReadableCode])
28-
let analyzer = ImageAnalyzer()
29-
let analysis = try? await analyzer.analyze(image, configuration: configuration)
30-
interaction.analysis = analysis
35+
Task {
36+
interaction.analysis = nil
37+
interaction.preferredInteractionTypes = []
38+
analyzedImage = image
39+
40+
if let analysis = try? await analyzer.analyze(image, configuration: configuration) {
41+
if analyzedImage == image && (analysis.hasResults(for: .text) || analysis.hasResults(for: .machineReadableCode)) {
42+
view.addInteraction(interaction)
43+
interaction.analysis = analysis
44+
interaction.preferredInteractionTypes = .automatic
45+
}
46+
}
47+
}
48+
}
49+
50+
@objc func hasLiveTextInteractionAt(point: CGPoint) -> Bool {
51+
return interaction.hasInteractiveItem(at: point) || interaction.hasActiveTextSelection
52+
}
53+
54+
@objc func updateContentRect() {
55+
interaction.setContentsRectNeedsUpdate()
56+
}
57+
58+
// MARK: Delegate
59+
60+
nonisolated func interaction(_ interaction: ImageAnalysisInteraction, shouldBeginAt point: CGPoint, for interactionType: ImageAnalysisInteraction.InteractionTypes) -> Bool {
61+
return hasLiveTextInteractionAt(point: point)
3162
}
3263
}

0 commit comments

Comments
 (0)