8

私は奇妙な問題に直面しています。libzbarを使用してiOSコマンドラインバーコードスキャナーユーティリティを開発しています(はい、これはジェイルブレイクされたデバイス用です)。CGImageCreateWithPNGDataProvider()またはCGImageCreateWithJPEGDataProvider()メソッドを使用してファイルからを取得しようとしている場合を除いて、すべてうまくいきCGImageRefます。これら2つの関数は、5.1.1iPadでセグメンテーション違反をスローするためです。ZBarScannerUIImageを使用して画像データを取得する場合、次のようなものを使用して、カスタムクラスに問題はありません。

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で使用できない可能性があるため、シンボルは開発sysroot内にあるが、iOSの実際のダイナミックライブラリにはないため、ビルドは成功するのではないかとさえ思った。もしそうなら、私がNSLoggedした関数ポインタはそうでしょう?ただし、NSオブジェクトとCGオブジェクトも関数もNULLではないようです。CGImageコンストラクターに渡すNULLはパラメーターだけですが、Appleのドキュメントでは、NULLになる可能性があると明示的に記載されています...(更新CGImageCreateWith[...]DataProviderNULLdecodeArray:ドキュメントが間違っているかどうかを確認するために、有効なNULL以外の配列を渡そうとしましたが、それでも同じエラーが発生しました)。

このクラッシュについてのポインタ(しゃれを意図したもの)を教えてください。ここで何が欠けていますか?私がこれまでに見つけたすべてのチュートリアルとリファレンスは、このようにCGDataProviderとCGImageを使用することを提案しています。

4

1 に答える 1

5

ファイル名を使用する場合、アップルのドキュメントのサンプルコードでは、コメントで試した内容とkCGRenderingIntentPerceptual、デフォルトではなく値の組み合わせを使用します。

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

これを行うことで、プログラムにデータ自体を保持する必要がなくなり、表示されているセグメンテーション違反を防ぐことができます。

(少なくとも、iOSの公式ドキュメントにあるCoreTextPageViewerのサンプルコードを入手して試してみて、そのプロジェクトをビルドし、実行していることがどのように異なるかを理解してみてください。)

于 2012-09-11T06:36:54.377 に答える