How to rotate a bitmap

C++Builder Logo
How to rotate a bitmapComment faire tourner un bitmap d'un certain angle

1. Rotating a bitmap with an angle of  90°Faire tourner un bitmap d'un angle de 90°
We are using the Pixels property of a canvas to do the job. This is really straight forward.  
With a rotation angle of 90°, the Width of the destination bitmap becomes the Height of the source and the Height of the destination bitmap, becomes the Width of the source. Once these properties are set, we rotate each pixel one at a time. 
This is easy but terribly slow for large bitmap. 
Pour effectuer une rotation de 180°, on utilise la propriété Pixels d'un canevas. Cette méthode est très simple mais très lente avec des bitmaps de taille importante. 
Dans une rotation de 90°, la propriété Width du bitmap de destination est égale à la propriété Height du bitmap source et vice versa. Lorsqu'on a défini ces deux propriétés du bitmap de destination, tout ce qui reste à faire est d'effectuer la rotation un pixel à la fois.

//Open the source and create the destination bitmap 
Graphics::TBitmap *SrcBitmap=new Graphics::TBitmap; 
Graphics::TBitmap *DestBitmap=new Graphics::TBitmap; 
SrcBitmap->LoadFromFile("YourBitmap.bmp");
 
//rotate by 90° 

DestBitmap->Width=SrcBitmap->Height; 
DestBitmap->Height=SrcBitmap->Width; 

//Rotate one pixel at a time 
for (int x=0;x<SrcBitmap->Width;x++) 

  for(int y=0;y<SrcBitmap->Height;y++) 
  { 
    DestBitmap->Canvas->Pixels[y][SrcBitmap->Width-1-x]= 
       SrcBitmap->Canvas->Pixels[x][y]; 
  } 


//Assign the Destination bitmap to a TImage 
Image1->Picture->Bitmap=DestBitmap; 
delete DestBitmap; 
delete SrcBitmap;


2. Rotating a bitmap with an angle of  180°Faire tourner un bitmap d'un angle de 180°
The method is the same as the one used to rotate a bitmap with an angle of 90°. The only difference is that the width and Height of the destination bitamp are the same as the source bitmap. La méthode est la même que pour une rotation de 90°. La seule différence est que les propriétés Width et Height du bitmap de destination sont égales à celles du bitmap source.

//Open the source and create the destination bitmap 
Graphics::TBitmap *SrcBitmap=new Graphics::TBitmap; 
Graphics::TBitmap *DestBitmap=new Graphics::TBitmap; 
SrcBitmap->LoadFromFile("YourBitmap.bmp"); 
//rotate by 180° 
DestBitmap->Width=SrcBitmap->Width; 
DestBitmap->Height=SrcBitmap->Height; 

//Rotate one pixel at a time 
for (int x=0;x<SrcBitmap->Width;x++) 

  for(int y=0;y<SrcBitmap->Height;y++) 
  { 
    DestBitmap->Canvas->Pixels[x][SrcBitmap->Height-1-y]= 
      SrcBitmap->Canvas->Pixels[x][y]; 
  } 


//Assign the Destination bitmap to a TImage 
Image1->Picture->Bitmap=DestBitmap; 
delete DestBitmap; 
delete SrcBitmap;


3. Rotating a bitmap with an angle of  any valueFaire tourner un bitmap d'un angle quelconque
The method is more complex. We need some trigonometrical knowledges to do the job. 
Take a look at the figure shown below : 
The points 0 to 3 are the coordinates of the source bitmap and the points 0' to 3' are the coordinates of the rotated bitmap. Point 0 is the origin (0,0) of the source bitmap. The point 1 is the point (0,bitmap->Width) , the point 2 is the point (bitmap->Height,0) and the point 3 is the point (bitmap->Width,bitmap->Height). In this example, the rotation angle is equal to 45° so the coordinates become points 0' to 3' and the bounding rectangle of the rotated bitmap is quite larger than the source bitmap.
Faire tourner un bitmap d'un angle quelconque est plus compliqué. Il faudra utiliser quelques formules trigonométriques pour y arriver. Examinons la figure ci dessous : 
Les points 0 à 3 représentent les coordonnées du bitmap source. Le point 0 correspond à l'origine (0,0). Le point 1 correspond au point de coordonnées (0, bitmap->Width), le point 2 au point de coordonnées (bitmap->Height,0) et le point 3 au point de coordonnées (bitmap->Width,bitamp->Height). On remarquera que la taille du rectangle dans lequel le bitmap est inscrit après rotation est plus grande que la taille du bitmap source.

