循序漸進學AVFoundation-自定義相機

本人小白,歡迎各位大佬補充指點
寫這篇文章之前先要感謝一下@敖老黑/@_南山憶這兩位博主,謝謝他們的肩膀.

寫這篇文章的目的:

  • 平時對手機硬件設備開發用的比較少
  • 看其他人的博客自己覺得還是比較亂,尤其是在適配iOS>10.0,更是亂
  • AVFoundation框架比較大,功能太多,用到一點研究一點,慢慢深入

概念

AVFoundation的強大之處我在這里就不一一贅述了.我也看了有人翻譯的蘋果官方AVFoundation框架的全部中文文檔,但是內容有點多,更重要的是有些類我們從來沒用過,一下子學太多會吃不消,因此,還是一點點來吧.


捕捉類:

就是AVFoundation框架中帶Capture(捕捉)字樣的所有類,這些類很強大,可以實現錄視頻/語音/拍照功能
根據蘋果官方文檔常見的捕捉類的關系是這樣的,如下圖:


蘋果官方圖片1.png

下面就一一講述一下這幾個類:

AVCaptureDevice

概念:
捕獲設備,通常是前置攝像頭,后置攝像頭,麥克風(音頻輸入), 一個AVCaptureDevice實例,代表一種設備
創建方式:
AVCaptureDevice實例不能被直接創建,因為設備本身已經存在了,我們是要拿到他而已
有三種拿到方式:
第一種:根據相機位置拿到對應的攝像頭

設備位置枚舉類型
 AVCaptureDevicePosition有3種(只針對攝像頭,不針對麥克風):
 AVCaptureDevicePositionUnspecified = 0,//不確定
 AVCaptureDevicePositionBack        = 1,后置
 AVCaptureDevicePositionFront       = 2,前置
設備種類:
//AVCaptureDeviceType 設備種類
 AVCaptureDeviceTypeBuiltInMicrophone //麥克風
 AVCaptureDeviceTypeBuiltInWideAngleCamera //廣角相機
 AVCaptureDeviceTypeBuiltInTelephotoCamera //比廣角相機更長的焦距。只有使用 AVCaptureDeviceDiscoverySession 可以使用
 AVCaptureDeviceTypeBuiltInDualCamera //變焦的相機,可以實現廣角和變焦的自動切換。使用同AVCaptureDeviceTypeBuiltInTelephotoCamera 一樣。
 AVCaptureDeviceTypeBuiltInDuoCamera //iOS 10.2 被 AVCaptureDeviceTypeBuiltInDualCamera 替換
方法如下:
 self.device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInDuoCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];

第二種:第二種:直接根據媒體類型直接拿到后置攝像頭

self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

第三種:先拿到所有的攝像頭設備,然后根據前后位置拿到前后置攝像頭

 - (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
 //1.獲取到當前所有可用的設備
 iOS<10.0(但是我試了下,好像還能用)
 NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
 ios>10.0
 AVCaptureDeviceDiscoverySession *deviceSession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera,AVCaptureDeviceTypeBuiltInDualCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
 NSArray *devices = deviceSession.devices;
 for ( AVCaptureDevice *device in devices )
 if ( device.position == position ){
 return device;
 }
 return nil;
 }

作用:
提供媒體數據到會話(AVCaptureSession)中,通過這個設備(AVCaptureDevice)創建一個(AVCaptureDeviceInput)捕捉設備輸入器,再添加到那個捕捉會話中

AVCaptureDeviceInput

概念:
輸入捕獲器,AVCaptureInput的一個子類,它提供了從AVCaptureDevice捕獲的媒體數據。
作用:
是AVCaptureSession的輸入源,它提供設備連接到系統的媒體數據,用AVCaptureDevice呈現的那些數據,即調用所有的輸入硬件,并捕獲輸入的媒體數據。例如攝像頭和麥克風
所謂的輸入硬件:比如,攝像頭可以捕獲外面的圖像/視頻輸入到手機;麥克風可以捕獲外部的聲音輸入到手機

AVCaptureSession

概念:
是AVFoundation 捕捉類(capture classes)的中心
分析:
capture:捕捉的意思
為何叫session(會話)呢?我的理解,為了讓輸入信息與輸出信息進行交流
你可以配置多個輸入和輸出,由一個單例會話來協調
作用:
AVCaptureSession對象來執行輸入設備和輸出設備之間的數據傳遞

  • 可以添加輸入(AVCaptureDeviceInput)和輸出(有多種例如:AVCaptureMovieFileOutput)
  • 通過[AVCaptureSession startRunning]啟動從輸入到輸出的數據流,[AVCaptureSession stopRunning]停止流
  • 屬性sessionPreset:來定制輸出的質量級別或比特率。
AVCaptureOutput

概念:
是一個抽象類,決定了捕捉會話(AVCaptureSession)輸出什么(一個視頻文件還是靜態圖片)
作用:
從AVCaptureInput接收的媒體流通過許多連接對象(AVCaptureConnection)連接到AVCaptureOutput呈現的.一個AVCaptureOutput對象在他創建的時候時沒有任何連接的(AVCaptureConnection),當AVCaptureOutput對象被添加到捕捉會話(AVCaptureSession)時,許多連接(connections)被創建用于映射捕捉會話(sessions)的輸入到輸出(也就是說,有了這些連接對象才能夠使輸入得到的數據映射到輸出)
AVCaptureConnection的作用蘋果官方的圖片如下:

蘋果官方圖片2.png

概念:
AVCaptureOutput的一個抽象子類,用于將捕獲的媒體數據寫入文件到某個路徑下。該類有兩個子類如下:

  • AVCaptureMovieFileOutput
    用于輸出視頻到文件目錄
  • AVCaptureAudioFileOutput
    用于輸出(相應格式的)音頻到文件目錄下
  • AVCaptureStillImageOutput
    AVCaptureOutput的一個抽象子類,用于將捕獲的媒體靜態圖片(iOS10廢棄掉了,使用AVCapturePhotoOutput)
    用戶可以在實時的捕獲資源下實時獲取到高質量的靜態圖片,通過captureStillImageAsynchronouslyFromConnection:completionHandler:方法(也就是點擊拍照動作方法)
    用戶還可以配置靜態圖像輸出以生成特定圖像格式的靜態圖像。
  • AVCapturePhotoOutput(>ios10)
    特點:
    • 除了擁有AVCaptureStillImageOutput的功能外還支持更多格式
    • AVCapturePhotoOutput/AVCaptureStillImageOutput不允許同時添加到捕捉會話中,否則會崩潰
    • 當用戶需要詳細監控拍照的過程那就可以通過設置代理來監控
      首先要創建并配置一個AVCapturePhotoSettings對象,然后通過 -capturePhotoWithSettings:delegate:設置代理
      監控狀態主要有(照片即將被拍攝,照片已經捕捉,但尚未處理,現場照片電影準備好,等等)
  • AVCapturePhotoSettings
    可以大量的設置照片的許多屬性,針對AVCapturePhotoOutput ,類似于 AVCaptureStillImageOutput 的 outputSettings
    常用創建方法:
//默認支持jpg格式
 + (instancetype)photoSettings;
 //指定格式創建   NSDictionary *setDic = @{AVVideoCodecKey:AVVideoCodecJPEG};
 + (instancetype)photoSettingsWithFormat:(nullable NSDictionary<NSString *, id> *)format;
 //常用(重要!!!!)
 + (instancetype)photoSettingsFromPhotoSettings:(AVCapturePhotoSettings *)photoSettings;
特別說明:
 用一個已經存在的AVCapturePhotoSettings對象,再創建一個新的AVCapturePhotoSettings對象,而且這個新對象僅僅uniqueID不一樣
 那么問題來了,既然已經有AVCapturePhotoSettings對象了,為何還要創建呢?
 因為AVCapturePhotoOutput -capturePhotoWithSettings:delegate:傳入的該對象不能重復使用,判定的標準就是uniqueID,如果uniqueID一樣就會崩潰掉!!!
  • AVCapturePhotoOutput -capturePhotoWithSettings:delegate:方法說明:
    該方法啟動一個照片捕捉,也就是立即拍照的意思,通過下面的代理方法實現就能拿到實時圖片數據:
-(void)captureOutput:(AVCapturePhotoOutput *)captureOutput didFinishProcessingPhotoSampleBuffer:(CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(AVCaptureBracketedStillImageSettings *)bracketSettings error:(NSError *)error;

注意:

1>該方法不能重復使用settings,判定重復方法通過settings對像的uniqueID,然而該屬性又是readonly,因此只能通過photoSettingsFromPhotoSettings:克隆了
2>初始化AVCaptureOutput對象,想給對象添加配置AVCapturePhotoSettings時,不能使用該方法,因為他就是拍照時使用的,而且他需要連接狀況下才能使用,即捕捉會話先添加輸入/輸出后,正常連接,因為這個方法一旦調用就回立馬書粗捕獲到的數據,但此時剛剛初始化而已,還未添加到捕捉會話中,那么就使用 setPhotoSettingsForSceneMonitoring:方法初始化配置即可
3>遵守一大堆規則:
散光燈規則:必須支持該散光燈模式
即調用該方法前一定要判斷是否支持閃光燈模式(如果不支持就回崩潰):
判定方法: [photoOutput.supportedFlashModes containsObject:@(AVCaptureFlashModeAuto)].
當然還要遵守一些亂七八糟的規則,用到的時候在分析吧:

  • 閃光燈設置

iOS<10
FlashMode:AVCaptureDevice的屬性
設置設備的閃光燈模式
AVCaptureFlashModeOff = 0,關
AVCaptureFlashModeOn = 1,開
AVCaptureFlashModeAuto = 2,自動
注意:切換前必須先調用這個方法lockForConfiguration:鎖定設備,在進行切換
如果iOS>10,則:
通過設置AVCapturePhotoSettings.flashMode的屬性設置

AVCaptureVideoPreviewLayer

概念:
預覽圖層,CALayer 的子類,自動顯示相機產生的實時圖像
當打開攝像頭的時候,我們會看到手機像透明的一樣展示外面的圖像,其實不是透明看到的,而是攝像頭搜集外面的圖像數據,一點一點實時的展示在這個圖層上沒有這個圖層時,就只有該控制器的View顯示


以上概念講完,下面我梳理了一下他們之間的關系如下圖:


捕捉類關系圖.png

代碼演示:

上面講了一堆概念,下面我們通過寫一個模仿釘釘打卡拍照的demo來學會使用上面的捕捉類:(該demo適配iOS>10.0)
界面分析如下:


Snip20171027_7.png

原理:
也就是說打開攝拍照界面時,往上面隨便添加你想要的東西,只要再生成圖片時,使用位圖將這些你添加的東西畫到拍照的圖片上就行了

代碼如下:


//  ZHWaterMarkCamera.h
/*
 使用配置
 1. info.plist需要配置
 NSPhotoLibraryUsageDescription
 訪問相冊,是否允許
 NSCameraUsageDescription
 訪問相機,是否允許
 NSLocationWhenInUseUsageDescription
 獲取地理位置
 NSLocationAlwaysUsageDescription(ios10)
 NSLocationAlwaysAndWhenInUsageDescription(ios11)
 獲取地理位置
 2.將圖片資源拖進Assets即可
 **/
#import <UIKit/UIKit.h>

@interface ZHWaterMarkCamera : UIViewController
//初始化方法
+(instancetype)makeWaterMarkCameraWithUserName:(NSString *)userName andCompletedBlock:(void(^)(UIImage *image))complete;
/** 是否需要12小時制處理,default is NO */
@property (nonatomic, assign) BOOL isTwelveHandle;
@end


//  ZHWaterMarkCamera.m
//  水印相機

#import "ZHWaterMarkCamera.h"
#import "ZHWaterMarkTool.h"
#import <AVFoundation/AVFoundation.h>
#import <CoreLocation/CoreLocation.h>

#define kScreenBounds [UIScreen mainScreen].bounds
#define kScreenWidth  [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define kSystemVersion [[[UIDevice currentDevice] systemVersion] floatValue]

@interface ZHWaterMarkCamera ()<UIGestureRecognizerDelegate,AVCapturePhotoCaptureDelegate,CLLocationManagerDelegate>

/*******AVFoundation部分*********/
/*
 捕獲設備,通常是前置攝像頭,后置攝像頭,麥克風(音頻輸入)
 */
@property(nonatomic)AVCaptureDevice *device;
/**
 AVCaptureSession對象來執行輸入設備和輸出設備之間的數據傳遞
 */
@property (nonatomic, strong) AVCaptureSession *captureSession;
/** 輸入設備
 */
@property (nonatomic, strong) AVCaptureDeviceInput *deviceInput;

//包含AVCaptureStillImageOutput/AVCapturePhotoOutput
@property (nonatomic,strong) AVCaptureOutput *captureOutput;
/** 針對AVCapturePhotoOutput 類似于 AVCaptureStillImageOutput 的 outputSettings */
@property (nonatomic, strong) AVCapturePhotoSettings *photoSettings;
/**  預覽圖層
 */
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;

/*******界面控件*********/
//閃光燈按鈕
@property (strong, nonatomic)  UIButton *flashButton;
/** 切換攝像頭按鈕 */
@property (nonatomic, strong) UIButton *switchButton;
/** 拍照按鈕 */
@property (nonatomic, strong) UIButton *cameraButton;
/*******界面數據*********/
/**  記錄開始的縮放比例 */
@property(nonatomic,assign)CGFloat beginGestureScale;
/** 最后的縮放比例 */
@property(nonatomic,assign)CGFloat effectiveScale;
/** 水印時間 */
@property (nonatomic, strong) NSString *timeString;
/** 水印日期 */
@property (nonatomic, strong) NSString *dateString;
/** 使用按鈕 */
@property (nonatomic, strong) UIButton *useImageBtn;
/** 取消/重拍按鈕 */
@property (nonatomic, strong) UIButton *leftButon;
/** 獲取拍攝的照片 */
@property (nonatomic, strong) UIImage *image;
/** 閃光燈文字 */
@property (nonatomic, strong) UILabel *flashLabel;
/** 點擊時的對焦框 */
@property (nonatomic)UIView *focusView;
/** 拍完照顯示生成的照片,保證預覽的效果和實際效果一致 */
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIView *topBlackView;
/*******獲取地理位置*********/
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic,strong) CLGeocoder *geocoder;
//姓名//地址名稱
@property (nonatomic,strong) NSString *userName;
@property (nonatomic,strong) NSString *adressStr;
@property (nonatomic,weak) UILabel *adressLabel;
@property (nonatomic,weak) UIImageView *bottomMaskView;
@property (nonatomic,copy) void (^complete)(UIImage *);
@end

@implementation ZHWaterMarkCamera
#pragma mark - 懶加載
//初始化設備
-(AVCaptureDevice *)device{
    if (_device == nil) {
        //拿到后置攝像頭
        _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //將閃光燈設置為自動,只試用與iOS<10.0
        if (kSystemVersion<10.0) {
            NSError *errors;
            [_device lockForConfiguration:&errors];
            if (errors) {
                //鎖定失敗
                return nil;
            }
            [_device setFlashMode:AVCaptureFlashModeAuto];
            [_device unlockForConfiguration];
        }
    }
    return _device ;
}
//初始化deviceInput
-(AVCaptureDeviceInput *)deviceInput{
    if (_deviceInput == nil) {
        if (!self.device) {
            //獲取設備失敗(模擬器)
            return nil;
        }
        NSError *error;
        _deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:&error];
        if (error) {
            return nil;
        }
    }
    return _deviceInput ;
}
//初始化捕捉會話
-(AVCaptureSession *)captureSession{
    if (_captureSession == nil) {
        _captureSession = [[AVCaptureSession alloc] init];
    }
    return _captureSession ;
}
//初始化AVCaptureOutput
-(AVCaptureOutput *)captureOutput{
    if (_captureOutput == nil) {
        //10.0之前的創建方式
        if (kSystemVersion < 10.0) {
            AVCaptureStillImageOutput *output = [[AVCaptureStillImageOutput alloc] init];
            //對輸出進行配置支持哪些格式
            NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
            [output setOutputSettings:outputSettings];
            _captureOutput = output;
        } else {
            //10.0之后的創建方式
            //創建輸出
            AVCapturePhotoOutput *photoOutput= [[AVCapturePhotoOutput alloc] init];
            //配置輸出
            AVCapturePhotoSettings *photoOutputSet  = [AVCapturePhotoSettings photoSettings];
            // [photoOutput capturePhotoWithSettings:photoOutputSet delegate:self];
            //初始化閃光燈設置
            photoOutputSet.flashMode = AVCaptureFlashModeAuto;
            _photoSettings = photoOutputSet;
            [photoOutput setPhotoSettingsForSceneMonitoring:photoOutputSet];
            _captureOutput = photoOutput;
        }
    }
    return _captureOutput ;
}
//初始化預覽圖層
-(AVCaptureVideoPreviewLayer *)previewLayer{
    if (_previewLayer == nil) {
        _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
        _previewLayer.frame = CGRectMake(0, 0,kScreenWidth, kScreenHeight);
        self.view.layer.masksToBounds = YES;
        _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    }
    return _previewLayer ;
}

#pragma mark - 系統方法
+(instancetype)makeWaterMarkCameraWithUserName:(NSString *)userName andCompletedBlock:(void (^)(UIImage *))complete{
    
    return [[self alloc] initWithName:userName andBlock: complete];
}
-(instancetype)initWithName:(NSString *)name andBlock:(void (^)(UIImage *))complete{
    if (self = [super init]) {
        _userName = name;
        _complete = complete;
    }
    return self;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    //獲取地理位置
    [self startLocation];
    //初始化設備裝置
    [self initAVCaptureSession];
    //初始化UI界面
    [self configureUI];
    //初始化縮放比例
    self.effectiveScale = self.beginGestureScale = 1.0f;
}

- (void)viewDidDisappear:(BOOL)animated{
    
    [super viewDidDisappear:YES];
    if (self.captureSession) {
        //停止掃描
        //停止流
        [self.captureSession stopRunning];
    }
}
/**
 隱藏導航欄
 */
