iOS - 将 UIImage 转换为 vImage 内存处理

Posted

技术标签:

【中文标题】iOS - 将 UIImage 转换为 vImage 内存处理【英文标题】:iOS - Converting a UIImage to vImage memory handling 【发布时间】:2014-04-05 14:01:32 【问题描述】:

我有一个函数可以将UIImage 转换为vImage(用于iosAccelerate.framework 中的一些vImage 方法。

我的方法是:

-(vImage_Buffer)convertImage:(UIImage *)image 
    CGImageRef sourceRef = [image CGImage];
    NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
    NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *sourceData = (unsigned char*)calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(sourceData, sourceWidth, sourceHeight,
                                                       bitsPerComponent, sourceBytesPerRow, colorSpace,
                                                       kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
    CGContextDrawImage(context, CGRectMake(0, 0, sourceWidth, sourceHeight), sourceRef);
    CGContextRelease(context);
    vImage_Buffer v_image = 
        .data = sourceData,
        .height = sourceHeight,
        .width = sourceWidth,
        .rowBytes = sourceBytesPerRow
    ;

    return v_image;

我通过在网络上混合和匹配一些代码 sn-ps 来构建它。

我的问题是,我有一个calloc 调用,它为sourceData 分配空间。但是如何以及在哪里释放这些内存?

鉴于我可能会多次调用此方法,看起来像原样,会有巨大的内存泄漏。我不认为我会在这里发布它,因为它为我的vImage_Buffer 变量提供了支持.data。但是我会在我的调用函数中释放它吗?或者将v_image 设置为nil或在调用方法中命名的任何返回变量)最终会释放calloc 行分配的内存?

有人指点一下吗?

【问题讨论】:

【参考方案1】:

首先你还需要通过调用CGColorSpaceRelease(colorSpace)释放colorSpace

calloc 分配的内存稍后可以在调用函数中使用free(v_image.data)或调用方法中命名的任何返回变量)释放。

您还可以更改您的方法实现以摆脱 CGContext 并使用 CGDataProviderRefCGImage 获取字节,这将类似于:

-(vImage_Buffer)convertImage:(UIImage *)image

    CGImageRef sourceRef = [image CGImage];
    NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
    NSUInteger sourceHeight = CGImageGetHeight(sourceRef);

    CGDataProviderRef provider = CGImageGetDataProvider(sourceRef);
    CFDataRef bitmapData = CGDataProviderCopyData(provider);

    unsigned char *sourceData = (unsigned char*)calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;

    CFDataGetBytes(bitmapData, CFRangeMake(0, CFDataGetLength(bitmapData)), sourceData);

    vImage_Buffer v_image = 
        .data = (void *)sourceData,
        .height = sourceHeight,
        .width = sourceWidth,
        .rowBytes = sourceBytesPerRow
    ;

    CFRelease(bitmapData);

    return v_image;

但是我没有检查性能。

我还建议将您的方法重命名为 vImageCreateFromImage 之类的名称。稍后你会知道你负责清理内存。

【讨论】:

【参考方案2】:

首先,也是最重要的,这在 iOS7.0 / OSX 10.9 中得到了极大的简化,引入了 vImageBuffer_InitWithCGImage 函数(在 vImage_Utilities.h 中声明,标题中包含相当广泛的文档)。如果您不需要支持较旧的操作系统,则应考虑使用此新功能。

其次,无论您使用现有代码还是InitWithCGImage,一旦您完成使用通过任一方式创建的vImage_Buffer 对象,您应该释放与数据字段相关联的内存:free(buffer.data);

【讨论】:

CGBitmapContext 既是导出机制,又是绘图表面。将绘图表面复杂性保持在最低限度的需要意味着它对于可以生成的格式不是很灵活。这是添加 vImageBuffer_InitWithCGImage 的原因之一。它使您可以轻松访问几乎所有您可能想要的 CG 兼容图像格式(以及更多)。

以上是关于iOS - 将 UIImage 转换为 vImage 内存处理的主要内容,如果未能解决你的问题,请参考以下文章

对于IOS,如何使用vImage将ARGB图像转换为灰度图像

IOS操作完成后如何释放vImage缓冲区

有没有人有 iOS 上 vImage 处理的示例代码?

来自 UIImage 或来自文件的 vImage - Swift 和 Accelerate 框架

iOS、SpriteKit 将 SKTextureAtlas/SKTexture 转换为 UIImage

我无法让 vImage(加速框架)将 420Yp8_Cb8_Cr8(平面)转换为 ARGB8888