代码之家  ›  专栏  ›  技术社区  ›  Kaelin Colclasure

CGImage浮点格式是否需要字节交换?

  •  0
  • Kaelin Colclasure  · 技术社区  · 12 年前

    我正在做一些需要浮点灰度图像数据的图像处理工作。方法 -imagePlanarFData: 以下是我目前如何从输入中提取这些数据 CIImage :

    - (NSData *)byteswapPlanarFData:(NSData *)data
                        swapInPlace:(BOOL)swapInPlace;
    {
        NSData * outputData = swapInPlace ? data : [data mutableCopy];
        const int32_t * image = [outputData bytes];
        size_t length = [outputData length] / sizeof(*image);
        for (int i = 0;
             i < length;
             i++) {
            int32_t * val = (int32_t *)&image[i];
            *val = OSSwapBigToHostInt32(*val);
        }
        return outputData;
    }
    
    - (NSData *)imagePlanarFData:(CIImage *)processedImage;
    {
        NSSize size = [processedImage extent].size;
        if (size.width == 0) {
            return nil;
        }
        dispatch_once(&_onceToken, ^ {
            _colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
            _bytesPerRow = size.width * sizeof(float);
            _cgx = CGBitmapContextCreate(NULL, size.width, size.height, 32, _bytesPerRow, _colorSpace, kCGImageAlphaNone | kCGBitmapFloatComponents);
            // Work-around for CIImage drawing EXC_BAD_ACCESS when running with Guard Malloc;
            // see <http://stackoverflow.com/questions/11689233/ciimage-drawing-exc-bad-access>
            NSDictionary * options = nil;
            if (getenv("MallocStackLogging") || getenv("MallocStackLoggingNoCompact")) {
                NSLog(@"Forcing CIImageContext to use software rendering; see %@",
                      @"<http://stackoverflow.com/questions/11689233/ciimage-drawing-exc-bad-access>");
                options = @{ kCIContextUseSoftwareRenderer: @YES };
            }
            _cix = [CIContext contextWithCGContext:_cgx
                                           options:options];
            _rect = CGRectMake(0, 0, size.width, size.height);
        });
        float * data = CGBitmapContextGetData(_cgx);
        CGContextClearRect(_cgx, _rect);
        [_cix drawImage:processedImage
                 inRect:_rect
               fromRect:_rect];
        NSData * pixelData = [NSData dataWithBytesNoCopy:data
                                                  length:_bytesPerRow * size.height
                                            freeWhenDone:NO];
        // For whatever bizarre reason, CoreGraphics uses big-endian floats (!)
        return [self byteswapPlanarFData:pixelData swapInPlace:NO];
    }
    

    正如评论中提到的,我非常惊讶地看到浮动像素数据以big-endian顺序来自CGBitmapContext。(我只是通过反复试验确定的。)因此,增加了方法 -byteswapPlanarFData:swapInPlace: 被介绍了,一切似乎都很好。。。有一段时间。

    但是 现在 我想呈现这个处理过的数据 返回 变成 CGImage .

    之前我的代码占用了 float * data 上面提取的缓冲区,并将其直接用于渲染新的 CG图像 然后把它包起来 NSImage ,如下所示:

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, bytesPerRow * size.height, NULL);
    CGImageRef renderedImage = CGImageCreate(size.width, size.height, 32, 32, bytesPerRow, colorSpace, kCGImageAlphaNone | kCGBitmapFloatComponents, provider, NULL, false, kCGRenderingIntentDefault);
    CGDataProviderRelease(provider);
    NSImage * image = [[NSImage alloc] initWithCGImage:renderedImage
                                                  size:size];
    CGImageRelease(renderedImage);
    

    所以 现在 我正在这样做:

    pixelData = [mumble imagePlanarFData:processedImage];
    // Swap data back to how it was before...
    pixelData = [mumble byteswapPlanarFData:pixelData
                                swapInPlace:YES];
    float * data = (float *)[pixelData bytes];
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, bytesPerRow * size.height, NULL);
    CGImageRef renderedImage = CGImageCreate(size.width, size.height, 32, 32, bytesPerRow, colorSpace, kCGImageAlphaNone | kCGBitmapFloatComponents, provider, NULL, false, kCGRenderingIntentDefault);
    CGDataProviderRelease(provider);
    NSImage * image = [[NSImage alloc] initWithCGImage:renderedImage
                                                  size:size];
    CGImageRelease(renderedImage);
    

    如上所述 工作相反,我收到了一张损坏的图片和来自CoreGraphics的一连串投诉:

    Mar 21 05:56:46 aoide.local LabCam[34235] <Error>: CMMConvLut::ConvertFloat 1 input (inf)
    Mar 21 05:56:46 aoide.local LabCam[34235] <Error>: ApplySequenceToBitmap failed (-171)
    Mar 21 05:56:46 aoide.local LabCam[34235] <Error>: ColorSyncTransformConvert - failed width = 160 height = 199 dstDepth = 7 dstLayout = 0 dstBytesPerRow = 1920 srcDepth = 7 srcLayout = 0 srcBytesPerRow = 640
    

    我哪里出了问题?

    1 回复  |  直到 12 年前
        1
  •  0
  •   Kaelin Colclasure    12 年前

    啊,发现问题了。。。事实证明,在我将字节交换调用添加到之前,有一个遗留的例程 -imagePlanarFData: 那是 而且 正在交换到位的字节。。。

    我会的 希望听到一些解释,解释为什么CoreGraphics希望在我们的小端平台上以大端字节顺序显示这些值。