rotbmp

To find the width and height of the bounding rectangle which correspond to the width and height of the destination bitmap, whe have to use the following formulas :La taille du bitmap de destination correspond a la taille du rectangle dans lequel le bitmap, après rotation, est inscrit. Pour trouver cette taille, on utilise les formules suivantes :
newx=x*cos(angle)+y*sin(angle) 
newy=y*cos(angle)-x*sin(angle)
 
The math functions in C++ expect a value in radians so we have to convert degrees to radians with the formula :Les fonctions sin et cos nécessitent que l'angle soit exprimer en radians. On utilisera donc la formule suivante pour effectuer la conversion degré / radian:
radian=(2*pi*degree)/360
 
For each point 0 to 3, we calculate the coordinates of the new points 0' to 3'. The width of the bounding rectangle is equal to the maximum value of x  (for the points 0' to 3') minus the minimum value of x. The height is equal to the maximum value of y minus the minimum value of y. 

For example, if the bitmap has a width of 100 pixels, a height of 226 pixels and if we want to perform a rotation of 45° :

Pour chaque point 0 à 3, on calcule les nouveaux points 0' à 3'. La propriété Width du bitmap de destination est alors égale à la valeur maximale de x moins la valeur minimale de x. De même, la propriété Height est égale à la valeur maximale de y moins la valeur minimale de y.

Prenons un exemple. Soit un bitmap source de dimansion 100 * 226 et un angle de rotation de 45°:

point 0 (0,0) --> point 0' (0,0) 
point 1 (100,0) --> point 1' (70.7,70.7) 
point 2 (0,226) --> point 2' (159.7,159.7) 
point 3 (100,226) --> point 3' (230.4,89)

The width of the destination bitmap (= bounding rectangle) is equal to 230 (230.4 - 0) (rounded). The height : 230 (159.7 - -70.7).La taille du bitmap de destination est alors égale à 230 * 230(230.4 - 0)et (159.7 - -70.7) après arrondi.

int angle=45;        //45° for example 
Graphics::TBitmap *SrcBitmap=new Graphics::TBitmap; 
Graphics::TBitmap *DestBitmap=new Graphics::TBitmap; 
SrcBitmap->LoadFromFile("Crayon.bmp"); 
//Convert degrees to radians 
float radians=(2*3.1416*angle)/360; 

float cosine=(float)cos(radians); 
float sine=(float)sin(radians); 

float Point1x=(-SrcBitmap->Height*sine); 
float Point1y=(SrcBitmap->Height*cosine); 
float Point2x=(SrcBitmap->Width*cosine-SrcBitmap->Height*sine); 
float Point2y=(SrcBitmap->Height*cosine+SrcBitmap->Width*sine); 
float Point3x=(SrcBitmap->Width*cosine); 
float Point3y=(SrcBitmap->Width*sine); 

float minx=min(0,min(Point1x,min(Point2x,Point3x))); 
float miny=min(0,min(Point1y,min(Point2y,Point3y))); 
float maxx=max(Point1x,max(Point2x,Point3x)); 
float maxy=max(Point1y,max(Point2y,Point3y)); 

int DestBitmapWidth=(int)ceil(fabs(maxx)-minx); 
int DestBitmapHeight=(int)ceil(fabs(maxy)-miny); 

DestBitmap->Height=DestBitmapHeight; 
DestBitmap->Width=DestBitmapWidth;


