source: trunk/Packages/bgrabitmap/blurnormal.inc

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 8.7 KB
Line 
1type
2 PWeightedPixel = ^TWeightedPixel;
3 TWeightedPixel = packed record
4 Coord: TPoint;
5 Weight: NativeInt;
6 PtrOfs: NativeInt;
7 end;
8
9var
10 maskWidth,maskHeight: integer;
11 blurOfs: TPoint;
12 ppixel: PWeightedPixel;
13 Pixel: array of TWeightedPixel;
14 PixelArrayLineStart: array of integer;
15 DiffPixel: array of TWeightedPixel;
16 DiffPixelArrayLineStart: array of integer;
17
18 bmpWidth,bmpHeight,lineDelta: NativeInt;
19
20 procedure LoadMask(out ABlurOfs: TPoint);
21 var x,y,n,i: NativeInt;
22 tempWeight: NativeInt;
23 diffMask: array of packed array of NativeInt;
24 p: PBGRAPixel;
25 begin
26 ABlurOfs := point(blurMask.Width shr 1, blurMask.Height shr 1);
27
28 //count number of non empty pixels
29 maskWidth := blurMask.Width;
30 maskHeight := blurMask.Height;
31 n := 0;
32 p := blurMask.Data;
33 for i := blurMask.NbPixels-1 downto 0 do
34 begin
35 if p^.red <> 0 then inc(n);
36 inc(p);
37 end;
38
39 //initialize arrays
40 setlength(diffMask, maskHeight, maskWidth+1);
41 for y := 0 to maskHeight - 1 do
42 fillchar(diffMask[y,0], (maskWidth+1)*sizeof(NativeInt), 0);
43
44 setlength(Pixel, n);
45 setlength(PixelArrayLineStart, maskHeight+1); //stores the first pixel of each line
46 n := 0;
47 //compute mask variations and initial mask pixel list
48 for y := 0 to maskHeight - 1 do
49 begin
50 PixelArrayLineStart[y] := n;
51 p := blurMask.ScanLine[y];
52 for x := 0 to maskWidth - 1 do
53 begin
54 tempWeight := p^.red;
55 inc(p);
56 diffMask[y,x] -= tempWeight;
57 diffMask[y,x+1] += tempWeight;
58
59 if tempWeight <> 0 then
60 begin
61 Pixel[n].Weight := tempWeight;
62 Pixel[n].Coord := Point(x,y);
63 Pixel[n].PtrOfs := (y-ABlurOfs.Y)*lineDelta + (x-ABlurOfs.X)*sizeof(TBGRAPixel);
64 Inc(n);
65 end;
66 end;
67 end;
68 PixelArrayLineStart[maskHeight] := n;
69
70 //count number of diff pixels
71 n := 0;
72 for y := 0 to maskHeight - 1 do
73 for x := 0 to maskWidth do
74 if diffMask[y,x] <> 0 then Inc(n);
75
76 //initialize arrays
77 setlength(DiffPixel, n);
78 setlength(DiffPixelArrayLineStart, maskHeight+1); //stores the first pixel of each diff line
79 n := 0;
80 //compute diff pixel list
81 for y := 0 to maskHeight - 1 do
82 begin
83 DiffPixelArrayLineStart[y] := n;
84 for x := 0 to maskWidth do
85 begin
86 tempWeight := diffMask[y,x];
87 if tempWeight <> 0 then
88 begin
89 DiffPixel[n].Weight := tempWeight;
90 DiffPixel[n].Coord := Point(x-1,y);
91 DiffPixel[n].PtrOfs := (y-ABlurOfs.Y)*lineDelta + (x-ABlurOfs.X-1)*sizeof(TBGRAPixel);
92 Inc(n);
93 end;
94 end;
95 end;
96 DiffPixelArrayLineStart[maskHeight] := n;
97 end;
98
99 function PrepareScan(AWantedBounds: TRect; out AClippedBounds: TRect): boolean;
100 begin
101 //evaluate required bounds taking blur radius into acount
102 AClippedBounds := bmp.GetImageBounds;
103 if IsRectEmpty(AClippedBounds) then
104 begin
105 result := false;
106 exit;
107 end;
108 AClippedBounds.Left := max(0, AClippedBounds.Left - blurOfs.X);
109 AClippedBounds.Top := max(0, AClippedBounds.Top - blurOfs.Y);
110 AClippedBounds.Right := min(bmpWidth, AClippedBounds.Right + maskWidth - 1 - blurOfs.X);
111 AClippedBounds.Bottom := min(bmpHeight, AClippedBounds.Bottom + maskHeight - 1 - blurOfs.Y);
112 if not IntersectRect(AClippedBounds, AClippedBounds, AWantedBounds) then
113 begin
114 result := false;
115 exit;
116 end;
117
118 result := true;
119 end;
120
121var
122 bounds: TRect;
123 yb, xb: NativeInt;
124 mindy, maxdy, n, nStart, nCount, nDiffStart, nDiffCount: NativeInt;
125 bmpX,bmpXBase,bmpYBase: NativeInt;
126 pixMaskAlpha, maskAlpha: NativeInt;
127 tempPixel: TBGRAPixel;
128 pdest : PBGRAPixel;
129 psrc : PByte;
130
131begin
132 bmpWidth := bmp.Width;
133 bmpHeight:= bmp.Height;
134 if bmp.LineOrder = riloTopToBottom then
135 lineDelta := bmpWidth*sizeof(TBGRAPixel) else
136 lineDelta := -bmpWidth*sizeof(TBGRAPixel);
137
138 if (ADestination.Width <> bmpWidth) or (ADestination.Height <> bmpHeight) then
139 raise exception.Create('Dimension mismatch');
140
141 LoadMask(blurOfs);
142 if not PrepareScan(ABounds, bounds) then exit; //nothing to do
143
144 bmpYBase := bounds.Top - blurOfs.Y;
145
146 //loop through destination
147 for yb := bounds.Top to bounds.Bottom - 1 do
148 begin
149 if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break;
150 psrc := PByte(bmp.ScanLine[yb]+bounds.Left);
151 pdest := ADestination.ScanLine[yb] + bounds.Left;
152 //compute vertical range
153 mindy := max(-blurOfs.Y, -yb);
154 maxdy := min(blurMask.Height - 1 - blurOfs.Y, bmpHeight - 1 - yb);
155
156 sumR := 0;
157 sumG := 0;
158 sumB := 0;
159 sumA := 0;
160 Adiv := 0;
161 {$ifdef PARAM_MASKSHIFT}
162 RGBdiv := 0;
163 {$endif}
164
165 bmpXBase := bounds.Left-blurOfs.X;
166 nStart := PixelArrayLineStart[mindy+blurOfs.Y];
167 nCount := PixelArrayLineStart[maxdy+blurOfs.Y+1]-nStart;
168 ppixel:= @Pixel[nStart];
169 //go through pixel list of the current vertical range
170 for n := nCount-1 downto 0 do
171 begin
172 bmpX := bmpXBase+ppixel^.Coord.x;
173 //check horizontal range
174 if (bmpX >= 0) and (bmpX < bmpWidth) then
175 begin
176 tempPixel := PBGRAPixel(psrc + ppixel^.PtrOfs)^;
177 maskAlpha := ppixel^.Weight;
178 pixMaskAlpha := maskAlpha * tempPixel.alpha;
179 sumA += pixMaskAlpha;
180 Adiv += maskAlpha;
181 {$ifdef PARAM_MASKSHIFT}
182 pixMaskAlpha := pixMaskAlpha shr maskShift;
183 RGBdiv += pixMaskAlpha;
184 {$endif}
185 {$hints off}
186 sumR += tempPixel.red * pixMaskAlpha;
187 sumG += tempPixel.green * pixMaskAlpha;
188 sumB += tempPixel.blue * pixMaskAlpha;
189 {$hints on}
190 end;
191 inc(ppixel);
192 end;
193
194 //compute average
195 if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
196 pdest^ := BGRAPixelTransparent
197 else
198 pdest^ := computeAverage;
199
200 nDiffStart := DiffPixelArrayLineStart[mindy+blurOfs.Y];
201 nDiffCount := DiffPixelArrayLineStart[maxdy+blurOfs.Y+1]-nDiffStart;
202
203 if nDiffCount < nCount then
204 begin
205 for xb := bounds.Left+1 to Bounds.Right - 1 do
206 begin
207 Inc(pdest);
208 inc(bmpXBase);
209 inc(psrc,sizeof(TBGRAPixel));
210
211 ppixel:= @DiffPixel[nDiffStart];
212 for n := nDiffCount-1 downto 0 do
213 begin
214 bmpX := bmpXBase+ppixel^.Coord.x;
215 if (bmpX >= 0) and (bmpX < bmpWidth) then
216 begin
217 tempPixel := PBGRAPixel(psrc + ppixel^.PtrOfs)^;
218 maskAlpha := ppixel^.Weight;
219 pixMaskAlpha := maskAlpha * tempPixel.alpha;
220 sumA += pixMaskAlpha;
221 Adiv += maskAlpha;
222 {$ifdef PARAM_MASKSHIFT}
223 pixMaskAlpha := (cardinal(pixMaskAlpha)+$80000000) shr maskShift - ($80000000 shr maskShift);
224 RGBdiv += pixMaskAlpha;
225 {$endif}
226 {$hints off}
227 sumR += tempPixel.red * pixMaskAlpha;
228 sumG += tempPixel.green * pixMaskAlpha;
229 sumB += tempPixel.blue * pixMaskAlpha;
230 {$hints on}
231 end;
232 inc(ppixel);
233 end;
234
235 //compute average
236 if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
237 pdest^ := BGRAPixelTransparent
238 else
239 pdest^ := ComputeAverage;
240 end;
241 end else
242 begin
243 for xb := bounds.Left+1 to Bounds.Right - 1 do
244 begin
245 Inc(pdest);
246 inc(bmpXBase);
247 inc(psrc,sizeof(TBGRAPixel));
248
249 sumR := 0;
250 sumG := 0;
251 sumB := 0;
252 sumA := 0;
253 Adiv := 0;
254 {$ifdef PARAM_MASKSHIFT}
255 RGBdiv := 0;
256 {$endif}
257
258 ppixel:= @Pixel[nStart];
259 for n := nCount-1 downto 0 do
260 begin
261 bmpX := bmpXBase+ppixel^.Coord.x;
262 //check horizontal range
263 if (bmpX >= 0) and (bmpX < bmpWidth) then
264 begin
265 tempPixel := PBGRAPixel(psrc + ppixel^.PtrOfs)^;
266 maskAlpha := ppixel^.Weight;
267 pixMaskAlpha := maskAlpha * tempPixel.alpha;
268 sumA += pixMaskAlpha;
269 Adiv += maskAlpha;
270 {$ifdef PARAM_MASKSHIFT}
271 pixMaskAlpha := pixMaskAlpha shr maskShift;
272 RGBdiv += pixMaskAlpha;
273 {$endif}
274 {$hints off}
275 sumR += tempPixel.red * pixMaskAlpha;
276 sumG += tempPixel.green * pixMaskAlpha;
277 sumB += tempPixel.blue * pixMaskAlpha;
278 {$hints on}
279 end;
280 inc(ppixel);
281 end;
282
283 //compute average
284 if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
285 pdest^ := BGRAPixelTransparent
286 else
287 pdest^ := computeAverage;
288 end;
289 end;
290
291 inc(bmpYBase);
292 end;
293 ADestination.InvalidateBitmap;
294end;
295{$undef PARAM_MASKSHIFT}
296
Note: See TracBrowser for help on using the repository browser.