Changeset 494 for GraphicTest/Packages/bgrabitmap/blurfast.inc
- Timestamp:
- Dec 22, 2016, 8:49:19 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/Packages/bgrabitmap/blurfast.inc
r472 r494 1 1 2 2 var 3 blurRow: array of UInt32or64; 3 blurRowY,blurRowX: packed array of NativeUInt; 4 iRadiusX,iRadiusY: NativeInt; 5 weightFactor: NativeUInt; 4 6 5 7 { Compute weights of pixels in a row } 6 8 procedure ComputeBlurRow; 7 9 var 8 i: Integer; 9 begin 10 SetLength(blurRow, 2*radius+1); 11 for i := 0 to radius do 12 begin 13 blurRow[i] := i+1; 14 blurRow[high(blurRow)-i] := blurRow[i]; 10 i: NativeInt; 11 ofs: single; 12 begin 13 SetLength(blurRowX, 2*iRadiusX+1); 14 if frac(radiusX)=0 then ofs := 1 else ofs := frac(radiusX); 15 for i := 0 to iRadiusX do 16 begin 17 blurRowX[i] := round((i+ofs)*weightFactor); 18 blurRowX[high(blurRowX)-i] := blurRowX[i]; 19 end; 20 SetLength(blurRowY, 2*iRadiusY+1); 21 if frac(radiusY)=0 then ofs := 1 else ofs := frac(radiusY); 22 for i := 0 to iRadiusY do 23 begin 24 blurRowY[i] := round((i+ofs)*weightFactor); 25 blurRowY[high(blurRowY)-i] := blurRowY[i]; 15 26 end; 16 27 end; … … 19 30 var 20 31 srcDelta, 21 verticalWeightShift, horizontalWeightShift: integer; 32 verticalWeightShift, horizontalWeightShift: NativeInt; 33 ys1,ys2: NativeInt; 22 34 23 35 { Compute blur result in a vertical direction } 24 procedure ComputeVerticalRow(psrc: PBGRAPixel; var sums: TRowSum; ys1,ys2: integer); inline; 25 var ys: integer; 26 c: TBGRAPixel; 27 w,aw: cardinal; 28 begin 29 for ys := ys1 to ys2 do 36 procedure ComputeVerticalRow(psrc: PBGRAPixel; var sums: TRowSum; pw: PNativeUInt; count: NativeInt); 37 var w: NativeUInt; 38 c: DWord; 39 begin 40 while count > 0 do 30 41 with sums do 31 42 begin 32 c := psrc^; 33 w := blurRow[ys]; //apply pixel weight 34 aw := c.alpha*w; 35 sumA += aw; 43 dec(count); 44 w := pw^; //apply pixel weight 45 inc(pw); 46 c := PDWord(psrc)^; 47 inc(PByte(psrc),srcDelta); 36 48 aDiv += w; 37 38 aw := aw shr verticalWeightShift; 49 w *= ((c shr TBGRAPixel_AlphaShift) and $ff); 50 sumA += w; 51 w := w shr verticalWeightShift; 52 rgbDiv += w; 39 53 {$hints off} 40 sumR += c.red*aw; 41 sumG += c.green*aw; 42 sumB += c.blue*aw; 43 rgbDiv += aw; 54 sumR += ((c shr TBGRAPixel_RedShift) and $ff)*w; 55 sumG += ((c shr TBGRAPixel_GreenShift) and $ff)*w; 56 sumB += ((c shr TBGRAPixel_BlueShift) and $ff)*w; 44 57 {$hints on} 45 inc(psrc,srcDelta);46 58 end; 47 59 end; 48 60 49 61 var 50 sums: array of TRowSum; 51 sumStartIndex,curIndex: integer; 62 psum, psumEnd: PRowSum; 63 sums: packed array of TRowSum; 64 sumStartIndex: NativeInt; 52 65 total: TRowSum; 53 66 extendedTotal: TExtendedRowSum; 54 yb,xb,xs,ys1,ys2,x: integer; 55 w: cardinal; 56 pdest: PBGRAPixel; 57 bmpWidth,bmpHeight : integer; 67 yb,xb,xs,x,xEnd: NativeInt; 68 w: NativeUInt; 69 pw: PNativeUInt; 70 psrc,pdest: PBGRAPixel; 71 bmpWidth,bmpHeight : NativeInt; 58 72 accumulationFactor: double; 59 73 bounds: TRect; 74 highSum: NativeInt; 75 tempDest: TBGRACustomBitmap; 60 76 61 77 begin 62 if radius = 0 then 78 radiusX := round(radiusX*10)*0.1; 79 radiusY := round(radiusY*10)*0.1; 80 if (radiusX <= 0) and (radiusY <= 0) then 63 81 begin 64 82 ADestination.PutImage(0,0,bmp,dmSet); 65 83 exit; 66 84 end; 85 iRadiusX := ceil(radiusX); 86 iRadiusY := ceil(radiusY); 87 if (frac(radiusX)=0) and (frac(radiusY)=0) then 88 weightFactor:= 1 89 else 90 weightFactor:= 10; 67 91 bmpWidth := bmp.Width; 68 92 bmpHeight := bmp.Height; … … 72 96 bounds := bmp.GetImageBounds; 73 97 if IsRectEmpty(bounds) then exit; 74 bounds.Left := max(0, bounds.Left - radius);75 bounds.Top := max(0, bounds.Top - radius);76 bounds.Right := min(bmp.Width, bounds.Right + radius);77 bounds.Bottom := min(bmp.Height, bounds.Bottom + radius);98 bounds.Left := max(0, bounds.Left - iRadiusX); 99 bounds.Top := max(0, bounds.Top - iRadiusY); 100 bounds.Right := min(bmp.Width, bounds.Right + iRadiusX); 101 bounds.Bottom := min(bmp.Height, bounds.Bottom + iRadiusY); 78 102 if not IntersectRect(bounds,bounds,ABounds) then exit; 79 103 80 accumulationFactor := (radius+2)*(radius+1) div 2 + (radius+1)*radius div 2; 104 if radiusX*radiusY >= 100 then 105 begin 106 tempDest := ADestination.NewBitmap(ADestination.Width,ADestination.Height); 107 FilterBlurBox(bmp,bounds,radiusX/3.2,radiusY/3.2,tempDest); 108 FilterBlurBox(tempDest,bounds,radiusX/2.9,radiusY/2.9,ADestination); 109 FilterBlurBox(ADestination,bounds,radiusX/3.2,radiusY/3.2,tempDest); 110 FilterBlurBox(tempDest,bounds,radiusX/2.3,radiusY/2.3,ADestination, ACheckShouldStop); 111 tempDest.Free; 112 exit; 113 end; 114 115 accumulationFactor := (iRadiusY+2)*(iRadiusY+1) div 2 + (iRadiusY+1)*iRadiusY div 2; 116 accumulationFactor *= sqr(weightFactor); 81 117 verticalWeightShift := 0; 82 while accumulationFactor > (high( UInt32or64) shr 16) + 1 do118 while accumulationFactor > (high(NativeUInt) shr 16) + 1 do 83 119 begin 84 120 inc(verticalWeightShift); … … 86 122 end; 87 123 horizontalWeightShift:= 0; 88 accumulationFactor *= ((radius+2)*(radius+1) div 2 + (radius+1)*radius div 2); 89 while accumulationFactor > (high(UInt32or64) shr 16) + 1 do 124 accumulationFactor *= ((iRadiusX+2)*(iRadiusX+1) div 2 + (iRadiusX+1)*iRadiusX div 2); 125 accumulationFactor *= sqr(weightFactor); 126 while accumulationFactor > (high(NativeUInt) shr 16) + 1 do 90 127 begin 91 128 inc(horizontalWeightShift); … … 94 131 ComputeBlurRow; 95 132 //current vertical sums 96 setlength(sums, 2*radius+1); 133 setlength(sums, 2*iRadiusX+1); 134 highSum := high(Sums); 135 psumEnd := @sums[highSum]; 136 inc(psumEnd); 97 137 if bmp.LineOrder = riloTopToBottom then 98 srcDelta := bmpWidth else 99 srcDelta := -bmpWidth; 138 srcDelta := bmpWidth*sizeof(TBGRAPixel) else 139 srcDelta := -bmpWidth*sizeof(TBGRAPixel); 140 141 xEnd := bounds.left-iRadiusX+highSum; 142 if xEnd >= bmpWidth then xEnd := bmpWidth-1; 100 143 //loop through destination bitmap 101 144 for yb := bounds.top to bounds.bottom-1 do … … 103 146 if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break; 104 147 //evalute available vertical range 105 if yb - radius< 0 then106 ys1 := radius- yb148 if yb - iRadiusY < 0 then 149 ys1 := iRadiusY - yb 107 150 else 108 151 ys1 := 0; 109 if yb + radius>= bmpHeight then110 ys2 := bmpHeight - yb + radius - 1152 if yb + iRadiusY >= bmpHeight then 153 ys2 := bmpHeight-1 - yb + iRadiusY 111 154 else 112 ys2 := high(sums);155 ys2 := 2*iRadiusY; 113 156 114 157 { initial vertical rows are computed here. Later, 115 158 for each pixel, vertical sums are shifted, so there 116 159 is only one vertical sum to calculate } 117 for xs := 0 to high(sums) do 118 begin 119 fillchar(sums[xs],sizeof(TRowSum),0); 120 x := bounds.left-radius+xs; 121 if (x >= 0) and (x < bmpWidth) then 122 ComputeVerticalRow(bmp.ScanLine[yb-radius+ys1]+x,sums[xs],ys1,ys2); 160 fillchar(sums[0],sizeof(TRowSum)*length(sums),0); 161 x := bounds.left-iRadiusX; 162 if x < 0 then 163 begin 164 xs := -x; 165 x := 0; 166 end else 167 xs := 0; 168 psrc := bmp.ScanLine[yb-iRadiusY+ys1]+x; 169 psum := @sums[xs]; 170 pw := @blurRowY[ys1]; 171 while true do 172 begin 173 ComputeVerticalRow(psrc,psum^,pw,ys2-ys1+1); 174 inc(x); 175 inc(psrc); 176 if x > xEnd then break; 177 inc(psum); 123 178 end; 124 179 sumStartIndex := 0; … … 128 183 begin 129 184 //add vertical rows 130 curIndex:= sumStartIndex; 185 pw := @blurRowX[0]; 186 psum := @sums[sumStartIndex]; 131 187 if horizontalWeightShift > 4 then 132 188 begin //we don't want to loose too much precision 133 {$hints off} 134 fillchar(extendedTotal,sizeof(extendedTotal),0); 135 {$hints on} 136 for xs := 0 to high(sums) do 137 with sums[curIndex] do 189 fillchar({%H-}extendedTotal,sizeof(extendedTotal),0); 190 for xs := highSum downto 0 do 191 with psum^ do 138 192 begin 139 w := blurRow[xs]; 193 w := pw^; 194 inc(pw); 140 195 extendedTotal.sumA += TExtendedRowValue(sumA)*w; 141 196 extendedTotal.aDiv += TExtendedRowValue(aDiv)*w; … … 144 199 extendedTotal.sumB += TExtendedRowValue(sumB)*w; 145 200 extendedTotal.rgbDiv += TExtendedRowValue(rgbDiv)*w; 146 inc( curIndex);147 if curIndex = length(sums) then curIndex := 0;201 inc(psum); 202 if psum >= psumEnd then pSum := @sums[0]; 148 203 end; 149 204 if (extendedTotal.aDiv > 0) and (extendedTotal.rgbDiv > 0) then … … 154 209 if horizontalWeightShift > 0 then 155 210 begin //lossy but efficient way 156 {$hints off} 157 fillchar(total,sizeof(total),0); 158 {$hints on} 159 for xs := 0 to high(sums) do 160 with sums[curIndex] do 211 fillchar({%H-}total,sizeof(total),0); 212 for xs := highSum downto 0 do 213 with psum^ do 161 214 begin 162 w := blurRow[xs]; 215 w := pw^; 216 inc(pw); 163 217 total.sumA += sumA*w shr horizontalWeightShift; 164 218 total.aDiv += aDiv*w shr horizontalWeightShift; … … 167 221 total.sumB += sumB*w shr horizontalWeightShift; 168 222 total.rgbDiv += rgbDiv*w shr horizontalWeightShift; 169 inc( curIndex);170 if curIndex = length(sums) then curIndex := 0;223 inc(psum); 224 if psum >= psumEnd then pSum := @sums[0]; 171 225 end; 172 226 if (total.aDiv > 0) and (total.rgbDiv > 0) then … … 179 233 fillchar(total,sizeof(total),0); 180 234 {$hints on} 181 for xs := 0 to high(sums)do182 with sums[curIndex]do235 for xs := highSum downto 0 do 236 with psum^ do 183 237 begin 184 w := blurRow[xs]; 238 w := pw^; 239 inc(pw); 185 240 total.sumA += sumA*w; 186 241 total.aDiv += aDiv*w; … … 189 244 total.sumB += sumB*w; 190 245 total.rgbDiv += rgbDiv*w; 191 inc( curIndex);192 if curIndex = length(sums) then curIndex := 0;246 inc(psum); 247 if psum >= psumEnd then pSum := @sums[0]; 193 248 end; 194 249 if (total.aDiv > 0) and (total.rgbDiv > 0) then 195 pdest^ := ComputeAverage(total)250 pdest^ := ComputeAverage(total) 196 251 else 197 252 pdest^:= BGRAPixelTransparent; … … 199 254 inc(pdest); 200 255 //shift vertical rows 201 fillchar(sums[sumStartIndex],sizeof(TRowSum),0); 202 x := xb+1-radius+high(sums); 203 if (x >= 0) and (x < bmpWidth) then 204 ComputeVerticalRow(bmp.ScanLine[yb-radius+ys1]+x,sums[sumStartIndex],ys1,ys2); 256 psum := @sums[sumStartIndex]; 257 fillchar(psum^,sizeof(TRowSum),0); 258 if x < bmpWidth then 259 begin 260 ComputeVerticalRow(psrc,psum^,@blurRowY[ys1],ys2-ys1+1); 261 inc(x); 262 inc(psrc); 263 end; 205 264 inc(sumStartIndex); 206 if sumStartIndex = length(sums)then sumStartIndex := 0;265 if sumStartIndex > highSum then sumStartIndex := 0; 207 266 end; 208 267 end;
Note:
See TracChangeset
for help on using the changeset viewer.