Now, the easy part, we take each pixel in the destination bitmap and get its value in the source bitmap using the same formulas. You would expect to get the value in the source bitmap and then to copy it to the destination bitmap but doing this, it leaves holes in the destination bitmap. It's because each point in the source bitmap doesn't have an equivalent in the destination bitmap.Maintenant, la partie la plus facile. On prend chaque pixel dans le bitmap de destination et on calcule à l'aide des même formules à quelle valeur correspond le pixel dans le bitmap source. Cette fçon de procéder évite les trous qui apparaissent dans le bitmap destination si on fait l'inverse : prendre chaque pixel dans la bitmap source et le copier dans le bitmap destination. Ces trous sont dû au fait que chaque pixel dans le source n'a pas nécessairement d'équivalent dans le bitmap de destination.

for(int x=0;x<DestBitmapWidth;x++) 

  for(int y=0;y<DestBitmapHeight;y++) 
  { 
    int SrcBitmapx=(int)((x+minx)*cosine+(y+miny)*sine); 
    int SrcBitmapy=(int)((y+miny)*cosine-(x+minx)*sine); 
    if(SrcBitmapx>=0&&SrcBitmapx<SrcBitmap->Width&&SrcBitmapy>=0&& 
         SrcBitmapy<SrcBitmap->Height) 
    { 
      DestBitmap->Canvas->Pixels[x][y]= 
          SrcBitmap->Canvas->Pixels[SrcBitmapx][SrcBitmapy]; 
    } 
  } 

//Show the rotated bitmap 
Image1->Picture->Bitmap=DestBitmap; 
delete DestBitmap; 
delete SrcBitmap;


Note : The min() and max() found in the code above are defines found in the windows API. If you don't want to include windows.h in your project, just redefine these macros yourself :Note : Les fonctions min() et max() utilisées dans le code ci-dessus sont en fait des macros définies dans l'API Windows. Si vous ne désirez pas inclure windows.h dans votre projet, vous pouvez redéfinir ces macros vous même :

#define min(a, b)  (((a) < (b)) ? (a) : (b)) 
#define max(a, b)  (((a) > (b)) ? (a) : (b))


4. Rotating using NT functionsRotation en utilisant les fonctions NT
There are some functions only available under Windows NT. They are really fast even with large bitmaps. The code uses the function SetWorldTransform(), the BitBlt() function and the XFORM structure.SetWorldTransform() is NOT available under windows 95/98. 
You have to compute the Width and Height of the destination bitmap as shown at point 3. and then add the code below.
Sous NT, il existe une fonction SetWorldTransform(), en combinaison avec BitBlt() et la structure XFORM, qui permet d'effectuer une rotation de façon rapide même avec des bitmaps de grande taille. La fonction SetWorldTransform n'est PAS disponible sous windows 95/98. 
Vous devez calculez d'abord la taille du bitmap de destination comme indiqué plus haut (point 3.) et ajouter le code ci-dessous :

SetGraphicsMode(DestBitmap->Canvas->Handle,GM_ADVANCED); 
XFORM xform; 
xform.eM11=cosine; 
xform.eM12=-sine; 
xform.eM21=sine; 
xform.eM22=cosine; 
xform.eDx=(float)-minx; 
xform.eDy=(float)-miny; 

SetWorldTransform(DestBitmap->Canvas->Handle,&xform); 

BitBlt(DestBitmap->Canvas->Handle, 
       0, 
       0, 
       DestBitmap->Width, 
       DestBitmap->Height, 
       SrcBitmap->Canvas->Handle, 
       0, 
       0, 
       SRCCOPY); 

//Show the rotated bitmap 
Image1->Picture->Bitmap=DestBitmap; 
delete DestBitmap; 
delete SrcBitmap;


