0% found this document useful (0 votes)
11 views

VCLImageUtils Pascal

VCLImageUtils pascal

Uploaded by

lexman 771
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views

VCLImageUtils Pascal

VCLImageUtils pascal

Uploaded by

lexman 771
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 104

unit VCLImageUtils;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
PngImage, GifImg, Math, Jpeg, Types;

const
clAliceBlue = $FFF8F0;
clAntiqueWhite = $D7EBFA;
clAquamarine = $D4FF7F;
clAzure = $FFFFF0;
clBeige = $DCF5F5;
clBisque = $C4E4FF;
clBlanchedAlmond = $CDEBFF;
clBlueViolet = $E22B8A;
clBrown = $2A2AA5;
clBurlyWood = $87B8DE;
clCadetBlue = $A09E5F;
clChartreuse = $00FF7F;
clChocolate = $1E69D2;
clCoral = $507FFF;
clCornflowerBlue = $ED9564;
clCornsilk = $DCF8FF;
clCrimson = $3C14DC;
clCyan = $FFFF00;
clDarkBlue = $8B0000;
clDarkCyan = $8B8B00;
clDarkGoldenrod = $0B86B8;
clDarkGray = $A9A9A9;
clDarkGreen = $006400;
clDarkKhaki = $6BB7BD;
clDarkMagenta = $8B008B;
clDarkOliveGreen = $2F6B55;
clDarkOrange = $008CFF;
clDarkOrchid = $CC3299;
clDarkRed = $00008B;
clDarkSalmon = $7A96E9;
clDarkSeaGreen = $8BBC8F;
clDarkSlateBlue = $8B3D48;
clDarkSlateGray = $4F4F2F;
clDarkTurquoise = $D1CE00;
clDarkViolet = $D30094;
clDeepPink = $9314FF;
clDeepSkyBlue = $FFBF00;
clDimGray = $696969;
clDodgerBlue = $FF901E;
clFirebrick = $2222B2;
clFloralWhite = $F0FAFF;
clForestGreen = $228B22;
clGainsboro = $DCDCDC;
clGhostWhite = $FFF8F8;
clGold = $00D7FF;
clGoldenrod = $20A5DA;
clGreenYellow = $2FFFAD;
clHoneydew = $F0FFF0;
clHotPink = $B469FF;
clIndianRed = $5C5CCD;
clIndigo = $82004B;
clIvory = $F0FFFF;
clKhaki = $8CE6F0;
clLavender = $FAE6E6;
clLavenderBlush = $F5F0FF;
clLawnGreen = $00FC7C;
clLemonChiffon = $CDFAFF;
clLightBlue = $E6D8AD;
clLightCoral = $8080F0;
clLightCyan = $FFFFE0;
clLightGoldenrodYellow = $D2FAFA;
clLightGray = $D3D3D3;
clLightGreen = $90EE90;
clLightPink = $C1B6FF;
clLightSalmon = $7AA0FF;
clLightSeaGreen = $AAB220;
clLightSkyBlue = $FACE87;
clLightSlateGray = $998877;
clLightSteelBlue = $DEC4B0;
clLightYellow = $E0FFFF;
clLimeGreen = $32CD32;
clLinen = $E6F0FA;
clMagenta = $FF00FF;
clMediumAquamarine = $AACD66;
clMediumBlue = $CD0000;
clMediumOrchid = $D355BA;
clMediumPurple = $DB7093;
clMediumSeaGreen = $71B33C;
clMediumSlateBlue = $EE687B;
clMediumSpringGreen = $9AFA00;
clMediumTurquoise = $CCD148;
clMediumVioletRed = $8515C7;
clMidnightBlue = $701919;
clMintCream = $FAFFF5;
clMistyRose = $E1E4FF;
clMoccasin = $B5E4FF;
clNavajoWhite = $ADDEFF;
clOldLace = $E6F5FD;
clOliveDrab = $238E6B;
clOrange = $00A5FF;
clOrangeRed = $0045FF;
clOrchid = $D670DA;
clPaleGoldenrod = $AAE8EE;
clPaleGreen = $98FB98;
clPaleTurquoise = $EEEEAF;
clPaleVioletRed = $9370DB;
clPapayaWhip = $D5EFFF;
clPeachPuff = $B9DAFF;
clPeru = $3F85CD;
clPink = $CBC0FF;
clPlum = $DDA0DD;
clPowderBlue = $E6E0B0;
clPurple = $800080;
clRosyBrown = $8F8FBC;
clRoyalBlue = $E16941;
clSaddleBrown = $13458B;
clSalmon = $7280FA;
clSandyBrown = $60A4F4;
clSeaGreen = $578B2E;
clSeaShell = $EEF5FF;
clSienna = $2D52A0;
clSkyBlue = $EBCE87;
clSlateBlue = $CD5A6A;
clSlateGray = $908070;
clSnow = $FAFAFF;
clSpringGreen = $7FFF00;
clSteelBlue = $B48246;
clTan = $8CB4D2;
clThistle = $D8BFD8;
clTomato = $4763FF;
clTurquoise = $D0E040;
clViolet = $EE82EE;
clWheat = $B3DEF5;
clWhiteSmoke = $F5F5F5;
clYellowGreen = $32CD9A;

type
TFlipType = (ftUpDown, ftLeftRight);
TRGBQuadArray = array[BYTE] of TRGBQuad;
TErrorDiffusion = (edNone, edFloydSteinberg, edStucki, edSierra, edJaJuNi);
TResizeMode = (rmNearest, rmBilinear, rmBicubic, rmLagrange,
rmBSpline, rmMitchell);
TRankMode = (rkMax, rkMin);
TPointF = packed record
X, Y: single;
end;
TMirrorType = (mtLeft, mtRight);
TCylinderDirection = (cdVertical, cdHorizontal);
TBathWindowMode = (bwVertical, bwHorizontal, bwBoth);
TWaveType = (wtVertical, wtHorizontal, wtBoth);
TSineMask = (smVert, smHorz, smBoth);

TBmpData24 = class(TObject)
private
sl: array of Pointer;
FWidth, FHeight: integer;
function GetData(x, y: integer):PRGBTriple;
protected
public
constructor Create(bmp: TBitmap);
destructor Destroy; override;
property Data[x, y: integer]: PRGBTriple read GetData; default;
property Width: integer read FWidth;
property Height: integer read FHeight;
end;

TBmpData8 = class(TObject)
private
sl: array of Pointer;
FWidth, FHeight: integer;
function GetData(x, y: integer):PByte;
protected
public
constructor Create(bmp: TBitmap);
destructor Destroy; override;
property Data[x, y: integer]: PByte read GetData; default;
property Width: integer read FWidth;
property Height: integer read FHeight;
end;

TBmpData4 = class(TObject)
private
sl: array of Pointer;
function GetData(x, y: integer):Byte;
procedure SetData(x, y: integer; value: Byte);
protected
public
constructor Create(bmp: TBitmap);
destructor Destroy; override;
property Data[x, y: integer]: Byte read GetData write SetData; default;
end;

TBmpData1 = class(TObject)
private
sl: array of Pointer;
FWidth, FHeight: integer;
function GetData(x, y: integer):Boolean;
procedure SetData(x, y: integer; value: Boolean);
protected
public
constructor Create(bmp: TBitmap);
destructor Destroy; override;
property Data[x, y: integer]: Boolean read GetData write SetData; default;
property Width: integer read FWidth;
property Height: integer read FHeight;
end;

function LoadPng(filename: string): TBitmap;


function LoadGif(filename: string): TBitmap;
function LoadJpeg(filename: string): TBitmap;
function JAlphaBlend(dst: TCanvas; dstX, dstY: integer;
src: TBitmap; alpha: single):Boolean;
function LoadCheckedImage(filename: string): TBitmap;
function GetThumbnailImage(filename: string;
width, height: integer;
bkColor: TColor = clWhite;
frame: Boolean = true): TBitmap;

function BmpClone(bmp: TBitmap): TBitmap;


function AdjustByte(value: integer): Byte; overload;
function AdjustByte(value: extended): Byte; overload;
function ExeDir: string;

function Flip(bmp: TBitmap; FlipType: TFlipType):Boolean;


function Rotate90(var bmp: TBitmap; plus: Boolean = true):Boolean;
function Invert(bmp: TBitmap): Boolean;
function PaletteEntryBmp(bmp8: TBitmap): TBitmap;
procedure GrayScale8(bmp8: TBitmap);
procedure SetGrayPalette(bmp8: TBitmap);
function GrayScale4(var bmp: TBitmap):Boolean;
function GrayScale4FloydStucci(var bmp: TBitmap; Stretch: Boolean = true):Boolean;
function GrayScale(var bmp: TBitmap):Boolean;
function BlackWhiteFloydStucci2(var bmp: TBitmap; threshold: byte = 127;
Stretch: Boolean = true;
Dark: TColor = clBlack;
Bright: TColor = clWhite):Boolean;
function BrightnessHistogram(bmp: TBitmap): TBitmap;
function RGBHistogram(bmp: TBitmap): TBitmap;
function Brightness(bmp: TBitmap; percent: integer = 10):Boolean;
function Contrast(bmp: TBitmap; nContrast: integer):Boolean;
function TwoColorGrayScale(var bmp: TBitmap; Dark, Bright: TColor):Boolean;
function Gamma(bmp: TBitmap; dGamma: single):Boolean;
function ColorFilter(bmp: TBitmap; fRed, fGreen, fBlue: single):Boolean;
function Saturation(bmp: TBitmap; percent: extended):Boolean;
procedure RGBToHSL(rgb: TRGBTriple; var h, s, l :integer);
procedure HSLToRGB(rgb: PRGBTriple; h, s, l :integer);
function Hue(bmp: TBitmap; angle: integer = 20):Boolean;
function HueHistogram(bmp24: TBitmap): TBitmap;
function Luminance(bmp: TBitmap; percent: integer = 20):Boolean;
function HistoStretch(grayBMP: TBitmap):Boolean;
function CountColors(bmp24: TBitmap):integer;
function BlackWhite(var bmp24: TBitmap; threshold: byte = 127): Boolean;
function RandomDither(var bmp24: TBitmap;
ErrorDiffusion: TErrorDiffusion = edStucki;
Dark: TColor = clBlack;
Bright: TColor = clWhite;
randomness: integer = 30;
Stretch: Boolean = true): Boolean;
function OrderedDither(var bmp24: TBitmap;
ErrorDiffusion: TErrorDiffusion = edStucki;
Dark: TColor = clBlack;
Bright: TColor = clWhite;
Stretch: Boolean = true):Boolean;
function Mirror(bmp: TBitmap;
mt: TMirrorType = mtLeft;
center: integer = 0): Boolean;
function RiceCake(bmp: TBitmap; factor: single = 0.8):Boolean;

function BmpResize(var bmp: TBitmap;


rwidth, rheight: integer;
mode: TResizeMode = rmBilinear):Boolean;
function PointF(X, Y: single): TPointF;
function Rotation(var bmp: TBitmap; angle: single; bkColor: TColor): Boolean;
function PtFInRect(pt: TPointF; r: TRect): Boolean;
function Caricature(bmp: TBitmap; factor: single = 100):Boolean;
function Fisheye(bmp: TBitmap; factor: single = 100):Boolean;
function SoftFisheye(bmp: TBitmap; factor: single = 0.8):Boolean;
function Swirl(bmp: TBitmap; factor: single = 0.05):Boolean;
function Shear(bmp: TBitmap; entropy: single = 0.4): Boolean;
function Cylinder(bmp: TBitmap; cd: TCylinderDirection = cdVertical):Boolean;
function BathroomWindow(bmp: TBitmap;
zone: integer = 10;
mode: TBathWindowMode = bwVertical):Boolean;
function BathroomWindow2(bmp: TBitmap; zone: integer = 8):Boolean;
function SpotLight(bmp: TBitmap; radius: integer):Boolean;
function Tile(bmp: TBitmap; area:integer = 16; entropy: integer = 2):Boolean;
function Ripple(bmp: TBitmap;
factor: single = 3.0;
frequency: single = 40):Boolean;
function Pixellate2(bmp: TBitmap; zone: integer = 6):Boolean;
function Ripple2(bmp: TBitmap;
factor: single = 0.2;
frequency: single = 40):Boolean;
function WaveGlass(bmp: TBitmap;
WaveType: TWaveType = wtVertical;
factor: single = 3;
frequency: single = 30):Boolean;
function ColorSpotLight(bmp: TBitmap; radius: integer):Boolean;
function Explosion(bmp: TBitmap; factor: integer):Boolean;

function Emboss1(var bmp: TBitmap; fGray: Boolean = true):Boolean;


function Emboss2(var bmp: TBitmap; fGray: Boolean = true):Boolean;
function Sobel(var bmp: TBitmap; fGray: Boolean = true):Boolean;
function Laplacian(var bmp: TBitmap; fGray: Boolean = true):Boolean;
function EdgeEnhance(var bmp: TBitmap; percent: integer = 50):Boolean;
function Edge(var bmp: TBitmap; fGray: Boolean = true):Boolean;
function Sharpen(var bmp: TBitmap; percent: integer = 50):Boolean;
function Median(var bmp: TBitmap; area: integer = 1):Boolean;
function Rank(bmp: TBitmap; mode: TRankMode = rkMax; zone: integer = 1):Boolean;
function Range(var bmp: TBitmap; zone: integer = 1; Gray: Boolean = true):Boolean;
function OilPaint(bmp: TBitmap; zone: integer = 2):Boolean;
function Blur(bmp: TBitmap; zone: integer = 1):Boolean;
function GaussianBlur(bmp: TBitmap; zone:integer = 2): Boolean;
function Pixellate(bmp: TBitmap; area:integer):Boolean;
function Mosaic(bmp: TBitmap; area:integer; range: TRect):Boolean;
function Vaseline(bmp: TBitmap; radius: integer):Boolean;
function FrostedGlass(bmp: TBitmap; alpha: single;
fBlur: integer; rct: TRect): Boolean;
procedure ShadowFrame(var bmp: TBitmap;
Margin: integer = 10;
ShadowWidth: integer = 7;
BackColor: TColor = clWhite);
function MakeMask1(var bmp:TBitmap; threshold: byte = 100): Boolean;
procedure MaskedOverlay(dst, src, mask: TBitmap; dstX, dstY: integer);
function SpotMask(w, h: integer; Radius: integer): TBitmap;
function SineMask(w, h: integer; mode: TSineMask): TBitmap;

function Grid(bmp: TBitmap; area:integer):Boolean;


function Soften(bmp: TBitmap; percent:integer): Boolean;
function Contour1(var bmp: TBitmap; threshold: integer): Boolean;
function Contour2(var bmp: TBitmap; Stretch: Boolean = true): Boolean;
function Parallelogram1(var bmp: TBitmap; deform: single; bkColor: TColor):
Boolean;
function Parallelogram2(var bmp: TBitmap; deform: single; bkColor: TColor):
Boolean;
function AlphaTile(var bmp:TBitmap; partition: integer = 10): Boolean;
function Divide(var bmp:TBitmap;
bkImage: TBitmap;
hdiv, vdiv: integer;
margin: integer = 20;
framewidth: integer = 5): Boolean;
function RadialBlur(bmp: TBitmap; zone: integer = 3):Boolean;
function AngleBlur(bmp: TBitmap; zone: integer = 3):Boolean;
function BrightnessModulation(var bmp, modu: TBitmap;
percent: single;
negative: boolean = false):Boolean;
function PolarShear(bmp: TBitmap;
rentropy: single = 0.5;
aentropy: single = 0.5;
bInterpolation: Boolean = true): Boolean;
function Circle1(var bmp: TBitmap; bkColor: TColor = clGray): Boolean;
function Circle2(var bmp: TBitmap; bkColor: TColor = clGray): Boolean;
function Focus(bmp: TBitmap; percent: single = 20): Boolean;
function LineInvert(bmp: TBitmap; cx, cy, angle: single
; bkColor: TColor = clGray): Boolean;
function Mirror2(var bmp: TBitmap; angle: single; bkColor: TColor): Boolean;
function Mirror3(var bmp: TBitmap; cx, cy, angle: single; bkColor: TColor):
Boolean;

implementation

//---------- TBmpData24 ----------------------

constructor TBmpData24.Create(bmp: TBitmap);


var
i: integer;
begin
SetLength(sl, bmp.Height);
for i := 0 to bmp.Height-1 do sl[i] := bmp.ScanLine[i];
FWidth := bmp.Width;
FHeight := bmp.Height;
end;

destructor TBmpData24.Destroy;
begin

inherited;
end;

function TBmpData24.GetData(x, y: integer):PRGBTriple;


begin
result := sl[y];
Inc(result, x);
end;

//---------- TBmpData8 ----------------------

constructor TBmpData8.Create(bmp: TBitmap);


var
i: integer;
begin
SetLength(sl, bmp.Height);
for i := 0 to bmp.Height-1 do sl[i] := bmp.ScanLine[i];
FWidth := bmp.Width;
FHeight := bmp.Height;
end;

destructor TBmpData8.Destroy;
begin

