前端处理图片高斯模糊

得到一个需求,要求书籍封面的背景和书籍封面的颜色有一定的一致性,也就是如下这种情况:

这种情况,我们解决的思路就是:利用canvas的图像高斯模糊算法,通过高斯模糊书籍封面,获得一张背景图像,结果就是这样:

我们需要依次解决以下两个问题:

1.基于canvas的高斯模糊算法

2.书籍封面是取自阿里大数据服务器的,canvas不支持非本地图片的drawImage和getImageData

针对第一个问题。高斯模糊算法网上有,这就是算法源码:

  1 function stackBlurCanvasRGBA( canvas, top_x, top_y, width, height, radius )
  2 {
  3     if ( isNaN(radius) || radius < 1 ) return;
  4     radius |= 0;
  5 
  6     if (typeof(canvas) == "string")
  7         var canvas  = document.getElementById( canvas );
  8     else if (!canvas instanceof HTMLCanvasElement)
  9         return;
 10 
 11     var context = canvas.getContext("2d");
 12     var imageData;
 13     try {
 14         try {
 15             imageData = context.getImageData( top_x, top_y, width, height );
 16         } catch(e) {
 17 
 18             // NOTE: this part is supposedly only needed if you want to work with local files
 19             // so it might be okay to remove the whole try/catch block and just use
 20             // imageData = context.getImageData( top_x, top_y, width, height );
 21             try {
 22                 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
 23                 imageData = context.getImageData( top_x, top_y, width, height );
 24             } catch(e) {
 25                 //alert("Cannot access local image");
 26                 throw new Error("unable to access local image data: " + e);
 27                 return;
 28             }
 29         }
 30     } catch(e) {
 31         //alert("Cannot access image");
 32         throw new Error("unable to access image data: " + e);
 33     }
 34 
 35     var pixels = imageData.data;
 36 
 37     var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,
 38         r_out_sum, g_out_sum, b_out_sum, a_out_sum,
 39         r_in_sum, g_in_sum, b_in_sum, a_in_sum,
 40         pr, pg, pb, pa, rbs;
 41 
 42     var div = radius + radius + 1;
 43     var w4 = width << 2;
 44     var widthMinus1  = width - 1;
 45     var heightMinus1 = height - 1;
 46     var radiusPlus1  = radius + 1;
 47     var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2;
 48 
 49     var stackStart = new BlurStack();
 50     var stack = stackStart;
 51     for ( i = 1; i < div; i++ )
 52     {
 53         stack = stack.next = new BlurStack();
 54         if ( i == radiusPlus1 ) var stackEnd = stack;
 55     }
 56     stack.next = stackStart;
 57     var stackIn = null;
 58     var stackOut = null;
 59 
 60     yw = yi = 0;
 61 
 62     var mul_sum = mul_table[radius];
 63     var shg_sum = shg_table[radius];
 64 
 65     for ( y = 0; y < height; y++ )
 66     {
 67         r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;
 68 
 69         r_out_sum = radiusPlus1 * ( pr = pixels[yi] );
 70         g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] );
 71         b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] );
 72         a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] );
 73 
 74         r_sum += sumFactor * pr;
 75         g_sum += sumFactor * pg;
 76         b_sum += sumFactor * pb;
 77         a_sum += sumFactor * pa;
 78 
 79         stack = stackStart;
 80 
 81         for ( i = 0; i < radiusPlus1; i++ )
 82         {
 83             stack.r = pr;
 84             stack.g = pg;
 85             stack.b = pb;
 86             stack.a = pa;
 87             stack = stack.next;
 88         }
 89 
 90         for ( i = 1; i < radiusPlus1; i++ )
 91         {
 92             p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 );
 93             r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i );
 94             g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs;
 95             b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs;
 96             a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs;
 97 
 98             r_in_sum += pr;
 99             g_in_sum += pg;