5. Rotating bitmaps using DIBsRotation en convertissant les bitmaps en DIBs
To rotate bitmap faster, you can convert your bitmap to a device independent bitmap (DIB), create a destination DIB to hold the rotated bitmap and then, convert the destination DIB to a device dependent bitmap.
Using this technique is, on my computer, seven times faster than using the Pixel property of a bitmap.
A part la méthode utilisée pour NT, les autres méthodes de rotation sont lentes. Pour améliorer la vitesse de rotation, on peut envisager de convertir le bitmap source en un device independent bitmap (DIB), créer un DIB destiné à contenir le bitmap après rotation et ensuite convertir ce DIB en bitmap que l'on peut afficher facilement. 
Sur mon PC, cette technique est sept fois plus rapide que lorsqu'on utilise la propriété Pixel du bitmap.

//Source Bitmap 
Graphics::TBitmap *SrcBitmap=new Graphics::TBitmap; 
//Destination bitmap 
Graphics::TBitmap *DestBitmap=new Graphics::TBitmap; 
SrcBitmap->LoadFromFile("YourBitmap.bmp"); 
DestBitmap->PixelFormat=SrcBitmap->PixelFormat; 
int angle=45;        //45° for example 
//Convert degrees to radians 
float radians=(2*3.1416*angle)/360; 

float cosine=(float)cos(radians); 
float sine=(float)sin(radians); 

float Point1x=(-SrcBitmap->Height*sine); 
float Point1y=(SrcBitmap->Height*cosine); 
float Point2x=(SrcBitmap->Width*cosine-SrcBitmap->Height*sine); 
float Point2y=(SrcBitmap->Height*cosine+SrcBitmap->Width*sine); 
float Point3x=(SrcBitmap->Width*cosine); 
float Point3y=(SrcBitmap->Width*sine); 

float minx=min(0,min(Point1x,min(Point2x,Point3x))); 
float miny=min(0,min(Point1y,min(Point2y,Point3y))); 
float maxx=max(0,max(Point1x,max(Point2x,Point3x))); 
float maxy=max(0,max(Point1y,max(Point2y,Point3y))); 

int DestBitmapWidth=(int)ceil(maxx-minx); 
int DestBitmapHeight=(int)ceil(maxy-miny); 

DestBitmap->Height=DestBitmapHeight; 
DestBitmap->Width=DestBitmapWidth; 

//create DIB for SrcBitmap 

LPBITMAPINFO srcBmpi=(LPBITMAPINFO)new char[sizeof(BITMAPINFO)]; 
ZeroMemory(srcBmpi,sizeof(BITMAPINFO)); 
//init BitmapInfo struct 
srcBmpi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); 
srcBmpi->bmiHeader.biWidth=SrcBitmap->Width; 
srcBmpi->bmiHeader.biHeight=SrcBitmap->Height; 
srcBmpi->bmiHeader.biPlanes=1; 
srcBmpi->bmiHeader.biCompression=BI_RGB; 
switch(SrcBitmap->PixelFormat) 

  case pf24bit:   srcBmpi->bmiHeader.biBitCount=24;   break
  case pf32bit:   srcBmpi->bmiHeader.biBitCount=32;   break

//Each row is zero padded so that the number of bytes 
//per row is divisible by 4 
int SrcNumberOfBytesPerRow=
    ((((SrcBitmap->Width*srcBmpi->bmiHeader.biBitCount)+31)&~31)/8); 

//use screen DC for GetDIBits 
HDC ScreenDC=GetDC(NULL); 

//get image size 
GetDIBits(ScreenDC,SrcBitmap->Handle,0,srcBmpi->bmiHeader.biHeight, 
    NULL,srcBmpi,DIB_RGB_COLORS); 

//if the driver didn't give the size, calculate it yourselves 
if(srcBmpi->bmiHeader.biSizeImage==0) 

  srcBmpi->bmiHeader.biSizeImage= 
      SrcNumberOfBytesPerRow*SrcBitmap->Height; 


//Allocate memory for the bits 
char* srcbits=new char[srcBmpi->bmiHeader.biSizeImage]; 