inherited;
end;

function TBmpData8.GetData(x, y: integer):PByte;


begin
result := sl[y];
Inc(result, x);
end;

//---------- TBmpData4 ----------------------


constructor TBmpData4.Create(bmp: TBitmap);
var
i: integer;
begin
SetLength(sl, bmp.Height);
for i := 0 to bmp.Height-1 do sl[i] := bmp.ScanLine[i];
end;

destructor TBmpData4.Destroy;
begin

inherited;
end;

function TBmpData4.GetData(x, y: integer):Byte;


var
p: PByte;
begin
p := sl[y];
Inc(p, x div 2);
result := p^;
if (x mod 2) = 0 then
result := result shr 4
else
result := result and $0F;
end;

procedure TBmpData4.SetData(x, y: integer; value: Byte);


var
p: PByte;
v: Byte;
begin
p := sl[y];
Inc(p, x div 2);
v := p^;
if (x mod 2) = 0 then
v := (v and $0F) or (value shl 4)
else
v := (v and $F0) or value;
p^ := v;
end;

function GrayScale4FloydStucci(var bmp: TBitmap; Stretch: Boolean = true):Boolean;


var
tmp8, bmp4:TBitmap;
w, h, ix, iy, x, y, i: integer;
src: TBmpData8;
dst: TBmpData4;
ct: array[0..15] of TRGBQuad;
v: Byte;
dif: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp8 := BmpClone(bmp);
if not GrayScale(tmp8) then
begin
tmp8.Free;
exit;
end;
if Stretch then
// if not HistoStretchGray(tmp8) then
if not HistoStretch(tmp8) then
begin
tmp8.Free;
exit;
end;

bmp4 := TBitmap.Create;
bmp4.PixelFormat := pf4bit;
bmp4.Width := w;
bmp4.Height := h;

for i := 0 to 15 do
begin
ct[i].rgbBlue := i shl 4;
ct[i].rgbGreen := i shl 4;
ct[i].rgbRed := i shl 4;
ct[i].rgbReserved := 0;
end;
SetDIBColorTable(bmp4.Canvas.Handle,0,15,ct);
DeleteObject(bmp4.ReleasePalette);

src := TBmpData8.Create(tmp8);
dst := TBmpData4.Create(bmp4);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
v := src[ix,iy]^ shr 4;
if (src[ix,iy]^ and $F) > 8 then Inc(v);
if v > $F then v := $F;
dst[ix, iy] := v;

dif := src[ix,iy]^ - (v shl 4);

x := ix+1; y := iy;
if (x < w) then src[x,y]^ := AdjustByte(src[x,y]^+ dif*7/16);

x := ix-1; y := iy+1;
if (x > -1) and (y < h) then src[x,y]^ := AdjustByte(src[x,y]^+ dif*3/16);

x := ix; y := iy+1;
if (y < h) then src[x,y]^ := AdjustByte(src[x,y]^+ dif*5/16);

x := ix+1; y := iy+1;
if (x < w) and (y < h) then src[x,y]^ := AdjustByte(src[x,y]^+ dif/16);
end;

dst.Free;
src.Free;
tmp8.Free;
bmp.Free;
bmp := bmp4;
result := true;
end;

//---------- TBmpData1 ----------------------

constructor TBmpData1.Create(bmp: TBitmap);


var
i: integer;
begin
SetLength(sl, bmp.Height);
for i := 0 to bmp.Height-1 do sl[i] := bmp.ScanLine[i];
FWidth := bmp.Width;
FHeight := bmp.Height;
end;

destructor TBmpData1.Destroy;
begin

inherited;
end;

function TBmpData1.GetData(x, y: integer):Boolean;


var
p: PByte;
begin
p := sl[y];
Inc(p, x div 8);
result := (p^ shr (7-(x mod 8)) and 1) = 1;
end;

procedure TBmpData1.SetData(x, y: integer; value: Boolean);


var
p: PByte;
begin
p := sl[y];
Inc(p, x div 8);
if value then
p^ := p^ or (1 shl (7-(x mod 8)))
else
p^ := p^ and not (1 shl (7-(x mod 8)));
end;

//-------------------------------------------------------------

function LoadPng(filename: string): TBitmap;


var
png: TPngImage;
begin
result := nil;
png := TPngImage.Create;
try
png.LoadFromFile(filename);
try
result := TBitmap.Create;
result.Assign(png);

except
FreeAndNil(result);
end;
finally
png.Free;
end;
end;

function LoadGif(filename: string): TBitmap;


var
gif: TGifImage;
begin
result := nil;
gif := TGifImage.Create;
try
gif.LoadFromFile(filename);
result := TBitmap.Create;
try
result.Assign(gif);
except
FreeAndNil(result);
end;
finally
gif.Free;
end;
end;

function LoadJpeg(filename: string): TBitmap;


var
jpg: TJpegImage;
begin
result := nil;

jpg := TJpegImage.Create;
try
jpg.LoadFromFile(filename);
result := TBitmap.Create;
try
result.Assign(jpg);
except
FreeAndNil(result)
end;
finally
jpg.Free;
end;
end;

function BmpClone(bmp: TBitmap): TBitmap;


begin
result := TBitmap.Create;
result.Assign(bmp);
end;

function AdjustByte(value: integer): Byte;


begin
if value < 0 then
result := 0
else
if value > 255 then
result := 255
else
result := value;
end;

function AdjustByte(value: extended): Byte;


begin
if value < 0 then
result := 0
else
if value > 255 then
result := 255
else
result := Round(value);
end;

function ExeDir: string;


begin
result := ExtractFilePath(ParamStr(0));
end;

function Flip(bmp: TBitmap; FlipType: TFlipType):Boolean;


var
w, h, ix, iy: integer;
tmp :TBitmap;
dst, src: TBmpData24;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

dst := TBmpData24.Create(bmp);
src := TBmpData24.Create(tmp);

if FlipType = ftUpDown then


begin
for iy := 0 to h-1 do
for ix := 0 to w-1 do
dst[ix,h-1-iy]^ := src[ix,iy]^;
end
else
begin
for iy := 0 to h-1 do
for ix := 0 to w-1 do
dst[w-1-ix,iy]^ := src[ix,iy]^;
end;

src.Free;
dst.Free;

tmp.Free;
result := true;
end;

function Rotate90(var bmp: TBitmap; plus: Boolean = true):Boolean;


var
w, h, ix, iy: integer;
tmp :TBitmap;
dst, src: TBmpData24;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);
tmp.Width := h;
tmp.Height := w;

src := TBmpData24.Create(bmp);
dst := TBmpData24.Create(tmp);

if plus then
begin
for iy := 0 to h-1 do
for ix := 0 to w-1 do
dst[h-1-iy,ix]^ := src[ix,iy]^;
end
else
begin
for iy := 0 to h-1 do
for ix := 0 to w-1 do
dst[iy,w-1-ix]^ := src[ix,iy]^;
end;

src.Free;
dst.Free;

bmp.Free;
bmp := tmp;
result := true;
end;

function Invert(bmp: TBitmap): Boolean;


var
w, h, ix, iy: integer;
tmp :TBitmap;
dst, src: TBmpData24;
pd, ps: PRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
pd := dst[ix,iy]; ps := src[ix,iy];
pd^.rgbtRed := 255 - ps^.rgbtRed;
pd^.rgbtGreen := 255 - ps^.rgbtGreen;
pd^.rgbtBlue := 255 - ps^.rgbtBlue;
end;
src.Free;
dst.Free;

tmp.Free;
result := true;
end;

function PaletteEntryBmp(bmp8: TBitmap): TBitmap;


var
num, i, x, y: integer;
pe: array[0..255] of TPaletteEntry;
begin
result := nil;
if bmp8.PixelFormat <> pf8bit then exit;
try
num := GetPaletteEntries(bmp8.Palette,0,256,pe);
except
exit;
end;
result := TBitmap.Create;
result.PixelFormat := pf24bit;
result.Width := 225;
result.Height := 225;

with result.Canvas do
begin
Pen.Color := clGray;
for i := 0 to num-1 do
begin
Brush.Color := RGB(pe[i].peRed, pe[i].peGreen, pe[i].peBlue);
x := 14*(i mod 16)+1; y := 14*(i div 16)+1;
Rectangle(x-1, y-1, x+14, y+14);
end;
end;
end;

procedure GrayScale8(bmp8: TBitmap);


var
num,i:integer;
pe: array[0..255] of TPaletteEntry;
ct: array[0..255] of TRGBQuad;
c:word;
begin
num := GetPaletteEntries(bmp8.Palette,0,256,pe);

for i := 0 to num-1 do
begin
c := trunc(pe[i].peRed*0.299+pe[i].peGreen*0.587+pe[i].peBlue*0.114);
ct[i].rgbBlue := c;
ct[i].rgbGreen := c;
ct[i].rgbRed := c;
ct[i].rgbReserved := 0;
end;

SetDIBColorTable(bmp8.Canvas.Handle,0,num,ct);
DeleteObject(bmp8.ReleasePalette);
end;
function GrayScale4(var bmp: TBitmap):Boolean;
var
tmp8, bmp4:TBitmap;
w, h, ix, iy, i: integer;
src: TBmpData8;
dst: TBmpData4;
ct: array[0..15] of TRGBQuad;
v: Byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp8 := BmpClone(bmp);
if not GrayScale(tmp8) then
begin
tmp8.Free;
exit;
end;
// if not HistoStretchGray(tmp8) then
if not HistoStretch(tmp8) then
begin
tmp8.Free;
exit;
end;

bmp4 := TBitmap.Create;
bmp4.PixelFormat := pf4bit;
bmp4.Width := w;
bmp4.Height := h;

for i := 0 to 15 do
begin
ct[i].rgbBlue := i shl 4;
ct[i].rgbGreen := i shl 4;
ct[i].rgbRed := i shl 4;
ct[i].rgbReserved := 0;
end;
SetDIBColorTable(bmp4.Canvas.Handle,0,15,ct);
DeleteObject(bmp4.ReleasePalette);

src := TBmpData8.Create(tmp8);
dst := TBmpData4.Create(bmp4);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
v := src[ix,iy]^ shr 4;
if (src[ix,iy]^ and $F) > 8 then Inc(v);
if v > $F then v := $F;
dst[ix, iy] := v;
end;

dst.Free;
src.Free;
tmp8.Free;
bmp.Free;
bmp := bmp4;
result := true;
end;

function BrightnessHistogram(bmp: TBitmap): TBitmap;


var
w, h, ix, iy, i, max: integer;
src: TBmpData24;
d: TRGBTriple;
Hist: array[0..255] of integer;
begin
for i := 0 to 255 do Hist[i] := 0;

w := bmp.Width;
h := bmp.Height;

src := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy]^;
inc(Hist[Trunc(0.299*d.rgbtRed + 0.587*d.rgbtGreen + 0.114*d.rgbtBlue)]);
end;

src.Free;

max := -1;
for i := 0 to 255 do if Hist[i] > max then max := Hist[i];

for i := 0 to 255 do Hist[i] := Round(Hist[i]*140/max);

result := TBitmap.Create;
result.PixelFormat := pf8bit;
result.Width := 275;
result.Height := 160;

with result.Canvas do
begin
Pen.Color := clGray;
for i := 0 to 255 do
begin
MoveTo(10+i,150);
LineTo(10+i,150-Hist[i]);
end;
Pen.Color := clBlack;
MoveTo(10, 150); LineTo(10, 10);
for i := 0 to 20 do
begin
MoveTo(10, 150-7*i);
if Odd(i) then LineTo(8, 150-7*i) else LineTo(6, 150-7*i);
end;
MoveTo(10, 150); LineTo(10+255, 150);
for i := 0 to 51 do
begin
MoveTo(10+5*i, 150);
if Odd(i) then LineTo(10+5*i, 152) else LineTo(10+5*i, 154);
end;
end;
end;
function RGBHistogram(bmp: TBitmap): TBitmap;
var
w, h, ix, iy, i, max: integer;
src: TBmpData24;
d: TRGBTriple;
L, R, G, B: array[0..255] of integer;
pt: array[0..255] of TPoint;
begin
for i := 0 to 255 do
begin
L[i] := 0; R[i] := 0; G[i] := 0; B[i] := 0;
end;

w := bmp.Width;
h := bmp.Height;

src := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy]^;
inc(R[d.rgbtRed]);
inc(G[d.rgbtGreen]);
inc(B[d.rgbtBlue]);
inc(L[Trunc(0.299*d.rgbtRed + 0.587*d.rgbtGreen + 0.114*d.rgbtBlue)]);
end;

src.Free;

max := -1;
for i := 0 to 255 do
begin
if R[i] > max then max := R[i];
if G[i] > max then max := G[i];
if B[i] > max then max := B[i];
if L[i] > max then max := L[i];
end;

result := TBitmap.Create;
result.PixelFormat := pf8bit;
result.Width := 275;
result.Height := 160;

with result.Canvas do
begin
Brush.Color := clSilver;
FillRect(Rect(0, 0, 275, 160));

Pen.Width := 2;

for i := 0 to 255 do pt[i] := Point(10+i,150-Round(R[i]*140/max));


Pen.Color := clRed;
PolyLine(pt);

for i := 0 to 255 do pt[i] := Point(10+i,150-Round(G[i]*140/max));


Pen.Color := RGB(0,$bb,0);
PolyLine(pt);
for i := 0 to 255 do pt[i] := Point(10+i,150-Round(B[i]*140/max));
Pen.Color := clBlue;
PolyLine(pt);

for i := 0 to 255 do pt[i] := Point(10+i,150-Round(L[i]*140/max));


Pen.Color := clBlack;
PolyLine(pt);

Pen.Width := 1;

Pen.Color := clBlack;
MoveTo(10, 150); LineTo(10, 10);
for i := 0 to 20 do
begin
MoveTo(10, 150-7*i);
if Odd(i) then LineTo(8, 150-7*i) else LineTo(6, 150-7*i);
end;
MoveTo(10, 150); LineTo(10+255, 150);
for i := 0 to 51 do
begin
MoveTo(10+5*i, 150);
if Odd(i) then LineTo(10+5*i, 152) else LineTo(10+5*i, 154);
end;
end;
end;

procedure SetGrayPalette(bmp8: TBitmap);


var
i: integer;
ct: array[0..255] of TRGBQuad;
begin
for i := 0 to 255 do
begin
ct[i].rgbBlue := i;
ct[i].rgbGreen := i;
ct[i].rgbRed := i;
ct[i].rgbReserved := 0;
end;
SetDIBColorTable(bmp8.Canvas.Handle,0,255,ct);
DeleteObject(bmp8.ReleasePalette);
end;

function GrayScale(var bmp: TBitmap):Boolean;


var
bmp8:TBitmap;
w, h, ix, iy: integer;
d: PRGBTriple;
src: TBmpData24;
dst: TBmpData8;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

bmp8 := TBitmap.Create;
bmp8.PixelFormat := pf8bit;
bmp8.Width := w;
bmp8.Height := h;

SetGrayPalette(bmp8);

src := TBmpData24.Create(bmp);
dst := TBmpData8.Create(bmp8);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy];
dst[ix, iy]^ := Trunc(0.299*d^.rgbtRed + 0.587*d^.rgbtGreen +
0.114*d^.rgbtBlue);
end;

dst.Free;
src.Free;

bmp.Free;
bmp := bmp8;
result := true;
end;

function BlackWhiteFloydStucci2(var bmp: TBitmap; threshold: byte = 127;


Stretch: Boolean = true;
Dark: TColor = clBlack;
Bright: TColor = clWhite):Boolean;
var
tmp8, bmp1:TBitmap;
w, h, ix, iy, x, y: integer;
src: TBmpData8;
dst: TBmpData1;
dif: integer;
ct: array[0..1] of TRGBQuad;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp8 := BmpClone(bmp);
if not GrayScale(tmp8) then
begin
tmp8.Free;
exit;
end;
if stretch then
// if not HistoStretchGray(tmp8) then
if not HistoStretch(tmp8) then
begin
tmp8.Free;
exit;
end;

bmp1 := TBitmap.Create;
bmp1.PixelFormat := pf1bit;
bmp1.Width := w;
bmp1.Height := h;
Dark := ColorToRGB(Dark);
ct[0].rgbBlue := GetBValue(Dark);
ct[0].rgbGreen := GetGValue(Dark);
ct[0].rgbRed := GetRValue(Dark);
ct[0].rgbReserved := 0;

Bright := ColorToRGB(Bright);
ct[1].rgbBlue := GetBValue(Bright);
ct[1].rgbGreen :=GetGValue(Bright);
ct[1].rgbRed := GetRValue(Bright);
ct[1].rgbReserved := 0;

SetDIBColorTable(bmp1.Canvas.Handle,0,2,ct);
DeleteObject(bmp1.ReleasePalette);

src := TBmpData8.Create(tmp8);
dst := TBmpData1.Create(bmp1);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
dst[ix, iy] := src[ix,iy]^ > threshold;

if dst[ix, iy] then


dif := src[ix,iy]^ - 255
else
dif := src[ix,iy]^;

