在将多个高分辨率图像合并为单个图像iOS时,内存会增加

时间:2013-11-22 11:57:32

标签: ios objective-c image memory-management memory-leaks

我必须将多个图像合并为单个(全部是高分辨率),它会占用大量内存。我将原始图像保存到本地目录,并将调整大小的图像设置为图像视图,放置在主图像上的不同位置。现在在保存最终合并图像时,我从本地目录中读取原始图像。这里内存增加,导致更多图像的错误(由于内存而崩溃)。

这里是代码:从本地目录中检索原始图像

UIImage *originalImage = [UIImage imageWithContentsOfFile:[self getOriginalImagePath:imageview.tag]];

是否有其他方法可以从本地目录获取图像而无需将其加载到内存中。

提前致谢

4 个答案:

答案 0 :(得分:2)

如果图像没有进入内存,就无法加载图像。理论上,使用某些图像格式,您可以实现自己的读取器,在读取文件时缩小图像,以便原始大小永远不会在内存中结束,但这需要大量工作才能获得很少的收益。

总的来说,您最好只将不同尺寸的图像保存为单独的文件并仅加载正确的尺寸(您似乎根据屏幕尺寸缩放它们,因此不需要那么多不同的版本)。 / p>

如果您继续动态调整它们的大小,请尽量确保尽快删除原始版本,即不要再保留任何图像引用,并且可能将整个内容包含在内@autoreleasepool(假设正在使用ARC):

@autoreleasepool {
    UIImage *originalImage = [UIImage imageWithContentsOfFile:[self getOriginalImagePath:imageview.tag]];
    UIImage *pThumbsImage = [self scaleImageToSize:CGSizeMake(AppScreenBound.size.width, AppScreenBound.size.height) imageWithImage:pOrignalImage];
    originalImage = nil;
    imageView.image = pThumbImage;
    pThumbImage = nil;
    // … ?
}

类似地处理创建中间版本的任何其他图像处理,即尽快删除不再需要的引用(例如通过分配nil或使它们超出范围),并放置{{围绕可能生成临时对象的子部分。

答案 1 :(得分:1)

找到一个解决方案,将其作为我自己问题的答案发布,可能会帮助其他人。来自Image I/O Programming Guide

的参考

“imageWithContentsOfFile:”的替代方法,可以使用 图像源

这是我如何使用它的代码。

UIImage *originalWMImage = [self createCGImageFromFile:your-image-path];

方法createCGImageFromFile:获取图像内容而不将其加载到内存

-(UIImage*) createCGImageFromFile :(NSString*)path
{
    // Get the URL for the pathname passed to the function.
    NSURL *url = [NSURL fileURLWithPath:path];
    CGImageRef        myImage = NULL;
    CGImageSourceRef  myImageSource;
    CFDictionaryRef   myOptions = NULL;
    CFStringRef       myKeys[2];
    CFTypeRef         myValues[2];

    // Set up options if you want them. The options here are for
    // caching the image in a decoded form and for using floating-point
    // values if the image format supports them.
    myKeys[0] = kCGImageSourceShouldCache;
    myValues[0] = (CFTypeRef)kCFBooleanTrue;
    myKeys[1] = kCGImageSourceShouldAllowFloat;
    myValues[1] = (CFTypeRef)kCFBooleanTrue;

    // Create the dictionary
    myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
                                   (const void **) myValues, 2,
                                   &kCFTypeDictionaryKeyCallBacks,
                                   & kCFTypeDictionaryValueCallBacks);

    // Create an image source from the URL.
    myImageSource = CGImageSourceCreateWithURL((CFURLRef)url, myOptions);
    CFRelease(myOptions);

    // Make sure the image source exists before continuing
    if (myImageSource == NULL){
        fprintf(stderr, "Image source is NULL.");
        return  NULL;
    }

    // Create an image from the first item in the image source.
    myImage = CGImageSourceCreateImageAtIndex(myImageSource,
                                              0,
                                              NULL);

    CFRelease(myImageSource);

    // Make sure the image exists before continuing
    if (myImage == NULL){
        fprintf(stderr, "Image not created from image source.");
        return NULL;
    }

    return [UIImage imageWithCGImage:myImage];
}

答案 2 :(得分:0)

这是代码:调整大小的图像并简单地分配给imageview。然后我在imageview上执行缩放和旋转。

UIImage *pThumbsImage = [self scaleImageToSize:CGSizeMake(AppScreenBound.size.width, AppScreenBound.size.height) imageWithImage:pOrignalImage]; 
    [imageView setImage:pThumbImage];

保存时:此代码在for循环中:(在主图像上合并的图像数量)

// get size of the second image
    CGFloat backgroundWidth = canvasSize.width;
    CGFloat backgroundHeight = canvasSize.height;

    //Image View: to be merged
    UIImageView* imageView = [[UIImageView alloc] initWithImage:stampImage];
    [imageView setFrame:CGRectMake(0, 0, stampFrameSize.size.width , stampFrameSize.size.height)];

    // Rotate Image View
    CGAffineTransform currentTransform = imageView.transform;
    CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform, radian);
    [imageView setTransform:newTransform];

    // Scale Image View
    CGRect imageFrame = [imageView frame];

    // Create Final Stamp View
    UIView  *finalStamp = nil;
    finalStamp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, imageFrame.size.width, imageFrame.size.height)];

    // Set Center of Stamp Image
    [imageView setCenter:CGPointMake(imageFrame.size.width /2, imageFrame.size.height /2)];
    [finalImageView addSubview:imageView];

    // Create Image From image View;
    UIGraphicsBeginImageContext(finalStamp.frame.size);
    [finalStamp.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIImage *pfinalMainImage = nil;

    // Create Final Image With Stamp
    UIGraphicsBeginImageContext(CGSizeMake(backgroundWidth, backgroundHeight));
    [canvasImage drawInRect:CGRectMake(0, 0, backgroundWidth, backgroundHeight)];
    [viewImage drawInRect:CGRectMake(stampFrameSize.origin.x , stampFrameSize.origin.y , stampImageFrame.size.width  , stampImageFrame.size.height) blendMode:kCGBlendModeNormal alpha:fAlphaValue];
    pfinalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

这里一切都很好。保存或生成合并图像时会出现问题。

答案 3 :(得分:0)

这是一个老问题,但我最近不得不面对这样的事情......所以我有答案。

我不得不将很多图像合并为一个,并且遇到了同样的问题。内存增加,直到应用程序崩溃。我创建的函数返回了UIImage,这就是问题所在。 ARC没有及时发布,因此我必须更改为返回CGImageRef并在适当的时间释放它们。