UIGraphicsBeginImageContext vs CGBitmapContextCreate

时间:2011-01-13 18:01:06

标签: ios colors cgbitmapcontextcreate

我正在尝试在后台线程中更改图像的颜色 Apple doc说UIGraphicsBeginImageContext只能从主线程调用,而我正在尝试使用CGBitmapContextCreate:

  

context = CGBitmapContextCreate   (位图数据,                                    pixelsWide,                                    pixelsHigh,                                    8,//每个组件的比特

                             bitmapBytesPerRow,
                             colorSpace,
                             kCGImageAlphaPremultipliedFirst);

我有两个版本的“changeColor”,第一个使用UIGraphisBeginImageContext,第二个使用CGBitmapContextCreate。

第一个正确改变颜色,但第二个没有 这是为什么?

- (UIImage*) changeColor: (UIColor*) aColor
{
    if(aColor == nil)
        return self;

    UIGraphicsBeginImageContext(self.size);

    CGRect bounds;
    bounds.origin = CGPointMake(0,0);
    bounds.size = self.size;
    [aColor set];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0, self.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextClipToMask(context, bounds, [self CGImage]);
    CGContextFillRect(context, bounds);

    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}

- (UIImage*) changeColor: (UIColor*) aColor
{
    if(aColor == nil)
        return self;

    CGContextRef context = CreateARGBBitmapContext(self.size);

    CGRect bounds;
    bounds.origin = CGPointMake(0,0);
    bounds.size = self.size;

    CGColorRef colorRef = aColor.CGColor;
    const CGFloat *components = CGColorGetComponents(colorRef);
    float red = components[0];
    float green = components[1];
    float blue = components[2];

    CGContextSetRGBFillColor(context, red, green, blue, 1);


    CGContextClipToMask(context, bounds, [self CGImage]);
    CGContextFillRect(context, bounds);

    CGImageRef imageRef = CGBitmapContextCreateImage(context);
    UIImage* img = [UIImage imageWithCGImage: imageRef];
    unsigned char* data = (unsigned char*)CGBitmapContextGetData (context);  
    CGContextRelease(context);
    free(data);

    return img;
}

CGContextRef CreateARGBBitmapContext(CGSize size)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    // Get image width, height. We'll use the entire image.                                                                                                                                                                                 
    size_t pixelsWide = size.width;
    size_t pixelsHigh = size.height;

    // Declare the number of bytes per row. Each pixel in the bitmap in this                                                                                                                                                                
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and                                                                                                                                                              
    // alpha.                                                                                                                                                                                                                               
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    // Use the generic RGB color space.                                                                                                                                                                                                     
    colorSpace = CGColorSpaceCreateDeviceRGB();

    if (colorSpace == NULL)
    {
        fprintf(stderr, "Error allocating color space\n");
        return NULL;
    }

    // Allocate memory for image data. This is the destination in memory                                                                                                                                                                    
    // where any drawing to the bitmap context will be rendered.                                                                                                                                                                            
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
        CGColorSpaceRelease( colorSpace );
        return NULL;
    }
    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits                                                                                                                                                                       
    // per component. Regardless of what the source image format is                                                                                                                                                                         
    // (CMYK, Grayscale, and so on) it will be converted over to the format                                                                                                                                                                 
    // specified here by CGBitmapContextCreate.                                                                                                                                                                                             
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,      // bits per component                                                                                                                                                                          
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
    }

    // Make sure and release colorspace before returning                                                                                                                                                                                    
    CGColorSpaceRelease( colorSpace );

    return context;

}

1 个答案:

答案 0 :(得分:3)

你的第二种方法是做第一种从未做过的工作。这是对第二种方法的调整,以便更接近第一种方法:

- (UIImage*) changeColor: (UIColor*) aColor
{
    if(aColor == nil)
        return self;

    CGContextRef context = CreateARGBBitmapContext(self.size);

    CGRect bounds;
    bounds.origin = CGPointMake(0,0);
    bounds.size = self.size;

    CGContextSetFillColorWithColor(aColor.CGColor);

    CGContextClipToMask(context, bounds, [self CGImage]);
    CGContextFillRect(context, bounds);

    CGImageRef imageRef = CGBitmapContextCreateImage(context);
    UIImage* img = [UIImage imageWithCGImage: imageRef];
    CGContextRelease(context);

    return img;
}

我做的两个更改是将其转换为使用CGContextSetFillColorWithColor(),并删除了位图上下文的后备数据的危险且不正确的free()。如果此代码段的行为与第一个代码段的行为不同,那么您必须查看CreateARGBBitmapContext()的实现,以验证它是否正确。

当然,正如Brad Larson在评论中提到的,如果您的目标是iOS 4.0及更高版本,UIKit图形方法(根据发行说明)是线程安全的,您应该能够使用第一种方法细