IOS native QR code scan (restricted scan Areas)
The main reason for writing this article is not to show how to use AVFoundation for QR code scanning, but to limit the scanning range of QR codes. (Because full screen scan is used by default)
The project encountered the need to scan the QR code function. Here I gave up using the third-party library and adopted the native scanning of apple.
The native advantage is that scanning is extremely fast and efficient, but one problem is that you don't know how to limit the scanning range.
Let's talk about how to use it for QR code scanning.
The first is to use several classes
@ Property (strong, nonatomic) AVCaptureDevice * device;
@ Property (strong, nonatomic) AVCaptureDeviceInput * input;
@ Property (strong, nonatomic) AVCaptureMetadataOutput * output;
@ Property (strong, nonatomic) AVCaptureSession * session;
@ Property (strong, nonatomic) AVCaptureVideoPreviewLayer * preview;
For the relationship between them, refer to the following article.
Portal
Create them
// Device
_ Device = [avcapturedevicedefadefadevicewithmediatype: AVMediaTypeVideo];
// Input
_ Input = [AVCaptureDeviceInputdeviceInputWithDevice: self. deviceerror: nil];
// Output
_ Output = [[AVCaptureMetadataOutputalloc] init];
[_ OutputsetMetadataObjectsDelegate: selfqueue: dispatch_get_main_queue ()];
// Session
_ Session = [[AVCaptureSessionalloc] init];
[_ SessionsetSessionPreset: AVCaptureSessionPresetHigh];
If ([_ sessioncanAddInput: self. input])
{
[_ SessionaddInput: self. input];
}
If ([_ sessioncanAddOutput: self. output])
{
[_ SessionaddOutput: self. output];
}
// Barcode type AVMetadataObjectTypeQRCode
_ Output. metadataObjectTypes = @ [AVMetadataObjectTypeQRCode];
// Preview
_ Preview = [AVCaptureVideoPreviewLayerlayerWithSession: _ session];
_ Preview. videoGravity = AVLayerVideoGravityResizeAspectFill;
_ Preview. frame = self. view. layer. bounds;
[Self. view. layerinsertSublayer: _ previewatIndex: 0];
// Start
[_ SessionstartRunning];
Then implement AVCaptureMetadataOutputObjectsDelegate
# Pragma mark AVCaptureMetadataOutputObjectsDelegate
-(Void) captureOutput :( AVCaptureOutput *) captureOutput didOutputMetadataObjects :( NSArray *) metadataObjects fromConnection :( AVCaptureConnection *) connection
{
NSString * stringValue;
If ([metadataObjectscount]> 0)
{
// Stop scanning
[_ SessionstopRunning];
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjectsobjectAtIndex: 0];
StringValue = metadataObject. stringValue;
}
}
So far, we can scan the QR code successfully, but there is an embarrassing problem. At this time, the scan is full screen scan. That is
Vc/CzuejrLDRy/nT0M/weight +/ydLJtcS146GjPC9wPgo8cD48YnI + c1_vcd4kpha + weight + Weight = "s rectangle of interest for each frame of video.
The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata. Specifying
A rectOfInterest may improve detection performance for certain types of metadata. The default value of this property is
Value CGRectMake (0, 0, 1, 1). Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.
The general meaning is to set the area (literally) of interest to each frame. Isn't that about setting the scan range? So I quickly set rectOfInterest to the frame in the middle frame,
[_ OutputsetRectOfInterest: CGRectMake (ScreenWidth-220)/64,220,220 +)];
// The width and height of the middle area are both 220 ScreenWidth and the screen width of the device.
However, the scan fails. Then I looked at the above paragraph.
The second sentence: the origin of the region is located in the upper left corner (I am sorry for this problem !), Then the area is relative to the device size. The default value is CGRectMake (0, 0, 1, 1). At this time, I know that there is a proportional relationship, and the maximum value is 1, that is to say, simply divide the size by the corresponding device width and height? Then change it
[_ OutputsetRectOfInterest: CGRectMake (ScreenWidth-220)/2)/ScreenWidth, (60 + 64)/ScreenHigh, 220/ScreenWidth, 220/ScreenHigh)];
It should have been perfect, but I was too happy to know that I was just too early. I found that this was not the case after a scan, but it was a lot worse.
So I tried to adjust it at, but it was not successful at the end. Finally, I set a very definite value.
[_ Output setRectOfInterest: CGRectMake (0.5, 0.5, 0.5, 0.5)];
This time it should be in the 1/4 area in the lower right, hey.
However, the facts hit me again. After scanning, we found that it was the lower-left 1/4 area. That is to say, the origin of rectOfInterest is in the upper-right corner !!!
Looking back, even if the top right corner is the origin, it should have no effect, but why not? It won't be the X and Y of the origin? Forget it. Try it.
[_ OutputsetRectOfInterest: CGRectMake (60 + 64)/ScreenHigh, (ScreenWidth-220)/2)/ScreenWidth, 220/ScreenWidth, 220/ScreenHigh)];
Scan again and find it successful! The origin is correct. I just want to say TMD!
But why can't I deal with the width and height? It won't be exchanged! Try it now
[_ OutputsetRectOfInterest: CGRectMake (124)/ScreenHigh, (ScreenWidth-220)/2)/ScreenWidth, 220/ScreenHigh, 220/ScreenWidth)];
With an uneasy mood, I tried again, scanning perfectly! I want to die for OMG.
So scanning the QR code with the system native is perfect!
I will share this with you today. For more information, see the source. Thank you-LC.