├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── LICENSE.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── z0kai │ │ └── filtercamera │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── 7_zidi.acv │ ├── java │ │ └── z0kai │ │ │ └── filtercamera │ │ │ ├── BitmapActivity.java │ │ │ ├── CameraActivity.java │ │ │ ├── CameraGLSurfaceView.java │ │ │ ├── CameraInstance.java │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ ├── activity_bitmap.xml │ │ ├── activity_camera.xml │ │ ├── activity_main.xml │ │ └── content_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── z_0kai_pet.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── z0kai │ └── filtercamera │ └── ExampleUnitTest.java ├── build.gradle ├── filterlib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── z0kai │ │ └── filterlib │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── z0kai │ │ │ └── filterlib │ │ │ ├── FilterRender.java │ │ │ ├── OpenGlUtils.java │ │ │ ├── PixelBuffer.java │ │ │ ├── RotationUtil.java │ │ │ └── filters │ │ │ ├── BaseFilter.java │ │ │ ├── BeautyFilter.java │ │ │ ├── ColorMatrixFilter.java │ │ │ ├── IFImageFilter.java │ │ │ ├── IFInkwellFilter.java │ │ │ ├── SepiaFilter.java │ │ │ ├── ToneCurveFilter.java │ │ │ └── VignetteFilter.java │ └── res │ │ ├── drawable │ │ └── inkwell_map.png │ │ ├── raw │ │ └── beautify_fragment.glsl │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── z0kai │ └── filterlib │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FilterCamera 2 | A library to filter image or camera for Android. 3 | 4 | This is an idea from [android-gpuimage](https://github.com/CyberAgent/android-gpuimage). 5 | # 6 | You can add an new Filter copy from #android-gpuimage# and then change to this project's style. 7 | # 8 | `remove the define of inputImageTexture in shader` 9 | 10 | #License 11 | 12 | Copyright 2016 0kai 13 | 14 | Licensed under the Apache License, Version 2.0 (the "License"); 15 | you may not use this file except in compliance with the License. 16 | You may obtain a copy of the License at 17 | 18 | http://www.apache.org/licenses/LICENSE-2.0 19 | 20 | Unless required by applicable law or agreed to in writing, software 21 | distributed under the License is distributed on an "AS IS" BASIS, 22 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | See the License for the specific language governing permissions and 24 | limitations under the License. 25 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.neenbedankt.android-apt' 3 | 4 | android { 5 | compileSdkVersion 24 6 | buildToolsVersion "24.0.0" 7 | defaultConfig { 8 | applicationId "z0kai.filtercamera" 9 | minSdkVersion 15 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(include: ['*.jar'], dir: 'libs') 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile project(':filterlib') 29 | 30 | 31 | compile 'com.android.support:appcompat-v7:24.0.0' 32 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha3' 33 | compile 'com.android.support:design:24.0.0' 34 | compile 'com.jakewharton:butterknife:8.1.0' 35 | testCompile 'junit:junit:4.12' 36 | apt 'com.jakewharton:butterknife-compiler:8.1.0' 37 | } 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\AndroidSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/z0kai/filtercamera/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package z0kai.filtercamera; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("z0kai.filtercamera", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/assets/7_zidi.acv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0kai/FilterCamera/c378de81e5bda00835e24a9147b697bd7d30122a/app/src/main/assets/7_zidi.acv -------------------------------------------------------------------------------- /app/src/main/java/z0kai/filtercamera/BitmapActivity.java: -------------------------------------------------------------------------------- 1 | package z0kai.filtercamera; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.widget.ImageView; 8 | 9 | import butterknife.BindView; 10 | import butterknife.ButterKnife; 11 | import z0kai.filterlib.FilterRender; 12 | import z0kai.filterlib.OpenGlUtils; 13 | import z0kai.filterlib.filters.BaseFilter; 14 | import z0kai.filterlib.filters.SepiaFilter; 15 | 16 | import static z0kai.filterlib.OpenGlUtils.NO_TEXTURE; 17 | 18 | public class BitmapActivity extends AppCompatActivity { 19 | 20 | @BindView(R.id.iv_bitmap) 21 | ImageView ivBitmap; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_bitmap); 27 | 28 | ButterKnife.bind(this); 29 | showFilterImage(); 30 | } 31 | 32 | private void showFilterImage() { 33 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.z_0kai_pet); 34 | BaseFilter filter = new SepiaFilter(); 35 | filter.setAsStatic(); 36 | FilterRender filterRender = new FilterRender(filter); 37 | bitmap = filterRender.getFilterBitmap(bitmap); 38 | ivBitmap.setImageBitmap(bitmap); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/z0kai/filtercamera/CameraActivity.java: -------------------------------------------------------------------------------- 1 | package z0kai.filtercamera; 2 | 3 | import android.content.Context; 4 | import android.graphics.PointF; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Button; 12 | import android.widget.LinearLayout; 13 | import android.widget.RelativeLayout; 14 | 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import butterknife.BindView; 21 | import butterknife.ButterKnife; 22 | import z0kai.filterlib.filters.BaseFilter; 23 | import z0kai.filterlib.filters.BeautyFilter; 24 | import z0kai.filterlib.filters.ColorMatrixFilter; 25 | import z0kai.filterlib.filters.IFInkwellFilter; 26 | import z0kai.filterlib.filters.SepiaFilter; 27 | import z0kai.filterlib.filters.ToneCurveFilter; 28 | import z0kai.filterlib.filters.VignetteFilter; 29 | 30 | public class CameraActivity extends AppCompatActivity { 31 | 32 | @BindView(R.id.rv_filter_buttons) 33 | RecyclerView rvFilterButtons; 34 | @BindView(R.id.camera_view) 35 | CameraGLSurfaceView cameraView; 36 | 37 | List filterList; 38 | List filterName; 39 | 40 | Context mContext; 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_camera); 46 | ButterKnife.bind(this); 47 | mContext = this; 48 | initFilters(); 49 | } 50 | 51 | private void initFilters() { 52 | filterList = new ArrayList<>(); 53 | filterName = new ArrayList<>(); 54 | 55 | addFilter("None", new BaseFilter()); 56 | addFilter("Sepia", new SepiaFilter()); 57 | // addFilter("美颜1", new BeautyFilter(getResources(), 1)); 58 | // addFilter("美颜3", new BeautyFilter(getResources(), 3)); 59 | addFilter("Beauty", new BeautyFilter(getResources(), 5)); 60 | 61 | try { 62 | InputStream is = mContext.getAssets().open("7_zidi.acv"); 63 | ToneCurveFilter toneCurveFilter = new ToneCurveFilter(); 64 | toneCurveFilter.setFromCurveFileInputStream(is); 65 | is.close(); 66 | addFilter(".Acv", toneCurveFilter); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | 71 | addFilter("Vignette", new VignetteFilter()); 72 | 73 | addFilter("Black-White", new IFInkwellFilter(mContext)); 74 | 75 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false); 76 | rvFilterButtons.setLayoutManager(layoutManager); 77 | rvFilterButtons.setAdapter(new ButtonAdapter()); 78 | } 79 | 80 | private void addFilter(String name, final BaseFilter filter) { 81 | filterName.add(name); 82 | filterList.add(filter); 83 | } 84 | 85 | private class ButtonAdapter extends RecyclerView.Adapter { 86 | 87 | @Override 88 | public ButtonAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 89 | Button button = new Button(mContext); 90 | return new ViewHolder(button); 91 | } 92 | 93 | @Override 94 | public void onBindViewHolder(final ButtonAdapter.ViewHolder holder, int position) { 95 | holder.itemView.setText(filterName.get(position)); 96 | holder.itemView.setOnClickListener(new View.OnClickListener() { 97 | @Override 98 | public void onClick(View view) { 99 | cameraView.setFilter(filterList.get(holder.getLayoutPosition())); 100 | } 101 | }); 102 | } 103 | 104 | @Override 105 | public int getItemCount() { 106 | return filterName.size(); 107 | } 108 | 109 | public class ViewHolder extends RecyclerView.ViewHolder { 110 | 111 | private Button itemView; 112 | 113 | public ViewHolder(Button itemView) { 114 | super(itemView); 115 | this.itemView = itemView; 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/z0kai/filtercamera/CameraGLSurfaceView.java: -------------------------------------------------------------------------------- 1 | package z0kai.filtercamera; 2 | 3 | import android.content.Context; 4 | import android.graphics.SurfaceTexture; 5 | import android.hardware.Camera; 6 | import android.opengl.GLES11Ext; 7 | import android.opengl.GLES20; 8 | import android.opengl.GLSurfaceView; 9 | import android.support.annotation.NonNull; 10 | import android.util.AttributeSet; 11 | import android.util.Log; 12 | import android.view.SurfaceHolder; 13 | 14 | import javax.microedition.khronos.egl.EGLConfig; 15 | import javax.microedition.khronos.opengles.GL10; 16 | 17 | import z0kai.filterlib.FilterRender; 18 | import z0kai.filterlib.RotationUtil; 19 | import z0kai.filterlib.filters.BaseFilter; 20 | import z0kai.filterlib.filters.SepiaFilter; 21 | 22 | /** 23 | * Created by Z0Kai on 2016/7/4. 24 | */ 25 | 26 | public class CameraGLSurfaceView extends GLSurfaceView implements SurfaceTexture.OnFrameAvailableListener { 27 | private static final String TAG = CameraGLSurfaceView.class.getSimpleName(); 28 | Context mContext; 29 | FilterRender mFilterRender; 30 | 31 | public CameraGLSurfaceView(Context context, AttributeSet attrs) { 32 | super(context, attrs); 33 | mContext = context; 34 | mFilterRender = new FilterRender(new BaseFilter()); 35 | CameraInstance.getInstance().tryOpenCamera(null, Camera.CameraInfo.CAMERA_FACING_FRONT); 36 | mFilterRender.setUpCamera(CameraInstance.getInstance().getCameraDevice(), true); 37 | mFilterRender.setGLSurfaceView(this); 38 | } 39 | 40 | @Override 41 | public void surfaceDestroyed(SurfaceHolder holder) { 42 | super.surfaceDestroyed(holder); 43 | CameraInstance.getInstance().stopCamera(); 44 | } 45 | 46 | @Override 47 | public void onPause() { 48 | super.onPause(); 49 | CameraInstance.getInstance().stopCamera(); 50 | } 51 | 52 | @Override 53 | public void onFrameAvailable(SurfaceTexture surfaceTexture) { 54 | this.requestRender(); 55 | } 56 | 57 | public void setFilter(@NonNull BaseFilter filter) { 58 | mFilterRender.setFilter(filter); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/z0kai/filtercamera/CameraInstance.java: -------------------------------------------------------------------------------- 1 | package z0kai.filtercamera; 2 | 3 | import android.graphics.PixelFormat; 4 | import android.graphics.Rect; 5 | import android.graphics.SurfaceTexture; 6 | import android.hardware.Camera; 7 | import android.os.Build; 8 | import android.util.Log; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.Comparator; 14 | import java.util.List; 15 | 16 | // Camera 仅适用单例 17 | public class CameraInstance { 18 | public static final String LOG_TAG = CameraInstance.class.getSimpleName(); 19 | 20 | private static final String ASSERT_MSG = "检测到CameraDevice 为 null! 请检查"; 21 | 22 | private Camera mCameraDevice; 23 | private Camera.Parameters mParams; 24 | 25 | public static final int DEFAULT_PREVIEW_RATE = 30; 26 | 27 | 28 | private boolean mIsPreviewing = false; 29 | 30 | private int mDefaultCameraID = -1; 31 | 32 | private static CameraInstance mThisInstance; 33 | private int mPreviewWidth; 34 | private int mPreviewHeight; 35 | 36 | private int mPictureWidth = 1000; 37 | private int mPictureHeight = 1000; 38 | 39 | private int mPreferPreviewWidth = 640; 40 | private int mPreferPreviewHeight = 640; 41 | 42 | private int mFacing = 0; 43 | 44 | private CameraInstance() {} 45 | 46 | public static synchronized CameraInstance getInstance() { 47 | if(mThisInstance == null) { 48 | mThisInstance = new CameraInstance(); 49 | } 50 | return mThisInstance; 51 | } 52 | 53 | public boolean isPreviewing() { return mIsPreviewing; } 54 | 55 | public int previewWidth() { return mPreviewWidth; } 56 | public int previewHeight() { return mPreviewHeight; } 57 | public int pictureWidth() { return mPictureWidth; } 58 | public int pictureHeight() { return mPictureHeight; } 59 | 60 | public void setPreferPreviewSize(int w, int h) { 61 | mPreferPreviewHeight = w; 62 | mPreferPreviewWidth = h; 63 | } 64 | 65 | public interface CameraOpenCallback { 66 | void cameraReady(); 67 | } 68 | 69 | public boolean tryOpenCamera(CameraOpenCallback callback) { 70 | return tryOpenCamera(callback, Camera.CameraInfo.CAMERA_FACING_FRONT); 71 | } 72 | 73 | public int getFacing() { 74 | return mFacing; 75 | } 76 | 77 | public synchronized boolean tryOpenCamera(CameraOpenCallback callback, int facing) { 78 | Log.i(LOG_TAG, "try open camera..."); 79 | 80 | try 81 | { 82 | if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) 83 | { 84 | int numberOfCameras = Camera.getNumberOfCameras(); 85 | 86 | Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 87 | for (int i = 0; i < numberOfCameras; i++) { 88 | Camera.getCameraInfo(i, cameraInfo); 89 | if (cameraInfo.facing == facing) { 90 | mDefaultCameraID = i; 91 | mFacing = facing; 92 | } 93 | } 94 | } 95 | stopPreview(); 96 | if(mCameraDevice != null) 97 | mCameraDevice.release(); 98 | 99 | if(mDefaultCameraID >= 0) { 100 | mCameraDevice = Camera.open(mDefaultCameraID); 101 | } 102 | else { 103 | mCameraDevice = Camera.open(); 104 | mFacing = Camera.CameraInfo.CAMERA_FACING_BACK; //default: back facing 105 | } 106 | } 107 | catch(Exception e) 108 | { 109 | Log.e(LOG_TAG, "Open Camera Failed!"); 110 | e.printStackTrace(); 111 | mCameraDevice = null; 112 | return false; 113 | } 114 | 115 | if(mCameraDevice != null) { 116 | Log.i(LOG_TAG, "Camera opened!"); 117 | 118 | try { 119 | initCamera(DEFAULT_PREVIEW_RATE); 120 | } catch (Exception e) { 121 | mCameraDevice.release(); 122 | mCameraDevice = null; 123 | return false; 124 | } 125 | 126 | if (callback != null) { 127 | callback.cameraReady(); 128 | } 129 | 130 | return true; 131 | } 132 | 133 | return false; 134 | } 135 | 136 | public synchronized void stopCamera() { 137 | if(mCameraDevice != null) { 138 | mIsPreviewing = false; 139 | mCameraDevice.stopPreview(); 140 | mCameraDevice.setPreviewCallback(null); 141 | mCameraDevice.release(); 142 | mCameraDevice = null; 143 | } 144 | } 145 | 146 | public boolean isCameraOpened() { 147 | return mCameraDevice != null; 148 | } 149 | 150 | public synchronized void startPreview(SurfaceTexture texture) { 151 | Log.i(LOG_TAG, "Camera startPreview..."); 152 | if(mIsPreviewing) { 153 | Log.e(LOG_TAG, "Err: camera is previewing..."); 154 | // stopPreview(); 155 | return ; 156 | } 157 | 158 | if(mCameraDevice != null) { 159 | try { 160 | mCameraDevice.setPreviewTexture(texture); 161 | } catch (IOException e) { 162 | e.printStackTrace(); 163 | } 164 | 165 | mCameraDevice.startPreview(); 166 | mIsPreviewing = true; 167 | } 168 | } 169 | 170 | public synchronized void stopPreview() { 171 | if(mIsPreviewing && mCameraDevice != null) { 172 | Log.i(LOG_TAG, "Camera stopPreview..."); 173 | mIsPreviewing = false; 174 | mCameraDevice.stopPreview(); 175 | } 176 | } 177 | 178 | public synchronized Camera.Parameters getParams() { 179 | if(mCameraDevice != null) 180 | return mCameraDevice.getParameters(); 181 | assert mCameraDevice != null : ASSERT_MSG; 182 | return null; 183 | } 184 | 185 | public synchronized void setParams(Camera.Parameters param) { 186 | if(mCameraDevice != null) { 187 | mParams = param; 188 | mCameraDevice.setParameters(mParams); 189 | } 190 | assert mCameraDevice != null : ASSERT_MSG; 191 | } 192 | 193 | public Camera getCameraDevice() { 194 | return mCameraDevice; 195 | } 196 | 197 | //保证从大到小排列 198 | private Comparator comparatorBigger = new Comparator() { 199 | @Override 200 | public int compare(Camera.Size lhs, Camera.Size rhs) { 201 | int w = rhs.width - lhs.width; 202 | if(w == 0) 203 | return rhs.height - lhs.height; 204 | return w; 205 | } 206 | }; 207 | 208 | //保证从小到大排列 209 | private Comparator comparatorSmaller= new Comparator() { 210 | @Override 211 | public int compare(Camera.Size lhs, Camera.Size rhs) { 212 | int w = lhs.width - rhs.width; 213 | if(w == 0) 214 | return lhs.height - rhs.height; 215 | return w; 216 | } 217 | }; 218 | 219 | public void initCamera(int previewRate) { 220 | if(mCameraDevice == null) { 221 | Log.e(LOG_TAG, "initCamera: Camera is not opened!"); 222 | return; 223 | } 224 | 225 | mParams = mCameraDevice.getParameters(); 226 | mParams.setRotation(mFacing == Camera.CameraInfo.CAMERA_FACING_BACK ? 90 : 270); 227 | mCameraDevice.setDisplayOrientation(90); 228 | List supportedPictureFormats = mParams.getSupportedPictureFormats(); 229 | 230 | for(int fmt : supportedPictureFormats) { 231 | Log.i(LOG_TAG, String.format("Picture Format: %x", fmt)); 232 | } 233 | 234 | mParams.setPictureFormat(PixelFormat.JPEG); 235 | 236 | List picSizes = mParams.getSupportedPictureSizes(); 237 | Camera.Size picSz = null; 238 | 239 | Collections.sort(picSizes, comparatorBigger); 240 | 241 | for(Camera.Size sz : picSizes) { 242 | Log.i(LOG_TAG, String.format("Supported picture size: %d x %d", sz.width, sz.height)); 243 | if(picSz == null || (sz.width >= mPictureWidth && sz.height >= mPictureHeight)) { 244 | picSz = sz; 245 | } 246 | } 247 | 248 | List prevSizes = mParams.getSupportedPreviewSizes(); 249 | Camera.Size prevSz = null; 250 | 251 | Collections.sort(prevSizes, comparatorBigger); 252 | 253 | for(Camera.Size sz : prevSizes) { 254 | if(prevSz == null || (sz.width >= mPreferPreviewWidth && sz.height >= mPreferPreviewHeight)) { 255 | prevSz = sz; 256 | Log.i(LOG_TAG, String.format("Supported preview size: %d x %d", sz.width, sz.height)); 257 | } 258 | } 259 | 260 | List frameRates = mParams.getSupportedPreviewFrameRates(); 261 | 262 | int fpsMax = 0; 263 | 264 | for(Integer n : frameRates) { 265 | Log.i(LOG_TAG, "Supported frame rate: " + n); 266 | if(fpsMax < n) { 267 | fpsMax = n; 268 | } 269 | } 270 | 271 | mParams.setPreviewSize(prevSz.width, prevSz.height); 272 | mParams.setPictureSize(picSz.width, picSz.height); 273 | 274 | List focusModes = mParams.getSupportedFocusModes(); 275 | if(focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)){ 276 | mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 277 | } 278 | 279 | previewRate = fpsMax; 280 | mParams.setPreviewFrameRate(previewRate); //设置相机预览帧率 281 | // mParams.setPreviewFpsRange(20, 60); 282 | 283 | try { 284 | mCameraDevice.setParameters(mParams); 285 | }catch (Exception e) { 286 | e.printStackTrace(); 287 | } 288 | 289 | 290 | mParams = mCameraDevice.getParameters(); 291 | 292 | Camera.Size szPic = mParams.getPictureSize(); 293 | Camera.Size szPrev = mParams.getPreviewSize(); 294 | 295 | mPreviewWidth = szPrev.width; 296 | mPreviewHeight = szPrev.height; 297 | 298 | mPictureWidth = szPic.width; 299 | mPictureHeight = szPic.height; 300 | 301 | Log.i(LOG_TAG, String.format("Camera Picture Size: %d x %d", szPic.width, szPic.height)); 302 | Log.i(LOG_TAG, String.format("Camera Preview Size: %d x %d", szPrev.width, szPrev.height)); 303 | } 304 | 305 | public synchronized void setFocusMode(String focusMode) { 306 | 307 | if(mCameraDevice == null) 308 | return; 309 | 310 | mParams = mCameraDevice.getParameters(); 311 | List focusModes = mParams.getSupportedFocusModes(); 312 | if(focusModes.contains(focusMode)){ 313 | mParams.setFocusMode(focusMode); 314 | } 315 | } 316 | 317 | public synchronized void setPictureSize(int width, int height, boolean isBigger) { 318 | 319 | if(mCameraDevice == null) { 320 | mPictureWidth = width; 321 | mPictureHeight = height; 322 | return; 323 | } 324 | 325 | mParams = mCameraDevice.getParameters(); 326 | 327 | 328 | List picSizes = mParams.getSupportedPictureSizes(); 329 | Camera.Size picSz = null; 330 | 331 | if(isBigger) { 332 | Collections.sort(picSizes, comparatorBigger); 333 | for(Camera.Size sz : picSizes) { 334 | if(picSz == null || (sz.width >= width && sz.height >= height)) { 335 | picSz = sz; 336 | } 337 | } 338 | } else { 339 | Collections.sort(picSizes, comparatorSmaller); 340 | for(Camera.Size sz : picSizes) { 341 | if(picSz == null || (sz.width <= width && sz.height <= height)) { 342 | picSz = sz; 343 | } 344 | } 345 | } 346 | 347 | mPictureWidth = picSz.width; 348 | mPictureHeight= picSz.height; 349 | 350 | try { 351 | mParams.setPictureSize(mPictureWidth, mPictureHeight); 352 | mCameraDevice.setParameters(mParams); 353 | } catch (Exception e) { 354 | e.printStackTrace(); 355 | } 356 | } 357 | 358 | public void focusAtPoint(float x, float y, final Camera.AutoFocusCallback callback) { 359 | focusAtPoint(x, y, 0.2f, callback); 360 | } 361 | 362 | public synchronized void focusAtPoint(float x, float y, float radius, final Camera.AutoFocusCallback callback) { 363 | if(mCameraDevice == null) { 364 | Log.e(LOG_TAG, "Error: focus after release."); 365 | return; 366 | } 367 | 368 | mParams = mCameraDevice.getParameters(); 369 | 370 | if(mParams.getMaxNumMeteringAreas() > 0) { 371 | 372 | int focusRadius = (int) (radius * 1000.0f); 373 | int left = (int) (x * 2000.0f - 1000.0f) - focusRadius; 374 | int top = (int) (y * 2000.0f - 1000.0f) - focusRadius; 375 | 376 | Rect focusArea = new Rect(); 377 | focusArea.left = Math.max(left, -1000); 378 | focusArea.top = Math.max(top, -1000); 379 | focusArea.right = Math.min(left + focusRadius, 1000); 380 | focusArea.bottom = Math.min(top + focusRadius, 1000); 381 | List meteringAreas = new ArrayList(); 382 | meteringAreas.add(new Camera.Area(focusArea, 800)); 383 | 384 | try { 385 | mCameraDevice.cancelAutoFocus(); 386 | mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 387 | mParams.setFocusAreas(meteringAreas); 388 | mCameraDevice.setParameters(mParams); 389 | mCameraDevice.autoFocus(callback); 390 | } catch (Exception e) { 391 | Log.e(LOG_TAG, "Error: focusAtPoint failed: " + e.toString()); 392 | } 393 | } else { 394 | Log.i(LOG_TAG, "The device does not support metering areas..."); 395 | try { 396 | mCameraDevice.autoFocus(callback); 397 | } catch (Exception e) { 398 | Log.e(LOG_TAG, "Error: focusAtPoint failed: " + e.toString()); 399 | } 400 | } 401 | 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /app/src/main/java/z0kai/filtercamera/MainActivity.java: -------------------------------------------------------------------------------- 1 | package z0kai.filtercamera; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.os.Bundle; 7 | import android.support.design.widget.FloatingActionButton; 8 | import android.support.design.widget.Snackbar; 9 | import android.support.v4.app.ActivityCompat; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.support.v7.widget.Toolbar; 12 | import android.view.View; 13 | 14 | import butterknife.ButterKnife; 15 | import butterknife.OnClick; 16 | 17 | public class MainActivity extends AppCompatActivity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 24 | setSupportActionBar(toolbar); 25 | 26 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 27 | fab.setOnClickListener(new View.OnClickListener() { 28 | @Override 29 | public void onClick(View view) { 30 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 31 | .setAction("Action", null).show(); 32 | } 33 | }); 34 | 35 | ButterKnife.bind(this); 36 | 37 | if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { 38 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 0); 39 | } 40 | } 41 | 42 | @OnClick(R.id.btn_camera) 43 | public void showCamera() { 44 | startActivity(new Intent(this, CameraActivity.class)); 45 | } 46 | 47 | @OnClick(R.id.btn_bitmap) 48 | public void showBitmap() { 49 | startActivity(new Intent(this, BitmapActivity.class)); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_bitmap.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |