이 기사의 예제에서는 Delphi의 기본 이미지 처리 방법을 요약합니다. 참고할 수 있도록 모든 사람과 공유하세요. 구체적인 분석은 다음과 같습니다.
//엠보싱 절차 Emboss(SrcBmp,DestBmp:TBitmap;AzimuthChange:integer);overload;var i, j, Gray, Azimuthvalue, R, G, B: 정수; SrcRGB, SrcRGB1, SrcRGB2, DestRGB: pRGBTriple; i에 대해 시작: = 0에서 SrcBmp.Height - 1에서 SrcRGB 시작 := SrcBmp.ScanLine[i]; DestBmp.ScanLine[i]; if (AzimuthChange >= -180) 및 (AzimuthChange < -135) i > 0이면 시작 SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; Inc(SrcRGB1); := SrcRGB; Inc(SrcRGB2); end else if (AzimuthChange >= -135) 및 (AzimuthChange < -90) i > 0이면 시작 then SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB; SrcRGB2 := SrcRGB1; Inc(SrcRGB2); (AzimuthChange >= -90) 및 (AzimuthChange < -45)는 i > 0이면 시작하고 SrcRGB1 := SrcBmp.ScanLine[i-1] else SrcRGB1 := SrcRGB2 := SrcRGB1; end else if (AzimuthChange >= -45) 및 (AzimuthChange < 0) 그런 다음 SrcRGB1을 시작합니다. SrcRGB; i > 0이면 SrcRGB2 := SrcBmp.ScanLine[i-1] else SrcRGB2 := SrcRGB; end else if (AzimuthChange >= 0) 및 (AzimuthChange < 45) 그러면 SrcRGB2 := SrcRGB; SrcBmp.Height - 1) 다음 SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB; end else if (AzimuthChange >= 45) and (AzimuthChange < 90) then start if (i < SrcBmp.Height - 1) then SrcRGB1 := SrcBmp.ScanLine[i +1] else SrcRGB1 := SrcRGB2 := SrcRGB1; end else if (AzimuthChange >= 90) 및 (AzimuthChange < 135) if (i < SrcBmp.Height - 1) then SrcRGB1 := SrcBmp.ScanLine[i+1] else SrcRGB1 := SrcRGB2 := SrcRGB1; Inc(SrcRGB1); (AzimuthChange >= 135) 및 (AzimuthChange <= 180) if (i < SrcBmp.Height - 1) then SrcRGB2 := SrcBmp.ScanLine[i+1] else SrcRGB2 := SrcRGB2; = SrcRGB; j에 대한 끝; 0에서 SrcBmp.Width - 1이면 시작합니다(AzimuthChange >= -180) 및 (AzimuthChange < -135) Azimuthvalue := AzimuthChange + 180 R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div 45)-((SrcRGB2.rgbtRed)*(45-방위각 값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*방위각 값 div 45)-((SrcRGB2.rgbtGreen)*(45- 방위각값)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*방위각 값 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= -135) 및 (AzimuthChange < -90) 그런 다음 방위각 값을 시작합니다 := 방위각 변경 + 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*방위값 div 45)-((SrcRGB2.rgbtRed)*(45-방위각값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*방위각 값 div 45)-((SrcRGB2.rgbtGreen)*(45-방위각 값) div 45)+78 B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *방위값 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= -90) 및 (AzimuthChange < -45) j=1이면 시작하고 Inc(SrcRGB1,- 1) 방위각 값 := 방위각 변경 + 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*방위각 값 div 45)-((SrcRGB2.rgbtRed)*(45-방위각 값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *방위값 div 45)-((SrcRGB2.rgbtGreen)*(45-방위각 값) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*방위각 값 div 45)-((SrcRGB2.rgbtBlue)*(45- 방위각 값) div 45)+78 end else; if (AzimuthChange >= -45) and (AzimuthChange < 0) then start Inc(SrcRGB1,-1); Inc(SrcRGB2,-1) end; SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*방위각값 div 45)-((SrcRGB2.rgbtRed)*(45-방위각 값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*방위각 값 div 45)-((SrcRGB2.rgbtGreen)*(45- 방위각값)div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*방위각 값 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= 0) and (AzimuthChange < 45) j=1이면 시작하고 시작합니다. Inc(SrcRGB1,-1); Inc(SrcRGB2,-1); 방위각 값 := 방위각 변경; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*방위각 값 div 45)-((SrcRGB2.rgbtRed)*( 45-방위각값)div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*방위각 값 div 45)-((SrcRGB2.rgbtGreen)*(45-방위각 값) div 45)+78 B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue) *방위값 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= 45) 및 (AzimuthChange < 90) j=1이면 시작하고 Inc(SrcRGB2,-1) ; 방위각 값 := 방위각 변경 - 45; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*방위각 값 div 45)-((SrcRGB2.rgbtRed)*(45-방위각 값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *방위값 div 45)-((SrcRGB2.rgbtGreen)*(45-방위각 값) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*방위각 값 div 45)-((SrcRGB2.rgbtBlue)*(45- 방위각 값) div 45)+78 end else; if (AzimuthChange >= 90) and (AzimuthChange < 135) then start Azimuthvalue := AzimuthChange - 90; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*Azimuthvalue div 45)-((SrcRGB2.rgbtRed)*(45 - 방위각 값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen)*방위각 값 div 45)-((SrcRGB2.rgbtGreen)*(45-방위각 값) div 45)+78; (SrcRGB1.rgbtBlue)*방위각 값 div 45)-((SrcRGB2.rgbtBlue)*(45-Azimuthvalue) div 45)+78; end else if (AzimuthChange >= 135) 및 (AzimuthChange <= 180) then start Azimuthvalue := AzimuthChange - 135; R:=SrcRGB.rgbtRed-((SrcRGB1.rgbtRed)*방위각 값 div 45)-((SrcRGB2.rgbtRed)*(45-방위각 값) div 45)+78; G:=SrcRGB.rgbtGreen-((SrcRGB1.rgbtGreen) *방위값 div 45)-((SrcRGB2.rgbtGreen)*(45-방위각 값) div 45)+78; B:=SrcRGB.rgbtBlue-((SrcRGB1.rgbtBlue)*방위각 값 div 45)-((SrcRGB2.rgbtBlue)*(45- 방위각값) div 45)+78; R:=최소(R,255); G:=최소(G,255); B:=최소(B,255) B:=Max(B,0); 회색:= (R shr 2) + (R shr 4) + (G shr 1) + (G shr 4) + (B shr 3); DestRGB.rgbtRed:=회색; DestRGB.rgbtBlue:=회색; if (j=-180) 및 (AzimuthChange<-135)) 또는 ((AzimuthChange>=90) 및 (AzimuthChange<=180) ))) 다음은 Inc(SrcRGB1)를 시작합니다. (j=135) 및 (AzimuthChange<180)) 또는 ((AzimuthChange>=-180) 및 (AzimuthChange<=-90))) start Inc(SrcRGB2); Inc(DestRGB); 끝; 끝;끝;프로시저 Emboss(Bmp:TBitmap;AzimuthChange:integer;ElevationChange:integer;WeightChange:integer);overload;var DestBmp:TBitmap;begin DestBmp:=TBitmap.Create(Bmp); Emboss(Bmp,DestBmp,AzimuthChange,ElevationChange) ,체중변화); Bmp.Assign(DestBmp);end;//역 프로시저 Negative(Bmp:TBitmap);var i, j: Integer; PRGB: pRGBTriple;begin Bmp.PixelFormat:=pf24Bit; for i := 0 to Bmp.Height - 1 do start PRGB := Bmp.ScanLine[i]; for j := 0 ~ Bmp.Width - 1 do start PRGB^.rgbtRed :=PRGB^.rgbtGreen :=PRGB^.rgbtBlue :=PRGB^.rgbtBlue 아님 end;end; 노출 절차 Exposure(Bmp:TBitmap);var i, j: 정수 PRGB: pRGBTriple;begin Bmp.PixelFormat:=pf24Bit; for i := 0 to Bmp.Height - 1 do start PRGB := Bmp.ScanLine[i]; for j := 0 to Bmp.Width - 1 do start if PRGB^.rgbtRed<128 PRGB^.rgbtRed :=PRGB^.rgbtRed가 아님 PRGB^.rgbtGreen<128인 경우 then PRGB^.rgbtGreen :=PRGB^.rgbtGreen; if PRGB^.rgbtBlue<128 then PRGB^.rgbtBlue :=not PRGB^.rgbtBlue; Inc(PRGB) end; SrcBmp:TBitmap);var i, j:Integer; SrcRGB:pRGBTriple; SrcPreRGB:pRGBTriple; 프로시저 Inc(SrcPreRGB); Inc(SrcNextRGB); SrcBmp.PixelFormat:=pf24Bit; for i := 0에서 SrcBmp.Height - 1 i > 0이면 시작하고 SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB := SrcBmp.ScanLine[i]; SrcBmp.ScanLine[i]; i < SrcBmp.Height - 1인 경우 then SrcNextRGB:=SrcBmp.ScanLine[i+1] else SrcNextRGB:=SrcBmp.ScanLine[i]; for j := 0 ~ SrcBmp.Width - 1 j > 0이면 시작하고 값:=SrcPreRGB.rgbtRed+ SrcRGB .rgbtRed+SrcNextRGB.rgbtRed; j > 0 다음 IncRGB; 값:=(Value+SrcPreRGB.rgbtRed+SrcRGB.rgbtRed+SrcNextRGB.rgbtRed) div 9; DecRGB;=값; j > 0이면 DecRGB; 값:=SrcPreRGB.rgbtGreen+SrcNextRGB.rgbtGreen; 값:=Value+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen; j < SrcBmp.Width - 1이면 IncRGB; 값:=(Value+SrcPreRGB.rgbtGreen+SrcRGB.rgbtGreen+SrcNextRGB.rgbtGreen) div 9; ; SrcRGB.rgbtGreen:=값; j>0이면 DecRGB; 값:=SrcPreRGB.rgbtBlue+SrcRGB.rgbtBlue+SrcNextRGB.rgbtBlue; j>0이면 IncRGB; .rgbtBlue; j <인 경우 SrcBmp.Width - 1 이후 IncRGB; Value:=(Value+SrcPreRGB.rgbtBlue+SrcNextRGB.rgbtBlue) div 9; SrcRGB.rgbtBlue:=value; end; 선명하게(SrcBmp:TBitmap);var i, j: 정수; SrcPreRGB: pRGBTriple; 값: 정수; 시작 SrcBmp.PixelFormat:=pf24Bit; for i := 0 to SrcBmp.Height - 1 do start SrcRGB := SrcBmp.ScanLine[i]; SrcPreRGB:=SrcBmp.ScanLine[i-1] else SrcPreRGB:=SrcBmp.ScanLine[i]; for j := 0 ~ SrcBmp.Width - 1 j = 1이면 시작하고 Dec(SrcPreRGB); rgbtRed+(SrcRGB.rgbtRed-SrcPreRGB.rgbtRed) div 2; 값:=최대(255,값); SrcRGB.rgbtRed:=값;=SrcRGB.rgbtGreen+(SrcRGB.rgbtGreen-SrcPreRGB.rgbtGreen) 값:= 최대(0,값);값:=최소(255,값); SrcRGB.rgbtGreen:=value; 값:=SrcRGB.rgbtBlue+(SrcRGB.rgbtBlue-SrcPreRGB.rgbtBlue) div 2; 값:=Max(0,Value); SrcRGB.rgbtBlue:= 값; Inc(SrcPreRGB); 끝; [이미지 회전 및 뒤집기] 다음 코드는 24비트 색상에 대해 포인터 이동이 있는 ScanLine을 사용하여 구현됩니다! //90도 회전 절차 Rotate90(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap;begin Bmp:=TBitmap.Create; Bitmap.Height;= Bitmap.PixelFormat; pf24bit; Width:=Bitmap.Width-1; Height:= 0부터 시작 rowIn := Bitmap.ScanLine[j]; = Bmp.ScanLine[i]; Inc(rowOut,Height - j); rowOut^ := rowIn^; end; Bitmap.Assign(Bmp);end;//180도 회전 절차 Rotate180(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Bmp:TBitmap; TBitmap.Create; Bmp.Width := Bmp.Height; Bitmap.Height;= pf24bit; Width:=Bitmap.Width-1; for j := 0 to height do start rowIn := Bitmap.ScanLine[j]; := 0 ~ 너비 do start rowOut := Bmp.ScanLine[Height - j] Inc(rowOut,Width - i); rowOut^ := rowIn^; end; Bitmap.Assign(Bmp);end;//270도 회전 절차 Rotate270(const Bitmap:TBitmap);var i,j:integer; pRGBTriple; 너비, 높이: 정수; 시작 Bmp:=TBitmap.Width; := Bitmap.Height;= Bitmap.Width;= pf24bit; Width:=Bitmap.Height-1; for j := 0부터 rowIn 시작 := Bitmap.ScanLine[j]; for i := 너비가 0이면 rowOut이 시작됩니다. Bmp.ScanLine[Width - i]; rowOut^ := rowIn^; end; Bitmap.Assign(Bmp);end;//모든 각도 함수 RotateBitmap: TBitmap;각도:정수;BackColor:TColor):TBitmap;var i,j,iOriginal,jOriginal,CosPoint,SinPoint: 정수; RowOriginal,RowRotated: SinTheta,CosTheta: 확장; 시작 결과:=TBitmap.Create; Result.Canvas.Brush.Color:=각도 360 ; 각도<0이면 Angle:=360-Abs(Angle); if Angle=0이면 Result.Assign(Bitmap) else if Angle=90이면 시작 Result.Assign(Bitmap); Rotate90(Result);//90도 회전되면 호출합니다. 위의 코드는 직접적으로 끝납니다. else if (Angle>90) and (Angle<180) then start AngleAdd:=90; Angle:=Angle-AngleAdd; end else if Angle=180 then start Result.Assign(Bitmap); Rotate180(Result);//180도 회전된 경우 위 프로세스를 직접 호출합니다. end else if (Angle>180) 각도<270) 시작 AngleAdd:=180; 각도:=Angle-AngleAdd end else if 각도=270 다음 시작 Result.Assign(Bitmap); Rotate270(Result);//270도 회전된 경우 위 프로세스를 직접 호출합니다. else if (Angle>270) and (Angle<360) then start AngleAdd:=270; Angle -AngleAdd; end else AngleAdd:=0; (Angle>0) 및 (Angle<90)이면 SinCos((Angle)을 시작합니다. + AngleAdd) * Pi / 180, SinTheta, CosTheta); if (SinTheta * CosTheta) < 0이면 시작 Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta)); = Round(Abs(Bitmap.Width * SinTheta - Bitmap.Height * CosTheta)); end else start Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta)); Result.Height := Round(Abs(Bitmap.Width * SinTheta + Bitmap.Height * CosTheta)); ; CosTheta:=Abs(CosTheta); SinTheta:=Abs(SinTheta); (AngleAdd=0) 또는 (AngleAdd=180) start CosPoint:=Round(Bitmap.Height*CosTheta); SinPoint:=Round(Bitmap.Height*SinTheta) end else start SinPoint:=Round(Bitmap.Width*CosTheta) ); CosPoint:=Round(Bitmap.Width*SinTheta); for j := 0 Result.Height-1 do start RowRotated := Result.Scanline[j]; for i := 0 to Result.Width-1 do start Case AngleAdd of 0: start jOriginal := Round((j+1)*CosTheta-( i+1-SinPoint)*SinTheta)-1; Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta)-1; end; iOriginal 시작 := Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta )-1; jOriginal := Bitmap.Height-Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta); end; 180: 시작 jOriginal := Bitmap.Height-Round((j+1)*CosTheta-(i+1-SinPoint)*SinTheta) iOriginal := Bitmap.Width-Round((i+1)*CosTheta- (CosPoint-j-1)*SinTheta) 270: iOriginal 시작 := Bitmap.Width-Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta); jOriginal := Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta)-1 ; end; if (iOriginal >= 0) 및 (iOriginal <= Bitmap.Width-1) 및 (jOriginal >= 0) (jOriginal <= Bitmap.Height-1) then start RowOriginal := Bitmap.Scanline[jOriginal]; RowRotated^ := RowOriginal^ Inc(RowRotated); ; end; end;end;//가로 뒤집기 절차 FlipHorz(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Width,Height:Integer;begin Bmp:=TBitmap.Create; Bmp.Width := Bitmap.Height; PixelFormat := pf24bit; 너비:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do start rowIn := Bitmap.ScanLine[j] for i := 0 to Width do start rowOut := Bmp.ScanLine[j]; ,Width - i); rowOut^ := rowIn^; Inc(rowIn); end; FlipVert(const Bitmap:TBitmap);var i,j:Integer; rowIn,rowOut:pRGBTriple; Width,Height:Integer;begin Bmp:=TBitmap.Create; 높이 := Bitmap.Width; Bmp.PixelFormat := pf24bit; Width:=Bitmap.Width-1; Height:=Bitmap.Height-1; for j := 0 to Height do start rowIn := Bitmap.ScanLine[j] for i := 0 to Width do start rowOut := Bmp .ScanLine[높이 - j]; rowOut^ := rowIn^; end; Bitmap.Assign(Bmp);end;[밝기, 대비, 채도 조정] 포인터 이동이 가능한 ScanLine을 사용하여 구현한 코드는 다음과 같습니다! function Min(a, b: 정수): 정수; a < b이면 시작하고 결과 := a else result := b;end;function Max(a, b: 정수): 정수; a > b이면 시작하고 결과: = a else result := b;end;//밝기 조정 절차 BrightnessChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: 정수; SrcRGB, DestRGB: pRGBTriple; start for i := 0 - SrcBmp.Height - 1 SrcRGB := SrcBmp.ScanLine[i]; DestRGB := 0 - SrcBmp.Width - 1 ValueChange > 0이면 시작하고 DestRGB.rgbtRed를 시작합니다. Min(255, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange); DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange); =최대(0, SrcRGB.rgbtRed + ValueChange); DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + ValueChange); DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue + ValueChange) Inc(DestRGB); ; 종료; 종료;//대비 조정 절차 ContrastChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var i, j: 정수; SrcRGB, DestRGB: pRGBTriple;begin for i := 0 to SrcBmp.Height - 1 do start SrcRGB := SrcBmp.ScanLine[i] ; DestRGB := j의 경우 DestBmp.ScanLine[i]; := 0 - SrcBmp.Width - 1 ValueChange>=0이면 시작하고 SrcRGB.rgbtRed >= 128이면 시작하고 DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + ValueChange) else DestRGB.rgbtRed := Max(0 , SrcRGB.rgbtRed - 값 변경); SrcRGB.rgbtGreen >= 128 then DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + ValueChange) else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen - ValueChange) if SrcRGB.rgbtBlue >= 128 then DestRGB.rgbtBlue := Min(255, SrcRGB.rgbtBlue + ValueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue - ValueChange); end else start if SrcRGB.rgbtRed >= 128 then DestRGB.rgbtRed := Max(128, SrcRGB.rgbtRed + 값변경) else DestRGB.rgbtRed := Min(128, SrcRGB.rgbtRed - ValueChange); if SrcRGB.rgbtGreen >= 128 then DestRGB.rgbtGreen := Max(128, SrcRGB.rgbtGreen + ValueChange) else DestRGB.rgbtGreen := Min(128, SrcRGB .rgbt녹색 - ValueChange); if SrcRGB.rgbtBlue >= 128 then DestRGB.rgbtBlue := Max(128, SrcRGB.rgbtBlue + ValueChange) else DestRGB.rgbtBlue := Min(128, SrcRGB.rgbtBlue - ValueChange) end; Inc(대상RGB); end;end;//채도 조정 절차 SaturationChange(const SrcBmp,DestBmp:TBitmap;ValueChange:integer);var Grays: array[0..767] of Integer; Alpha: array[0..255] of Word Gray; x, y: 정수; SrcRGB,DestRGB: pRGBTriple; Byte;beginValueChange:=ValueChange+255;for i := 0 ~ 255 do Alpha[i] := (i * ValueChange) Shr 8;x := 0;for i := 0 ~ 255 dobegin Gray := i - Alpha [i]; 회색[x] := 회색; Inc(x) := 회색[x]; Inc(x);end; for y:= 0에서 SrcBmp.Height - 1 dobegin SrcBmp.ScanLine[Y]; DestRGB:= DestBmp.ScanLine[Y] for x:= 0에서 SrcBmp.Width - 1 회색을 시작하세요 := 회색[SrcRGB.rgbtRed + SrcRGB.rgbtGreen + SrcRGB.rgbtBlue]; if Gray + Alpha[SrcRGB.rgbtRed]>0 then DestRGB.rgbtRed := Min(255,Gray + Alpha[SrcRGB.rgbtRed]) else DestRGB.rgbtRed := 0; rgbtGreen]>0 다음 DestRGB.rgbtGreen := Min(255,Gray + Alpha[SrcRGB.rgbtGreen]) else DestRGB.rgbtGreen := 0; if Gray + Alpha[SrcRGB.rgbtBlue]>0 then DestRGB.rgbtBlue := Min(255,Gray + Alpha[SrcRGB.rgbtBlue] ) else DestRGB.rgbtBlue := 0; Inc(SrcRGB); Inc(DestRGB); end;end; end;//RGB 조정 절차 RGBChange(SrcBmp,DestBmp:TBitmap;RedChange,GreenChange,BlueChange:integer);var SrcRGB, DestRGB: pRGBTriple; i에 대해 시작: = 0에서 SrcBmp.Height- 1에서 SrcRGB를 시작합니다. SrcBmp.ScanLine[i]; DestRGB :=DestBmp.ScanLine[i]; for j := 0 ~ SrcBmp.Width - 1 RedChange> 0이면 시작하고 DestRGB.rgbtRed := Min(255, SrcRGB.rgbtRed + RedChange) else DestRGB.rgbtRed := 최대(0, SrcRGB.rgbtRed + RedChange); if GreenChange> 0이면 DestRGB.rgbtGreen := Min(255, SrcRGB.rgbtGreen + GreenChange) else DestRGB.rgbtGreen := Max(0, SrcRGB.rgbtGreen + GreenChange)이면 BlueChange> 0이면 DestRGB; .rgbtBlue := 최소(255, SrcRGB.rgbtBlue + BlueChange) else DestRGB.rgbtBlue := Max(0, SrcRGB.rgbtBlue + BlueChange); Inc(SrcRGB) end;end;[색상 조정]//RGB<=>BGRprocedure RGB2BGR(const Bitmap:TBitmap);var X: 정수 Y: 정수; pRGBTriple; Byte;begin for Y := 0 to (Bitmap.Height - 1) do start for X := 0 to (Bitmap.Width - 1) do start Color := PRGB^.rgbtRed; = PRGB^.rgbtBlue; PRGB^.rgbtBlue := 색상; 끝; end;end;//회색조(가중치) 절차 Grayscale(const Bitmap:TBitmap);var X: 정수; Y: 정수; PRGB: pRGBTriple; 회색: Byte;begin for Y := 0 ~ (Bitmap.Height - 1) PRGB 시작 := Bitmap.ScanLine[Y]; for X := 0 ~ (Bitmap.Width - 1) 회색 시작 := (77 * 빨간색 + 151 * 녹색 + 28 * 파란색) shr 8; PRGB^.rgbtGreen:=회색; PRGB^.rgbtBlue:=end; ;
이론:
키워드:
그리기 영역 - 즉, 창이 이미지를 표시하는 영역으로, 전체 화면일 수도 있습니다. (일반 창보다 전체 화면에서 그리기 효과가 더 좋습니다.)
중심점 - 즉, 원본 이미지의 그리기 영역에 표시되는 중심점의 좌표입니다(면책조항: 이 개념은 특히 중요합니다).
먼저 이미지 확대에 대해 이야기해 보겠습니다. 일반적인 접근 방식은 이미지를 직접 확대하는 것이지만, 이 글에서 소개하는 방법은 우리가 볼 수 있는 부분만 확대하는 것입니다. 하나는 확대되는 영역입니다. 물론 이 상황에 대해서는 말할 것도 없습니다. 두 번째는 확대된 이미지가 그리기 영역보다 크다는 것입니다. 이것이 오늘 논의할 핵심 주제입니다. 이 경우 먼저 확대된 이미지의 크기를 결정한 다음 크기를 계산해야 합니다. "중심점" 위치와 크기를 기준으로 원본 이미지를 추출하고, 최종적으로 캡처된 이미지를 도면 영역으로 확대합니다.
표시된 이미지가 그리기 영역을 초과하는 경우 이미지 전체를 보려면 이미지를 로밍해야 합니다. 원리는 다음과 같습니다. 마우스가 그리기 영역을 클릭하면 로밍이 시작되고 먼저 마우스의 클릭 위치를 기록한 다음 마우스의 움직임을 감지하고 마우스와 마지막 변위를 기반으로 "중심점"을 계산합니다( 화면 좌표를 원본 이미지 좌표로 변환해야 함) 위의 확대 원리에 따라 원본 이미지에서 표시할 부분을 꺼내 도면 영역에 확대하여 표시합니다.
알고리즘 구현:
1. 이미지 확대
변수 정의:
PZoom: 배율(정수: 100은 100%, 100은 필요에 따라 10000 이상으로 변경될 수 있지만 부동 소수점 숫자는 권장되지 않음)
a, b: 중심점
w, h: 캡처할 원본 이미지의 너비와 높이
x, y: 가로챌 위치(왼쪽 위 모서리)
sw,sh: 원본 이미지의 너비와 높이
p1, p2: 배율
aw,ah : 확대된 이미지의 크기
pw,ph: 그리기 영역 크기
vx,vy: 그리기 영역에 표시되는 위치(왼쪽 위 모서리)
vw, vh : 그리기 영역에 표시되는 크기
ptx, pty: 임시 변수
알려진 변수: PZoom, (a, b), (sw, sh), (p1, p2), (aw, ah), (pw, ph)
계산할 변수: (x,y),(w,h),(vx,vy),(vw,vh)
계산 시작:
aw=Round(PZoom*sw/100);ah=Round(PZoom*sh/100);p1=aw/pwp2=ah/ph// 참고: Round는 Int()와 같이 반올림에 사용됩니다. 언어 ()etc if p1>1이면 w=Round(sw/p1) else w=swif p2>1이면 h=Round(sh/p2) else h=sh// 참고: shr은 오른쪽 시프트 연산자입니다. x=aw shr 1y=bh 대신 ">>1", "div 2", "/2" 또는 "Round(w/2)"를 사용할 수 있습니다. shr 1 // 참고: div는 정수 나누기 연산자입니다 ptx=(w*PZoom) div 100pty=(h*PZoom) div 100// 다음은 그리기 영역에 표시되는 이미지의 크기와 위치를 계산합니다.
변하기 쉬운
Pencent:double; // 확대/축소 비율 wx:double; // 높은 확대 비율 // wx:=pw/ptx hx:=ph/pty if wx>hx then Pencent: =hx else Pencent:=wx; // 이미지의 최종 크기를 가져옵니다. vw:=Round(Pencent*ptx) vh:=Round(Pencent*pty); 그림의 위치 계산 vx:=(pw-vw) div 2 vy:=(ph-vh) div 2;// -------------------- ----------------
이제 두 가지 중요한 작업이 완료되었습니다(x, y), (w, h), (vx, vy), (vw, vh) 작업을 수행하기 위해 Windows API를 선택했습니다.
변하기 쉬운
sDC는 원본 그림의 장치 핸들(DC)이며 임시 장치 핸들 dDC이고 BitBlt(tDC,0,0,w,h,sDC,0,0,SRCCOPY);SetStretchBltMode(dDC) ,STRETCH_DELETESCANS);StretchBlt(dDC ,0,0,vw,vh,tDC,0,0,w,h,SRCCOPY);
마지막으로 표시된 영역을 그립니다.
예를 들어:
BitBlt(GetDC(0),vx,vy,vx+vw,xy+vh,dDC,0,0,SRCCOPY);
2. 이미지 로밍
먼저 세 가지 전역 변수를 정의합니다.
FBeginDragPoint :TPoint; // 마우스가 드래그를 시작하는 위치를 기록합니다. FBeginDragSBPoint :TPoint; // "중심점" 위치를 기록합니다. FBeginDrag :boolean; // "드래그" a, b가 시작되었는지 여부: 정수; " 위치
마우스 왼쪽 버튼을 클릭하면 마우스 위치와 "중심점" 위치를 기록하고 FBeginDrag를 true로 설정합니다.
마우스 오른쪽 버튼이 나타나면 FBeginDrag를 false로 설정하세요.
마우스가 움직일 때 FBeginDrag가 false로 판단되며 true인 경우에는 다음 처리가 수행됩니다.
X와 Y가 마우스의 현재 위치라고 가정합니다.
a=FBeginDragPoint.X-((X-FBeginDragPoint.X)*100) div PZoomb=FBeginDragPoint.Y-((Y-FBeginDragPoint.Y)*100) div PZoom
마지막으로 위에 소개한 이미지를 활용해 이미지를 확대해서 표시해 보세요.
팁:
1. 이미지가 큰 경우 델파이의 비트맵 객체를 사용할 때 메모리 오버플로 오류가 발생합니다. 이 경우 다음과 같이 설정할 수 있습니다.
bitImage:=TBitmap.Create; bitImage.PixelFormat:=pf24bit;
2. 이미지가 창 크기에 자동으로 맞춰지도록 하려면 다음 코드를 참조하세요.
var p1,p2 :double;begin p1:=pw/sw; p2:=ph/sw; if p1>p2 then PZoom:=Round(p2*100) else PZoom:=Round(p1*100); 0이면 PZoom:=100;end;
Delphi 회색조 이미지 픽셀 색상 밝기 처리
이미지 처리에서는 속도가 중요합니다. 따라서 TVczhBitmap을 얻으려면 TBitmap을 다시 처리해야 합니다. 이는 GetPixels 및 SetPixels가 너무 느리기 때문에 다른 방법을 사용해야 하기 때문입니다.
단위 untBitmapProc; 인터페이스는 TVczhBitmap=class(TBitmap) 개인 데이터:PByteArray; 프로시저 SetFormat; 프로시저 SetBytes(X,Y:Integer; :Byte); function GetBytes(X,Y:Integer):Byte 보호 게시 생성자; 공용 속성 Bytes[X,Y:Integer]:Byte read SetBytes; 프로시저 LoadFromFile(FileName:String); end; 구현 프로시저 TVczhBitmap.SetFormat; TVczhBitmap.GetBytePointer(X,Y:Integer):PByte는 Line<>Y인 경우 시작됩니다. start Line:=Y; Data:=ScanLine[Y]; Longint(result):=Longint(Data)+X; 프로시저 TVczhBitmap.SetBytes(X,Y:Integer;Value:Byte); X,Y)^:=값; 함수 TVczhBitmap.GetBytes(X,Y:Integer):Byte; result:=GetBytePointer(X,Y)^; 생성자 TVczhBitmap.Create; Line:=-1; 상속된 LoadFromFile(파일 이름); ; 라인:=-1; 프로시저 TVczhBitmap.ToGray; B:Byte; Y:=0에서 Height-1까지 do X:=0에서 Width-1까지 do start R:=0 for B:=0 to 2 do R:=R+GetBytes(X*3+ B,Y); B:=0 ~ 2 do SetBytes(X*3+B,Y,R div 3) end;
그런 다음 여러 양식을 만들어야 합니다. 첫 번째는 그림을 표시하는 데 사용되고 두 번째는 그림을 처리하는 데 사용됩니다. 다른 모든 양식은 두 번째 양식에서 상속되며 실제 처리 방법을 포함합니다.
먼저 두 번째 창을 살펴보겠습니다.
단위 untProc; 인터페이스는 Windows, 메시지, SysUtils, 변형, 그래픽, 컨트롤, 양식, 대화 상자, ExtCtrls, untBitmapProc, StdCtrls, ComCtrls를 사용합니다. type TfrmProcessor = class(TForm) pbBar: TPaintBox: TButton; 프로시저 FormCreate(발신자: TObject); 절차 FormDestroy(Sender: TObject); 프로시저 pbBarPaint(Sender: TObject); private { Private 선언 } BarData:array[0 ..255]바이트; TVczhBitmap; 절차 DrawBar; var frmProcessor: TfrmProcessor; 구현 {$R *.dfm}은 untViewer를 사용합니다. TfrmProcessor.DrawBar; var I:Integer; Bar.Canvas.FillRect(Bar.Canvas.ClipRect); I:=1 to 255 do Bar.Canvas.LineTo(I,255-BarData[I]); TfrmProcessor.FormCreate(보내기: TObject); Bar.Width:=256; Bar.Canvas.Brush.Color:=clWhite; =bsSolid; end; 절차 TfrmProcessor.FormDestroy(Sender: TObject); end; 절차 TfrmProcessor.FormShow(Sender: TObject); start for I:=0 to 255 do BarData[I]:=I; DrawBar; .Canvas.Draw(0,0,Bar); end; 절차 TfrmProcessor.Button1Click(Sender: TObject); var X,Y:Integer; Y:=0에서 Buffer.Height-1로 시작 X:=0에서 Buffer.Width*3-1로 수행 Played.Bytes[X,Y]:=BarData[Buffer.Bytes[ X,Y]]; frmViewer.FormPaint(frmViewer);
그런 다음 이를 상속하는 창을 만든 다음 BarData[]를 조정하고 Apply를 눌러 결과를 확인합니다.
이제 이미지 처리를 시작합니다. 특정 효과는 샘플 프로그램을 참조하세요.
1. 색상 반전.
회색조 이미지의 색상 범위는 0부터 255까지이므로 색상을 반전하려면 255에서 색상 값을 빼서 반전된 색상을 얻을 수 있습니다.
var I:Integer; I:=0 ~ 255 do BarData[I]:=255-I;//255에서 색상 값 빼기 DrawBar;
2. 색상 범위를 좁혀 밝기를 높이거나 약화시킵니다.
색상은 원래 0~255 입니다. 예를 들어 0에서 16까지 범위를 조정하면 이미지가 상당히 어두워집니다. 시작 값을 a로 설정하고 종료 값을 b로 설정한 다음 새 색상 값 New=a+(b-1)*Old/255를 설정할 수 있습니다. 이렇게 하면 원래 색상 순서를 손상시키지 않고 밝기가 변경됩니다. 코드는 다음과 같습니다
var I:Integer; I:=0 ~ 255 do BarData[I]:=(255-sbMin.Position)+Round((sbMin.Position-sbMax.Position)/255*I); ); Button1Click(버튼1);
여기의 sbMin.Position과 sbMaxPosition은 모두 반전되었습니다. 따라서 255를 사용하여 빼십시오.
3. 특정 범위 내에서 색상 범위를 늘리십시오.
이미지 자체의 색상 범위가 작은 경우 이 방법을 사용하여 이미지의 대비를 높일 수 있으며 이는 이미지 분석에 도움이 됩니다. 구체적인 방법:
a 값을 시작 값으로 선택하고 b 값을 종료 값으로 선택한 후 다음 공식에 따라 변형합니다.
| 0 (X<=a)
f(X)= | 255/(바)*(Xa)
255(X>=b)
var I:Integer; I:=0 ~ 255에 대해 시작 I<=sbMin.Position then BarData[I]:=0 else if I>=sbMax.Position then BarData[I]:=255 else BarData[I ]:=Round(255/(sbMax.Position-sbMin.Position)*(I-sbMin.Position)) end; pbBarPaint(pbBar); Button1Click(Button1);
4. 흑백사진으로 변환
세 번째 함수를 사용하면 b<=a일 때 이미지의 색상이 검정색을 제외한 흰색임을 알 수 있습니다. 이 작업의 이점은 직접 표시될 수 없습니다. 이는 가장자리 감지와 같은 고급 이미지 처리에 있어서만 효과적입니다. 본 예는 세 번째 방법의 수식을 이용하여 변형이 가능하므로 자세한 설명은 생략한다.
5. 지수적 밝기 조정
이 그래프의 정의역은 [0,1]이고, 값의 범위도 [0,1]이라고 가정합니다. 그런 다음 함수 f(x)=x^c를 정의하면 f(x)의 이미지는 위에 표시된 섹션을 갖습니다. 마우스를 사용하여 다시 작동 할 때, 우리는 지점 p (a, b)를 가져간 다음 f (x)가 지점 p를 통과 한 다음 c = ln (b)/ln (a)을 통과하게 할 수 있습니다. C를 사용하면 색상으로 작동 할 수 있습니다.
new = (Old/255)^C*255 = EXP (ln (old/255)*255 var eac : exer; /255; EC; LN (EB)/LN (EA); bardata [exp (i/255)*255;
이렇게하면 이미지의 밝기가 조정됩니다.
델파이 그래픽에 특수 효과를 표시하기위한 팁
개요
---- 현재 많은 학습 소프트웨어 및 게임 CD에서는 종종 다양한 것을 볼 수 있습니다.
그래픽 디스플레이 기술은 그래픽 움직임, 인터레이스, 빗방울 모양, 블라인드, 빌딩 블록 스태킹 및 기타 디스플레이 방법에 의존하여 사진을 더욱 활기차고 청중에게 매력적으로 만듭니다. 이 기사는 델파이에서 다양한 그래픽 디스플레이 기술을 구현하는 방법을 살펴 봅니다.
기본 원칙
---- Delphi에서는 이미지를 표시하는 것이 매우 간단합니다. 형식으로 시간을 정의하고 사진 속성을 설정 한 다음 유효한 .ico, .bmp, .emf 또는 .wmf 파일,로드를 선택하십시오. 선택한 파일은 시계 구성 요소에 표시됩니다. 그러나 이것은 그래픽을 형태로 직접 표시하며 전혀 기술이 없습니다. 그래픽 디스플레이에 고유 한 효과가 있도록하기 위해 다음 단계를 수행 할 수 있습니다.
---- 타이밍 구성 요소를 정의하고 먼저 타임 지 구성 요소에 표시 할 그래픽을로드합니다. 즉, 디스크의 그래픽 내용을 그래픽 캐시로 메모리에로드하십시오.
---- 타임 지 구성 요소의 그래픽과 동일한 크기의 새 비트 맵 객체를 만듭니다.
---- 캔버스의 저작권 기능 (하나의 캔버스의 직사각형 영역을 다른 캔버스의 직사각형 영역에 복사), 기술을 사용하고 동적으로 형성
파일 내용을 비트 맵으로 변환 한 다음 비트 맵을 양식에 표시합니다.
---- 구현 방법
다양한 그래픽 디스플레이 기술이 다음과 같습니다.
1. 푸시-풀 효과
화면을 위쪽, 아래, 왼쪽 및 오른쪽 방향에서 표현할 수 있도록 그래픽을 당기고 동시에이 효과는 4 가지 유형의 원래 그래픽을 덮을 수 있습니다. 왼쪽을 당기고 오른쪽을 당기십시오. 그러나 원리는 비슷하며 풀업 효과를 예로 들어보십시오.
원리 : 먼저, 임시 그래픽에 배치 된 첫 번째 수평선을 비트 맵의 마지막 그래픽으로 이동 한 다음, 임시 그래픽의 첫 두 수평선을 마지막 두 비트 맵으로 이동시킵니다 그런 다음 모든 그래픽 데이터가 이동 될 때까지 처음 3 개와 4 줄을 이동하십시오. 움직이는 과정에서 표시된 비트 맵이 하단에서 상단으로 떠 오르면 풀업 효과를 얻을 수 있습니다.
프로그램 알고리즘 :
TORMICT (Tobject) : = image1.Height; i : = 0에서 bmpheight는 newbmp.canvas.copyrect를 시작합니다 (rect (0, bmpheight-i, bmpwidth, bmpheight), image1.canvas, rect (0,0, bmpwidth, i)); , 종말;
2. 수직 비틀 거리는 효과
원리 : 홀수 스캔 라인이 두 부분으로 표시 될 그래픽을 분할하고 균등 한 스캔 라인은 하단에서 상단으로 이동하며 동시에 수행됩니다. 화면에서 상단 및 하단에 나타나는 가벼운 그래픽이 완전히 깨끗해질 때까지 화면의 중앙을 향해 이동한다는 것을 알 수 있습니다.
프로그램 알고리즘 :
절차 tform1 BMPHEIGHT : = Height; i : = 0; i <= bmpheight는 j : = i를 시작합니다. bmpheight-i+j-1, bmpwidth, bmpheight-i+j); (0, bmpeight-j, bmpeight-j+1), image1.canvas (0, ij, bmpwidth, i-j+1); (120,100, I+2;
3. 수평 비틀 거리는 효과
원리 : 그래픽이 두 그룹으로 나뉘어져 있음을 제외하고는 수직 인터레이스 효과와 동일한 원리입니다.
프로그램 알고리즘 :
절차 tform1 BMPHEIGHT : = Height; i : = 0; i <= bmpwidth는 j : = i를 시작합니다. I+J-1,0, BMPWIDTH-I+J, BMPHEIGHT); (BMPWIDTH-J, 0, BMPWIDTH-J+1), image1.Canvas (ij, 0, i-j+1, bmpheight); (120,100, I+2;
4. 빗방울 효과
원리 : 임시 그래픽의 마지막 스캔 라인을 가시 보이는 비트 맵의 첫 번째 스캔 라인으로 순서대로 이동 하여이 스캔 라인이 화면에 추적을 남길 수 있습니다. 그런 다음 임시 그래픽의 두 번째 스캔 라인이 시행 한 비트 맵의 첫 번째 스캔 라인으로 이동합니다. 나머지 스캔 라인의 경우.
프로그램 알고리즘 :
절차 tform1 BMPHEIGHT : = Height; i : = bmpheight downto 1 j : = 1 ~ i는 newbmp.canvas.copyrect를 시작합니다 (rect (0, j-1, bmpwidth, j), image1.canvas, rect (0, i-1, bmpwidth, i));
5. Louvres 효과
원칙 : 임시 그래픽에 배치 된 데이터를 여러 그룹으로 나눈 다음 각 그룹이 첫 번째 그룹에서 첫 번째 스캔 라인을 보이는 비트 맵의 해당 위치로 이동시킵니다. 시간은 두 번째 스캔 라인을 이동 한 다음 세 번째 및 네 번째 스캔 라인을 이동하십시오.
프로그램 알고리즘 :
TFORM1. 높이 : = image1.Height; bmpwidth : = xgroup; xcount; -1, bmpwidth, xcount*j+i), image1.canvas, rect (xcount*J+I-1, Xcount*J+I);
6. 빌딩 블록 효과
원리 : 빗방울 효과의 변화는 빌딩 블록 효과가 스캔 라인뿐만 아니라 매번 그래픽을 움직입니다.
프로그램 알고리즘 :
절차 tform1 BMPHEIGHT : = Height; i : = bmpheight; i> 0은 j : = 10을 시작합니다. , bmpwidth, i); 끝;
결론
위의 그래픽 디스플레이 효과는 모두 컴퓨터에 전달되었습니다. 잘 작동합니다.
델파이를 사용하여 이미지 돋보기 구현
하나의 타이밍 구성 요소의 이름 속성에 두 개의 타임 매지 구성 요소가 이미지 1으로 설정되어 원래 이미지 디스플레이의 캐리어 역할을합니다. 다른 타임 지 구성 요소에는 이름 속성이 image2로 설정되어 있으며 확대 된 이미지를 표시합니다.
이 예제의 핵심은 StretchBLT 함수가 로컬 이미지 확대를 달성하는 데 사용됩니다.
절차 tform1.Image1mouseMove (Sender : Tobject; Shift : TshiftState; X, Y : Integer); StretchBlt 시작 (image2.canvas.handle, 0,0, image2.width, image2.height, image1.canvas.handle ,, y- 20,40,40, srccopy); screen.cursors [1] : = loadcursorfromfile ( 'magnify.cur');
이 프로그램은 먼저 StretchBLT 함수를 호출하고 마우스의 현재 위치를 중심 지점으로 사용하고 측면 길이가 40 인 Image1 구성 요소의 부분 이미지를 선택하고 이미지 2 구성 요소로 부분 이미지를 확대합니다. 그런 다음 Image2 구성 요소의 새로 고침 메소드를 호출하여 Image2 구성 요소의 표시를 새로 고치십시오. 마지막으로 마우스 포인터를 새로운 모양으로 설정하십시오.
프로그램 코드는 다음과 같습니다.
Unit1; 인터페이스 우주, 메시지, sysutils, 변형, 클래스, 그래픽, 컨트롤, 양식, 대화, extctrls, type tform1 = 클래스 (tform) 이미지 2 : Timage image1mousemove; x, y : 정수); formmouseMove (sender : tobject; shift : tshiftState;; shift : tshiftState; X, y : Integer); thingtretchblt (image2.canvas.handle, 0,0, image2.width, image1.canvas.handle, x-20, y-20,40,40, srccopy); ] : = loadCursOrfromFile ( 'magnify.cur'); self.cursor : = 1; end; procedure tform1.formmouseMove (발신자 : tobject; shift : tshiftState; x, y : integer); screen.cursors [1] : = crdefault : = 1; end; end .
파일을 저장 한 다음 F9 키를 눌러 프로그램을 실행하면 프로그램이 실행됩니다.
돋보기 이미지는 우수한 이미지보기 소프트웨어의 필수 기능입니다.
이 글이 모든 사람의 델파이 프로그래밍에 도움이 되기를 바랍니다.