• iOS系统原生二维码扫描与生成


    iOS系统原生二维码代码

    1.扫描识别各种类型的码 (条形码, 二维码 , 彩色码 等)

    2.添加扫描视图的范围(中间框框)

    3.开启和关闭闪光灯

    4.识别相册中的二维码图片

    5.生成二维码图片

    先展示下效果图:

    1. 二维码扫描识别

    1.首先导入库文件

    #import <AVFoundation/AVFoundation.h>

    2.接着签订需要的代理, 并创建所需要的属性(这里我只讲述关键代码)

    AVCaptureMetadataOutputObjectsDelegate : 用于扫描获取到数据后的回调 , (metadataObjects: 扫描二维码数据信息)

    #import <AVFoundation/AVFoundation.h>

    #import "QRScanView.h"

    // 二维码扫描器

    @interface QrCodeReaderViewController () <AVCaptureMetadataOutputObjectsDelegate, AVCaptureVideoDataOutputSampleBufferDelegate,

        UIImagePickerControllerDelegate, UINavigationControllerDelegate>

    @property (nonatomic, strong) AVCaptureSession *session;

    @property (nonatomic, strong) AVCaptureVideoPreviewLayer *layer;

    @property (nonatomic, strong) AVCaptureMetadataOutput *output;

    @property (nonatomic, strong) AVCaptureVideoDataOutput *videoDataOutput;

    @property (nonatomic, assign) CGRect scanRect;

    @property (nonatomic, weak) QRScanView *scanView;

    @end

    @implementation QrCodeReaderViewController

    - (void)viewDidLoad {

        [super viewDidLoad];

        CGFloat scanWH = 220;

        CGFloat scanX = (kScreenWidth - scanWH) * 0.5;

        CGFloat scanY = (kScreenHeight - scanWH) * 0.5;

        self.scanRect = CGRectMake(scanX, scanY, scanWH, scanWH);

        AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

        if (status == AVAuthorizationStatusAuthorized || status == AVAuthorizationStatusRestricted) {

            [self loadScanView];

        } else if (status == AVAuthorizationStatusNotDetermined) {

            // 请求使用相机权限

            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {

                if (granted) {

                    dispatch_async(dispatch_get_main_queue(), ^{

                        [self loadScanView];

                    });

                } else {

                    [[[UIAlertView alloc] initWithTitle:@"无权限访问相机" message:@"无权限访问相机" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];

                }

            }];

        } else {

            [[[UIAlertView alloc] initWithTitle:@"无权限访问相机" message:@"无权限访问相机" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];

        }

        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"相册" style:UIBarButtonItemStylePlain target:self action:@selector(analyzeOnClick)];

    }

    #pragma mark - 从相册解析二维码图片

    - (void)analyzeOnClick {

        UIImagePickerController *picker = [[UIImagePickerController alloc] init];

        picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

        picker.delegate = self;

        [self presentViewController:picker animated:YES completion:nil];

    }

    - (void)loadScanView {

        //获取摄像设备

        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        //创建设备输入流

        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];

        //创建元数据输出流

        self.output = [[AVCaptureMetadataOutput alloc]init];

        //为输出流对象设置代理 并在主线程里刷新

        [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

        //初始化链接对象

        self.session = [[AVCaptureSession alloc]init];

        //设置高质量采集率

        [self.session setSessionPreset:AVCaptureSessionPresetHigh];

        // 添加设备输入流

        [self.session addInput:input];

        // 添加设备输出流

        [self.session addOutput:self.output];

        // 创建摄像数据输出流并将其添加到会话对象上 --> 用于识别光线强弱

        self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];

        [self.videoDataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

        [self.session addOutput:self.videoDataOutput];

        //设置扫码支持的编码格式(如下设置条形码和二维码兼容)

        self.output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,//二维码

                                    //以下为条形码,如果项目只需要扫描二维码,下面都不要写

                                    AVMetadataObjectTypeEAN13Code,

                                    AVMetadataObjectTypeEAN8Code,

                                    AVMetadataObjectTypeUPCECode,

                                    AVMetadataObjectTypeCode39Code,

                                    AVMetadataObjectTypeCode39Mod43Code,

                                    AVMetadataObjectTypeCode93Code,

                                    AVMetadataObjectTypeCode128Code,

                                    AVMetadataObjectTypePDF417Code];

        // 实例化预览图层, 用于显示会话对象

        self.layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];

        // 保持纵横比;填充层边界

        self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;

    //    layer.frame = self.view.layer.bounds;

        self.layer.frame = [UIScreen mainScreen].bounds;

        [self.view.layer insertSublayer:self.layer atIndex:0];

        // 在block中使用weak self,不然会导致该controller的内存无法回收

        __weak typeof(self) wekself = self;

        // 添加通知

        [[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {

            // 如果不设置,整个屏幕都可以扫

            wekself.output.rectOfInterest = [wekself.layer metadataOutputRectOfInterestForRect:wekself.scanRect];

        }];

        // 添加扫描视图

        QRScanView *scanView = [[QRScanView alloc] initWithScanRect:self.scanRect];

        [self.view addSubview:scanView];

        self.scanView = scanView;

        scanView.offFlashBlock = ^(BOOL flag) {

            [wekself offFlashWithMode:(flag ? AVCaptureTorchModeOn : AVCaptureTorchModeOff)];

        };

        //开始捕获

        [self.session startRunning];

    }

    // 根据Mode是否打开闪光灯

    - (void)offFlashWithMode:(AVCaptureTorchMode)mode {

        AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        NSError *error = nil;

        if ([captureDevice hasTorch]) {

            BOOL locked = [captureDevice lockForConfiguration:&error];

            if (locked && error == nil) {

                // 打开手电筒 | 关闭手电筒

                captureDevice.torchMode = mode;

                [captureDevice unlockForConfiguration];

            }

        }

    }

    #pragma mark - AVCaptureMetadataOutputObjectsDelegate

    // 扫描到数据后的回调

    -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{

        if (metadataObjects.count>0) {

            [self.session stopRunning];

            AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects[0];

            if (self.qrcodeValueBlock) {

                self.qrcodeValueBlock(metadataObject.stringValue);

            }

    //        [self.navigationController popViewControllerAnimated:YES];

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                [self.session startRunning];

            });

        }

    }

    #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate

    // 获取到光线的强弱值

    - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

        // 这个方法会时时调用,但内存很稳定

        CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL, sampleBuffer, kCMAttachmentMode_ShouldPropagate);

        NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary *)metadataDict];

        CFRelease(metadataDict);

        NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];

        float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];

        NSLog(@"%f", brightnessValue);

        self.scanView.brightnessValue = brightnessValue;

    }

    #pragma mark - UIImagePickerContorllerDelegate

    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {

        // 对选取照片的处理,如果选取的图片尺寸过大,则压缩选取图片,否则不处理

        UIImage *originalImage = info[UIImagePickerControllerOriginalImage];

        UIImage *image = [self imageSizeWithScreenImage:originalImage];

        // CIDetector (CIDetector可用于人脸识别)进行图片解析,从而使我们可以便捷的从相册中获取到二维码

        // 声明一个CIDetector,并设定识别类型 CIDetectorTypeQRCode

        CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];

        // 获取识别结果

        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];

        if ([features count] <= 0) {

            [BaseViewController alertWithTitle:@"识别结果为nil"];

        } else {

            CIQRCodeFeature *feature = [features firstObject];

            [BaseViewController alertWithTitle:feature.messageString];

    //        for (CIQRCodeFeature *feature in features) {

    //            NSLog(@"%@", feature.messageString);

    //        }

        }

        [picker dismissViewControllerAnimated:YES completion:nil];

    }

    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

        [picker dismissViewControllerAnimated:YES completion:nil];

    }

    // 返回一张不超过屏幕尺寸的image

    - (UIImage *)imageSizeWithScreenImage:(UIImage *)image {

        CGFloat imageW = image.size.width;

        CGFloat imageH = image.size.height;

        CGFloat screenW = kScreenWidth;

        CGFloat screenH = kScreenHeight;

        if (imageW <= screenW && imageH <= screenH) {

            return image;

        }

        CGFloat max = MAX(imageW, imageH);

        CGFloat scale = max / (screenH * 2.0);

        CGSize size = CGSizeMake(imageW / scale, imageW / scale);

        UIGraphicsBeginImageContext(size);

        [image drawInRect:CGRectMake(0, 0, size.width, size.height)];

        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();

        return newImage;

    }

    - (void)dealloc {

        NSLog(@"QrCodeReader - dealloc");

        // 将引用置空

        [[NSNotificationCenter defaultCenter] removeObserver:self];

        [self.session stopRunning];

        self.session = nil;

        self.layer = nil;

        self.output = nil;

        self.videoDataOutput = nil;

    }

    @end

    // 自定义扫描视图

    @interface QRScanView : UIView

    - (instancetype)initWithScanRect:(CGRect)scanRect;

    // 是否隐藏开启闪光灯按钮

    @property (nonatomic, assign) float brightnessValue;

    @property (nonatomic, copy) void (^offFlashBlock)(BOOL flag);

    @end

    #import "QRScanView.h"

    @interface QRScanView()

    @property (nonatomic, weak) UIView *lineView;

    @property (nonatomic, weak) UIButton *flashBtn;

    @end

    @implementation QRScanView {

        CGRect _scanRect;

        dispatch_source_t timer;

    }

    - (instancetype)initWithScanRect:(CGRect)scanRect {

        if (self = [super initWithFrame:[UIScreen mainScreen].bounds]) {

            self.backgroundColor = [UIColor clearColor];

            _scanRect = scanRect;

            UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(scanRect.origin.x, scanRect.origin.y, scanRect.size.width, 1)];

            lineView.backgroundColor = [UIColor greenColor];

            lineView.tag = 1;

            [self addSubview:lineView];

            self.lineView = lineView;

            UIButton *flashBtn = [[UIButton alloc] initWithFrame:CGRectMake(scanRect.origin.x, CGRectGetMaxY(scanRect) + 15, scanRect.size.width, 40)];

            flashBtn.hidden = YES;

            [flashBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

            [flashBtn setTitle:@"开启闪光灯" forState:UIControlStateNormal];

            [flashBtn addTarget:self action:@selector(openFlashOnClick) forControlEvents:UIControlEventTouchUpInside];

            [self addSubview:flashBtn];

            self.flashBtn = flashBtn;

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                [self dispatchScanViewAnimation];

            });

        }

        return self;

    }

    - (void)openFlashOnClick {

        self.flashBtn.selected = !self.flashBtn.selected;

        [self.flashBtn setTitle:(self.flashBtn.selected ? @"关闭闪光灯" : @"开启闪光灯") forState:UIControlStateNormal];

        if (self.offFlashBlock) {

            self.offFlashBlock(self.flashBtn.selected);

        }

    }

    - (void)setBrightnessValue:(float)brightnessValue {

        _brightnessValue = brightnessValue;

        if (brightnessValue < -1) {

            self.flashBtn.hidden = NO;

        } else if (self.flashBtn.selected == NO && self.flashBtn.hidden == NO) {

            self.flashBtn.hidden = YES;

        }

    }

    - (void)dispatchScanViewAnimation {

        if (timer) {

            dispatch_source_cancel(timer);

            timer = nil;

        }

        timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(1, 1));

        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.003 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);

        dispatch_source_set_event_handler(timer, ^{

            dispatch_async(dispatch_get_main_queue(), ^{

                CGRect frame = self.lineView.frame;

                if (self.lineView.tag == 2) {

                    frame.origin.y -= 0.5;

                    if (frame.origin.y <= _scanRect.origin.y) {

                        self.lineView.tag = 1;

                    }

                } else {

                    frame.origin.y += 0.5;

                    if (CGRectGetMaxY(frame) >= CGRectGetMaxY(_scanRect)) {

                        self.lineView.tag = 2;

                    }

                }

                self.lineView.frame = frame;

            });

        });

        dispatch_resume(timer);

    }

    - (void)drawRect:(CGRect)rect {

        // Drawing code

        CGContextRef ctx = UIGraphicsGetCurrentContext();

        [[[UIColor blackColor] colorWithAlphaComponent:0.5] setFill];

        CGMutablePathRef screenPath = CGPathCreateMutable();

        CGPathAddRect(screenPath, NULL, self.bounds);

        CGMutablePathRef scanPath = CGPathCreateMutable();

        CGPathAddRect(scanPath, NULL, _scanRect);

        CGMutablePathRef path = CGPathCreateMutable();

        CGPathAddPath(path, NULL, screenPath);

        CGPathAddPath(path, NULL, scanPath);

        CGContextAddPath(ctx, path);

        /** kCGPathEOFill:奇偶规则填充(被覆盖过奇数点的填充,被覆盖过偶数点的不填充)

        就比如说从任意位置p作一条射线,若与该射线相交的多边形边的数目为奇数,则p是在多边形内,

        就去填充,否则就不填充。*/

        CGContextDrawPath(ctx, kCGPathEOFill);

        CGPathRelease(path);

        CGPathRelease(screenPath);

        CGPathRelease(scanPath);

    }

    @end

    2.二维码扫描范围设置

    1.AVCaptureMetadataOutput  扫描数据的输出对象

    2.AVCaptureVideoPreviewLayer 扫描视图

    3.rectOfInterest  该属性就是设置扫描内容的范围大小,需要使用[layer metadataOutputRectOfInterestForRect:_scanRect]; 方法进行矩形转换获取扫描的范围大小

    // 只有添加该通知,在该通知里面设置rectOfInterest属性才有效

        [[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {

            // 如果不设置,整个屏幕都可以扫

            output.rectOfInterest = [layer metadataOutputRectOfInterestForRect:_scanRect];

        }];

    3.开启和关闭闪光灯

    // 创建摄像数据输出流并将其添加到会话对象上 --> 用于识别光线强弱

        self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];

        [self.videoDataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

        [self.session addOutput:self.videoDataOutput];

    // 根据Mode是否打开闪光灯

    - (void)offFlashWithMode:(AVCaptureTorchMode)mode {

        AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        NSError *error = nil;

        if ([captureDevice hasTorch]) {

            BOOL locked = [captureDevice lockForConfiguration:&error];

            if (locked && error == nil) {

                // 打开手电筒 | 关闭手电筒

                captureDevice.torchMode = mode;

                [captureDevice unlockForConfiguration];

            }

        }

    }

    #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate

    // 获取到光线的强弱值

    - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

        // 这个方法会时时调用,但内存很稳定

        CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL, sampleBuffer, kCMAttachmentMode_ShouldPropagate);

        NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary *)metadataDict];

        CFRelease(metadataDict);

        NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];

        float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];

        NSLog(@"%f", brightnessValue);

        self.scanView.brightnessValue = brightnessValue;

    }

    4.识别相册中的二维码图片

    实现两个代理: UIImagePickerControllerDelegate, UINavigationControllerDelegate

    #pragma mark - 从相册解析二维码图片

    - (void)analyzeOnClick {

        UIImagePickerController *picker = [[UIImagePickerController alloc] init];

        picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

        picker.delegate = self;

        [self presentViewController:picker animated:YES completion:nil];

    }

    #pragma mark - UIImagePickerContorllerDelegate

    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {

        // 对选取照片的处理,如果选取的图片尺寸过大,则压缩选取图片,否则不处理

        UIImage *originalImage = info[UIImagePickerControllerOriginalImage];

        UIImage *image = [self imageSizeWithScreenImage:originalImage];

        // CIDetector (CIDetector可用于人脸识别)进行图片解析,从而使我们可以便捷的从相册中获取到二维码

        // 声明一个CIDetector,并设定识别类型 CIDetectorTypeQRCode

        CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];

        // 获取识别结果

        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];

        if ([features count] <= 0) {

            [BaseViewController alertWithTitle:@"识别结果为nil"];

        } else {

            CIQRCodeFeature *feature = [features firstObject];

            [BaseViewController alertWithTitle:feature.messageString];

    //        for (CIQRCodeFeature *feature in features) {

    //            NSLog(@"%@", feature.messageString);

    //        }

        }

        [picker dismissViewControllerAnimated:YES completion:nil];

    }

    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

        [picker dismissViewControllerAnimated:YES completion:nil];

    }

    // 返回一张不超过屏幕尺寸的image

    - (UIImage *)imageSizeWithScreenImage:(UIImage *)image {

        CGFloat imageW = image.size.width;

        CGFloat imageH = image.size.height;

        CGFloat screenW = kScreenWidth;

        CGFloat screenH = kScreenHeight;

        if (imageW <= screenW && imageH <= screenH) {

            return image;

        }

        CGFloat max = MAX(imageW, imageH);

        CGFloat scale = max / (screenH * 2.0);

        CGSize size = CGSizeMake(imageW / scale, imageW / scale);

        UIGraphicsBeginImageContext(size);

        [image drawInRect:CGRectMake(0, 0, size.width, size.height)];

        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();

        return newImage;

    }

    5.二维码图片生成

    1.需要包含头文件

    #import <CoreImage/CoreImage.h>

    // 二维码生成器

    @interface QrCodeGeneratorViewController ()

    @property (weak, nonatomic) IBOutlet UITextView *contentTxv;

    @property (weak, nonatomic) IBOutlet UIImageView *qrcodeImv;

    - (IBAction)generatorOnClick;

    @end

    @implementation QrCodeGeneratorViewController

    - (IBAction)generatorOnClick {

        // 0.导入头文件 #import <CoreImage/CoreImage.h>

        // 1.创建过滤器 -- 苹果没有将这个字符封装成常量

        CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];

        // 2.过滤器恢复默认设置

        [filter setDefaults];

        // 3.给过滤器添加数据(正则表达式/帐号和密码) -- 通过KVC设置过滤器,只能设置NSData类型

        NSString *dataString = self.contentTxv.text;

        NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];

        [filter setValue:data forKeyPath:@"inputMessage"];

        // 4.获取输出的二维码

        CIImage *outputImage = [filter outputImage];

        // 5.显示二维码

        //    self.qrcodeImv.image = [UIImage imageWithCIImage:outputImage];

        // 显示放大后清晰的二维码图片

        self.qrcodeImv.image = [self createNonInterpolatedUIImageFormCIImage:outputImage withSize:120];

    }

    /**

    *  根据CIImage生成指定大小的UIImage

    *

    *  @param image CIImage

    *  @param size  图片宽度

    */

    - (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size

    {

        CGRect extent = CGRectIntegral(image.extent);

        CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));

        // 1.创建bitmap;

        size_t width = CGRectGetWidth(extent) * scale;

        size_t height = CGRectGetHeight(extent) * scale;

        CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();

        CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);

        CIContext *context = [CIContext contextWithOptions:nil];

        CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];

        CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);

        CGContextScaleCTM(bitmapRef, scale, scale);

        CGContextDrawImage(bitmapRef, extent, bitmapImage);

        // 2.保存bitmap到图片

        CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);

        CGContextRelease(bitmapRef);

        CGImageRelease(bitmapImage);

        return [UIImage imageWithCGImage:scaledImage];

    }

    @end

    让明天,不后悔今天的所作所为
  • 相关阅读:
    Sicily 1153. 马的周游问题 解题报告
    回溯法与八皇后问题
    Sicily 1151. 魔板 解题报告
    Sicily 1176. Two Ends 解题报告
    Sicily 1046. Plane Spotting 解题报告
    Java多线程11:ReentrantLock的使用和Condition
    Java多线程10:ThreadLocal的作用及使用
    Java多线程9:ThreadLocal源码剖析
    Java多线程8:wait()和notify()/notifyAll()
    Java多线程7:死锁
  • 原文地址:https://www.cnblogs.com/-yun/p/14346304.html
Copyright © 2020-2023  润新知