iOS UImage 与 RGB 裸数据的相互转换

Touch the data of image in iOS

Get data from a image

较简单,根据已有的 image 的属性,创建 CGBitmapContext, 这个 context 是带有直接访问的指针的。然后将 Image 绘制到这个 context, 得到裸数据。

Code:

    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(srcImg.CGImage);
CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceRGB(); float width = srcImg.size.width;
float height = srcImg.size.height; // Get source image data
uint8_t *imageData = (uint8_t *) malloc(width * height * 4); CGContextRef imageContext = CGBitmapContextCreate(imageData,
width, height,
8, static_cast<size_t>(width * 4),
colorRef, alphaInfo); CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), srcImg.CGImage);
CGContextRelease(imageContext);
CGColorSpaceRelease(colorRef);

拿到指针就可以操作数据了。

需要注意的地方:alphaInfo, 通常我处理的图像都是带有透明度的,但是 RGBA 和 ARGB 都有遇到过,所以需要看清楚这个信息是哪一种,列举如下:

typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {
kCGImageAlphaNone, /* For example, RGB. */
kCGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */
kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
kCGImageAlphaLast, /* For example, non-premultiplied RGBA */
kCGImageAlphaFirst, /* For example, non-premultiplied ARGB */
kCGImageAlphaNoneSkipLast, /* For example, RBGX. */
kCGImageAlphaNoneSkipFirst, /* For example, XRGB. */
kCGImageAlphaOnly /* No color data, alpha data only */
};

一般来说我们的工程都会打开一个png图片压缩的选项,所以我们拿到的 image 一般来说是 premultiplied 的,也就是说,RGB的值已经是和alpha值相乘的结果了,在 OpenGL 纹理操作的时候要注意。

Create a image from raw data

1) Create BitmapContext and get image from it

	size_t bitsPerComponent = 8;
size_t bitsPerPixel = 32;
size_t bytesPerRow = static_cast<size_t>(4 * outWidth);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); // set the alpha mode RGBA
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast; ////
// This method is much simple and without coordinate flip
// You can use this method either
// but the UIGraphicsBeginImageContext() is much more modern.
//// CGContextRef cgBitmapCtx = CGBitmapContextCreate(outData,
static_cast<size_t>(outWidth),
static_cast<size_t>(outHeight),
bitsPerComponent,
bytesPerRow,
colorSpaceRef,
bitmapInfo); CGImageRef cgImg = CGBitmapContextCreateImage(cgBitmapCtx); UIImage *retImg = [UIImage imageWithCGImage:cgImg]; CGContextRelease(cgBitmapCtx);
CGColorSpaceRelease(colorSpaceRef);
free(outData);

主要方法就是 CGBitmapContextCreate 直接将数据地址 outData 作为初始化参数提供,这样这个 context 就是带有正确数据的了,然后就直接获得 CGImage 了。

2) CGDataProvider --> CGImage --> UIImage

这个方法的思路就是直接使用 CGImageCreate() 函数直接创建 CGImage.

    size_t bitsPerComponent = 8;
size_t bitsPerPixel = 32;
size_t bytesPerRow = static_cast<size_t>(4 * outWidth);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); // set the alpha mode RGBA
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, outData, outDataLength, NULL); CGImageRef imageRef = CGImageCreate(outWidth, outHeight,
bitsPerComponent, bitsPerPixel, bytesPerRow,
colorSpaceRef, bitmapInfo, provider,
NULL, NO, renderingIntent); UIImage *retImage1 = [UIImage imageWithCGImage:imageRef];

创建 provider 的时候无需回调函数,故直接提供 NULL.

创建 CGImage 時需要提供详细的配置参数,其中部分参数和创建 CGBitmapContext 相同,额外需要提供的就是默认参数以及不需要使用的特性比如 decode array 等等。得到 CGImageRef 后可以直接得到 UIImage 对象,但是我发现我的同事写了如下一段代码:

    UIGraphicsBeginImageContext(outSize);
// the same: UIGraphicsBeginImageContextWithOptions(outSize, NO, 1.0f); CGContextRef cgCtx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(cgCtx, kCGBlendModeCopy); CGContextDrawImage(cgCtx, CGRectMake(0.0, 0.0, outWidth, outHeight), imageRef); UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();

这段代码的功能是:创建CGContext 然后将 CGimage 绘制到当前的 Context 上面,再得到 UIImage.

基本可以认为是 [UIImage imageWithCGImage:imageRef] 我的不知道为什么同事这样写,可能是这个方法是有什么坑的,我暂时没有遇到。所以我将这段代码先记下来,留着以后用。

关于 UIGraphicsBeginImageContext() 方法,apple 的介绍如下:

iOS Note: iOS applications should use the function UIGraphicsBeginImageContextWithOptions instead of using the low-level Quartz functions described here. If your application creates an offscreen bitmap using Quartz, the coordinate system used by bitmap graphics context is the default Quartz coordinate system. In contrast, if your application creates an image context by calling the function UIGraphicsBeginImageContextWithOptions, UIKit applies the same transformation to the context’s coordinate system as it does to a UIView object’s graphics context. This allows your application to use the same drawing code for either without having to worry about different coordinate systems. Although your application can manually adjust the coordinate transformation matrix to achieve the correct results, in practice, there is no performance benefit to doing so.

上面所述的 low-level Quartz function 就是我们上面用的 CGBitmapContextCreate 这一类方法。所以用这个新的方法直接就将 创建好的 bitmapContext 绑定到当前状态。仍然调用 CGContextDrawImage() 函数,将 CGImage 绘制到指定的 context 上面。然后再获取 UIImage. 总的来说,这个和我们之前的那一套原理是一样的,应该说这样是更新式的做法,推荐的做法。

参考

Quartz 2D Programming Guide

How do I create a CGImage with RGB data?

Converting RGB data into a bitmap in Objective-C++ Cocoa

CGImage to UIImage doesn't work

iOS UImage 与 RGB 裸数据的相互转换的更多相关文章

  1. iOS 直播-获取音频(视频)数据

    iOS 直播-获取音频(视频)数据 // // ViewController.m // capture-test // // Created by caoxu on 16/6/3. // Copyri ...

  2. iOS开发之JSON格式数据的生成与解析

    本文将从四个方面对IOS开发中JSON格式数据的生成与解析进行讲解: 一.JSON是什么? 二.我们为什么要用JSON格式的数据? 三.如何生成JSON格式的数据? 四.如何解析JSON格式的数据? ...

  3. iOS五种本地缓存数据方式

    iOS五种本地缓存数据方式   iOS本地缓存数据方式有五种:前言 1.直接写文件方式:可以存储的对象有NSString.NSArray.NSDictionary.NSData.NSNumber,数据 ...

  4. 关于iOS去除数组中重复数据的几种方法

    关于iOS去除数组中重复数据的几种方法   在工作工程中我们不必要会遇到,在数组中有重复数据的时候,如何去除重复的数据呢? 第一种:利用NSDictionary的AllKeys(AllValues)方 ...

  5. iOS中使用RSA对数据进行加密解密

    RSA算法是一种非对称加密算法,常被用于加密数据传输.如果配合上数字摘要算法, 也可以用于文件签名. 本文将讨论如何在iOS中使用RSA传输加密数据. 本文环境 mac os openssl-1.0. ...

  6. RGB图像数据字符叠加,图像压缩(ijl库),YUV转RGB

    jackyhwei 发布于 2010-01-01 12:02 点击:3218次  来自:CSDN.NET 一些非常有用的图像格式转换及使用的源代码,包括RGB图像数据字符叠加,图像压缩(ijl库),Y ...

  7. vc/mfc获取rgb图像数据后动态显示及保存图片的方法

    vc/mfc获取rgb图像数据后动态显示及保存图片的方法 该情况可用于视频通信中获取的位图数据回放显示或显示摄像头捕获的本地图像 第一种方法 #include<vfw.h> 加载 vfw3 ...

  8. iOS开发网络篇—JSON数据的解析

    iOS开发网络篇—JSON数据的解析 iOS开发网络篇—JSON介绍 一.什么是JSON JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式 ...

  9. Linux Bash 脚本:自己定义延迟代码块(裸数据保存方案)

    结合 alias 和 read 使用方法.能够保存一些将要延迟执行的脚本,或者裸数据(字符串不被扩展)到一个变量中.以备后用. $ alias BEGIN='read -d "" ...

随机推荐

  1. ajax struts2 数据的返回形式

    这篇随笔算是接上篇的数据请求返回,上一篇关于分页用的返回的数据形式是json,http://www.cnblogs.com/tele-share/p/7192206.html这次主要探讨ajax从st ...

  2. navicat for sqlite 11.1.12 patch 永久试用 不报毒

    因为最近需要用这个但是网上都是注册机没有成功注册,所以就自己动手使用ollydbg开刀,    修改成了永久试用版本. 着急用所以没仔细分析,暂时先这样吧. 这个下载版本 http://dlsw.ba ...

  3. 【二分图】ZJOI2007小Q的游戏

    660. [ZJOI2007] 小Q的矩阵游戏 ★☆   输入文件:qmatrix.in   输出文件:qmatrix.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] ...

  4. MVVM 框架解析之双向绑定

    更好的阅读体验,点击 原文地址 MVVM 框架 近年来前端一个明显的开发趋势就是架构从传统的 MVC 模式向 MVVM 模式迁移.在传统的 MVC 下,当前前端和后端发生数据交互后会刷新整个页面,从而 ...

  5. BZOJ3930: [CQOI2015]选数

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3930 容斥原理. 令l=(L-1)/k,r=R/k,这样找k的倍数就相当于找1的倍数. 设F[ ...

  6. hdu_1698Just a Hook(线段树)

    hdu_1698Just a Hook(线段树) 标签: 线段树 题目链接 题意: 一个英雄的技能是发射一个长度为n的金属链,初始的金属链都是铁做的,标记为1,我们可以对于某个区间修改它的金属材质,如 ...

  7. HDU--2015

    偶数求和 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  8. SSH私用私钥登陆

    1.导入私钥,将私钥文件放到当前登陆用户目录下的.ssh目录下 2.指定私钥登陆,ssh -i .ssh/ssh_rsa  root@target.com 如果出现了下面这种情况 这是因为私钥文件权限 ...

  9. FineReport父子格实现动态参数注入

    "深入学习FineReport后发现其功能及其强大,之前使用存储过程实现的报表完全可以使用FineReport本身的功能实现. 当你需要的表名,查询条件等均未知的时候,使用"动态参 ...

  10. 安装linux的关键步骤