@@ -53,8 +53,77 @@ var shgTable = []uint32{
5353 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 ,
5454}
5555
56- // Process takes the source image and returns it's blurred version by applying the blur radius defined as parameter.
57- func Process (src image.Image , radius uint32 ) (* image.NRGBA , error ) {
56+ // Run takes the source image and returns it's blurred version by applying the blur radius defined as parameter.
57+ func Run (dst , src image.Image , radius uint32 ) error {
58+ // Limit the maximum blur radius to 255 to avoid overflowing the multable.
59+ if int (radius ) >= len (mulTable ) {
60+ radius = uint32 (len (mulTable ) - 1 )
61+ }
62+
63+ if radius < 1 {
64+ return errors .New ("blur radius must be greater than 0" )
65+ }
66+
67+ if img , ok := dst .(* image.NRGBA ); ok {
68+ process (img , src , radius )
69+ }
70+
71+ return nil
72+ }
73+
74+ func process (dst * image.NRGBA , src image.Image , radius uint32 ) {
75+ srcBounds := src .Bounds ()
76+ srcMinX := srcBounds .Min .X
77+ srcMinY := srcBounds .Min .Y
78+
79+ dstBounds := srcBounds .Sub (srcBounds .Min )
80+ dstW := dstBounds .Dx ()
81+ dstH := dstBounds .Dy ()
82+
83+ switch src0 := src .(type ) {
84+ case * image.NRGBA :
85+ rowSize := srcBounds .Dx () * 4
86+ for dstY := 0 ; dstY < dstH ; dstY ++ {
87+ di := src0 .PixOffset (0 , dstY )
88+ si := src0 .PixOffset (srcMinX , srcMinY + dstY )
89+ for dstX := 0 ; dstX < dstW ; dstX ++ {
90+ copy (dst .Pix [di :di + rowSize ], src0 .Pix [si :si + rowSize ])
91+ }
92+ }
93+ case * image.YCbCr :
94+ for dstY := 0 ; dstY < dstH ; dstY ++ {
95+ di := dst .PixOffset (0 , dstY )
96+ for dstX := 0 ; dstX < dstW ; dstX ++ {
97+ srcX := srcMinX + dstX
98+ srcY := srcMinY + dstY
99+ siy := src0 .YOffset (srcX , srcY )
100+ sic := src0 .COffset (srcX , srcY )
101+ r , g , b := color .YCbCrToRGB (src0 .Y [siy ], src0 .Cb [sic ], src0 .Cr [sic ])
102+ dst .Pix [di + 0 ] = r
103+ dst .Pix [di + 1 ] = g
104+ dst .Pix [di + 2 ] = b
105+ dst .Pix [di + 3 ] = 0xff
106+ di += 4
107+ }
108+ }
109+ default :
110+ for dstY := 0 ; dstY < dstH ; dstY ++ {
111+ di := dst .PixOffset (0 , dstY )
112+ for dstX := 0 ; dstX < dstW ; dstX ++ {
113+ c := color .NRGBAModel .Convert (src .At (srcMinX + dstX , srcMinY + dstY )).(color.NRGBA )
114+ dst .Pix [di + 0 ] = c .R
115+ dst .Pix [di + 1 ] = c .G
116+ dst .Pix [di + 2 ] = c .B
117+ dst .Pix [di + 3 ] = c .A
118+ di += 4
119+ }
120+ }
121+ }
122+
123+ blurImage (dst , radius )
124+ }
125+
126+ func blurImage (src * image.NRGBA , radius uint32 ) {
58127 var (
59128 stackEnd * blurStack
60129 stackIn * blurStack
@@ -70,17 +139,6 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
70139 rInSum , gInSum , bInSum , aInSum ,
71140 pr , pg , pb , pa uint32
72141 )
73- // Limit the maximum blur radius to 255, otherwise it overflows the multable length
74- // and will panic with and index out of range error.
75- if int (radius ) >= len (mulTable ) {
76- radius = uint32 (len (mulTable ) - 1 )
77- }
78-
79- if radius < 1 {
80- return nil , errors .New ("blur radius must be greater than 0" )
81- }
82-
83- img := toNRGBA (src )
84142
85143 div = radius + radius + 1
86144 widthMinus1 = width - 1
@@ -106,10 +164,10 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
106164 for y = 0 ; y < height ; y ++ {
107165 rInSum , gInSum , bInSum , aInSum , rSum , gSum , bSum , aSum = 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
108166
109- pr = uint32 (img .Pix [yi ])
110- pg = uint32 (img .Pix [yi + 1 ])
111- pb = uint32 (img .Pix [yi + 2 ])
112- pa = uint32 (img .Pix [yi + 3 ])
167+ pr = uint32 (src .Pix [yi ])
168+ pg = uint32 (src .Pix [yi + 1 ])
169+ pb = uint32 (src .Pix [yi + 2 ])
170+ pa = uint32 (src .Pix [yi + 3 ])
113171
114172 rOutSum = radiusPlus1 * pr
115173 gOutSum = radiusPlus1 * pg
@@ -139,10 +197,10 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
139197 diff = i
140198 }
141199 p = yi + (diff << 2 )
142- pr = uint32 (img .Pix [p ])
143- pg = uint32 (img .Pix [p + 1 ])
144- pb = uint32 (img .Pix [p + 2 ])
145- pa = uint32 (img .Pix [p + 3 ])
200+ pr = uint32 (src .Pix [p ])
201+ pg = uint32 (src .Pix [p + 1 ])
202+ pb = uint32 (src .Pix [p + 2 ])
203+ pa = uint32 (src .Pix [p + 3 ])
146204
147205 stack .r = pr
148206 stack .g = pg
@@ -166,16 +224,16 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
166224
167225 for x = 0 ; x < width ; x ++ {
168226 pa = (aSum * mulSum ) >> shgSum
169- img .Pix [yi + 3 ] = uint8 (pa )
227+ src .Pix [yi + 3 ] = uint8 (pa )
170228
171229 if pa != 0 {
172- img .Pix [yi ] = uint8 ((rSum * mulSum ) >> shgSum )
173- img .Pix [yi + 1 ] = uint8 ((gSum * mulSum ) >> shgSum )
174- img .Pix [yi + 2 ] = uint8 ((bSum * mulSum ) >> shgSum )
230+ src .Pix [yi ] = uint8 ((rSum * mulSum ) >> shgSum )
231+ src .Pix [yi + 1 ] = uint8 ((gSum * mulSum ) >> shgSum )
232+ src .Pix [yi + 2 ] = uint8 ((bSum * mulSum ) >> shgSum )
175233 } else {
176- img .Pix [yi ] = 0
177- img .Pix [yi + 1 ] = 0
178- img .Pix [yi + 2 ] = 0
234+ src .Pix [yi ] = 0
235+ src .Pix [yi + 1 ] = 0
236+ src .Pix [yi + 2 ] = 0
179237 }
180238
181239 rSum -= rOutSum
@@ -195,10 +253,10 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
195253 }
196254 p = (yw + p ) << 2
197255
198- stackIn .r = uint32 (img .Pix [p ])
199- stackIn .g = uint32 (img .Pix [p + 1 ])
200- stackIn .b = uint32 (img .Pix [p + 2 ])
201- stackIn .a = uint32 (img .Pix [p + 3 ])
256+ stackIn .r = uint32 (src .Pix [p ])
257+ stackIn .g = uint32 (src .Pix [p + 1 ])
258+ stackIn .b = uint32 (src .Pix [p + 2 ])
259+ stackIn .a = uint32 (src .Pix [p + 3 ])
202260
203261 rInSum += stackIn .r
204262 gInSum += stackIn .g
@@ -238,10 +296,10 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
238296 rInSum , gInSum , bInSum , aInSum , rSum , gSum , bSum , aSum = 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
239297
240298 yi = x << 2
241- pr = uint32 (img .Pix [yi ])
242- pg = uint32 (img .Pix [yi + 1 ])
243- pb = uint32 (img .Pix [yi + 2 ])
244- pa = uint32 (img .Pix [yi + 3 ])
299+ pr = uint32 (src .Pix [yi ])
300+ pg = uint32 (src .Pix [yi + 1 ])
301+ pb = uint32 (src .Pix [yi + 2 ])
302+ pa = uint32 (src .Pix [yi + 3 ])
245303
246304 rOutSum = radiusPlus1 * pr
247305 gOutSum = radiusPlus1 * pg
@@ -267,10 +325,10 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
267325
268326 for i = 1 ; i <= radius ; i ++ {
269327 yi = (yp + x ) << 2
270- pr = uint32 (img .Pix [yi ])
271- pg = uint32 (img .Pix [yi + 1 ])
272- pb = uint32 (img .Pix [yi + 2 ])
273- pa = uint32 (img .Pix [yi + 3 ])
328+ pr = uint32 (src .Pix [yi ])
329+ pg = uint32 (src .Pix [yi + 1 ])
330+ pb = uint32 (src .Pix [yi + 2 ])
331+ pa = uint32 (src .Pix [yi + 3 ])
274332
275333 stack .r = pr
276334 stack .g = pg
@@ -301,16 +359,16 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
301359 for y = 0 ; y < height ; y ++ {
302360 p = yi << 2
303361 pa = (aSum * mulSum ) >> shgSum
304- img .Pix [p + 3 ] = uint8 (pa )
362+ src .Pix [p + 3 ] = uint8 (pa )
305363
306364 if pa > 0 {
307- img .Pix [p ] = uint8 ((rSum * mulSum ) >> shgSum )
308- img .Pix [p + 1 ] = uint8 ((gSum * mulSum ) >> shgSum )
309- img .Pix [p + 2 ] = uint8 ((bSum * mulSum ) >> shgSum )
365+ src .Pix [p ] = uint8 ((rSum * mulSum ) >> shgSum )
366+ src .Pix [p + 1 ] = uint8 ((gSum * mulSum ) >> shgSum )
367+ src .Pix [p + 2 ] = uint8 ((bSum * mulSum ) >> shgSum )
310368 } else {
311- img .Pix [p ] = 0
312- img .Pix [p + 1 ] = 0
313- img .Pix [p + 2 ] = 0
369+ src .Pix [p ] = 0
370+ src .Pix [p + 1 ] = 0
371+ src .Pix [p + 2 ] = 0
314372 }
315373
316374 rSum -= rOutSum
@@ -330,10 +388,10 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
330388 }
331389 p = (x + (p * width )) << 2
332390
333- stackIn .r = uint32 (img .Pix [p ])
334- stackIn .g = uint32 (img .Pix [p + 1 ])
335- stackIn .b = uint32 (img .Pix [p + 2 ])
336- stackIn .a = uint32 (img .Pix [p + 3 ])
391+ stackIn .r = uint32 (src .Pix [p ])
392+ stackIn .g = uint32 (src .Pix [p + 1 ])
393+ stackIn .b = uint32 (src .Pix [p + 2 ])
394+ stackIn .a = uint32 (src .Pix [p + 3 ])
337395
338396 rInSum += stackIn .r
339397 gInSum += stackIn .g
@@ -367,73 +425,4 @@ func Process(src image.Image, radius uint32) (*image.NRGBA, error) {
367425 yi += width
368426 }
369427 }
370- return img , nil
371- }
372-
373- // toNRGBA converts an image type to *image.NRGBA with min-point at (0, 0).
374- func toNRGBA (img image.Image ) * image.NRGBA {
375- srcBounds := img .Bounds ()
376- srcMinX := srcBounds .Min .X
377- srcMinY := srcBounds .Min .Y
378-
379- dstBounds := srcBounds .Sub (srcBounds .Min )
380- dstW := dstBounds .Dx ()
381- dstH := dstBounds .Dy ()
382- dst := image .NewNRGBA (dstBounds )
383-
384- switch src := img .(type ) {
385- case * image.NRGBA :
386- rowSize := srcBounds .Dx () * 4
387- for dstY := 0 ; dstY < dstH ; dstY ++ {
388- di := dst .PixOffset (0 , dstY )
389- si := src .PixOffset (srcMinX , srcMinY + dstY )
390- for dstX := 0 ; dstX < dstW ; dstX ++ {
391- copy (dst .Pix [di :di + rowSize ], src .Pix [si :si + rowSize ])
392- }
393- }
394- case * image.YCbCr :
395- for dstY := 0 ; dstY < dstH ; dstY ++ {
396- di := dst .PixOffset (0 , dstY )
397- for dstX := 0 ; dstX < dstW ; dstX ++ {
398- srcX := srcMinX + dstX
399- srcY := srcMinY + dstY
400- siy := src .YOffset (srcX , srcY )
401- sic := src .COffset (srcX , srcY )
402- r , g , b := color .YCbCrToRGB (src .Y [siy ], src .Cb [sic ], src .Cr [sic ])
403- dst .Pix [di + 0 ] = r
404- dst .Pix [di + 1 ] = g
405- dst .Pix [di + 2 ] = b
406- dst .Pix [di + 3 ] = 0xff
407- di += 4
408- }
409- }
410- case * image.Gray :
411- for dstY := 0 ; dstY < dstH ; dstY ++ {
412- di := dst .PixOffset (0 , dstY )
413- si := src .PixOffset (srcMinX , srcMinY + dstY )
414- for dstX := 0 ; dstX < dstW ; dstX ++ {
415- c := src .Pix [si ]
416- dst .Pix [di + 0 ] = c
417- dst .Pix [di + 1 ] = c
418- dst .Pix [di + 2 ] = c
419- dst .Pix [di + 3 ] = 0xff
420- di += 4
421- si ++
422- }
423- }
424- default :
425- for dstY := 0 ; dstY < dstH ; dstY ++ {
426- di := dst .PixOffset (0 , dstY )
427- for dstX := 0 ; dstX < dstW ; dstX ++ {
428- c := color .NRGBAModel .Convert (img .At (srcMinX + dstX , srcMinY + dstY )).(color.NRGBA )
429- dst .Pix [di + 0 ] = c .R
430- dst .Pix [di + 1 ] = c .G
431- dst .Pix [di + 2 ] = c .B
432- dst .Pix [di + 3 ] = c .A
433- di += 4
434- }
435- }
436- }
437-
438- return dst
439428}
0 commit comments