Q&A

  • BMP파일의 해상도와 크기에 대한 질문임다.
먼저 글을 읽어주어 감사함다...



합성한 이미지의 해상도를 구하고 그 해상도를 변경할 수 있는 방법을

알려주시면 감사하겠습니다..

포토샵에서는 그림의 해상도를 마음대로 조절할 수 있는데...

델파이에서 그런 기능을 구현할 수 없는지요??

참고로 이미지 컴포넌트에 있는 그림은 BMP입니다..



그림의 형태를 그대로 유지하면서 해상도를 바꾸어서 파일로 저장하거나..

복사기처럼 101%확대 혹은 99%로 축소하여 파일로 저장할 수 있는 방법이

있으면 알려주십시요.....



끝까지 읽어주어 감사함다...

1  COMMENTS
  • Profile
    조규춘 2000.11.03 18:09
    벤츄라 wrote:

    > 먼저 글을 읽어주어 감사함다...

    >

    > 합성한 이미지의 해상도를 구하고 그 해상도를 변경할 수 있는 방법을

    > 알려주시면 감사하겠습니다..

    > 포토샵에서는 그림의 해상도를 마음대로 조절할 수 있는데...

    > 델파이에서 그런 기능을 구현할 수 없는지요??

    > 참고로 이미지 컴포넌트에 있는 그림은 BMP입니다..

    >

    > 그림의 형태를 그대로 유지하면서 해상도를 바꾸어서 파일로 저장하거나..

    > 복사기처럼 101%확대 혹은 99%로 축소하여 파일로 저장할 수 있는 방법이

    > 있으면 알려주십시요.....

    >

    > 끝까지 읽어주어 감사함다...



    제일루 간단한 방법은...

    컴포넌트 사서 쓰셔요~ (이미지 라이브러리) 라구 하는 컴포넌트 쓰셔요...

    가격이 비싸서 그렇지... 진짜루 지금 이야기 하신거 말구두 무궁무진하게 많은 기능을 할수도 있답니다.



    그런데.. 못산다면 어쩔수 없는 노력이 필요하겠지요 ^^



    ========우선 해상도 구하는 것에 대해서 이야기를 하자믄.....======

    TotalNumBitsPerPixel := GetDeviceCaps(Canvas.Handle, BITSPIXEL) *

    GetDeviceCaps(Canvas.Handle, PLANES);



    해서 얻어오는 값이..

    1 = 2 colors (monochrome)

    4 = 16 colors

    8 = 256 colors

    15 = 32,768 colors

    16 = 65,536 colors

    24 = 16,777,216 colors



    이렇게 되는 거랍니다. ^^





    ======== 다음 해상도를 변경하는 방법이라구 되어 있는데.. =====

    위에서 쓴것처럼 간단한 것이 있을텐데.. 음냐.. 거까진 모르것구..

    256칼라루 만드는 것 한다면..

    만든이가 grahame.s.marsh@corp.courtaulds.co.uk 이사람인데..

    난 절대루 모르는 사람입니다. ^^



    unit Comp2;



    {$IFNDEF WIN32}

    Sorry, WIN 32 only!

    {$ENDIF}



    interface



    uses

    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

    ExtDlgs, ExtCtrls, StdCtrls, Buttons, ComCtrls;





    // declare own bitmap file record, specifically for 256 colour bitmaps

    type

    T256Palette = array [0..255] of TRGBQuad;

    P256Bitmap = ^T256Bitmap;

    T256Bitmap = packed record

    b256File : TBitmapFileHeader;

    b256Info : TBitmapInfoHeader;

    b256Pal : T256Palette;

    b256Data : record end;

    end;



    type

    TBitmapCompForm = class(TForm)

    GroupBox1: TGroupBox;

    InBrowseBtn: TBitBtn;

    InFilenameEdit: TEdit;

    InFilesizeLabel: TLabel;

    InScrollBox: TScrollBox;

    InImage: TImage;

    OpenPictureDialog: TOpenPictureDialog;

    GroupBox2: TGroupBox;

    OutFilenameEdit: TEdit;

    OutBrowseBtn: TBitBtn;

    SaveDialog: TSaveDialog;

    OutScrollBox: TScrollBox;

    OutImage: TImage;

    CompressBtn: TBitBtn;

    OutFilesizeLabel: TLabel;

    CompUsingLabel: TLabel;

    PaletteCheckBox: TCheckBox;

    QualityTrackBar: TTrackBar;

    QualityLabel: TLabel;

    Label1: TLabel;

    procedure InBrowseBtnClick(Sender: TObject);

    procedure QualityTrackBarChange(Sender: TObject);

    procedure OutBrowseBtnClick(Sender: TObject);

    procedure OutFilenameEditChange(Sender: TObject);

    procedure CompressBtnClick(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

    private

    InBitmap : P256Bitmap; // copy of bitmap file

    InSize, // copy of filesize

    InDataSize, // size of bitmap data

    InColours : integer; // number of colours



    procedure FreeStuff;

    public

    end;



    var

    BitmapCompForm: TBitmapCompForm;



    implementation



    {$R *.DFM}



    //-- calls to video for windopws dll -------------------------------------------



    type

    PICInfo = ^TICInfo;

    TICInfo = packed record

    dwSize, // sizeof (TICInfo)

    fccType, // compressor type eg vidc

    fccHandler, // compressor subtype eg rle

    dwFlags, // lo word is type specific

    dwVersion, // version of driver

    dwVersionICM : DWORD; // version of the ICM

    szName : array [0..15] of wchar; // short name

    szDescription : array [0..127] of wchar; // long name

    szDriver : array [0..127] of wchar; // driver that contains the compressor

    end;



    const

    ICMODE_COMPRESS = 1;

    ICTYPE_VIDEO = ord ('v') +

    ord ('i') shl 8 +

    ord ('d') shl 16 +

    ord ('c') shl 24;

    type

    TICHandle = THandle;



    function ICLocate (fccType, fccHandler: DWORD; lpbiIn, lpbmOut : PBitmapInfoHeader; wFlags: word) : TICHandle;

    stdcall; external 'msvfw32.dll' name 'ICLocate';



    function ICGetInfo (Handle: TICHandle; var ICInfo: TICInfo; cb: DWORD): LRESULT;

    stdcall; external 'msvfw32.dll' name 'ICGetInfo';



    function ICImageCompress (Handle: TICHandle; uiFlags: UINT; lpbiIn: PBitmapInfo;

    lpBits: pointer; lpbiOut: PBitmapInfo; lQuality: integer; plSize: PInteger): HBitmap;

    stdcall; external 'msvfw32.dll' name 'ICImageCompress';



    function ICClose (Handle: TICHandle): LRESULT;

    stdcall; external 'msvfw32.dll' name 'ICClose';



    //--- compressor form ----------------------------------------------------------



    const

    FSStr = 'File size: %d';

    CUStr = 'Compressed using: %s';

    BitmapSignature = $4D42;



    procedure TBitmapCompForm.FormDestroy(Sender: TObject);

    begin

    FreeStuff

    end;



    procedure TBitmapCompForm.FreeStuff;

    begin

    if InSize <> 0 then

    begin

    FreeMem (InBitmap, InSize);

    InBitmap := nil;

    InSize := 0

    end

    end;



    procedure TBitmapCompForm.InBrowseBtnClick(Sender: TObject);

    var

    Bitmap : TBitmap;

    begin

    with OpenPictureDialog do

    if Execute then

    begin

    InFilesizeLabel.Caption := Format (FSStr, [0]);

    InImage.Picture := nil;

    InFilenameEdit.Text := '';

    FreeStuff;



    with TFileStream.Create (Filename, fmOpenRead) do

    try

    InSize := Size;

    GetMem (InBitmap, InSize);

    Read (InBitmap^, InSize);



    with InBitmap^ do

    if b256File.bfType = BitmapSignature then

    if b256Info.biBitCount = 8 then

    if b256Info.biCompression = BI_RGB then

    begin

    // Ok, we have a 256 colour, uncompressed bitmap

    InFilenameEdit.Text := Filename;



    // determine number of entries in palette

    if b256Info.biClrUsed = 0 then

    InColours := 256

    else

    InColours := b256Info.biClrUsed;



    // determine size of data bits

    with InBitmap^.b256Info do

    if biSizeImage = 0 then

    InDataSize := biWidth * biHeight

    else

    InDataSize := biSizeImage



    end else

    ShowMessage ('Bitmap already compressed')

    else

    ShowMessage ('Not a 256 colour bitmap')

    else

    ShowMessage ('Not a bitmap')

    finally

    Free

    end;



    // show the bitmap and file size

    if InFileNameEdit.Text <> '' then

    begin

    Bitmap := TBitmap.Create;

    try

    Bitmap.LoadFromFile (InFilenameEdit.Text);

    InImage.Picture.Bitmap := Bitmap

    finally

    Bitmap.Free

    end;

    InScrollBox.VertScrollBar.Range := InBitmap^.b256Info.biHeight;

    InScrollBox.HorzScrollBar.Range := InBitmap^.b256Info.biWidth;

    InFilesizeLabel.Caption := Format (FSStr, [InBitmap^.b256File.bfSize])

    end

    end

    end;



    procedure TBitmapCompForm.OutBrowseBtnClick(Sender: TObject);

    begin

    with SaveDialog do

    if Execute then

    OutFilenameEdit.Text := Filename

    end;



    //--- Palette Compression ------------------------------------------------------



    // compress a 256 colour palette by removing unused entries

    // returns new number of entries

    function CompressPalette (var Pal: T256Palette; Data: pointer; DataSize: integer): word;

    type

    TPaletteUsed = packed record

    Used : boolean;

    NewEntry : byte;

    end;

    TPaletteUsedArray = array [0..255] of TPaletteUsed;

    var

    PUArray: TPaletteUsedArray;

    Scan: PByte;

    NewValue,

    Loop: integer;

    NewPal : T256Palette;

    begin

    // look through the bitmap data bytes looking for palette entries in use

    fillchar (PUArray, sizeof (PUArray), 0);

    Scan:= Data;

    for Loop:= 1 to DataSize do

    begin

    PUArray[Scan^].Used := true;

    inc (Scan)

    end;



    // go through palette and set new entry numbers for those in use

    NewValue := 0;

    for Loop:= 0 to 255 do

    with PUArray[Loop] do

    if Used then

    begin

    NewEntry := NewValue;

    inc (NewValue);

    end;

    Result := NewValue; // return number in use

    if NewValue = 256 then

    exit; // QED



    // go through bitmap data assigninging new palette numbers

    Scan:= Data;

    for Loop:= 1 to DataSize do

    begin

    Scan^ := PUArray[Scan^].NewEntry;

    inc (Scan)

    end;



    // create a new palette and copy across only those entries in use

    fillchar (NewPal, sizeof (T256Palette), 0);

    for Loop := 0 to 255 do

    with PUArray [Loop] do

    if Used then

    NewPal[NewEntry] := Pal [Loop];



    // return the new palette

    Pal := NewPal

    end;



    //--- try to compress input image -> output image ------------------------------



    procedure TBitmapCompForm.CompressBtnClick(Sender: TObject);

    var

    Bitmap: TBitmap;

    Handle: THandle;

    CompressHandle: integer;

    ICInfo: TICInfo;

    OutBitmap,

    InBitmapCopy : P256Bitmap;

    CompressedStuff,

    OutData,

    InDataCopy : pointer;

    OutSize,

    OutColours : integer;

    begin

    // make an output bitmap file

    GetMem (OutBitmap, sizeof (T256Bitmap));

    try

    // make a copy of the input file as we will play with the data

    GetMem (InBitmapCopy, InSize);

    try

    Move (InBitmap^, InBitmapCopy^, InSize);

    InDataCopy := pointer (integer(InBitmapCopy) + sizeof (TBitmapFileHeader) +

    sizeof (TBitmapInfoHeader) + InColours * sizeof (TRGBQuad));



    // crunch the palette

    with InBitmapCopy^ do

    if PaletteCheckBox.Checked then

    OutColours := CompressPalette (b256Pal, InDataCopy, InDataSize)

    else

    OutColours := InColours;



    // now copy the input file to fill in most of the output bitmap values

    Move (InBitmapCopy^, OutBitmap^, sizeof (T256Bitmap));

    // set the compression required

    OutBitmap^.b256Info.biCompression := BI_RLE8;



    // find a compressor

    CompressHandle := ICLocate (ICTYPE_VIDEO, 0, @InBitmapCopy^.b256Info,

    @OutBitmap.b256Info, ICMODE_COMPRESS);

    try

    fillchar (ICInfo, sizeof (TICInfo), 0);

    ICInfo.dwSize := sizeof (TICInfo);

    // get info on the compressor

    ICGetInfo (CompressHandle, ICInfo, sizeof (TICInfo));

    OutSize := 0; // best compression

    // now compress the image

    Handle := ICImageCompress (CompressHandle, 0, @InBitmapCopy^.b256Info,

    InDataCopy, @OutBitmap^.b256Info, QualityTrackBar.Position*100, @OutSize);

    finally

    ICClose (CompressHandle)

    end;



    if Handle <> 0 then

    begin

    // get the compressed data

    CompressedStuff := GlobalLock (Handle);

    try

    // modify the filesize and offset in case palette has shrunk

    with OutBitmap^.b256File do

    begin

    bfOffBits := sizeof (TBitmapFileHeader) + sizeof(TBitmapInfoHeader) +

    OutColours * sizeof (TRGBQuad);

    bfSize := bfOffBits + OutSize

    end;

    // locate the data

    OutData := pointer (integer(CompressedStuff) +

    sizeof(TBitmapInfoHeader) + InColours * sizeof (TRGBQuad));



    // modify the bitmap info header

    with OutBitmap^.b256Info do

    begin

    biSizeImage := OutSize;

    biClrUsed := OutColours;

    biClrImportant := 0

    end;



    // save the bitmap to disc

    with TFileStream.Create (OutFilenameEdit.Text, fmCreate) do

    try

    write (OutBitmap^, sizeof (TBitmapFileHeader) + sizeof (TBitmapInfoHeader));

    write (InBitmapCopy^.b256Pal, OutColours*sizeof (TRGBQuad));

    write (OutData^, OutSize)

    finally

    Free

    end;



    // view the result

    Bitmap := TBitmap.Create;

    try

    Bitmap.LoadFromFile (OutFilenameEdit.Text);

    OutImage.Picture.Bitmap := Bitmap

    finally

    Bitmap.Free

    end;



    // set the scrollbars and give some stats

    with OutBitmap^ do

    begin

    OutScrollBox.VertScrollBar.Range := b256Info.biHeight;

    OutScrollBox.HorzScrollBar.Range := b256Info.biWidth;

    OutFileSizeLabel.Caption := Format (FSStr, [b256File.bfSize]);

    CompUsingLabel.Caption := Format (CUStr, [WideCharToString (ICInfo.szDescription)])

    end



    // now tidy up

    finally

    GlobalUnlock (Handle)

    end

    end else

    ShowMessage ('Bitmap could not be compressed')

    finally

    FreeMem (InBitmapCopy, InSize)

    end

    finally

    FreeMem (OutBitmap, sizeof (T256Bitmap))

    end

    end;



    procedure TBitmapCompForm.QualityTrackBarChange(Sender: TObject);

    begin

    QualityLabel.Caption := IntToStr (QualityTrackBar.Position)

    end;



    procedure TBitmapCompForm.OutFilenameEditChange(Sender: TObject);

    begin

    CompressBtn.Enabled := (InFilenameEdit.Text <> '') and

    (OutFilenameEdit.Text <> '')

    end;



    end.







    ===== 그다음은 확대 및 축소 인감요?? =============

    델파이는 이미지 크기를 변경하는 쉬운 방법 두가지를 제공합니다.



    Image 컴포넌트를 사용한다면, 속성중에 Stretch라는 것이 있지요? 이것은 AutoSize와 반대되는 역할을 한다는 것은 알고 계시죠? 즉, 컴포넌트 크기에 맞춰서 사용자가 지정한 이미지를 늘리거나 축소시키거나 하는 것이지요.



    또하나의 방법은, TCanvas 객체에 있는 StretchDraw라는 프로시져를 사용하는 것입니다. 이것은 지정한 그래픽의 크기를 목적 객체의 크기에 맞춘후 복사를 하는 것입니다.

    아래 코드를 보면 imgInput 콘트롤의 그림을 imgOutput 콘트롤에 맞추어 넣고 있습니다.



    imgOutput.Canvas.StretchDraw(imgOutput.ClientRect, imgInput.Picture.Graphic);



    이 방법은 이미지를 늘릴경우, 배수에 따라서 똑같은 이미지를 그 배수만큼 반복시켜서 전체 이미지를 확대 시키고, 축소시에는 이미지중 배수에 따라 중간 중간의 픽셀을 제거하는 방식으로 하기 때문에 속도가 빠르고, 사용하기도 쉽습니다. 하지만, 이러한 확대시에는 그림 모양이 각지게 보이는 현상이 있으며, 축소시에는 필요한 정보가 제거되어 그림에서 보이지 않게 될 수도 있습니다.



    여기에서는 이러한 단순한 방법대신에 약간의 공식을 사용해서 좀더 부드럽게 이미지가 보일 수 있도록 하는 알고리즘을 설명드릴 것입니다.



    이미지를 줄이기 위해서 TCanvas.StretchDraw를 사용하면 원본 이미지로부터 몇몇 픽셀들을 제거하게 됩니다. 이 방법의 문제점은 제거된 픽셀에 있던 정보들은 완전히 잃어버리게 된다는 것입니다. 만약 거기에 중요한 정보(수직선이 있는 픽셀들과 같이)가 있었다면 결과물에서는 보이지 않게 될 것입니다.



    더 좋은 방법은 축소된 출력 이미지안에 들어갈 픽셀을 만들기 위해 근처의 픽셀들을 가지고 평균을 내는 것입니다. 이렇게 해서 출력 이미지의 각 픽셀에 대해 작업하는 것입니다. 각각의 출력 픽셀에 대하여, 프로그램이 출력 픽셀로 매핑될 입력 이미지의 픽셀들을 계산하는 것입니다. 그리고 나선, 이 입력 픽셀들의 Red, Green, Blue 값들에 대해 평균을 만들어 내는 것입니다.



    델파이 자료실에 있는 리스트를 보시면 ShrinkPicture라는 프로시져를 발견하실 수 있을 겁니다. 이것은 이미지를 줄이는 루틴입니다. 이 함수는 입력 캔버스인 from_canvas의 영역인 from_x1 <= x <= from_x2 와 from_y1 <= y <= from_y2 를 출력 캔버스 to_canvas 의 영역 to_x1 <= x <= to_x2, to_y1 <= y <= to_y2 로 축소시킵니다.



    여기에서 가장 중요한 코드는 입력 픽셀들로부터 출력 픽셀로의 값을 결정해서 매핑시키는 함수입니다. 이미지가 x와 y 방향으로 각각 xscale, yscale 만큼이 비율로 줄어든다면, 출력 픽셀 (to_x, to_y)는 아래와 같은 식에 따라 사각형 x1 <= x <= x2, y1 <= y <= y2 로 매핑됩니다.



    y1 = Trunc((to_y - to_y1) / yscale + from_y1)

    y2 = Trunc((to_y + 1 - to_y1) / yscale + from_y1) - 1

    x1 = Trunc((to_x - to_x1) / xscale + from_x1)

    x2 = Trunc((to_x + 1 - to_x1) / xscale + from_x1) - 1



    프로시져가 입력 이미지의 사각형 부분을 찾아 낸후, 이 픽셀들의 Reg, Gree, Blue 색깔의 각각에 대해 평균을 찾아낸 후 출력 픽셀 (to_x, to_y)에 그 값을 지정하는 것입니다.



    별로 어렵지 않죠? 이렇게 하면, 적어도 정보의 손실은 막을 수 있어서 축소된 이미지를 보면 어느정도 부드럽게 축소가 되었다는 것을 알 수 가 있습니다.



    이미지를 늘리기 위해서 StretchDraw는 원본 이미지의 각 픽셀을 반복해서 늘리는 방식을 사용합니다. 이 알고리즘이 속도는 빠르지만, 이미지에 계단 현상이 보이게 됩니다. 이러한 문제를 해결하기 위한 알고리즘도 이미지 축소에서 쓰이는 방식과 비슷한 방식을 사용합니다.



    이미지 확대를 위해 각각의 출력 픽셀에 대해서, 프로그램은 입력 이미지의 어느 부분이 출력 픽셀로 매핑되는지를 계산하게 됩니다. 출력 이미지가 더 크기 때문에, 하나의 출력 픽셀이 하나의 입력 픽셀에 정확히 매칭되지는 않을 것입니다. 입력 픽셀을 분할해서 사용한다고 하는 것이 많을 것입니다. 하지만, 하나의 픽셀을 나눌 수 는 없겠죠??? 그래서 아래와 같이 계산을 하게 되는 것입니다.



    만약 이미지가 xscale, yscale의 비율로 x, y 방향에서 확대되었다면, 출력 픽셀 (to_x, to_y)는 아래 공식에 따라 점(sfrom_x, sfrom_y) 로부터 매핑됩니다.



    sfrom_y = (to_y - to_y1) / yscale + from_y1

    sfrom_x = (to_x - to_x1) / xscale + from_x1



    그리고 나서, 프로그램은 계산된 입력 점 근처의 네개의 픽셀에 대해 평가합니다. 위의 그림에서, 이 픽셀들은 왼쪽 상단 구석의 네개에 해당합니다. 이 픽셀들은 각각



    (ifrom_x, ifrom_y)

    (ifrom_x + 1, ifrom_y)

    (ifrom_x, ifrom_y + 1)

    (ifrom_x + 1, ifrom_y + 1)



    이며 이때의 ifrom_x, ifrom_y의 값은 아래와 같습니다.



    ifrom_y = Trunc(sfrom_y)

    ifrom_x = Trunc(sfrom_x)



    프로그램은 이 네개의 픽셀에 대한 Red, Green, Blue 칼라 값을 계산해 냅니다. 이것은 출력 픽셀에 대해 가중치 평균(Weighted Average)을 사용하며, 이 평균은 입력 픽셀이 결과치에 근접하게 반영하도록 하기 위한 것입니다.



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



    원점 (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)



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



    출력 이미지의 각 픽셀에 대해서, 프로그램은 출력 픽셀에 매핑되는 입력 이미지내의 점을 찾기 위해 위의 공식을 사용합니다. 그리고 나서, EnlargePicture에서 했던 것처럼 출력 픽셀의 칼라 값을 찾기 위해 네개의 근처 픽셀의 칼라 값에 대한 가중치 평균을 계산합니다.



    자료실에 있는 소스를 보시면 RotatePicture라는 프로시져가 있는데, 이것이 회전을 위한 루틴입니다. 이 코드에서는 위에 설명했던것과는 조금 다르게 이미지 왼쪽 상단 모서리가 아닌, 이미지의 중심을 기준으로 해서 회전을 시킵니다. 그렇기 때문에, 계산이 진행되기 전에 출력 픽셀의 위치로부터 (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)));



    그래두 그림 축소 저장하는거..

    다음 아랫줄 만큼 간단한건 없을껄요..

    단지.. 진짜루 화질이 않조을 뿐이징.. 푸하하..

    procedure TForm1.Button3Click(Sender: TObject);

    var

    Buf: TBitmap;

    begin

    Buf := TBitmap.Create;

    // Buf.Monochrome := True;

    Buf.Width := Screen.Width div 4;

    Buf.Height := Screen.Height div 4;



    StretchBlt(Buf.Canvas.Handle, 0, 0, Buf.Width, Buf.Height,

    GetDC(0), 0, 0, Screen.Width, Screen.Height, SRCCOPY);



    Buf.SaveToFile('Res.bmp');

    Buf.Free;

    end;



    한델공식동호회가 될 델세상(http://www.freechal.com/delphiworld)의 조규춘이였습니다.



    (내가 지금까지 한델에서 답변한것중에 제일 긴 내용이였습니다.