📄 imgutil.pas
字号:
{$R-} // Turn off Range Checking because of ARRAY[0..0] construct below
unit ImgUtil;
// The new algorithms are 5 to 8 imes faster (dirty but fast) and they
// not need so many memory (if the bitmap very large you have a problem ->
// windows must use the swapfile).
{$WARNINGS OFF}
{$HINTS OFF}
interface
uses Windows, Graphics,math;
procedure SpiegelnHorizontal (Bitmap:TBitmap);
procedure SpiegelnVertikal (Bitmap:TBitmap);
procedure Drehen90Grad (Bitmap:TBitmap);
procedure Drehen270Grad (Bitmap:TBitmap);
procedure Drehen180Grad (Bitmap:TBitmap);
FUNCTION Rotate90(Bitmap:TBitmap): TBitmap;
procedure ConvertBitmapToGrayscale (const Bmp: TBitmap);
procedure ChangeTrans(abmp:Tbitmap;colorf:Tcolor);
function Blend(C1, C2: TColor; W1: Integer): TColor;
procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: integer = 1);
function GetHSV(c:Tcolor):integer;
implementation
USES dialogs,
Classes, // Rect
SysUtils;
TYPE
EBitmapError = CLASS(Exception);
TRGBArray = ARRAY[0..0] OF TRGBTriple;
pRGBArray = ^TRGBArray;
procedure ConvertBitmapToGrayscale (const Bmp: TBitmap);
var
x, y, Gray: Integer;
Row: PRGBArray;
begin
Bmp.PixelFormat := pf24Bit;
for y := 0 to Bmp.Height - 1 do
begin
Row := Bmp.ScanLine[y];
for x := 0 to Bmp.Width - 1 do
begin
Gray := (Row[x].rgbtRed + Row[x].rgbtGreen + Row[x].rgbtBlue) div 3;
Row[x].rgbtRed := Gray;
Row[x].rgbtGreen := Gray;
Row[x].rgbtBlue := Gray;
end;
end;
end;
procedure ChangeTrans(abmp:Tbitmap;colorf:Tcolor);
var x, y, Gray: Integer;
Row: PRGBArray;
r,g,b:integer;
begin
r:=GetRValue(colorf);
g:=GetGValue(colorf);
b:=GetBValue(colorf);
if (abmp.PixelFormat<>pf24bit) then
abmp.PixelFormat:=pf24bit;
for y := 0 to aBmp.Height - 1 do begin
Row := aBmp.ScanLine[y];
for x := 0 to aBmp.Width - 1 do begin
if (Row[x].rgbtRed=255) and
(Row[x].rgbtGreen=0) and
(Row[x].rgbtBlue =255) then begin
Row[x].rgbtRed:=r;
Row[x].rgbtGreen:=g;
Row[x].rgbtBlue :=b;
end;
end;
end;
end;
procedure SpiegelnHorizontal(Bitmap:TBitmap);
var i,j,w,n : INTEGER;
RowIn : pRGBArray;
RowOut: pRGBArray;
temp:Tbitmap;
begin
temp:=Tbitmap.create;
temp.Width := Bitmap.Width;
temp.Height := Bitmap.Height;
temp.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now
n:=bitmap.width;
for j := 0 to Bitmap.Height-1 do begin
rowout := temp.Scanline[j];
rowin := Bitmap.Scanline[j];
for i := 0 to n-1 do rowout[i] := rowin[n-1-i];
end;
bitmap.Assign(temp);
temp.free;
end;
procedure SpiegelnVertikal(Bitmap : TBitmap);
var j,w : INTEGER;
help : TBitmap;
begin
help := TBitmap.Create;
help.Width := Bitmap.Width;
help.Height := Bitmap.Height;
help.PixelFormat := Bitmap.PixelFormat;
w := Bitmap.Width*sizeof(TRGBTriple);
for j := 0 to Bitmap.Height-1 do move(Bitmap.Scanline[j]^,Help.Scanline[Bitmap.Height - 1 - j]^,w);
Bitmap.Assign(help);
help.free;
end;
type THelpRGB = packed record
rgb : TRGBTriple;
dummy : byte;
end;
procedure Drehen270Grad(Bitmap:TBitmap);
var aStream : TMemorystream;
header : TBITMAPINFO;
dc : hDC;
P : ^THelpRGB;
x,y,b,h : Integer;
RowOut: pRGBArray;
BEGIN
aStream := TMemoryStream.Create;
aStream.SetSize(Bitmap.Height*Bitmap.Width * 4);
with header.bmiHeader do begin
biSize := SizeOf(TBITMAPINFOHEADER);
biWidth := Bitmap.Width;
biHeight := Bitmap.Height;
biPlanes := 1;
biBitCount := 32;
biCompression := 0;
biSizeimage := aStream.Size;
biXPelsPerMeter :=1;
biYPelsPerMeter :=1;
biClrUsed :=0;
biClrImportant :=0;
end;
dc := GetDC(0);
P := aStream.Memory;
GetDIBits(dc,Bitmap.Handle,0,Bitmap.Height,P,header,dib_RGB_Colors);
ReleaseDC(0,dc);
b := bitmap.Height; // rotate
h := bitmap.Width; // rotate
bitmap.Width := b;
bitmap.height := h;
for y := 0 to (h-1) do begin
rowOut := Bitmap.ScanLine[(h-1)-y];
P := aStream.Memory; // reset pointer
inc(p,y);
for x := (b-1) downto 0 do begin
rowout[x] := p^.rgb;
inc(p,h);
end;
end;
aStream.Free;
end;
procedure Drehen90Grad(Bitmap:TBitmap);
var aStream : TMemorystream;
header : TBITMAPINFO;
dc : hDC;
P : ^THelpRGB;
x,y,b,h : Integer;
RowOut: pRGBArray;
BEGIN
aStream := TMemoryStream.Create;
aStream.SetSize(Bitmap.Height*Bitmap.Width * 4);
with header.bmiHeader do begin
biSize := SizeOf(TBITMAPINFOHEADER);
biWidth := Bitmap.Width;
biHeight := Bitmap.Height;
biPlanes := 1;
biBitCount := 32;
biCompression := 0;
biSizeimage := aStream.Size;
biXPelsPerMeter :=1;
biYPelsPerMeter :=1;
biClrUsed :=0;
biClrImportant :=0;
end;
dc := GetDC(0);
P := aStream.Memory;
GetDIBits(dc,Bitmap.Handle,0,Bitmap.Height,P,header,dib_RGB_Colors);
ReleaseDC(0,dc);
b := bitmap.Height; // rotate
h := bitmap.Width; // rotate
bitmap.Width := b;
bitmap.height := h;
for y := 0 to (h-1) do begin
rowOut := Bitmap.ScanLine[y];
P := aStream.Memory; // reset pointer
inc(p,y);
for x := 0 to (b-1) do begin
rowout[x] := p^.rgb;
inc(p,h);
end;
end;
aStream.Free;
end;
procedure Drehen180Grad(Bitmap:TBitmap);
var i,j : INTEGER;
rowIn : pRGBArray;
rowOut: pRGBArray;
help : TBitmap;
begin
help := TBitmap.Create;
help.Width := Bitmap.Width;
help.Height := Bitmap.Height;
help.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now
FOR j := 0 TO Bitmap.Height - 1 DO BEGIN
rowIn := Bitmap.ScanLine[j];
rowOut := help.ScanLine[Bitmap.Height - j - 1];
FOR i := 0 TO Bitmap.Width - 1 DO rowOut[Bitmap.Width - i - 1] := rowIn[i]
END;
bitmap.assign(help);
help.free;
end;
FUNCTION Rotate90(Bitmap:TBitmap): TBitmap;
VAR i,j : INTEGER;
rowIn : pRGBArray;
BEGIN
IF Bitmap.PixelFormat <> pf24bit then
exit;
RESULT := TBitmap.Create;
RESULT.Width := Bitmap.Height;
RESULT.Height := Bitmap.Width;
RESULT.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now
// Out[j, Right - i - 1] = In[i, j]
FOR j := 0 TO Bitmap.Height - 1 DO BEGIN
rowIn := Bitmap.ScanLine[j];
FOR i := 0 TO Bitmap.Width - 1 DO
pRGBArray(RESULT.ScanLine[Bitmap.Width - i - 1])[j] := rowIn[i]
END;
END;
function Blend(C1, C2: TColor; W1: Integer): TColor;
var
W2, A1, A2, D, F, G: Integer;
begin
if C1 < 0 then C1 := GetSysColor(C1 and $FF);
if C2 < 0 then C2 := GetSysColor(C2 and $FF);
if W1 >= 100 then D := 1000
else D := 100;
W2 := D - W1;
F := D div 2;
A2 := C2 shr 16 * W2;
A1 := C1 shr 16 * W1;
G := (A1 + A2 + F) div D and $FF;
Result := G shl 16;
A2 := (C2 shr 8 and $FF) * W2;
A1 := (C1 shr 8 and $FF) * W1;
G := (A1 + A2 + F) div D and $FF;
Result := Result or G shl 8;
A2 := (C2 and $FF) * W2;
A1 := (C1 and $FF) * W1;
G := (A1 + A2 + F) div D and $FF;
Result := Result or G;
end;
const
GRADIENT_CACHE_SIZE = 16;
type
PRGBQuad = ^TRGBQuad;
TRGBQuad = Integer;
PRGBQuadArray = ^TRGBQuadArray;
TRGBQuadArray = array [0..0] of TRGBQuad;
var
GradientCache: array [0..GRADIENT_CACHE_SIZE] of array of TRGBQuad;
NextCacheIndex: Integer = 0;
function FindGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
begin
Assert(Size > 0);
Result := GRADIENT_CACHE_SIZE - 1;
while Result >= 0 do
begin
if (Length(GradientCache[Result]) = Size) and
(GradientCache[Result][0] = CL) and
(GradientCache[Result][Length(GradientCache[Result]) - 1] = CR) then Exit;
Dec(Result);
end;
end;
function MakeGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
var
R1, G1, B1: Integer;
R2, G2, B2: Integer;
R, G, B: Integer;
I: Integer;
Bias: Integer;
begin
Assert(Size > 0);
Result := NextCacheIndex;
Inc(NextCacheIndex);
if NextCacheIndex >= GRADIENT_CACHE_SIZE then NextCacheIndex := 0;
R1 := CL and $FF;
G1 := CL shr 8 and $FF;
B1 := CL shr 16 and $FF;
R2 := CR and $FF - R1;
G2 := CR shr 8 and $FF - G1;
B2 := CR shr 16 and $FF - B1;
SetLength(GradientCache[Result], Size);
Dec(Size);
Bias := Size div 2;
if Size > 0 then
for I := 0 to Size do
begin
R := R1 + (R2 * I + Bias) div Size;
G := G1 + (G2 * I + Bias) div Size;
B := B1 + (B2 * I + Bias) div Size;
GradientCache[Result][I] := R + G shl 8 + B shl 16;
end
else
begin
R := R1 + R2 div 2;
G := G1 + G2 div 2;
B := B1 + B2 div 2;
GradientCache[Result][0] := R + G shl 8 + B shl 16;
end;
end;
function GetGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
begin
Result := FindGradient(Size, CL, CR);
if Result < 0 then Result := MakeGradient(Size, CL, CR);
end;
procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: integer = 1);
const
// GRAD_MODE: array [0..1] of DWORD = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V);
W: array [0..1] of Integer = (2, 1);
H: array [0..1] of Integer = (1, 2);
type
TriVertex = packed record
X, Y: Longint;
R, G, B, A: Word;
end;
var
V: array [0..1] of TriVertex;
GR: GRADIENT_RECT;
Size, I, Start, Finish: Integer;
GradIndex: Integer;
R, CR: TRect;
Brush: HBRUSH;
begin
if not RectVisible(DC, ARect) then Exit;
ClrTopLeft := ColorToRGB(ClrTopLeft);
ClrBottomRight := ColorToRGB(ClrBottomRight);
{ Have to do it manually if msimg32.dll is not available }
GetClipBox(DC, CR);
if Kind = 0 then begin
Size := ARect.Right - ARect.Left;
if Size <= 0 then Exit;
Start := 0; Finish := Size - 1;
if CR.Left > ARect.Left then Inc(Start, CR.Left - ARect.Left);
if CR.Right < ARect.Right then Dec(Finish, ARect.Right - CR.Right);
R := ARect; Inc(R.Left, Start); R.Right := R.Left + 1;
end else begin
Size := ARect.Bottom - ARect.Top;
if Size <= 0 then Exit;
Start := 0; Finish := Size - 1;
if CR.Top > ARect.Top then Inc(Start, CR.Top - ARect.Top);
if CR.Bottom < ARect.Bottom then Dec(Finish, ARect.Bottom - CR.Bottom);
R := ARect; Inc(R.Top, Start); R.Bottom := R.Top + 1;
end;
GradIndex := GetGradient(Size, ClrTopLeft, ClrBottomRight);
for I := Start to Finish do begin
Brush := CreateSolidBrush(GradientCache[GradIndex][I]);
Windows.FillRect(DC, R, Brush);
OffsetRect(R, Integer(Kind = 0), Integer(Kind = 1));
DeleteObject(Brush);
end;
end;
function GetHSV(c:Tcolor):integer;
var
Delta: double;
Min : double;
R,G,B: integer;
ss,vv,hh:double;
H,S,V:Integer;
begin
R := C and $FF;
G := C shr 8 and $FF;
B := C shr 16 and $FF;
Min := MinIntValue( [R, G, B] );
V := MaxIntValue( [R, G, B] );
Delta := V - Min;
if V = 0 then ss := 0
else ss := Delta/V;
if ss = 0 then hh := 0
else begin
if R = V then hh := 60 * (G - B) / Delta
else if G = V then hh := 120 + 60 * (B - R) / Delta
else if B = V then hh := 240 + 60 * (R - G) / Delta;
if hh < 0 then hh := hh + 360;
end;
S := round(ss*255);
H := round(hh*255/360);
if (r<160) and (g<160) and (b<160) then s:=200;
result:=s;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -