@phucprime/react-native-image-editor 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +247 -0
- package/android/build.gradle +62 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradlew +240 -0
- package/android/gradlew.bat +91 -0
- package/android/libs/photo-editor-android.jar +0 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/BaseActivity.java +300 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/ColorPickerAdapter.java +129 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/EmojiAdapter.java +91 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/EmojiFragment.java +56 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/GalleryUtils.java +73 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/ImageAdapter.java +69 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/ImageFragment.java +93 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/MainActivity.java +29 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/MediaActivity.java +95 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/PhotoEditorActivity.java +1055 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/TranslationService.java +31 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/UtilFunctions.java +176 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/widget/RealtimeBlurView.java +359 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/widget/SlidingUpPanelLayout.java +1527 -0
- package/android/src/main/java/com/ahmedadeltito/photoeditor/widget/ViewDragHelper.java +1466 -0
- package/android/src/main/java/ui/photoeditor/RNPhotoEditorModule.java +108 -0
- package/android/src/main/java/ui/photoeditor/RNPhotoEditorPackage.java +29 -0
- package/android/src/main/res/drawable/above_shadow.xml +7 -0
- package/android/src/main/res/drawable/below_shadow.xml +7 -0
- package/android/src/main/res/drawable/fading_shadow.xml +7 -0
- package/android/src/main/res/drawable/rounded_border_text_view.xml +13 -0
- package/android/src/main/res/drawable-xhdpi/aa.png +0 -0
- package/android/src/main/res/drawable-xhdpi/bb.png +0 -0
- package/android/src/main/res/drawable-xhdpi/c.png +0 -0
- package/android/src/main/res/drawable-xhdpi/cc.png +0 -0
- package/android/src/main/res/drawable-xhdpi/d.png +0 -0
- package/android/src/main/res/drawable-xhdpi/dd.png +0 -0
- package/android/src/main/res/drawable-xhdpi/e.png +0 -0
- package/android/src/main/res/drawable-xhdpi/ee.png +0 -0
- package/android/src/main/res/drawable-xhdpi/i.png +0 -0
- package/android/src/main/res/drawable-xhdpi/j.png +0 -0
- package/android/src/main/res/drawable-xhdpi/k.png +0 -0
- package/android/src/main/res/drawable-xhdpi/l.png +0 -0
- package/android/src/main/res/drawable-xhdpi/m.png +0 -0
- package/android/src/main/res/drawable-xhdpi/n.png +0 -0
- package/android/src/main/res/drawable-xhdpi/o.png +0 -0
- package/android/src/main/res/drawable-xhdpi/p.png +0 -0
- package/android/src/main/res/drawable-xhdpi/q.png +0 -0
- package/android/src/main/res/drawable-xhdpi/r.png +0 -0
- package/android/src/main/res/drawable-xhdpi/s.png +0 -0
- package/android/src/main/res/drawable-xhdpi/t.png +0 -0
- package/android/src/main/res/drawable-xhdpi/u.png +0 -0
- package/android/src/main/res/drawable-xhdpi/v.png +0 -0
- package/android/src/main/res/drawable-xhdpi/w.png +0 -0
- package/android/src/main/res/drawable-xhdpi/x.png +0 -0
- package/android/src/main/res/drawable-xhdpi/y.png +0 -0
- package/android/src/main/res/drawable-xhdpi/z.png +0 -0
- package/android/src/main/res/layout/activity_main.xml +28 -0
- package/android/src/main/res/layout/activity_photo_editor.xml +316 -0
- package/android/src/main/res/layout/add_text_popup_window.xml +47 -0
- package/android/src/main/res/layout/color_picker_item_list.xml +15 -0
- package/android/src/main/res/layout/fragment_main_photo_edit_emoji.xml +11 -0
- package/android/src/main/res/layout/fragment_main_photo_edit_image.xml +10 -0
- package/android/src/main/res/layout/fragment_photo_edit_emoji_item_list.xml +17 -0
- package/android/src/main/res/layout/fragment_photo_edit_image_item_list.xml +16 -0
- package/android/src/main/res/raw/emojioneandroid +0 -0
- package/android/src/main/res/raw/eventtusicons +0 -0
- package/android/src/main/res/raw/font_awesome_solid.otf +0 -0
- package/android/src/main/res/raw/icomoon.ttf +0 -0
- package/android/src/main/res/values/arrays.xml +447 -0
- package/android/src/main/res/values/attrs.xml +30 -0
- package/android/src/main/res/values/colors.xml +21 -0
- package/android/src/main/res/values/dimens.xml +4 -0
- package/android/src/main/res/values/strings.xml +33 -0
- package/android/src/main/res/values/styles.xml +27 -0
- package/ios/RNImageEditor.podspec +26 -0
- package/ios/RNPhotoEditor.h +13 -0
- package/ios/RNPhotoEditor.m +163 -0
- package/ios/RNPhotoEditor.xcodeproj/project.pbxproj +362 -0
- package/lib/index.d.ts +125 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +114 -0
- package/lib/index.js.map +1 -0
- package/package.json +73 -0
- package/react-native-image-editor.podspec +39 -0
- package/src/index.ts +232 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.ahmedadeltito.photoeditor;
|
|
2
|
+
|
|
3
|
+
import java.util.HashMap;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Created by Thien PV on 11/24/23.
|
|
7
|
+
*/
|
|
8
|
+
public class TranslationService {
|
|
9
|
+
|
|
10
|
+
private static TranslationService instance = null;
|
|
11
|
+
private HashMap<String, String> translations;
|
|
12
|
+
|
|
13
|
+
private TranslationService() {
|
|
14
|
+
translations = new HashMap<>();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static TranslationService getInstance() {
|
|
18
|
+
if (instance == null) {
|
|
19
|
+
instance = new TranslationService();
|
|
20
|
+
}
|
|
21
|
+
return instance;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public void init(HashMap translations) {
|
|
25
|
+
this.translations = translations;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public String getTranslation(String key) {
|
|
29
|
+
return translations.get(key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
package com.ahmedadeltito.photoeditor;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.graphics.Bitmap;
|
|
6
|
+
import android.os.Build;
|
|
7
|
+
import android.text.Html;
|
|
8
|
+
import android.util.Base64;
|
|
9
|
+
import android.view.View;
|
|
10
|
+
import android.view.animation.AlphaAnimation;
|
|
11
|
+
import android.view.inputmethod.InputMethodManager;
|
|
12
|
+
|
|
13
|
+
import java.io.ByteArrayOutputStream;
|
|
14
|
+
import java.util.ArrayList;
|
|
15
|
+
import java.util.StringTokenizer;
|
|
16
|
+
import java.util.regex.Matcher;
|
|
17
|
+
import java.util.regex.Pattern;
|
|
18
|
+
public class UtilFunctions {
|
|
19
|
+
|
|
20
|
+
// private static final String pattern =
|
|
21
|
+
// "\\s*([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4})\\s*";
|
|
22
|
+
// private static final String pattern =
|
|
23
|
+
// "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}\\@[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+";
|
|
24
|
+
|
|
25
|
+
private static final AlphaAnimation enableAnim = new AlphaAnimation(0.6f,
|
|
26
|
+
1.0f);
|
|
27
|
+
|
|
28
|
+
private static final AlphaAnimation disableAnim = new AlphaAnimation(1.0f,
|
|
29
|
+
0.6f);
|
|
30
|
+
|
|
31
|
+
public static boolean stringIsEmpty(String string) {
|
|
32
|
+
|
|
33
|
+
if (string != null) {
|
|
34
|
+
if (!string.trim().equals("")) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static boolean stringIsNotEmpty(String string) {
|
|
42
|
+
if (string != null && !string.equals("null")) {
|
|
43
|
+
if (!string.trim().equals("")) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public static String[] stringTokenizer(String string) {
|
|
51
|
+
|
|
52
|
+
StringTokenizer tokens = new StringTokenizer(string, ",");
|
|
53
|
+
String[] result = new String[tokens.countTokens()];
|
|
54
|
+
|
|
55
|
+
for (int i = 0; i < tokens.countTokens(); i++) {
|
|
56
|
+
result[i] = tokens.nextToken();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public static String ArrayToString(ArrayList<String> string) {
|
|
63
|
+
|
|
64
|
+
String result = "";
|
|
65
|
+
StringBuilder builder = new StringBuilder();
|
|
66
|
+
int len = string.size() - 1;
|
|
67
|
+
if (string.size() > 0) {
|
|
68
|
+
for (int i = 0; i < len; i++) {
|
|
69
|
+
result += string.get(i) + ", ";
|
|
70
|
+
builder.append(string.get(i));
|
|
71
|
+
builder.append(", ");
|
|
72
|
+
}
|
|
73
|
+
result += string.get(len);
|
|
74
|
+
builder.append(string.get(len));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return builder.toString();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public static boolean isValidEmail(String s) {
|
|
81
|
+
|
|
82
|
+
// return Pattern.matches(pattern, s);
|
|
83
|
+
try {
|
|
84
|
+
return android.util.Patterns.EMAIL_ADDRESS.matcher(s).matches();
|
|
85
|
+
} catch (NullPointerException exception) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public static void enableView(View v) {
|
|
91
|
+
if (Build.VERSION.SDK_INT >= 11) {
|
|
92
|
+
try {
|
|
93
|
+
v.setAlpha(1.0f);
|
|
94
|
+
return;
|
|
95
|
+
} catch (Exception e) {
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
enableAnim.setDuration(100);
|
|
99
|
+
enableAnim.setFillAfter(true);
|
|
100
|
+
v.startAnimation(enableAnim);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public static void disableView(View v) {
|
|
105
|
+
if (Build.VERSION.SDK_INT >= 11) {
|
|
106
|
+
try {
|
|
107
|
+
v.setAlpha(0.6f);
|
|
108
|
+
return;
|
|
109
|
+
} catch (Exception e) {
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
disableAnim.setDuration(100);
|
|
113
|
+
disableAnim.setFillAfter(true);
|
|
114
|
+
v.startAnimation(disableAnim);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public static String stripHtml(String html) {
|
|
120
|
+
String s = Html.fromHtml(html).toString();
|
|
121
|
+
s = s.replaceAll("[\n\r\t]", " ");
|
|
122
|
+
return s;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public static boolean containSpace(String s) {
|
|
126
|
+
Pattern pattern = Pattern.compile("\\s");
|
|
127
|
+
Matcher matcher = pattern.matcher(s);
|
|
128
|
+
return matcher.find();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public static String getYoutubeVideoId(String youtubeUrl) {
|
|
132
|
+
String video_id = "";
|
|
133
|
+
if (youtubeUrl != null && youtubeUrl.trim().length() > 0
|
|
134
|
+
&& youtubeUrl.startsWith("http")) {
|
|
135
|
+
String expression = "^.*((youtu.be"
|
|
136
|
+
+ "\\/)"
|
|
137
|
+
+ "|(v\\/)|(\\/u\\/w\\/)|(embed\\/)|(watch\\?))\\??v?=?([^#\\&\\?]*).*";
|
|
138
|
+
CharSequence input = youtubeUrl;
|
|
139
|
+
Pattern pattern = Pattern.compile(expression,
|
|
140
|
+
Pattern.CASE_INSENSITIVE);
|
|
141
|
+
Matcher matcher = pattern.matcher(input);
|
|
142
|
+
if (matcher.matches()) {
|
|
143
|
+
String groupIndex1 = matcher.group(7);
|
|
144
|
+
if (groupIndex1 != null && groupIndex1.length() == 11)
|
|
145
|
+
video_id = groupIndex1;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return video_id;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public static String encodeImage(Bitmap bitmap) {
|
|
152
|
+
String encodedImage = "";
|
|
153
|
+
try {
|
|
154
|
+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
155
|
+
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
|
|
156
|
+
byte[] b = baos.toByteArray();
|
|
157
|
+
baos.close();
|
|
158
|
+
baos = null;
|
|
159
|
+
encodedImage = Base64.encodeToString(b,
|
|
160
|
+
Base64.NO_WRAP);
|
|
161
|
+
} catch (Exception e) {
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
return encodedImage;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public static void hideKeyboardFrom(Activity activity) {
|
|
168
|
+
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
|
|
169
|
+
imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public static void showKeyboardAt(Activity activity) {
|
|
173
|
+
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
174
|
+
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
package com.ahmedadeltito.photoeditor.widget;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Created by Ahmed Adel on 5/7/17.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import android.app.Activity;
|
|
8
|
+
import android.content.Context;
|
|
9
|
+
import android.content.ContextWrapper;
|
|
10
|
+
import android.content.pm.ApplicationInfo;
|
|
11
|
+
import android.content.res.TypedArray;
|
|
12
|
+
import android.graphics.Bitmap;
|
|
13
|
+
import android.graphics.Canvas;
|
|
14
|
+
import android.graphics.Rect;
|
|
15
|
+
import android.renderscript.Allocation;
|
|
16
|
+
import android.renderscript.Element;
|
|
17
|
+
import android.renderscript.RSRuntimeException;
|
|
18
|
+
import android.renderscript.RenderScript;
|
|
19
|
+
import android.renderscript.ScriptIntrinsicBlur;
|
|
20
|
+
import android.util.AttributeSet;
|
|
21
|
+
import android.util.TypedValue;
|
|
22
|
+
import android.view.View;
|
|
23
|
+
import android.view.ViewTreeObserver;
|
|
24
|
+
|
|
25
|
+
import ui.photoeditor.R;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A realtime blurring overlay (like iOS UIVisualEffectView). Just put it above
|
|
29
|
+
* the view you want to blur and it doesn't have to be in the same ViewGroup
|
|
30
|
+
* <ul>
|
|
31
|
+
* <li>realtimeBlurRadius (10dp)</li>
|
|
32
|
+
* <li>realtimeDownsampleFactor (4)</li>
|
|
33
|
+
* <li>realtimeOverlayColor (#aaffffff)</li>
|
|
34
|
+
* </ul>
|
|
35
|
+
*/
|
|
36
|
+
public class RealtimeBlurView extends View {
|
|
37
|
+
|
|
38
|
+
private float mDownsampleFactor; // default 4
|
|
39
|
+
private int mOverlayColor; // default #aaffffff
|
|
40
|
+
private float mBlurRadius; // default 10dp (0 < r <= 25)
|
|
41
|
+
|
|
42
|
+
private boolean mDirty;
|
|
43
|
+
private Bitmap mBitmapToBlur, mBlurredBitmap;
|
|
44
|
+
private Canvas mBlurringCanvas;
|
|
45
|
+
private RenderScript mRenderScript;
|
|
46
|
+
private ScriptIntrinsicBlur mBlurScript;
|
|
47
|
+
private Allocation mBlurInput, mBlurOutput;
|
|
48
|
+
private boolean mIsRendering;
|
|
49
|
+
private final Rect mRectSrc = new Rect(), mRectDst = new Rect();
|
|
50
|
+
// mDecorView should be the root view of the activity (even if you are on a different window like a dialog)
|
|
51
|
+
private View mDecorView;
|
|
52
|
+
// If the view is on different root view (usually means we are on a PopupWindow),
|
|
53
|
+
// we need to manually call invalidate() in onPreDraw(), otherwise we will not be able to see the changes
|
|
54
|
+
private boolean mDifferentRoot;
|
|
55
|
+
private static int RENDERING_COUNT;
|
|
56
|
+
|
|
57
|
+
public RealtimeBlurView(Context context, AttributeSet attrs) {
|
|
58
|
+
super(context, attrs);
|
|
59
|
+
|
|
60
|
+
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RealtimeBlurView);
|
|
61
|
+
mBlurRadius = a.getDimension(R.styleable.RealtimeBlurView_realtimeBlurRadius,
|
|
62
|
+
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()));
|
|
63
|
+
mDownsampleFactor = a.getFloat(R.styleable.RealtimeBlurView_realtimeDownsampleFactor, 4);
|
|
64
|
+
mOverlayColor = a.getColor(R.styleable.RealtimeBlurView_realtimeOverlayColor, 0xAAFFFFFF);
|
|
65
|
+
a.recycle();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public void setBlurRadius(float radius) {
|
|
69
|
+
if (mBlurRadius != radius) {
|
|
70
|
+
mBlurRadius = radius;
|
|
71
|
+
mDirty = true;
|
|
72
|
+
invalidate();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public void setDownsampleFactor(float factor) {
|
|
77
|
+
if (factor <= 0) {
|
|
78
|
+
throw new IllegalArgumentException("Downsample factor must be greater than 0.");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (mDownsampleFactor != factor) {
|
|
82
|
+
mDownsampleFactor = factor;
|
|
83
|
+
mDirty = true; // may also change blur radius
|
|
84
|
+
releaseBitmap();
|
|
85
|
+
invalidate();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public void setOverlayColor(int color) {
|
|
90
|
+
if (mOverlayColor != color) {
|
|
91
|
+
mOverlayColor = color;
|
|
92
|
+
invalidate();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private void releaseBitmap() {
|
|
97
|
+
if (mBlurInput != null) {
|
|
98
|
+
mBlurInput.destroy();
|
|
99
|
+
mBlurInput = null;
|
|
100
|
+
}
|
|
101
|
+
if (mBlurOutput != null) {
|
|
102
|
+
mBlurOutput.destroy();
|
|
103
|
+
mBlurOutput = null;
|
|
104
|
+
}
|
|
105
|
+
if (mBitmapToBlur != null) {
|
|
106
|
+
mBitmapToBlur.recycle();
|
|
107
|
+
mBitmapToBlur = null;
|
|
108
|
+
}
|
|
109
|
+
if (mBlurredBitmap != null) {
|
|
110
|
+
mBlurredBitmap.recycle();
|
|
111
|
+
mBlurredBitmap = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private void releaseScript() {
|
|
116
|
+
if (mRenderScript != null) {
|
|
117
|
+
mRenderScript.destroy();
|
|
118
|
+
mRenderScript = null;
|
|
119
|
+
}
|
|
120
|
+
if (mBlurScript != null) {
|
|
121
|
+
mBlurScript.destroy();
|
|
122
|
+
mBlurScript = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
protected void release() {
|
|
127
|
+
releaseBitmap();
|
|
128
|
+
releaseScript();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
protected boolean prepare() {
|
|
132
|
+
if (mBlurRadius == 0) {
|
|
133
|
+
release();
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
float downsampleFactor = mDownsampleFactor;
|
|
138
|
+
|
|
139
|
+
if (mDirty || mRenderScript == null) {
|
|
140
|
+
if (mRenderScript == null) {
|
|
141
|
+
try {
|
|
142
|
+
mRenderScript = RenderScript.create(getContext());
|
|
143
|
+
mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
|
|
144
|
+
} catch (RSRuntimeException e) {
|
|
145
|
+
if (isDebug(getContext())) {
|
|
146
|
+
if (e.getMessage() != null && e.getMessage().startsWith("Error loading RS jni library: java.lang.UnsatisfiedLinkError:")) {
|
|
147
|
+
throw new RuntimeException("Error loading RS jni library, Upgrade buildToolsVersion=\"24.0.2\" or higher may solve this issue");
|
|
148
|
+
} else {
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
// In release mode, just ignore
|
|
153
|
+
releaseScript();
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
mDirty = false;
|
|
160
|
+
float radius = mBlurRadius / downsampleFactor;
|
|
161
|
+
if (radius > 25) {
|
|
162
|
+
downsampleFactor = downsampleFactor * radius / 25;
|
|
163
|
+
radius = 25;
|
|
164
|
+
}
|
|
165
|
+
mBlurScript.setRadius(radius);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
final int width = getWidth();
|
|
169
|
+
final int height = getHeight();
|
|
170
|
+
|
|
171
|
+
int scaledWidth = Math.max(1, (int) (width / downsampleFactor));
|
|
172
|
+
int scaledHeight = Math.max(1, (int) (height / downsampleFactor));
|
|
173
|
+
|
|
174
|
+
if (mBlurringCanvas == null || mBlurredBitmap == null
|
|
175
|
+
|| mBlurredBitmap.getWidth() != scaledWidth
|
|
176
|
+
|| mBlurredBitmap.getHeight() != scaledHeight) {
|
|
177
|
+
releaseBitmap();
|
|
178
|
+
|
|
179
|
+
boolean r = false;
|
|
180
|
+
try {
|
|
181
|
+
mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
|
|
182
|
+
if (mBitmapToBlur == null) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
mBlurringCanvas = new Canvas(mBitmapToBlur);
|
|
186
|
+
|
|
187
|
+
mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur,
|
|
188
|
+
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
|
|
189
|
+
mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType());
|
|
190
|
+
|
|
191
|
+
mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
|
|
192
|
+
if (mBlurredBitmap == null) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
r = true;
|
|
197
|
+
} catch (OutOfMemoryError e) {
|
|
198
|
+
// Bitmap.createBitmap() may cause OOM error
|
|
199
|
+
// Simply ignore and fallback
|
|
200
|
+
} finally {
|
|
201
|
+
if (!r) {
|
|
202
|
+
releaseBitmap();
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
protected void blur(Bitmap bitmapToBlur, Bitmap blurredBitmap) {
|
|
211
|
+
mBlurInput.copyFrom(bitmapToBlur);
|
|
212
|
+
mBlurScript.setInput(mBlurInput);
|
|
213
|
+
mBlurScript.forEach(mBlurOutput);
|
|
214
|
+
mBlurOutput.copyTo(blurredBitmap);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
|
|
218
|
+
@Override
|
|
219
|
+
public boolean onPreDraw() {
|
|
220
|
+
final int[] locations = new int[2];
|
|
221
|
+
Bitmap oldBmp = mBlurredBitmap;
|
|
222
|
+
View decor = mDecorView;
|
|
223
|
+
if (decor != null && isShown() && prepare()) {
|
|
224
|
+
boolean redrawBitmap = mBlurredBitmap != oldBmp;
|
|
225
|
+
oldBmp = null;
|
|
226
|
+
decor.getLocationOnScreen(locations);
|
|
227
|
+
int x = -locations[0];
|
|
228
|
+
int y = -locations[1];
|
|
229
|
+
|
|
230
|
+
getLocationOnScreen(locations);
|
|
231
|
+
x += locations[0];
|
|
232
|
+
y += locations[1];
|
|
233
|
+
|
|
234
|
+
// just erase transparent
|
|
235
|
+
mBitmapToBlur.eraseColor(mOverlayColor & 0xffffff);
|
|
236
|
+
|
|
237
|
+
int rc = mBlurringCanvas.save();
|
|
238
|
+
mIsRendering = true;
|
|
239
|
+
RENDERING_COUNT++;
|
|
240
|
+
try {
|
|
241
|
+
mBlurringCanvas.scale(1.f * mBitmapToBlur.getWidth() / getWidth(), 1.f * mBitmapToBlur.getHeight() / getHeight());
|
|
242
|
+
mBlurringCanvas.translate(-x, -y);
|
|
243
|
+
if (decor.getBackground() != null) {
|
|
244
|
+
decor.getBackground().draw(mBlurringCanvas);
|
|
245
|
+
}
|
|
246
|
+
decor.draw(mBlurringCanvas);
|
|
247
|
+
} catch (StopException e) {
|
|
248
|
+
} finally {
|
|
249
|
+
mIsRendering = false;
|
|
250
|
+
RENDERING_COUNT--;
|
|
251
|
+
mBlurringCanvas.restoreToCount(rc);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
blur(mBitmapToBlur, mBlurredBitmap);
|
|
255
|
+
|
|
256
|
+
if (redrawBitmap || mDifferentRoot) {
|
|
257
|
+
invalidate();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
protected View getActivityDecorView() {
|
|
266
|
+
Context ctx = getContext();
|
|
267
|
+
for (int i = 0; i < 4 && ctx != null && !(ctx instanceof Activity) && ctx instanceof ContextWrapper; i++) {
|
|
268
|
+
ctx = ((ContextWrapper) ctx).getBaseContext();
|
|
269
|
+
}
|
|
270
|
+
if (ctx instanceof Activity) {
|
|
271
|
+
return ((Activity) ctx).getWindow().getDecorView();
|
|
272
|
+
} else {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@Override
|
|
278
|
+
protected void onAttachedToWindow() {
|
|
279
|
+
super.onAttachedToWindow();
|
|
280
|
+
mDecorView = getActivityDecorView();
|
|
281
|
+
if (mDecorView != null) {
|
|
282
|
+
mDecorView.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
|
|
283
|
+
mDifferentRoot = mDecorView.getRootView() != getRootView();
|
|
284
|
+
if (mDifferentRoot) {
|
|
285
|
+
mDecorView.postInvalidate();
|
|
286
|
+
}
|
|
287
|
+
} else {
|
|
288
|
+
mDifferentRoot = false;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@Override
|
|
293
|
+
protected void onDetachedFromWindow() {
|
|
294
|
+
if (mDecorView != null) {
|
|
295
|
+
mDecorView.getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
|
296
|
+
}
|
|
297
|
+
release();
|
|
298
|
+
super.onDetachedFromWindow();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
@Override
|
|
302
|
+
public void draw(Canvas canvas) {
|
|
303
|
+
if (mIsRendering) {
|
|
304
|
+
// Quit here, don't draw views above me
|
|
305
|
+
throw STOP_EXCEPTION;
|
|
306
|
+
} else if (RENDERING_COUNT > 0) {
|
|
307
|
+
// Doesn't support blurview overlap on another blurview
|
|
308
|
+
} else {
|
|
309
|
+
super.draw(canvas);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@Override
|
|
314
|
+
protected void onDraw(Canvas canvas) {
|
|
315
|
+
super.onDraw(canvas);
|
|
316
|
+
drawBlurredBitmap(canvas, mBlurredBitmap, mOverlayColor);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Custom draw the blurred bitmap and color to define your own shape
|
|
321
|
+
*
|
|
322
|
+
* @param canvas
|
|
323
|
+
* @param blurredBitmap
|
|
324
|
+
* @param overlayColor
|
|
325
|
+
*/
|
|
326
|
+
protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap, int overlayColor) {
|
|
327
|
+
if (blurredBitmap != null) {
|
|
328
|
+
mRectSrc.right = blurredBitmap.getWidth();
|
|
329
|
+
mRectSrc.bottom = blurredBitmap.getHeight();
|
|
330
|
+
mRectDst.right = getWidth();
|
|
331
|
+
mRectDst.bottom = getHeight();
|
|
332
|
+
canvas.drawBitmap(blurredBitmap, mRectSrc, mRectDst, null);
|
|
333
|
+
}
|
|
334
|
+
canvas.drawColor(overlayColor);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private static class StopException extends RuntimeException {
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private static StopException STOP_EXCEPTION = new StopException();
|
|
341
|
+
|
|
342
|
+
static {
|
|
343
|
+
try {
|
|
344
|
+
RealtimeBlurView.class.getClassLoader().loadClass("android.renderscript.RenderScript");
|
|
345
|
+
} catch (ClassNotFoundException e) {
|
|
346
|
+
throw new RuntimeException("RenderScript support not enabled. Add \"android { defaultConfig { renderscriptSupportModeEnabled true }}\" in your build.gradle");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// android:debuggable="true" in AndroidManifest.xml (auto set by build tool)
|
|
351
|
+
static Boolean DEBUG = null;
|
|
352
|
+
|
|
353
|
+
static boolean isDebug(Context ctx) {
|
|
354
|
+
if (DEBUG == null && ctx != null) {
|
|
355
|
+
DEBUG = (ctx.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
|
356
|
+
}
|
|
357
|
+
return DEBUG == Boolean.TRUE;
|
|
358
|
+
}
|
|
359
|
+
}
|