Swift-技巧(九)CGImage To CVPixelBuffer

摘要

iOS 中图像的表现形式不只是 Image,还有更加底层的方式,比如 CVPixelBuffer 像素缓存形式,那么 CGImage 就可以转换为像素缓存的方式也是需要了解的。

CGImage 苹果官方解释是一张 bitmap 图像或者图像 mask。它是 UIImage 类中的一个属性,并可以通过 UIImage 的初始化函数称为一个 Image 对象。

CVPixelBuffer 是核心缓存像素对象的引用,这里存储着一张图像。

在需要 CVPixelBuffer 对象的应用场景中,可以把 CGImage 转换获得到。

CGImage To CVPixelBuffer

这里使用 CGContext 对象中的函数将 CGImage 转换为 CVPixelBuffer。需要提前导入 CoreGraphics 框架。

import CoreGraphics

然后将转换函数放在 CGImage 扩展中,就可以直接访问 CGImage 对象的 widthheight,甚至可以通过 self 访问到自身。

extension CGImage {
	// 转换函数
	...
}
实现方法

接下来按照需求由少到多的情况来处理 CGImageCVPixelBuffer 。首先就是直接获取到一个 ARGB 的像素缓存对象。

public func pixelBuffer() -> CVPixelBuffer? {
	return pixelBuffer(width: width, height: height, orientation: .up)
}

函数中的 widthheight 可以直接访问到,orientation 是图像的方向,这里默认是 .up(竖直)。

那么可以调整图片的 widthheight 转换成一个 ARGB 的像素缓存对象。

public func pixelBuffer(width: Int, height: Int,
                        orientation: CGImagePropertyOrientation) -> CVPixelBuffer? {
  return pixelBuffer(width: width, height: height,
                     pixelFormatType: kCVPixelFormatType_32ARGB,
                     colorSpace: CGColorSpaceCreateDeviceRGB(),
                     alphaInfo: .noneSkipFirst,
                     orientation: orientation)
}

函数中多了一些参数,pixelFormatType 是像素格式类型,这里设置的就是 ARGB 格式,colorSpace 是颜色空间参数,alphaInfoalpha 在内存中的位置,这几个参数如果不确定,就直接设置成这样。

这个函数可以设置这么多参数,从另外一个角度说,这个函数就是最终的实现,上面的几个函数都是对这个函数的封装处理。

这个函数的处理逻辑就是创建并配置 CGContext 对象,然后调用它的 draw 函数获取到 CBPixelBuffer 对象。如果对这些参数的意思,如何配置,还能做什么样的扩展感兴趣,给我留言

public func pixelBuffer(width: Int, height: Int,
                          pixelFormatType: OSType,
                          colorSpace: CGColorSpace,
                          alphaInfo: CGImageAlphaInfo,
                          orientation: CGImagePropertyOrientation) -> CVPixelBuffer? {
    assert(orientation == .up)

    var maybePixelBuffer: CVPixelBuffer?
    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
                 kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue]
    let status = CVPixelBufferCreate(kCFAllocatorDefault,
                                     width,
                                     height,
                                     pixelFormatType,
                                     attrs as CFDictionary,
                                     &maybePixelBuffer)

    guard status == kCVReturnSuccess, let pixelBuffer = maybePixelBuffer else {
      return nil
    }

    let flags = CVPixelBufferLockFlags(rawValue: 0)
    guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(pixelBuffer, flags) else {
      return nil
    }
    defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, flags) }

    guard let context = CGContext(data: CVPixelBufferGetBaseAddress(pixelBuffer),
                                  width: width,
                                  height: height,
                                  bitsPerComponent: 8,
                                  bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
                                  space: colorSpace,
                                  bitmapInfo: alphaInfo.rawValue)
    else {
      return nil
    }

    context.draw(self, in: CGRect(x: 0, y: 0, width: width, height: height))
    return pixelBuffer
  }

题外话

