Windows Mobile上实现图片任意角度旋转

作者:金海建

 

目的:在Windows Mobile上,微软的API和库不支持图片的任意角度旋转,只支持90,180,270度旋转。既然它不支持我们只能自力更生了。

简介:通过介绍和实现旋转PNG图片,来说明实现图片旋转的方法。过程大概如下,先用Imaging读取并解码png图片,使之转成ARGB格式的位图。然后利用顶点旋转的公式,对位图矩阵进行旋转,旋转完成后,利用Imaging库,转换成IImage接口。最后利用IImage接口来画图。

 

    先来看下平面直角坐标变换的旋转坐标变换,其定义是

定义:若二坐标系{Oij}{O′;i′,j}满足OO′,另∠(ij′)=θ

        则坐标系{O′;i′,j}可看成是由坐标系{Oij}O旋转θ角得到的,称由{Oij}{O′;i′,j}的变换为旋转坐标变换

旋转公式为:

X' =  X cosθ -  Y sinθ

Y' =  X sinθ  + Y cosθ

由于我们是用数组的下表来表示坐标的,所以最小的坐标是为(0,0)。我们需要先做坐标旋转,然后平移坐标。如下图所示:

Windows Mobile上实现图片任意角度旋转_WinCE

 

平移的动作,是把所以的负坐标变成正坐标。用MinXMinY来表示最小的X坐标和Y坐标。

X' =  X cosθ -  Y sinθ - MinX;

Y' =  X sinθ  + Y cosθ - MinY;

根据上面的公式我们推出

x = (x'+MinX)cosθ+ (y'+MinY)sinθ

y = (y'+MinY)conθ- (x'+MinX)sinθ

 

图片旋转后,会出现失真现象,需要用双线性内插值进行优化

 

双线性内插值:对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v),其中ij均为非负整数,uv[0,1)区间的浮点数,则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)(i+1,j)(i,j+1)(i+1,j+1)所对应的周围四个像素的值决定,即:

 f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)

其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。

这就是双线性内插值法。双线性内插值法计算量大,但缩放后图像质量高,不会出现像素值不连续的的情况。由于双线性插值具有低通滤波器的性质,使高频分量受损,所以可能会使图像轮廓在一定程度上变得模糊。

 

 

 

