有关如何在CGImageDestinationFinalize中处理此崩溃的任何建议? [英] Any suggestions on how to handle this crash in CGImageDestinationFinalize?

查看:456
本文介绍了有关如何在CGImageDestinationFinalize中处理此崩溃的任何建议?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



最近我遇到了一次崩溃,我不确定如何才能最好地处理。在这种情况下,图像是一个损坏的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在这里
CFRelease(imageDestination);
}
}

崩溃日志的片段是:

 异常类型:EXC_BAD_ACCESS(SIGSEGV)
异常代码:KERN_INVALID_ADDRESS位于0x06980000
崩溃线程:8

线程8名称:调度队列:com.apple.root.default-priority
线程8崩溃:
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。



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



编辑&补充代码:



所有这些处理都发生在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 numberWi thInt:1024],kCGImageSourceThumbnailMaxPixelSize,
(id)kCFBooleanTrue,(id)kCGImageSourceCreateThumbnailFromImageAlways,
nil];

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

if(!image){
return nil;
} else {
[(id)image autorelease];
返回图片;
}
}

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

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

if(!imageSource){
DebugLog(@问题创建图像的图像源:%@,imageLocationOnDisk);
返回零;
} else {
[(id)imageSource autorelease];
return imageSource;
}
}


解决方案

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



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

   - (void)checkImage 
{
NSURL * imageLocationOnDisk = [[NSBundle mainBundle] URLForResource:@htg -logo-tiny
withExtension:@gif];
断言(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);
断言(图片);

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);
断言(dest);
CGImageDestinationAddImage(dest,image,(CFDictionaryRef)options);
CGImageDestinationFinalize(dest);
}

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

正如我上面所说,我的机器上的代码运行正常。我也尝试使用 CGImageSourceCreateImageAtIndex 成功。



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



我注意到的一件事是您在 CGImageDestinationCreateWithURL 通话。根据文档,它应该 NULL



编辑:相关图片大小为792×1111(由PhotoShop和Preview.app报告)并且大部分是黑色。


My application reads and resizes images that are loaded from the internet; and unfortunately I can't control the creation of these images.

Recently I had a crash that I am not sure how best to be able to handle. In this case the image was a corrupt GIF file. It wasn't badly corrupted but it was reporting a resolution size (height x width) that wasn't accurate. The image was supposed to be a 400x600 image but was reporting something like 1111x999.

The code snippet that crashed is:

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

The snippet of the crash log is:

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

The image in question was a GIF so I had the type in my method set to @"com.compuserve.gif". As far as I can tell the CGImageDestinationRef imageDestination was a valid object.

Part of the logic of my app is to keep images in the same format as they are read. So in this case I was resizing and writing back out a GIF.

I tried forcing to write out the CGImageRef as a PNG and interestingly the application didn't crash. It wrote out the PNG (which wasn't valid -- just a blank black image), but it didn't crash. But I've no idea in normal course of execution to know that I should write a GIF as a PNG.

Anybody got any ideas as to how I can handle or trap this condition? I'd greatly appreaciate any suggestions as this is a worry for me re: application stability. Or is this just a straight up "report as a radar to Apple"?

Edits & supplementary code:

All of this processing occurs within a NSOperationQueue and not on the main thread

Image in question is available at http://dribbble.com/system/users/1409/screenshots/182540/htg-logo-tiny.gif?1306878218

Here is the function where I create the 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;
    }
}

and the CGImageSourceRef is created from a filepath like:

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

解决方案

I created a test project from your description which loads and saves the image from the provided URL. It runs without problems in the simulator and on an iPhone 4 (iOS 4.3.2).

Could you try to run the following method in your project/environment:

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

To run the test you have to copy the image to your project's resources.

As I said above code works fine on my machine. I also tried it successfully with CGImageSourceCreateImageAtIndex.

The fact that the error happens in your app might be related to some other kind of error. Perhaps there's an issue with your threaded use of the ImageIO API.

One thing I noticed was the options argument you passed in the CGImageDestinationCreateWithURL call. According to the documentation it should be NULL.

Edit: The image in question has a size of 792 × 1111 (as reported by both PhotoShop and Preview.app) and is mostly black.

这篇关于有关如何在CGImageDestinationFinalize中处理此崩溃的任何建议?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