iOS 實(shí)現(xiàn)拍照的焦距調(diào)節(jié)

我們?cè)谧远x相機(jī)時(shí),若要實(shí)現(xiàn)鏡頭變焦,也就是推近或者拉遠(yuǎn)焦距,有兩種方法可以實(shí)現(xiàn):可以通過修改AVCaptureDevice的縮放系數(shù)videoZoomFactor來實(shí)現(xiàn)鏡頭變焦,也可以通過修改AVCaptureConnection的縮放系數(shù)videoScaleAndCropFactor來實(shí)現(xiàn)鏡頭變焦。

1、修改AVCaptureDevice的縮放系數(shù)videoZoomFactor

通過修改AVCaptureDevice的縮放系數(shù)videoZoomFactor來實(shí)現(xiàn)鏡頭變焦的核心代碼如下:

//最小縮放值
- (CGFloat)minZoomFactor
{
    CGFloat minZoomFactor = 1.0;
    if (@available(iOS 11.0, *)) {
        minZoomFactor = self.device.minAvailableVideoZoomFactor;
    }
    return minZoomFactor;
}

//最大縮放值
- (CGFloat)maxZoomFactor
{
    CGFloat maxZoomFactor = self.device.activeFormat.videoMaxZoomFactor;
    if (@available(iOS 11.0, *)) {
        maxZoomFactor = self.device.maxAvailableVideoZoomFactor;
    }
    
    if (maxZoomFactor > 6.0) {
        maxZoomFactor = 6.0;
    }
    return maxZoomFactor;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]){
        self.slider.minimumValue = self.minZoomFactor;
        self.slider.maximumValue = self.maxZoomFactor;
        self.currentZoomFactor = self.device.videoZoomFactor;
    }
    return YES;
}

//縮放手勢(shì)
- (void)zoomChangePinchGestureRecognizerClick:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
    if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan ||
        pinchGestureRecognizer.state == UIGestureRecognizerStateChanged)
    {
        CGFloat currentZoomFactor = self.currentZoomFactor * pinchGestureRecognizer.scale;
        self.slider.hidden = NO;
        
        if (currentZoomFactor < self.maxZoomFactor &&
            currentZoomFactor > self.minZoomFactor){
            
            NSError *error = nil;
            if ([self.device lockForConfiguration:&error] ) {
                self.device.videoZoomFactor = currentZoomFactor;
                self.slider.value = self.device.videoZoomFactor;
                [self.device unlockForConfiguration];
            }
            else {
                NSLog( @"Could not lock device for configuration: %@", error );
            }
        }
    }
    else
    {
        self.slider.hidden = YES;
    }
}

- (void)sliderValueChangeClick:(UISlider *)sender
{
    self.slider.hidden = NO;
    
    if (sender.value < self.maxZoomFactor &&
        sender.value > self.minZoomFactor){
        
        NSError *error = nil;
        if ([self.device lockForConfiguration:&error] ) {
            self.device.videoZoomFactor = sender.value;
            [self.device unlockForConfiguration];
        }
        else {
            NSLog( @"Could not lock device for configuration: %@", error );
        }
    }
}

以上這么多代碼,核心代碼只有一處,通過該句代碼設(shè)置了新的縮放比例:

self.device.videoZoomFactor = currentZoomFactor;

2、修改AVCaptureConnection的縮放系數(shù)videoScaleAndCropFactor

通過修改AVCaptureConnection的縮放系數(shù)videoScaleAndCropFactor來實(shí)現(xiàn)鏡頭變焦的核心代碼如下:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if ( [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] ) {
        beginGestureScale = effectiveScale;
    }
    return YES;
}

