Любые предложения о том, как обрабатывать этот сбой в CGImageDestinationFinalize? - PullRequest
0 голосов
/ 01 июня 2011

Мое приложение считывает и изменяет размеры изображений, загружаемых из Интернета;и, к сожалению, я не могу контролировать создание этих образов.

Недавно у меня произошел сбой, который я не знаю, как лучше всего справиться.В этом случае изображение было поврежденным GIF-файлом.Он не был сильно поврежден, но сообщал, что размер разрешения (высота х ширина) был неточным.Предполагалось, что это изображение размером 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.

У кого-нибудь есть какие-либо идеи относительно того, как я могу справиться или перехватить это условие?Я очень ценю любые предложения, так как это беспокоит меня по поводу стабильности приложения.Или это просто «отчет как радар для 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;
    }
}

Ответы [ 3 ]

2 голосов
/ 06 июня 2011

Я создал тестовый проект из вашего описания, который загружает и сохраняет изображение с предоставленного 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.

Тот факт, что ошибка возникает в вашем приложении, может быть связан с каким-то другим типом ошибки.Возможно, есть проблема с вашим многопоточным использованием API-интерфейса ImageIO.

Одна вещь, которую я заметил, была аргументом параметров, который вы передали в вызове CGImageDestinationCreateWithURL.Согласно документации это должно быть NULL.

Редактировать: Соответствующее изображение имеет размер 792 × 1111 (как сообщается в PhotoShop и Preview.app) и в большинстве своемчерный.

0 голосов
/ 16 марта 2013

Я опубликую информацию о подобной аварии, которую я нашел после часа отладки, может быть, это было бы полезно для кого-то ... Причина была в такой глупости. У меня было два заполнителя в NSLog и только одна реальная переменная.

NSLog(@"lastItemDate = %@ unixtime = %@", lastItemDate);
0 голосов
/ 04 июня 2011

Что вы можете сделать, это сохранить изображение в объекте UIImage, нарисовать его в новом контексте (используя свойство size) и затем создать объект CGImageRef.Это исправит коррупцию.Хотя вам нужно делать это для каждого получаемого вами изображения, это будет небольшим снижением производительности.

Обратите внимание, что вы должны отправлять сообщения на UIImage из основного потока.

...