📄 teefilterseditor.pas
字号:
if Filters.Items.Count>0 then
begin
Filters.ItemIndex:=0;
FiltersClick(Self);
Preview;
end;
end;
{ TFilter }
procedure TFilter.Apply;
begin
Apply(Rect(0,0,Bitmap.Width-1,Bitmap.Height-1));
end;
procedure TFilter.Apply(const R:TRect);
begin
CalcLines;
end;
class procedure TFilter.ApplyTo(Bitmap: TBitmap);
var tmp : TFilter;
begin
tmp:=Create(nil);
try
tmp.Bitmap:=Bitmap;
tmp.Apply;
finally
tmp.Free;
end;
end;
class function TFilter.Description:String;
begin
result:=ClassName;
end;
procedure TFilter.CalcLines;
var y : Integer;
Dif : Integer;
tmp : Integer;
begin
Bitmap.PixelFormat:=pf24Bit;
tmp:=Bitmap.Height;
SetLength(Lines,tmp);
if tmp>1 then
begin
Lines[0]:=Bitmap.ScanLine[0];
Lines[1]:=Bitmap.ScanLine[1];
Dif:=Integer(Lines[1])-Integer(Lines[0]);
for y:=2 to tmp-1 do
Lines[y]:=Pointer(Integer(Lines[y-1])+Dif);
end;
end;
procedure TFilter.CreateEditor(AParent:TWinControl; AChanged:TNotifyEvent);
begin // No properties (abstract)
FChanged:=AChanged;
end;
{ TInvertFilter }
procedure TInvertFilter.Apply(const R:TRect);
var x,y : Integer;
begin
inherited;
for y:=R.Top to R.Bottom do
for x:=R.Left to R.Right do
with Lines[y,x] do
begin
rgbtBlue:=255-rgbtBlue;
rgbtGreen:=255-rgbtGreen;
rgbtRed:=255-rgbtRed;
end;
end;
class function TInvertFilter.Description: String;
begin
result:='Invert';
end;
{ TGrayScaleFilter }
procedure TGrayScaleFilter.Apply(const R:TRect);
var x,y : Integer;
tmp : Byte;
begin
inherited;
case Method of
gmSimple: for y:=R.Top to R.Bottom do
for x:=R.Left to R.Right do
with Lines[y,x] do
begin
tmp:=(rgbtBlue+rgbtGreen+rgbtRed) div 3;
rgbtBlue:=tmp;
rgbtGreen:=tmp;
rgbtRed:=tmp;
end;
gmEye: for y:=R.Top to R.Bottom do
for x:=R.Left to R.Right do
with Lines[y,x] do
begin
tmp:=Round( (0.30*rgbtRed) +
(0.59*rgbtGreen) +
(0.11*rgbtBlue));
rgbtBlue:=tmp;
rgbtGreen:=tmp;
rgbtRed:=tmp;
end;
gmEye2: for y:=R.Top to R.Bottom do
for x:=R.Left to R.Right do
with Lines[y,x] do
begin
tmp:=(11*rgbtRed+16*rgbtGreen+5*rgbtBlue) div 32;
rgbtBlue:=tmp;
rgbtGreen:=tmp;
rgbtRed:=tmp;
end;
end;
end;
class function TGrayScaleFilter.Description: String;
begin
result:='Gray scale';
end;
{ TMosaicFilter }
constructor TMosaicFilter.Create(Collection:TCollection);
begin
inherited;
FAmount:=8;
IOnlyPositive:=True;
end;
procedure TMosaicFilter.Apply(const R:TRect);
var x, y,
xx,yy : Integer;
tmpDims : Single;
tmpX,
tmpY : Integer;
ar,
ag,
ab : Integer;
Line : PRGBTriples;
begin
inherited;
if Amount=0 then exit;
tmpDims:=1.0/Sqr(Amount);
for y:=0 to ((R.Bottom-R.Top) div Amount)-1 do
for x:=0 to ((R.Right-R.Left) div Amount)-1 do
begin
tmpY:=Amount*y;
tmpX:=Amount*x;
ar:=0;
ag:=0;
ab:=0;
for yy:=0 to Amount-1 do
begin
Line:=Lines[tmpY+yy+R.Top];
for xx:=0 to Amount-1 do
with Line^[tmpX+xx+R.Left] do
begin
Inc(ar,rgbtRed);
Inc(ag,rgbtGreen);
Inc(ab,rgbtBlue);
end;
end;
ar:=Round(ar*tmpDims);
ag:=Round(ag*tmpDims);
ab:=Round(ab*tmpDims);
if ar>255 then ar:=255;
if ag>255 then ag:=255;
if ab>255 then ab:=255;
for yy:=0 to Amount-1 do
begin
Line:=Lines[tmpY+yy+R.Top];
for xx:=0 to Amount-1 do
with Line^[tmpX+xx+R.Left] do
begin
rgbtBlue:=ab;
rgbtGreen:=ag;
rgbtRed:=ar;
end;
end;
end;
end;
class function TMosaicFilter.Description: String;
begin
result:='Mosaic';
end;
{ TFlipFilter }
procedure TFlipFilter.Apply(const R:TRect);
var tmp : TRGBTriple;
tmpH,
tmpY,
x,y : Integer;
begin
inherited;
tmpH:=R.Bottom-R.Top;
{$R-}
for y:=0 to (tmpH div 2)-1 do
for x:=R.Left to R.Right do
begin
tmp:=Lines[R.Top+y]^[x];
tmpY:=R.Top+tmpH-1-y;
Lines[R.Top+y]^[x]:=Lines[tmpY]^[x];
Lines[tmpY]^[x]:=tmp;
end;
end;
class function TFlipFilter.Description: String;
begin
result:='Flip';
end;
{ TReverseFilter }
procedure TReverseFilter.Apply(const R:TRect);
var tmp : TRGBTriple;
tmpW,
tmpX,
x,y : Integer;
begin
inherited;
tmpW:=R.Right-R.Left;
for x:=0 to (tmpW div 2)-1 do
for y:=R.Top to R.Bottom do
begin
tmp:=Lines[y,R.Left+x];
tmpX:=R.Left+tmpW-1-x;
Lines[y,R.Left+x]:=Lines[y,tmpX];
Lines[y,tmpX]:=tmp;
end;
end;
class function TReverseFilter.Description: String;
begin
result:='Reverse';
end;
procedure InstallHook;
{$IFDEF CLR}
var p: TTeeOnCreateEditor;
{$ENDIF}
begin
{$IFDEF CLR}
p:=TeeFiltersShowEditor;
TeeOnShowEditor.Add(@p);
{$ELSE}
TeeOnShowEditor.Add(@TeeFiltersShowEditor);
{$ENDIF}
end;
procedure RemoveHook;
{$IFDEF CLR}
var p: TTeeOnCreateEditor;
{$ENDIF}
begin
{$IFDEF CLR}
p:=TeeFiltersShowEditor;
TeeOnShowEditor.Remove(@p);
{$ELSE}
TeeOnShowEditor.Remove(@TeeFiltersShowEditor);
{$ENDIF}
end;
{ TAmountFilter }
Constructor TAmountFilter.Create(Collection:TCollection);
begin
inherited;
FPercent:=True;
FAmount:=5; // %
end;
procedure TAmountFilter.ScrollChanged(Sender: TObject);
begin
FAmount:=(Sender as TScrollBar).Position;
FChanged(Self);
end;
procedure TAmountFilter.ResetScroll;
begin
with FScrollBar do
if FPercent then
begin
if IOnlyPositive then Min:=0 else Min:=-100;
Max:=100;
end
else
begin
if IOnlyPositive then Min:=0 else Min:=-255;
Max:=255;
end;
end;
procedure TAmountFilter.CheckClick(Sender: TObject);
begin
FPercent:=(Sender as TCheckBox).Checked;
ResetScroll;
FChanged(Self);
end;
procedure TAmountFilter.CreateEditor(AParent:TWinControl; AChanged:TNotifyEvent);
begin
inherited;
FScrollBar:=TScrollBar.Create(AParent);
with FScrollBar do
begin
Parent:=AParent;
SetBounds(4,8,AParent.Width-8,16);
ResetScroll;
Position:=Self.FAmount;
OnChange:=ScrollChanged;
end;
with TCheckBox.Create(AParent) do
begin
Parent:=AParent;
SetBounds(4,28,75,16);
Caption:=TeeMsg_Percent;
Checked:=Self.Percent;
OnClick:=CheckClick;
end;
end;
{ TBrightnessFilter }
procedure TBrightnessFilter.Apply(const R: TRect);
var x,y,l : Integer;
IPercent : Single;
begin
inherited;
if Percent then
IPercent:=FAmount*0.01
else
IPercent:=1;
for y:=R.Top to R.Bottom do
for x:=R.Left to R.Right do
with Lines[y,x] do
begin
if Percent then l:=rgbtRed+Round(rgbtRed*IPercent)
else l:=rgbtRed+Amount;
if l<0 then rgbtRed:=0 else if l>255 then rgbtRed:=255 else rgbtRed:=l;
if Percent then l:=rgbtGreen+Round(rgbtGreen*IPercent)
else l:=rgbtGreen+Amount;
if l<0 then rgbtGreen:=0 else if l>255 then rgbtGreen:=255 else rgbtGreen:=l;
if Percent then l:=rgbtBlue+Round(rgbtBlue*IPercent)
else l:=rgbtBlue+Amount;
if l<0 then rgbtBlue:=0 else if l>255 then rgbtBlue:=255 else rgbtBlue:=l;
end;
end;
class function TBrightnessFilter.Description: String;
begin
result:='Brightness';
end;
type
Float=Single;
const
// HLSMAX BEST IF DIVISIBLE BY 6. RGBMAX, HLSMAX must each fit in a byte.
HLSMAX = 240; // H,L, and S vary over 0-HLSMAX
RGBMAX = 255; // R,G, and B vary over 0-RGBMAX
RGBMAX2 = 2.0*RGBMAX;
InvRGBMAX2 = 1.0/RGBMAX2;
HLSMAXDiv2=HLSMAX/2;
HLSMAXDiv3=HLSMAX/3;
HLSMAXDiv6=HLSMAX/6;
HLSMAXDiv12=HLSMAX/12;
HLSMAX2=HLSMAX*2;
HLSMAX3=HLSMAX*3;
HLSMAX2Div3=HLSMAX2/3;
{ Hue is undefined if Saturation is 0 (grey-scale)
This value determines where the Hue scrollbar is
initially set for achromatic colors }
HLSUndefined = 160; // HLSMAX2Div3;
procedure RGBToHLS(const Color:TRGBTriple; var Hue, Luminance, Saturation: Word);
var
H, L, S: Float;
R, G, B: Word;
dif : Integer;
sum, cMax, cMin: Word;
Rdelta, Gdelta, Bdelta: Extended; { intermediate value: % of spread from max }
begin
R:=Color.rgbtRed;
G:=Color.rgbtGreen;
B:=Color.rgbtBlue;
{ calculate lightness }
if R>G then
if R>B then cMax:=R else cMax:=B
else
if G>B then cMax:=G else cMax:=B;
if R<G then
if R<B then cMin:=R else cMin:=B
else
if G<B then cMin:=G else cMin:=B;
sum:=(cMax + cMin);
L := ( (sum * HLSMAX) + RGBMAX ) / ( 2 * RGBMAX);
if cMax = cMin then { r=g=b --> achromatic case }
begin { saturation }
Hue := Round(HLSUndefined);
// pwHue := 160; { MS's ColorRGBToHLS always defaults to 160 in this case }
Luminance := Round(L);
Saturation := 0;
end
else { chromatic case }
begin
dif:=cMax-cMin;
{ saturation }
if L <= HLSMAXDiv2 then
S := ( (dif*HLSMAX) + (sum*0.5) ) / sum
else
S := ( (dif*HLSMAX) + ( RGBMAX-(sum*0.5) )) / (2*RGBMAX-sum);
{ hue }
Rdelta := ( ((cMax-R)*HLSMAXDiv6) + (dif*0.5) ) / dif;
Gdelta := ( ((cMax-G)*HLSMAXDiv6) + (dif*0.5) ) / dif;
Bdelta := ( ((cMax-B)*HLSMAXDiv6) + (dif*0.5) ) / dif;
if R = cMax then
H := Bdelta - Gdelta
else
if G = cMax then
H := HLSMAX3 + Rdelta - Bdelta
else // B == cMax
H := HLSUndefined + Gdelta - Rdelta;
if H < 0 then H := H + HLSMAX
else
if H > HLSMAX then H := H - HLSMAX;
Hue := Round(H);
Luminance := Round(L);
Saturation := Round(S);
end;
end;
procedure HLSToRGB(Hue, Luminance, Saturation: Word; var rgb: TRGBTriple);
function HueToRGB(const Lum, Sat:Float; Hue: Float): Integer;
begin
{ range check: note values passed add/subtract thirds of range }
if hue < 0 then hue:=hue+HLSMAX;
if hue > HLSMAX then hue:=hue-HLSMAX;
{ return r,g, or b value from this tridrant }
if hue < HLSMAXDiv6 then
Result := Round( Lum + (((Sat-Lum)*hue+HLSMAXDiv12)/HLSMAXDiv6))
else
if hue < HLSMAXDiv2 then
Result := Round( Sat)
else
if hue < HLSMAX2Div3 then
Result := Round( Lum + (((Sat-Lum)*(HLSMAX2Div3-hue)+HLSMAXDiv12)/HLSMAXDiv6) )
else
Result := Round( Lum );
end;
function RoundColor(const Value: Float): Integer;
begin
if Value > 255 then Result := 255 else Result := Round(Value);
end;
var
Magic1, Magic2: Float; { calculated magic numbers (really!) }
function RoundColor2(const Hue: Float): Integer;
begin
result:=RoundColor((HueToRGB(Magic1,Magic2,Hue)*RGBMAX + HLSMAXDiv2)/HLSMAX);
end;
begin
if Saturation = 0 then
with rgb do
begin { achromatic case }
rgbtRed := RoundColor( (Luminance * RGBMAX)/HLSMAX );
rgbtGreen:=rgbtRed;
rgbtBlue:=rgbtGreen;
if Hue <> HLSUndefined then ;{ ERROR }
end
else
begin { chromatic case }
{ set up magic numbers }
if Luminance <= HLSMAXDiv2 then
Magic2 := (Luminance * (HLSMAX + Saturation) + HLSMAXDiv2) / HLSMAX
else
Magic2 := Luminance + Saturation - ((Luminance * Saturation) + HLSMAXDiv2) / HLSMAX;
Magic1 := 2 * Luminance - Magic2;
{ get RGB, change units from HLSMAX to RGBMAX }
rgb.rgbtRed:=RoundColor2(Hue+HLSMAXDiv3);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -