UIGraphicsBeginImageContext与CGBitmapContextCreate

我试图改变后台线程中的图像的颜色。
苹果文档说UIGraphicsBeginImageContext只能从主线程调用,我试图使用CGBitmapContextCreate:

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

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

你的第二个方法是做第一个从未做过的工作。 下面是第二种方法的调整,以更贴近第一个:

 - (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()来validation它是否正确。

当然,正如Brad Larson在评论中提到的那样,如果你的目标是iOS 4.0及以上版本,那么UIKit的graphics方法(根据版本说明)是线程安全的,你应该可以使用第一种方法。