OSDN Git Service

3e02549b0d458c29fc968630d495865f066c8571
[android-x86/packages-apps-Eleven.git] / src / com / cyanogenmod / eleven / utils / BitmapUtils.java
1 /*
2  * Copyright (C) 2012 Andrew Neal
3  * Copyright (C) 2014 The CyanogenMod Project
4  * Licensed under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with the
6  * License. You may obtain a copy of the License at
7  * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
8  * or agreed to in writing, software distributed under the License is
9  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
10  * KIND, either express or implied. See the License for the specific language
11  * governing permissions and limitations under the License.
12  */
13
14 package com.cyanogenmod.eleven.utils;
15
16 import android.graphics.Bitmap;
17 import android.graphics.Canvas;
18 import android.graphics.Paint;
19
20 /**
21  * {@link Bitmap} specific helpers.
22  *
23  * @author Andrew Neal (andrewdneal@gmail.com)
24  */
25 public final class BitmapUtils {
26
27     /* Initial blur radius. */
28     private static final int DEFAULT_BLUR_RADIUS = 8;
29
30     /** This class is never instantiated */
31     private BitmapUtils() {
32     }
33
34     /**
35      * Takes a bitmap and creates a new slightly blurry version of it.
36      *
37      * @param sentBitmap The {@link Bitmap} to blur.
38      * @return A blurred version of the given {@link Bitmap}.
39      */
40     public static final Bitmap createBlurredBitmap(final Bitmap sentBitmap) {
41         if (sentBitmap == null) {
42             return null;
43         }
44
45         // Stack Blur v1.0 from
46         // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
47         //
48         // Java Author: Mario Klingemann <mario at quasimondo.com>
49         // http://incubator.quasimondo.com
50         // created Feburary 29, 2004
51         // Android port : Yahel Bouaziz <yahel at kayenko.com>
52         // http://www.kayenko.com
53         // ported april 5th, 2012
54
55         // This is a compromise between Gaussian Blur and Box blur
56         // It creates much better looking blurs than Box Blur, but is
57         // 7x faster than my Gaussian Blur implementation.
58         //
59         // I called it Stack Blur because this describes best how this
60         // filter works internally: it creates a kind of moving stack
61         // of colors whilst scanning through the image. Thereby it
62         // just has to add one new block of color to the right side
63         // of the stack and remove the leftmost color. The remaining
64         // colors on the topmost layer of the stack are either added on
65         // or reduced by one, depending on if they are on the right or
66         // on the left side of the stack.
67         //
68         // If you are using this algorithm in your code please add
69         // the following line:
70         //
71         // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
72
73         final Bitmap mBitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
74
75         final int w = mBitmap.getWidth();
76         final int h = mBitmap.getHeight();
77
78         final int[] pix = new int[w * h];
79         mBitmap.getPixels(pix, 0, w, 0, 0, w, h);
80
81         final int wm = w - 1;
82         final int hm = h - 1;
83         final int wh = w * h;
84         final int div = DEFAULT_BLUR_RADIUS + DEFAULT_BLUR_RADIUS + 1;
85
86         final int r[] = new int[wh];
87         final int g[] = new int[wh];
88         final int b[] = new int[wh];
89         final int vmin[] = new int[Math.max(w, h)];
90         int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
91
92         int divsum = div + 1 >> 1;
93         divsum *= divsum;
94         final int dv[] = new int[256 * divsum];
95         for (i = 0; i < 256 * divsum; i++) {
96             dv[i] = i / divsum;
97         }
98
99         yw = yi = 0;
100
101         final int[][] stack = new int[div][3];
102         int stackpointer;
103         int stackstart;
104         int[] sir;
105         int rbs;
106         final int r1 = DEFAULT_BLUR_RADIUS + 1;
107         int routsum, goutsum, boutsum;
108         int rinsum, ginsum, binsum;
109
110         for (y = 0; y < h; y++) {
111             rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
112             for (i = -DEFAULT_BLUR_RADIUS; i <= DEFAULT_BLUR_RADIUS; i++) {
113                 p = pix[yi + Math.min(wm, Math.max(i, 0))];
114                 sir = stack[i + DEFAULT_BLUR_RADIUS];
115                 sir[0] = (p & 0xff0000) >> 16;
116                 sir[1] = (p & 0x00ff00) >> 8;
117                 sir[2] = p & 0x0000ff;
118                 rbs = r1 - Math.abs(i);
119                 rsum += sir[0] * rbs;
120                 gsum += sir[1] * rbs;
121                 bsum += sir[2] * rbs;
122                 if (i > 0) {
123                     rinsum += sir[0];
124                     ginsum += sir[1];
125                     binsum += sir[2];
126                 } else {
127                     routsum += sir[0];
128                     goutsum += sir[1];
129                     boutsum += sir[2];
130                 }
131             }
132             stackpointer = DEFAULT_BLUR_RADIUS;
133
134             for (x = 0; x < w; x++) {
135
136                 r[yi] = dv[rsum];
137                 g[yi] = dv[gsum];
138                 b[yi] = dv[bsum];
139
140                 rsum -= routsum;
141                 gsum -= goutsum;
142                 bsum -= boutsum;
143
144                 stackstart = stackpointer - DEFAULT_BLUR_RADIUS + div;
145                 sir = stack[stackstart % div];
146
147                 routsum -= sir[0];
148                 goutsum -= sir[1];
149                 boutsum -= sir[2];
150
151                 if (y == 0) {
152                     vmin[x] = Math.min(x + DEFAULT_BLUR_RADIUS + 1, wm);
153                 }
154                 p = pix[yw + vmin[x]];
155
156                 sir[0] = (p & 0xff0000) >> 16;
157                 sir[1] = (p & 0x00ff00) >> 8;
158                 sir[2] = p & 0x0000ff;
159
160                 rinsum += sir[0];
161                 ginsum += sir[1];
162                 binsum += sir[2];
163
164                 rsum += rinsum;
165                 gsum += ginsum;
166                 bsum += binsum;
167
168                 stackpointer = (stackpointer + 1) % div;
169                 sir = stack[stackpointer % div];
170
171                 routsum += sir[0];
172                 goutsum += sir[1];
173                 boutsum += sir[2];
174
175                 rinsum -= sir[0];
176                 ginsum -= sir[1];
177                 binsum -= sir[2];
178
179                 yi++;
180             }
181             yw += w;
182         }
183         for (x = 0; x < w; x++) {
184             rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
185             yp = -DEFAULT_BLUR_RADIUS * w;
186             for (i = -DEFAULT_BLUR_RADIUS; i <= DEFAULT_BLUR_RADIUS; i++) {
187                 yi = Math.max(0, yp) + x;
188
189                 sir = stack[i + DEFAULT_BLUR_RADIUS];
190
191                 sir[0] = r[yi];
192                 sir[1] = g[yi];
193                 sir[2] = b[yi];
194
195                 rbs = r1 - Math.abs(i);
196
197                 rsum += r[yi] * rbs;
198                 gsum += g[yi] * rbs;
199                 bsum += b[yi] * rbs;
200
201                 if (i > 0) {
202                     rinsum += sir[0];
203                     ginsum += sir[1];
204                     binsum += sir[2];
205                 } else {
206                     routsum += sir[0];
207                     goutsum += sir[1];
208                     boutsum += sir[2];
209                 }
210
211                 if (i < hm) {
212                     yp += w;
213                 }
214             }
215             yi = x;
216             stackpointer = DEFAULT_BLUR_RADIUS;
217             for (y = 0; y < h; y++) {
218                 pix[yi] = 0xff000000 | dv[rsum] << 16 | dv[gsum] << 8 | dv[bsum];
219
220                 rsum -= routsum;
221                 gsum -= goutsum;
222                 bsum -= boutsum;
223
224                 stackstart = stackpointer - DEFAULT_BLUR_RADIUS + div;
225                 sir = stack[stackstart % div];
226
227                 routsum -= sir[0];
228                 goutsum -= sir[1];
229                 boutsum -= sir[2];
230
231                 if (x == 0) {
232                     vmin[y] = Math.min(y + r1, hm) * w;
233                 }
234                 p = x + vmin[y];
235
236                 sir[0] = r[p];
237                 sir[1] = g[p];
238                 sir[2] = b[p];
239
240                 rinsum += sir[0];
241                 ginsum += sir[1];
242                 binsum += sir[2];
243
244                 rsum += rinsum;
245                 gsum += ginsum;
246                 bsum += binsum;
247
248                 stackpointer = (stackpointer + 1) % div;
249                 sir = stack[stackpointer];
250
251                 routsum += sir[0];
252                 goutsum += sir[1];
253                 boutsum += sir[2];
254
255                 rinsum -= sir[0];
256                 ginsum -= sir[1];
257                 binsum -= sir[2];
258
259                 yi += w;
260             }
261         }
262
263         mBitmap.setPixels(pix, 0, w, 0, 0, w, h);
264         return mBitmap;
265     }
266
267     /**
268      * This is only used when the launcher shortcut is created.
269      *
270      * @param bitmap The artist, album, genre, or playlist image that's going to
271      *            be cropped.
272      * @param size The new size.
273      * @return A {@link Bitmap} that has been resized and cropped for a launcher
274      *         shortcut.
275      */
276     public static final Bitmap resizeAndCropCenter(final Bitmap bitmap, final int size) {
277         final int w = bitmap.getWidth();
278         final int h = bitmap.getHeight();
279         if (w == size && h == size) {
280             return bitmap;
281         }
282
283         final float mScale = (float)size / Math.min(w, h);
284
285         final Bitmap mTarget = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
286         final int mWidth = Math.round(mScale * bitmap.getWidth());
287         final int mHeight = Math.round(mScale * bitmap.getHeight());
288         final Canvas mCanvas = new Canvas(mTarget);
289         mCanvas.translate((size - mWidth) / 2f, (size - mHeight) / 2f);
290         mCanvas.scale(mScale, mScale);
291         final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
292         mCanvas.drawBitmap(bitmap, 0, 0, paint);
293         return mTarget;
294     }
295 }