iOS: CGImageCreateWith[PNG or JPEG]DataProvider вызывает ошибку сегментации

Я столкнулся со странной проблемой. Я разрабатываю утилиту для сканирования штрих-кода командной строки iOS, используя libzbar (да, это для взломанных устройств). Все идет нормально, за исключением случаев, когда я пытаюсь использовать методы CGImageCreateWithPNGDataProvider() или CGImageCreateWithJPEGDataProvider() для получения CGImageRef из файла, потому что эти две функции вызывают segfault на моем iPad 5.1.1. Проблема не в моем пользовательском классе ZBarScanner, потому что если я использую UIImage для получения данных изображения, используя что-то вроде

UIImage *uiImage = [UIImage imageWithContentsOfFile:fname];
CGImageRef image = uiImage.CGImage;

затем он работает нормально и печатает данные, хранящиеся в штрих-коде. Кроме того, изображения PNG и JPEG хорошо отформатированы — я могу просматривать их с помощью файлового браузера на самом устройстве, а также пробовал несколько других изображений. Я даже пытался опустить все вызовы функций CFRelease() и сообщения release, чтобы избежать висячих указателей. Вот мой код:

#define LOG() NSLog(@"Reached line %d", __LINE__)

int main(int argc, char **argv)
{
    if (argc != 2)
            return 1;

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    LOG(); // line 21

    NSString *fname = [[NSString stringWithUTF8String:argv[1]] retain]; // added an extra retain just in case

    LOG(); // line 25

    CFDataRef data = (CFDataRef)[NSData dataWithContentsOfFile:fname];
    CGDataProviderRef dProv = CGDataProviderCreateWithCFData(data);
    // I also tried using
    // dProv = CGDataProviderCreateWithFilename(argv[1]);
    // that made no difference either. The data and data provider are
    // valid, but the CGImage constructors always segfault.
    if (dProv == NULL) {
        fprintf(stderr, "Invalid CGDataProvider\n");
        abort();
    }

    LOG(); // line 34

    CGImageRef image = NULL;

    if ([[fname pathExtension] isEqualToString:@"png"]) {
        LOG(); // line 39
        NSLog(@"Function pointer: %p", CGImageCreateWithPNGDataProvider);
        image = CGImageCreateWithPNGDataProvider(dProv, NULL, false, kCGRenderingIntentDefault); // This function segfaults, or...
        LOG();
    } else if ([[fname pathExtension] isEqualToString:@"jpg"]
        || [[fname pathExtension] isEqualToString:@"jpeg"]) {
        LOG();
        image = CGImageCreateWithJPEGDataProvider(dProv, NULL, true, kCGRenderingIntentDefault); // ... or this one.
        LOG();
    } else {
        fprintf(stderr, "File '%s' is neither a PNG nor a JPEG file!\n", argv[1]);
        LOG();
        abort();
    }

    LOG();
    // CFRelease(dProv);
    LOG();
    ZBarScanner *scanner = [ZBarScanner zbarScannerWithCGImage:image];
    // CFRelease(image);
    LOG();
    NSArray *arr = [scanner scan];
    NSLog(@"The result of the scanning is:\n%@", arr);
    LOG();
    [pool drain];

    return 0;
}

Если я запускаю его в отладчике (для ясности удалены беспорядок GDB и NSLog):

gdb ./scanner
(gdb) run ./barcode1.png
Reached line 21
Reached line 25
Reached line 34
Reached line 39
Function pointer: 0x37c5b535

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000
0x00000000 in ?? ()
(gdb) backtrace
#0 0x00000000 in ?? ()
(gdb)

Таким образом, даже обратная трассировка не показывает ничего явно неправильного/полезного... Хотя кажется, что что-то равно NULL где-то. Я даже подозревал, что из-за того, что мой набор инструментов является неофициальной сборкой на основе версии 4.0, эти функции могут быть недоступны в iOS 5.1.1, поэтому сборка прошла успешно, поскольку символы CGImageCreateWith[...]DataProvider находятся внутри системного корня development, но не среди фактических динамических библиотек iOS, но если бы это было так, указатель функции I NSLogged out был бы NULL, верно? Однако ни объекты NS и CG, ни функции не кажутся NULL — единственный NULL, который я передаю конструкторам CGImage, — это параметр decodeArray, но в документации Apple явно указано, что он может быть NULL... ( Обновление: я попытался передать действительный массив, отличный от NULL, чтобы выяснить, неверна ли документация, но все равно получил ту же ошибку).

Не могли бы вы дать мне какие-нибудь указания (каламбур) об этом сбое? Что мне здесь не хватает? Все учебники и ссылки, которые я нашел до сих пор, предлагают использовать CGDataProvider и CGImage именно так.


