よく、以下のようなコードでオフスクリーンコンテキストを作成し、
描画の後画像を得るサンプルを見ます。
コードが単純なためか、非常に広く使われていると思います。
UIGraphicsBeginImageContextWithOptions(CGSizeMake(1024, 1024), NO, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextFillEllipseInRect(context, CGRectMake(0, 0, 1024, 1024));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
ですが、これは本来やらなくていい処理をしていると思いませんか?
というのも、
描画のためのコンテキストを一度作成し、UIGraphicsGetImageFromCurrentImageContextでわざわざコピーしてきているのです。
メモリを用意して、そこに描画して、それをそのまま画像にすれば、
この無駄なコピーは本来発生しないはずなんです。
その点を考慮に入れると、本来最小限のコードは例えば以下のようになるかと思います。
補助関数
static void bufferFree(void *info, const void *data, size_t size)
{
free((void *)data);
}
static size_t align16(size_t size)
{
if(size == 0)
return 0;
return (((size - 1) >> 4) << 4) + 16;
}
メイン処理
size_t width = 1000;
size_t height = 1000;
size_t bitsPerComponent = 8;
size_t bytesPerRow = align16(4 * width);
size_t bufferSize = bytesPerRow * height;
uint8_t *bytes = malloc(bufferSize);
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrderDefault;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(bytes, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextFillEllipseInRect(context, CGRectMake(0, 0, width, height));
CGContextRelease(context);
context = NULL;
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, bytes, bufferSize, bufferFree);
size_t bitsPerPixel = 32;
CGImageRef image = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitmapInfo, dataProvider, NULL, NO, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
dataProvider = NULL;
CGColorSpaceRelease(colorSpace);
colorSpace = NULL;
CGImageRelease(image);
ポイントはCGBitmapContextCreateに自分で用意したメモリを使ってもらう点です。
描画が終われば、即座にコンテキストは捨ててしまい、
ラスターデータだけが残るので、そのままCGImageのバッファとして、CGDataProviderCreateWithDataを通して使用します。
bytesPerRowを16バイトアラインメントが推奨されているので、対応してあげる事、
など少し気を配っておいた方がいい点もあります。
というわけで、これにより無駄なコピーを避ける事ができます。
若干コードが多いため、
使い回すなら、関数やクラスに加工して使うと良いでしょう。
画像の扱いは負荷が高いため、
気づくとCPU負荷があがりすぎていたりすると思いますので、気になる場合は試してみてはいかがでしょうか。