【问题标题】:Any suggestions on how to handle this crash in CGImageDestinationFinalize?有关如何在 CGImageDestinationFinalize 中处理此崩溃的任何建议?
【发布时间】:2011-09-06 04:12:43
【问题描述】:

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

最近我发生了一次崩溃,我不确定如何最好地处理。在这种情况下,图像是损坏的 GIF 文件。它没有严重损坏,但它报告的分辨率大小(高度 x 宽度)不准确。该图像应该是 400x600 的图像,但报告的尺寸类似于 1111x999。

sn-p崩溃的代码是:

- (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);
    }
}

崩溃日志的sn-p是:

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。

有人对我如何处理或捕获这种情况有任何想法吗?我非常感谢任何建议,因为这让我担心:应用程序稳定性。或者这只是一个直截了当的“向 Apple 报告雷达”?

编辑和补充代码:

所有这些处理都发生在 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;
    }
}

【问题讨论】:

  • CGImageRef image 参数从何而来?你自己创造吗?如何?能发一下损坏的图吗?您是否尝试在您的应用中绘制它?
  • @Nikolai Ruhe:感谢 cmets。我已经用更多信息更新了这个问题。我没有尝试绘制图像,因为在这种情况下,场景只是下载、调整大小并存储在磁盘上。
  • 通常,在测试 10,000 张图像时,这是我们唯一遇到问题的一张!
  • 指定的网址有404。
  • 啊,它一定被删除了。我确实有它的副本,但不拥有版权,因此无法分享。

标签: iphone objective-c core-image


【解决方案1】:

您可以做的是将图像存储在UIImage 对象中,在新的上下文中绘制它(使用size 属性),然后创建一个CGImageRef 对象。这将修复损坏。虽然您需要对收到的每张图片都执行此操作,但这会带来很小的性能损失。

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

【讨论】:

  • 感谢您的回答/cmets 一百万。我的错我应该在我的问题中说明所有这些处理都发生在 NSOperationsQueue 中。我想如果它不会过多地阻塞运行循环,我理论上可以使用 performSelectorOnMainThread。
  • 关于我如何知道正确大小的任何想法,因为我目前依靠 ImageIO lib 来告诉我,在这种情况下它的值不正确。我不希望能够处理图像,只是检测条件并防止崩溃。
  • @Damien 你试过用CGImageSourceCreateImageAtIndex 代替CGImageSourceCreateThumbnailAtIndex吗?
【解决方案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 报告)并且大部分是黑色的。

【讨论】:

  • 很抱歉延迟回复您。 WWDC 活动让我比我预期的要忙。感谢您为此付出的所有帮助和工作。我还没有机会尝试您的建议(我会在这个周末尝试)。
【解决方案3】:

我将发布我在调试一小时后发现的类似崩溃的解决方案,也许它对某人有用...... 原因就在这么愚蠢的事情上。 我在 NSLog 中有两个占位符,只有一个实变量。

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

【讨论】:

    猜你喜欢
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多