旋转代码

 

  1. void RotateImageBuf(const BYTE* src, int srcWidth, int srcHeight, BYTE*& dst, int& dstWidth, int& dstHeight, double angle)     
  2. {    
  3.     double cosA = cos(angle);  
  4.     double sinA = sin(angle);  
  5.   
  6.   
  7.     double x1 = srcWidth * cosA;  
  8.     double y1 = srcWidth * sinA;  
  9.     double x2 = srcWidth * cosA - srcHeight * sinA;  
  10.     double y2 = srcWidth * sinA + srcHeight * cosA;  
  11.     double x3 = - srcHeight * sinA;  
  12.     double y3 = srcHeight * cosA;  
  13.   
  14.     double minWidth = min(0,min(x3,min(x1,x2)));  
  15.     double minHeight = min(0,min(y3,min(y1,y2)));  
  16.   
  17.     double maxWidth = max(0,max(x3,max(x1,x2)));  
  18.     double maxHeight = max(0,max(y3,max(y1,y2)));  
  19.   
  20.     dstWidth = abs(maxWidth - minWidth) + 1;  
  21.     dstHeight = abs(maxHeight - minHeight) + 1;   
  22.   
  23.     double ndstX = 0;  
  24.     double ndstY = 0;  
  25.   
  26.     dst = new BYTE[dstWidth * dstHeight * 4];  
  27.   
  28.     UINT32  *pDst = (UINT32 *)dst;  
  29.     UINT32  *pSrc = (UINT32 *)src;  
  30.     UINT32   crDefault = ((UINT32 *)src)[0];  
  31.   
  32.     UINT32 color [2][2];  
  33.     BYTE alpha[2][2];  
  34.     BYTE rColor[2][2];  
  35.     BYTE gColor[2][2];  
  36.     BYTE bColor[2][2];  
  37.   
  38.     BYTE afinal,rfinal,gfinal,bfinal;  
  39.     double ox,oy;  
  40.      
  41.     for(int y=0; y < dstHeight; y++)  
  42.     {  
  43.         for(int x=0; x < dstWidth; x++)  
  44.         {  
  45.             ndstX = (x + minWidth) * cosA + (y + minHeight) * sinA;  
  46.             ndstY = (y + minHeight) * cosA - (x +minWidth) * sinA;  
  47.             if((ndstX >= 0) && (ndstX < srcWidth) && (ndstY >= 0) && (ndstY < srcHeight))  
  48.             {  
  49.   
  50.                 color[0][0] = pSrc[ (int)((int)ndstY*srcWidth + ndstX) ];      
  51.                 if((int)ndstX + 1 >= srcWidth)  
  52.                     color[1][0] = crDefault;  
  53.                 else  
  54.                     color[1][0] = pSrc[ (int)((int)ndstY*srcWidth + ndstX +1) ];      
  55.   
  56.                 if((int)ndstY + 1 >= srcHeight)  
  57.                     color[0][1] = crDefault;  
  58.                 else  
  59.                     color[0][1] = pSrc[ (int)(((int)ndstY+1)*srcWidth + ndstX) ];      
  60.   
  61.                 if((int)ndstY + 1 >= srcHeight || (int)ndstX + 1 >= srcWidth)  
  62.                     color[1][1] = crDefault;  
  63.                 else  
  64.                     color[1][1] = pSrc[ (int)(((int)ndstY+1)*srcWidth + ndstX+1) ];     
  65.   
  66.   
  67.                 alpha[0][0]  = (color[0][0] & 0XFF000000) >> 24;  
  68.                 bColor[0][0] = (color[0][0] & 0XFF0000) >> 16;  
  69.                 gColor[0][0] = (color[0][0] & 0X00FF00) >> 8;  
  70.                 rColor[0][0] = color[0][0] & 0X0000FF;  
  71.   
  72.                 alpha[1][0]  = (color[1][0] & 0XFF000000) >> 24;  
  73.                 bColor[1][0] = (color[1][0] & 0XFF0000) >> 16;  
  74.                 gColor[1][0] = (color[1][0] & 0X00FF00) >> 8;  
  75.                 rColor[1][0] = color[1][0] & 0X0000FF;  
  76.   
  77.                 alpha[0][1]  = (color[0][1] & 0XFF000000) >> 24;  
  78.                 bColor[0][1] = (color[0][1] & 0XFF0000) >> 16;  
  79.                 gColor[0][1] = (color[0][1] & 0X00FF00) >> 8;  
  80.                 rColor[0][1] = color[0][1] & 0X0000FF;  
  81.   
  82.                 alpha[1][1]  = (color[1][1] & 0XFF000000) >> 24;  
  83.                 bColor[1][1] = (color[1][1] & 0XFF0000) >> 16;  
  84.                 gColor[1][1] = (color[1][1] & 0X00FF00) >> 8;  
  85.                 rColor[1][1] = color[1][1] & 0X0000FF;  
  86.   
  87.                 //f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)  
  88.                 ox = (ndstX - (int)ndstX);     
  89.                 oy = (ndstY - (int)ndstY);  
  90.                 rfinal = (1 - ox)*(1 - oy)*rColor[0][0] + ox*(1 - oy)*rColor[1][0] + (1-ox)*oy*rColor[0][1] + ox*oy*rColor[1][1];     
  91.                 gfinal = (1 - ox)*(1 - oy)*gColor[0][0] + ox*(1 - oy)*gColor[1][0] + (1-ox)*oy*gColor[0][1] + ox*oy*gColor[1][1];   
  92.                 bfinal = (1 - ox)*(1 - oy)*bColor[0][0] + ox*(1 - oy)*bColor[1][0] + (1-ox)*oy*bColor[0][1] + ox*oy*bColor[1][1];   
  93.                 afinal = (1 - ox)*(1 - oy)*alpha[0][0] + ox*(1 - oy)*alpha[1][0] + (1-ox)*oy*alpha[0][1] + ox*oy*alpha[1][1];   
  94.                   
  95.                 pDst[y * (int)dstWidth + x] = RGBA(rfinal,gfinal,bfinal,afinal);  
  96.             }  
  97.             else  
  98.             {  
  99.                 pDst[y * (int)dstWidth + x] = crDefault;  
  100.             }  
  101.         }  
  102.     }  
  103. }  

 

 