-(BOOL)prefersStatusBarHidden {
    return YES;
}
//只支持豎屏
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - 獲取地理位置
- (void)startLocation {
    // 初始化定位管理器
    _locationManager = [[CLLocationManager alloc] init];
    [_locationManager requestAlwaysAuthorization];
    [_locationManager requestWhenInUseAuthorization];
    // 設置代理
    _locationManager.delegate = self;
    // 設置定位精確度到米
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    // 設置過濾器為無
    _locationManager.distanceFilter = kCLDistanceFilterNone;
    // 開始定位
    [_locationManager startUpdatingLocation];//開始定位之后會不斷的執行代理方法更新位置會比較費電所以建議獲取完位置即時關閉更新位置服務
    //初始化地理編碼器
    _geocoder = [[CLGeocoder alloc] init];
}
#pragma mark - CLLocationManagerDelegate-
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    CLLocation * location = locations.lastObject;
    [_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        if (placemarks.count > 0) {
            CLPlacemark *placemark = [placemarks objectAtIndex:0];
            //獲取城市
            NSString *city = placemark.locality;
            if (!city) {
                //四大直轄市的城市信息無法通過locality獲得,只能通過獲取省份的方法來獲得(如果city為空,則可知為直轄市)
                city = placemark.administrativeArea;
            }
            // 位置名
            self.adressStr = placemark.name;
        }else {
            self.adressStr = @"獲取位置失敗";
        }
        //不用的時候關閉更新位置服務
        [self.locationManager stopUpdatingLocation];
        //更新地址label
        [self updateAdressLabel];
        //隱藏提示
        self.adressLabel.hidden = YES;
        //相機使能
        self.cameraButton.enabled = YES;
        //開始流
        if (self.captureSession) {
            //開始掃描
            //啟動從輸入到輸出的數據流
            [self.captureSession startRunning];
        }
    }];
    
}
#pragma mark - 設備配置
- (void)initAVCaptureSession{
    //1.初始化捕獲會話(懶加載)
    //2.初始化捕捉設備并配置設備(懶加載)
    //3.初始化輸入捕獲(懶加載)
    //4.初始化輸出捕獲(懶加載)
    //5.將輸入輸出分別添加到捕捉會話中
    //判斷是否能夠添輸入到會話中
    if (![self.captureSession canAddInput:self.deviceInput]) {
        return;
    }
    if (![self.captureSession canAddOutput:self.captureOutput]) {
        return;
    }
    [self.captureSession addInput:self.deviceInput];
    [self.captureSession addOutput:self.captureOutput];
    
    
    //6.圖層預覽
    [self.view.layer addSublayer:self.previewLayer];
}

#pragma mark - 初始化UI
-(void)configureUI {
    //1.添加預覽圖層頂部的黑色導航欄
    self.topBlackView = [self createTopBlackView];
    //2.左上角日期時間顯示view
    [self topMaskViewWithView:self.topBlackView];
    //3.添加底部黑色導航欄View
    UIView *bottomBlackView = [self bottomBlackView];
    //4.底部姓名/地址label
    self.bottomMaskView = [self bottomMaskViewWithView:bottomBlackView];
    //5.黃色對焦框添加(就是一個透明View然后添加邊框即可)
    _focusView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
    _focusView.layer.borderWidth = 1.0;
    _focusView.layer.borderColor =[UIColor orangeColor].CGColor;
    _focusView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:_focusView];
    _focusView.hidden = YES;
    //6.給View添加點擊手勢(獲取焦距)
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(focusGesture:)];
    [self.view addGestureRecognizer:tapGesture];
    //7.添加縮放手勢
    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
    pinch.delegate = self;
    [self.view addGestureRecognizer:pinch];
    //獲取位置前屏幕中間提示正在獲取位置信息
    UILabel *adressLabel = [[UILabel alloc] init];
    adressLabel.text = @"位置獲取中...";
    adressLabel.textColor = [UIColor whiteColor];
    adressLabel.textAlignment = NSTextAlignmentCenter;
    adressLabel.frame = CGRectMake((kScreenWidth-100)*0.5, kScreenHeight * 0.5, 100, 30);
    [self.view addSubview:adressLabel];
    self.view.backgroundColor = [UIColor blackColor];
    self.cameraButton.enabled = NO;
    self.adressLabel = adressLabel;
}
/**
 *  頂部黑色導航view
 */
-(UIView *)createTopBlackView {
    //創建一個頂部的View
    UIView *topBlackView = [ZHWaterMarkTool viewWithFrame:CGRectMake(0, 0, kScreenWidth, 50) WithSuperView:self.view];
    //在View上添加按鈕
    /** 切換前置后置攝像頭按鈕 */
    _switchButton = [ZHWaterMarkTool buttonWithTitle:nil imageName:@"cameraBack" target:self action:@selector(switchCameraSegmentedControlClick:)];
    _switchButton.frame = CGRectMake(kScreenWidth-45, 12.5, 30, 23);
    [topBlackView addSubview:_switchButton];
    
    /** 閃光燈操作按鈕 */
    //左邊是按鈕
    _flashButton = [ZHWaterMarkTool buttonWithTitle:nil imageName:@"camera_light_n" target:self action:@selector(flashButtonClick:)];
    _flashButton.frame = CGRectMake(20, 12.5, 13, 21);
    [topBlackView addSubview:_flashButton];
    //右邊是"自動"標題
    _flashLabel = [ZHWaterMarkTool labelWithText:@"自動" fontSize:14 alignment:NSTextAlignmentCenter];
    _flashLabel.frame = CGRectMake(CGRectGetMaxX(_flashButton.frame), CGRectGetMinY(_flashButton.frame), 50, 21);
    [topBlackView addSubview:self.flashLabel];
    /** 因為閃光燈圖標太小,點擊比較費勁,所以添加一個空白按鈕增大點擊范圍 */
    UIButton *tapButton = [ZHWaterMarkTool buttonWithTitle:nil imageName:nil target:self action:@selector(flashButtonClick:)];
    [tapButton setFrame:(CGRectMake(20, 0, 65, 50))];
    [tapButton setBackgroundColor:[UIColor clearColor]];
    [topBlackView addSubview:tapButton];
    
    return topBlackView;
}

