Skia第一个摘出来的例子,图片绕Y轴转

SkBitmap *pskBitmap; 
SkCanvas *pskCanvas;
BITMAPINFO *lpbmi;
HWND  g_hWnd;

SkBitmap *bkBitmap;//背景图片

SkRect   g_rtImg;// 图片最初按钮。

SkRect   g_rtClip;//矩阵裁剪用 ,做图片旋转时,每次旋转时的裁剪会用到上一次的裁剪范围。
//g_rtClip是共用裁剪范围,多个不同的位置共用,每次旋转前初始化为要旋转图片的原始位置

//初始化背景图片,
void MyInitBkImage(char *filename)
{
	SkFILEStream stream(filename);
	SkImageDecoder * coder = SkImageDecoder::Factory(&stream);
	if (coder)
	{
		bkBitmap = new SkBitmap();
		coder->decode(&stream,bkBitmap,SkBitmap::kRGB_565_Config,SkImageDecoder::kDecodePixels_Mode);
	}
}

//整体初始化
void MyInit()
{
	pskBitmap = new SkBitmap();
	pskBitmap->setConfig(SkBitmap::kRGB_565_Config,800,480);
	pskBitmap->allocPixels();//分配位图所占空间

	pskCanvas = new SkCanvas();
	pskCanvas->setBitmapDevice(*pskBitmap);

	lpbmi  = (BITMAPINFO*)malloc( sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(2) );

	//printf("%d,%d\n",sizeof(BITMAPINFOHEADER),sizeof(BITMAPINFO));40,44

	memset( lpbmi, 0, sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(2) );//必须同上方一直

	lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);//位图信息头大小 40字节
	lpbmi->bmiHeader.biWidth = 800;
	lpbmi->bmiHeader.biHeight = -480;
	lpbmi->bmiHeader.biPlanes = 1;
	lpbmi->bmiHeader.biBitCount = 16;              //16位位图  565模式0xF800、0x07E0、0x001F
	lpbmi->bmiHeader.biCompression = BI_BITFIELDS; //压缩参数  BI_RGB=0表示无压缩,
	lpbmi->bmiHeader.biSizeImage = 0;

	lpbmi->bmiColors[0].rgbBlue = 0;  
	lpbmi->bmiColors[0].rgbGreen = 0xF8;  //248?
	lpbmi->bmiColors[0].rgbRed = 0;  
	lpbmi->bmiColors[0].rgbReserved = 0;  

	lpbmi->bmiColors[1].rgbBlue = 0xE0;  //224
	lpbmi->bmiColors[1].rgbGreen = 0x07;  //7
	lpbmi->bmiColors[1].rgbRed = 0;  
	lpbmi->bmiColors[1].rgbReserved = 0;  

	lpbmi->bmiColors[2].rgbBlue = 0x1F;  //31
	lpbmi->bmiColors[2].rgbGreen = 0;  
	lpbmi->bmiColors[2].rgbRed = 0;  
	lpbmi->bmiColors[2].rgbReserved = 0;

	MyInitBkImage("\\USER\\skia\\bk.png");

	g_rtImg.setLTRB(151,214,249,346); //初始化图片位置
	//g_rtClip 在每次旋转前初始化                
}

//画图片filename,rt为其范围,图片没有保存,每次临时加载
void DrawImage(char * filename,SkCanvas *canvas, SkRect rt, SkPaint *paint)
{
	int ti = GetTickCount();
	SkFILEStream stream(filename);
	SkImageDecoder* coder = SkImageDecoder::Factory(&stream);
	SkBitmap *bitmap;
	if (coder)
	{
		//printf(" file %s code success\n",filename);
		bitmap = new SkBitmap();
		coder->decode(&stream, bitmap, SkBitmap::kRGB_565_Config,
			SkImageDecoder::kDecodePixels_Mode);
	}
	else
	{
		printf(" file %s code fail\n",filename);
		return;
	}
	//printf("24bit800*480png,code time =%d\n",GetTickCount()-ti);//367
	ti = GetTickCount();
	canvas->drawBitmap(*bitmap,rt.fLeft, rt.fTop);
	//printf("24bit800*480png,draw time =%d\n",GetTickCount()-ti);//12
	delete bitmap;
	return;

}

//画背景
void DrawBKImage()
{
	SkIRect rt;
	rt.setXYWH(0,0,800,480);
	int ti = GetTickCount();
	pskCanvas->drawBitmap(*bkBitmap,rt.fLeft,rt.fTop);
	printf("--------------time draw bk 24bit800*480=%d\n",GetTickCount()-ti);//11
}

