uigraphicsbeginimagecontext vs cgbitmapcontextcreate
-
11-10-2019 - |
質問
背景スレッドで画像の色を変更しようとしています。
Apple Docは、uigraphicsbeginimagecontextはメインスレッドからのみ呼び出されると言います、そして、私はcgbitmapcontextcreateを使用しようとしています:
コンテキスト= cgbitmapcontextcreate(bitmapdata、pixelswide、pixelshigh、8、//コンポーネントあたりビット
bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst);
uigraphisbeginimagecontextを使用して「changecolor」の最初のバージョンの2つのバージョンがあり、2番目はcgbitmapcontextcreateを使用しています。
最初のものは色を正しく変えますが、2番目の色は正しく変わりません。
何故ですか?
- (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;
}
解決
あなたの2番目の方法は、最初の方法が決してしなかった仕事をすることです。最初の方法をより密接に一致させるための2番目の方法の調整を次に示します。
- (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;
}
私が行った2つの変更は、これを使用するように変換しました CGContextSetFillColorWithColor()
, 、そして私は危険で間違っていることを削除しました free()
ビットマップコンテキストのバッキングデータの。このコードスニペットが最初のコードと同じように動作しない場合、あなたはあなたの実装を見る必要があります CreateARGBBitmapContext()
それが正しいことを確認するため。
もちろん、Brad Larsonがコメントで述べたように、iOS 4.0以上をターゲットにしている場合、UIKITグラフィックスメソッドは(リリースノートによると)スレッドセーフであり、最初の方法を正常に使用できるはずです。