DelphiでGDI+を使って画像ファイルを回転させるサンプル


[参考元](http://blog.livedoor.jp/junki560/archives/23794296.html)

アルファチャンネル(透明色・半透明色)にも対応しています

```pascal
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  GDIPAPI, GDIPOBJ, Math, GDIPUTIL;


procedure RotateBMP(var bmp: TGPBitmap; angle: single);
  function GetRect(bmp: TGPBitmap): TGPRectF;
  var
    path: TGPGraphicsPath;
    mtrx: TGPMatrix;
  begin
    path := TGPGraphicsPath.Create;
    mtrx := TGPMatrix.Create;
    try
      path.AddRectangle(MakeRect(0, 0, bmp.GetWidth, bmp.GetHeight));
      mtrx.Rotate(angle); //ワールド座標を回転
      path.Transform(mtrx);
      path.GetBounds(Result); //ワールド座標をページ座標に変換
    finally
      mtrx.Free;
      path.Free;
    end;
  end;
var
  dst: TGPBitmap;
  gr: TGPGraphics;
  r: TGPRectF;
begin
  //回転後のページ座標のRectを取得する
  r := GetRect(bmp);

  //回転後のサイズでBitmapオブジェクトを作成(小数以下切上)
  dst := TGPBitmap.Create(Ceil(r.Width), Ceil(r.Height), PixelFormat32bppARGB);
  dst.SetResolution(96,96);  //標準のDPIに設定(PNGファイル対策)
  gr := TGPGraphics.Create(dst);
  try
    //画像がすべて収まるように中心点の座標(0,0)を移動する
    gr.TranslateTransform(-r.X, -r.Y);
    gr.RotateTransform(angle); //ワールド座標を回転
    gr.DrawImage(bmp,0,0);
  finally
    gr.Free;
  end;
  bmp.Free;
  bmp := dst;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  bmp: TGPBitmap;
  LImgGUID : TGUID;
begin
  bmp := TGPBitmap.Create('z:Sample.png');
  bmp.SetResolution(96,96); //標準のDPIに設定(PNGファイル対策)
  //図形を45°回転させる
  RotateBMP(bmp, 45);
  if GetEncoderClsid('image/png', LImgGUID) >= 0 then begin
    bmp.Save('z:Rotate.png', LImgGUID);
  end;
  bmp.Free;
end;
end.
```

<br>
以下の変更で、拡大率の変更も可能です

```pascal
gr.RotateTransform(angle: Single)
mtrx.Rotate(angle: Single)
↓ 
gr.ScaleTransform(scaleX, scaleY: Single)
mtrx.Scale(scaleX, scaleY: Single)
//例：mtrx.Scale(1.5,1.5) 1.5倍
//例：mtrx.Scale(1,-1) 上下反転
//例：mtrx.Scale(-1,1) 左右反転
```

<br>
2020.4.17 加筆
また、RotateBMP関数を以下の用に書き直せば、```gr.RotateTransform```は不要になります。

```pascal
procedure RotateBMP(var bmp: TGPBitmap; angle: single);
var
  mtrx: TGPMatrix;
  path: TGPGraphicsPath;
  dst : TGPBitmap;
  gr  : TGPGraphics;
  r   : TGPRectF;
begin
  mtrx := TGPMatrix.Create;
  try
    mtrx.Rotate(angle); //ワールド座標を回転
//    mtrx.Scale(1,-1);
    path := TGPGraphicsPath.Create;
    try
      //回転後のページ座標のRectを取得する
      path.AddRectangle(MakeRect(0, 0, bmp.GetWidth, bmp.GetHeight));
      path.Transform(mtrx);
      path.GetBounds(r); //ワールド座標をページ座標に変換
    finally
      path.Free;
    end;

    //回転後のサイズでBitmapオブジェクトを作成(小数以下切上)
    dst := TGPBitmap.Create(Ceil(r.Width), Ceil(r.Height), PixelFormat32bppARGB);
    dst.SetResolution(96,96);  //標準のDPIに設定(PNGファイルの対策)
    gr := TGPGraphics.Create(dst);
    try
      //画像がすべて収まるように中心点の座標(0,0)を移動する
      gr.TranslateTransform(-r.X, -r.Y);
      gr.MultiplyTransform(mtrx); //ページ座標をワールド座標に変換
      gr.DrawImage(bmp,0,0);
    finally
      gr.Free;
    end;
  finally
    mtrx.Free;
  end;
  bmp.Free;
  bmp := dst;
end;

```