//get the bits 
GetDIBits(ScreenDC,SrcBitmap->Handle,0,srcBmpi->bmiHeader.biHeight, 
    srcbits,srcBmpi,DIB_RGB_COLORS); 
  

//create DIB for DestBitmap 
LPBITMAPINFO destBmpi=(LPBITMAPINFO)new char[sizeof(BITMAPINFO)]; 
ZeroMemory(destBmpi,sizeof(BITMAPINFO)); 

//init BitmapInfo struct 
destBmpi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); 
destBmpi->bmiHeader.biWidth=DestBitmap->Width; 
destBmpi->bmiHeader.biHeight=DestBitmap->Height; 
destBmpi->bmiHeader.biPlanes=1; 
destBmpi->bmiHeader.biCompression=BI_RGB; 
destBmpi->bmiHeader.biBitCount=srcBmpi->bmiHeader.biBitCount; 
//Each row is zero padded so that the number of bytes 
//per row is divisible by 4 
int DestNumberOfBytesPerRow= 
    ((((DestBitmap->Width*destBmpi->bmiHeader.biBitCount)+31)&~31)/8); 

//get image size 
GetDIBits(ScreenDC,DestBitmap->Handle,0,destBmpi->bmiHeader.biHeight, 
    NULL,destBmpi,DIB_RGB_COLORS); 

//if the driver didn't give the size, calculate it ourselves 
if(destBmpi->bmiHeader.biSizeImage==0) 

  destBmpi->bmiHeader.biSizeImage= 
      DestNumberOfBytesPerRow*DestBitmap->Height; 


//Allocate memory for the bits 
char* destbits=new char[destBmpi->bmiHeader.biSizeImage]; 

//Set bits in destination buffer 
//Perform the rotation 
for(int y=0;y<DestBitmapHeight;y++) 

  for(int x=0;x<DestBitmapWidth;x++) 
  { 
    int SrcBitmapx=(int)((x+minx)*cosine+(y+miny)*sine); 
    int SrcBitmapy=(int)((y+miny)*cosine-(x+minx)*sine); 
    if(SrcBitmapx>=0&&SrcBitmapx<SrcBitmap->Width&&SrcBitmapy>=0&& 
        SrcBitmapy<SrcBitmap->Height) 
    { 
      for (int i=0;i<srcBmpi->bmiHeader.biBitCount/8;i++) 
      { 
        *(destbits+(DestNumberOfBytesPerRow*y)+ 
          (x*srcBmpi->bmiHeader.biBitCount/8+i))= 
            *(srcbits+(SrcNumberOfBytesPerRow*SrcBitmapy)+ 
              (SrcBitmapx*srcBmpi->bmiHeader.biBitCount/8+i)); 
      } 
    } 
  } 


//Set the bits in destination bitmap 
//Convert destination DIB to a bitmap 
SetDIBits(ScreenDC,DestBitmap->Handle,0, 
    destBmpi->bmiHeader.biHeight,destbits,destBmpi,DIB_RGB_COLORS); 
Image1->Picture->Bitmap=DestBitmap; 

delete DestBitmap; 
delete SrcBitmap; 
delete srcbits; 
delete destbits; 
delete destBmpi; 
delete srcBmpi; 


This sample is only usable with 24 or 32-bit bitmaps. Besides, I have only checked the code with 24-bit bitmaps because I don't have a 32-bit bitmap at hand.Cet exemple n'est utilisable tel quel qu'avec des bitmaps 24 ou 32-bit. De plus, je n'ai pas testé le code avec un bitmap 32-bit pour la simple raison que je n'en ai pas et que je n'ai pas de programme de dessin me permettant d'en créer un.
6. Rotating bitmaps using GDI+Utilisation de GDI+ pour effectuer une rotation
GDI+ is the new API from Microsoft intended to replace the old GDI. GDI+ is included in XP natively and can be used in 98/ME/NT/2K if the proper DLL is installed. 
It simplifies things greatly. 
The first sample below, performs a 90-degrees rotation and then a vertical flip. 
The second sample rotates the image by 45-degrees. 

