├── .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 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190812184743393.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FmZWlfXw==,size_16,color_FFFFFF,t_70) 5 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190812184808331.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FmZWlfXw==,size_16,color_FFFFFF,t_70) 6 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190812184830104.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FmZWlfXw==,size_16,color_FFFFFF,t_70) 7 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190812184843212.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FmZWlfXw==,size_16,color_FFFFFF,t_70) 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 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 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 | --------------------------------------------------------------------------------