需要对浮点型运算,改为整形预算。在模拟上测试过,旋转一张图片,整形预算要比浮点型预算快20倍。

改为整形运算代码。

 

  1. void RotateImageZhenxingBuf(const BYTE* src, int srcWidth, int srcHeight, BYTE*& dst, int& dstWidth, int& dstHeight, double angle)     
  2. {    
  3.     double cosA = cos(angle);  
  4.     double sinA = sin(angle);  
  5.   
  6.   
  7.     double x1 = srcWidth * cosA;  
  8.     double y1 = srcWidth * sinA;  
  9.     double x2 = srcWidth * cosA - srcHeight * sinA;  
  10.     double y2 = srcWidth * sinA + srcHeight * cosA;  
  11.     double x3 = - srcHeight * sinA;  
  12.     double y3 = srcHeight * cosA;  
  13.   
  14.     double minWidthD = min(0,min(x3,min(x1,x2)));  
  15.     double minHeightD = min(0,min(y3,min(y1,y2)));  
  16.   
  17.     double maxWidthD = max(0,max(x3,max(x1,x2)));  
  18.     double maxHeightD = max(0,max(y3,max(y1,y2)));  
  19.   
  20.     dstWidth = abs(minWidthD - maxWidthD) + 1;  
  21.     dstHeight = abs(maxHeightD - minHeightD) + 1;   
  22.   
  23.     int minWidth= minWidthD;  
  24.     int minHeight=  minHeightD;  
  25.   
  26.     int maxWidth =  maxWidthD;  
  27.     int maxHeight =  maxHeightD;  
  28.     int ndstX = 0;  
  29.     int ndstY = 0;  
  30.   
  31.     dst = new BYTE[dstWidth * dstHeight * 4];  
  32.   
  33.     UINT32  *pDst = (UINT32 *)dst;  
  34.     UINT32  *pSrc = (UINT32 *)src;  
  35.     UINT32   crDefault = ((UINT32 *)src)[0];  
  36.   
  37.     UINT32 color [2][2];  
  38.     BYTE alpha[2][2];  
  39.     BYTE rColor[2][2];  
  40.     BYTE gColor[2][2];  
  41.     BYTE bColor[2][2];  
  42.   
  43.     int afinal,rfinal,gfinal,bfinal;  
  44.       
  45.     long icosA = cosA * 256 * 256;  
  46.     long isinA = sinA * 256 * 256;  
  47.   
  48.     int x;     
  49.     int y;     
  50.     int kx;     
  51.     int ky;  
  52.     for(int j=0; j < dstHeight; j++)  
  53.     {  
  54.         for(int i=0; i < dstWidth; i++)  
  55.         {  
  56.             ndstX = (i + minWidth) * icosA + (j + minHeight) * isinA;  
  57.             ndstY = (j + minHeight) * icosA - (i +minWidth) * isinA;  
  58.             ndstX = ndstX >> 8;  
  59.             ndstY = ndstY >> 8;  
  60.             if ( (ndstX >> 8) < srcWidth && (ndstX >> 8) >=0 && (ndstY >> 8) < srcHeight && (ndstY >> 8) >= 0)     
  61.             {    
  62.   
  63.                 kx = ndstX >> 8;     
  64.                 ky = ndstY >> 8;     
  65.                 x = ndstX & 0xFF;     
  66.                 y = ndstY & 0xFF;     
  67.   
  68.                 color[0][0] = pSrc[ ky*srcWidth + kx ];   
  69.                 if(kx + 1 >= srcWidth)  
  70.                     color[1][0] = crDefault;  
  71.                 else  
  72.                     color[1][0] = pSrc[ ky*srcWidth + kx +1 ];  
  73.   
  74.                 if(ky + 1 >= srcHeight)  
  75.                     color[0][1] = crDefault;  
  76.                 else  
  77.                     color[0][1] = pSrc[ (ky+1)*srcWidth + kx ];   
  78.   
  79.                 if(ky + 1 >= srcHeight || kx + 1 >= srcWidth)  
  80.                     color[1][1] = crDefault;  
  81.                 else  
  82.                     color[1][1] = pSrc[ (ky+1)*srcWidth + kx+1 ];    
  83.   
  84.                 alpha[0][0]  = (color[0][0] & 0XFF000000) >> 24;  
  85.                 bColor[0][0] = (color[0][0] & 0XFF0000) >> 16;  
  86.                 gColor[0][0] = (color[0][0] & 0X00FF00) >> 8;  
  87.                 rColor[0][0] = color[0][0] & 0XFF;  
  88.   
  89.                 alpha[1][0]  = (color[1][0] & 0XFF000000) >> 24;  
  90.                 bColor[1][0] = (color[1][0] & 0XFF0000) >> 16;  
  91.                 gColor[1][0] = (color[1][0] & 0X00FF00) >> 8;  
  92.                 rColor[1][0] = color[1][0] & 0XFF;  
  93.   
  94.                 alpha[0][1]  = (color[0][1] & 0XFF000000) >> 24;  
  95.                 bColor[0][1] = (color[0][1] & 0XFF0000) >> 16;  
  96.                 gColor[0][1] = (color[0][1] & 0X00FF00) >> 8;  
  97.                 rColor[0][1] = color[0][1] & 0XFF;  
  98.   
  99.                 alpha[1][1]  = (color[1][1] & 0XFF000000) >> 24;  
  100.                 bColor[1][1] = (color[1][1] & 0XFF0000) >> 16;  
  101.                 gColor[1][1] = (color[1][1] & 0X00FF00) >> 8;  
  102.                 rColor[1][1] = color[1][1] & 0XFF;  
  103.   
  104.                 afinal = (0x100 - x)*(0x100 - y)*alpha[0][0] + x*(0x100 - y)*alpha[1][0] + (0x100-x)*y*alpha[0][1] + x*y*alpha[1][1];     
  105.                 rfinal = (0x100 - x)*(0x100 - y)*rColor[0][0] + x*(0x100 - y)*rColor[1][0] + (0x100-x)*y*rColor[0][1] + x*y*rColor[1][1];     
  106.                 gfinal = (0x100 - x)*(0x100 - y)*gColor[0][0] + x*(0x100 - y)*gColor[1][0] + (0x100-x)*y*gColor[0][1] + x*y*gColor[1][1];     
  107.                 bfinal = (0x100 - x)*(0x100 - y)*bColor[0][0] + x*(0x100 - y)*bColor[1][0] + (0x100-x)*y*bColor[0][1] + x*y*bColor[1][1];     
  108.   
  109.                 afinal = afinal >> 16;     
  110.                 if (afinal>255)     
  111.                     afinal = 255;     
  112.                 if (afinal<0)     
  113.                     afinal = 0;     
  114.   
  115.                 rfinal = rfinal >> 16;     
  116.                 if (rfinal>255)     
  117.                     rfinal = 255;     
  118.                 if (rfinal<0)     
  119.                     rfinal = 0;    
  120.   
  121.                 gfinal = gfinal >> 16;     
  122.                 if (gfinal>255)     
  123.                     gfinal = 255;     
  124.                 if (gfinal<0)     
  125.                     gfinal = 0;    
  126.   
  127.                 bfinal = bfinal >> 16;     
  128.                 if (bfinal>255)     
  129.                     bfinal = 255;     
  130.                 if (bfinal<0)     
  131.                     bfinal = 0;    
  132.                 pDst[j * dstWidth + i] = RGBA(rfinal,gfinal,bfinal,afinal);  
  133.             }  
  134.             else  
  135.             {  
  136.                 pDst[j * dstWidth + i] = crDefault;  
  137.             }  
  138.         }  
  139.     }  
  140. }  

 

 