/**
 *  頂部蒙版
 */
-(UIImageView *)topMaskViewWithView:(UIView *)view {
    //1.半透明imageView
    UIImageView *topMaskview = [[UIImageView alloc] initWithFrame:(CGRectMake(0, CGRectGetMaxY(view.frame), kScreenWidth, 100))];
    topMaskview.image = [UIImage imageNamed:@"markTopMView"];
    [self.view addSubview:topMaskview];
    //2.獲得當前日期時間
    NSString *timeStr = timeStr = [ZHWaterMarkTool dateStingWithFormatterSting:@"yyyy.MM.dd hh:mm" andInputDate:nil];
    NSString *dateString = [timeStr substringWithRange:NSMakeRange(0, 10)];
    //時間字符串
    self.timeString = [timeStr substringWithRange:NSMakeRange(11, 5)];
    //獲得今天星期幾
    NSString *weekDay = [ZHWaterMarkTool weekdayStringFromDate:nil];
    //日期字符串
    self.dateString = [NSString stringWithFormat:@"%@ %@",dateString,weekDay];
    if (self.isTwelveHandle) {
        BOOL hasAMPM = [ZHWaterMarkTool isTwelveMechanism];
        int time = [ZHWaterMarkTool currentIntTime];
        self.timeString = hasAMPM ? [NSString stringWithFormat:@"%@%@",self.timeString,(time > 12 ? @"pm" : @"am")] : self.timeString;
    }
    //添加顯示label
    //顯示時間的label
    UILabel *label = [ZHWaterMarkTool labelWithText:self.timeString fontSize:30 alignment:0];
    label.frame = CGRectMake(20, 20, 150, 30);
    //顯示日期的label
    UILabel *dateLabel = [ZHWaterMarkTool labelWithText:self.dateString fontSize:14 alignment:0];
    dateLabel.frame = CGRectMake(20, CGRectGetMaxY(label.frame)+5, 200, 15);
    [topMaskview addSubview:label];
    [topMaskview addSubview:dateLabel];
    return topMaskview;
}
/**
 *  底部黑色view
 */
-(UIView *)bottomBlackView {
    //底部導航欄View
    UIView *bottomBlackView = [ZHWaterMarkTool viewWithFrame:CGRectMake(0, kScreenHeight - 125, kScreenWidth, 125) WithSuperView:self.view];
    
    /** 拍照按鈕 */
    self.cameraButton = [ZHWaterMarkTool buttonWithTitle:nil imageName:@"cameraPress" target:self action:@selector(takePhotoButtonClick:)];
    self.cameraButton.frame = CGRectMake(kScreenWidth*1/2.0-34, 23, 68, 68);
    [bottomBlackView addSubview:self.cameraButton];
    
    /** 取消/重拍 */
    self.leftButon = [ZHWaterMarkTool buttonWithTitle:@"取消" imageName:nil target:self action:@selector(cancle:)];
    self.leftButon.frame = CGRectMake(5, 32.5, 60, 60);
    [bottomBlackView addSubview:self.leftButon];
    
    /** 使用照片 */
    self.useImageBtn = [ZHWaterMarkTool buttonWithTitle:@"使用" imageName:nil target:self action:@selector(userImage:)];
    self.useImageBtn.frame = CGRectMake(kScreenWidth -65, 32.5, 50, 50);
    self.useImageBtn.hidden = YES;
    [bottomBlackView addSubview:self.useImageBtn];
    return bottomBlackView;
}
/**
 *  底部蒙版
 */
-(UIImageView *)bottomMaskViewWithView:(UIView *)bottomBlackView {
    //半透明ImgeView
    UIImageView *bottomMaskView = [ZHWaterMarkTool imageViewWithImageName:@"markBottomMView" superView:self.view frame:CGRectMake(0, CGRectGetMinY(bottomBlackView.frame) - 100, kScreenWidth, 100)];
    //添加姓名label
    CGFloat width = [ZHWaterMarkTool calculateRowWidth:self.userName fontSize:14 fontHeight:14];
    UILabel *userLabel = [ZHWaterMarkTool labelWithText:self.userName fontSize:14 alignment:2];
    userLabel.frame = CGRectMake(bottomMaskView.frame.size.width - width - 20, 35,width, 30);
    //小頭像圖標
    [ZHWaterMarkTool imageViewWithImageName:@"markUser" superView:bottomMaskView frame:CGRectMake(CGRectGetMinX(userLabel.frame)- 15, userLabel.center.y - 6.5, 13, 13)];
    [bottomMaskView addSubview:userLabel];
    //添加地址label
    CGFloat widthx = [ZHWaterMarkTool calculateRowWidth:@"地址信息" fontSize:14 fontHeight:14];
    UILabel *addLabel = [ZHWaterMarkTool labelWithText:@"地址信息" fontSize:14 alignment:2];
    addLabel.frame = CGRectMake(bottomMaskView.frame.size.width - widthx - 20, 60,widthx, 30);
    addLabel.tag = 101;
    //地址圖標
    UIImageView *addimageView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMinX(addLabel.frame)- 15, addLabel.center.y - 6.5, 13, 13)];
    addimageView.image = [UIImage imageNamed:@"icon_add"];
    addimageView.tag = 102;
    [bottomMaskView addSubview:addimageView];
    [bottomMaskView addSubview:addLabel];
    
    return bottomMaskView;
}
//獲取到地址信息時更新地址label
-(void)updateAdressLabel{
    UIView *supppView = _bottomMaskView;
    UILabel *addLabel = [supppView viewWithTag:101];
    UIImageView *addImageView = [supppView viewWithTag:102];
    CGFloat widthx = [ZHWaterMarkTool calculateRowWidth:self.adressStr fontSize:14 fontHeight:14];
    addLabel.text = self.adressStr;
    addLabel.frame =  CGRectMake(_bottomMaskView.frame.size.width - widthx - 20, 60,widthx, 30);
    addImageView.frame = CGRectMake(CGRectGetMinX(addLabel.frame)- 15, addLabel.center.y - 6.5, 13, 13);
}

