Q&A

  • TImage안의 그림 회전 방법 ?
안녕하세요.
Imgae안의 그림을 회전하고 싶은데 방법이 있나요,
90동,180도,270도로요.

아시는분 부탁드립니다.

좋은하루 되시고 돈 많이 버세요.
2  COMMENTS
  • Profile
    보들레르 2002.01.19 23:27
    안녕하세요~ 구창민입니다.

    아래 예제를 기술하시고 마우스로 이미지를 강제로 회전시키면

    모든 각도로 회전됩니다.

    참고 하시고, 님도 돈 많이 버세요.

    그럼~ 항상 즐거운 프로그래밍 하시길~~

    unit PlgBltU;
    interface

    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, Buttons, ExtCtrls, Math;

    type
      TForm1 = class(TForm)
        Img: TImage;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormPaint(Sender: TObject);
        procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
      private
        P          : Array[0..3] of TPoint;
        OAng       : Array[0..3] of Double;
        OverHandle : Integer;
        BkBmp      : TBitmap;
        MidPt      : TPoint;
        Ang,R      : Double;
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.DFM}

    procedure TForm1.FormCreate(Sender: TObject);
    var
      Pt : Integer;
    begin
      BkBmp := TBitmap.Create;
      BkBmp.Width := Width;
      BkBmp.Height := Height;
      P[0] := Img.BoundsRect.TopLeft;
      P[3] := Img.BoundsRect.BottomRight;
      P[1] := P[0]; Inc(P[1].X,Img.Width);
      P[2] := P[3]; Dec(P[2].X,Img.Width);
      with Img do MidPt := Point(Left+Width div 2,Top + Height div 2);
      with Img do R := SqRt(Sqr(Width div 2)+Sqr(Height div 2));
      for Pt := 0 to 3 do with P[Pt] do
        OAng[Pt]:= ArcTan2(Y-MidPt.Y,X-MidPt.X)+Pi;
      OverHandle := -1;
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      BkBmp.Free;
    end;

    procedure TForm1.FormPaint(Sender: TObject);
    var
      Pt : Integer;
    begin
      with BkBmp.Canvas do
        begin
          Brush.Color := clBtnFace;
          FillRect(ClipRect);
          if PlgBlt(Handle,P,Img.Canvas.Handle,0,0,Img.Width,Img.Height,0,0,0) then
            begin
              Brush.Color := clBlack;
              for Pt := 0 to 3 do with P[Pt] do
                FillRect(Rect(X-3,Y-3,X+3,Y+3));
            end
          else
            TextOut(0,0,'PlgBlt currently supported only on WinNT');
        end;
      Canvas.Draw(0,0,BkBmp);
    end;

    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
    var
      Pt      : Integer;
      TmpRect : TRect;
    begin
      if ssLeft in Shift then
        begin
          if OverHandle = -1 then exit;
          Ang := ArcTan2(Y-MidPt.Y,X-MidPt.X)-OAng[OverHandle]+Pi;
          for Pt := 0 to 3 do
            P[Pt] := Point(MidPt.X-Round(R*Cos(Ang+OAng[Pt])),
                           MidPt.Y-Round(R*Sin(Ang+OAng[Pt])));
          Paint;
        end
      else
        begin
          OverHandle := -1;
          for Pt := 0 to 3 do
            begin
              with P[Pt] do TmpRect := Rect(X-3,Y-3,X+3,Y+3);
              if PtInRect(TmpRect,Point(X,Y)) then
                begin
                  Cursor := crHandPoint;
                  OverHandle := Pt;
                end;
            end;
          if OverHandle = -1 then Cursor := crDefault;
        end;
    end;

    end.


  • Profile
    조규춘 2002.01.19 12:11




    하이염..~~

    넘 바빠서..

    오랫만에.. 오는 군요...^^

    아~ 옛날이여~

    안녕하셔요~
    조규춘입니다.

    이미지 회전에 관한 거 적어 놓구 갈꼐용~

      여기에서는 출력 픽셀을 입력 이미지로 매핑시키게 됩니다.  이것을 사용해 이미지의 회전을 부드럽게 할 수 있습니다.

    원점 (0, 0)을 기준으로 점(x, y)를 Theta 각도만큼 회전시키려 한다면, 결과값(x', y')은 다음과 같습니다.

    x' = x * cos(theta) + y * sin(theta)
    y' = -x * sin(theta) + y * cos(theta)

    theta에 대해 반대방향으로 회전 할 경우의 각도는 -theta입니다.   즉, 출력 픽셀을 입력 위치로 매핑시키기 위해서는 회전 된 반대 방향으로 같은 각도만큼 돌리면 될 것이며, 이렇게 하기 위해서는 -theta를 사용하면 됩니다.  만약, 출력 픽셀이 (x', y')이라면 그에 대한 입력 픽셀(x, y)는 다음과 같습니다.

    x = x' * Cos(-theta) + y' * Sin(-theta)
    y = -x' * Sin(-theta) + y' * Cos(-theta)

    여기에서 Sin(-theta)는 -Sin(theta)이고 Cos(-theta)는 Cos(theta)와 같으므로,

    x = x' * Cos(theta) - y' * Sin(theta)
    y = x' * Sin(theta) + y' * Cos(theta)

    의 공식을 사용해 프로그램에서 이미지를 회전시킬 수 가 있습니다.

    출력 이미지의 각 픽셀에 대해서, 프로그램은 출력 픽셀에 매핑되는 입력 이미지내의 점을 찾기 위해 위의 공식을 사용합니다.  

    이 코드에서는 위에 설명했던것과는 조금 다르게 이미지 왼쪽 상단 모서리가 아닌, 이미지의 중심을 기준으로 해서 회전을 시킵니다.   그렇기 때문에, 계산이 진행되기 전에 출력 픽셀의 위치로부터 (to_cx, to_cy)값이 빼졌고, 결과에 (from_cx, from_cy)가 더해졌습니다.

    마지막으로, 회전을 할 경우에 고려해야할 사항이 하나 더 있습니다.
    회전이 되면 원본 이미지보다 바깥쪽으로 모서리가 벗어날 수 있어서 짤리게 됩니다.  180' 회전이 아니면, 거의 항상 그렇죠?  그래서, GetRotateSize라는 프로시져를 이용해 출력될 이미지의 높이와 너비를 계산하게 됩니다.  아래에 그 공식이 나와 있습니다.

    new_width = Round(Abs(old_width * Cos(theta)) + Abs(old_height * Sin(theta)));
    new_height = Round(Abs(old_width * Sin(theta)) + Abs(old_height * Cos(theta)));



    음냐..... 너무 어렵지요 ^^

    그래서 위의 공식을 코딩으로 하자면...

    이렇게 되나봐요~

    참고로 아래의 코드는 박상윤씨라구 잘생긴 분이 한거랍니다. ^^
    (박상윤씨가 이글 보면 술 한잔 사주~~~)

    xc:= trunc(bi^.bmiHeader.biWidth/2 ); // 이미지의 중앙을 원점으로 잡는다.
    yc:= trunc(bi^.bmiHeader.biHeight/2);

    radian:=degree*3.141592/180; //각도를 라디안으로 변화  

    for i:=-yc+1 to yc do begin
    for j:=-xc+1 to xc do begin //중심이 중앙이므로 -에서 +까지 처리한다.
    //+1을 한이유는 배열이 1부터이기때문
      
    v:=(i-py); //이동 변환
    u:=(j-px);  

    y:=(u*sin(radian)+v*cos(radian))/zy; //확대축소 및 회전 변환
    x:=(u*cos(radian)-v*Sin(radian))/zx;

    if y>0 then //실수 좌표에서 정수 좌표로 변환하여 차이 p,q를 구함
      m:=trunc(y) //양수 일 때 와 음수 일 때 틀려지는 것은 정수점을
    else //구하는 조건이 x,y를 넘지 않는 정수이기 때문이다.
      m:=trunc(y-1); //음수의 경우 넘지 않는 다는 의미는 -1만큼 이동하여
    if x>0 then //정수를 구해야 한다는 것을 의미한다.
      n:=trunc(x)
    else
      n:=trunc(x-1);

    q:=y-m; //실수좌표와 정수 좌표의 차이계산
    p:=x-n;

    if((m>=-yc+1)and(m<=yc) )and ((n>=-xc+1)and(n<=xc)) //원하는 이미지크기
    then begin //만큼만 계산함
      d:=trunc((1.0-q)*((1.0-p)*data[n+xc,m+yc]+p*data[n+1+xc,m+yc])
           +q*((1.0-p)*data[n+xc,m+1+yc]+p*data[n+1+xc,m+1+yc]));
    end //선형 보간법에 의한 데이터계산
    else
    d:=255

    if d<0 then d:=0;
    if d>255 then d:=255;

    outdata[j+xc,i+yc]:=d; //계산된 데이터를 출력 화상데이터에 입력

    end; //for
    end; //for