x := ix+1; y := iy;
if (x < w) then src[x,y]^ := AdjustByte(src[x,y]^+ dif*7/16);

x := ix-1; y := iy+1;
if (x > -1) and (y < h) then src[x,y]^ := AdjustByte(src[x,y]^+ dif*3/16);

x := ix; y := iy+1;
if (y < h) then src[x,y]^ := AdjustByte(src[x,y]^+ dif*5/16);

x := ix+1; y := iy+1;
if (x < w) and (y < h) then src[x,y]^ := AdjustByte(src[x,y]^+ dif/16);
end;

dst.Free;
src.Free;
tmp8.Free;
bmp.Free;
bmp := bmp1;
result := true;
end;

function Brightness(bmp: TBitmap; percent: integer = 10):Boolean;


var
w, h, ix, iy, rr: integer;
bd: TBmpData24;
d: PRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

rr := 255*percent div 100;

bd := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := bd[ix,iy];
d^.rgbtRed := AdjustByte(d^.rgbtRed + rr);
d^.rgbtGreen := AdjustByte(d^.rgbtGreen + rr);
d^.rgbtBlue := AdjustByte(d^.rgbtBlue + rr);
end;

bd.Free;

result := true;
end;

function Contrast(bmp: TBitmap; nContrast: integer):Boolean;


var
w, h, ix, iy: integer;
bd: TBmpData24;
d: PRGBTriple;
value: Single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

if (nContrast>100) or (nContrast<-100) then exit;

value := (100.0+nContrast)/100.0;
value := value*value;

w := bmp.Width;
h := bmp.Height;

bd := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := bd[ix,iy];
d^.rgbtRed := AdjustByte(((d^.rgbtRed/255.0 - 0.5)*value + 0.5)*255.0);
d^.rgbtGreen := AdjustByte(((d^.rgbtGreen/255.0 - 0.5)*value + 0.5)*255.0);
d^.rgbtBlue := AdjustByte(((d^.rgbtBlue/255.0 - 0.5)*value + 0.5)*255.0);
end;

bd.Free;
result := true;
end;

function Emboss1(var bmp: TBitmap; fGray: Boolean = true):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy];
r := -d^.rgbtRed;
g := -d^.rgbtGreen;
b := -d^.rgbtBlue;

x := ix+1; y := iy+1;
if (x > w-1) then x := ix;
if (y > h-1) then y := iy;
d := src[x,y];
r := r - d^.rgbtRed;
g := g - d^.rgbtGreen;
b := b - d^.rgbtBlue;

x := ix-1; y := iy-1;
if (x < 0) then x := ix;
if (y < 0) then y := iy;
d := src[x,y];
r := r + 2*d^.rgbtRed;
g := g + 2*d^.rgbtGreen;
b := b + 2*d^.rgbtBlue;

d := dst[ix,iy];
d^.rgbtRed := AdjustByte(r+127);
d^.rgbtGreen := AdjustByte(g+127);
d^.rgbtBlue := AdjustByte(b+127);
end;

dst.Free;
src.Free;

tmp.Free;

if fGray then GrayScale(bmp);

result := true;
end;

function Emboss2(var bmp: TBitmap; fGray: Boolean = true):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy];
r := d^.rgbtRed;
g := d^.rgbtGreen;
b := d^.rgbtBlue;

x := ix+1; y := iy+1;
if (x > w-1) then x := ix;
if (y > h-1) then y := iy;
d := src[x,y];
r := r - d^.rgbtRed;
g := g - d^.rgbtGreen;
b := b - d^.rgbtBlue;

d := dst[ix,iy];
d^.rgbtRed := AdjustByte(r+127);
d^.rgbtGreen := AdjustByte(g+127);
d^.rgbtBlue := AdjustByte(b+127);
end;

dst.Free;
src.Free;

tmp.Free;

if fGray then GrayScale(bmp);

result := true;
end;

function CompInt(Item1, Item2: pointer):integer;


begin
result := integer(Item1) - integer(Item2);
end;

function CountColors(bmp24: TBitmap):integer;


var
i, x, y, w, h: integer;
tl: TList;
src: TBmpData24;
pData: PRGBTriple;
c: COLORREF;
begin
w := bmp24.Width;
h := bmp24.Height;
src := TBmpData24.Create(bmp24);

tl := TList.Create;
try
tl.Capacity := w * h;
for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
pData := src[x, y];
c := RGB(pData^.rgbtRed, pData^.rgbtGreen, pData^.rgbtBlue);
tl.Add(pointer(c));
end;
end;
tl.Sort(CompInt);
result := 1;
for i := 1 to tl.Count-1 do
if integer(tl[i-1]) <> integer(tl[i]) then inc(result);
finally
tl.Free;
end;

src.Free;
end;

function TwoColorGrayScale(var bmp: TBitmap; Dark, Bright: TColor):Boolean;


var
bmp8: TBitmap;
w, h, ix, iy, i: integer;
d: PRGBTriple;
src: TBmpData24;
dst: TBmpData8;
ct: array[0..255] of TRGBQuad;
dr, dg, db, br, bg, bb: Byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

bmp8 := TBitmap.Create;
bmp8.PixelFormat := pf8bit;
bmp8.Width := w;
bmp8.Height := h;

Dark := ColorToRGB(Dark);
Bright := ColorToRGB(Bright);
dr := GetRValue(Dark); dg := GetGValue(Dark); db := GetBValue(Dark);
br := GetRValue(Bright); bg := GetGValue(Bright); bb := GetBValue(Bright);
for i := 0 to 255 do
begin
ct[i].rgbRed := Round(dr+(br-dr)*i/255);
ct[i].rgbGreen := Round(dg+(bg-dg)*i/255);
ct[i].rgbBlue := Round(db+(bb-db)*i/255);
ct[i].rgbReserved := 0;
end;
SetDIBColorTable(bmp8.Canvas.Handle,0,256,ct);
DeleteObject(bmp8.ReleasePalette);
src := TBmpData24.Create(bmp);
dst := TBmpData8.Create(bmp8);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy];
dst[ix, iy]^ := Trunc(0.299*d^.rgbtRed + 0.587*d^.rgbtGreen +
0.114*d^.rgbtBlue);
end;

dst.Free;
src.Free;

bmp.Free;
bmp := bmp8;
result := true;
end;

function Gamma(bmp: TBitmap; dGamma: single):Boolean;


var
ga: array[0..255] of byte;
bd: TBmpData24;
d: PRGBTriple;
w, h, ix, iy, i: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if (dGamma < 0.2) or (dGamma > 5.0) then exit;
w := bmp.Width;
h := bmp.Height;

for i := 0 to 255 do
ga[i] := Trunc(Min(255.0, ( 255.0 * Power(i/255.0, 1.0/dGamma)) + 0.5));

bd := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := bd[ix, iy];
d^.rgbtRed := ga[d^.rgbtRed];
d^.rgbtGreen := ga[d^.rgbtGreen];
d^.rgbtBlue := ga[d^.rgbtBlue];
end;

bd.Free;

result := true;
end;

function ColorFilter(bmp: TBitmap; fRed, fGreen, fBlue: single):Boolean;


var
bd: TBmpData24;
w, h, ix, iy: integer;
d: TRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

bd := TBmpData24.Create(bmp);

fRed := 1.0+fRed/100;
fGreen := 1.0+fGreen/100;
fBlue := 1.0+fBlue/100;

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := bd[ix,iy]^;
bd[ix,iy]^.rgbtRed := AdjustByte(d.rgbtRed*fRed);
bd[ix,iy]^.rgbtGreen := AdjustByte(d.rgbtGreen*fGreen);
bd[ix,iy]^.rgbtBlue := AdjustByte(d.rgbtBlue*fBlue);
end;

bd.Free;

result := true;
end;

function Saturation(bmp: TBitmap; percent: extended):Boolean;


var
bd: TBmpData24;
w, h, ix, iy: integer;
d: TRGBTriple;
SatComp, SatCompR, SatCompG, SatCompB, level: extended;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

level := 1+percent/100;
SatComp := 1.0 - level;
SatCompR := 0.3086 * SatComp;
SatCompG := 0.6094 * SatComp;
SatCompB := 0.0820 * SatComp;

bd := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := bd[ix,iy]^;
bd[ix,iy]^.rgbtRed := AdjustByte(d.rgbtRed*(SatCompR+level)+
d.rgbtGreen*SatCompG+
d.rgbtBlue*SatCompB);

bd[ix,iy]^.rgbtGreen := AdjustByte(d.rgbtRed*SatCompR+
d.rgbtGreen*(SatCompG+level)+
d.rgbtBlue*SatCompB);

bd[ix,iy]^.rgbtBlue := AdjustByte(d.rgbtRed*SatCompR+
d.rgbtGreen*SatCompG+
d.rgbtBlue*(SatCompB+level));
end;
bd.Free;

result := true;
end;

function Sobel(var bmp: TBitmap; fGray: Boolean = true):Boolean;


const
hmask: array[-1..1] of array[-1..1] of integer = ((-1,-2,-1),
( 0, 0, 0),
( 1, 2, 1));
vmask: array[-1..1] of array[-1..1] of integer = ((-1, 0, 1),
(-2, 0, 2),
(-1, 0, 1));
var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
rv, gv, bv, rh, gh, bh: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
rv := 0; gv := 0; bv := 0; rh := 0; gh := 0; bh := 0;
for y := iy-1 to iy+1 do
for x := ix-1 to ix+1 do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

rv := rv + vmask[x-ix,y-iy]*d^.rgbtRed;
gv := gv + vmask[x-ix,y-iy]*d^.rgbtGreen;
bv := bv + vmask[x-ix,y-iy]*d^.rgbtBlue;

rh := rh + hmask[x-ix,y-iy]*d^.rgbtRed;
gh := gh + hmask[x-ix,y-iy]*d^.rgbtGreen;
bh := bh + hmask[x-ix,y-iy]*d^.rgbtBlue;
end;
d := dst[ix,iy];

d^.rgbtRed := AdjustByte(sqrt(rv*rv+rh*rh));
d^.rgbtGreen := AdjustByte(sqrt(gv*gv+gh*gh));
d^.rgbtBlue := AdjustByte(sqrt(bv*bv+bh*bh));

end;

dst.Free;
src.Free;

tmp.Free;

if fGray then GrayScale(bmp);

result := true;
end;

function Laplacian(var bmp: TBitmap; fGray: Boolean = true):Boolean;


const
mask: array[-1..1] of array[-1..1] of integer = (( 0,-1, 0),
(-1, 4,-1),
( 0,-1, 0));
var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
r := 0; g := 0; b := 0;
for y := iy-1 to iy+1 do
for x := ix-1 to ix+1 do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

r := r + mask[x-ix,y-iy]*d^.rgbtRed;
g := g + mask[x-ix,y-iy]*d^.rgbtGreen;
b := b + mask[x-ix,y-iy]*d^.rgbtBlue;

end;
d := dst[ix,iy];

d^.rgbtRed := AdjustByte(r+127);
d^.rgbtGreen := AdjustByte(g+127);
d^.rgbtBlue := AdjustByte(b+127)
end;

dst.Free;
src.Free;

tmp.Free;
if fGray then GrayScale(bmp);

result := true;
end;

function EdgeEnhance(var bmp: TBitmap; percent: integer = 50):Boolean;


const
mask: array[-1..1] of array[-1..1] of integer = (( 0,-1, 0),
(-1, 4,-1),
( 0,-1, 0));
var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
rate : Extended;
begin
result := false;
if (percent<0) or (percent>100) then exit;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

rate := percent/100;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
r := 0; g := 0; b := 0;
for y := iy-1 to iy+1 do
for x := ix-1 to ix+1 do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

r := r + mask[x-ix,y-iy]*d^.rgbtRed;
g := g + mask[x-ix,y-iy]*d^.rgbtGreen;
b := b + mask[x-ix,y-iy]*d^.rgbtBlue;

end;
d := dst[ix,iy];

d^.rgbtRed := AdjustByte(d^.rgbtRed + rate*r);


d^.rgbtGreen := AdjustByte(d^.rgbtGreen + rate*g);
d^.rgbtBlue := AdjustByte(d^.rgbtBlue + rate*b)
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Edge(var bmp: TBitmap; fGray: Boolean = true):Boolean;


const
mask: array[-1..1] of array[-1..1] of integer = ((-1,-1,-1),
(-1, 8,-1),
(-1,-1,-1));
var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
r := 0; g := 0; b := 0;
for y := iy-1 to iy+1 do
for x := ix-1 to ix+1 do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

r := r + mask[x-ix,y-iy]*d^.rgbtRed;
g := g + mask[x-ix,y-iy]*d^.rgbtGreen;
b := b + mask[x-ix,y-iy]*d^.rgbtBlue;

end;
d := dst[ix,iy];

d^.rgbtRed := AdjustByte(r+127);
d^.rgbtGreen := AdjustByte(g+127);
d^.rgbtBlue := AdjustByte(b+127)
end;

dst.Free;
src.Free;

tmp.Free;

if fGray then GrayScale(bmp);

result := true;
end;

function Sharpen(var bmp: TBitmap; percent: integer = 50):Boolean;


const
mask: array[-1..1] of array[-1..1] of integer = ((-1,-1,-1),
(-1, 8,-1),
(-1,-1,-1));
var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
rate: extended;
begin
result := false;
if (percent<0) or (percent>100) then exit;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

rate := percent/100;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
r := 0; g := 0; b := 0;
for y := iy-1 to iy+1 do
for x := ix-1 to ix+1 do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

r := r + mask[x-ix,y-iy]*d^.rgbtRed;
g := g + mask[x-ix,y-iy]*d^.rgbtGreen;
b := b + mask[x-ix,y-iy]*d^.rgbtBlue;

end;
d := dst[ix,iy];

d^.rgbtRed := AdjustByte(d^.rgbtRed + rate*r);


d^.rgbtGreen := AdjustByte(d^.rgbtGreen + rate*g);
d^.rgbtBlue := AdjustByte(d^.rgbtBlue + rate*b)
end;

dst.Free;
src.Free;

tmp.Free;

result := true;
end;

function ColorSort(Item1, Item2: Pointer): Integer;


begin
result := byte(Item1)-byte(Item2);
end;

function Median(var bmp: TBitmap; area: integer = 1):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
rl, gl, bl: TList;
md, num, indx: integer;
begin
result := false;
if (area<1) or (area>4) then exit;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

num := (2*area+1)*(2*area+1);
md := Round(num/2);

rl := TList.Create; rl.Capacity := num; rl.Count := num;


gl := Tlist.Create; gl.Capacity := num; gl.Count := num;
bl := TList.Create; bl.Capacity := num; bl.Count := num;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
indx := 0;
for y := iy-area to iy+area do
for x := ix-area to ix+area do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

rl[indx] := pointer(d^.rgbtRed);
gl[indx] := pointer(d^.rgbtGreen);
bl[indx] := pointer(d^.rgbtBlue);
inc(indx);
end;

rl.Sort(ColorSort);
gl.Sort(ColorSort);
bl.Sort(ColorSort);

d := dst[ix,iy];

d^.rgbtRed := byte(rl[md]);
d^.rgbtGreen := byte(gl[md]);
d^.rgbtBlue := byte(bl[md]);
end;

dst.Free;
src.Free;
rl.Free;
gl.Free;
bl.Free;

tmp.Free;

result := true;
end;

procedure RGBToHSL(rgb: TRGBTriple; var h, s, l :integer);


var
r, g, b, hh, ss, ll, maxc, minc, cr, cg, cb:extended;
begin
r := rgb.rgbtRed/255;
g := rgb.rgbtGreen/255;
b := rgb.rgbtBlue/255;

maxc := Max(Max(r,g),b);
minc := Min(Min(r,g),b);

ll := (maxc+minc)/2;

if (maxc - minc) < 0.000001 then


begin
ss := 0;
hh := 0;
end
else
begin
if ll<=0.5 then
ss := (maxc-minc)/(maxc+minc)
else
ss := (maxc-minc)/(2-maxc-minc);

cr := (maxc-r)/(maxc-minc);
cg := (maxc-g)/(maxc-minc);
cb := (maxc-b)/(maxc-minc);
if maxc=r then
hh := cb-cg
else
if maxc=g then
hh := 2+cr-cb
else
hh := 4+cg-cr;

hh := 60*hh;
if hh<0 then hh := hh+360;
end;

h := trunc(hh);
s := trunc(ss*100);
l := trunc(ll*100);

end;

procedure HSLToRGB(rgb: PRGBTriple; h, s, l :integer);


var
ss, ll, r, g, b, maxc, minc: extended;
hh, hhh: integer;
begin
hh := h;
ss := s/100;
ll := l/100;

r := 0; g := 0; b := 0;

if s = 0 then
begin
r := ll;
g := ll;
b := ll;
end
else
begin
if ll<=0.5 then
maxc := ll*(1+ss)
else
maxc := ll*(1-ss)+ss;

minc := 2*ll-maxc;