#pragma mark - 事件處理
//切換鏡頭
- (void)switchCameraSegmentedControlClick:(UIButton *)sender {
    //根據媒體類型拿到當前能輸入媒體數據的所有可用的設備源(前/后置攝像頭,這時沒有用到語音,因此不可用的)
    NSUInteger cameraCount = [self obtainAvailableDevices].count;
    //說明前后攝像頭都能用
    if (cameraCount > 1) {
        NSError *error;
        //添加旋轉動畫
        CATransition *animation = [CATransition animation];
        animation.duration = .3f;
        animation.type = @"oglFlip";
        //新的設備新的輸入
        AVCaptureDevice *newCamera = nil;
        AVCaptureDeviceInput *newInput = nil;
        //拿到當前設備的位置
        AVCaptureDevicePosition position = self.deviceInput.device.position;
        if (position == AVCaptureDevicePositionFront){
            //如果當前為前置,那就拿到后置
            newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
            //動畫左向右翻轉
            animation.subtype = kCATransitionFromLeft;
            //前置到后置,顯示閃光燈
            self.flashButton.hidden = NO;
            self.flashLabel.hidden = NO;
        }else {
            //當前為后置,那就拿到前置
            newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
            //動畫從右往左翻轉
            animation.subtype = kCATransitionFromRight;
            //后置到前置,隱藏閃光燈
            self.flashButton.hidden = YES;
            self.flashLabel.hidden = YES;
        }
        //添加動畫到圖層
        [self.previewLayer addAnimation:animation forKey:nil];
        //根據新的設備創建新的輸入捕捉
        newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
        if (newInput != nil) {
            //捕捉會話開始配置
            [self.captureSession beginConfiguration];
            //移除捕捉輸入
            [self.captureSession removeInput:self.deviceInput];
            //添加新的捕捉輸入
            if ([self.captureSession canAddInput:newInput]) {
                [self.captureSession addInput:newInput];
                self.deviceInput = newInput;
            } else {
                [self.captureSession addInput:self.deviceInput];
            }
            //提交會話配置
            [self.captureSession commitConfiguration];
            
        } else if (error) {
            NSLog(@"toggle carema failed, error = %@", error);
        }
    }
}
//拿到所有可用的攝像頭(video)設備
-(NSArray *)obtainAvailableDevices{
    if (kSystemVersion < 10.0) {
        return [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    } else {
        AVCaptureDeviceDiscoverySession *deviceSession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera,AVCaptureDeviceTypeBuiltInDualCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
        return deviceSession.devices;
    }
}
//根據前后位置拿到相應的設備
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
    NSArray *devices = [self obtainAvailableDevices];
    if (!devices) {
        return nil;
    }
    for ( AVCaptureDevice *device in devices ){
        if ( device.position == position ){
            return device;
        }
    }
    return nil;
}
//閃光燈模式切換
- (void)flashButtonClick:(UIButton *)sender {
    //拿到后置攝像頭
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //自動->打開->關閉
    //必須判定是否有閃光燈,否則如果沒有閃光燈會崩潰
    if (!device.hasFlash) {
        NSLog(@"設備不支持閃光燈");
        return ;
    }
    AVCaptureFlashMode tempflashMode = AVCaptureFlashModeOff;
    //拿到當前設備的閃光狀態
    AVCaptureFlashMode xxflshMode = kSystemVersion >10.0 ? self.photoSettings.flashMode : device.flashMode;
    switch (xxflshMode) {
        case AVCaptureFlashModeOff: {//關閉->自動
            tempflashMode = AVCaptureFlashModeAuto;
            self.flashLabel.text = @"自動";
            break;
        }
        case AVCaptureFlashModeOn: {//開->關閉
            tempflashMode = AVCaptureFlashModeOff;
            self.flashLabel.text = @"關閉";
            break;
        }
        case AVCaptureFlashModeAuto: {//自動->打開
            tempflashMode = AVCaptureFlashModeOn;
            self.flashLabel.text = @"打開";
            break;
        }
        default:
            break;
    }
    if (kSystemVersion < 10.0) {
        //修改前必須先鎖定
        [device lockForConfiguration:nil];
        if ([device isFlashModeSupported:tempflashMode])
            [device setFlashMode:tempflashMode];
        [device unlockForConfiguration];
    }else{
        //修改outputseting的閃光燈模式
        self.photoSettings.flashMode = tempflashMode;
    }
}
//點擊拍照
- (void)takePhotoButtonClick:(UIButton *)sender {
    
    self.useImageBtn.hidden = NO;
    self.flashLabel.hidden = YES;
    self.flashButton.hidden = YES;
    self.switchButton.hidden = YES;
    [self.leftButon setTitle:@"重拍" forState:(UIControlStateNormal)];
    sender.hidden = YES;
    //拿到連接
    AVCaptureConnection *stillImageConnection = [self.captureOutput connectionWithMediaType:AVMediaTypeVideo];
    //拿到當前手機方向
    UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];
    //根據當前手機方向設置攝像頭拍攝方向
    AVCaptureVideoOrientation avcaptureOrientation = [self avOrientationForDeviceOrientation:curDeviceOrientation];
    //設置圖片方向
    [stillImageConnection setVideoOrientation:avcaptureOrientation];
    //設置縮放比例
    [stillImageConnection setVideoScaleAndCropFactor:self.effectiveScale];
    if (kSystemVersion <10.0) {
        AVCaptureStillImageOutput *stillImageOutput = (AVCaptureStillImageOutput *)self.captureOutput;
        //生成靜態圖像數據
        [stillImageOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
            
            if (imageDataSampleBuffer == NULL) {
                return ;
            }
            //拿到圖片數據流
            NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            //生成image圖片(注意:這個image是沒有時間/個人信息/地址信息的)
            [self dealWithImage:[UIImage imageWithData:jpegData]];
        }];
    }else{
        /*
         這個地方有一個技巧:
         當前目前設備是后置攝像頭/閃光燈開時,切換到前置時,那么flashmode要設置為閃光燈關閉模式,否則會崩潰,但是當再次從前置切換到后置時,閃光燈狀態仍然要返回切換前后置之前的那個狀態!這就是為何要專門要使用一個搶引用來引用self.photoSettings的原因
         */
        //!!!!使用這個方法一定要遵守規則哦!!!!
        //1.重新創建配置(必須創建,一個setting只能使用一次前面說過)
        AVCapturePhotoSettings *newSettings = [AVCapturePhotoSettings photoSettingsFromPhotoSettings:self.photoSettings];
        AVCapturePhotoOutput *photoOutput =  (AVCapturePhotoOutput *)self.captureOutput;
        //2.判斷當前的閃光燈模式是否支持設備,如果不支持的話,會崩潰(閃光燈規則)
        //后置攝像頭閃光燈支持0,1,2 //前置攝像頭閃光燈只支持0
        if (![photoOutput.supportedFlashModes containsObject:@(newSettings.flashMode)]) {
            //不支持,那么當前設備一定是前置攝像頭,那么修改配置
            newSettings.flashMode = AVCaptureFlashModeOff;
        }
        [photoOutput capturePhotoWithSettings:newSettings delegate:self];
    }
}