// scale image depending on users pinch gesture
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer
{
    BOOL allTouchesAreOnThePreviewLayer = YES;
    NSUInteger numTouches = [recognizer numberOfTouches], i;
    for ( i = 0; i < numTouches; ++i ) {
        CGPoint location = [recognizer locationOfTouch:i inView:previewView];
        CGPoint convertedLocation = [previewLayer convertPoint:location fromLayer:previewLayer.superlayer];
        if ( ! [previewLayer containsPoint:convertedLocation] ) {
            allTouchesAreOnThePreviewLayer = NO;
            break;
        }
    }
    
    if ( allTouchesAreOnThePreviewLayer ) {
        effectiveScale = beginGestureScale * recognizer.scale;
        if (effectiveScale < 1.0)
            effectiveScale = 1.0;
        CGFloat maxScaleAndCropFactor = [[stillImageOutput connectionWithMediaType:AVMediaTypeVideo] videoMaxScaleAndCropFactor];
        if (effectiveScale > maxScaleAndCropFactor)
            effectiveScale = maxScaleAndCropFactor;
        [CATransaction begin];
        [CATransaction setAnimationDuration:.025];
        [previewLayer setAffineTransform:CGAffineTransformMakeScale(effectiveScale, effectiveScale)];
        [CATransaction commit];
    }
}

以上代碼的核心是針對(duì)預(yù)覽圖層 AVCaptureVideoPreviewLayer做了放大或者縮小變換,但是這并沒有改變拍攝出來的照片是變焦前的圖片的本質(zhì)!我們還要接著往下做工作:

- (void)recordButtonClick:(UIButton *)sender
{
    //imgaeOutput 此時(shí)沒有捕獲圖像
    if (self.imgaeOutput.capturingStillImage == NO)
    {
        //獲取指定連接
        AVCaptureConnection *stillImageConnection = [self.imgaeOutput connectionWithMediaType:AVMediaTypeVideo];
        
        //設(shè)置視頻方向
        UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];
        AVCaptureVideoOrientation avcaptureOrientation = (AVCaptureVideoOrientation)curDeviceOrientation;
        if (curDeviceOrientation == UIDeviceOrientationLandscapeLeft){
            avcaptureOrientation = AVCaptureVideoOrientationLandscapeRight;
        }else if(curDeviceOrientation == UIDeviceOrientationLandscapeRight){
            avcaptureOrientation = AVCaptureVideoOrientationLandscapeLeft;
        }
        [stillImageConnection setVideoOrientation:avcaptureOrientation];
        
        //設(shè)置縮放比例
        [stillImageConnection setVideoScaleAndCropFactor:effectiveScale];
        
        [self.imgaeOutput setOutputSettings:@{AVVideoCodecKey:AVVideoCodecJPEG}];
        [self.imgaeOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error) {
            if (error){
                
            }else{
                NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                UIImage *image = [UIImage imageWithData:jpegData];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.navigationController pushViewController:[[AVImageViewController alloc]initWithImage:image] animated:YES];
                });
                
                //寫入相冊(cè)
                CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
                [library writeImageDataToSavedPhotosAlbum:jpegData metadata:(__bridge id)attachments completionBlock:^(NSURL *assetURL, NSError *error) {
                    if (error) {
                        
                    }
                }];
                
                if (attachments)
                    CFRelease(attachments);
            }
        }];
    }
}

在拍照時(shí),獲取當(dāng)前縮放比例并設(shè)置AVCaptureConnection的縮放比例videoScaleAndCropFactor

//獲取指定連接
AVCaptureConnection *stillImageConnection = [self.imgaeOutput connectionWithMediaType:AVMediaTypeVideo];

//設(shè)置縮放比例
[stillImageConnection setVideoScaleAndCropFactor:effectiveScale];

點(diǎn)擊查看更多AVCaptureDevice信息
點(diǎn)擊查看更多AVCaptureConnection信息

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,193評(píng)論 3 119
  • 原文鏈接http://www.cnblogs.com/kenshincui/p/4186022.html 音頻在i...
    Hyman0819閱讀 22,149評(píng)論 4 74
  • 輸入設(shè)備AVCaptureDevice 繼承自NSObject:是關(guān)于相機(jī)硬件的接口,用于配置底層硬件的屬性(例如...
    蘇沫離閱讀 19,734評(píng)論 0 52
  • 林美下班回家,總會(huì)到小區(qū)前的公園里走走。 公園最初實(shí)際是一座小山,政府部門做了相應(yīng)的打理,使得小山的拙樸里多出了幾...
    素意簡文閱讀 356評(píng)論 0 4
  • 當(dāng)人們同情籠中鳥無助的眼神,他們選擇了放飛。千鳥齊飛,很美,卻僅僅讓更多原本自由的生靈重復(fù)被放飛,再被抓捕的悲哀。...
    落木疏影閱讀 284評(píng)論 0 1

友情鏈接更多精彩內(nèi)容