hhh := hh+120;
if hhh>=360 then hhh := hhh-360;
case hhh of
0..59 : r := minc+(maxc-minc)*hhh/60;
60..179 : r := maxc;
180..239: r := minc+(maxc-minc)*(240-hhh)/60;
240..359: r := minc;
end;

hhh := hh;
case hhh of
0..59 : g := minc+(maxc-minc)*hhh/60;
60..179 : g := maxc;
180..239: g := minc+(maxc-minc)*(240-hhh)/60;
240..359: g := minc;
end;

hhh := hh-120;
if hhh<0 then hhh := hhh+360;
case hhh of
0..59 : b := minc+(maxc-minc)*hhh/60;
60..179 : b := maxc;
180..239: b := minc+(maxc-minc)*(240-hhh)/60;
240..359: b := minc;
end;
end;

rgb^.rgbtRed := trunc(r*255);
rgb^.rgbtGreen := trunc(g*255);
rgb^.rgbtBlue := trunc(b*255);
end;

function Hue(bmp: TBitmap; angle: integer = 20):Boolean;


var
tmp:TBitmap;
w, h, ix, iy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
hh, ss, ll :integer;
begin
result := false;

if (angle<0) or (angle>360) then exit;

if bmp.PixelFormat <> pf24bit then exit;


w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy];
RGBToHSL(d^, hh, ss, ll);
hh := (hh+angle) mod 360;
HSLToRGB(dst[ix,iy],hh,ss,ll);
end;

dst.Free;
src.Free;

tmp.Free;

result := true;
end;

function Luminance(bmp: TBitmap; percent: integer = 20):Boolean;


var
tmp:TBitmap;
w, h, ix, iy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
hh, ss, ll :integer;
begin
result := false;

if (percent<-100) or (percent>100) then exit;

if bmp.PixelFormat <> pf24bit then exit;


w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
d := src[ix,iy];
RGBToHSL(d^, hh, ss, ll);
ll := trunc(ll*(1+percent/100));
if ll>100 then ll := 100;
HSLToRGB(dst[ix,iy],hh,ss,ll);
end;

dst.Free;
src.Free;
tmp.Free;

result := true;
end;

function HistoStretch(grayBMP: TBitmap):Boolean;


var
bd: TBmpData8;
i, w, h, x, y: integer;
hist: array[0..255] of integer;
threshold, lt, ht, originalrange, stretchedrange: integer;
stretchfactor, scalefactor: single;
begin
result := false;
if grayBMP.PixelFormat <> pf8bit then exit;
w := grayBMP.Width;
h := grayBMP.Height;

for i := 0 to 255 do hist[i] := 0;

stretchfactor := 1.00;
threshold := Round(w*h*0.015);

bd := TBmpData8.Create(grayBMP);

for y := 0 to h-1 do
for x := 0 to w-1 do
inc(hist[bd[x,y]^]);

lt := 0;
for i := 0 to 255 do
begin
lt := lt + hist[i];
if lt > threshold then
begin
lt := i;
break;
end;
end;

ht := 0;
for i := 255 downto 0 do
begin
ht := ht + hist[i];
if ht > threshold then
begin
ht := i;
break;
end;
end;
originalrange := ht - lt + 1;
stretchedrange := originalrange + Round(stretchfactor * (255 - originalrange));
scaleFactor := stretchedrange / originalrange;

for y := 0 to h-1 do
for x := 0 to w-1 do
bd[x,y]^ := AdjustByte(scalefactor * (bd[x,y]^ - lt));

bd.Free;

result := true;
end;

function BlackWhite(var bmp24: TBitmap; threshold: byte = 127): Boolean;


var
bmp1: TBitmap;
src: TBmpData8;
dst: TBmpData1;
ix, iy, w, h: integer;
begin
result := false;
if bmp24.PixelFormat <> pf24bit then exit;
w := bmp24.Width;
h := bmp24.Height;

bmp1 := TBitmap.Create;
bmp1.PixelFormat := pf1bit;
bmp1.Width := w;
bmp1.Height := h;

GrayScale(bmp24);

src := TBmpData8.Create(bmp24);
dst := TBmpData1.Create(bmp1);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
dst[ix,iy] := src[ix,iy]^ > threshold;

dst.Free;
src.Free;

bmp24.Free;

bmp24 := bmp1;

result := true;
end;

function RandomDither(var bmp24: TBitmap;


ErrorDiffusion: TErrorDiffusion = edStucki;
Dark: TColor = clBlack;
Bright: TColor = clWhite;
randomness: integer = 30;
Stretch: Boolean = true): Boolean;
const
FSmask: array[-1..1,0..1] of single = ((0,3/16), (0,5/16), (7/16, 1/16));
STmask: array[-2..2,0..2] of single
= ((0, 2/42, 1/42), (0, 4/42, 2/42), (0, 8/42, 4/42),
(8/42, 4/42, 2/42), (4/42, 2/42, 1/42));
SRmask: array[-2..2,0..2] of single
= ((0, 2/32, 0), (0, 4/32, 2/32), (0, 5/32, 3/32),
(5/32, 4/32, 2/32), (3/32, 2/32, 0));
JJmask: array[-2..2,0..2] of single
= ((0, 3/48, 1/48), (0, 5/48, 3/48), (0, 7/48, 5/48),
(7/48, 5/48, 3/48), (5/48, 3/48, 1/48));
var
bmp1: TBitmap;
src: TBmpData8;
dst: TBmpData1;
ix, iy, xx, yy, w, h: integer;
p8 : PByte;
d: Boolean;
err: integer;
ct: array[0..1] of TRGBQuad;
mfactor: integer;
begin
result := false;
if bmp24.PixelFormat <> pf24bit then exit;
w := bmp24.Width;
h := bmp24.Height;

bmp1 := TBitmap.Create;
bmp1.PixelFormat := pf1bit;
bmp1.Width := w;
bmp1.Height := h;

Dark := ColorToRGB(Dark);
ct[0].rgbBlue := GetBValue(Dark);
ct[0].rgbGreen := GetGValue(Dark);
ct[0].rgbRed := GetRValue(Dark);
ct[0].rgbReserved := 0;

Bright := ColorToRGB(Bright);
ct[1].rgbBlue := GetBValue(Bright);
ct[1].rgbGreen :=GetGValue(Bright);
ct[1].rgbRed := GetRValue(Bright);
ct[1].rgbReserved := 0;

SetDIBColorTable(bmp1.Canvas.Handle,0,2,ct);
DeleteObject(bmp1.ReleasePalette);

GrayScale(bmp24);

if Stretch then HistoStretch(bmp24);

Randomize;
mfactor := (256-randomness) div 2;

src := TBmpData8.Create(bmp24);
dst := TBmpData1.Create(bmp1);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
p8 := src[ix,iy];
d := p8^ > (Random(randomness)+mfactor);
dst[ix,iy] := d;
if ErrorDiffusion = edNone then continue;

if d then err := p8^-255 else err := p8^;

case ErrorDiffusion of
edFloydSteinberg: begin
for yy := iy to iy+1 do
for xx := ix-1 to ix+1 do
begin
if FSmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*FSmask[xx-ix,yy-iy]);
end;
end;
edStucki: begin
for yy := iy to iy+2 do
for xx := ix-2 to ix+2 do
begin
if STmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*STmask[xx-ix,yy-iy]);
end;
end;
edSierra: begin
for yy := iy to iy+2 do
for xx := ix-2 to ix+2 do
begin
if SRmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*SRmask[xx-ix,yy-iy]);
end;
end;
edJaJuNi: begin
for yy := iy to iy+2 do
for xx := ix-2 to ix+2 do
begin
if JJmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*JJmask[xx-ix,yy-iy]);
end;
end;
end;
end;

dst.Free;
src.Free;
bmp24.Free;

bmp24 := bmp1;

result := true;
end;

function OrderedDither(var bmp24: TBitmap;


ErrorDiffusion: TErrorDiffusion = edStucki;
Dark: TColor = clBlack;
Bright: TColor = clWhite;
Stretch: Boolean = true):Boolean;
const
//ptn: array[0..2] of array[0..2] of byte = ((64, 128, 64),(128, 196, 128),
// (64, 128, 64));
//ptn: array[0..1] of array[0..1] of byte = ((51, 153),(204, 102));
ptn: array[0..3] of array[0..3] of byte = (( 51, 204, 153, 102),
( 102, 153, 204, 51),
( 204, 51, 102, 153),
( 153, 102, 51, 204));

FSmask: array[-1..1,0..1] of single = ((0,3/16), (0,5/16), (7/16, 1/16));


STmask: array[-2..2,0..2] of single
= ((0, 2/42, 1/42), (0, 4/42, 2/42), (0, 8/42, 4/42),
(8/42, 4/42, 2/42), (4/42, 2/42, 1/42));
SRmask: array[-2..2,0..2] of single
= ((0, 2/32, 0), (0, 4/32, 2/32), (0, 5/32, 3/32),
(5/32, 4/32, 2/32), (3/32, 2/32, 0));
JJmask: array[-2..2,0..2] of single
= ((0, 3/48, 1/48), (0, 5/48, 3/48), (0, 7/48, 5/48),
(7/48, 5/48, 3/48), (5/48, 3/48, 1/48));
var
bmp1:TBitmap;
w, h, ix, iy, xx, yy, area: integer;
src: TBmpData8;
dst: TBmpData1;
ct: array[0..1] of TRGBQuad;
p8: PByte;
d: Boolean;
err: integer;
begin
result := false;
if bmp24.PixelFormat <> pf24bit then exit;
w := bmp24.Width;
h := bmp24.Height;

GrayScale(bmp24);

if stretch then HistoStretch(bmp24);

bmp1 := TBitmap.Create;
bmp1.PixelFormat := pf1bit;
bmp1.Width := w;
bmp1.Height := h;

Dark := ColorToRGB(Dark);
ct[0].rgbBlue := GetBValue(Dark);
ct[0].rgbGreen := GetGValue(Dark);
ct[0].rgbRed := GetRValue(Dark);
ct[0].rgbReserved := 0;

Bright := ColorToRGB(Bright);
ct[1].rgbBlue := GetBValue(Bright);
ct[1].rgbGreen :=GetGValue(Bright);
ct[1].rgbRed := GetRValue(Bright);
ct[1].rgbReserved := 0;

SetDIBColorTable(bmp1.Canvas.Handle,0,2,ct);
DeleteObject(bmp1.ReleasePalette);

//area := 2;
//area := 3;
area := 4;

src := TBmpData8.Create(bmp24);
dst := TBmpData1.Create(bmp1);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
p8 := src[ix, iy];
d := p8^ > ptn[ix mod area, iy mod area];
dst[ix,iy] := d;

if ErrorDiffusion = edNone then continue;

if d then err := p8^-255 else err := p8^;

case ErrorDiffusion of
edFloydSteinberg: begin
for yy := iy to iy+1 do
for xx := ix-1 to ix+1 do
begin
if FSmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*FSmask[xx-ix,yy-iy]);
end;
end;
edStucki: begin
for yy := iy to iy+2 do
for xx := ix-2 to ix+2 do
begin
if STmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*STmask[xx-ix,yy-iy]);
end;
end;
edSierra: begin
for yy := iy to iy+2 do
for xx := ix-2 to ix+2 do
begin
if SRmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*SRmask[xx-ix,yy-iy]);
end;
end;
edJaJuNi: begin
for yy := iy to iy+2 do
for xx := ix-2 to ix+2 do
begin
if JJmask[xx-ix,yy-iy] = 0 then continue;
if (xx<0) or (xx>w-1) then continue;
if yy>h-1 then continue;

p8 := src[xx,yy];
p8^ := AdjustByte(p8^ + err*JJmask[xx-ix,yy-iy]);
end;
end;
end;
end;

dst.Free;
src.Free;

bmp24.Free;
bmp24 := bmp1;

result := true;
end;

function BmpResize(var bmp: TBitmap;


rwidth, rheight: integer;
mode: TResizeMode = rmBilinear):Boolean;
var
tmp: TBitmap;
src, dst: TBmpData24;
wfactor, hfactor, coefx00, coefx01, coefy00, coefy01: extended;
ix, iy, fx, fy, x, y, w, h, x0, x1, y0, y1: integer;
xx, yy, r1, r2, g1, g2, b1, b2, r, g, b: extended;
dxx, dyy, dx, dy, wx, wy: extended;
d, d00, d10, d01, d11: PRGBTriple;

dxn: array[1..4] of extended;


dyn: array[0..3] of extended;
RX, RY: array[-1..2] of extended;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

wfactor := w/rwidth;
hfactor := h/rheight;

tmp := BmpClone(bmp);
tmp.Width := rwidth;
tmp.Height := rheight;
src := TBmpData24.Create(bmp);
dst := TBmpData24.Create(tmp);

for iy := 0 to rheight-1 do
for ix := 0 to rwidth-1 do
case mode of
rmNearest:
begin
x0 := Round(wfactor*ix); if x0>w-1 then x0 := w-1;
y0 := Round(hfactor*iy); if y0>h-1 then y0 := h-1;
dst[ix,iy]^ := src[x0,y0]^;
end;
rmBilinear:
begin
xx := wfactor*ix;
yy := hfactor*iy;

x0 := trunc(xx); if x0<0 then x0 := 0;


x1 := x0+1; if x1>w-1 then x1 := x0;
y0 := trunc(yy); if y0<0 then y0 := 0;
y1 := y0+1; if y1>h-1 then y1 := y0;

coefx01 := xx-x0; coefx00 := 1-coefx01;


coefy01 := yy-y0; coefy00 := 1-coefy01;

d := dst[ix,iy];
d00 := src[x0, y0]; d10 := src[x1,y0];
d01 := src[x0, y1]; d11 := src[x1,y1];

r1 := d00^.rgbtRed*coefx00 + d10^.rgbtRed*coefx01;
r2 := d01^.rgbtRed*coefx00 + d11^.rgbtRed*coefx01;
d^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := d00^.rgbtGreen*coefx00 + d10^.rgbtGreen*coefx01;
g2 := d01^.rgbtGreen*coefx00 + d11^.rgbtGreen*coefx01;
d^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := d00^.rgbtBlue*coefx00 + d10^.rgbtBlue*coefx01;
b2 := d01^.rgbtBlue*coefx00 + d11^.rgbtBlue*coefx01;
d^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
rmBicubic:
begin
xx := wfactor*ix; x := trunc(xx);
yy := hfactor*iy; y := trunc(yy);

r := 0; g := 0; b := 0;
for fy := y-1 to y+2 do
for fx := x-1 to x+2 do
begin
dx := Abs(xx-fx);
dy := Abs(yy-fy);

if dx<1 then
wx := (dx-1)*(dx*dx-dx-1)
else
wx := -(dx-1)*(dx-2)*(dx-2);
if dy<1 then
wy := (dy-1)*(dy*dy-dy-1)
else
wy := -(dy-1)*(dy-2)*(dy-2);

x0 := fx; if (x0<0) or (x0>w-1) then x0 := x;


y0 := fy; if (y0<0) or (y0>h-1) then y0 := y;

d := src[x0,y0];

r := r + d^.rgbtRed*wx*wy;
g := g + d^.rgbtGreen*wx*wy;
b := b + d^.rgbtBlue*wx*wy;
end;

dst[ix,iy]^.rgbtRed := AdjustByte(r);
dst[ix,iy]^.rgbtGreen := AdjustByte(g);
dst[ix,iy]^.rgbtBlue := AdjustByte(b);
end;
rmMitchell:
begin
xx := wfactor*ix; x := trunc(xx);
yy := hfactor*iy; y := trunc(yy);

r := 0; g := 0; b := 0;
for fy := y-1 to y+2 do
for fx := x-1 to x+2 do
begin
dx := Abs(xx-fx);
dy := Abs(yy-fy);

if dx<1 then
wx := 7*dx*dx*dx/6-2*dx*dx+8/9
else
wx := 2*dx*dx-10*dx/3-7*dx*dx*dx/18+16/9;

if dy<1 then
wy := 7*dy*dy*dy/6-2*dy*dy+8/9
else
wy := 2*dy*dy-10*dy/3-7*dy*dy*dy/18+16/9;

x0 := fx; if (x0<0) or (x0>w-1) then x0 := x;


y0 := fy; if (y0<0) or (y0>h-1) then y0 := y;

r := r + src[x0,y0]^.rgbtRed*wx*wy;
g := g + src[x0,y0]^.rgbtGreen*wx*wy;
b := b + src[x0,y0]^.rgbtBlue*wx*wy;
end;

dst[ix,iy]^.rgbtRed := AdjustByte(r);
dst[ix,iy]^.rgbtGreen := AdjustByte(g);
dst[ix,iy]^.rgbtBlue := AdjustByte(b);
end;
rmLagrange:
begin
xx := wfactor*ix; x := trunc(xx);
yy := hfactor*iy; y := trunc(yy);

r := 0; g := 0; b := 0;
for fy := y-1 to y+2 do
for fx := x-1 to x+2 do
begin
dx := Abs(xx-fx);
dy := Abs(yy-fy);

