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

4

我有一个函数,其中我将UIImage转换为vImage(用于iOS的Accelerate.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;
}

我是通过在网上混搭几个代码片段构建的。

我的问题是:我有一个calloc调用来为sourceData分配空间。但是,我应该在哪里释放这个内存?

考虑到我可能会多次调用此方法,似乎现在这样会导致内存泄漏。我认为我不会在这里释放它,因为它为我的vImage_Buffer变量提供了支持.data。但是,我应该在调用函数中释放它吗?还是将v_image(或者在调用方法中返回的任何变量)设置为nil最终会释放calloc行分配的内存?

有人有任何指针吗?

2个回答

3

首先,您还需要通过调用CGColorSpaceRelease(colorSpace)来释放colorSpace

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

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

-(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兼容图像格式(以及更多)。 - Ian Ollmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接