├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── afei
│ │ └── gpuimagedemo
│ │ ├── activity
│ │ ├── BaseActivity.java
│ │ ├── CameraActivity.java
│ │ ├── GalleryActivity.java
│ │ └── MainActivity.java
│ │ ├── camera
│ │ ├── Camera2Loader.java
│ │ └── CameraLoader.java
│ │ └── util
│ │ ├── FileUtils.java
│ │ ├── GPUImageFilterTools.java
│ │ └── ImageUtils.java
│ └── res
│ ├── drawable
│ └── item_ripple_bg.xml
│ ├── layout
│ ├── activity_camera.xml
│ ├── activity_gallery.xml
│ └── activity_main.xml
│ ├── mipmap-nodpi
│ └── lookup_amatorka.png
│ ├── mipmap-xxhdpi
│ ├── ic_camera.png
│ ├── ic_close.png
│ ├── ic_compare.png
│ ├── ic_gallery.png
│ ├── ic_launcher.png
│ ├── ic_ok.png
│ └── ic_switch_camera.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── raw
│ └── tone_cuver_sample.acv
│ ├── values-zh-rCN
│ └── strings.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/
38 |
39 | # Keystore files
40 | # Uncomment the following line if you do not want to check your keystore files in.
41 | #*.jks
42 |
43 | # External native build folder generated in Android Studio 2.2 and later
44 | .externalNativeBuild
45 |
46 | # Google Services (e.g. APIs or Firebase)
47 | google-services.json
48 |
49 | # Freeline
50 | freeline.py
51 | freeline/
52 | freeline_project_description.json
53 |
54 | # fastlane
55 | fastlane/report.xml
56 | fastlane/Preview.html
57 | fastlane/screenshots
58 | fastlane/test_output
59 | fastlane/readme.md
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GPUImageDemo
2 |
3 | ## 一、应用截图
4 | 
5 | 
6 | 
7 | 
8 |
9 | ## 二、前言
10 | GPUImage 是一个开源的图像渲染的库,使用它可以轻松实现很多滤镜效果,也可以很轻松的定义和实现自己特有的滤镜效果。
11 |
12 | 地址:[https://github.com/cats-oss/android-gpuimage](https://github.com/cats-oss/android-gpuimage)
13 |
14 | ## 三、依赖工程
15 | 要想使用 GPUImage,使用 Android Studio 只需要在 build.gradle 里面添加相关的依赖即可。
16 | ```
17 | implementation 'jp.co.cyberagent.android:gpuimage:2.0.3'
18 | ```
19 |
20 | ## 四、GPUImage 类介绍
21 | ### 1. 目录结构
22 |
23 | |--- filter : 这个包下面是各种滤镜效果类。
24 | |--- util : 这个包下面是一些工具类。
25 | |--- GLTextureView : 继承自 TextureView,和 GLSurfaceView 功能类似。
26 | |--- GPUImage : 核心实现类,配合 GLSurfaceView/GLTextureView 和 GPUImageFilter 实现渲染。
27 | |--- GPUImageNativeLibrary : 包含一些图片转码的 native 方法。
28 | |--- GPUImageRenderer : 实际的渲染者。
29 | |--- GPUImageView : 继承自 FrameLayout,封装了一个 GPUImage 和 GPUImageFilter,使用起来更方便。
30 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 34
5 | defaultConfig {
6 | applicationId "com.afei.gpuimagedemo"
7 | minSdkVersion 26
8 | targetSdkVersion 34
9 | versionCode 1
10 | versionName "1.0"
11 | }
12 | buildTypes {
13 | release {
14 | minifyEnabled false
15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
16 | }
17 | }
18 | compileOptions {
19 | sourceCompatibility JavaVersion.VERSION_1_8
20 | targetCompatibility JavaVersion.VERSION_1_8
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation 'androidx.appcompat:appcompat:1.6.0'
26 | implementation 'jp.co.cyberagent.android:gpuimage:2.1.0'
27 | }
28 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/activity/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.activity;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 |
5 | public class BaseActivity extends AppCompatActivity {
6 |
7 | public final String TAG = getClass().getSimpleName();
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/activity/CameraActivity.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.activity;
2 |
3 | import android.net.Uri;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 | import android.widget.SeekBar;
9 | import android.widget.TextView;
10 | import android.widget.Toast;
11 |
12 | import androidx.annotation.Nullable;
13 | import androidx.core.view.ViewCompat;
14 |
15 | import com.afei.gpuimagedemo.R;
16 | import com.afei.gpuimagedemo.camera.Camera2Loader;
17 | import com.afei.gpuimagedemo.camera.CameraLoader;
18 | import com.afei.gpuimagedemo.util.FileUtils;
19 | import com.afei.gpuimagedemo.util.GPUImageFilterTools;
20 | import com.afei.gpuimagedemo.util.GPUImageFilterTools.OnGpuImageFilterChosenListener;
21 |
22 | import jp.co.cyberagent.android.gpuimage.GPUImageView;
23 | import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
24 | import jp.co.cyberagent.android.gpuimage.util.Rotation;
25 |
26 | public class CameraActivity extends BaseActivity implements View.OnClickListener {
27 |
28 | private GPUImageView mGPUImageView;
29 | private SeekBar mSeekBar;
30 | private TextView mFilterNameTv;
31 |
32 | private GPUImageFilter mNoImageFilter = new GPUImageFilter();
33 | private GPUImageFilter mCurrentImageFilter = mNoImageFilter;
34 | private GPUImageFilterTools.FilterAdjuster mFilterAdjuster;
35 |
36 | private CameraLoader mCameraLoader;
37 |
38 | @Override
39 | protected void onCreate(@Nullable Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_camera);
42 | initView();
43 | initCamera();
44 | }
45 |
46 | private void initView() {
47 | mGPUImageView = findViewById(R.id.gpuimage);
48 | mSeekBar = findViewById(R.id.tone_seekbar);
49 | mFilterNameTv = findViewById(R.id.filter_name_tv);
50 | mFilterNameTv.setOnClickListener(this);
51 | mSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
52 | findViewById(R.id.compare_iv).setOnTouchListener(mOnTouchListener);
53 | findViewById(R.id.close_iv).setOnClickListener(this);
54 | findViewById(R.id.save_iv).setOnClickListener(this);
55 | findViewById(R.id.switch_camera_iv).setOnClickListener(this);
56 | }
57 |
58 | private void initCamera() {
59 | mCameraLoader = new Camera2Loader(this);
60 | mCameraLoader.setOnPreviewFrameListener(new CameraLoader.OnPreviewFrameListener() {
61 | @Override
62 | public void onPreviewFrame(byte[] data, int width, int height) {
63 | mGPUImageView.updatePreviewFrame(data, width, height);
64 | }
65 | });
66 | mGPUImageView.setRatio(0.75f); // 固定使用 4:3 的尺寸
67 | updateGPUImageRotate();
68 | mGPUImageView.setRenderMode(GPUImageView.RENDERMODE_CONTINUOUSLY);
69 | }
70 |
71 | private void updateGPUImageRotate() {
72 | Rotation rotation = getRotation(mCameraLoader.getCameraOrientation());
73 | boolean flipHorizontal = false;
74 | boolean flipVertical = false;
75 | if (mCameraLoader.isFrontCamera()) { // 前置摄像头需要镜像
76 | if (rotation == Rotation.NORMAL || rotation == Rotation.ROTATION_180) {
77 | flipHorizontal = true;
78 | } else {
79 | flipVertical = true;
80 | }
81 | }
82 | mGPUImageView.getGPUImage().setRotation(rotation, flipHorizontal, flipVertical);
83 | }
84 |
85 | @Override
86 | protected void onResume() {
87 | super.onResume();
88 | if (ViewCompat.isLaidOut(mGPUImageView) && !mGPUImageView.isLayoutRequested()) {
89 | mCameraLoader.onResume(mGPUImageView.getWidth(), mGPUImageView.getHeight());
90 | } else {
91 | mGPUImageView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
92 | @Override
93 | public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
94 | int oldRight, int oldBottom) {
95 | mGPUImageView.removeOnLayoutChangeListener(this);
96 | mCameraLoader.onResume(mGPUImageView.getWidth(), mGPUImageView.getHeight());
97 | }
98 | });
99 | }
100 | }
101 |
102 | @Override
103 | protected void onPause() {
104 | super.onPause();
105 | mCameraLoader.onPause();
106 | }
107 |
108 | @Override
109 | public void onClick(View v) {
110 | switch (v.getId()) {
111 | case R.id.filter_name_tv:
112 | GPUImageFilterTools.showDialog(this, mOnGpuImageFilterChosenListener);
113 | break;
114 | case R.id.close_iv:
115 | finish();
116 | break;
117 | case R.id.save_iv:
118 | saveSnapshot();
119 | break;
120 | case R.id.switch_camera_iv:
121 | mGPUImageView.getGPUImage().deleteImage();
122 | mCameraLoader.switchCamera();
123 | updateGPUImageRotate();
124 | break;
125 | }
126 | }
127 |
128 | private void saveSnapshot() {
129 | String fileName = System.currentTimeMillis() + ".jpg";
130 | mGPUImageView.saveToPictures("GPUImage", fileName, mOnPictureSavedListener);
131 | }
132 |
133 | private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
134 | @Override
135 | public boolean onTouch(View v, MotionEvent event) {
136 | if (v.getId() == R.id.compare_iv) {
137 | switch (event.getAction()) {
138 | case MotionEvent.ACTION_DOWN:
139 | mGPUImageView.setFilter(mNoImageFilter);
140 | break;
141 | case MotionEvent.ACTION_UP:
142 | mGPUImageView.setFilter(mCurrentImageFilter);
143 | break;
144 | }
145 | }
146 | return true;
147 | }
148 | };
149 |
150 | private OnGpuImageFilterChosenListener mOnGpuImageFilterChosenListener = new OnGpuImageFilterChosenListener() {
151 | @Override
152 | public void onGpuImageFilterChosenListener(GPUImageFilter filter, String filterName) {
153 | switchFilterTo(filter);
154 | mFilterNameTv.setText(filterName);
155 | }
156 | };
157 |
158 | private void switchFilterTo(GPUImageFilter filter) {
159 | if (mCurrentImageFilter == null
160 | || (filter != null && !mCurrentImageFilter.getClass().equals(filter.getClass()))) {
161 | mCurrentImageFilter = filter;
162 | mGPUImageView.setFilter(mCurrentImageFilter);
163 | mFilterAdjuster = new GPUImageFilterTools.FilterAdjuster(mCurrentImageFilter);
164 | mSeekBar.setVisibility(mFilterAdjuster.canAdjust() ? View.VISIBLE : View.GONE);
165 | } else {
166 | mSeekBar.setVisibility(View.GONE);
167 | }
168 | }
169 |
170 | private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
171 | @Override
172 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
173 | if (mFilterAdjuster != null) {
174 | mFilterAdjuster.adjust(progress);
175 | }
176 | mGPUImageView.requestRender();
177 | }
178 |
179 | @Override
180 | public void onStartTrackingTouch(SeekBar seekBar) {
181 | }
182 |
183 | @Override
184 | public void onStopTrackingTouch(SeekBar seekBar) {
185 | }
186 | };
187 |
188 | private GPUImageView.OnPictureSavedListener mOnPictureSavedListener = new GPUImageView.OnPictureSavedListener() {
189 | @Override
190 | public void onPictureSaved(Uri uri) {
191 | String filePath = FileUtils.getRealFilePath(CameraActivity.this, uri);
192 | Log.d(TAG, "save to " + filePath);
193 | Toast.makeText(CameraActivity.this, "Saved: " + filePath, Toast.LENGTH_SHORT).show();
194 | }
195 | };
196 |
197 | private Rotation getRotation(int orientation) {
198 | switch (orientation) {
199 | case 90:
200 | return Rotation.ROTATION_90;
201 | case 180:
202 | return Rotation.ROTATION_180;
203 | case 270:
204 | return Rotation.ROTATION_270;
205 | default:
206 | return Rotation.NORMAL;
207 | }
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/activity/GalleryActivity.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.activity;
2 |
3 | import android.graphics.Bitmap;
4 | import android.media.ExifInterface;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.provider.MediaStore;
8 | import android.util.Log;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 | import android.widget.SeekBar;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import androidx.activity.result.ActivityResultLauncher;
16 | import androidx.activity.result.contract.ActivityResultContracts;
17 | import androidx.annotation.Nullable;
18 |
19 | import com.afei.gpuimagedemo.R;
20 | import com.afei.gpuimagedemo.util.FileUtils;
21 | import com.afei.gpuimagedemo.util.GPUImageFilterTools;
22 | import com.afei.gpuimagedemo.util.GPUImageFilterTools.OnGpuImageFilterChosenListener;
23 | import com.afei.gpuimagedemo.util.ImageUtils;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 |
28 | import jp.co.cyberagent.android.gpuimage.GPUImageView;
29 | import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
30 |
31 | public class GalleryActivity extends BaseActivity implements View.OnClickListener {
32 |
33 | private GPUImageView mGPUImageView;
34 | private SeekBar mSeekBar;
35 | private TextView mFilterNameTv;
36 |
37 | private GPUImageFilter mNoImageFilter = new GPUImageFilter();
38 | private GPUImageFilter mCurrentImageFilter = mNoImageFilter;
39 | private GPUImageFilterTools.FilterAdjuster mFilterAdjuster;
40 |
41 | private ActivityResultLauncher mGalleryLauncher;
42 |
43 | @Override
44 | protected void onCreate(@Nullable Bundle savedInstanceState) {
45 | super.onCreate(savedInstanceState);
46 | setContentView(R.layout.activity_gallery);
47 | initView();
48 | openGallery();
49 | }
50 |
51 | private void initView() {
52 | mGPUImageView = findViewById(R.id.gpuimage);
53 | mSeekBar = findViewById(R.id.tone_seekbar);
54 | mFilterNameTv = findViewById(R.id.filter_name_tv);
55 | mGPUImageView.setOnClickListener(this);
56 | mFilterNameTv.setOnClickListener(this);
57 | mSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
58 | findViewById(R.id.compare_iv).setOnTouchListener(mOnTouchListener);
59 | findViewById(R.id.close_iv).setOnClickListener(this);
60 | findViewById(R.id.save_iv).setOnClickListener(this);
61 | mGalleryLauncher = registerForActivityResult(
62 | new ActivityResultContracts.GetContent(),
63 | this::handleGalleryResult);
64 | }
65 |
66 | @Override
67 | public void onClick(View v) {
68 | switch (v.getId()) {
69 | case R.id.gpuimage:
70 | openGallery();
71 | break;
72 | case R.id.filter_name_tv:
73 | GPUImageFilterTools.showDialog(this, mOnGpuImageFilterChosenListener);
74 | break;
75 | case R.id.close_iv:
76 | finish();
77 | break;
78 | case R.id.save_iv:
79 | saveImage();
80 | break;
81 | }
82 | }
83 |
84 | private void handleGalleryResult(Uri imageUri) {
85 | if (imageUri != null) {
86 | try {
87 | Log.w(TAG, "imageUri path: " + imageUri.getPath());
88 | Bitmap selectedBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
89 | Log.w(TAG, "selectedBitmap: " + selectedBitmap.getWidth() + ", " + selectedBitmap.getHeight());
90 | int rotation = ImageUtils.getRotation(this, imageUri);
91 | Bitmap rotatedBitmap = ImageUtils.rotateBitmap(selectedBitmap, rotation);
92 | Log.w(TAG, "rotatedBitmap: " + rotatedBitmap.getWidth() + ", " + rotatedBitmap.getHeight());
93 |
94 | mGPUImageView.setRatio(rotatedBitmap.getWidth() * 1f / rotatedBitmap.getHeight()); // 设置正确的比例才能更好的显示
95 | mGPUImageView.setImage(rotatedBitmap);
96 | mGPUImageView.setFilter(mCurrentImageFilter);
97 | } catch (IOException e) {
98 | throw new RuntimeException(e);
99 | }
100 | }
101 | }
102 |
103 | private void openGallery() {
104 | if (mGalleryLauncher != null) {
105 | mGalleryLauncher.launch("image/*");
106 | }
107 | }
108 |
109 | private void saveImage() {
110 | String fileName = System.currentTimeMillis() + ".jpg";
111 | mGPUImageView.saveToPictures("GPUImage", fileName, mOnPictureSavedListener);
112 | }
113 |
114 | private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
115 | @Override
116 | public boolean onTouch(View v, MotionEvent event) {
117 | if (v.getId() == R.id.compare_iv) {
118 | switch (event.getAction()) {
119 | case MotionEvent.ACTION_DOWN:
120 | mGPUImageView.setFilter(mNoImageFilter);
121 | break;
122 | case MotionEvent.ACTION_UP:
123 | mGPUImageView.setFilter(mCurrentImageFilter);
124 | break;
125 | }
126 | }
127 | return true;
128 | }
129 | };
130 |
131 | private OnGpuImageFilterChosenListener mOnGpuImageFilterChosenListener = new OnGpuImageFilterChosenListener() {
132 | @Override
133 | public void onGpuImageFilterChosenListener(GPUImageFilter filter, String filterName) {
134 | switchFilterTo(filter);
135 | mFilterNameTv.setText(filterName);
136 | }
137 | };
138 |
139 | private void switchFilterTo(GPUImageFilter filter) {
140 | if (mCurrentImageFilter == null
141 | || (filter != null && !mCurrentImageFilter.getClass().equals(filter.getClass()))) {
142 | mCurrentImageFilter = filter;
143 | mGPUImageView.setFilter(mCurrentImageFilter);
144 | mFilterAdjuster = new GPUImageFilterTools.FilterAdjuster(mCurrentImageFilter);
145 | mSeekBar.setVisibility(mFilterAdjuster.canAdjust() ? View.VISIBLE : View.GONE);
146 | } else {
147 | mSeekBar.setVisibility(View.GONE);
148 | }
149 | }
150 |
151 | private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
152 | @Override
153 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
154 | if (mFilterAdjuster != null) {
155 | mFilterAdjuster.adjust(progress);
156 | }
157 | mGPUImageView.requestRender();
158 | }
159 |
160 | @Override
161 | public void onStartTrackingTouch(SeekBar seekBar) {
162 | }
163 |
164 | @Override
165 | public void onStopTrackingTouch(SeekBar seekBar) {
166 | }
167 | };
168 |
169 | private GPUImageView.OnPictureSavedListener mOnPictureSavedListener = new GPUImageView.OnPictureSavedListener() {
170 | @Override
171 | public void onPictureSaved(Uri uri) {
172 | String filePath = FileUtils.getRealFilePath(GalleryActivity.this, uri);
173 | Log.d(TAG, "save to " + filePath);
174 | Toast.makeText(GalleryActivity.this, "Saved: " + filePath, Toast.LENGTH_SHORT).show();
175 | }
176 | };
177 | }
178 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.activity;
2 |
3 | import static android.content.pm.PackageManager.PERMISSION_GRANTED;
4 |
5 | import android.Manifest;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.provider.Settings;
10 | import android.view.View;
11 | import android.widget.Toast;
12 |
13 | import androidx.activity.result.contract.ActivityResultContracts;
14 | import androidx.annotation.NonNull;
15 | import androidx.core.app.ActivityCompat;
16 | import androidx.core.content.ContextCompat;
17 |
18 | import com.afei.gpuimagedemo.R;
19 |
20 | public class MainActivity extends BaseActivity implements View.OnClickListener{
21 |
22 | private static final int REQUEST_PERMISSION = 1;
23 | private final String[] PERMISSIONS = new String[] {
24 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
25 | Manifest.permission.CAMERA
26 | };
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_main);
32 | initView();
33 | checkPermission();
34 | }
35 |
36 | private void initView() {
37 | findViewById(R.id.camera_layout).setOnClickListener(this);
38 | findViewById(R.id.gallery_layout).setOnClickListener(this);
39 | }
40 |
41 | private boolean checkPermission() {
42 | for (int i = 0; i < PERMISSIONS.length; i++) {
43 | int state = ContextCompat.checkSelfPermission(this, PERMISSIONS[i]);
44 | if (state != PERMISSION_GRANTED) {
45 | ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION);
46 | return false;
47 | }
48 | }
49 | return true;
50 | }
51 |
52 | @Override
53 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
54 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
55 | if (requestCode == REQUEST_PERMISSION) {
56 | for (int i = 0; i < permissions.length; i++) {
57 | if (grantResults[i] != PERMISSION_GRANTED) {
58 | Toast.makeText(this, R.string.main_permission_hint, Toast.LENGTH_SHORT).show();
59 | Intent intent = new Intent();
60 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
61 | Uri uri = Uri.fromParts("package", getPackageName(), null);
62 | intent.setData(uri);
63 | registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
64 | if (result.getResultCode() == RESULT_OK) {
65 | checkPermission();
66 | }
67 | }).launch(intent);
68 | }
69 | }
70 | }
71 | }
72 |
73 | @Override
74 | public void onClick(View v) {
75 | switch (v.getId()) {
76 | case R.id.camera_layout:
77 | startActivity(new Intent(this, CameraActivity.class));
78 | break;
79 | case R.id.gallery_layout:
80 | startActivity(new Intent(this, GalleryActivity.class));
81 | break;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/camera/Camera2Loader.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.camera;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.graphics.ImageFormat;
7 | import android.hardware.camera2.CameraAccessException;
8 | import android.hardware.camera2.CameraCaptureSession;
9 | import android.hardware.camera2.CameraCharacteristics;
10 | import android.hardware.camera2.CameraDevice;
11 | import android.hardware.camera2.CameraManager;
12 | import android.hardware.camera2.CaptureRequest;
13 | import android.hardware.camera2.params.StreamConfigurationMap;
14 | import android.media.Image;
15 | import android.media.ImageReader;
16 | import android.util.Log;
17 | import android.util.Size;
18 | import android.view.Surface;
19 |
20 | import androidx.annotation.NonNull;
21 |
22 | import com.afei.gpuimagedemo.util.ImageUtils;
23 |
24 | import java.util.Arrays;
25 |
26 | public class Camera2Loader extends CameraLoader {
27 |
28 | private static final String TAG = "Camera2Loader";
29 |
30 | private Activity mActivity;
31 |
32 | private CameraManager mCameraManager;
33 | private CameraCharacteristics mCharacteristics;
34 | private CameraDevice mCameraDevice;
35 | private CameraCaptureSession mCaptureSession;
36 | private ImageReader mImageReader;
37 |
38 | private String mCameraId;
39 | private int mCameraFacing = CameraCharacteristics.LENS_FACING_BACK;
40 | private int mViewWidth;
41 | private int mViewHeight;
42 | private float mAspectRatio = 0.75f; // 4:3
43 |
44 | public Camera2Loader(Activity activity) {
45 | mActivity = activity;
46 | mCameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
47 | }
48 |
49 | @Override
50 | public void onResume(int width, int height) {
51 | mViewWidth = width;
52 | mViewHeight = height;
53 | setUpCamera();
54 | }
55 |
56 | @Override
57 | public void onPause() {
58 | releaseCamera();
59 | }
60 |
61 | @Override
62 | public void switchCamera() {
63 | mCameraFacing ^= 1;
64 | Log.d(TAG, "current camera facing is: " + mCameraFacing);
65 | releaseCamera();
66 | setUpCamera();
67 | }
68 |
69 | @Override
70 | public int getCameraOrientation() {
71 | int degrees = mActivity.getWindowManager().getDefaultDisplay().getRotation();
72 | switch (degrees) {
73 | case Surface.ROTATION_0:
74 | degrees = 0;
75 | break;
76 | case Surface.ROTATION_90:
77 | degrees = 90;
78 | break;
79 | case Surface.ROTATION_180:
80 | degrees = 180;
81 | break;
82 | case Surface.ROTATION_270:
83 | degrees = 270;
84 | break;
85 | default:
86 | degrees = 0;
87 | break;
88 | }
89 | int orientation = 0;
90 | try {
91 | String cameraId = getCameraId(mCameraFacing);
92 | CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
93 | orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
94 | } catch (CameraAccessException e) {
95 | e.printStackTrace();
96 | }
97 | Log.d(TAG, "degrees: " + degrees + ", orientation: " + orientation + ", mCameraFacing: " + mCameraFacing);
98 | if (mCameraFacing == CameraCharacteristics.LENS_FACING_FRONT) {
99 | return (orientation + degrees) % 360;
100 | } else {
101 | return (orientation - degrees) % 360;
102 | }
103 | }
104 |
105 | @Override
106 | public boolean hasMultipleCamera() {
107 | try {
108 | int size = mCameraManager.getCameraIdList().length;
109 | return size > 1;
110 | } catch (CameraAccessException e) {
111 | e.printStackTrace();
112 | }
113 | return false;
114 | }
115 |
116 | @Override
117 | public boolean isFrontCamera() {
118 | return mCameraFacing == CameraCharacteristics.LENS_FACING_FRONT;
119 | }
120 |
121 | @SuppressLint("MissingPermission")
122 | private void setUpCamera() {
123 | try {
124 | mCameraId = getCameraId(mCameraFacing);
125 | mCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
126 | mCameraManager.openCamera(mCameraId, mCameraDeviceCallback, null);
127 | } catch (CameraAccessException e) {
128 | Log.e(TAG, "Opening camera (ID: " + mCameraId + ") failed.");
129 | e.printStackTrace();
130 | }
131 | }
132 |
133 | private void releaseCamera() {
134 | if (mCaptureSession != null) {
135 | mCaptureSession.close();
136 | mCaptureSession = null;
137 | }
138 | if (mCameraDevice != null) {
139 | mCameraDevice.close();
140 | mCameraDevice = null;
141 | }
142 | if (mImageReader != null) {
143 | mImageReader.close();
144 | mImageReader = null;
145 | }
146 | }
147 |
148 | private String getCameraId(int facing) throws CameraAccessException {
149 | for (String cameraId : mCameraManager.getCameraIdList()) {
150 | if (mCameraManager.getCameraCharacteristics(cameraId).get(CameraCharacteristics.LENS_FACING) ==
151 | facing) {
152 | return cameraId;
153 | }
154 | }
155 | // default return
156 | return Integer.toString(facing);
157 | }
158 |
159 | private void startCaptureSession() {
160 | Size size = chooseOptimalSize();
161 | Log.d(TAG, "size: " + size.toString());
162 | mImageReader = ImageReader.newInstance(size.getWidth(), size.getHeight(), ImageFormat.YUV_420_888, 2);
163 | mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
164 | @Override
165 | public void onImageAvailable(ImageReader reader) {
166 | if (reader != null) {
167 | Image image = reader.acquireNextImage();
168 | if (image != null) {
169 | if (mOnPreviewFrameListener != null) {
170 | byte[] data = ImageUtils.generateNV21Data(image);
171 | mOnPreviewFrameListener.onPreviewFrame(data, image.getWidth(), image.getHeight());
172 | }
173 | image.close();
174 | }
175 | }
176 | }
177 | }, null);
178 |
179 | try {
180 | mCameraDevice.createCaptureSession(Arrays.asList(mImageReader.getSurface()), mCaptureStateCallback, null);
181 | } catch (CameraAccessException e) {
182 | e.printStackTrace();
183 | Log.e(TAG, "Failed to start camera session");
184 | }
185 | }
186 |
187 | private Size chooseOptimalSize() {
188 | Log.d(TAG, "viewWidth: " + mViewWidth + ", viewHeight: " + mViewHeight);
189 | if (mViewWidth == 0 || mViewHeight == 0) {
190 | return new Size(0, 0);
191 | }
192 | StreamConfigurationMap map = mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
193 | Size[] sizes = map.getOutputSizes(ImageFormat.YUV_420_888);
194 | int orientation = getCameraOrientation();
195 | boolean swapRotation = orientation == 90 || orientation == 270;
196 | int width = swapRotation ? mViewHeight : mViewWidth;
197 | int height = swapRotation ? mViewWidth : mViewHeight;
198 | return getSuitableSize(sizes, width, height, mAspectRatio);
199 | }
200 |
201 | private Size getSuitableSize(Size[] sizes, int width, int height, float aspectRatio) {
202 | int minDelta = Integer.MAX_VALUE;
203 | int index = 0;
204 | Log.d(TAG, "getSuitableSize. aspectRatio: " + aspectRatio);
205 | for (int i = 0; i < sizes.length; i++) {
206 | Size size = sizes[i];
207 | // 先判断比例是否相等
208 | if (size.getWidth() * aspectRatio == size.getHeight()) {
209 | int delta = Math.abs(width - size.getWidth());
210 | if (delta == 0) {
211 | return size;
212 | }
213 | if (minDelta > delta) {
214 | minDelta = delta;
215 | index = i;
216 | }
217 | }
218 | }
219 | return sizes[index];
220 | }
221 |
222 | private CameraDevice.StateCallback mCameraDeviceCallback = new CameraDevice.StateCallback() {
223 | @Override
224 | public void onOpened(@NonNull CameraDevice camera) {
225 | mCameraDevice = camera;
226 | startCaptureSession();
227 | }
228 |
229 | @Override
230 | public void onDisconnected(@NonNull CameraDevice camera) {
231 | mCameraDevice.close();
232 | mCameraDevice = null;
233 | }
234 |
235 | @Override
236 | public void onError(@NonNull CameraDevice camera, int error) {
237 | mCameraDevice.close();
238 | mCameraDevice = null;
239 | }
240 | };
241 |
242 | private CameraCaptureSession.StateCallback mCaptureStateCallback = new CameraCaptureSession.StateCallback() {
243 | @Override
244 | public void onConfigured(@NonNull CameraCaptureSession session) {
245 | if (mCameraDevice == null) {
246 | return;
247 | }
248 | mCaptureSession = session;
249 | try {
250 | CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
251 | builder.addTarget(mImageReader.getSurface());
252 | builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
253 | builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
254 | session.setRepeatingRequest(builder.build(), null, null);
255 | } catch (CameraAccessException e) {
256 | e.printStackTrace();
257 | }
258 | }
259 |
260 | @Override
261 | public void onConfigureFailed(@NonNull CameraCaptureSession session) {
262 | Log.e(TAG, "Failed to configure capture session.");
263 | }
264 | };
265 |
266 | }
267 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/camera/CameraLoader.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.camera;
2 |
3 | public abstract class CameraLoader {
4 |
5 | protected OnPreviewFrameListener mOnPreviewFrameListener;
6 |
7 | public abstract void onResume(int width, int height);
8 |
9 | public abstract void onPause();
10 |
11 | public abstract void switchCamera();
12 |
13 | public abstract int getCameraOrientation();
14 |
15 | public abstract boolean hasMultipleCamera();
16 |
17 | public abstract boolean isFrontCamera();
18 |
19 | public void setOnPreviewFrameListener(OnPreviewFrameListener onPreviewFrameListener) {
20 | mOnPreviewFrameListener = onPreviewFrameListener;
21 | }
22 |
23 | public interface OnPreviewFrameListener {
24 | void onPreviewFrame(byte[] data, int width, int height);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/util/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.util;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.net.Uri;
7 | import android.provider.MediaStore;
8 |
9 | public class FileUtils {
10 |
11 | public static String getRealFilePath(final Context context, final Uri uri) {
12 | final String scheme = uri.getScheme();
13 | String data = null;
14 | if (scheme == null)
15 | data = uri.getPath();
16 | else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
17 | data = uri.getPath();
18 | } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
19 | Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns
20 | .DATA}, null, null, null);
21 | if (null != cursor) {
22 | if (cursor.moveToFirst()) {
23 | int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
24 | if (index > -1) {
25 | data = cursor.getString(index);
26 | }
27 | }
28 | cursor.close();
29 | }
30 | }
31 | return data;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/util/GPUImageFilterTools.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 CyberAgent
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.afei.gpuimagedemo.util;
18 |
19 | import android.app.AlertDialog;
20 | import android.content.Context;
21 | import android.content.DialogInterface;
22 | import android.graphics.BitmapFactory;
23 | import android.graphics.PointF;
24 | import android.opengl.Matrix;
25 |
26 | import com.afei.gpuimagedemo.R;
27 |
28 | import jp.co.cyberagent.android.gpuimage.filter.*;
29 |
30 | import java.util.LinkedList;
31 | import java.util.List;
32 |
33 | public class GPUImageFilterTools {
34 | public static void showDialog(final Context context,
35 | final OnGpuImageFilterChosenListener listener) {
36 | final FilterList filters = new FilterList();
37 | filters.addFilter(context.getString(R.string.contrast), FilterType.CONTRAST);
38 | filters.addFilter(context.getString(R.string.invert), FilterType.INVERT);
39 | filters.addFilter(context.getString(R.string.pixelation), FilterType.PIXELATION);
40 | filters.addFilter(context.getString(R.string.hue), FilterType.HUE);
41 | filters.addFilter(context.getString(R.string.gamma), FilterType.GAMMA);
42 | filters.addFilter(context.getString(R.string.brightness), FilterType.BRIGHTNESS);
43 | filters.addFilter(context.getString(R.string.sepia), FilterType.SEPIA);
44 | filters.addFilter(context.getString(R.string.grayscale), FilterType.GRAYSCALE);
45 | filters.addFilter(context.getString(R.string.sharpness), FilterType.SHARPEN);
46 | filters.addFilter(context.getString(R.string.sobel_edge_detection), FilterType.SOBEL_EDGE_DETECTION);
47 | filters.addFilter(context.getString(R.string.convolution_3x3), FilterType.THREE_X_THREE_CONVOLUTION);
48 | filters.addFilter(context.getString(R.string.emboss), FilterType.EMBOSS);
49 | filters.addFilter(context.getString(R.string.posterize), FilterType.POSTERIZE);
50 | filters.addFilter(context.getString(R.string.grouped_filters), FilterType.FILTER_GROUP);
51 | filters.addFilter(context.getString(R.string.saturation), FilterType.SATURATION);
52 | filters.addFilter(context.getString(R.string.exposure), FilterType.EXPOSURE);
53 | filters.addFilter(context.getString(R.string.highlight_shadow), FilterType.HIGHLIGHT_SHADOW);
54 | filters.addFilter(context.getString(R.string.monochrome), FilterType.MONOCHROME);
55 | filters.addFilter(context.getString(R.string.opacity), FilterType.OPACITY);
56 | filters.addFilter(context.getString(R.string.rgb), FilterType.RGB);
57 | filters.addFilter(context.getString(R.string.white_balance), FilterType.WHITE_BALANCE);
58 | filters.addFilter(context.getString(R.string.vignette), FilterType.VIGNETTE);
59 | filters.addFilter(context.getString(R.string.tone_curve), FilterType.TONE_CURVE);
60 |
61 | filters.addFilter(context.getString(R.string.blend_difference), FilterType.BLEND_DIFFERENCE);
62 | filters.addFilter(context.getString(R.string.blend_source_over), FilterType.BLEND_SOURCE_OVER);
63 | filters.addFilter(context.getString(R.string.blend_color_burn), FilterType.BLEND_COLOR_BURN);
64 | filters.addFilter(context.getString(R.string.blend_color_dodge), FilterType.BLEND_COLOR_DODGE);
65 | filters.addFilter(context.getString(R.string.blend_darken), FilterType.BLEND_DARKEN);
66 | filters.addFilter(context.getString(R.string.blend_dissolve), FilterType.BLEND_DISSOLVE);
67 | filters.addFilter(context.getString(R.string.blend_exclusion), FilterType.BLEND_EXCLUSION);
68 | filters.addFilter(context.getString(R.string.blend_hard_light), FilterType.BLEND_HARD_LIGHT);
69 | filters.addFilter(context.getString(R.string.blend_lighten), FilterType.BLEND_LIGHTEN);
70 | filters.addFilter(context.getString(R.string.blend_add), FilterType.BLEND_ADD);
71 | filters.addFilter(context.getString(R.string.blend_divide), FilterType.BLEND_DIVIDE);
72 | filters.addFilter(context.getString(R.string.blend_multiply), FilterType.BLEND_MULTIPLY);
73 | filters.addFilter(context.getString(R.string.blend_overlay), FilterType.BLEND_OVERLAY);
74 | filters.addFilter(context.getString(R.string.blend_screen), FilterType.BLEND_SCREEN);
75 | filters.addFilter(context.getString(R.string.blend_alpha), FilterType.BLEND_ALPHA);
76 | filters.addFilter(context.getString(R.string.blend_color), FilterType.BLEND_COLOR);
77 | filters.addFilter(context.getString(R.string.blend_hue), FilterType.BLEND_HUE);
78 | filters.addFilter(context.getString(R.string.blend_saturation), FilterType.BLEND_SATURATION);
79 | filters.addFilter(context.getString(R.string.blend_luminosity), FilterType.BLEND_LUMINOSITY);
80 | filters.addFilter(context.getString(R.string.blend_linear_burn), FilterType.BLEND_LINEAR_BURN);
81 | filters.addFilter(context.getString(R.string.blend_soft_light), FilterType.BLEND_SOFT_LIGHT);
82 | filters.addFilter(context.getString(R.string.blend_subtract), FilterType.BLEND_SUBTRACT);
83 | filters.addFilter(context.getString(R.string.blend_chroma_key), FilterType.BLEND_CHROMA_KEY);
84 | filters.addFilter(context.getString(R.string.blend_normal), FilterType.BLEND_NORMAL);
85 |
86 | filters.addFilter(context.getString(R.string.lookup_amatorka), FilterType.LOOKUP_AMATORKA);
87 | filters.addFilter(context.getString(R.string.gaussian_blur), FilterType.GAUSSIAN_BLUR);
88 | filters.addFilter(context.getString(R.string.crosshatch), FilterType.CROSSHATCH);
89 |
90 | filters.addFilter(context.getString(R.string.box_blur), FilterType.BOX_BLUR);
91 | filters.addFilter(context.getString(R.string.cga_color_space), FilterType.CGA_COLORSPACE);
92 | filters.addFilter(context.getString(R.string.dilation), FilterType.DILATION);
93 | filters.addFilter(context.getString(R.string.kuwahara), FilterType.KUWAHARA);
94 | filters.addFilter(context.getString(R.string.rgb_dilation), FilterType.RGB_DILATION);
95 | filters.addFilter(context.getString(R.string.sketch), FilterType.SKETCH);
96 | filters.addFilter(context.getString(R.string.toon), FilterType.TOON);
97 | filters.addFilter(context.getString(R.string.smooth_toon), FilterType.SMOOTH_TOON);
98 | filters.addFilter(context.getString(R.string.halftone), FilterType.HALFTONE);
99 |
100 | filters.addFilter(context.getString(R.string.bulge_distortion), FilterType.BULGE_DISTORTION);
101 | filters.addFilter(context.getString(R.string.glass_sphere), FilterType.GLASS_SPHERE);
102 | filters.addFilter(context.getString(R.string.haze), FilterType.HAZE);
103 | filters.addFilter(context.getString(R.string.laplacian), FilterType.LAPLACIAN);
104 | filters.addFilter(context.getString(R.string.non_maximum_suppression), FilterType.NON_MAXIMUM_SUPPRESSION);
105 | filters.addFilter(context.getString(R.string.sphere_refraction), FilterType.SPHERE_REFRACTION);
106 | filters.addFilter(context.getString(R.string.swirl), FilterType.SWIRL);
107 | filters.addFilter(context.getString(R.string.weak_pixel_inclusion), FilterType.WEAK_PIXEL_INCLUSION);
108 | filters.addFilter(context.getString(R.string.false_color), FilterType.FALSE_COLOR);
109 |
110 | filters.addFilter(context.getString(R.string.color_balance), FilterType.COLOR_BALANCE);
111 |
112 | filters.addFilter(context.getString(R.string.levels_min_mid_adjust), FilterType.LEVELS_FILTER_MIN);
113 |
114 | filters. addFilter(context.getString(R.string.bilateral_blur), FilterType.BILATERAL_BLUR);
115 |
116 | filters.addFilter(context.getString(R.string.transform_2d), FilterType.TRANSFORM2D);
117 |
118 |
119 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
120 | builder.setTitle(context.getString(R.string.choose_filter));
121 | builder.setItems(filters.names.toArray(new String[filters.names.size()]),
122 | new DialogInterface.OnClickListener() {
123 | @Override
124 | public void onClick(final DialogInterface dialog, final int item) {
125 | listener.onGpuImageFilterChosenListener(
126 | createFilterForType(context, filters.filters.get(item)), filters.names.get(item));
127 | }
128 | });
129 | builder.create().show();
130 | }
131 |
132 | private static GPUImageFilter createFilterForType(final Context context, final FilterType type) {
133 | switch (type) {
134 | case CONTRAST:
135 | return new GPUImageContrastFilter(2.0f);
136 | case GAMMA:
137 | return new GPUImageGammaFilter(2.0f);
138 | case INVERT:
139 | return new GPUImageColorInvertFilter();
140 | case PIXELATION:
141 | return new GPUImagePixelationFilter();
142 | case HUE:
143 | return new GPUImageHueFilter(90.0f);
144 | case BRIGHTNESS:
145 | return new GPUImageBrightnessFilter(1.5f);
146 | case GRAYSCALE:
147 | return new GPUImageGrayscaleFilter();
148 | case SEPIA:
149 | return new GPUImageSepiaToneFilter();
150 | case SHARPEN:
151 | GPUImageSharpenFilter sharpness = new GPUImageSharpenFilter();
152 | sharpness.setSharpness(2.0f);
153 | return sharpness;
154 | case SOBEL_EDGE_DETECTION:
155 | return new GPUImageThresholdEdgeDetectionFilter();
156 | case THREE_X_THREE_CONVOLUTION:
157 | GPUImage3x3ConvolutionFilter convolution = new GPUImage3x3ConvolutionFilter();
158 | convolution.setConvolutionKernel(new float[] {
159 | -1.0f, 0.0f, 1.0f,
160 | -2.0f, 0.0f, 2.0f,
161 | -1.0f, 0.0f, 1.0f
162 | });
163 | return convolution;
164 | case EMBOSS:
165 | return new GPUImageEmbossFilter();
166 | case POSTERIZE:
167 | return new GPUImagePosterizeFilter();
168 | case FILTER_GROUP:
169 | List filters = new LinkedList();
170 | filters.add(new GPUImageContrastFilter());
171 | filters.add(new GPUImageDirectionalSobelEdgeDetectionFilter());
172 | filters.add(new GPUImageGrayscaleFilter());
173 | return new GPUImageFilterGroup(filters);
174 | case SATURATION:
175 | return new GPUImageSaturationFilter(1.0f);
176 | case EXPOSURE:
177 | return new GPUImageExposureFilter(0.0f);
178 | case HIGHLIGHT_SHADOW:
179 | return new GPUImageHighlightShadowFilter(0.0f, 1.0f);
180 | case MONOCHROME:
181 | return new GPUImageMonochromeFilter(1.0f, new float[]{0.6f, 0.45f, 0.3f, 1.0f});
182 | case OPACITY:
183 | return new GPUImageOpacityFilter(1.0f);
184 | case RGB:
185 | return new GPUImageRGBFilter(1.0f, 1.0f, 1.0f);
186 | case WHITE_BALANCE:
187 | return new GPUImageWhiteBalanceFilter(5000.0f, 0.0f);
188 | case VIGNETTE:
189 | PointF centerPoint = new PointF();
190 | centerPoint.x = 0.5f;
191 | centerPoint.y = 0.5f;
192 | return new GPUImageVignetteFilter(centerPoint, new float[] {0.0f, 0.0f, 0.0f}, 0.3f, 0.75f);
193 | case TONE_CURVE:
194 | GPUImageToneCurveFilter toneCurveFilter = new GPUImageToneCurveFilter();
195 | toneCurveFilter.setFromCurveFileInputStream(
196 | context.getResources().openRawResource(R.raw.tone_cuver_sample));
197 | return toneCurveFilter;
198 | case BLEND_DIFFERENCE:
199 | return createBlendFilter(context, GPUImageDifferenceBlendFilter.class);
200 | case BLEND_SOURCE_OVER:
201 | return createBlendFilter(context, GPUImageSourceOverBlendFilter.class);
202 | case BLEND_COLOR_BURN:
203 | return createBlendFilter(context, GPUImageColorBurnBlendFilter.class);
204 | case BLEND_COLOR_DODGE:
205 | return createBlendFilter(context, GPUImageColorDodgeBlendFilter.class);
206 | case BLEND_DARKEN:
207 | return createBlendFilter(context, GPUImageDarkenBlendFilter.class);
208 | case BLEND_DISSOLVE:
209 | return createBlendFilter(context, GPUImageDissolveBlendFilter.class);
210 | case BLEND_EXCLUSION:
211 | return createBlendFilter(context, GPUImageExclusionBlendFilter.class);
212 |
213 |
214 | case BLEND_HARD_LIGHT:
215 | return createBlendFilter(context, GPUImageHardLightBlendFilter.class);
216 | case BLEND_LIGHTEN:
217 | return createBlendFilter(context, GPUImageLightenBlendFilter.class);
218 | case BLEND_ADD:
219 | return createBlendFilter(context, GPUImageAddBlendFilter.class);
220 | case BLEND_DIVIDE:
221 | return createBlendFilter(context, GPUImageDivideBlendFilter.class);
222 | case BLEND_MULTIPLY:
223 | return createBlendFilter(context, GPUImageMultiplyBlendFilter.class);
224 | case BLEND_OVERLAY:
225 | return createBlendFilter(context, GPUImageOverlayBlendFilter.class);
226 | case BLEND_SCREEN:
227 | return createBlendFilter(context, GPUImageScreenBlendFilter.class);
228 | case BLEND_ALPHA:
229 | return createBlendFilter(context, GPUImageAlphaBlendFilter.class);
230 | case BLEND_COLOR:
231 | return createBlendFilter(context, GPUImageColorBlendFilter.class);
232 | case BLEND_HUE:
233 | return createBlendFilter(context, GPUImageHueBlendFilter.class);
234 | case BLEND_SATURATION:
235 | return createBlendFilter(context, GPUImageSaturationBlendFilter.class);
236 | case BLEND_LUMINOSITY:
237 | return createBlendFilter(context, GPUImageLuminosityBlendFilter.class);
238 | case BLEND_LINEAR_BURN:
239 | return createBlendFilter(context, GPUImageLinearBurnBlendFilter.class);
240 | case BLEND_SOFT_LIGHT:
241 | return createBlendFilter(context, GPUImageSoftLightBlendFilter.class);
242 | case BLEND_SUBTRACT:
243 | return createBlendFilter(context, GPUImageSubtractBlendFilter.class);
244 | case BLEND_CHROMA_KEY:
245 | return createBlendFilter(context, GPUImageChromaKeyBlendFilter.class);
246 | case BLEND_NORMAL:
247 | return createBlendFilter(context, GPUImageNormalBlendFilter.class);
248 |
249 | case LOOKUP_AMATORKA:
250 | GPUImageLookupFilter amatorka = new GPUImageLookupFilter();
251 | amatorka.setBitmap(BitmapFactory.decodeResource(context.getResources(), R.mipmap.lookup_amatorka));
252 | return amatorka;
253 | case GAUSSIAN_BLUR:
254 | return new GPUImageGaussianBlurFilter();
255 | case CROSSHATCH:
256 | return new GPUImageCrosshatchFilter();
257 |
258 | case BOX_BLUR:
259 | return new GPUImageBoxBlurFilter();
260 | case CGA_COLORSPACE:
261 | return new GPUImageCGAColorspaceFilter();
262 | case DILATION:
263 | return new GPUImageDilationFilter();
264 | case KUWAHARA:
265 | return new GPUImageKuwaharaFilter();
266 | case RGB_DILATION:
267 | return new GPUImageRGBDilationFilter();
268 | case SKETCH:
269 | return new GPUImageSketchFilter();
270 | case TOON:
271 | return new GPUImageToonFilter();
272 | case SMOOTH_TOON:
273 | return new GPUImageSmoothToonFilter();
274 |
275 | case BULGE_DISTORTION:
276 | return new GPUImageBulgeDistortionFilter();
277 | case GLASS_SPHERE:
278 | return new GPUImageGlassSphereFilter();
279 | case HAZE:
280 | return new GPUImageHazeFilter();
281 | case LAPLACIAN:
282 | return new GPUImageLaplacianFilter();
283 | case NON_MAXIMUM_SUPPRESSION:
284 | return new GPUImageNonMaximumSuppressionFilter();
285 | case SPHERE_REFRACTION:
286 | return new GPUImageSphereRefractionFilter();
287 | case SWIRL:
288 | return new GPUImageSwirlFilter();
289 | case WEAK_PIXEL_INCLUSION:
290 | return new GPUImageWeakPixelInclusionFilter();
291 | case FALSE_COLOR:
292 | return new GPUImageFalseColorFilter();
293 | case COLOR_BALANCE:
294 | return new GPUImageColorBalanceFilter();
295 | case LEVELS_FILTER_MIN:
296 | GPUImageLevelsFilter levelsFilter = new GPUImageLevelsFilter();
297 | levelsFilter.setMin(0.0f, 3.0f, 1.0f);
298 | return levelsFilter;
299 | case HALFTONE:
300 | return new GPUImageHalftoneFilter();
301 |
302 | case BILATERAL_BLUR:
303 | return new GPUImageBilateralBlurFilter();
304 |
305 | case TRANSFORM2D:
306 | return new GPUImageTransformFilter();
307 |
308 | default:
309 | throw new IllegalStateException("No filter of that type!");
310 | }
311 |
312 | }
313 |
314 | private static GPUImageFilter createBlendFilter(Context context, Class extends GPUImageTwoInputFilter> filterClass) {
315 | try {
316 | GPUImageTwoInputFilter filter = filterClass.newInstance();
317 | filter.setBitmap(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher));
318 | return filter;
319 | } catch (Exception e) {
320 | e.printStackTrace();
321 | return null;
322 | }
323 | }
324 |
325 | public interface OnGpuImageFilterChosenListener {
326 | void onGpuImageFilterChosenListener(GPUImageFilter filter, String filterName);
327 | }
328 |
329 | private enum FilterType {
330 | CONTRAST, GRAYSCALE, SHARPEN, SEPIA, SOBEL_EDGE_DETECTION, THREE_X_THREE_CONVOLUTION, FILTER_GROUP, EMBOSS, POSTERIZE, GAMMA, BRIGHTNESS, INVERT, HUE, PIXELATION,
331 | SATURATION, EXPOSURE, HIGHLIGHT_SHADOW, MONOCHROME, OPACITY, RGB, WHITE_BALANCE, VIGNETTE, TONE_CURVE, BLEND_COLOR_BURN, BLEND_COLOR_DODGE, BLEND_DARKEN, BLEND_DIFFERENCE,
332 | BLEND_DISSOLVE, BLEND_EXCLUSION, BLEND_SOURCE_OVER, BLEND_HARD_LIGHT, BLEND_LIGHTEN, BLEND_ADD, BLEND_DIVIDE, BLEND_MULTIPLY, BLEND_OVERLAY, BLEND_SCREEN, BLEND_ALPHA,
333 | BLEND_COLOR, BLEND_HUE, BLEND_SATURATION, BLEND_LUMINOSITY, BLEND_LINEAR_BURN, BLEND_SOFT_LIGHT, BLEND_SUBTRACT, BLEND_CHROMA_KEY, BLEND_NORMAL, LOOKUP_AMATORKA,
334 | GAUSSIAN_BLUR, CROSSHATCH, BOX_BLUR, CGA_COLORSPACE, DILATION, KUWAHARA, RGB_DILATION, SKETCH, TOON, SMOOTH_TOON, BULGE_DISTORTION, GLASS_SPHERE, HAZE, LAPLACIAN, NON_MAXIMUM_SUPPRESSION,
335 | SPHERE_REFRACTION, SWIRL, WEAK_PIXEL_INCLUSION, FALSE_COLOR, COLOR_BALANCE, LEVELS_FILTER_MIN, BILATERAL_BLUR, HALFTONE, TRANSFORM2D
336 | }
337 |
338 | private static class FilterList {
339 | public List names = new LinkedList();
340 | public List filters = new LinkedList();
341 |
342 | public void addFilter(final String name, final FilterType filter) {
343 | names.add(name);
344 | filters.add(filter);
345 | }
346 | }
347 |
348 | public static class FilterAdjuster {
349 | private final Adjuster extends GPUImageFilter> adjuster;
350 |
351 | public FilterAdjuster(final GPUImageFilter filter) {
352 | if (filter instanceof GPUImageSharpenFilter) {
353 | adjuster = new SharpnessAdjuster().filter(filter);
354 | } else if (filter instanceof GPUImageSepiaToneFilter) {
355 | adjuster = new SepiaAdjuster().filter(filter);
356 | } else if (filter instanceof GPUImageContrastFilter) {
357 | adjuster = new ContrastAdjuster().filter(filter);
358 | } else if (filter instanceof GPUImageGammaFilter) {
359 | adjuster = new GammaAdjuster().filter(filter);
360 | } else if (filter instanceof GPUImageBrightnessFilter) {
361 | adjuster = new BrightnessAdjuster().filter(filter);
362 | } else if (filter instanceof GPUImageThresholdEdgeDetectionFilter) {
363 | adjuster = new SobelAdjuster().filter(filter);
364 | } else if (filter instanceof GPUImageEmbossFilter) {
365 | adjuster = new EmbossAdjuster().filter(filter);
366 | } else if (filter instanceof GPUImage3x3TextureSamplingFilter) {
367 | adjuster = new GPU3x3TextureAdjuster().filter(filter);
368 | } else if (filter instanceof GPUImageHueFilter) {
369 | adjuster = new HueAdjuster().filter(filter);
370 | } else if (filter instanceof GPUImagePosterizeFilter) {
371 | adjuster = new PosterizeAdjuster().filter(filter);
372 | } else if (filter instanceof GPUImagePixelationFilter) {
373 | adjuster = new PixelationAdjuster().filter(filter);
374 | } else if (filter instanceof GPUImageSaturationFilter) {
375 | adjuster = new SaturationAdjuster().filter(filter);
376 | } else if (filter instanceof GPUImageExposureFilter) {
377 | adjuster = new ExposureAdjuster().filter(filter);
378 | } else if (filter instanceof GPUImageHighlightShadowFilter) {
379 | adjuster = new HighlightShadowAdjuster().filter(filter);
380 | } else if (filter instanceof GPUImageMonochromeFilter) {
381 | adjuster = new MonochromeAdjuster().filter(filter);
382 | } else if (filter instanceof GPUImageOpacityFilter) {
383 | adjuster = new OpacityAdjuster().filter(filter);
384 | } else if (filter instanceof GPUImageRGBFilter) {
385 | adjuster = new RGBAdjuster().filter(filter);
386 | } else if (filter instanceof GPUImageWhiteBalanceFilter) {
387 | adjuster = new WhiteBalanceAdjuster().filter(filter);
388 | } else if (filter instanceof GPUImageVignetteFilter) {
389 | adjuster = new VignetteAdjuster().filter(filter);
390 | } else if (filter instanceof GPUImageDissolveBlendFilter) {
391 | adjuster = new DissolveBlendAdjuster().filter(filter);
392 | } else if (filter instanceof GPUImageGaussianBlurFilter) {
393 | adjuster = new GaussianBlurAdjuster().filter(filter);
394 | } else if (filter instanceof GPUImageCrosshatchFilter) {
395 | adjuster = new CrosshatchBlurAdjuster().filter(filter);
396 | } else if (filter instanceof GPUImageBulgeDistortionFilter) {
397 | adjuster = new BulgeDistortionAdjuster().filter(filter);
398 | } else if (filter instanceof GPUImageGlassSphereFilter) {
399 | adjuster = new GlassSphereAdjuster().filter(filter);
400 | } else if (filter instanceof GPUImageHazeFilter) {
401 | adjuster = new HazeAdjuster().filter(filter);
402 | } else if (filter instanceof GPUImageSphereRefractionFilter) {
403 | adjuster = new SphereRefractionAdjuster().filter(filter);
404 | } else if (filter instanceof GPUImageSwirlFilter) {
405 | adjuster = new SwirlAdjuster().filter(filter);
406 | } else if (filter instanceof GPUImageColorBalanceFilter) {
407 | adjuster = new ColorBalanceAdjuster().filter(filter);
408 | } else if (filter instanceof GPUImageLevelsFilter) {
409 | adjuster = new LevelsMinMidAdjuster().filter(filter);
410 | } else if (filter instanceof GPUImageBilateralBlurFilter) {
411 | adjuster = new BilateralAdjuster().filter(filter);
412 | } else if (filter instanceof GPUImageTransformFilter) {
413 | adjuster = new RotateAdjuster().filter(filter);
414 | }
415 | else {
416 |
417 | adjuster = null;
418 | }
419 | }
420 |
421 | public boolean canAdjust() {
422 | return adjuster != null;
423 | }
424 |
425 | public void adjust(final int percentage) {
426 | if (adjuster != null) {
427 | adjuster.adjust(percentage);
428 | }
429 | }
430 |
431 | private abstract class Adjuster {
432 | private T filter;
433 |
434 | @SuppressWarnings("unchecked")
435 | public Adjuster filter(final GPUImageFilter filter) {
436 | this.filter = (T) filter;
437 | return this;
438 | }
439 |
440 | public T getFilter() {
441 | return filter;
442 | }
443 |
444 | public abstract void adjust(int percentage);
445 |
446 | protected float range(final int percentage, final float start, final float end) {
447 | return (end - start) * percentage / 100.0f + start;
448 | }
449 |
450 | protected int range(final int percentage, final int start, final int end) {
451 | return (end - start) * percentage / 100 + start;
452 | }
453 | }
454 |
455 | private class SharpnessAdjuster extends Adjuster {
456 | @Override
457 | public void adjust(final int percentage) {
458 | getFilter().setSharpness(range(percentage, -4.0f, 4.0f));
459 | }
460 | }
461 |
462 | private class PixelationAdjuster extends Adjuster {
463 | @Override
464 | public void adjust(final int percentage) {
465 | getFilter().setPixel(range(percentage, 1.0f, 100.0f));
466 | }
467 | }
468 |
469 | private class HueAdjuster extends Adjuster {
470 | @Override
471 | public void adjust(final int percentage) {
472 | getFilter().setHue(range(percentage, 0.0f, 360.0f));
473 | }
474 | }
475 |
476 | private class ContrastAdjuster extends Adjuster {
477 | @Override
478 | public void adjust(final int percentage) {
479 | getFilter().setContrast(range(percentage, 0.0f, 2.0f));
480 | }
481 | }
482 |
483 | private class GammaAdjuster extends Adjuster {
484 | @Override
485 | public void adjust(final int percentage) {
486 | getFilter().setGamma(range(percentage, 0.0f, 3.0f));
487 | }
488 | }
489 |
490 | private class BrightnessAdjuster extends Adjuster {
491 | @Override
492 | public void adjust(final int percentage) {
493 | getFilter().setBrightness(range(percentage, -1.0f, 1.0f));
494 | }
495 | }
496 |
497 | private class SepiaAdjuster extends Adjuster {
498 | @Override
499 | public void adjust(final int percentage) {
500 | getFilter().setIntensity(range(percentage, 0.0f, 2.0f));
501 | }
502 | }
503 |
504 | private class SobelAdjuster extends Adjuster {
505 | @Override
506 | public void adjust(final int percentage) {
507 | getFilter().setLineSize(range(percentage, 0.0f, 5.0f));
508 | }
509 | }
510 |
511 | private class EmbossAdjuster extends Adjuster {
512 | @Override
513 | public void adjust(final int percentage) {
514 | getFilter().setIntensity(range(percentage, 0.0f, 4.0f));
515 | }
516 | }
517 |
518 | private class PosterizeAdjuster extends Adjuster {
519 | @Override
520 | public void adjust(final int percentage) {
521 | // In theorie to 256, but only first 50 are interesting
522 | getFilter().setColorLevels(range(percentage, 1, 50));
523 | }
524 | }
525 |
526 | private class GPU3x3TextureAdjuster extends Adjuster {
527 | @Override
528 | public void adjust(final int percentage) {
529 | getFilter().setLineSize(range(percentage, 0.0f, 5.0f));
530 | }
531 | }
532 |
533 | private class SaturationAdjuster extends Adjuster {
534 | @Override
535 | public void adjust(final int percentage) {
536 | getFilter().setSaturation(range(percentage, 0.0f, 2.0f));
537 | }
538 | }
539 |
540 | private class ExposureAdjuster extends Adjuster {
541 | @Override
542 | public void adjust(final int percentage) {
543 | getFilter().setExposure(range(percentage, -10.0f, 10.0f));
544 | }
545 | }
546 |
547 | private class HighlightShadowAdjuster extends Adjuster {
548 | @Override
549 | public void adjust(final int percentage) {
550 | getFilter().setShadows(range(percentage, 0.0f, 1.0f));
551 | getFilter().setHighlights(range(percentage, 0.0f, 1.0f));
552 | }
553 | }
554 |
555 | private class MonochromeAdjuster extends Adjuster {
556 | @Override
557 | public void adjust(final int percentage) {
558 | getFilter().setIntensity(range(percentage, 0.0f, 1.0f));
559 | //getFilter().setColor(new float[]{0.6f, 0.45f, 0.3f, 1.0f});
560 | }
561 | }
562 |
563 | private class OpacityAdjuster extends Adjuster {
564 | @Override
565 | public void adjust(final int percentage) {
566 | getFilter().setOpacity(range(percentage, 0.0f, 1.0f));
567 | }
568 | }
569 |
570 | private class RGBAdjuster extends Adjuster {
571 | @Override
572 | public void adjust(final int percentage) {
573 | getFilter().setRed(range(percentage, 0.0f, 1.0f));
574 | //getFilter().setGreen(range(percentage, 0.0f, 1.0f));
575 | //getFilter().setBlue(range(percentage, 0.0f, 1.0f));
576 | }
577 | }
578 |
579 | private class WhiteBalanceAdjuster extends Adjuster {
580 | @Override
581 | public void adjust(final int percentage) {
582 | getFilter().setTemperature(range(percentage, 2000.0f, 8000.0f));
583 | //getFilter().setTint(range(percentage, -100.0f, 100.0f));
584 | }
585 | }
586 |
587 | private class VignetteAdjuster extends Adjuster {
588 | @Override
589 | public void adjust(final int percentage) {
590 | getFilter().setVignetteStart(range(percentage, 0.0f, 1.0f));
591 | }
592 | }
593 |
594 | private class DissolveBlendAdjuster extends Adjuster {
595 | @Override
596 | public void adjust(final int percentage) {
597 | getFilter().setMix(range(percentage, 0.0f, 1.0f));
598 | }
599 | }
600 |
601 | private class GaussianBlurAdjuster extends Adjuster {
602 | @Override
603 | public void adjust(final int percentage) {
604 | getFilter().setBlurSize(range(percentage, 0.0f, 1.0f));
605 | }
606 | }
607 |
608 | private class CrosshatchBlurAdjuster extends Adjuster {
609 | @Override
610 | public void adjust(final int percentage) {
611 | getFilter().setCrossHatchSpacing(range(percentage, 0.0f, 0.06f));
612 | getFilter().setLineWidth(range(percentage, 0.0f, 0.006f));
613 | }
614 | }
615 |
616 | private class BulgeDistortionAdjuster extends Adjuster {
617 | @Override
618 | public void adjust(final int percentage) {
619 | getFilter().setRadius(range(percentage, 0.0f, 1.0f));
620 | getFilter().setScale(range(percentage, -1.0f, 1.0f));
621 | }
622 | }
623 |
624 | private class GlassSphereAdjuster extends Adjuster {
625 | @Override
626 | public void adjust(final int percentage) {
627 | getFilter().setRadius(range(percentage, 0.0f, 1.0f));
628 | }
629 | }
630 |
631 | private class HazeAdjuster extends Adjuster {
632 | @Override
633 | public void adjust(final int percentage) {
634 | getFilter().setDistance(range(percentage, -0.3f, 0.3f));
635 | getFilter().setSlope(range(percentage, -0.3f, 0.3f));
636 | }
637 | }
638 |
639 | private class SphereRefractionAdjuster extends Adjuster {
640 | @Override
641 | public void adjust(final int percentage) {
642 | getFilter().setRadius(range(percentage, 0.0f, 1.0f));
643 | }
644 | }
645 |
646 | private class SwirlAdjuster extends Adjuster {
647 | @Override
648 | public void adjust(final int percentage) {
649 | getFilter().setAngle(range(percentage, 0.0f, 2.0f));
650 | }
651 | }
652 |
653 | private class ColorBalanceAdjuster extends Adjuster {
654 |
655 | @Override
656 | public void adjust(int percentage) {
657 | getFilter().setMidtones(new float[]{
658 | range(percentage, 0.0f, 1.0f),
659 | range(percentage / 2, 0.0f, 1.0f),
660 | range(percentage / 3, 0.0f, 1.0f)});
661 | }
662 | }
663 |
664 | private class LevelsMinMidAdjuster extends Adjuster {
665 | @Override
666 | public void adjust(int percentage) {
667 | getFilter().setMin(0.0f, range(percentage, 0.0f, 1.0f), 1.0f);
668 | }
669 | }
670 |
671 | private class BilateralAdjuster extends Adjuster {
672 | @Override
673 | public void adjust(final int percentage) {
674 | getFilter().setDistanceNormalizationFactor(range(percentage, 0.0f, 15.0f));
675 | }
676 | }
677 |
678 | private class RotateAdjuster extends Adjuster {
679 | @Override
680 | public void adjust(final int percentage) {
681 | float[] transform = new float[16];
682 | Matrix.setRotateM(transform, 0, 360 * percentage / 100, 0, 0, 1.0f);
683 | getFilter().setTransform3D(transform);
684 | }
685 | }
686 |
687 | }
688 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/afei/gpuimagedemo/util/ImageUtils.java:
--------------------------------------------------------------------------------
1 | package com.afei.gpuimagedemo.util;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.ImageFormat;
6 | import android.graphics.Matrix;
7 | import android.graphics.Rect;
8 | import android.media.ExifInterface;
9 | import android.media.Image;
10 | import android.net.Uri;
11 |
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.nio.ByteBuffer;
15 |
16 | public class ImageUtils {
17 |
18 | public static byte[] generateNV21Data(Image image) {
19 | Rect crop = image.getCropRect();
20 | int format = image.getFormat();
21 | int width = crop.width();
22 | int height = crop.height();
23 | Image.Plane[] planes = image.getPlanes();
24 | byte[] data = new byte[width * height * ImageFormat.getBitsPerPixel(format) / 8];
25 | byte[] rowData = new byte[planes[0].getRowStride()];
26 | int channelOffset = 0;
27 | int outputStride = 1;
28 | for (int i = 0; i < planes.length; i++) {
29 | switch (i) {
30 | case 0:
31 | channelOffset = 0;
32 | outputStride = 1;
33 | break;
34 | case 1:
35 | channelOffset = width * height + 1;
36 | outputStride = 2;
37 | break;
38 | case 2:
39 | channelOffset = width * height;
40 | outputStride = 2;
41 | break;
42 | }
43 | ByteBuffer buffer = planes[i].getBuffer();
44 | int rowStride = planes[i].getRowStride();
45 | int pixelStride = planes[i].getPixelStride();
46 | int shift = i == 0 ? 0 : 1;
47 | int w = width >> shift;
48 | int h = height >> shift;
49 | buffer.position(rowStride * (crop.top >> shift) + pixelStride * (crop.left >> shift));
50 | for (int row = 0; row < h; row++) {
51 | int length;
52 | if (pixelStride == 1 && outputStride == 1) {
53 | length = w;
54 | buffer.get(data, channelOffset, length);
55 | channelOffset += length;
56 | } else {
57 | length = (w - 1) * pixelStride + 1;
58 | buffer.get(rowData, 0, length);
59 | for (int col = 0; col < w; col++) {
60 | data[channelOffset] = rowData[col * pixelStride];
61 | channelOffset += outputStride;
62 | }
63 | }
64 | if (row < h - 1) {
65 | buffer.position(buffer.position() + rowStride - length);
66 | }
67 | }
68 | }
69 | return data;
70 | }
71 |
72 | public static Bitmap rotateBitmap(Bitmap bitmap, int rotation) {
73 | if (rotation == 0) {
74 | return bitmap;
75 | }
76 | return rotateResizeBitmap(bitmap, rotation, 1f);
77 | }
78 |
79 | public static Bitmap rotateResizeBitmap(Bitmap source, float angle, float scale) {
80 | Matrix matrix = new Matrix();
81 | matrix.postRotate(angle);
82 | if (scale != 1f) {
83 | matrix.setScale(scale, scale);
84 | }
85 | return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
86 | }
87 |
88 | public static int getRotation(Context context, Uri imageUri) {
89 | if (imageUri == null) {
90 | return 0;
91 | }
92 | ExifInterface ei;
93 | try {
94 | InputStream inputStream = context.getContentResolver().openInputStream(imageUri);
95 | ei = new ExifInterface(inputStream);
96 | } catch (IOException e) {
97 | return 0;
98 | }
99 | int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
100 | switch (orientation) {
101 | case ExifInterface.ORIENTATION_ROTATE_90:
102 | return 90;
103 | case ExifInterface.ORIENTATION_ROTATE_180:
104 | return 180;
105 | case ExifInterface.ORIENTATION_ROTATE_270:
106 | return 270;
107 | default:
108 | return 0;
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/item_ripple_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
19 |
20 |
26 |
27 |
34 |
35 |
42 |
43 |
44 |
45 |
49 |
50 |
55 |
56 |
65 |
66 |
67 |
68 |
74 |
75 |
83 |
84 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
21 |
22 |
27 |
28 |
37 |
38 |
39 |
45 |
46 |
52 |
53 |
62 |
63 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
27 |
28 |
32 |
33 |
39 |
40 |
41 |
52 |
53 |
57 |
58 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-nodpi/lookup_amatorka.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-nodpi/lookup_amatorka.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_close.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_compare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_compare.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_gallery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_gallery.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_ok.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_switch_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxhdpi/ic_switch_camera.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/tone_cuver_sample.acv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/app/src/main/res/raw/tone_cuver_sample.acv
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GPUImageDemo
3 |
4 |
5 | 相机
6 | 相册
7 | 请打开相关权限
8 |
9 |
10 | 选择滤镜
11 |
12 |
13 | 对比度
14 | 反相
15 | 像素化
16 | 色度
17 | 伽马
18 | 亮度
19 | 褐色(怀旧)
20 | 灰度
21 | 锐化
22 | Sobel边缘检测
23 | 3x3卷积
24 | 浮雕
25 | 色调分离
26 | 组合(对比度+灰度+Sobel边缘检测)
27 | 饱和度
28 | 曝光
29 | 提亮阴影
30 | 单色
31 | 不透明度
32 | RGB
33 | 白平衡
34 | 晕影
35 | 色调曲线
36 | 差异混合
37 | 源混合
38 | 色彩加深混合
39 | 色彩减淡混合
40 | 加深混合
41 | 溶解
42 | 排除混合
43 | 强光混合
44 | 减淡混合
45 | 加法混合
46 | 分割混合
47 | 正片叠底
48 | 叠加
49 | 屏幕包裹
50 | 透明混合
51 | 颜色混合
52 | 色度混合
53 | 饱和度混合
54 | 明度混合
55 | 线性加深
56 | 柔光
57 | 差值混合
58 | 色度键混合
59 | 正常混合
60 | 颜色查找表(Amatorka)
61 | 高斯模糊
62 | 交叉线阴影
63 | 盒状模糊
64 | CGA色彩滤镜
65 | 扩展边缘模糊,变黑白
66 | Kuwahara滤波
67 | RGB扩展边缘模糊,有色彩
68 | 素描
69 | 卡通
70 | 平滑卡通
71 | 点染
72 | 鱼眼
73 | 水晶球
74 | 薄雾
75 | 拉普拉斯变换
76 | 非最大抑制
77 | 球形折射
78 | 漩涡
79 | 弱像素包含
80 | 假色
81 | 颜色平衡
82 | 色阶
83 | 双边模糊
84 | 形状变化(2D)
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 | #000000
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GPUImageDemo
3 |
4 |
5 | Camera
6 | Gallery
7 | Please Open Permission
8 |
9 |
10 | Choose Filter
11 |
12 |
13 | Contrast
14 | Invert
15 | Pixelation
16 | Hue
17 | Gamma
18 | Brightness
19 | Sepia
20 | Grayscale
21 | Sharpness
22 | Sobel Edge Detection
23 | 3x3 Convolution
24 | Emboss
25 | Posterize
26 | Grouped filters
27 | Saturation
28 | Exposure
29 | Highlight Shadow
30 | Monochrome
31 | Opacity
32 | RGB
33 | White Balance
34 | Vignette
35 | ToneCurve
36 | Blend (Difference)
37 | Blend (Source Over)
38 | Blend (Color Burn)
39 | Blend (Color Dodge)
40 | Blend (Darken)
41 | Blend (Dissolve)
42 | Blend (Exclusion)
43 | Blend (Hard Light)
44 | Blend (Lighten)
45 | Blend (Add)
46 | Blend (Divide)
47 | Blend (Multiply)
48 | Blend (Overlay)
49 | Blend (Screen)
50 | Blend (Alpha)
51 | Blend (Color)
52 | Blend (Hue)
53 | Blend (Saturation)
54 | Blend (Luminosity)
55 | Blend (Linear Burn)
56 | Blend (Soft Light)
57 | Blend (Subtract)
58 | Blend (Chroma Key)
59 | Blend (Normal)
60 | Lookup (Amatorka)
61 | Gaussian Blur
62 | Crosshatch
63 | Box Blur
64 | CGA Color Space
65 | Dilation
66 | Kuwahara
67 | RGB Dilation
68 | Sketch
69 | Toon
70 | Smooth Toon
71 | Halftone
72 | Bulge Distortion
73 | Glass Sphere
74 | Haze
75 | Laplacian
76 | Non Maximum Suppression
77 | Sphere Refraction
78 | Swirl
79 | Weak Pixel Inclusion
80 | False Color
81 | Color Balance
82 | Levels Min (Mid Adjust)
83 | Bilateral Blur
84 | Transform (2-D)
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '7.4.1' apply false
4 | id 'com.android.library' version '7.4.1' apply false
5 | }
6 |
7 | task clean(type: Delete) {
8 | delete rootProject.buildDir
9 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afei-cn/GPUImageDemo/3b8a76abc83d7dbb5ec10e519a6808fdcec2a664/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jul 03 17:36:08 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "GPUImageDemo"
16 |
17 | include ':app'
18 |
--------------------------------------------------------------------------------