├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── meitu │ │ └── cropimageproject │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── ezgif.com-video-to-gif.gif │ ├── java │ │ └── com │ │ │ └── meitu │ │ │ └── cropimageproject │ │ │ └── activity │ │ │ ├── DisplayActivity.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable │ │ ├── ic_launcher.png │ │ └── screenshot.png │ │ ├── layout │ │ ├── activity_main.xml │ │ └── display_iamge_activity.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── meitu │ └── cropimageproject │ └── ExampleUnitTest.java ├── build.gradle ├── cropimagelibrary ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── meitu │ │ └── cropimagelibrary │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── meitu │ │ │ └── cropimagelibrary │ │ │ ├── info │ │ │ └── ImageInfo.java │ │ │ ├── util │ │ │ ├── FileUtil.java │ │ │ ├── ImageLoadUtil.java │ │ │ ├── RectUtils.java │ │ │ ├── RotationGestureDetector.java │ │ │ └── SaveBitmapCallback.java │ │ │ └── view │ │ │ └── CropImageView.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── meitu │ └── cropimagelibrary │ └── 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/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.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/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | GitHub同步 4 | https://github.com/waterCode 5 | 6 | 博客地址:http://blog.csdn.net/sinat_28676875/article/details/60322063 7 | 8 | 动态图: 9 | ![image](https://github.com/waterCode/CropImageProject/blob/master/app/src/main/assets/ezgif.com-video-to-gif.gif) 10 | 11 | 用法: 12 | ```xml 13 | 19 | ``` 20 | ```java 21 | CropImageView mNeedCropView = (CropImageView) findViewById(R.id.crop_photo_civ); 22 | uri = getIntent().getParcelableExtra("uri"); 23 | mNeedCropView.setImageURI(uri); 24 | ``` 25 | 用法大概和ImageView相同,不过要保存图片要申请权限,,6.0以上要动态申请,直接设置uri,我这里的uri是从图库里面选着返回的 26 | 27 | 其他public方法, 28 | ```java 29 | /** 30 | * 设置最小放大倍数 31 | * 32 | * @param MIN_SCALE 最小放大倍数 33 | */ 34 | setMinScale(float MIN_SCALE) 35 | /** 36 | * 设置最小放大倍数 37 | * 38 | * @param MAX_SCALE 最大放大倍数 39 | */ 40 | setMaxScale(float MAX_SCALE); 41 | 42 | 43 | /** 44 | * 放大设置开关 45 | * 46 | * @param mScaleEnable 是否开启 47 | */ 48 | setScaleEnable(boolean mScaleEnable); 49 | 50 | /** 51 | * 旋转开关 52 | * 53 | * @param mRotateEnable 是否开启 54 | */ 55 | setRotateEnable(boolean mRotateEnable);//设置是否开启旋转 56 | 57 | setHorizontalMirror();//设置是否开启水平镜像 58 | setVerticalMirror();//设置垂直镜像 59 | postAnyRotate(float anyAngel);//旋转图片任意角度, 60 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | 4 | android { 5 | compileSdkVersion 24 6 | buildToolsVersion "26.0.1" 7 | defaultConfig { 8 | applicationId "com.meitu.cropimageproject" 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 | 24 | 25 | dependencies { 26 | compile fileTree(include: ['*.jar'], dir: 'libs') 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:25.3.1' 31 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 32 | testCompile 'junit:junit:4.12' 33 | compile 'com.github.bumptech.glide:glide:3.8.0' 34 | compile 'com.android.support:support-v4:25.3.1' 35 | annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC0' 36 | compile project(':cropimagelibrary') 37 | 38 | } 39 | -------------------------------------------------------------------------------- /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 C:\Users\meitu\AppData\Local\Android\Sdk/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/meitu/cropimageproject/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.meitu.cropimageproject; 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("com.meitu.cropimageproject", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/assets/ezgif.com-video-to-gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waterCode/CropImageProject/65fec159ef6bf7c7333f607e4f63f1d4098e4fdd/app/src/main/assets/ezgif.com-video-to-gif.gif -------------------------------------------------------------------------------- /app/src/main/java/com/meitu/cropimageproject/activity/DisplayActivity.java: -------------------------------------------------------------------------------- 1 | package com.meitu.cropimageproject.activity; 2 | 3 | import android.content.pm.PackageManager; 4 | import android.graphics.Bitmap; 5 | import android.media.MediaScannerConnection; 6 | import android.net.Uri; 7 | import android.os.AsyncTask; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.os.Handler; 11 | import android.os.Looper; 12 | import android.os.Message; 13 | import android.os.MessageQueue; 14 | import android.support.annotation.Nullable; 15 | import android.support.v4.app.ActivityCompat; 16 | import android.support.v4.content.ContextCompat; 17 | import android.support.v7.app.AppCompatActivity; 18 | import android.util.Log; 19 | import android.view.View; 20 | import android.view.ViewGroup; 21 | 22 | import com.meitu.cropimagelibrary.util.FileUtil; 23 | import com.meitu.cropimagelibrary.util.SaveBitmapCallback; 24 | import com.meitu.cropimagelibrary.view.CropImageView; 25 | import com.meitu.cropimageproject.R; 26 | 27 | import java.io.File; 28 | 29 | 30 | /** 31 | * Created by zmc on 2017/7/18. 32 | */ 33 | 34 | public class DisplayActivity extends AppCompatActivity { 35 | private String TAG = "DisplayActivity"; 36 | private Uri uri;//怎么部分重构? 37 | private CropImageView mNeedCropView; 38 | private Looper looper; 39 | 40 | 41 | private static class MyHandler extends Handler{ 42 | @Override 43 | public void handleMessage(Message msg) { 44 | super.handleMessage(msg); 45 | //处理消息, 46 | } 47 | } 48 | 49 | private static class MyHanderCallback implements Handler.Callback{ 50 | 51 | @Override 52 | public boolean handleMessage(Message msg) { 53 | return false; 54 | } 55 | } 56 | private Handler myHandler = new Handler(new MyHanderCallback()); 57 | 58 | @Override 59 | protected void onCreate(@Nullable Bundle savedInstanceState) { 60 | super.onCreate(savedInstanceState); 61 | setContentView(R.layout.display_iamge_activity); 62 | Log.d(TAG,"maxmemory"+(Runtime.getRuntime().maxMemory()/1024/1024)); 63 | if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) 64 | != PackageManager.PERMISSION_GRANTED) { 65 | ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); 66 | } else { 67 | // 68 | //finish(); 69 | } 70 | 71 | mNeedCropView = (CropImageView) findViewById(R.id.crop_photo_civ); 72 | uri = getIntent().getParcelableExtra("uri"); 73 | mNeedCropView.setImageURI(uri); 74 | 75 | } 76 | 77 | // TODO: 2017/7/27 Exif 方向 78 | // TODO: 2017/7/27 大尺寸图片oom ,不同阶段 79 | public void onClick(View v) { 80 | switch (v.getId()) { 81 | case R.id.set_mirror_image_bt: 82 | mNeedCropView.setHorizontalMirror(); 83 | break; 84 | case R.id.crop_Image_bt: 85 | 86 | 87 | Bitmap bitmap = mNeedCropView.cropAndSaveImage(); 88 | SaveFileTask saveFileTask = new SaveFileTask(); 89 | saveFileTask.execute(bitmap); 90 | break; 91 | case R.id.rightRotate_bt: 92 | mNeedCropView.postAnyRotate(45); 93 | break; 94 | case R.id.leftRotate_bt: 95 | mNeedCropView.leftRotate90(); 96 | break; 97 | case R.id.cancel_crop_activity_bt: 98 | finish(); 99 | default: 100 | break; 101 | } 102 | } 103 | 104 | 105 | public File getDefaultDir() { 106 | File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "crop_iamge"); 107 | if (!file.exists()) { 108 | file.mkdir(); 109 | } 110 | return file; 111 | } 112 | 113 | 114 | private class SaveFileTask extends AsyncTask { 115 | 116 | @Override 117 | protected File doInBackground(Bitmap... params) { 118 | 119 | if (params == null && params.length < 1) 120 | return null; 121 | File parent = getDefaultDir(); 122 | if(params[0] ==null) 123 | return null; 124 | return FileUtil.bitmapConvertToFile(DisplayActivity.this, params[0], parent, new SaveBitmapCallback() { 125 | 126 | @Override 127 | public void onFailed() { 128 | 129 | } 130 | }); 131 | } 132 | 133 | 134 | @Override 135 | protected void onPostExecute(File file) { 136 | super.onPostExecute(file); 137 | if (file != null) { 138 | Log.d(TAG, "图片文件路径为" + file.getAbsolutePath()); 139 | //通知图库 140 | MediaScannerConnection.scanFile(DisplayActivity.this, new String[]{file.getAbsolutePath()}, null, new MediaScannerConnection.OnScanCompletedListener() { 141 | 142 | 143 | @Override 144 | public void onScanCompleted(String path, Uri uri) { 145 | Log.d(TAG, "扫描后 path"+ path+" uri :"+uri.toString()); 146 | 147 | } 148 | }); 149 | } 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/meitu/cropimageproject/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.meitu.cropimageproject.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | 10 | import com.meitu.cropimageproject.R; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | 14 | public static final int GET_IMAGE = 1; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | 21 | } 22 | 23 | 24 | public void onClick(View v) { 25 | //就一个按钮 26 | Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 27 | intent.setType("image/*"); 28 | startActivityForResult(intent, GET_IMAGE); 29 | } 30 | 31 | @Override 32 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 33 | super.onActivityResult(requestCode, resultCode, data); 34 | if (resultCode == Activity.RESULT_OK) { 35 | switch (requestCode) { 36 | case GET_IMAGE: 37 | Uri uri = data.getData(); 38 | Intent intent = new Intent(this, DisplayActivity.class); 39 | intent.putExtra("uri", uri); 40 | startActivity(intent); 41 | break; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waterCode/CropImageProject/65fec159ef6bf7c7333f607e4f63f1d4098e4fdd/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waterCode/CropImageProject/65fec159ef6bf7c7333f607e4f63f1d4098e4fdd/app/src/main/res/drawable/screenshot.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 |