UIGraphicsBeginImageContext vs CGBitmapContextCreate [英] UIGraphicsBeginImageContext vs CGBitmapContextCreate

查看:256
本文介绍了UIGraphicsBeginImageContext vs CGBitmapContextCreate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在后台线程中更改图片的颜色。

Apple doc说UIGraphicsBeginImageContext只能从主线程调用,我想使用CGBitmapContextCreate:

I'm trying to change color of an image in a background thread.
Apple doc says UIGraphicsBeginImageContext can only be called from main thread, and I'm trying to use CGBitmapContextCreate:


context = CGBitmapContextCreate
(bitmapData,
pixelsWide,
pixelsHigh,
8,// bits per组件

context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, // bits per component

                             bitmapBytesPerRow,
                             colorSpace,
                             kCGImageAlphaPremultipliedFirst);




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

I have two versions of "changeColor" first one using UIGraphisBeginImageContext, second one using CGBitmapContextCreate.

第一个正确更改颜色,第二个不正确。

为什么?

The first one correctly changes color, but second one doesn't.
Why is that?

- (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;

}


推荐答案

方法是做第一个从来没有做的工作。下面是调整第二种方法以更紧密地匹配第一种方法:

Your second method is doing work that the first never did. Here's an adjustment of the second method to more closely match the first one:

- (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()的实现,以验证它是否正确。

The two changes I made were I converted this to use CGContextSetFillColorWithColor(), and I removed the dangerous and incorrect free() of the backing data of the bitmap context. If this code snippet does not behave identically to the first one, then you will have to look at your implementation of CreateARGBBitmapContext() to verify that it is correct.

当然,如Brad Larson在评论中提到的,如果你的目标是iOS 4.0及以上,UIKit的图形方法(根据发行说明)线程安全,你应该能够使用第一种方法很好。

Of course, as Brad Larson mentioned in the comments, if you're targeting iOS 4.0 and above, the UIKit graphics methods are (according to the release notes) thread-safe and you should be able to use the first method just fine.

这篇关于UIGraphicsBeginImageContext vs CGBitmapContextCreate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