24bitのビットマップ


24bitのビットマップデータを作るにはどうしたら良いかといろいろ試していると
CGImageCreateのbitmapInfoの指定で24bitのビットマップができた。

CGImageCreate
Creates a bitmap image from data supplied by a data provider.

CGImageRef CGImageCreate (
   size_t width,
   size_t height,
   size_t bitsPerComponent,
   size_t bitsPerPixel,
   size_t bytesPerRow,
   CGColorSpaceRef colorspace,
   CGBitmapInfo bitmapInfo,
   CGDataProviderRef provider,
   const CGFloat decode[],
   bool shouldInterpolate,
   CGColorRenderingIntent intent
);

動作確認用のテストプログラム

-(void)bitmapTest2:(NSString*)fname
{
	//------------------------------------------------------------
	// ◆デスクトップのスクリーンショットを取得
	//------------------------------------------------------------
	// Available in Mac OS X v10.5 and later
	CGImageRef screenImageRef = CGWindowListCreateImage(
			[[NSScreen mainScreen]frame], 
			kCGWindowListOptionOnScreenBelowWindow,
			kCGNullWindowID, 
			kCGWindowImageDefault);	
	
	
	int width = CGImageGetWidth(screenImageRef);
	int height = CGImageGetHeight(screenImageRef);
	
	NSLog(@"width : %d",width) ;
	NSLog(@"height : %d",height) ;

	unsigned char *data = malloc(width * height * sizeof(unsigned char) * 4);
	CGContextRef bitmapContext = CGBitmapContextCreate(data,
			width,
			height,
			8,
			width * 4,
			CGColorSpaceCreateDeviceRGB(),
			kCGImageAlphaPremultipliedLast);
	

	CGContextDrawImage(bitmapContext, CGRectMake(0,0,width,height), screenImageRef);
	unsigned char *bitmap = CGBitmapContextGetData(bitmapContext);

	
	CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(NULL,
			bitmap,
			width * height * 4,
			NULL);
	
	
	CGImageRef imageRef = CGImageCreate(width,	// width
			height, // height
			8,          // bitsPerComponent
			32,        // bitsPerPixel
			width * 4,  // bytesPerRow
			CGColorSpaceCreateDeviceRGB(),  // colorspace
			kCGBitmapByteOrderDefault,  // bitmapInfo ※この指定で24ビットのビットマップになる
			dataProviderRef,    // provider
			NULL,                       // decode
			NO,                          // shouldInterpolate
			kCGRenderingIntentDefault);    // intent
	
	
	CGImageAlphaInfo info = CGImageGetAlphaInfo(imageRef);
	if(info == kCGImageAlphaNone) NSLog(@"info : kCGImageAlphaNone") ;
	if(info == kCGImageAlphaPremultipliedLast) NSLog(@"info : kCGImageAlphaPremultipliedLast") ;
	if(info == kCGImageAlphaPremultipliedFirst) NSLog(@"info : kCGImageAlphaPremultipliedFirst") ;
	if(info == kCGImageAlphaLast) NSLog(@"info : kCGImageAlphaLast") ;
	if(info == kCGImageAlphaFirst) NSLog(@"info : kCGImageAlphaFirst") ;
	if(info == kCGImageAlphaNoneSkipLast) NSLog(@"info : kCGImageAlphaNoneSkipLast") ;
	if(info == kCGImageAlphaNoneSkipFirst) NSLog(@"info : kCGImageAlphaNoneSkipFirst") ;


	//------------------------------------------------------------
	// ◆ファイル出力
	//------------------------------------------------------------
	
	// ビットマップを作成
	NSBitmapImageRep* bitmap_rep = [[NSBitmapImageRep alloc]initWithCGImage:imageRef] ; // このビットマップは24ビットになる
	
	NSLog(@"bitmap_rep.bitsPerPixel : %d",bitmap_rep.bitsPerPixel) ;
	NSLog(@"bitmap_rep.bytesPerPlane : %d",bitmap_rep.bytesPerPlane) ;
	NSLog(@"bitmap_rep.bytesPerRow : %d",bitmap_rep.bytesPerRow) ;
	NSLog(@"bitmap_rep.numberOfPlanes : %d",bitmap_rep.numberOfPlanes) ;
	NSLog(@"bitmap_rep.samplesPerPixel : %d",bitmap_rep.samplesPerPixel) ;
	
	
	
	// ファイル出力
	[self writeImageFileName:fname BitmapImageRep:bitmap_rep] ;
	
	
	//------------------------------------------------------------
	// 後処理
	//------------------------------------------------------------
	free(data);
	CGDataProviderRelease(dataProviderRef);
	CGImageRelease(imageRef);

	CGImageRelease(screenImageRef);

	[bitmap_rep release] ;
}

テストプログラムの実行結果

CGImageCreateのbitmapInfoにkCGBitmapByteOrderDefaultを指定した場合の実行結果
2009-11-23 20:19:37.870 ImageTest[2148:a0f] width : 1680
2009-11-23 20:19:37.873 ImageTest[2148:a0f] height : 1050
2009-11-23 20:19:37.910 ImageTest[2148:a0f] info : kCGImageAlphaNone
2009-11-23 20:19:37.911 ImageTest[2148:a0f] bitmap_rep.bitsPerPixel : 24
2009-11-23 20:19:37.911 ImageTest[2148:a0f] bitmap_rep.bytesPerPlane : 5292000
2009-11-23 20:19:37.912 ImageTest[2148:a0f] bitmap_rep.bytesPerRow : 5040
2009-11-23 20:19:37.912 ImageTest[2148:a0f] bitmap_rep.numberOfPlanes : 1
2009-11-23 20:19:37.913 ImageTest[2148:a0f] bitmap_rep.samplesPerPixel : 3
imageRefのCGImageAlphaInfoを確認するとkCGImageAlphaNoneになっている。
2009-11-23 20:19:37.910 ImageTest[2148:a0f] info : kCGImageAlphaNone
NSBitmapImageRepのbitsPerPixel(bitmap_rep.bitsPerPixel)は、24になっている。
2009-11-23 20:19:37.911 ImageTest[2148:a0f] bitmap_rep.bitsPerPixel : 24
bitmap_rep.bytesPerRowは、画像の幅1680 × 3の5040と一致している。

この結果を見ると、24bitのビットマップが作成されているようだ。
とりあえず、この方法で進めてみよう。


2009.12.15追記

上記のプログラムでは、作成したビットマップデータはおかしくなっているかも?

http://d.hatena.ne.jp/kurusaki/20091215/1260872312