Note: Read the article GDI+ and C++ Builder to know how to install, initialize and use GDI+.
GDI+ est la nouvelle API de Microsoft destinée à remplacer GDI. Elle fait déjà partie de XP et peut être utilisée avec 98/ME/NT/2k à condition d'installer la DLL adéquate. 
GDI+ simplifie énormément les choses dans le cas de rotations. 
Le premier exemple, ci dessous, effectue une rotation de 90° et un renversement vertical. 
Le second exemple réalise une rotation de 45°. 

Note: Lisez l'article GDI+ et C++ Builder pour apprendre comment installer, initialiser et utiliser GDI+.

  Gdiplus::Graphics graphics(hdc);
  Gdiplus::Image image(L"YourPicture.gif");
  
  //First sample
  //90° rotation and vertical flip
  graphics.DrawImage(&image, 10, 10, image.GetWidth(), image.GetHeight());
  image.RotateFlip(Gdiplus::Rotate90FlipY);
  graphics.DrawImage(&image, 200, 10);



  //Second sample
  //Rotate by arbitrary angle
  //Warning: the rotation is performed from the origin (0,0).
  //All the device context (window) is rotated, not only the image.
  //First draw not-rotated image
  graphics.DrawImage(&image,0,100);
  //make a translation to make it visible at the right of the first image
  graphics.TranslateTransform(260.0f,80.0f);
  //rotate
  graphics.RotateTransform(45.0f);
  //draw rotated image
  graphics.DrawImage(&image,0,0);

Acknowledgment
Some of the code samples given in this article are based on a Microsoft knowledge base document (Q77127) from the Win32sdk and on an article written by Zafir Anjum for www.codeguru.com.Certains des exemples donnés dans cet article sont librement inspirés d'un document Microsoft (Q77127) du Win32sdk et sur un article écrit par Zafir Anjum pour www.codeguru.com.
 

 

转载于:https://my.oschina.net/lyr/blog/53979

标题基于SpringBoot的马术俱乐部管理系统设计与实现AI更换标题第1章引言介绍马术俱乐部管理系统的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景与意义阐述马术俱乐部管理系统对提升俱乐部管理效率的重要性。1.2国内外研究现状分析国内外马术俱乐部管理系统的发展现状及存在的问题。1.3研究方法以及创新点概述本文采用的研究方法,包括SpringBoot框架的应用,以及系统的创新点。第2章相关理论总结和评述与马术俱乐部管理系统相关的现有理论。2.1SpringBoot框架理论介绍SpringBoot框架的基本原理、特点及其在Web开发中的应用。2.2数据库设计理论阐述数据库设计的基本原则、方法以及在管理系统中的应用。2.3马术俱乐部管理理论概述马术俱乐部管理的基本理论,包括会员管理、课程安排等。第3章系统设计详细描述马术俱乐部管理系统的设计方案,包括架构设计、功能模块设计等。3.1系统架构设计给出系统的整体架构,包括前端、后端和数据库的交互方式。3.2功能模块设计详细介绍系统的各个功能模块,如会员管理、课程管理、预约管理等。3.3数据库设计阐述数据库的设计方案,包括表结构、字段设计以及数据关系。第4章系统实现介绍马术俱乐部管理系统的实现过程,包括开发环境、编码实现等。4.1开发环境搭建介绍系统开发所需的环境,包括操作系统、开发工具等。4.2编码实现详细介绍系统各个功能模块的编码实现过程。4.3系统测试与调试阐述系统的测试方法、测试用例以及调试过程。第5章系统应用与分析呈现马术俱乐部管理系统的应用效果,并进行性能分析。5.1系统应用情况介绍系统在马术俱乐部中的实际应用情况。5.2系统性能分析从响应时间、并发处理能力等方面对系统性能进行分析。5.3用户反馈与改进收集用户反馈,提出系统改进建议。第6章结论与展望总结马术俱乐部管理系统的设计与实现成果,并展望未来的研究
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值