if dx<1 then
wx := 0.5*(dx-2)*(dx+1)*(dx-1)
else
wx := -(dx-3)*(dx-2)*(dx-1)/6;

if dy<1 then
wy := 0.5*(dy-2)*(dy+1)*(dy-1)
else
wy := -(dy-3)*(dy-2)*(dy-1)/6;

x0 := fx; if (x0<0) or (x0>w-1) then x0 := x;


y0 := fy; if (y0<0) or (y0>h-1) then y0 := y;

r := r + src[x0,y0]^.rgbtRed*wx*wy;
g := g + src[x0,y0]^.rgbtGreen*wx*wy;
b := b + src[x0,y0]^.rgbtBlue*wx*wy;
end;

dst[ix,iy]^.rgbtRed := AdjustByte(r);
dst[ix,iy]^.rgbtGreen := AdjustByte(g);
dst[ix,iy]^.rgbtBlue := AdjustByte(b);
end;
rmBSpline:
begin
xx := wfactor*ix; x := trunc(xx);
yy := hfactor*iy; y := trunc(yy);

dxx := xx-x;
dyy := yy-y;

dxn[1] := 1-dxx; dxn[1] := dxn[1]*dxn[1]*dxn[1]/6;


dxn[2] := 2-dxx; dxn[2] := dxn[2]*dxn[2]*dxn[2]/6;
dxn[3] := 3-dxx; dxn[3] := dxn[3]*dxn[3]*dxn[3]/6;
dxn[4] := 4-dxx; dxn[4] := dxn[4]*dxn[4]*dxn[4]/6;

dyn[0] := 0+dyy; dyn[0] := dyn[0]*dyn[0]*dyn[0]/6;


dyn[1] := 1+dyy; dyn[1] := dyn[1]*dyn[1]*dyn[1]/6;
dyn[2] := 2+dyy; dyn[2] := dyn[2]*dyn[2]*dyn[2]/6;
dyn[3] := 3+dyy; dyn[3] := dyn[3]*dyn[3]*dyn[3]/6;

RX[-1] := dxn[1];
RX[0] := dxn[2]-4*dxn[1];
RX[1] := dxn[3]-4*dxn[2]+6*dxn[1];
RX[2] := dxn[4]-4*dxn[3]+6*dxn[2]-4*dxn[1];

RY[-1] := dyn[3]-4*dyn[2]+6*dyn[1]-4*dyn[0];
RY[0] := dyn[2]-4*dyn[1]+6*dyn[0];
RY[1] := dyn[1]-4*dyn[0];
RY[2] := dyn[0];

r := 0; g := 0; b := 0;
for fy := y-1 to y+2 do
for fx := x-1 to x+2 do
begin
x0 := fx; if (x0<0) or (x0>w-1) then x0 := x;
y0 := fy; if (y0<0) or (y0>h-1) then y0 := y;

r := r + src[x0,y0]^.rgbtRed*RX[fx-x]*RY[fy-y];
g := g + src[x0,y0]^.rgbtGreen*RX[fx-x]*RY[fy-y];
b := b + src[x0,y0]^.rgbtBlue*RX[fx-x]*RY[fy-y];
end;

dst[ix,iy]^.rgbtRed := AdjustByte(r);
dst[ix,iy]^.rgbtGreen := AdjustByte(g);
dst[ix,iy]^.rgbtBlue := AdjustByte(b);
end;
end;

src.Free;
dst.Free;
bmp.Free;
bmp := tmp;
result := true;
end;

function HueHistogram(bmp24: TBitmap): TBitmap;


var
bd: TBmpData24;
c: TRGBTriple;
w, h, i, x, y, hh, ss, ll, max: integer;
ht: array[0..359] of integer;
begin
result := nil;
if bmp24.PixelFormat <> pf24bit then exit;

w := bmp24.Width;
h := bmp24.Height;

for i := 0 to 359 do ht[i] := 0;

bd := TBmpData24.Create(bmp24);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
c := bd[x,y]^;
RGBToHSL(c, hh, ss, ll);
inc(ht[hh]);
end;

bd.Free;

max := 0;
for i := 0 to 359 do
if ht[i] > max then max := ht[i];

result := TBitmap.Create;
result.PixelFormat := pf24bit;
result.Width := 370;
result.Height := 160;

for i := 0 to 359 do
begin
HSLToRGB(@c, i, 60, 40);
result.Canvas.Pen.Color := RGB(c.rgbtRed, c.rgbtGreen, c.rgbtBlue);
result.Canvas.MoveTo(5+i, 155);
result.Canvas.LineTo(5+i, 155-Round(ht[i]*150/max));
end;
end;

function JAlphaBlend(dst: TCanvas; dstX, dstY: integer;


src: TBitmap; alpha: single):Boolean;
var
bf: TBlendFunction;
begin
bf.BlendOp := AC_SRC_OVER;
bf.BlendFlags := 0;
bf.SourceConstantAlpha := Round(alpha*255/100);
bf.AlphaFormat := 0;
result := Windows.AlphaBlend(dst.Handle, dstX, dstY, src.Width,
src.Height,src.Canvas.Handle, 0, 0, src.Width, src.Height, bf);
end;

function Blur(bmp: TBitmap; zone: integer = 1):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b, v: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

v := zone*2+1;
v := v*v;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
r := 0; g := 0; b := 0;
for y := iy-zone to iy+zone do
for x := ix-zone to ix+zone do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];

r := r + d^.rgbtRed;
g := g + d^.rgbtGreen;
b := b + d^.rgbtBlue;
end;
d := dst[ix,iy];
d^.rgbtRed := r div v;
d^.rgbtGreen := g div v;
d^.rgbtBlue := b div v;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Rank(bmp: TBitmap; mode: TRankMode = rkMax; zone: integer = 1):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
case mode of
rkMax: begin
r := 0; g := 0; b := 0;
end;
else begin
r := 255; g := 255; b := 255;
end;
end;
for y := iy-zone to iy+zone do
for x := ix-zone to ix+zone do
begin
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;
d := src[xx,yy];
case mode of
rkMax: begin
if r<d^.rgbtRed then r := d^.rgbtRed;
if g<d^.rgbtGreen then g := d^.rgbtGreen;
if b<d^.rgbtBlue then b := d^.rgbtBlue;
end;
else begin
if r>d^.rgbtRed then r := d^.rgbtRed;
if g>d^.rgbtGreen then g := d^.rgbtGreen;
if b>d^.rgbtBlue then b := d^.rgbtBlue;
end;
end;
end;
d := dst[ix,iy];

d^.rgbtRed := r;
d^.rgbtGreen := g;
d^.rgbtBlue := b;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Range(var bmp: TBitmap; zone: integer = 1; Gray: Boolean = true):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y: integer;
src, dst: TBmpData24;
d: PRGBTriple;
rmax, gmax, bmax, rmin, gmin, bmin: byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
rmax := 0; gmax := 0; bmax := 0;
rmin := 255; gmin := 255; bmin := 255;
for y := iy-zone to iy+zone do
for x := ix-zone to ix+zone do
begin
if (y<0) or (y>h-1) then continue;
if (x<0) or (x>w-1) then continue;
d := src[x,y];

if rmax<d^.rgbtRed then rmax := d^.rgbtRed;


if gmax<d^.rgbtGreen then gmax := d^.rgbtGreen;
if bmax<d^.rgbtBlue then bmax := d^.rgbtBlue;

if rmin>d^.rgbtRed then rmin := d^.rgbtRed;


if gmin>d^.rgbtGreen then gmin := d^.rgbtGreen;
if bmin>d^.rgbtBlue then bmin := d^.rgbtBlue;
end;
d := dst[ix,iy];

d^.rgbtRed := rmax-rmin;
d^.rgbtGreen := gmax-gmin;
d^.rgbtBlue := bmax-bmin;
end;
dst.Free;
src.Free;

tmp.Free;

if Gray then
result := GrayScale(bmp)
else
result := true;
end;

function PointF(X, Y: single): TPointF;


begin
result.X := X;
result.Y := Y;
end;

function Rotation(var bmp: TBitmap; angle: single; bkColor: TColor): Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
pts: array[0..3] of TPointF;
sn, cs: single;
srcRect: TRect;
w, h, ww, hh, i, ix, iy: integer;
sx, sy, rx, ry, xmin, xmax, ymin, ymax: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := w+2;
tmp.Height := h+2;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,w+2,h+2));
tmp.Canvas.Draw(1, 1, bmp);
bmp.Free;
bmp := tmp;

pts[0] := PointF(0, 0);


pts[1] := PointF(w, 0);
pts[2] := PointF(w, h);
pts[3] := PointF(0, h);

angle := -angle;
sn := sin(pi*angle/180);
cs := cos(pi*angle/180);
for i := 0 to 3 do
pts[i] := PointF(pts[i].X*cs+pts[i].Y*sn, -pts[i].X*sn+pts[i].Y*cs);

xmin := 100000; xmax := -100000;


ymin := 100000; ymax := -100000;
for i := 0 to 3 do
begin
if xmin>pts[i].X then xmin := pts[i].X;
if xmax<pts[i].X then xmax := pts[i].X;
if ymin>pts[i].Y then ymin := pts[i].Y;
if ymax<pts[i].Y then ymax := pts[i].Y;
end;

ww := Round(xmax-xmin+1);
hh := Round(ymax-ymin+1);

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := ww;
tmp.Height := hh;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,ww,hh));

angle := -angle;
sn := sin(pi*angle/180);
cs := cos(pi*angle/180);

src := TBmpData24.Create(bmp);
dst := TBmpData24.Create(tmp);

srcRect := Rect(0,0,w,h);

for iy := 0 to hh-1 do
for ix := 0 to ww-1 do
begin
rx := ix+xmin;
ry := iy+ymin;
sx := rx*cs+ry*sn;
sy := -rx*sn+ry*cs;
if PtInRect(srcRect, Point(Ceil(sx),Ceil(sy))) or
PtInRect(srcRect, Point(Floor(sx),Floor(sy)))
then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0+1, y0+1]^.rgbtRed*coefx00 + src[x1+1,y0+1]^.rgbtRed*coefx01;


r2 := src[x0+1, y1+1]^.rgbtRed*coefx00 + src[x1+1,y1+1]^.rgbtRed*coefx01;
dst[ix,iy]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0+1, y0+1]^.rgbtGreen*coefx00 +
src[x1+1,y0+1]^.rgbtGreen*coefx01;
g2 := src[x0+1, y1+1]^.rgbtGreen*coefx00 +
src[x1+1,y1+1]^.rgbtGreen*coefx01;
dst[ix,iy]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0+1, y0+1]^.rgbtBlue*coefx00 + src[x1+1,y0+1]^.rgbtBlue*coefx01;


b2 := src[x0+1, y1+1]^.rgbtBlue*coefx00 + src[x1+1,y1+1]^.rgbtBlue*coefx01;
dst[ix,iy]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;

bmp.Free;
bmp := tmp;

result := true;
end;

function OilPaint(bmp: TBitmap; zone: integer = 2):Boolean;


var
tmp:TBitmap;
w, h, ix, iy, x, y: integer;
src, dst: TBmpData24;
d: PRGBTriple;
rh, gh, bh: array[0..15] of integer;
i, rmax, gmax, bmax: integer;
rind, gind, bind: byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
rmax := 0; gmax := 0; bmax := 0;
rind := 0; gind := 0; bind := 0;
for i := 0 to 15 do
begin
rh[i] := 0; gh[i] := 0; bh[i] := 0;
end;

for y := iy-zone to iy+zone do


for x := ix-zone to ix+zone do
begin
if (y<0) or (y>h-1) then continue;
if (x<0) or (x>w-1) then continue;
d := src[x,y];
inc(rh[d^.rgbtRed shr 4]);
inc(gh[d^.rgbtGreen shr 4]);
inc(bh[d^.rgbtBlue shr 4]);
end;

for i := 0 to 15 do
begin
if rmax < rh[i] then begin rmax := rh[i]; rind := i; end;
if gmax < gh[i] then begin gmax := gh[i]; gind := i; end;
if bmax < bh[i] then begin bmax := bh[i]; bind := i; end;
end;
d := dst[ix,iy];

d^.rgbtRed := rind shl 4;


d^.rgbtGreen := gind shl 4;
d^.rgbtBlue := bind shl 4;
end;

dst.Free;
src.Free;

tmp.Free;

result := true;
end;

function GaussianBlur(bmp: TBitmap; zone:integer = 2): Boolean;


var
tmp: TBItmap;
src, dst: TBmpData24;
d: TRGBTriple;
w, h, i, x, y, ix, iy, range: integer;
count, sr, sg, sb, gauss: single;
gf: array of single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if (zone < 1) or (zone > 30) then exit;

w := bmp.Width;
h := bmp.Height;

range := zone*3;
SetLength(gf,range+1);

for i := 0 to range do
gf[i] := exp(-i*i/(2*zone*zone));

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

// at first, bmp -> tmp (x blur)


for y := 0 to h-1 do
for x := 0 to w-1 do
begin
count := 0;
sr := 0; sg := 0; sb := 0;
for ix := x-range to x+range do
begin
if (ix<0) or (ix>w-1) then continue;
d := dst[ix,y]^;
gauss := gf[abs(ix-x)];
sr := sr+d.rgbtRed*gauss;
sg := sg+d.rgbtGreen*gauss;
sb := sb+d.rgbtBlue*gauss;
count := count+gauss;
end;
src[x,y]^.rgbtBlue := AdjustByte(sb/count);
src[x,y]^.rgbtGreen := AdjustByte(sg/count);
src[x,y]^.rgbtRed := AdjustByte(sr/count);
end;

// second, tmp -> bmp (y blur)


for y := 0 to h-1 do
for x := 0 to w-1 do
begin
count := 0;
sr := 0; sg := 0; sb := 0;
for iy := y-range to y+range do
begin
if (iy<0) or (iy>h-1) then continue;
d := src[x, iy]^;
gauss := gf[abs(iy-y)];
sr := sr+d.rgbtRed*gauss;
sg := sg+d.rgbtGreen*gauss;
sb := sb+d.rgbtBlue*gauss;
count := count+gauss;
end;
dst[x,y]^.rgbtBlue := AdjustByte(sb/count);
dst[x,y]^.rgbtGreen := AdjustByte(sg/count);
dst[x,y]^.rgbtRed := AdjustByte(sr/count);
end;

src.Free;
dst.Free;
tmp.Free;

result := true;
end;

function Mirror(bmp: TBitmap;


mt: TMirrorType = mtLeft;
center: integer = 0): Boolean;
var
tmp:TBitmap;
w, h, ix, iy, w2: integer;
src, dst: TBmpData24;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

if center = 0 then w2 := w div 2 else w2 := center;

for iy := 0 to h-1 do
for ix := 0 to w-1 do
case mt of
mtLeft: if ix >= w2 then dst[ix,iy]^ := src[w-1-ix,iy]^;
mtRight: if ix < w2 then dst[ix,iy]^ := src[w-1-ix,iy]^;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Pixellate(bmp: TBitmap; area:integer):Boolean;


var
src: TBmpData24;
w, h, x, y, r, g, b, count: integer;
ix, iy, nd, nw, nh: integer;
d: PRGBTriple;
t: TRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if area < 2 then exit;
w := bmp.Width;
h := bmp.Height;

src := TBmpData24.Create(bmp);

nd := area-1;
nw := w div area; if (w mod area)<>0 then inc(nw);
nh := h div area; if (h mod area)<>0 then inc(nh);

for y := 0 to nh-1 do
begin
for x := 0 to nw-1 do
begin

b := 0; g := 0; r := 0; count := 0;
for iy := y*area to y*area+nd do
begin
if iy>h-1 then continue;
for ix := x*area to x*area+nd do
begin
if ix>w-1 then continue;
d := src[ix, iy];
b := b + d^.rgbtBlue;
g := g + d^.rgbtGreen;
r := r + d^.rgbtRed;
inc(count);
end;
end;

t.rgbtBlue := b div count;


t.rgbtGreen := g div count;
t.rgbtRed := r div count;

for iy := y*area to y*area+nd do


begin
if iy>h-1 then continue;
for ix := x*area to x*area+nd do
begin
if ix>w-1 then continue;
src[ix,iy]^ := t;
end;
end;

end;
end;

src.Free;
result := true;
end;

function Mosaic(bmp: TBitmap; area:integer; range: TRect):Boolean;


var
src: TBmpData24;
w, h, x, y, r, g, b, count: integer;
ix, iy, nd, nw, nh: integer;
d: PRGBTriple;
t: TRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if area < 2 then exit;
w := range.Right-range.Left+1;
h := range.Bottom-range.Top+1;

src := TBmpData24.Create(bmp);

nd := area-1;
nw := w div area; if (w mod area)<>0 then inc(nw);
nh := h div area; if (h mod area)<>0 then inc(nh);

for y := 0 to nh-1 do
begin
for x := 0 to nw-1 do
begin

