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. 概率分布之间的距离度量以及python实现(四)

    1.f 散度(f-divergence) KL-divergence 的坏处在于它是无界的.事实上KL-divergence 属于更广泛的 f-divergence 中的一种. 如果P和Q被定义成空间 ...

  2. 【转载】LINUX上MYSQL优化三板斧

    现在MySQL运行的大部分环境都是在Linux上的,如何在Linux操作系统上根据MySQL进行优化,我们这里给出一些通用简单的策略.这些方法都有助于改进MySQL的性能. 闲话少说,进入正题. 一. ...

  3. Jenkins+Gitlab CE+Robot Framework持续集成

    环境 Ubuntu 14.04.3 LTS Desktop 前提 1.在本地能执行测试脚本(pybot yourTestSuit.txt),本文不讲解如何学习使用RF框架 2.已有Gitlab环境,本 ...

  4. css写的常见图形

    .aly-tooltip { display: inline-block; padding: 5px; padding-left: 15px; padding-right: 15px; backgro ...

  5. Python全栈考试(一)

    1.执行 Python 脚本的两种方式 1) 使用命令行执行Python脚本: python C:\tesst.py 2) 使用各种IDE软件.pycharm wing 2.简述位.字节的关系 位 ( ...

  6. ASP.NET Core 依赖注入

    一.什么是依赖注入(Denpendency Injection) 这也是个老身常谈的问题,到底依赖注入是什么? 为什么要用它? 初学者特别容易对控制反转IOC(Iversion of Control) ...

  7. 共60课:Python基础教程

    简介: 你会看到一堆下载链接.我们就选"Python 2.7.5 Windows Installer",如果是64位系统的同学选下面那个"Python 2.7.5 Win ...

  8. CVE-2017-8635复现

    在最近几个月里,我花了一些时间深入了Device Guard以及如何实现用户模式代码完整性(UMCI).如果您对Device Guard不熟悉,您可以 在这里阅读更多信息.通常情况下,UMCI可防止未 ...

  9. flume1.8 Sources类型介绍(二)

    1 Flume Sources 1.1 Avro Source 监听Avro端口,从Avro client streams接收events.要求属性是粗体字. agent a1例子: ipFilter ...

  10. [数据库] SQL查询语句表行列转换及一行数据转换成两列

    原文来自:http://blog.csdn.net/Eastmount/article/details/50559008 本文主要讲述了SQL查询语句表之间的行列转换,同时也包括如何将一行数据转换成两 ...