如何从自定义数据流编写CoreGraphics CGImageRef?

时间:2014-07-17 00:11:50

标签: c++ objective-c core-graphics quartz-graphics

我希望结束的是一个Core Graphics CGImageRef,它被覆盖 - (void)drawRect:(CGRect)rect方法绘制到屏幕上。这是我到目前为止所做的。

- (void)drawRect:(CGRect)rect
{
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    const CGFloat _x = CGRectGetMinX(rect);
    const CGFloat _y = CGRectGetMinY(rect);
    const CGFloat _w = CGRectGetWidth(rect);
    const CGFloat _h = CGRectGetHeight(rect);

    const CGFloat scale = [[UIScreen mainScreen] scale];

    const int pixelsWide = (_w * scale);
    const int pixelsHigh = (_h * scale);

    const size_t colorValues = 4;
    const int rawMemorySize = (pixelsWide * pixelsHigh * colorValues);

    // raw pixel data memory
    UInt8 pixelData[rawMemorySize];

    // fill the raw pixel buffer with arbitrary gray color for test

    for(size_t ui = 0; ui < rawMemorySize; ui++)
    {
        pixelData[ui] = 255; // black
    }

    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CFDataRef rgbData = CFDataCreate(NULL, pixelData, rawMemorySize);
    CGDataProviderRef provider = CGDataProviderCreateWithCFData(rgbData);

    CGImageRef rgbImageRef = CGImageCreate(pixelsWide, pixelsHigh, 8, (colorValues * colorValues), (pixelsWide * colorValues), colorspace, kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);

    CFRelease(rgbData);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorspace);

    //Draw the bitmapped image
    CGContextDrawImage(currentContext, CGRectMake(_x, _y, pixelsWide, 64), rgbImageRef);
    CGImageRelease(rgbImageRef);
}

我在for循环中抛出了一个EXC_BAD_ACCESS错误。

我觉得我很亲密,但我不确定。什么想法可能是罪魁祸首?提前谢谢你:)

2 个答案:

答案 0 :(得分:3)

还有一些需要注意的事项。

drawRect的rect参数只是脏矩形,可能小于self.bounds。除非您的代码经过优化,只能绘制脏矩形,否则请使用self.bounds

在堆栈上分配pixelData数组是一个坏主意,可能是错误的原因。这一切都取决于观点有多大。我怀疑AaronGolden使用的视图比你小,因此没有任何问题。对阵列calloc更安全,并在您完成使用后将其释放。请注意,calloc会将数组清除为透明黑色。

以下是我过去用过这类事情的一些示例代码。即使使用calloc创建像素阵列,您仍然可以像标准数组一样访问它(例如pixels[100] = 0xff0000ff;完全有效)。但是,出于性能原因,我通常使用指针来访问单个像素。

const CGFloat scale = [[UIScreen mainScreen] scale];
int width  = self.bounds.size.width  * scale;
int height = self.bounds.size.height * scale;

uint32_t *pixels = calloc( width * height, sizeof(uint32_t) );
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate( pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast );

uint8_t *bufptr = (uint8_t *)pixels;
for ( int y = 0; y < height; y++)
{
    for ( int x = 0; x < width; x++ )
    {
        bufptr[0] = redValue;
        bufptr[1] = greenValue;
        bufptr[2] = blueValue;
        bufptr[3] = alphaValue;

        bufptr += 4;
    }
}

CGImageRef newCGImage = CGBitmapContextCreateImage( context );
CGContextRelease( context );
CGColorSpaceRelease( colorSpace );
free( pixels );

答案 1 :(得分:1)

以下是一些建议。我尝试了你的代码,并没有在for循环中遇到错误的访问,就像你描述的那样,但是:

您不需要for循环将所有内容设置为255。您可以使用memset

memset(pixelData, 255, sizeof(pixelData));

在你对CGImageCreate的调用中,紧跟在你的文字8之后的参数是错误的。这应该是每个像素的位数,8 * colorValues而不是colorValues * colorValues。因此,创建您的图像:

CGImageRef rgbImageRef = CGImageCreate(pixelsWide, pixelsHigh, 8, 8 * colorValues, pixelsWide * colorValues, colorspace, kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);

最后,我注意到你发表评论说255对应黑色,但那不对。如果您将所有像素数据字节设为255,则您的图像应为完整白色。您在CGContextDrawImage调用中以64点的高度绘制图像,当我使用这些更正运行代码时,我确实看到 white 条高64位。