출처: http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=0&indx=452991&page=1
비트맵의 PixelFormat 속성이 pf32Bit인 TBitmap 원본으로부터 크기조정한
비트맵을 얻는 소스입니다.
Andrew Jameson의 오리지널 소스에서 Transparency 값이 유지되도록 수정한 것과
GDI+ API를 이용한 것 중에서 선택할 수 있습니다.
type
TRGBAArray = array[Word] of TRGBQUAD;
pRGBAArray = ^TRGBAArray;
// Modified(to reserve transparency) version of Andrew Jameson's work.
// Src 비트맵 이미지를 Dst 비트맵의 크기에 맞추어 Dst 비트맵에 복사한다.
function SmoothResize(Src, Dst: TBitmap): BOOL;
var
x, y: Integer;
xP, yP: Integer;
xP2, yP2: Integer;
SrcLine1, SrcLine2: pRGBAArray;
t3: Integer;
z, z2, iz2: Integer;
DstLine: pRGBAArray;
DstGap: Integer;
w1, w2, w3, w4: Integer;
begin
Src.PixelFormat := pf32Bit;
Dst.PixelFormat := pf32Bit;
if (Src.Width = Dst.Width) and (Src.Height = Dst.Height) then
begin
Result := true;
Dst.Assign(Src);
end else
try
DstLine := Dst.ScanLine[0];
DstGap := Integer(Dst.ScanLine[1]) - Integer(DstLine);
xP2 := MulDiv(pred(Src.Width), $10000, Dst.Width);
yP2 := MulDiv(pred(Src.Height), $10000, Dst.Height);
yP := 0;
for y := 0 to pred(Dst.Height) do
begin
xP := 0;
SrcLine1 := Src.ScanLine[yP shr 16];
if (yP shr 16 < pred(Src.Height)) then
SrcLine2 := Src.ScanLine[succ(yP shr 16)]
else
SrcLine2 := Src.ScanLine[yP shr 16];
z2 := succ(yP and $FFFF);
iz2 := succ((not yp) and $FFFF);
for x := 0 to pred(Dst.Width) do
begin
t3 := xP shr 16;
z := xP and $FFFF;
w2 := MulDiv(z, iz2, $10000);
w1 := iz2 - w2;
w4 := MulDiv(z, z2, $10000);
w3 := z2 - w4;
DstLine[x].rgbRed := (SrcLine1[t3].rgbRed * w1 +
SrcLine1[t3 + 1].rgbRed * w2 +
SrcLine2[t3].rgbRed * w3 + SrcLine2[t3 + 1].rgbRed * w4) shr 16;
DstLine[x].rgbGreen := (SrcLine1[t3].rgbGreen * w1 +
SrcLine1[t3 + 1].rgbGreen * w2 +
SrcLine2[t3].rgbGreen * w3 + SrcLine2[t3 + 1].rgbGreen * w4) shr 16;
DstLine[x].rgbBlue := (SrcLine1[t3].rgbBlue * w1 +
SrcLine1[t3 + 1].rgbBlue * w2 +
SrcLine2[t3].rgbBlue * w3 + SrcLine2[t3 + 1].rgbBlue * w4) shr 16;
DstLine[x].rgbReserved := (SrcLine1[t3].rgbReserved * w1 +
SrcLine1[t3 + 1].rgbReserved * w2 +
SrcLine2[t3].rgbReserved * w3 + SrcLine2[t3 + 1].rgbReserved * w4) shr 16;
Inc(xP, xP2);
end; {for}
Inc(yP, yP2);
DstLine := pRGBAArray(Integer(DstLine) + DstGap);
end; {for}
Result := true;
except
Result := false;
end; {try}
end; {SmoothResize}
//-------------------------
(사용 함수)
{$DEFINE USE_GDIPLUS}
function GetResizedBitmap(Bmp: TBitmap; NewSize: TSize): TBitmap;
{$IFDEF USE_GDIPLUS}
var
InputBmp: TGPBitmap;
Graphics: TGPGraphics;
x, y: integer;
P: PARGBArray;
GPColor: TGPColor;
// SrcBmp: TGPBitmap;
// pixels: pInt;
BitmapData: TBitmapData;
R: TGPRect;
p2: pbyte;
{$ENDIF}
begin
if not Assigned(Bmp) then
exit;
// pixel당 24bit 또는 32 bit로 이미지를 구성하는 Bitmap만 처리한다.
if (Bmp.PixelFormat <> pf24Bit) and (Bmp.PixelFormat <> pf32Bit) then
exit;
// create graphics object for output image
try
Result := TBitmap.Create;
Result.PixelFormat := bmp.PixelFormat;
Result.Width := NewSize.cx;
Result.Height := NewSize.cy;
{$IFNDEF USE_GDIPLUS}
SmoothResize(bmp, Result); // GDI+ 함수를 이용한 이미지 크기조정은 아래 코드 참조.
{$ENDIF}
except
FreeAndNil(Result);
exit;
end;
{$IFNDEF USE_GDIPLUS}
exit;
{$ENDIF}
{$IFDEF USE_GDIPLUS}
// 아래와 같이 Bitmap의 핸들을 이용한 이미지 취득시는 알파채널의 값을 잃은 이미지(=불투명 이미지)를
// 얻는다.
{ if (Bmp.PixelFormat in [pf1Bit, pf4Bit, pf8Bit]) then
InputBmp := TGPBitmap.Create(Bmp.Handle, Bmp.Palette)
else
InputBmp := TGPBitmap.Create(Bmp.Handle, 0);
}
// 아래와 같이 픽셀단위 또는 라인 단위로 이미지 데이터를 직접 복사하면 알파채널의 값이
// 유지된다.
// 또 다른 방법으로 DIB를 취득해서 이미지를 데이터를 한번에 복사하는 방법이 있는데 이 것은
// 별도로 게시한 "알파채널의 값을 잃지 않고 TBitmap으로 부터 GDI+ TGPBitmap을 얻는 함수"에
// 나와있다.
R := MakeRect(0, 0, Bmp.Width, Bmp.Height); // 픽셀단위로 처리시는 불필요
if Bmp.AlphaFormat = afPremultiplied then
begin
InputBmp := TGPBitmap.Create(Bmp.Width, Bmp.Height, PixelFormat32bppPARGB);
InputBmp.LockBits(R, ImageLockModeWrite, PixelFormat32bppPARGB, BitmapData); // 픽셀단위로 처리시는 불필요
end else
begin
InputBmp := TGPBitmap.Create(Bmp.Width, Bmp.Height, PixelFormat32bppARGB);
InputBmp.LockBits(R, ImageLockModeWrite, PixelFormat32bppARGB, BitmapData); // 픽셀단위로 처리시는 불필요
end;
p2 := BitmapData.Scan0;
for y := 0 to Bmp.Height - 1 do
begin
// 픽셀단위로 처리시는 아래 코드를 이용한다.
{ for x := 0 to (Bmp.Width - 1) do
begin
GPColor := MakeColor(P[x].rgbReserved, P[x].rgbRed, P[x].rgbGreen, P[x].rgbBlue);
InputBmp.SetPixel(x, y, GPColor);
end; }
// 라인 단위로 처리시는 아래 코드를 이용한다.
P := Bmp.Scanline[y];
CopyMemory(p2, p, Bmp.Width * 4);
inc(p2, BitmapData.Stride);
end;
InputBmp.UnlockBits(BitmapData); // 픽셀단위로 처리시는 불필요
try
Graphics := TGPGraphics.Create(Result.Canvas.Handle);
try
// set the composition mode to copy
Graphics.SetCompositingMode(CompositingModeSourceCopy);
// set high quality rendering modes
Graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
Graphics.SetPixelOffsetMode(PixelOffsetModeHighQuality);
Graphics.SetSmoothingMode(SmoothingModeHighQuality);
// draw the input image on the output in modified size
Graphics.DrawImage(InputBmp, 0, 0, Result.Width, Result.Height);
finally
Graphics.Free;
end;
finally
InputBmp.Free;
end;
{$ENDIF}
end;
'언어 > delphi' 카테고리의 다른 글
BinToHexEx (0) | 2018.05.15 |
---|---|
자바의 Toast VCL용입니다 (0) | 2018.05.15 |
입력값 검사루틴 - 코드 리팩토링 (0) | 2018.05.15 |
초를 0시간 0분 0초식으로 리턴 (0) | 2018.05.15 |
익명함수+쓰레드를 활용한 간단한 쓰레드 사용 방법 (0) | 2018.05.15 |