person Community    schedule 11.09.2012    source источник
comment
Вы не упоминаете проверку следующего шага в цепочке от поставщика данных - вы уверены, что data является допустимым объектом (и непустым)? Кроме того, вы пытались передать некоторое фиктивное значение для массива декодирования, просто чтобы убедиться, что документы неверны?   -  person jscs    schedule 11.09.2012
comment
@JoshCaswell Я сейчас проверю, спасибо за предложение.   -  person    schedule 11.09.2012
comment
@JoshCaswell Я добавил assert(data != NULL); и assert([data length] > 0;, и все прошло...   -  person    schedule 11.09.2012
comment
@JoshCaswell Я тоже увижу массив, минутку.   -  person    schedule 11.09.2012
comment
@JoshCaswell Я пробовал с фиктивным массивом размером 1024 (CGFloat), но все равно получаю segfault. Кстати, почему GDB не находит ничего полезного? Я использую gcc -g для создания символов отладки...   -  person    schedule 11.09.2012
comment
Кроме того, у меня есть идея: возможно ли, что эти функции требуют присутствия живого CGContext?   -  person    schedule 11.09.2012
comment
@JoshCaswell есть другие идеи? Или, может быть, какая-то реакция на мой последний комментарий? Я не смог найти никаких доказательств моей теории о действительном CGContextRef...   -  person    schedule 11.09.2012
comment
Я не знаю, поможет ли это, но на моем (не взломанном) iPhone ваш код не дает сбой - и в этот момент нет активного CGContext.   -  person Martin R    schedule 11.09.2012
comment
Моей следующей мыслью тоже была CGContext, но если функции CGImageCreateWith[...]DataProvider() требовали ее, она была бы частью интерфейса (т. е. переданной). Ваши подозрения по поводу проблем с связыванием кажутся разумными — может быть, внутренняя функция, которую используют функции создания образа, была изменена с 4.0 на 5.1? Я не знаю, как это узнать.   -  person jscs    schedule 11.09.2012
comment
@Josh Cashwell, к сожалению, я тоже, но в любом случае это не должно влиять на ход программы, это будет проблемой при связывании самого CoreGraphics, но не при связывании приложения с CG.   -  person    schedule 11.09.2012
comment
@ H2CO3 ты смог решить эту проблему? я думаю, что я сталкиваюсь с чем-то подобным   -  person Roy Tang    schedule 12.11.2012
comment
@RoyTang, к сожалению, нет. (Кстати, этот вопрос действительно так плох? Или почему он получил 5 отрицательных голосов?)   -  person    schedule 12.11.2012
comment
Я ненавижу комментировать голосование, но серьезно, да, что за пять отрицательных голосов? В эти дни здесь происходит какое-то ебанутое голосование (в основном, правда).   -  person jscs    schedule 28.01.2013
comment
@JoshCaswell Я не знаю, почему это заслужило пять отрицательных голосов. Это конкретный, конкретный вопрос по теме, не являющийся спамом, написанный на достаточно хорошем английском языке и с необходимым форматированием. Это также показывает мои усилия по чтению документации и использованию отладчика.   -  person    schedule 28.01.2013
comment
Абсолютно; это отличный вопрос. Я предполагаю, что вы стали жертвой злости (я определенно был), или, возможно, у вас есть завистливый враг.   -  person jscs    schedule 28.01.2013
comment
@JoshCaswell Да... В наши дни что-то не так... :(   -  person    schedule 28.01.2013
comment
Объясните голосование против!   -  person    schedule 06.07.2013
comment
он думает, что libzbar можно использовать на устройствах без джейлбрейка   -  person Nicolas Manzini    schedule 05.08.2013


Ответы (1)


при использовании имени файла пример кода из документации Apple использует комбинацию того, что вы упомянули в своих комментариях, плюс значение kCGRenderingIntentPerceptual, а не значение по умолчанию:

    CGDataProviderRef pngDP = CGDataProviderCreateWithFilename([filePath fileSystemRepresentation]);
    if (pngDP) {
        CGImageRef img = CGImageCreateWithPNGDataProvider(pngDP, NULL, true, kCGRenderingIntentPerceptual); // true for interpolate, false for not-interpolate

это должно избавить вас от необходимости хранить сами данные в вашей программе и может предотвратить segfault, который вы видите.

(по крайней мере, возможно, получите и попробуйте пример кода для CoreTextPageViewer, найденный в официальной документации iOS, создайте этот проект и попытайтесь выяснить, чем отличается то, что вы делаете.)

person john.k.doe    schedule 11.09.2012
comment
Спасибо за предложение! Я сделал то, что вы предложили здесь, но я все еще получаю исходную ошибку. - person ; 11.09.2012