//根據當前手機方向拿到攝像頭拍攝方向
- (AVCaptureVideoOrientation)avOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation{
    AVCaptureVideoOrientation result = (AVCaptureVideoOrientation)deviceOrientation;
    if ( deviceOrientation == UIDeviceOrientationLandscapeLeft )
        result = AVCaptureVideoOrientationLandscapeRight;
    else if ( deviceOrientation == UIDeviceOrientationLandscapeRight )
        result = AVCaptureVideoOrientationLandscapeLeft;
    return result;
}

//取消/重拍
-(void)cancle:(UIButton *)sender {
    if ([sender.titleLabel.text isEqualToString:@"取消"]) {
        [self dismissViewControllerAnimated:YES completion:nil];
    } else {
        [sender setTitle:@"取消" forState:(UIControlStateNormal)];
        [self.imageView removeFromSuperview];
        self.cameraButton.hidden = NO;
        self.useImageBtn.hidden = YES;
        self.switchButton.hidden = NO;
        //判斷當前攝像頭方向,如果前置隱藏閃光設置,反之顯示
        AVCaptureDevicePosition position = self.deviceInput.device.position;
        if (position == AVCaptureDevicePositionFront) {
            self.flashLabel.hidden = YES;
            self.flashButton.hidden = YES;
        }else{
            self.flashLabel.hidden = NO;
            self.flashButton.hidden = NO;
        }
        //重新開始流
        [self.captureSession startRunning];
    }
}
//使用圖片調用代理方法返回圖片
-(void)userImage:(UIButton *)button {
    if (_complete) {
        _complete(self.image);
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}
//點擊聚焦
- (void)focusGesture:(UITapGestureRecognizer*)gesture{
    //拿到點擊點
    CGPoint point = [gesture locationInView:gesture.view];
    //設置聚焦
    [self focusAtPoint:point];
}
- (void)focusAtPoint:(CGPoint)point{
    CGSize size = self.view.bounds.size;
    //點擊除了上下黑色導航欄以內的才會聚焦
    if (point.y > (kScreenHeight - 125)||point.y < 50) {
        return;
    }
    //找到聚焦位置(注意該point是在屏幕的比例位置)
    CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width );
    NSError *error;
    if ([self.device lockForConfiguration:&error]) {
        //對焦模式和對焦點
        if ([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [self.device setFocusPointOfInterest:focusPoint];
            [self.device setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        //曝光模式和曝光點
        if ([self.device isExposureModeSupported:AVCaptureExposureModeAutoExpose ]) {
            [self.device setExposurePointOfInterest:focusPoint];
            [self.device setExposureMode:AVCaptureExposureModeAutoExpose];
        }
        [self.device unlockForConfiguration];
        //設置對焦動畫
        _focusView.center = point;
        _focusView.hidden = NO;
        [UIView animateWithDuration:0.3 animations:^{
            //先放大1.25倍
            _focusView.transform = CGAffineTransformMakeScale(1.25, 1.25);
        }completion:^(BOOL finished) {
            [UIView animateWithDuration:0.5 animations:^{
                //再返回原來的尺寸
                _focusView.transform = CGAffineTransformIdentity;
            } completion:^(BOOL finished) {
                _focusView.hidden = YES;
            }];
        }];
    }
}
//縮放手勢 用于調整焦距(設置圖層的縮放比例)
/*
 原理:
 手勢添加到了self.view上,當兩個手指開始縮放時只是把self.view縮放了,self.previewLayer圖層也跟著縮放,而此時相機捕獲的圖片數據,仍然是沒有縮放前的,因此拿到縮放比例給連接(AVCaptureConnection)設置,一點擊拍照就會根據所設置的連接獲取縮放后的圖片數據
 **/
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer{
    /*******該段代碼用于判斷觸摸點是否超過圖層有效區域*********/
    BOOL allTouchesAreOnThePreviewLayer = YES;
    //拿到觸摸點(幾根手指)
    NSUInteger numTouches = [recognizer numberOfTouches];
    for (int i = 0; i < numTouches; ++i) {
        //拿到每個觸摸點在view上面的位置
        CGPoint location = [recognizer locationOfTouch:i inView:self.view];
        //轉化成在self.previewLayer上面的位置
        CGPoint convertedLocation = [self.previewLayer convertPoint:location fromLayer:self.previewLayer.superlayer];
        //判斷這個觸摸點是否在self.previewLayer圖層上面,在上面才會縮放
        if ( ! [self.previewLayer containsPoint:convertedLocation] ) {
            allTouchesAreOnThePreviewLayer = NO;
            break;
        }
    }
    /*******在有效區域內*********/
    if (allTouchesAreOnThePreviewLayer) {
        //根據手勢縮放比例拿到新的縮放比例
        self.effectiveScale = self.beginGestureScale * recognizer.scale;
        //縮小最小為1.0
        if (self.effectiveScale < 1.0){
            self.effectiveScale = 1.0;
        }
        //拿到相機支持的最大縮放比例
        CGFloat maxScaleAndCropFactor = [[self.captureOutput connectionWithMediaType:AVMediaTypeVideo] videoMaxScaleAndCropFactor];
        //設置最大縮放比例
        if (self.effectiveScale > maxScaleAndCropFactor)
            self.effectiveScale = maxScaleAndCropFactor;
        //添加縮放動畫到圖層上
        [CATransaction begin];
        [CATransaction setAnimationDuration:.025];
        [self.previewLayer setAffineTransform:CGAffineTransformMakeScale(self.effectiveScale, self.effectiveScale)];
        [CATransaction commit];
    }
}

#pragma mark - gestureRecognizer delegate
//開始縮放時調用
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if ( [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] ) {
        //開始縮放屏幕前初始化縮放比例
        self.beginGestureScale = self.effectiveScale;
    }
    return YES;
}
#pragma mark - AVCapturePhotoCaptureDelegate
//用于監視照片的拍攝過程,實時獲取到拍照的圖層數據
-(void)captureOutput:(AVCapturePhotoOutput *)captureOutput didFinishProcessingPhotoSampleBuffer:(CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(AVCaptureBracketedStillImageSettings *)bracketSettings error:(NSError *)error{
    if (error) {
        NSLog(@"error : %@", error.localizedDescription);
        return;
    }
    if (!photoSampleBuffer) {
        return;
    }
    NSData *data = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer];
    [self dealWithImage:[UIImage imageWithData:data]];
}

#pragma mark - 畫圖層
//處理圖片
-(void)dealWithImage:(UIImage *)image{
    //前置攝像頭拍照會旋轉180解決辦法
    if (self.deviceInput.device.position == AVCaptureDevicePositionFront) {
        UIImageOrientation imgOrientation = UIImageOrientationLeftMirrored;
        image = [[UIImage alloc]initWithCGImage:image.CGImage scale:1.0f orientation:imgOrientation];
    }
    //重新畫一張圖片(將時間/個人信息/地址信息畫上去)
    self.image = [self drawMarkImage:image];
    //停止流
    [self.captureSession stopRunning];
    //展示圖片view
    //防止重復添加
    if (self.imageView) {
        [self.imageView removeFromSuperview];
    }
    self.imageView = [[UIImageView alloc]initWithFrame:self.previewLayer.frame];
    [self.view insertSubview:_imageView belowSubview:_topBlackView];
    self.imageView.layer.masksToBounds = YES;
    self.imageView.image = image;
}
/**
 *  繪制帶水印的圖片
 */
-(UIImage *)drawMarkImage:(UIImage *)image  {
    //開啟位圖上下文
    UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, NO, 0.0);
    //將相機拍到的圖片畫到上下文
    [image drawInRect:kScreenBounds];
    
    /** 頂部蒙版 */
    CGRect rectTopMask = CGRectMake(0, 0, kScreenWidth, 100);
    UIImage *imageTopMask = [UIImage imageNamed:@"markTopMView"];
    [imageTopMask drawInRect:rectTopMask];
    
    /** 時間 */
    CGRect rectTime = CGRectMake(20, 15, 200, 30);
    NSDictionary *dicTime = @{NSFontAttributeName:[UIFont systemFontOfSize:30],NSForegroundColorAttributeName:[UIColor whiteColor]};
    [self.timeString drawInRect:rectTime withAttributes:dicTime];
    
    /** 日期 */
    CGRect rectDate = CGRectMake(20, CGRectGetMaxY(rectTime) + 5, 200, 25);
    NSDictionary *dicDate = @{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:[UIColor whiteColor]};
    [self.dateString drawInRect:rectDate withAttributes:dicDate];
    
    /** 底部蒙版 */
    CGRect rectBottomMask = CGRectMake(0, kScreenHeight - 110, kScreenWidth, 110);
    UIImage *imageBottomMask = [UIImage imageNamed:@"markBottomMView"];
    [imageBottomMask drawInRect:rectBottomMask];
    
    /** logo */
    UIImage *logo = [UIImage imageNamed:@"markLogo"];
    [logo drawInRect:CGRectMake(kScreenWidth - 103, kScreenHeight - 70, 83,20)];
    
    /** 用戶名 */
    CGFloat width1 = [ZHWaterMarkTool calculateRowWidth:self.userName fontSize:14 fontHeight:20];
    CGRect rectUserName = CGRectMake(kScreenWidth - width1 - 20, kScreenHeight - 90, width1, 20);
    NSDictionary *dicUserName = @{NSFontAttributeName:[UIFont systemFontOfSize:14],NSForegroundColorAttributeName:[UIColor whiteColor]};
    [self.userName drawInRect:rectUserName withAttributes:dicUserName];
    
    /** 用戶圖標 */
    UIImage *imageUser = [UIImage imageNamed:@"markUser"];
    CGRect rectUser = CGRectMake(CGRectGetMinX(rectUserName) - 20, CGRectGetMinY(rectUserName), 13, 13);
    [imageUser drawInRect:rectUser];
    //地址名/地址圖標
    /** 地址名 */
    CGFloat width2 = [ZHWaterMarkTool calculateRowWidth:self.adressStr fontSize:14 fontHeight:20];
    CGRect rectadd = CGRectMake(kScreenWidth - width2 - 20, kScreenHeight - 70, width2, 20);
    NSDictionary *dicadd = @{NSFontAttributeName:[UIFont systemFontOfSize:14],NSForegroundColorAttributeName:[UIColor whiteColor]};
    [self.adressStr drawInRect:rectadd withAttributes:dicadd];
    
    /** 地址圖標 */
    UIImage *imageadd = [UIImage imageNamed:@"icon_add"];
    CGRect rectadd2 = CGRectMake(CGRectGetMinX(rectadd) - 20, CGRectGetMinY(rectadd), 13, 13);
    [imageadd drawInRect:rectadd2];
    //生成新的圖片
    UIImage *newPic = UIGraphicsGetImageFromCurrentImageContext();
    //關閉圖層上下文
    UIGraphicsEndImageContext();
    
    return newPic;
}
@end

github上Demo地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容