100             b_in_sum += pb;
101             a_in_sum += pa;
102 
103             stack = stack.next;
104         }
105 
106 
107         stackIn = stackStart;
108         stackOut = stackEnd;
109         for ( x = 0; x < width; x++ )
110         {
111             pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum;
112             if ( pa != 0 )
113             {
114                 pa = 255 / pa;
115                 pixels[yi]   = ((r_sum * mul_sum) >> shg_sum) * pa;
116                 pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
117                 pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
118             } else {
119                 pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
120             }
121 
122             r_sum -= r_out_sum;
123             g_sum -= g_out_sum;
124             b_sum -= b_out_sum;
125             a_sum -= a_out_sum;
126 
127             r_out_sum -= stackIn.r;
128             g_out_sum -= stackIn.g;
129             b_out_sum -= stackIn.b;
130             a_out_sum -= stackIn.a;
131 
132             p =  ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
133 
134             r_in_sum += ( stackIn.r = pixels[p]);
135             g_in_sum += ( stackIn.g = pixels[p+1]);
136             b_in_sum += ( stackIn.b = pixels[p+2]);
137             a_in_sum += ( stackIn.a = pixels[p+3]);
138 
139             r_sum += r_in_sum;
140             g_sum += g_in_sum;
141             b_sum += b_in_sum;
142             a_sum += a_in_sum;
143 
144             stackIn = stackIn.next;
145 
146             r_out_sum += ( pr = stackOut.r );
147             g_out_sum += ( pg = stackOut.g );
148             b_out_sum += ( pb = stackOut.b );
149             a_out_sum += ( pa = stackOut.a );
150 
151             r_in_sum -= pr;
152             g_in_sum -= pg;
153             b_in_sum -= pb;
154             a_in_sum -= pa;
155 
156             stackOut = stackOut.next;
157 
158             yi += 4;
159         }
160         yw += width;
161     }
162 
163 
164     for ( x = 0; x < width; x++ )
165     {
166         g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0;
167 
168         yi = x << 2;
169         r_out_sum = radiusPlus1 * ( pr = pixels[yi]);
170         g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]);
171         b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]);
172         a_out_sum = radiusPlus1 * ( pa = pixels[yi+3]);
173 
174         r_sum += sumFactor * pr;
175         g_sum += sumFactor * pg;
176         b_sum += sumFactor * pb;
177         a_sum += sumFactor * pa;
178 
179         stack = stackStart;
180 
181         for ( i = 0; i < radiusPlus1; i++ )
182         {
183             stack.r = pr;
184             stack.g = pg;
185             stack.b = pb;
186             stack.a = pa;
187             stack = stack.next;
188         }
189 
190         yp = width;
191 
192         for ( i = 1; i <= radius; i++ )
193         {
194             yi = ( yp + x ) << 2;
195 
196             r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i );
197             g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs;
198             b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs;
199             a_sum += ( stack.a = ( pa = pixels[yi+3])) * rbs;
200 
201             r_in_sum += pr;
202             g_in_sum += pg;
203             b_in_sum += pb;
204             a_in_sum += pa;
205 
206             stack = stack.next;
207 
208             if( i < heightMinus1 )
209             {
210                 yp += width;
211             }
212         }
213 
214         yi = x;
215         stackIn = stackStart;
216         stackOut = stackEnd;
217         for ( y = 0; y < height; y++ )
218         {
219             p = yi << 2;
220             pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum;
221             if ( pa > 0 )
222             {
223                 pa = 255 / pa;
224                 pixels[p]   = ((r_sum * mul_sum) >> shg_sum ) * pa;
225                 pixels[p+1] = ((g_sum * mul_sum) >> shg_sum ) * pa;
226                 pixels[p+2] = ((b_sum * mul_sum) >> shg_sum ) * pa;
227             } else {
228                 pixels[p] = pixels[p+1] = pixels[p+2] = 0;
229             }
230 
231             r_sum -= r_out_sum;
232             g_sum -= g_out_sum;
233             b_sum -= b_out_sum;
234             a_sum -= a_out_sum;
235 
236             r_out_sum -= stackIn.r;
237             g_out_sum -= stackIn.g;
238             b_out_sum -= stackIn.b;
239             a_out_sum -= stackIn.a;
240 
241             p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
242 
243             r_sum += ( r_in_sum += ( stackIn.r = pixels[p]));
244             g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1]));
245             b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2]));
246             a_sum += ( a_in_sum += ( stackIn.a = pixels[p+3]));
247 
248             stackIn = stackIn.next;
249 
250             r_out_sum += ( pr = stackOut.r );
251             g_out_sum += ( pg = stackOut.g );
252             b_out_sum += ( pb = stackOut.b );
253             a_out_sum += ( pa = stackOut.a );
254 
255             r_in_sum -= pr;
256             g_in_sum -= pg;
257             b_in_sum -= pb;
258             a_in_sum -= pa;
259 
260             stackOut = stackOut.next;
261 
262             yi += width;
263         }
264     }
265 
266     context.putImageData( imageData, top_x, top_y );
267 
268 }
View Code