//画图片filename,效果使其绕Y轴旋转rotateY角度,调用DrawImage()
void DrawRotateYImage(char * filename,int rotateY,SkRect rtImg)
{

	SkRect rtClip = g_rtClip;//保留上次裁剪范围

	pskCanvas->resetMatrix(); 

	SkMatrix matrix;
	Sk3DView	sk3DView;
	sk3DView.rotateY(rotateY); //绕Y轴旋转
	sk3DView.getMatrix(&matrix);

	matrix.preTranslate(-(rtImg.fLeft+rtImg.width()/2), 0);
	matrix.postTranslate((rtImg.fLeft+rtImg.width()/2), 0);

	matrix.mapRect(&g_rtClip,rtImg); //两个参数都是SkRect类型
	//matrix.mapRect 作用:src经过matrix变化,形成dst
	//图片的最初范围经过matrix变化(每次绕Y轴旋转角度不一样),得出新的裁剪范围

	rtClip.join(g_rtClip);				//计算最终裁剪范围
	g_rtClip = rtClip ;					//保存裁剪范围,供下次计算最终裁剪范围

	//DrawBKImage();//此处画背景,不然会保留不同ratateY角度图片的痕迹  ,放在此处 画背景用时多 ,为4或者3,
	pskCanvas->save();
	pskCanvas->clipRect(rtClip);//矩阵裁剪

	DrawBKImage();//此处画背景,不然会保留不同ratateY角度图片的痕迹    放在此处 画背景用时小 ,为0或者1,
	//具体画的内容,与pskCanvas画布的裁剪有关系?

	//pskCanvas->save(SkCanvas::kMatrix_SaveFlag); 可以去掉,之前已经有pskCanvas->save();
	pskCanvas->concat(matrix);	

	DrawImage(filename,pskCanvas,rtImg,NULL);
	//此处的位置参数须是图片原始位置,不能是裁剪范围,否则显示的位置偏离

	//pskCanvas->restore();     与save对应
	pskCanvas->restore();
	//pskCanvas->resetMatrix();
}

//触发图片旋转函数
void MyLButtonDown()
{
	g_rtClip = g_rtImg; //初始裁剪范围为要画图片的正常范围。
	for (int i =0;i<=10;i++)
	{
		DrawRotateYImage("\\user\\skia\\music-n.png",36*(i+0),g_rtImg);
		HDC dc = GetDC(g_hWnd);
		SetDIBitsToDevice(dc, 0, 0, 800, 480, 0, 0, 0, 800, pskBitmap->getPixels(), lpbmi, DIB_RGB_COLORS);
		//将数据显示到屏幕上
		ReleaseDC(g_hWnd,dc);
	}
}

  

附图:

正常图效果

旋转45°效果

旋转180°效果

2011-11-18、11:01:59 补充

DrawRotateYImage()函数中:

//--------------------------------------------------------------------1
	pskCanvas->save();
//--------------------------------------------------------------------2
	pskCanvas->clipRect(rtClip);//矩阵裁剪
//--------------------------------------------------------------------3
	DrawBKImage();//此处画背景,不然会保留不同ratateY角度图片的痕迹    放在此处 画背景用时小 ,为0或者1,
	pskCanvas->concat(matrix);	
//--------------------------------------------------------------------4

	DrawImage(filename,pskCanvas,rtImg,NULL);
	pskCanvas->restore();
//--------------------------------------------------------------------5

  设置5个位置

将代码

SkRect rt = rtImg;
rt.fLeft +=150;
DrawImage(filename,pskCanvas,rt,NULL);

  分别填到5个不同的位置。

总结:

   在位置1,也就是pskCanvas->save之前,所有的画图是有效的。

     在位置2,也就是cave之后,但是没有任何特殊的设置前,所有的画图是有效的。

     在位置3,也就是clipRect之后,concat之前,所有的绘画,只在clipRect的矩形中有作用,其他范围绘画会被裁减

     在位置4,也就是concat之后,restore之前,绘画的内容,会按照matrix旋转。如果经过matrix重置之后,如果还在之前clipRect的范围里,会显示。

        此时是clipRect仍有效,但是是相对于经过matrix变化之后的图像

   在位置5,也就是restore之后,所有绘画会正常显示。(复位到最近保存的设置,就是clipRect、concat等设置之前)

ezhong的博客园:http://www.cnblogs.com/ezhong/

原文地址:https://www.cnblogs.com/ezhong/p/2252780.html