时间仓促,说的东西可能不全面,在你查看的过程中遇到什么问题,评论区给我留言,我会尽快回复。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
常用代码整理: 12.判断邮箱格式是否正确的代码: //利用正则表达式验证 -(BOOL)isValidateEmail:(NSString *)email { NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES%@",emailRegex]; return [emailTest evaluateWithObject:email]; } 13.图片压缩 用法:UIImage *yourImage= [self imageWithImageSimple:image scaledToSize:CGSizeMake(210.0, 210.0)]; //压缩图片 - (UIImage*)imageWithImageSimple:(UIImage*)image scaledToSize:(CGSize)newSize { // Create a graphics image context UIGraphicsBeginImageContext(newSize); // Tell the old image to draw in this newcontext, with the desired // new size [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; // Get the new image from the context UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); // End the context UIGraphicsEndImageContext(); // Return the new image. return newImage; } 14.亲测可用的图片上传代码 - (IBAction)uploadButton:(id)sender { UIImage *image = [UIImage imageNamed:@"1.jpg"]; //图片名 NSData *imageData = UIImageJPEGRepresentation(image,0.5);//压缩比例 NSLog(@"字节数:%i",[imageData length]); // post url NSString *urlString = @"http://192.168.1.113:8090/text/UploadServlet"; //服务器地址 // setting up the request object now NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ; [request setURL:[NSURL URLWithString:urlString]]; [request setHTTPMethod:@"POST"]; // NSString *boundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"]; NSString *contentType = [NSString stringWithFormat:@"multipart/form-data;boundary=%@",boundary]; [request addValue:contentType forHTTPHeaderField: @"Content-Type"]; // NSMutableData *body = [NSMutableData data]; [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithString:@"Content-Disposition:form-data; name=\"userfile\"; filename=\"2.png\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; //上传上去的图片名字 [body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[NSData dataWithData:imageData]]; [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [request setHTTPBody:body]; // NSLog(@"1-body:%@",body); NSLog(@"2-request:%@",request); NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; NSLog(@"3-测试输出:%@",returnString); 15.给imageView加载图片 UIImage *myImage = [UIImage imageNamed:@"1.jpg"]; [imageView setImage:myImage]; [self.view addSubview:imageView]; 16.对图库的操作 选择相册: UIImagePickerControllerSourceTypesourceType=UIImagePickerControllerSourceTypeCamera; if (![UIImagePickerControllerisSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { sourceType=UIImagePickerControllerSourceTypePhotoLibrary; } UIImagePickerController * picker = [[UIImagePickerControlleralloc]init]; picker.delegate = self; picker.allowsEditing=YES; picker.sourceType=sourceType; [self presentModalViewController:picker animated:YES]; 选择完毕: -(void)imagePickerController:(UIImagePickerController*)pickerdidFinishPickingMediaWithInfo:(NSDictionary *)info { [picker dismissModalViewControllerAnimated:YES]; UIImage * image=[info objectForKey:UIImagePickerControllerEditedImage]; [self performSelector:@selector(selectPic:) withObject:imageafterDelay:0.1]; } -(void)selectPic:(UIImage*)image { NSLog(@"image%@",image); imageView = [[UIImageView alloc] initWithImage:image]; imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); [self.viewaddSubview:imageView]; [self performSelectorInBackground:@selector(detect:) withObject:nil]; } detect为自己定义的方法,编辑选取照片后要实现的效果 取消选择: -(void)imagePickerControllerDIdCancel:(UIImagePickerController*)picker { [picker dismissModalViewControllerAnimated:YES]; } 17.跳到下个View nextWebView = [[WEBViewController alloc] initWithNibName:@"WEBViewController" bundle:nil]; [self presentModalViewController:nextWebView animated:YES]; //创建一个UIBarButtonItem右边按钮 UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"右边" style:UIBarButtonItemStyleDone target:self action:@selector(clickRightButton)]; [self.navigationItem setRightBarButtonItem:rightButton]; 设置navigationBar隐藏 self.navigationController.navigationBarHidden = YES;// iOS开发之UIlabel多行文字自动换行 (自动折行) UIView *footerView = [[UIView alloc]initWithFrame:CGRectMake(10, 100, 300, 180)]; UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 100, 300, 150)]; label.text = @"Hello world! Hello world!Hello world! Hello world! Hello world! Hello world! Hello world! Hello world!Hello world! Hello world! Hello world! Hello world! Hello world! Helloworld!"; //背景颜色为红色 label.backgroundColor = [UIColor redColor]; //设置字体颜色为白色 label.textColor = [UIColor whiteColor]; //文字居中显示 label.textAlignment = UITextAlignmentCenter; //自动折行设置 label.lineBreakMode = UILineBreakModeWordWrap; label.numberOfLines = 0; 30.代码生成button CGRect frame = CGRectMake(0, 400, 72.0, 37.0); UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; button.frame = frame; [button setTitle:@"新添加的按钮" forState: UIControlStateNormal]; button.backgroundColor = [UIColor clearColor]; button.tag = 2000; [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; 31.让某个控件在View的中心位置显示: (某个控件,比如label,View)label.center = self.view.center; 32.好看的文字处理 以tableView中cell的textLabel为例子: cell.backgroundColor = [UIColorscrollViewTexturedBackgroundColor]; //设置文字的字体 cell.textLabel.font = [UIFont fontWithName:@"AmericanTypewriter" size:100.0f]; //设置文字的颜色 cell.textLabel.textColor = [UIColor orangeColor]; //设置文字的背景颜色 cell.textLabel.shadowColor = [UIColor whiteColor]; //设置文字的显示位置 cell.textLabel.textAlignment = UITextAlignmentCenter; 33. ———————-隐藏Status Bar—————————– 读者可能知道一个简易的方法,那就是在程序的viewDidLoad中加入 [[UIApplication sharedApplication]setStatusBarHidden:YES animated:NO]; 33. 更改AlertView背景 UIAlertView *theAlert = [[[UIAlertViewalloc] initWithTitle:@"Atention" message: @"I'm a Chinese!" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Okay",nil] autorelease]; [theAlert show]; UIImage *theImage = [UIImageimageNamed:@"loveChina.png"]; theImage = [theImage stretchableImageWithLeftCapWidth:0topCapHeight:0]; CGSize theSize = [theAlert frame].size; UIGraphicsBeginImageContext(theSize); [theImage drawInRect:CGRectMake(5, 5, theSize.width-10, theSize.height-20)];//这个地方的大小要自己调整,以适应alertview的背景颜色的大小。 theImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); theAlert.layer.contents = (id)[theImage CGImage]; 34. 键盘透明 textField.keyboardAppearance = UIKeyboardAppearanceAlert; 状态栏的网络活动风火轮是否旋转 [UIApplication sharedApplication].networkActivityIndicatorVisible,默认值是NO。 35截取屏幕图片 //创建一个基于位图的图形上下文并指定大小为CGSizeMake(200,400) UIGraphicsBeginImageContext(CGSizeMake(200,400)); //renderInContext 呈现接受者及其子范围到指定的上下文 [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; //返回一个基于当前图形上下文的图片 UIImage *aImage = UIGraphicsGetImageFromCurrentImageContext(); //移除栈顶的基于当前位图的图形上下文 UIGraphicsEndImageContext(); //以png格式返回指定图片的数据 imageData = UIImagePNGRepresentation(aImage); 36更改cell选中的背景 UIView *myview = [[UIView alloc] init]; myview.frame = CGRectMake(0, 0, 320, 47); myview.backgroundColor = [UIColorcolorWithPatternImage:[UIImage imageNamed:@"0006.png"]]; cell.selectedBackgroundView = myview; 37显示图像: CGRect myImageRect = CGRectMake(0.0f, 0.0f, 320.0f, 109.0f); UIImageView *myImage = [[UIImageView alloc] initWithFrame:myImageRect]; [myImage setImage:[UIImage imageNamed:@"myImage.png"]]; myImage.opaque = YES; //opaque是否透明 [self.view addSubview:myImage]; 38.能让图片适应框的大小(没有确认) NSString*imagePath = [[NSBundle mainBundle] pathForResource:@"XcodeCrash"ofType:@"png"]; UIImage *image = [[UIImage alloc]initWithContentsOfFile:imagePath]; UIImage *newImage= [image transformWidth:80.f height:240.f]; UIImageView *imageView = [[UIImageView alloc]initWithImage:newImage]; [newImagerelease]; [image release]; [self.view addSubview:imageView]; 39.实现点击图片进行跳转的代码:生成一个带有背景图片的button,给button绑定想要的事件! UIButton *imgButton=[[UIButton alloc]initWithFrame:CGRectMake(0, 0, 120, 120)]; [imgButton setBackgroundImage:(UIImage *)[self.imgArray objectAtIndex:indexPath.row] forState:UIControlStateNormal]; imgButton.tag=[indexPath row]; [imgButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我为双鱼狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值