b := 0; g := 0; r := 0; count := 0;
for iy := y*area to y*area+nd do
begin
if iy>h-1 then continue;
for ix := x*area to x*area+nd do
begin
if ix>w-1 then continue;
d := src[range.Left+ix, range.Top+iy];
b := b + d^.rgbtBlue;
g := g + d^.rgbtGreen;
r := r + d^.rgbtRed;
inc(count);
end;
end;

t.rgbtBlue := b div count;


t.rgbtGreen := g div count;
t.rgbtRed := r div count;

for iy := y*area to y*area+nd do


begin
if iy>h-1 then continue;
for ix := x*area to x*area+nd do
begin
if ix>w-1 then continue;
src[range.Left+ix, range.Top+iy]^ := t;
end;
end;

end;
end;

src.Free;
result := true;
end;

function RiceCake(bmp: TBitmap; factor: single = 0.8):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y, xx, c: integer;
//d: PRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

c := Round(w*factor);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
xx := Round(x + w*cos((x-c)*2*pi*2/w)/6);
if (xx>=0) and (xx<w) then
dst[x,y]^ := src[xx,y]^;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function PtFInRect(pt: TPointF; r: TRect): Boolean;


begin
result := (pt.X >= r.Left) and (pt.X <= r.Right) and
(pt.Y >= r.Top) and (pt.Y <= r.Bottom);
end;

function Caricature(bmp: TBitmap; factor: single = 100):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, a, c, cx, cy, sx, sy: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
cx := w/2;
cy := h/2;
rct := Rect(0,0,w-1,h-1);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2(y-cy,x-cx); // radian
sx := Sqrt(r*c)*Cos(a) + cx;
sy := Sqrt(r*c)*Sin(a) + cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;
dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Fisheye(bmp: TBitmap; factor: single = 100):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, rr, a, c, cx, cy, sx, sy: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
cx := w/2;
cy := h/2;
rct := Rect(0,0,w-1,h-1);
rr := Sqrt(cx*cx+cy*cy);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2(y-cy,x-cx); // radian
sx := c*r*r/rr*Cos(a) + cx;
sy := c*r*r/rr*Sin(a) + cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);
g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;
g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Swirl(bmp: TBitmap; factor: single = 0.05):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, rr, a, c, cx, cy, sx, sy: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
cx := w/2;
cy := h/2;
rct := Rect(0,0,w-1,h-1);
rr := Sqrt(cx*cx+cy*cy);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2(y-cy,x-cx); // radian
a := a + c*r;
sx := r*Cos(a) + cx;
sy := r*Sin(a) + cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Shear(bmp: TBitmap; entropy: single = 0.4): Boolean;


var
tmp:TBitmap;
w, h, x, y: integer;
src, dst: TBmpData24;
yshift: array of single;
sx, sy, r, dr: single;
rct: TRect;

x0, x1, y0, y1: integer;


r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

Randomize;
r := 0;
dr := entropy;
SetLength(yshift, w);
for x := 0 to w-1 do
begin
if Random(1001) > 500 then r := r+dr else r := r-dr;
yshift[x] := r;
end;
rct := Rect(0,0,w-2,h-2);
//r := 0;

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
if Random(1001) > 500 then r := r+dr else r := r-dr;
for x := 0 to w-1 do
begin
sx := x+r;
sy := y+yshift[x];
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Cylinder(bmp: TBitmap; cd: TCylinderDirection = cdVertical):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, a, xx, yy, sx, sy: single;
rct: TRect;

x0, x1, y0, y1: integer;


r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

rct := Rect(0,0,w,h);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(rct);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

if cd = cdVertical then
begin
r := w/2;

for x := 0 to w-1 do
begin
xx := x-r;
a := ArcTan2(sqrt(r*r-xx*xx),xx); // radian
sx := 2*r*(1-a/pi);
if (sx<0) or (sx>w-2) then continue;

for y := 0 to h-2 do
begin
sy := y;
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end
else
begin
r := h/2;

for y := 0 to h-1 do
begin
yy := y-r;
a := ArcTan2(sqrt(r*r-yy*yy),yy); // radian
sy := 2*r*(1-a/pi);
if (sy<0) or (sy>h-2) then continue;

for x := 0 to w-2 do
begin
sx := x;
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function SoftFisheye(bmp: TBitmap; factor: single = 0.8):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, a, c, e, cx, cy, rr, sx, sy: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if (factor<0.1) or (factor>1.1) then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
cx := w/2;
cy := h/2;
rr := Sqrt(cx*cx+cy*cy);
rct := Rect(0,0,w-2,h-2);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2(y-cy,x-cx); // radian
e := sin(c*r*pi/(2*rr)); e := sqrt(e)+0.1;
sx := r*e*Cos(a) + cx;
sy := r*e*Sin(a) + cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function BathroomWindow(bmp: TBitmap;


zone: integer = 10;
mode: TBathWindowMode = bwVertical):Boolean;
var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
xx, yy, rnd: integer;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

rnd := zone*2+1;
rct := Rect(0,0,w-1,h-1);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
xx := x; yy := y;
case mode of
bwVertical: xx := x + (x mod rnd) - zone;
bwHorizontal:yy := y + (y mod rnd) - zone;
bwBoth: begin
xx := x + (x mod rnd) - zone;
yy := y + (y mod rnd) - zone;
end;
end;
if PtInRect(rct,Point(xx,yy)) then dst[x,y]^ := src[xx,yy]^;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function BathroomWindow2(bmp: TBitmap; zone: integer = 8):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, a, cx, cy, sx, sy: single;
rnd: integer;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

rnd := zone*2+1;
cx := w/2;
cy := h/2;
rct := Rect(0,0,w-2,h-2);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2(y-cy,x-cx); // radian
sx := x + (Round(((a+pi)*180/pi+0.1*r)) mod rnd) + zone;
sy := y;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function SpotLight(bmp: TBitmap; radius: integer):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, c, cx, cy, rr: single;
d, s: PRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rr := radius*radius;

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clBlack;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := (x-cx)*(x-cx)+(y-cy)*(y-cy);
c :=1.1*(1-r/rr);
if c<0 then continue;
d := dst[x,y];
s := src[x,y];
d^.rgbtRed := AdjustByte(s^.rgbtRed*c);
d^.rgbtGreen := AdjustByte(s^.rgbtGreen*c);
d^.rgbtBlue := AdjustByte(s^.rgbtBlue*c);
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Tile(bmp: TBitmap; area:integer = 16; entropy: integer = 2):Boolean;


var
tmp: TBitmap;
w, h, x, y, ix, iy, xx, yy,nd, nw, nh, ne: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if area < 10 then exit;

w := bmp.Width;
h := bmp.Height;

tmp := BmpClone(bmp);

Invert(bmp);

nd := area-1;
ne := entropy*2+1;
nw := w div area; if (w mod area)<>0 then inc(nw);
nh := h div area; if (h mod area)<>0 then inc(nh);
Randomize;

for y := 0 to nh-1 do
begin
for x := 0 to nw-1 do
begin
ix := x*area;
iy := y*area;
xx := ix+Random(ne)-entropy;
yy := iy+Random(ne)-entropy;
bmp.Canvas.CopyRect(Rect(xx, yy, xx+nd, yy+nd), tmp.Canvas,
Rect(ix, iy, ix+nd, iy+nd));

end;
end;

tmp.Free;
result := true;
end;

function Ripple(bmp: TBitmap;


factor: single = 3.0;
frequency: single = 40):Boolean;
var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, a, c, f, cx, cy, rr, sx, sy: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
f := frequency;
cx := w/2;
cy := h/2;
rct := Rect(0,0,w-2,h-2);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2(y-cy,x-cx);
rr := r+c*sin(f*r*pi/180);
sx := rr*Cos(a) + cx;
sy := rr*Sin(a) + cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Pixellate2(bmp: TBitmap; zone: integer = 6):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
r, a, rr, aa, cx, cy: single;
xx, yy: integer;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rct := Rect(0,0,w-1,h-1);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
rr := (Trunc(r) div zone)*zone;
a := ArcTan2((y-cy),(x-cx))*180/pi; // degree
aa := (Trunc(a) div zone)*zone*pi/180; // radian
xx := Round(rr*cos(aa)+cx);
yy := Round(rr*sin(aa)+cy);
if PtInRect(rct,Point(xx,yy)) then
dst[x,y]^ := src[xx,yy]^;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Ripple2(bmp: TBitmap;


factor: single = 0.2;
frequency: single = 40):Boolean;
var
dst: TBmpData24;
w, h, x, y: integer;
r, c, f, cx, cy, bb: single;
d: PRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
f := frequency;
cx := w/2;
cy := h/2;

dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
r := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
bb := 1+c*sin(f*r*pi/180);
d := dst[x,y];
d^.rgbtRed := AdjustByte(d^.rgbtRed*bb);
d^.rgbtGreen := AdjustByte(d^.rgbtGreen*bb);
d^.rgbtBlue := AdjustByte(d^.rgbtBlue*bb);
end;
end;

dst.Free;

result := true;
end;

function WaveGlass(bmp: TBitmap;


WaveType: TWaveType = wtVertical;
factor: single = 3;
frequency: single = 30):Boolean;
var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
c, f, sx, sy: single;
x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

c := factor;
f := frequency;
rct := Rect(0,0,w-2,h-2);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
begin
for x := 0 to w-1 do
begin
sx := x;
sy := y;
case WaveType of
wtVertical : sx := x + c*sin(f*x*pi/180);
wtHorizontal: sy := y + c*sin(f*y*pi/180);
wtBoth : begin
sx := x + c*sin(f*x*pi/180);
sy := y + c*sin(f*y*pi/180);
end;
end;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function ColorSpotLight(bmp: TBitmap; radius: integer):Boolean;


var
dst: TBmpData24;
w, h, x, y: integer;
r, c, cx, cy, rr: single;
d: TRGBTriple;
bd: PRGBTriple;
SatComp, SatCompR, SatCompG, SatCompB: extended;
b: byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rr := radius*radius;

dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := (x-cx)*(x-cx)+(y-cy)*(y-cy);
c :=1.1*(1-r/rr);
if c>0 then
begin
SatComp := 1.0 - c;
SatCompR := 0.3086 * SatComp;
SatCompG := 0.6094 * SatComp;
SatCompB := 0.0820 * SatComp;

d := dst[x,y]^;
bd := dst[x,y];
bd^.rgbtRed := AdjustByte(d.rgbtRed*(SatCompR+c)+
d.rgbtGreen*SatCompG+
d.rgbtBlue*SatCompB);

bd^.rgbtGreen := AdjustByte(d.rgbtRed*SatCompR+
d.rgbtGreen*(SatCompG+c)+
d.rgbtBlue*SatCompB);

bd^.rgbtBlue := AdjustByte(d.rgbtRed*SatCompR+
d.rgbtGreen*SatCompG+
d.rgbtBlue*(SatCompB+c));
end
else
begin
d := dst[x,y]^;
bd := dst[x,y];

b := Trunc(0.3086*d.rgbtRed + 0.6094*d.rgbtGreen + 0.0820*d.rgbtBlue);


bd^.rgbtRed := b;
bd^.rgbtGreen := b;
bd^.rgbtBlue := b;
end;
end;

dst.Free;

result := true;
end;

function Vaseline(bmp: TBitmap; radius: integer):Boolean;


var
tmp: TBitmap;
dst, src: TBmpData24;
w, h, x, y: integer;
r, cx, cy, rr: single;
d, s: PRGBTriple;
z, ix, iy, sr, sg, sb, count: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rr := radius*radius;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
z :=Round(0.3*r*r*r/rr);
if (z>1) then
begin
if z>10 then z := 10;
count := 0;
sr := 0; sg := 0; sb := 0;
for iy := y-z to y+z do
begin
if (iy<0) or (iy>h-1) then continue;
for ix := x-z to x+z do
begin
if (ix<0) or (ix>w-1) then continue;
s := src[ix,iy];
sr := sr + s^.rgbtRed;
sg := sg + s^.rgbtGreen;
sb := sb + s^.rgbtBlue;
inc(count);
end;
end;
d := dst[x,y];
d^.rgbtRed := sr div count;
d^.rgbtGreen := sg div count;
d^.rgbtBlue := sb div count;
end;
end;

dst.Free;
src.Free;

result := true;
end;

function Explosion(bmp: TBitmap; factor: integer):Boolean;


var
tmp: TBitmap;
dst, src: TBmpData24;
w, h, x, y, xx, yy, rf: integer;
r, a, b, cx, cy: single;
d, s: PRGBTriple;
deg: single;
ss, sss: single;
sft: array[-1..361] of integer;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rct := Rect(0,0,w,h);

rf := factor;

Randomize;
for x := -1 to 361 do sft[x] := Random(rf);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2((y-cy),(x-cx));
deg := (a+pi)*180/pi;
sss := Trunc(deg)-deg;
ss := (1-sss)*sft[Trunc(deg)]+sss*sft[Trunc(deg)+1];
if r<ss then continue;
r := r-ss;
xx := Round(r*cos(a)+cx);
yy := Round(r*sin(a)+cy);
if PtInRect(rct, Point(xx,yy)) then
begin
b := 1+(ss-rf/2)/(rf*4);
d := dst[x,y];
s := src[xx,yy];
d^.rgbtRed := AdjustByte(s^.rgbtRed*b);
d^.rgbtGreen := AdjustByte(s^.rgbtGreen*b);
d^.rgbtBlue := AdjustByte(s^.rgbtBlue*b);
end;
end;

dst.Free;
src.Free;

result := true;
end;

function FrostedGlass(bmp: TBitmap; alpha: single; fBlur: integer; rct: TRect):


Boolean;
var
tmp: TBitmap;
w, h: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := w;
tmp.Height := h;
tmp.Canvas.Brush.Color := RGB($ee,$ee,$ee);
tmp.Canvas.FillRect(Rect(0,0,w,h));

JAlphaBlend(tmp.Canvas, 0, 0, bmp, alpha);


GaussianBlur(tmp, fBlur);

bmp.Canvas.CopyRect(rct,tmp.Canvas,rct);

tmp.Free;
result := true;
end;

procedure ShadowFrame(var bmp: TBitmap;


Margin: integer = 10;
ShadowWidth: integer = 7;
BackColor: TColor = clWhite);
var
tmp: TBitmap;
w, h, ww, hh: integer;

p: integer;
begin
w := bmp.Width;
h := bmp.Height;
ww := w + ShadowWidth+2+Margin*2;
hh := h + ShadowWidth+2+Margin*2;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := ww;
tmp.Height := hh;
tmp.Canvas.Brush.Color := backcolor;
tmp.Canvas.FillRect(Rect(0,0,ww,hh));

p := ShadowWidth+Margin;
if ShadowWidth > 5 then
tmp.Canvas.Brush.Color := $606060
else
tmp.Canvas.Brush.Color := $404040;
tmp.Canvas.FillRect(Rect(p, p, p+w, p+h));

GaussianBlur(tmp, 3);

tmp.Canvas.Draw(Margin, Margin, bmp);

bmp.Free;
bmp := tmp;
end;

function MakeMask1(var bmp:TBitmap; threshold: byte = 100): Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
w, h, x, y: integer;
s: PRGBTriple;
b: byte;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := w;
tmp.Height := h;