用Imaging接口加载png图片,并调用RotateImageBuf进行旋转,最后返回IImage接口。

 

  1. // need to delete pImagebuf;  
  2. HRESULT RotateImage(IImagingFactory *pImgFactory, IImage *pImage, IImage * &pImageOut, LPBYTE &pImageBuf, double angle)  
  3. {  
  4.     HRESULT hr = S_OK;  
  5.   
  6.     IBitmapImage *pIBitmap = NULL;  
  7.     ImageInfo ImInfo;  
  8.     pImage->GetImageInfo(&ImInfo);  
  9.   
  10.     if((ImInfo.PixelFormat & 0xFF00)>>8 != 32)  
  11.     {  
  12.         hr = S_FALSE;  
  13.         goto Error;  
  14.     }  
  15.     if(S_OK != pImgFactory->CreateBitmapFromImage(  
  16.         pImage, ImInfo.Width, ImInfo.Height, ImInfo.PixelFormat, InterpolationHintDefault, &pIBitmap))  
  17.     {  
  18.         hr = S_FALSE;  
  19.         goto Error;  
  20.     }  
  21.       
  22.     RECT rcLocked ={0,0,ImInfo.Width,ImInfo.Height};  
  23.     BitmapData bmpData;  
  24.   
  25.     if(S_OK != pIBitmap->LockBits(&rcLocked, ImageLockModeRead | ImageLockModeWrite, ImInfo.PixelFormat, &bmpData))  
  26.     {  
  27.         hr = S_FALSE;  
  28.         goto Error;  
  29.     }  
  30.   
  31.     BYTE *pDst = NULL;  
  32.     int nDstWidth=0,nDstHeight=0;  
  33.     RotateImageZhenxingBuf((BYTE *)bmpData.Scan0, ImInfo.Width, ImInfo.Height, pDst, nDstWidth, nDstHeight, angle);  
  34.       
  35.     pIBitmap->UnlockBits(&bmpData);  
  36.   
  37.     BitmapData bmpDataNew;  
  38.     bmpDataNew.Height = nDstHeight;  
  39.     bmpDataNew.Width = nDstWidth;  
  40.     bmpDataNew.PixelFormat = ImInfo.PixelFormat;  
  41.     bmpDataNew.Stride = nDstWidth * 4;  
  42.     bmpDataNew.Reserved = 0;  
  43.     bmpDataNew.Scan0 = (void *)pDst;  
  44.   
  45.     IBitmapImage *pBmpImageNew = NULL;  
  46.     hr = pImgFactory->CreateBitmapFromBuffer(&bmpDataNew, &pBmpImageNew);  
  47.   
  48.     IImage * pImageNew = NULL;  
  49.     pBmpImageNew->QueryInterface(IID_IImage, (void **)&pImageNew);  
  50.       
  51.     pImageOut = pImageNew;  
  52.     pImageBuf = pDst;  
  53. Error:  
  54.       
  55.     if(pBmpImageNew)  
  56.         pBmpImageNew->Release();  
  57.   
  58.     if(pIBitmap)  
  59.         pIBitmap->Release();  
  60.     return hr;  
  61. }