如何处理iOS 8照片扩展中的内存限制?

我在现有的照片编辑应用程序中添加了新的iOS 8照片扩展程序。 我的应用程序具有相当复杂的过滤器管道,并且需要一次在内存中保留多个纹理。 但是,在具有1 GB RAM的设备上,我可以轻松处理8个MP图像。

然而,在扩展中,存在更多的内存限制。 我不得不将图像缩小到2MP以下,以便在不使扩展名崩溃的情况下进行处理。 我还发现内存问题只发生在没有调试器连接到扩展时。 有了它,一切正常。

我做了一些实验。 我修改了一个内存预算测试应用程序以在扩展中工作,并提出了以下结果(显示在崩溃之前可以分配的RAM数量,以MB为单位):

╔═══════════════════════╦═════╦═══════════╦══════════════════╗
║        Device         ║ App ║ Extension ║ Ext. (+Debugger) ║
╠═══════════════════════╬═════╬═══════════╬══════════════════╣
║ iPhone 6 Plus (8.0.2) ║ 646 ║       115 ║              645 ║
║ iPhone 5 (8.1 beta 2) ║ 647 ║        97 ║              646 ║
║ iPhone 4s (8.0.2)     ║ 305 ║        97 ║              246 ║
╚═══════════════════════╩═════╩═══════════╩══════════════════╝

几点意见:

  • 使用附加的调试器,扩展的行为就像“普通”应用程序一样
  • 尽管与其他设备相比,4s只有内存总量(512 MB)的一半,但它与系统获得的扩展名相同〜100 MB。
  • 现在我的问题是:我该如何在照片编辑扩展中使用这么少的内存? 一个包含8MP(相机分辨率)RGBA图像的纹理单独消耗约31MB。 如果我必须告诉用户只有在使用主应用程序时才能进行全尺寸编辑,那么这种扩展机制有什么意义?

    你们中的一个人是否也达到了这个障碍? 你有没有找到解决这个约束的解决方案?


    我正在为我的公司开发照片编辑扩展,并且我们正面临同样的问题。 我们的内部图像处理引擎需要超过150MB才能对图像应用特定的效果。 这甚至不计算每副本需要大约100MB内存的全景图像。

    我们发现只有两种解决方法,但不是真正的解决方案。

  • 缩小图像并应用滤镜。 这将需要较少的内存,但图像结果是可怕的。 至少扩展名不会崩溃。
  • 要么

  • 使用CoreImage或Metal进行图像处理。 正如我们分析了使用CoreImage的苹果公司的Sample Photo Editing Extension,可以处理非常大的图像甚至全景图,而不会造成质量或分辨率的损失。 实际上,我们无法通过加载非常大的图像来使扩展程序崩溃。 示例代码可以处理全景图,内存为40mb,非常令人印象深刻。
  • 根据Apple的应用程序扩展编程指南,第55页,“处理内存约束”一章,扩展中内存压力的解决方案是查看图像处理代码。 到目前为止,我们正在将我们的图像处理引擎移植到CoreImage,并且结果比我们以前的引擎要好得多。

    我希望我能帮上一点忙。 Marco Paiva


    如果你使用核心图像“配方”,就不用担心内存,就像Marco说的那样。 在图像对象返回到视图之前,不会渲染应用了核心图像滤镜的图像。

    这意味着您可以将一百万个滤镜应用于高速公路广告牌尺寸的照片,并且内存不会成为问题。 过滤器的规格可以简单地编译成一个卷积或内核,所有内容都可以缩小到相同的大小 - 无论如何。

    关于内存管理和溢出等问题的误解可以通过使用自己选择的编程语言,开发环境和硬件平台的核心概念来轻松弥补。

    苹果公司介绍Core Image过滤器编程的文档就足够了; 如果您想特别参考我认为与您的问题有关的文档部分,请询问。


    下面是你如何在Core Image中应用两个连续的卷积核心,以及它们之间的“中间结果”:

    - (CIImage *)outputImage { 
    
    const double g = self.inputIntensity.doubleValue;
    const CGFloat weights_v[] = { -1*g, 0*g, 1*g,
                                  -1*g, 0*g, 1*g,
                                  -1*g, 0*g, 1*g};
    
    CIImage *result = [CIFilter filterWithName:@"CIConvolution3X3" keysAndValues:
              @"inputImage", self.inputImage,
              @"inputWeights", [CIVector vectorWithValues:weights_v count:9],
              @"inputBias", [NSNumber numberWithFloat:1.0],
              nil].outputImage;
    
    CGRect rect = [self.inputImage extent];
    rect.origin = CGPointZero;
    
    CGRect cropRectLeft = CGRectMake(0, 0, rect.size.width, rect.size.height);
    CIVector *cropRect = [CIVector vectorWithX:rect.origin.x Y:rect.origin.y Z:rect.size.width W:rect.size.height];
    result = [result imageByCroppingToRect:cropRectLeft];
    
    result = [CIFilter filterWithName:@"CICrop" keysAndValues:@"inputImage", result, @"inputRectangle", cropRect, nil].outputImage;
    
    
    const CGFloat weights_h[] = {-1*g, -1*g, -1*g,
        0*g,   0*g,   0*g,
        1*g,   1*g,     1*g};
    
    
    result = [CIFilter filterWithName:@"CIConvolution3X3" keysAndValues:
              @"inputImage", result,
              @"inputWeights", [CIVector vectorWithValues:weights_h count:9],
              @"inputBias", [NSNumber numberWithFloat:1.0],
              nil].outputImage;
    
    result = [result imageByCroppingToRect:cropRectLeft];
    
    result = [CIFilter filterWithName:@"CICrop" keysAndValues:@"inputImage", result, @"inputRectangle", cropRect, nil].outputImage;
    
    result = [CIFilter filterWithName:@"CIColorInvert" keysAndValues:kCIInputImageKey, result, nil].outputImage;
    
    return result;
    

    }

    链接地址: http://www.djcxy.com/p/23203.html

    上一篇: How to handle memory constraints in iOS 8 Photo Extensions?

    下一篇: Difference between using a module pattern and instantiating new objects