react-native-rectangle-doc-scanner 3.65.0 → 3.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DocScanner.js +12 -0
- package/package.json +1 -1
- package/src/DocScanner.tsx +15 -0
- package/vendor/react-native-document-scanner/ios/DocumentScannerView.m +22 -1
- package/vendor/react-native-document-scanner/ios/IPDFCameraViewController.m +176 -87
- package/vendor/react-native-document-scanner/ios/RNPdfScannerManager.m +26 -13
package/dist/DocScanner.js
CHANGED
|
@@ -88,6 +88,18 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
88
88
|
return Math.min(100, Math.max(0, quality));
|
|
89
89
|
}, [quality]);
|
|
90
90
|
const handlePictureTaken = (0, react_1.useCallback)((event) => {
|
|
91
|
+
const captureError = event?.error;
|
|
92
|
+
if (captureError) {
|
|
93
|
+
console.error('[DocScanner] Native capture error received:', captureError);
|
|
94
|
+
captureOriginRef.current = 'auto';
|
|
95
|
+
setIsAutoCapturing(false);
|
|
96
|
+
setDetectedRectangle(null);
|
|
97
|
+
if (captureResolvers.current) {
|
|
98
|
+
captureResolvers.current.reject(new Error(String(captureError)));
|
|
99
|
+
captureResolvers.current = null;
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
91
103
|
console.log('[DocScanner] handlePictureTaken called with event:', {
|
|
92
104
|
hasInitialImage: !!event.initialImage,
|
|
93
105
|
hasCroppedImage: !!event.croppedImage,
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -150,6 +150,21 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
150
150
|
|
|
151
151
|
const handlePictureTaken = useCallback(
|
|
152
152
|
(event: PictureEvent) => {
|
|
153
|
+
const captureError = (event as any)?.error;
|
|
154
|
+
if (captureError) {
|
|
155
|
+
console.error('[DocScanner] Native capture error received:', captureError);
|
|
156
|
+
captureOriginRef.current = 'auto';
|
|
157
|
+
setIsAutoCapturing(false);
|
|
158
|
+
setDetectedRectangle(null);
|
|
159
|
+
|
|
160
|
+
if (captureResolvers.current) {
|
|
161
|
+
captureResolvers.current.reject(new Error(String(captureError)));
|
|
162
|
+
captureResolvers.current = null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
console.log('[DocScanner] handlePictureTaken called with event:', {
|
|
154
169
|
hasInitialImage: !!event.initialImage,
|
|
155
170
|
hasCroppedImage: !!event.croppedImage,
|
|
@@ -127,7 +127,28 @@
|
|
|
127
127
|
- (void) capture {
|
|
128
128
|
NSLog(@"[DocumentScanner] capture called");
|
|
129
129
|
[self captureImageWithCompletionHander:^(UIImage *croppedImage, UIImage *initialImage, CIRectangleFeature *rectangleFeature) {
|
|
130
|
-
|
|
130
|
+
NSLog(@"[DocumentScanner] captureImageWithCompletionHander callback - croppedImage: %@, initialImage: %@", croppedImage ? @"YES" : @"NO", initialImage ? @"YES" : @"NO");
|
|
131
|
+
|
|
132
|
+
if (!croppedImage && initialImage) {
|
|
133
|
+
// Use initial image when cropping is not available
|
|
134
|
+
croppedImage = initialImage;
|
|
135
|
+
} else if (!initialImage && croppedImage) {
|
|
136
|
+
// Mirror cropped image so downstream logic continues to work
|
|
137
|
+
initialImage = croppedImage;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!croppedImage || !initialImage) {
|
|
141
|
+
NSLog(@"[DocumentScanner] capture failed - missing image data");
|
|
142
|
+
if (self.onPictureTaken) {
|
|
143
|
+
self.onPictureTaken(@{ @"error": @"capture_failed" });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!self.captureMultiple) {
|
|
147
|
+
[self stop];
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
131
152
|
if (self.onPictureTaken) {
|
|
132
153
|
NSLog(@"[DocumentScanner] Calling onPictureTaken");
|
|
133
154
|
// Use maximum JPEG quality (1.0) or user's quality setting, whichever is higher
|
|
@@ -15,6 +15,19 @@
|
|
|
15
15
|
#import <ImageIO/ImageIO.h>
|
|
16
16
|
#import <GLKit/GLKit.h>
|
|
17
17
|
|
|
18
|
+
static inline void dispatch_async_main_queue(dispatch_block_t block)
|
|
19
|
+
{
|
|
20
|
+
if (!block) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if ([NSThread isMainThread]) {
|
|
25
|
+
block();
|
|
26
|
+
} else {
|
|
27
|
+
dispatch_async(dispatch_get_main_queue(), block);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
@interface IPDFCameraViewController () <AVCaptureVideoDataOutputSampleBufferDelegate, AVCapturePhotoCaptureDelegate>
|
|
19
32
|
|
|
20
33
|
@property (nonatomic,strong) AVCaptureSession *captureSession;
|
|
@@ -47,6 +60,39 @@
|
|
|
47
60
|
BOOL _isCapturing;
|
|
48
61
|
}
|
|
49
62
|
|
|
63
|
+
- (void)completeCaptureWithCroppedImage:(UIImage *)croppedImage
|
|
64
|
+
initialImage:(UIImage *)initialImage
|
|
65
|
+
rectangle:(CIRectangleFeature *)rectangleFeature
|
|
66
|
+
error:(NSError *)error
|
|
67
|
+
{
|
|
68
|
+
void (^completionHandler)(UIImage *, UIImage *, CIRectangleFeature *) = self.captureCompletionHandler;
|
|
69
|
+
|
|
70
|
+
dispatch_async_main_queue(^{
|
|
71
|
+
if (error) {
|
|
72
|
+
NSLog(@"[IPDFCameraViewController] Completing capture with error: %@", error.localizedDescription);
|
|
73
|
+
if (completionHandler) {
|
|
74
|
+
completionHandler(nil, nil, nil);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
UIImage *resolvedInitial = initialImage ?: croppedImage;
|
|
78
|
+
UIImage *resolvedCropped = croppedImage ?: resolvedInitial;
|
|
79
|
+
|
|
80
|
+
if (!resolvedInitial || !resolvedCropped) {
|
|
81
|
+
NSLog(@"[IPDFCameraViewController] Missing images during completion, sending failure to JS");
|
|
82
|
+
if (completionHandler) {
|
|
83
|
+
completionHandler(nil, nil, nil);
|
|
84
|
+
}
|
|
85
|
+
} else if (completionHandler) {
|
|
86
|
+
completionHandler(resolvedCropped, resolvedInitial, rectangleFeature);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
self.captureCompletionHandler = nil;
|
|
91
|
+
self->_isCapturing = NO;
|
|
92
|
+
[self hideGLKView:NO completion:nil];
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
50
96
|
- (void)awakeFromNib
|
|
51
97
|
{
|
|
52
98
|
[super awakeFromNib];
|
|
@@ -153,7 +199,16 @@
|
|
|
153
199
|
[session addOutput:self.photoOutput];
|
|
154
200
|
NSLog(@"[IPDFCamera] Using AVCapturePhotoOutput (modern API)");
|
|
155
201
|
} else {
|
|
156
|
-
NSLog(@"[IPDFCamera]
|
|
202
|
+
NSLog(@"[IPDFCamera] WARNING: Cannot add AVCapturePhotoOutput, falling back to AVCaptureStillImageOutput");
|
|
203
|
+
self.photoOutput = nil;
|
|
204
|
+
// Fallback to legacy API
|
|
205
|
+
self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
|
|
206
|
+
if ([session canAddOutput:self.stillImageOutput]) {
|
|
207
|
+
[session addOutput:self.stillImageOutput];
|
|
208
|
+
NSLog(@"[IPDFCamera] Fallback successful: Using AVCaptureStillImageOutput");
|
|
209
|
+
} else {
|
|
210
|
+
NSLog(@"[IPDFCamera] CRITICAL ERROR: Cannot add any capture output!");
|
|
211
|
+
}
|
|
157
212
|
}
|
|
158
213
|
} else {
|
|
159
214
|
// Fallback for older iOS versions (< iOS 10)
|
|
@@ -443,7 +498,10 @@
|
|
|
443
498
|
|
|
444
499
|
if (!self.captureSession || !self.captureSession.isRunning) {
|
|
445
500
|
NSLog(@"[IPDFCameraViewController] ERROR: captureSession is not running");
|
|
446
|
-
|
|
501
|
+
NSError *error = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
502
|
+
code:-200
|
|
503
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"capture_session_not_running" }];
|
|
504
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:error];
|
|
447
505
|
return;
|
|
448
506
|
}
|
|
449
507
|
|
|
@@ -464,24 +522,25 @@
|
|
|
464
522
|
|
|
465
523
|
// Use modern AVCapturePhotoOutput API (iOS 10+)
|
|
466
524
|
if (@available(iOS 10.0, *)) {
|
|
467
|
-
if (
|
|
468
|
-
NSLog(@"[IPDFCameraViewController]
|
|
469
|
-
|
|
470
|
-
self.
|
|
471
|
-
[weakSelf hideGLKView:NO completion:nil];
|
|
525
|
+
if (self.photoOutput) {
|
|
526
|
+
NSLog(@"[IPDFCameraViewController] Using AVCapturePhotoOutput to capture");
|
|
527
|
+
AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings];
|
|
528
|
+
[self.photoOutput capturePhotoWithSettings:settings delegate:self];
|
|
472
529
|
return;
|
|
473
530
|
}
|
|
474
531
|
|
|
475
|
-
NSLog(@"[IPDFCameraViewController]
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
532
|
+
NSLog(@"[IPDFCameraViewController] photoOutput is nil, trying fallback to stillImageOutput");
|
|
533
|
+
// Fallback to legacy API if photoOutput is not available
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Fallback: Use legacy AVCaptureStillImageOutput (iOS < 10 or when photoOutput failed)
|
|
537
|
+
{
|
|
480
538
|
if (!self.stillImageOutput) {
|
|
481
539
|
NSLog(@"[IPDFCameraViewController] ERROR: stillImageOutput is nil");
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
540
|
+
NSError *error = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
541
|
+
code:-201
|
|
542
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"missing_still_image_output" }];
|
|
543
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:error];
|
|
485
544
|
return;
|
|
486
545
|
}
|
|
487
546
|
|
|
@@ -501,9 +560,10 @@
|
|
|
501
560
|
|
|
502
561
|
if (!videoConnection) {
|
|
503
562
|
NSLog(@"[IPDFCameraViewController] ERROR: No video connection found");
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
563
|
+
NSError *error = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
564
|
+
code:-202
|
|
565
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"no_video_connection" }];
|
|
566
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:error];
|
|
507
567
|
return;
|
|
508
568
|
}
|
|
509
569
|
|
|
@@ -521,126 +581,155 @@
|
|
|
521
581
|
|
|
522
582
|
if (error) {
|
|
523
583
|
NSLog(@"[IPDFCameraViewController] ERROR in didFinishProcessingPhoto: %@", error);
|
|
524
|
-
|
|
525
|
-
self.captureCompletionHandler = nil;
|
|
526
|
-
[self hideGLKView:NO completion:nil];
|
|
584
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:error];
|
|
527
585
|
return;
|
|
528
586
|
}
|
|
529
587
|
|
|
588
|
+
// iOS 11+ uses fileDataRepresentation
|
|
530
589
|
NSData *imageData = [photo fileDataRepresentation];
|
|
531
590
|
if (!imageData) {
|
|
532
591
|
NSLog(@"[IPDFCameraViewController] ERROR: Failed to get image data from photo");
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
592
|
+
NSError *dataError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
593
|
+
code:-203
|
|
594
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"no_image_data_from_photo" }];
|
|
595
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:dataError];
|
|
536
596
|
return;
|
|
537
597
|
}
|
|
538
598
|
|
|
599
|
+
NSLog(@"[IPDFCameraViewController] Got image data from AVCapturePhoto, size: %lu bytes", (unsigned long)imageData.length);
|
|
539
600
|
[self processImageData:imageData];
|
|
540
601
|
}
|
|
541
602
|
|
|
542
603
|
// AVCapturePhotoCaptureDelegate method for iOS 10
|
|
543
604
|
- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhotoSampleBuffer:(CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(AVCaptureBracketedStillImageSettings *)bracketSettings error:(NSError *)error API_DEPRECATED("Use -captureOutput:didFinishProcessingPhoto:error: instead.", ios(10.0, 11.0)) {
|
|
544
605
|
NSLog(@"[IPDFCameraViewController] didFinishProcessingPhotoSampleBuffer called (iOS 10)");
|
|
545
|
-
|
|
606
|
+
|
|
607
|
+
if (error) {
|
|
608
|
+
NSLog(@"[IPDFCameraViewController] ERROR in didFinishProcessingPhotoSampleBuffer: %@", error);
|
|
609
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:error];
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (!photoSampleBuffer) {
|
|
614
|
+
NSLog(@"[IPDFCameraViewController] ERROR: photoSampleBuffer is nil");
|
|
615
|
+
NSError *bufferError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
616
|
+
code:-204
|
|
617
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"photo_sample_buffer_nil" }];
|
|
618
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:bufferError];
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// iOS 10: Use AVCapturePhotoOutput's method for converting sample buffer
|
|
623
|
+
NSData *imageData = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer];
|
|
624
|
+
|
|
625
|
+
if (!imageData) {
|
|
626
|
+
NSLog(@"[IPDFCameraViewController] ERROR: Failed to create JPEG data from photo sample buffer");
|
|
627
|
+
NSError *dataError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
628
|
+
code:-205
|
|
629
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"jpeg_conversion_failed" }];
|
|
630
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:dataError];
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
NSLog(@"[IPDFCameraViewController] Got image data from photo sample buffer (iOS 10), size: %lu bytes", (unsigned long)imageData.length);
|
|
635
|
+
[self processImageData:imageData];
|
|
546
636
|
}
|
|
547
637
|
|
|
638
|
+
// Helper method for legacy AVCaptureStillImageOutput (iOS < 10)
|
|
548
639
|
- (void)handleCapturedImageData:(CMSampleBufferRef)sampleBuffer error:(NSError *)error {
|
|
549
|
-
NSLog(@"[IPDFCameraViewController] handleCapturedImageData called, error=%@, buffer=%@", error, sampleBuffer ? @"YES" : @"NO");
|
|
640
|
+
NSLog(@"[IPDFCameraViewController] handleCapturedImageData called (legacy), error=%@, buffer=%@", error, sampleBuffer ? @"YES" : @"NO");
|
|
550
641
|
|
|
551
642
|
if (error) {
|
|
552
643
|
NSLog(@"[IPDFCameraViewController] ERROR capturing image: %@", error);
|
|
553
|
-
|
|
554
|
-
self.captureCompletionHandler = nil;
|
|
555
|
-
[self hideGLKView:NO completion:nil];
|
|
644
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:error];
|
|
556
645
|
return;
|
|
557
646
|
}
|
|
558
647
|
|
|
559
648
|
if (!sampleBuffer) {
|
|
560
649
|
NSLog(@"[IPDFCameraViewController] ERROR: sampleBuffer is nil");
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
650
|
+
NSError *bufferError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
651
|
+
code:-206
|
|
652
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"sample_buffer_nil" }];
|
|
653
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:bufferError];
|
|
564
654
|
return;
|
|
565
655
|
}
|
|
566
656
|
|
|
657
|
+
// iOS < 10: Use AVCaptureStillImageOutput's method
|
|
567
658
|
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBuffer];
|
|
568
659
|
|
|
569
660
|
if (!imageData) {
|
|
570
|
-
NSLog(@"[IPDFCameraViewController] ERROR: Failed to create image data from sample buffer");
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
661
|
+
NSLog(@"[IPDFCameraViewController] ERROR: Failed to create image data from sample buffer (legacy)");
|
|
662
|
+
NSError *dataError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
663
|
+
code:-207
|
|
664
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"legacy_sample_conversion_failed" }];
|
|
665
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:dataError];
|
|
574
666
|
return;
|
|
575
667
|
}
|
|
576
668
|
|
|
669
|
+
NSLog(@"[IPDFCameraViewController] Got image data from still image output (legacy), size: %lu bytes", (unsigned long)imageData.length);
|
|
577
670
|
[self processImageData:imageData];
|
|
578
671
|
}
|
|
579
672
|
|
|
580
673
|
- (void)processImageData:(NSData *)imageData {
|
|
581
674
|
NSLog(@"[IPDFCameraViewController] processImageData called, imageData size: %lu bytes", (unsigned long)imageData.length);
|
|
582
675
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
_isCapturing = NO;
|
|
589
|
-
[self hideGLKView:NO completion:nil];
|
|
676
|
+
if (!imageData || imageData.length == 0) {
|
|
677
|
+
NSError *dataError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
678
|
+
code:-208
|
|
679
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"empty_image_data" }];
|
|
680
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:dataError];
|
|
590
681
|
return;
|
|
591
682
|
}
|
|
592
683
|
|
|
593
|
-
|
|
594
|
-
{
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
else
|
|
602
|
-
{
|
|
603
|
-
enhancedImage = [self filteredImageUsingContrastFilterOnImage:enhancedImage];
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
if (self.isBorderDetectionEnabled && rectangleDetectionConfidenceHighEnough(_imageDedectionConfidence))
|
|
607
|
-
{
|
|
608
|
-
CIRectangleFeature *rectangleFeature = [self biggestRectangleInRectangles:[[self highAccuracyRectangleDetector] featuresInImage:enhancedImage]];
|
|
609
|
-
|
|
610
|
-
if (rectangleFeature)
|
|
611
|
-
{
|
|
612
|
-
enhancedImage = [self correctPerspectiveForImage:enhancedImage withFeatures:rectangleFeature];
|
|
684
|
+
UIImage *initialImage = [UIImage imageWithData:imageData];
|
|
685
|
+
if (!initialImage) {
|
|
686
|
+
NSError *conversionError = [NSError errorWithDomain:@"IPDFCameraViewController"
|
|
687
|
+
code:-209
|
|
688
|
+
userInfo:@{ NSLocalizedDescriptionKey: @"initial_image_conversion_failed" }];
|
|
689
|
+
[self completeCaptureWithCroppedImage:nil initialImage:nil rectangle:nil error:conversionError];
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
613
692
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
|
617
|
-
UIImage *initialImage = [UIImage imageWithData:imageData];
|
|
618
|
-
UIGraphicsEndImageContext();
|
|
693
|
+
UIImage *croppedImage = initialImage;
|
|
694
|
+
CIRectangleFeature *rectangleFeature = nil;
|
|
619
695
|
|
|
620
|
-
|
|
621
|
-
|
|
696
|
+
BOOL shouldEnhance = (self.cameraViewType == IPDFCameraViewTypeBlackAndWhite) || self.isBorderDetectionEnabled;
|
|
697
|
+
if (shouldEnhance) {
|
|
698
|
+
CIImage *processedImage = [CIImage imageWithData:imageData];
|
|
699
|
+
if (!processedImage) {
|
|
700
|
+
NSLog(@"[IPDFCameraViewController] Unable to create CIImage from data, returning original image");
|
|
701
|
+
} else {
|
|
702
|
+
if (self.cameraViewType == IPDFCameraViewTypeBlackAndWhite) {
|
|
703
|
+
processedImage = [self filteredImageUsingEnhanceFilterOnImage:processedImage];
|
|
622
704
|
} else {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
705
|
+
processedImage = [self filteredImageUsingContrastFilterOnImage:processedImage];
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if (self.isBorderDetectionEnabled && rectangleDetectionConfidenceHighEnough(_imageDedectionConfidence)) {
|
|
709
|
+
CIRectangleFeature *detectedRectangle = [self biggestRectangleInRectangles:[[self highAccuracyRectangleDetector] featuresInImage:processedImage]];
|
|
710
|
+
|
|
711
|
+
if (detectedRectangle) {
|
|
712
|
+
rectangleFeature = detectedRectangle;
|
|
713
|
+
CIImage *correctedImage = [self correctPerspectiveForImage:processedImage withFeatures:detectedRectangle];
|
|
714
|
+
|
|
715
|
+
UIGraphicsBeginImageContext(CGSizeMake(correctedImage.extent.size.height, correctedImage.extent.size.width));
|
|
716
|
+
[[UIImage imageWithCIImage:correctedImage scale:1.0 orientation:UIImageOrientationRight] drawInRect:CGRectMake(0, 0, correctedImage.extent.size.height, correctedImage.extent.size.width)];
|
|
717
|
+
UIImage *perspectiveCorrectedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
718
|
+
UIGraphicsEndImageContext();
|
|
719
|
+
|
|
720
|
+
if (perspectiveCorrectedImage) {
|
|
721
|
+
croppedImage = perspectiveCorrectedImage;
|
|
722
|
+
} else {
|
|
723
|
+
NSLog(@"[IPDFCameraViewController] Failed to create perspective corrected image, using original");
|
|
724
|
+
}
|
|
725
|
+
} else {
|
|
726
|
+
NSLog(@"[IPDFCameraViewController] No rectangle detected during manual capture, returning original image");
|
|
727
|
+
}
|
|
628
728
|
}
|
|
629
|
-
} else {
|
|
630
|
-
[weakSelf hideGLKView:NO completion:nil];
|
|
631
|
-
UIImage *initialImage = [UIImage imageWithData:imageData];
|
|
632
|
-
completionHandler(initialImage, initialImage, nil);
|
|
633
729
|
}
|
|
634
730
|
}
|
|
635
|
-
else
|
|
636
|
-
{
|
|
637
|
-
[weakSelf hideGLKView:NO completion:nil];
|
|
638
|
-
UIImage *initialImage = [UIImage imageWithData:imageData];
|
|
639
|
-
completionHandler(initialImage, initialImage, nil);
|
|
640
|
-
}
|
|
641
731
|
|
|
642
|
-
|
|
643
|
-
self.captureCompletionHandler = nil;
|
|
732
|
+
[self completeCaptureWithCroppedImage:croppedImage initialImage:initialImage rectangle:rectangleFeature error:nil];
|
|
644
733
|
}
|
|
645
734
|
|
|
646
735
|
- (void)hideGLKView:(BOOL)hidden completion:(void(^)())completion
|
|
@@ -34,24 +34,37 @@ RCT_EXPORT_VIEW_PROPERTY(quality, float)
|
|
|
34
34
|
RCT_EXPORT_VIEW_PROPERTY(brightness, float)
|
|
35
35
|
RCT_EXPORT_VIEW_PROPERTY(contrast, float)
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// Main capture method - uses the last created scanner view
|
|
38
|
+
RCT_EXPORT_METHOD(capture:(nullable NSNumber *)reactTag) {
|
|
38
39
|
NSLog(@"[RNPdfScannerManager] capture called with reactTag: %@", reactTag);
|
|
39
40
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
DocumentScannerView *targetView = nil;
|
|
42
|
+
|
|
43
|
+
if (reactTag) {
|
|
44
|
+
UIView *view = [self.bridge.uiManager viewForReactTag:reactTag];
|
|
45
|
+
if ([view isKindOfClass:[DocumentScannerView class]]) {
|
|
46
|
+
targetView = (DocumentScannerView *)view;
|
|
47
|
+
self->_scannerView = targetView;
|
|
48
|
+
} else if (view) {
|
|
49
|
+
NSLog(@"[RNPdfScannerManager] View for tag %@ is not DocumentScannerView: %@", reactTag, NSStringFromClass(view.class));
|
|
50
|
+
} else {
|
|
51
|
+
NSLog(@"[RNPdfScannerManager] No view found for tag %@", reactTag);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!targetView && self->_scannerView) {
|
|
56
|
+
NSLog(@"[RNPdfScannerManager] Falling back to last known scanner view");
|
|
57
|
+
targetView = self->_scannerView;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!targetView) {
|
|
61
|
+
NSLog(@"[RNPdfScannerManager] ERROR: No scanner view available for capture");
|
|
43
62
|
return;
|
|
44
63
|
}
|
|
45
|
-
DocumentScannerView *scannerView = (DocumentScannerView *)view;
|
|
46
|
-
NSLog(@"[RNPdfScannerManager] Calling capture on view: %@", scannerView);
|
|
47
|
-
[scannerView capture];
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
64
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
[_scannerView capture];
|
|
65
|
+
NSLog(@"[RNPdfScannerManager] Calling capture on view: %@", targetView);
|
|
66
|
+
[targetView capture];
|
|
67
|
+
});
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
- (UIView*) view {
|