有关如何在CGImageDestinationFinalize中处理此崩溃的任何建议?

时间:2011-06-01 10:17:43

标签: iphone objective-c core-image

我的应用程序读取并调整从互联网加载的图像;不幸的是,我无法控制这些图像的创建。

最近我发生了一次撞车事故,我不知道如何才能最好地处理。在这种情况下,图像是一个损坏的GIF文件。它没有严重损坏,但它报告的分辨率大小(高度x宽度)不准确。该图像应该是400x600图像,但报告的内容类似于1111x999。

崩溃的代码段是:

- (void) saveRawImageRefToDisk:(CGImageRef)image withUUID:(NSString *)uuid andType:(NSString *)type {
    if (!uuid || !type) {
        return;
    }

    NSDictionary *imageDestinationWriteOptions = [NSDictionary dictionaryWithObjectsAndKeys:
                                              [NSNumber numberWithInt:1], (id)kCGImagePropertyOrientation,
                                              (id)kCFBooleanFalse, (id)kCGImagePropertyHasAlpha,
                                              [NSNumber numberWithInt:1.0], kCGImageDestinationLossyCompressionQuality,
                                              nil];

    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL((CFURLRef)[NSURL fileURLWithPath:[self getRawImagePathForUUID:uuid]], (CFStringRef)type, 1, nil);
    if (imageDestination) {
        CGImageDestinationAddImage(imageDestination, image, (CFDictionaryRef)imageDestinationWriteOptions);
        CGImageDestinationFinalize(imageDestination); //<--- EXC_BAD_ACCESS in here
        CFRelease(imageDestination);
    }
}

崩溃日志的片段是:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x06980000
Crashed Thread:  8

Thread 8 name:  Dispatch queue: com.apple.root.default-priority
Thread 8 Crashed:
0   libsystem_c.dylib               0x348cf6a4 memcpy$VARIANT$CortexA9 + 212
1   CoreGraphics                    0x366de30c CGAccessSessionGetBytes + 112
2   ImageIO                         0x32941b04 GenerateFromRGBImageWu + 256
3   ImageIO                         0x329432aa _CGImagePluginWriteGIF + 3390
4   ImageIO                         0x32932b3a CGImageDestinationFinalize + 118

有问题的图片是GIF,所以我的方法中的类型设置为 @“com.compuserve.gif”。据我所知,CGImageDestinationRef imageDestination是一个有效的对象。

我的应用程序的部分逻辑是保持图像的格式与读取的格式相同。所以在这种情况下,我正在调整大小并写回GIF。

我试图强制将 CGImageRef 写成PNG,有趣的是应用程序没有崩溃。它写出了PNG(这是无效的 - 只是一个空白的黑色图像),但它没有崩溃。但是我不知道在正常的执行过程中知道我应该把GIF写成PNG。

任何人都对我如何处理或陷入这种情况有任何想法?我非常感谢任何建议,因为这让我很担心:应用程序的稳定性。或者这只是一个直接的“报告作为对苹果的雷达”?

编辑&amp;补充代码:

所有这些处理都发生在NSOperationQueue内而不是主线程上

有问题的图片可在http://dribbble.com/system/users/1409/screenshots/182540/htg-logo-tiny.gif?1306878218

找到

这是我创建CGImageRef的函数:

- (CGImageRef) createIpadSizedImageRefFromImageSource:(CGImageSourceRef)imageSource withSourceSizeOf(CGSize)imageSourceSize {
    NSDictionary *imageCreationOptions = [NSDictionary dictionaryWithObjectsAndKeys:
                                      (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
                                      (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
                                      [NSNumber numberWithInt:1024], kCGImageSourceThumbnailMaxPixelSize,
                                      (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageAlways,
                                      nil];

    CGImageRef image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, (CFDictionaryRef)imageCreationOptions);

    if (!image) {
        return nil;
    } else {
        [(id) image autorelease];
        return image;
    }
}

并且CGImageSourceRef是从文件路径创建的,如:

- (CGImageSourceRef) createImageSourceFromURL:(NSURL *)imageLocationOnDisk {
    CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageLocationOnDisk, NULL);

    if (!imageSource) {
        DebugLog(@"Issue creating image source for image at: %@", imageLocationOnDisk);
        return nil;
    } else {
        [(id) imageSource autorelease];
        return imageSource;
    }
}

3 个答案:

答案 0 :(得分:2)

我根据您的描述创建了一个测试项目,该项目从提供的URL加载并保存图像。它在模拟器和iPhone 4(iOS 4.3.2)上运行没有问题。

您是否可以尝试在项目/环境中运行以下方法:

- (void)checkImage
{
    NSURL *imageLocationOnDisk = [[NSBundle mainBundle] URLForResource:@"htg-logo-tiny"
                                                         withExtension:@"gif"];
    assert(imageLocationOnDisk);

    CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageLocationOnDisk, NULL);
    assert(imageSource);

    id options = [NSDictionary dictionaryWithObjectsAndKeys:
                  (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
                  (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
                  [NSNumber numberWithInt:1024], kCGImageSourceThumbnailMaxPixelSize,
                  (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageAlways,
                  nil];

    CGImageRef image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, (CFDictionaryRef)options);
    assert(image);

    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* file = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"foo.png"];

    options = [NSDictionary dictionaryWithObjectsAndKeys:
               [NSNumber numberWithInt:1], (id)kCGImagePropertyOrientation,
               (id)kCFBooleanFalse, (id)kCGImagePropertyHasAlpha,
               [NSNumber numberWithInt:1.0], kCGImageDestinationLossyCompressionQuality,
               nil];
    CGImageDestinationRef dest = CGImageDestinationCreateWithURL((CFURLRef)[NSURL fileURLWithPath:file],
                                                                 kUTTypePNG,
                                                                 1,
                                                                 NULL);
    assert(dest);
    CGImageDestinationAddImage(dest, image, (CFDictionaryRef)options);
    CGImageDestinationFinalize(dest);
}

要运行测试,您必须将图像复制到项目的资源中。

正如我上面所说,代码在我的机器上工作正常。我也用CGImageSourceCreateImageAtIndex成功地尝试了它。

您的应用中发生错误的事实可能与其他类型的错误有关。您的线程使用ImageIO API可能存在问题。

我注意到的一件事是你在CGImageDestinationCreateWithURL电话中传递的选项参数。根据文档,它应该是NULL

修改:相关图片的大小为792×1111(由PhotoShop和Preview.app报告),大部分为黑色。

答案 1 :(得分:0)

您可以做的是将图像存储在UIImage对象中,在新的上下文中绘制(使用size属性),然后创建一个CGImageRef对象。这将解决腐败问题。虽然您需要为您收到的每张图片执行此操作,但这将是一个很小的性能损失。

请注意,您必须从主线程向UIImage发送消息。

答案 2 :(得分:-1)

我要发布一小段调试后发现的类似崩溃的消息,也许对某人有用...... 原因是如此愚蠢的事情。 我在NSLog中有两个占位符,只有一个实变量。

NSLog(@"lastItemDate = %@ unixtime = %@", lastItemDate);