This repository has been archived on 2024-02-26. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
MyPresenter1.0/bgrabitmap/blurnormal.inc
2015-02-08 16:52:18 -08:00

256 lines
7.2 KiB
PHP

var
maskWidth,maskHeight: integer;
blurOfs: TPoint;
PixelWeight: array of integer;
PixelOfs: array of TPoint;
PixelArrayLineStart: array of integer;
DiffPixelWeight: array of integer;
DiffPixelOfs: array of TPoint;
DiffPixelArrayLineStart: array of integer;
procedure LoadMask;
var x,y,n: integer;
tempWeight: integer;
diffMask: array of array of integer;
begin
blurOfs := point(blurMask.Width shr 1, blurMask.Height shr 1);
//count number of non empty pixels
maskWidth := blurMask.Width;
maskHeight := blurMask.Height;
n := 0;
for y := 0 to maskHeight - 1 do
for x := 0 to maskWidth - 1 do
if blurMask.GetPixel(x, y).red <> 0 then Inc(n);
//initialize arrays
setlength(diffMask, maskHeight, maskWidth+1);
for y := 0 to maskHeight - 1 do
for x := 0 to maskWidth do
diffMask[y,x] := 0;
setlength(PixelWeight, n);
setlength(PixelOfs, n);
setlength(PixelArrayLineStart, maskHeight+1); //stores the first pixel of each line
n := 0;
//compute mask variations and initial mask pixel list
for y := 0 to maskHeight - 1 do
begin
PixelArrayLineStart[y] := n;
for x := 0 to maskWidth - 1 do
begin
tempWeight := blurMask.GetPixel(x, y).red;
diffMask[y,x] -= tempWeight;
diffMask[y,x+1] += tempWeight;
if tempWeight <> 0 then
begin
PixelWeight[n] := tempWeight;
PixelOfs[n] := Point(x,y);
Inc(n);
end;
end;
end;
PixelArrayLineStart[maskHeight] := n;
//count number of diff pixels
n := 0;
for y := 0 to maskHeight - 1 do
for x := 0 to maskWidth do
if diffMask[y,x] <> 0 then Inc(n);
//initialize arrays
setlength(DiffPixelWeight, n);
setlength(DiffPixelOfs, n);
setlength(DiffPixelArrayLineStart, maskHeight+1); //stores the first pixel of each diff line
n := 0;
//compute diff pixel list
for y := 0 to maskHeight - 1 do
begin
DiffPixelArrayLineStart[y] := n;
for x := 0 to maskWidth do
begin
tempWeight := diffMask[y,x];
if tempWeight <> 0 then
begin
DiffPixelWeight[n] := tempWeight;
DiffPixelOfs[n] := Point(x-1,y);
Inc(n);
end;
end;
end;
DiffPixelArrayLineStart[maskHeight] := n;
end;
var
curScans: array of PBGRAPixel;
bounds: TRect;
{procedure ShowCurScans;
var str: string;
i: Integer;
begin
str := '';
for i := 0 to high(curScans) do
begin
if i <> 0 then str += ', ';
if curScans[i]=nil then str += 'nil' else
str += 'bmp['+inttostr(curScans[i]-bmp.Data)+']';
end;
ShowMessage(str);
end;}
function PrepareScan: boolean;
var
bmpY: integer;
y : Integer;
begin
//evaluate required bounds taking blur radius into acount
bounds := bmp.GetImageBounds;
if IsRectEmpty(bounds) then
begin
result := false;
exit;
end;
bounds.Left := max(0, bounds.Left - blurOfs.X);
bounds.Top := max(0, bounds.Top - blurOfs.Y);
bounds.Right := min(bmp.Width, bounds.Right + maskWidth - 1 - blurOfs.X);
bounds.Bottom := min(bmp.Height, bounds.Bottom + maskHeight - 1 - blurOfs.Y);
if not IntersectRect(bounds, bounds, ABounds) then
begin
result := false;
exit;
end;
//init scanlines
setlength(curScans, maskHeight);
for y := 0 to maskHeight-1 do
begin
bmpY := y+bounds.Top-blurOfs.Y;
if (bmpY < 0) or (bmpY >= bmp.Height) then
curScans[y] := nil else
curScans[y] := bmp.ScanLine[bmpY];
end;
//ShowCurScans;
result := true;
end;
procedure ShiftScan(NewY: integer); inline;
var y: integer;
begin
for y := 0 to maskHeight-2 do
curScans[y] := curScans[y+1];
//get next scanline
if newY >= bmp.Height then
curScans[maskHeight-1] := nil
else
curScans[maskHeight-1] := bmp.ScanLine[newY];
//ShowCurScans;
end;
var
yb, xb: integer;
mindy, maxdy, n: integer;
bmpWidth,bmpX: integer;
pixMaskAlpha, maskAlpha: integer;
tempPixel: TBGRAPixel;
pdest : PBGRAPixel;
pt: TPoint;
begin
LoadMask;
if (ADestination.Width <> bmp.Width) or (ADestination.Height <> bmp.Height) then
raise exception.Create('Dimension mismatch');
if not PrepareScan then exit; //nothing to do
bmpWidth := bmp.Width;
//loop through destination
for yb := bounds.Top to bounds.Bottom - 1 do
begin
if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break;
pdest := ADestination.ScanLine[yb] + bounds.Left;
//compute vertical range
mindy := max(-blurOfs.Y, -yb);
maxdy := min(blurMask.Height - 1 - blurOfs.Y, bmp.Height - 1 - yb);
sumR := 0;
sumG := 0;
sumB := 0;
sumA := 0;
Adiv := 0;
{$ifdef PARAM_MASKSHIFT}
RGBdiv := 0;
{$endif}
//go through pixel list of the current vertical range
for n := PixelArrayLineStart[mindy+blurOfs.Y] to PixelArrayLineStart[maxdy+blurOfs.Y+1]-1 do
begin
pt := PixelOfs[n];
bmpX := bounds.Left-blurOfs.X+pt.x;
//check horizontal range
if (bmpX >= 0) and (bmpX < bmpWidth) then
begin
tempPixel := (curScans[pt.y]+bmpX)^;
maskAlpha := PixelWeight[n];
pixMaskAlpha := maskAlpha * tempPixel.alpha;
sumA += pixMaskAlpha;
Adiv += maskAlpha;
{$ifdef PARAM_MASKSHIFT}
pixMaskAlpha := pixMaskAlpha shr maskShift;
RGBdiv += pixMaskAlpha;
{$endif}
{$hints off}
sumR += tempPixel.red * pixMaskAlpha;
sumG += tempPixel.green * pixMaskAlpha;
sumB += tempPixel.blue * pixMaskAlpha;
{$hints on}
end;
end;
for xb := bounds.Left to Bounds.Right - 1 do
begin
if xb > bounds.left then
begin
for n := DiffPixelArrayLineStart[mindy+blurOfs.Y] to DiffPixelArrayLineStart[maxdy+blurOfs.Y+1]-1 do
begin
pt := DiffPixelOfs[n];
bmpX := xb-blurOfs.X+pt.x;
if (bmpX >= 0) and (bmpX < bmpWidth) then
begin
tempPixel := (curScans[pt.y]+bmpX)^;
maskAlpha := DiffPixelWeight[n];
pixMaskAlpha := maskAlpha * tempPixel.alpha;
sumA += pixMaskAlpha;
Adiv += maskAlpha;
{$ifdef PARAM_MASKSHIFT}
pixMaskAlpha := (cardinal(pixMaskAlpha)+$80000000) shr maskShift - ($80000000 shr maskShift);
RGBdiv += pixMaskAlpha;
{$endif}
{$hints off}
sumR += tempPixel.red * pixMaskAlpha;
sumG += tempPixel.green * pixMaskAlpha;
sumB += tempPixel.blue * pixMaskAlpha;
{$hints on}
end;
end;
end;
//compute average
if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
pdest^ := BGRAPixelTransparent
else
pdest^ := computeAverage;
Inc(pdest);
end;
ShiftScan(yb-blurOfs.Y+maskHeight);
end;
ADestination.InvalidateBitmap;
end;
{$undef PARAM_MASKSHIFT}