src := TBmpData24.Create(bmp);
dst := TBmpData24.Create(tmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
s := src[x,y];
b := Trunc(0.299*s^.rgbtRed + 0.587*s^.rgbtGreen + 0.114*s^.rgbtBlue);
if b< threshold then dst[x,y]^ := s^;
end;

dst.Free;
src.Free;
bmp.Free;
bmp := tmp;
result := true;
end;

procedure MaskedOverlay(dst, src, mask: TBitmap; dstX, dstY: integer);


var
w, h, dw, dh, sw, sh, x, y:integer;
d, s: TBmpData24;
m: TBmpData8;
a: byte;
pd, ps: PRGBTriple;
begin
dw := dst.Width;
dh := dst.Height;
sw := src.Width;
sh := src.Height;

w := Min(dw-dstX, sw);
h := Min(dh-dstY, sh);

if (w<1) or (h<1) then exit;

if (mask.Width<sw) or (mask.Height<sh) then exit;

d := TBmpData24.Create(dst);
s := TBmpData24.Create(src);
m := TBmpData8.Create(mask);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
a := m[x,y]^;
if a = 0 then continue;
if (x+dstX<0) or (y+dstY<0) then continue;
pd := d[x+dstX,y+dstY];
ps := s[x,y];
pd^.rgbtRed := AdjustByte(((255-a)*pd^.rgbtRed + a*ps^.rgbtRed)/255);
pd^.rgbtGreen := AdjustByte(((255-a)*pd^.rgbtGreen + a*ps^.rgbtGreen)/255);
pd^.rgbtBlue := AdjustByte(((255-a)*pd^.rgbtBlue + a*ps^.rgbtBlue)/255);
end;

m.Free;
s.Free;
d.Free;
end;

function SpotMask(w, h: integer; Radius: integer): TBitmap;


var
bd: TBmpData8;
x, y: integer;
r, cx, cy, rr: single;
c: integer;
begin
result := TBitmap.Create;
result.PixelFormat := pf8bit;
result.Width := w;
result.Height := h;
SetGrayPalette(result);

cx := w/2;
cy := h/2;
rr := Radius*Radius;

bd := TBmpData8.Create(result);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := (x-cx)*(x-cx)+(y-cy)*(y-cy);
c :=Round(255*(1-r/rr));
if c<0 then
bd[x,y]^ := 0
else
bd[x,y]^ := c;
end;

bd.Free;
end;

function SineMask(w, h: integer; mode: TSineMask): TBitmap;


var
bd: TBmpData8;
x, y: integer;
begin
result := TBitmap.Create;
result.PixelFormat := pf8bit;
result.Width := w;
result.Height := h;

SetGrayPalette(result);

bd := TBmpData8.Create(result);

for y := 0 to h-1 do
for x := 0 to w-1 do
case mode of
smVert: bd[x,y]^ := Round(255*sin(x*pi/(w-1)));
smHorz: bd[x,y]^ := Round(255*sin(y*pi/(h-1)));
smBoth:bd[x,y]^ := Round(255*sin(x*pi/(w-1))*sin(y*pi/(h-1)));
end;

bd.Free;
end;

function AsCodecBmpCheckFileHeader18(const a: Pointer): Boolean;


{$IFDEF DELPHI_5}
type
PCardinal = ^Cardinal;
{$ENDIF}
var
m: Pointer;
begin
result := False;
if (PBitmapFileHeader(a)^.bfType <> 19778) then exit;
m := Pointer(Cardinal(a)+SizeOf(TBitmapFileHeader));
if (PCardinal(m)^ = SizeOf(TBitmapInfoHeader)) or
(PCardinal(m)^ = SizeOf(TBitmapCoreHeader)) then
result := true;
end;

function AsCodecJpgCheckFileHeader2(const a: Pointer): Boolean;


begin
result := ((PByte(a)^ = 255) and (PByte(Cardinal(a)+1)^ = 216));
end;

function AsCodecGifCheckFileHeader6(const a: Pointer): Boolean;


const
gifver: array[0..5] of Char = 'GIF87A';
var
m: PByte;
n: Integer;
begin
result := False;
m := a;
for n := 0 to 5 do
begin
if m^ <> Integer(gifver[n]) then
begin
if n = 3 then
exit
else
if n = 4 then
begin
if m^ <> Ord('9') then exit;
end
else
begin
if m^ <> Integer(gifver[n])+32 then exit;
end;
end;
Inc(m);
end;
result := true;
end;

function LoadCheckedImage(filename: string): TBitmap;


var
ms: TMemoryStream;
a: Pointer;
gif: TGifImage;
jpg: TJpegImage;
png: TPngImage;
begin
result := nil;
ms := TMemoryStream.Create;
try
try
ms.LoadFromFile(filename);
a := ms.Memory;
result := TBitmap.Create;
if AsCodecBmpCheckFileHeader18(a) then
begin
result.LoadFromStream(ms);
end
else
if AsCodecGifCheckFileHeader6(a) then
begin
gif := TGifImage.Create;
try
gif.LoadFromStream(ms);
result.Assign(gif);
finally
gif.Free;
end;
end
else
if AsCodecJpgCheckFileHeader2(a) then
begin
jpg := TJpegImage.Create;
try
jpg.LoadFromStream(ms);
result.Assign(jpg);
finally
jpg.Free;
end;
end
else
begin
png := TPngImage.Create;
try
try
png.LoadFromStream(ms);
result.Assign(png);
except
FreeAndNil(result)
end;
finally
png.Free;
end;
end;
except
FreeAndNil(result);
end;
finally
ms.Free;
end;
end;

function GetThumbnailImage(filename: string;


width, height: integer;
bkColor: TColor = clWhite;
frame: Boolean = true): TBitmap;
var
img: TBitmap;
w, h, s1, s2: extended;
rct: TRect;
begin
result := TBitmap.Create;
result.PixelFormat := pf24bit;
result.Width := width;
result.Height := height;
rct := Rect(0,0,width, height);
result.Canvas.Brush.Color := bkColor;
result.Canvas.FillRect(rct);
img := LoadCheckedImage(filename);
if Assigned(img) then
begin
img.PixelFormat := pf24bit;
s1 := width/height;
w := img.Width;
h := img.Height;
s2 := w/h;
if s1 > s2 then
begin
w := height*s2;
h := height;
end
else
begin
w := width;
h := width/s2;
end;
BmpResize(img, Trunc(w),Trunc(h), rmLagrange);
result.Canvas.Draw(Round((width-w)/2),Round((height-h)/2), img);
img.Free;
end
else
DrawText(result.Canvas.Handle,'No Image', 8, rct,
DT_CENTER or DT_SINGLELINE or DT_VCENTER);

if frame then begin


result.Canvas.Brush.Style := bsClear;
result.Canvas.Rectangle(rct);
end;
end;

function Grid(bmp: TBitmap; area:integer):Boolean;


var
bd: TBmpData24;
w, h, x, y, r, g, b, count: integer;
ix, iy, nd, nw, nh: integer;
d, e: TRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if area < 2 then exit;
w := bmp.Width;
h := bmp.Height;

bd := TBmpData24.Create(bmp);

nd := area-1;
nw := w div area; if (w mod area)<>0 then inc(nw);
nh := h div area; if (h mod area)<>0 then inc(nh);

for y := 0 to nh-1 do
begin
for x := 0 to nw-1 do
begin

b := 0; g := 0; r := 0; count := 0;
for iy := y*area to y*area+nd do
begin
if iy>h-1 then continue;
for ix := x*area to x*area+nd do
begin
if ix>w-1 then continue;
d := bd[ix, iy]^;
b := b + d.rgbtBlue;
g := g + d.rgbtGreen;
r := r + d.rgbtRed;
inc(count);
end;
end;

b := b div count;
g := g div count;
r := r div count;

d.rgbtBlue := b;
d.rgbtGreen := g;
d.rgbtRed := r;

e.rgbtBlue := AdjustByte(d.rgbtBlue*1.2);
e.rgbtGreen := AdjustByte(d.rgbtGreen*1.2);
e.rgbtRed := AdjustByte(d.rgbtRed*1.2);

for iy := y*area to y*area+nd-1 do


begin
if iy>h-1 then continue;
for ix := x*area to x*area+nd-1 do
begin
if ix>w-1 then continue;
bd[ix,iy]^ := d;
end;
end;

iy := y*area+nd;
if iy<=h-1 then
begin
for ix := x*area to x*area+nd do
begin
if ix>w-1 then continue;
bd[ix,iy]^ := e;
end;
end;

ix := x*area+nd;
if ix<=w-1 then
begin
for iy := y*area to y*area+nd-1 do
begin
if iy>h-1 then continue;
bd[ix,iy]^ := e;
end;
end;

end;
end;

bd.Free;
result := true;
end;

function Soften(bmp: TBitmap; percent:integer): Boolean;


var
tmp: TBitmap;
dst, src: TBmpData24;
w, h, x, y: integer;
d, s: PRGBTriple;
r: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if (percent<0) or (percent>100) then exit;

w := bmp.Width;
h := bmp.Height;

r := percent/100;

tmp := BmpClone(bmp);
GaussianBlur(tmp, 1);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
d := dst[x,y];
s := src[x,y];
d^.rgbtRed := AdjustByte((1-r)*d^.rgbtRed + r*s^.rgbtRed);
d^.rgbtGreen := AdjustByte((1-r)*d^.rgbtGreen + r*s^.rgbtGreen);
d^.rgbtBlue := AdjustByte((1-r)*d^.rgbtBlue + r*s^.rgbtBlue);
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Contour1(var bmp: TBitmap; threshold: integer): Boolean;


var
tmp: TBitmap;
src: TBmpData24;
dst: TBmpData1;
w, h, x, y: integer;
s, t: PRGBTriple;
r1, r2, r3, rr, gg, bb: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

tmp := TBitmap.Create;
tmp.PixelFormat := pf1bit;
tmp.Width := w;
tmp.Height := h;

r3 := sqrt(3.0);

src := TBmpData24.Create(bmp);
dst := TBmpData1.Create(tmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
s := src[x,y];

if x+1>w-1 then
r1 := 0
else
begin
t := src[x+1,y];
bb := s^.rgbtBlue - t^.rgbtBlue;
gg := s^.rgbtGreen - t^.rgbtGreen;
rr := s^.rgbtRed - t^.rgbtRed;
r1 := trunc(sqrt(rr*rr+gg*gg+bb*bb)/r3);
end;

if y+1>h-1 then
r2 := 0
else
begin
t := src[x,y+1];
bb := s^.rgbtBlue - t^.rgbtBlue;
gg := s^.rgbtGreen - t^.rgbtGreen;
rr := s^.rgbtRed - t^.rgbtRed;
r2 := trunc(sqrt(rr*rr+gg*gg+bb*bb)/r3);
end;

if (r1>=threshold) or (r2>=threshold) then


dst[x,y] := false;
end;

dst.Free;
src.Free;

bmp.Free;
bmp := tmp;
result := true;
end;

function Contour2(var bmp: TBitmap; Stretch: Boolean = true): Boolean;


var
tmp: TBitmap;
src: TBmpData24;
dst: TBmpData8;
w, h, x, y: integer;
s, t: PRGBTriple;
r1, r2, r3, rr, gg, bb: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := TBitmap.Create;
tmp.PixelFormat := pf8bit;
tmp.Width := w;
tmp.Height := h;
SetGrayPalette(tmp);

r3 := sqrt(3.0);

src := TBmpData24.Create(bmp);
dst := TBmpData8.Create(tmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
s := src[x,y];

if x+1>w-1 then
r1 := 0
else
begin
t := src[x+1,y];
bb := s^.rgbtBlue - t^.rgbtBlue;
gg := s^.rgbtGreen - t^.rgbtGreen;
rr := s^.rgbtRed - t^.rgbtRed;
r1 := trunc(sqrt(rr*rr+gg*gg+bb*bb)/r3);
end;

if y+1>h-1 then
r2 := 0
else
begin
t := src[x,y+1];
bb := s^.rgbtBlue - t^.rgbtBlue;
gg := s^.rgbtGreen - t^.rgbtGreen;
rr := s^.rgbtRed - t^.rgbtRed;
r2 := trunc(sqrt(rr*rr+gg*gg+bb*bb)/r3);
end;

dst[x,y]^ := AdjustByte(255-r1-r2);
end;

dst.Free;
src.Free;

if Stretch then HistoStretch(tmp);

bmp.Free;
bmp := tmp;
result := true;
end;

function Parallelogram1(var bmp: TBitmap; deform: single; bkColor: TColor):


Boolean;
var
tmp: TBitmap;
src, dst: TBmpData24;
srcRect: TRect;
w, h, ww, hh, i, ix, iy: integer;

sx, sy: single;


x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := w+2;
tmp.Height := h+2;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,w+2,h+2));
tmp.Canvas.Draw(1, 1, bmp);
bmp.Free;
bmp := tmp;

ww := Round(w+Abs(deform));;
hh := h;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := ww;
tmp.Height := hh;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,ww,hh));

src := TBmpData24.Create(bmp);
dst := TBmpData24.Create(tmp);

srcRect := Rect(0,0,w,h);

for iy := 0 to hh-1 do
for ix := 0 to ww-1 do
begin
if deform > 0 then
sx := ix+deform*iy/h-deform
else
sx := ix+deform*iy/h;
sy := iy;

if PtInRect(srcRect, Point(Ceil(sx),Ceil(sy))) or
PtInRect(srcRect, Point(Floor(sx),Floor(sy)))
then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;
r1 := src[x0+1, y0+1]^.rgbtRed*coefx00 + src[x1+1,y0+1]^.rgbtRed*coefx01;
r2 := src[x0+1, y1+1]^.rgbtRed*coefx00 + src[x1+1,y1+1]^.rgbtRed*coefx01;
dst[ix,iy]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0+1, y0+1]^.rgbtGreen*coefx00 +
src[x1+1,y0+1]^.rgbtGreen*coefx01;
g2 := src[x0+1, y1+1]^.rgbtGreen*coefx00 +
src[x1+1,y1+1]^.rgbtGreen*coefx01;
dst[ix,iy]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0+1, y0+1]^.rgbtBlue*coefx00 + src[x1+1,y0+1]^.rgbtBlue*coefx01;


b2 := src[x0+1, y1+1]^.rgbtBlue*coefx00 + src[x1+1,y1+1]^.rgbtBlue*coefx01;
dst[ix,iy]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;

bmp.Free;
bmp := tmp;

result := true;
end;

function Parallelogram2(var bmp: TBitmap; deform: single; bkColor: TColor):


Boolean;
var
tmp: TBitmap;
src, dst: TBmpData24;
srcRect: TRect;
w, h, ww, hh, i, ix, iy: integer;
angle: single;

sx, sy: single;


x0, x1, y0, y1: integer;
r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;
if deform > h*0.8 then exit;

angle := ArcTan2(deform, h);

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := w+2;
tmp.Height := h+2;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,w+2,h+2));
tmp.Canvas.Draw(1, 1, bmp);
bmp.Free;
bmp := tmp;

ww := Round(w+Abs(deform));;
hh := h;

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := ww;
tmp.Height := hh;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,ww,hh));

src := TBmpData24.Create(bmp);
dst := TBmpData24.Create(tmp);

srcRect := Rect(0,0,w,h);

for iy := 0 to hh-1 do
for ix := 0 to ww-1 do
begin
if deform > 0 then
sx := ix+deform*iy/h-deform
else
sx := ix+deform*iy/h;
sy := iy;

if PtInRect(srcRect, Point(Ceil(sx),Ceil(sy))) or
PtInRect(srcRect, Point(Floor(sx),Floor(sy)))
then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0+1, y0+1]^.rgbtRed*coefx00 + src[x1+1,y0+1]^.rgbtRed*coefx01;


r2 := src[x0+1, y1+1]^.rgbtRed*coefx00 + src[x1+1,y1+1]^.rgbtRed*coefx01;
dst[ix,iy]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0+1, y0+1]^.rgbtGreen*coefx00 +
src[x1+1,y0+1]^.rgbtGreen*coefx01;
g2 := src[x0+1, y1+1]^.rgbtGreen*coefx00 +
src[x1+1,y1+1]^.rgbtGreen*coefx01;
dst[ix,iy]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0+1, y0+1]^.rgbtBlue*coefx00 + src[x1+1,y0+1]^.rgbtBlue*coefx01;


b2 := src[x0+1, y1+1]^.rgbtBlue*coefx00 + src[x1+1,y1+1]^.rgbtBlue*coefx01;
dst[ix,iy]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;

bmp.Free;
bmp := tmp;

result := BmpResize(bmp, ww, Trunc(hh*cos(angle)));


end;
function AlphaTile(var bmp:TBitmap; partition: integer = 10): Boolean;
var
tmp1, tmp2, dst: TBitmap;
w, h, ww, hh, x, y: integer;
src, tgt: TBmpData24;
mask: TBmpData8;
r: byte;
d, s: PRGBTriple;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

ww := Ceil(w/partition);
hh := Ceil(h/partition);

tmp1 := BmpClone(bmp);
BmpResize(tmp1, ww, hh, rmBicubic);
Invert(tmp1);
GrayScale(tmp1);
//HistoStretch(tmp1);

tmp2 := TBitmap.Create;
tmp2.PixelFormat := pf8bit;
tmp2.Width := w;
tmp2.Height := h;
SetGrayPalette(tmp2);

for x := 0 to partition-1 do
for y := 0 to partition-1 do
tmp2.Canvas.Draw(ww*x, hh*y, tmp1);
tmp1.Free;

dst := TBitmap.Create;
dst.PixelFormat := pf24bit;
dst.Width := w;
dst.Height := h;

src := TBmpData24.Create(bmp);
tgt := TBmpData24.Create(dst);
mask := TBmpData8.Create(tmp2);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
r := mask[x,y]^;
s := src[x,y];
d := tgt[x,y];

d^.rgbtRed := AdjustByte((255-r)*0.85+s^.rgbtRed*r/255);
d^.rgbtGreen := AdjustByte((255-r)*0.85+s^.rgbtGreen*r/255);
d^.rgbtBlue := AdjustByte((255-r)*0.85+s^.rgbtBlue*r/255);
end;

mask.Free;
tgt.Free;
src.Free;

tmp2.Free;

bmp.Free;
bmp := dst;
result := true;
end;

function Divide(var bmp:TBitmap;


bkImage: TBitmap;
hdiv, vdiv: integer;
margin: integer = 20;
framewidth: integer = 5): Boolean;
var
dst, tmp: TBitmap;
w, h, ww, hh, www, hhh, x, y: integer;
dstRct, srcRct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

ww := w div hdiv;
hh := h div vdiv;
www := ww + framewidth*2;
hhh := hh + framewidth*2;

dstRct := Rect(framewidth, framewidth, framewidth+ww, framewidth+hh);

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := www;
tmp.Height := hhh;
tmp.Canvas.Rectangle(0,0,www, hhh);