而第二个问题也很简单,canvas虽然不支持处理外域图片,但是可以接收图像的base64
把图片处理成base64,后端服务器语言只需调用一个函数就能做到,但是大规模字符串传递会影响服务器效率,所以,将图片转换成base64只能通过前端解决

由于只考虑谷歌浏览器,所以这方面的转换十分简单,

XMLHttpRequest 2.0 可以设置responseType, 我们将其设置为 blob

然后将blob转换成base64

代码如下:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 5     <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
 6     <meta name="apple-mobile-web-app-capable" content="yes">
 7     <meta name="format-detection" content="telephone=no">
 8     <title>Examples</title>
 9     <meta name="description" content="">
10     <meta name="keywords" content="">
11     <link href="" rel="stylesheet">
12     <style>
13         .hero {
14             padding: 3em 0;
15             position: relative;
16         }
17         .hero__background {
18             position: absolute;
19             top: 0;
20             left: 0;
21             width: 100%;
22             height: 200px;
23             z-index: 1;
24         }
25         .hero__title {
26             position: relative;
27             z-index: 2;
28             color: #fff;
29             text-align: center;
30         }
31 
32     </style>
33 
34 <body>
35 <div class="hero">
36     <canvas class="hero__background" id="heroCanvas" width="200" height="200" data-canvas></canvas>
37     <!--<h1 class="hero__title"></h1>-->
38 </div>
39 
40 <!-- Our image to be blurred http://oss-asq-img.11222.cn/cover/raw/2013081212197381.jpg-->
41 
42 <img id="img" data-canvas-image  style="top:200px; position:relative; ">
43 <canvas id="mc" style="height:200px; 320px;"></canvas>
44 <div id="add" style="height:300px; 400px;">
45   
46 </div>
47 </body>
48 <script type="text/javascript" src="js/stackBoxBlur.js"></script>
49 <script type="text/javascript">
50 
51        
52 </script>
53 <script>
54      function ajax(url,method,funcs){
55         var xhr=new XMLHttpRequest();
56         xhr.open(method,url,true);
57         xhr.responseType='blob';
58         xhr.onload=function(e){
59            if(this.status==200){
60                funcs(this.response); 
61            } 
62         }
63         xhr.send(null);
64      }
65      var url='http://xxxxxxxxxxx/demo/abc.jpg';
66      ajax(url,'get',function(x){
67           var bb=new Blob([x],{type:'image/jpeg'});
68           var ak=btoa(bb);     
69            var reader = new window.FileReader();
70           reader.readAsDataURL(x); 
71           reader.onloadend = function() {
72                 ak = this.result;                
73                 document.querySelector('#img').src=ak;
74                  var BLUR_RADIUS = 100;
75                  var canvas = document.querySelector('[data-canvas]');
76                  var canvasContext = canvas.getContext('2d');
77                  var image = new Image();
78                  image.src = ak;
79                  image.crossOrigin = "Anonymous";
80                  var drawBlur = function() {
81                         var w = canvas.width;
82                         var h = canvas.height;
83                         canvasContext.drawImage(image, 0, 0, w, h);
84                         stackBlurCanvasRGBA('heroCanvas', 0, 0, w, h, BLUR_RADIUS);
85                   };
86                   image.onload = function() {
87                       drawBlur();
88                    }
89      }
90 });
91     
92 </script>
93 </html>
View Code

问题解决

原文地址:https://www.cnblogs.com/JhoneLee/p/4317550.html