dst := TBitmap.Create;
dst.PixelFormat := pf24bit;
dst.Width := www*hdiv + margin*2;
dst.Height := hhh*vdiv + margin*2;

for x := 0 to dst.Width div bkImage.Width do


for y := 0 to dst.Height div bkImage.Height do
dst.Canvas.Draw(bkImage.Width*x, bkImage.Height*y, bkImage);

Randomize;

for x := 0 to hdiv-1 do
for y := 0 to vdiv-1 do
begin
srcRct := Rect(ww*x, hh*y, ww*(x+1), hh*(y+1));
tmp.Canvas.CopyRect(dstRct, bmp.Canvas, srcRct);
dst.Canvas.Draw(margin+www*x+Random(5)-2, margin+hhh*y+Random(5)-2, tmp);
end;

tmp.Free;
bmp.Free;
bmp := dst;
result := true;
end;

function RadialBlur(bmp: TBitmap; zone: integer = 3):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
s, d: PRGBTriple;
w, h, x, y: integer;
a, cx, cy: single;
rr, i, xx, yy, count, r, g, b: integer;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rct := Rect(0,0,w-1,h-1);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
rr := Round(Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy)));
a := ArcTan2((y-cy),(x-cx)); // radian
count := 0; r := 0; g := 0; b := 0;
for i := rr-zone to rr+zone do
begin
if i<0 then continue;
xx := Round(i*cos(a)+cx);
yy := Round(i*sin(a)+cy);
if PtInRect(rct,Point(xx,yy)) then
begin
s := src[xx,yy];
r := r + s^.rgbtRed;
g := g + s^.rgbtGreen;
b := b + s^.rgbtBlue;
inc(count);
end;
end;
if count = 0 then continue;
d := dst[x,y];
d^.rgbtRed := r div count;
d^.rgbtGreen := g div count;
d^.rgbtBlue := b div count;
end;

dst.Free;
src.Free;
tmp.Free;
result := true;
end;

function AngleBlur(bmp: TBitmap; zone: integer = 3):Boolean;


var
tmp: TBitmap;
src, dst: TBmpData24;
s, d: PRGBTriple;
w, h, x, y: integer;
rr, cx, cy: single;
a, i, xx, yy, count, r, g, b: integer;
rct: TRect;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

cx := w/2;
cy := h/2;
rct := Rect(0,0,w-1,h-1);

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
rr := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := Round(ArcTan2((y-cy),(x-cx))*180/pi); // degree
count := 0; r := 0; g := 0; b := 0;
for i := a-zone to a+zone do
begin
xx := Round(rr*cos(i*pi/180)+cx);
yy := Round(rr*sin(i*pi/180)+cy);
if PtInRect(rct,Point(xx,yy)) then
begin
s := src[xx,yy];
r := r + s^.rgbtRed;
g := g + s^.rgbtGreen;
b := b + s^.rgbtBlue;
inc(count);
end;
end;
if count = 0 then continue;
d := dst[x,y];
d^.rgbtRed := r div count;
d^.rgbtGreen := g div count;
d^.rgbtBlue := b div count;
end;

dst.Free;
src.Free;
tmp.Free;
result := true;
end;

function BrightnessModulation(var bmp, modu: TBitmap;


percent: single;
negative: boolean = false):Boolean;
var
src: TBmpData24;
mdu: TBmpData8;
s: PRGBTriple;
m: byte;
r, p: single;
w, h, x, y: integer;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if modu.PixelFormat <> pf24bit then exit;
if (bmp.Width>modu.Width) or (bmp.Height>modu.Height) then exit;

w := bmp.Width;
h := bmp.Height;

p := percent/100;

if negative then Invert(modu);


GrayScale(modu);
HistoStretch(modu);

src := TBmpData24.Create(bmp);
mdu := TBmpData8.Create(modu);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
m := mdu[x,y]^;
r := (1-p) + 2*p*m/255;
s := src[x,y];
s^.rgbtRed := AdjustByte(r*s^.rgbtRed);
s^.rgbtGreen := AdjustByte(r*s^.rgbtGreen);
s^.rgbtBlue := AdjustByte(r*s^.rgbtBlue);
end;

mdu.Free;
src.Free;

result := true;
end;

function PolarShear(bmp: TBitmap;


rentropy: single = 0.5;
aentropy: single = 0.5;
bInterpolation: Boolean = true): Boolean;
var
tmp:TBitmap;
w, h, x, y, p, q: integer;
src, dst: TBmpData24;
rshift: array of single;
ashift: array[0..181] of single;
a, rr, cx, cy, f: single;
sx, sy, r, dr: single;
rct: TRect;

x0, x1, y0, y1: integer;


r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

q := Round(Sqrt(w*w+h*h)/2)+3;
SetLength(rshift, q);

Randomize;

r := 0;
dr := rentropy;
for x := 0 to q-1 do
begin
p := Random(1500);
if p < 500 then r := r-dr
else
if p > 1000 then r := r+dr;
rshift[x] := r;
end;

r := 0;
dr := aentropy;
for x := 0 to 181 do
begin
p := Random(1500);
if p < 500 then r := r-dr
else
if p > 1000 then r := r+dr;
ashift[x] := r;
end;

cx := w/2;
cy := h/2;
rct := Rect(0,0,w-2,h-2);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := clGray;
bmp.Canvas.FillRect(Rect(0,0,w,h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
rr := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2((y-cy),(x-cx))*180/pi; // degree
if bInterpolation then
begin
f := rr - Trunc(rr);
rr := rr + (1-f)*rshift[Trunc(rr)] + f*rshift[Trunc(rr)+1];
f := Abs(a) - Trunc(Abs(a));
a := a + (1-f)*ashift[Trunc(Abs(a))] + f*ashift[Trunc(Abs(a)+1)];
end
else
begin
rr := rr + rshift[Round(rr)];
a := a + ashift[Round(Abs(a))];
end;
sx := rr*cos(a*pi/180)+cx;
sy := rr*sin(a*pi/180)+cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Circle1(var bmp: TBitmap; bkColor: TColor = clGray): Boolean;


var
tmp:TBitmap;
w, h, x, y, q: integer;
src, dst: TBmpData24;
a, rr, cx, cy, c: single;
sx, sy: single;
rct: TRect;

x0, x1, y0, y1: integer;


r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
w := bmp.Width;
h := bmp.Height;

q := max(w,h);
BmpResize(bmp,q,q);

cx := q/2;
cy := q/2;
rct := Rect(0,0,q-2,q-2);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := bkColor;
bmp.Canvas.FillRect(Rect(0,0,q,q));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to q-1 do
for x := 0 to q-1 do
begin
rr := Sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
a := ArcTan2((y-cy),(x-cx))*180/pi; // degree

if Abs(a)<45 then
c := 1/cos(a*pi/180)
else
if Abs(a)<135 then
c := 1/sin(Abs(a)*pi/180)
else
c := -1/cos(a*pi/180);

rr := rr*c;
sx := rr*cos(a*pi/180)+cx;
sy := rr*sin(a*pi/180)+cy;
if PtFInRect(PointF(sx, sy), rct) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

function Circle2(var bmp: TBitmap; bkColor: TColor = clGray): Boolean;


var
tmp:TBitmap;
w, h, x, y, q: integer;
src, dst: TBmpData24;
sx, sy, r, l: single;
rct: TRect;

x0, x1, y0, y1: integer;


r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

w := bmp.Width;
h := bmp.Height;

q := max(w,h);
BmpResize(bmp,q,q);

r := q/2;
rct := Rect(0,0,q-2,q-2);

tmp := BmpClone(bmp);
bmp.Canvas.Brush.Color := bkColor;
bmp.Canvas.FillRect(Rect(0,0,q,q));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 1 to q-1 do
for x := 0 to q-1 do
begin
l := sqrt(2*r*y-y*y);
if l = 0 then sx := 0 else sx := r*(x-r)/l+r;
sy := y;

if PtFInRect(PointF(sx, sy), rct) then


begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0, y0]^.rgbtRed*coefx00 + src[x1,y0]^.rgbtRed*coefx01;


r2 := src[x0, y1]^.rgbtRed*coefx00 + src[x1,y1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0, y0]^.rgbtGreen*coefx00 + src[x1,y0]^.rgbtGreen*coefx01;


g2 := src[x0, y1]^.rgbtGreen*coefx00 + src[x1,y1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0, y0]^.rgbtBlue*coefx00 + src[x1,y0]^.rgbtBlue*coefx01;


b2 := src[x0, y1]^.rgbtBlue*coefx00 + src[x1,y1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;

tmp.Free;
result := BmpResize(bmp, w, h);
end;

function Focus(bmp: TBitmap; percent: single = 20): Boolean;


const
mask: array[-1..1] of array[-1..1] of integer = (( -1, 0, -1),
( 0, 4, 0),
( -1, 0, -1));
var
tmp:TBitmap;
w, h, ix, iy, x, y, xx, yy: integer;
src, dst: TBmpData24;
d: PRGBTriple;
r, g, b: integer;
p: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if (percent<0) or (percent>100) then exit;
w := bmp.Width;
h := bmp.Height;

p := percent/100;

tmp := BmpClone(bmp);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for iy := 0 to h-1 do
for ix := 0 to w-1 do
begin
r := 0; g := 0; b := 0;
for y := iy-1 to iy+1 do
for x := ix-1 to ix+1 do
begin
if mask[x-ix,y-iy] = 0 then continue;
if (y<0) or (y>h-1) then yy := iy else yy := y;
if (x<0) or (x>w-1) then xx := ix else xx := x;

d := src[xx,yy];

r := r + mask[x-ix,y-iy]*d^.rgbtRed;
g := g + mask[x-ix,y-iy]*d^.rgbtGreen;
b := b + mask[x-ix,y-iy]*d^.rgbtBlue;
end;
d := dst[ix,iy];

d^.rgbtRed := AdjustByte(d^.rgbtRed + p*r);


d^.rgbtGreen := AdjustByte(d^.rgbtGreen + p*g);
d^.rgbtBlue := AdjustByte(d^.rgbtBlue + p*b)
end;

dst.Free;
src.Free;

tmp.Free;

result := true;
end;

function LineInvert(bmp: TBitmap; cx, cy, angle: single


; bkColor: TColor = clGray): Boolean;
var
tmp:TBitmap;
w, h, x, y: integer;
src, dst: TBmpData24;
a, b, dd: single;
sx, sy, sn, cs: single;
rct: TRect;

x0, x1, y0, y1: integer;


r1, r2, g1, g2, b1, b2: single;
coefx00, coefx01, coefy00, coefy01: single;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;
if (angle<0) or (angle>360) then exit;

w := bmp.Width;
h := bmp.Height;

if not PtFInRect(PointF(cx, cy), Rect(0,0,w,h)) then exit;

if Abs(cos(angle*pi/180)) < 1.0E-20 then


a := 1.0E20
else
a := sin(angle*pi/180)/cos(angle*pi/180);

b := cy- a*cx;

if (90<=angle) and (angle<270) then


begin
sn := sin((angle-90)*pi/180);
cs := cos((angle-90)*pi/180);
end
else
begin
sn := sin((angle+90)*pi/180);
cs := cos((angle+90)*pi/180);
end;

rct := Rect(0,0,w,h);

tmp := TBitmap.Create;
tmp.PixelFormat := pf24bit;
tmp.Width := w+2;
tmp.Height := h+2;
tmp.Canvas.Brush.Color := bkColor;
tmp.Canvas.FillRect(Rect(0,0,w+2, h+2));
tmp.Canvas.Draw(1,1,bmp);

bmp.Canvas.Brush.Color := bkColor;
bmp.Canvas.FillRect(Rect(0,0,w, h));

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
begin
dd := Abs(y-a*x-b)/sqrt(1+a*a);

if y < a*x+b then


begin
sx := x + 2*dd*cs;
sy := y + 2*dd*sn;
end
else
begin
sx := x - 2*dd*cs;
sy := y - 2*dd*sn;
end;

if PtInRect(rct, Point(Ceil(sx),Ceil(sy))) or
PtInRect(rct, Point(Floor(sx),Floor(sy))) then
begin
x0 := floor(sx);
x1 := x0+1;
y0 := floor(sy);
y1 := y0+1;

coefx01 := sx-x0; coefx00 := 1-coefx01;


coefy01 := sy-y0; coefy00 := 1-coefy01;

r1 := src[x0+1, y0+1]^.rgbtRed*coefx00 + src[x1+1,y0+1]^.rgbtRed*coefx01;


r2 := src[x0+1, y1+1]^.rgbtRed*coefx00 + src[x1+1,y1+1]^.rgbtRed*coefx01;
dst[x,y]^.rgbtRed := AdjustByte(r1*coefy00 + r2*coefy01);

g1 := src[x0+1, y0+1]^.rgbtGreen*coefx00 +
src[x1+1,y0+1]^.rgbtGreen*coefx01;
g2 := src[x0+1, y1+1]^.rgbtGreen*coefx00 +
src[x1+1,y1+1]^.rgbtGreen*coefx01;
dst[x,y]^.rgbtGreen := AdjustByte(g1*coefy00 + g2*coefy01);

b1 := src[x0+1, y0+1]^.rgbtBlue*coefx00 + src[x1+1,y0+1]^.rgbtBlue*coefx01;


b2 := src[x0+1, y1+1]^.rgbtBlue*coefx00 + src[x1+1,y1+1]^.rgbtBlue*coefx01;
dst[x,y]^.rgbtBlue := AdjustByte(b1*coefy00 + b2*coefy01);
end;
end;

dst.Free;
src.Free;
tmp.Free;
result := true;
end;

function Mirror2(var bmp: TBitmap; angle: single; bkColor: TColor): Boolean;


var
tmp: TBitmap;
w, h: integer;
a, b, cx, cy, sn, cs: single;
pt: array[0..3] of TPoint;
rgn: HRGN;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

if (angle<0) or (angle>360) then exit;

w := bmp.Width;
h := bmp.Height;

pt[0] := Point(0,0);
pt[1] := Point(w,0);
pt[2] := Point(w,h);
pt[3] := Point(0,h);

sn := sin(angle*pi/180);
cs := cos(angle*pi/180);

cx := w/2;
cy := h/2;

if sn = 0 then
begin
if angle = 0 then
begin
pt[0] := Point(0, Round(cy));
pt[1] := Point(w, Round(cy));
end
else
begin
pt[2] := Point(w, Round(cy));
pt[3] := Point(0, Round(cy));
end;
end
else
if cs = 0 then
begin
if angle = 90 then
begin
pt[1] := Point(Round(cx), 0);
pt[2] := Point(Round(cx), h);
end
else
begin
pt[0] := Point(Round(cx), 0);
pt[3] := Point(Round(cx), h);
end;
end
else
begin
a := sn/cs;
b := cy-a*cx;
if (b >=0) and (b < h) then
begin
if (angle < 90) or (angle > 270) then
begin
pt[0] := Point(0, Round(b));
pt[1] := Point(w, Round(a*w+b));
end
else
begin
pt[3] := Point(0, Round(b));
pt[2] := Point(w, Round(a*w+b));
end;
end
else
begin
if angle < 180 then
begin
pt[1] := Point(Round(-b/a),0);
pt[2] := Point(Round((h-b)/a), h);
end
else
begin
pt[0] := Point(Round(-b/a),0);
pt[3] := Point(Round((h-b)/a), h);
end;
end;
end;

tmp := BmpClone(bmp);
LineInvert(tmp, cx, cy, angle, bkColor);

rgn := CreatePolygonRgn(pt, 4, WINDING);


SelectClipRgn(bmp.Canvas.Handle, rgn);
bmp.Canvas.Draw(Round(cx-tmp.Width/2), Round(cy-tmp.Height/2), tmp);
SelectClipRgn(bmp.Canvas.Handle, 0);
DeleteObject(rgn);

tmp.Free;
result := true;
end;

function Mirror3(var bmp: TBitmap; cx, cy, angle: single; bkColor: TColor):
Boolean;
var
tmp: TBitmap;
w, h, x, y: integer;
src, dst: TBmpData24;
a, b, sn, cs: single;
fUp: Boolean;
begin
result := false;
if bmp.PixelFormat <> pf24bit then exit;

if (angle<0) or (angle>360) then exit;

w := bmp.Width;
h := bmp.Height;

sn := sin(angle*pi/180);
cs := cos(angle*pi/180);

if Abs(cs) < 1.0E-20 then a := 1.0E20 else a := sn/cs;

b := cy- a*cx;

if (90<=angle) and (angle<270) then fUp := true else fUp := false;

tmp := BmpClone(bmp);
LineInvert(tmp, cx, cy, angle, bkColor);

src := TBmpData24.Create(tmp);
dst := TBmpData24.Create(bmp);

for y := 0 to h-1 do
for x := 0 to w-1 do
if fUp then
begin
if (a*x+b>y) then dst[x,y]^ := src[x,y]^;
end
else
begin
if (a*x+b<y) then dst[x,y]^ := src[x,y]^;
end;

dst.Free;
src.Free;

tmp.Free;
result := true;
end;

end.

You might also like