diff --git a/build.gradle b/build.gradle index 002953b..e1ee6fc 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:2.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -14,7 +14,7 @@ buildscript { allprojects { group 'com.github.crazyorr' - version '0.1.0' + version '0.1.1' repositories { jcenter() } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c71e76..a894ea7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Wed Apr 27 10:50:19 CST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/library/build.gradle b/library/build.gradle index eea1606..c07b5b0 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -6,13 +6,13 @@ apply plugin: 'signing' archivesBaseName = 'zoom-crop-image' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + compileSdkVersion 23 + buildToolsVersion "23.0.3" defaultConfig { minSdkVersion 14 - targetSdkVersion 22 - versionCode 1 + targetSdkVersion 23 + versionCode 2 versionName version } @@ -35,7 +35,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:22.1.1' + compile 'com.android.support:appcompat-v7:23.3.0' } task androidJavadocs(type: Javadoc) { diff --git a/library/src/main/java/com/github/crazyorr/zoomcropimage/CropImageLayout.java b/library/src/main/java/com/github/crazyorr/zoomcropimage/CropImageLayout.java index dc27142..52fb358 100644 --- a/library/src/main/java/com/github/crazyorr/zoomcropimage/CropImageLayout.java +++ b/library/src/main/java/com/github/crazyorr/zoomcropimage/CropImageLayout.java @@ -93,81 +93,6 @@ public CropImageLayout(Context context, AttributeSet attrs, int defStyleAttr) { this.addView(mCropImageBorderView, lp); } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mWidth = w; - mHeight = h; - initCropSize(); - } - - /** - * 裁切图片 - * - * @return - */ - public Bitmap crop() { - return mZoomCropImageView.crop(mOutputWidth, mOutputHeight); - } - - /** - * 必须提供Uri,否则无法获取到旋转信息 - * @param uri - */ - public void setImageURI(Uri uri){ - String path = FileUtils.getPath(getContext(), uri); - - WindowManager windowManager = (WindowManager)getContext() - .getSystemService(Context.WINDOW_SERVICE); - Display windowDisplay = windowManager.getDefaultDisplay(); - Point size = new Point(); - windowDisplay.getSize(size); - Log.i(TAG, "Screen Width = " + size.x); - Log.i(TAG, "Screen Height = " + size.y); - - int degrees = readImageRotationDegree(path); - Bitmap rotatedBitmap = rotaingBitmap(degrees, - sampleBitmap(getContext(), uri, size.x, size.y)); - mZoomCropImageView.setImageBitmap(rotatedBitmap); - } - - /** - * 设置输出图片尺寸 - * @param outputWidth - * @param outputHeight - */ - public void setOutputSize(int outputWidth, int outputHeight){ - mOutputWidth = outputWidth; - mOutputHeight = outputHeight; - initCropSize(); - } - - /** - * 设置切割形状 - * @param cropShape - */ - public void setCropShape(int cropShape){ - mCropImageBorderView.setCropShape(cropShape); - mZoomCropImageView.setCropShape(cropShape); - } - - private void initCropSize(){ - if(mWidth != 0 && mHeight != 0 - && mOutputWidth != 0 && mOutputHeight != 0){ - final double CROP_SIZE_RATIO = 0.9; - double scaleWidth = Math.floor(mWidth * CROP_SIZE_RATIO / mOutputWidth); - double scaleHeight = Math.floor(mHeight * CROP_SIZE_RATIO / mOutputHeight); - //放大倍数取较小值 - double scale = Math.min(scaleWidth, scaleHeight); - - int mCropWidth = (int)(mOutputWidth * scale); - int mCropHeight = (int)(mOutputHeight * scale); - - mZoomCropImageView.setCropSize(mCropWidth, mCropHeight); - mCropImageBorderView.setCropSize(mCropWidth, mCropHeight); - } - } - /** * 读取图片属性:旋转的角度 * @param path 图片绝对路径 @@ -196,7 +121,7 @@ public static int readImageRotationDegree(String path) { } return degree; } - + /** * 旋转图片 * @param degrees @@ -205,14 +130,14 @@ public static int readImageRotationDegree(String path) { */ public static Bitmap rotaingBitmap(int degrees , Bitmap bitmap) { // 旋转图片 动作 - Matrix matrix = new Matrix();; + Matrix matrix = new Matrix(); matrix.postRotate(degrees); // 创建新的图片 Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; } - + /** * 压缩图片尺寸 * @return @@ -267,4 +192,79 @@ public static Bitmap sampleBitmap(Context context, Uri uri, } return bitmap; } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mWidth = w; + mHeight = h; + initCropSize(); + } + + /** + * 裁切图片 + * + * @return + */ + public Bitmap crop() { + return mZoomCropImageView.crop(mOutputWidth, mOutputHeight); + } + + /** + * 必须提供Uri,否则无法获取到旋转信息 + * @param uri + */ + public void setImageURI(Uri uri){ + String path = FileUtils.getPath(getContext(), uri); + + WindowManager windowManager = (WindowManager)getContext() + .getSystemService(Context.WINDOW_SERVICE); + Display windowDisplay = windowManager.getDefaultDisplay(); + Point size = new Point(); + windowDisplay.getSize(size); + Log.i(TAG, "Screen Width = " + size.x); + Log.i(TAG, "Screen Height = " + size.y); + + int degrees = readImageRotationDegree(path); + Bitmap rotatedBitmap = rotaingBitmap(degrees, + sampleBitmap(getContext(), uri, size.x, size.y)); + mZoomCropImageView.setImageBitmap(rotatedBitmap); + } + + /** + * 设置输出图片尺寸 + * @param outputWidth + * @param outputHeight + */ + public void setOutputSize(int outputWidth, int outputHeight){ + mOutputWidth = outputWidth; + mOutputHeight = outputHeight; + initCropSize(); + } + + /** + * 设置切割形状 + * @param cropShape + */ + public void setCropShape(int cropShape){ + mCropImageBorderView.setCropShape(cropShape); + mZoomCropImageView.setCropShape(cropShape); + } + + private void initCropSize(){ + if(mWidth != 0 && mHeight != 0 + && mOutputWidth != 0 && mOutputHeight != 0){ + final double CROP_SIZE_RATIO = 0.9; + double scaleWidth = mWidth * CROP_SIZE_RATIO / mOutputWidth; + double scaleHeight = mHeight * CROP_SIZE_RATIO / mOutputHeight; + //缩放倍数取较小值 + double scale = Math.min(scaleWidth, scaleHeight); + + int mCropWidth = (int)(mOutputWidth * scale); + int mCropHeight = (int)(mOutputHeight * scale); + + mZoomCropImageView.setCropSize(mCropWidth, mCropHeight); + mCropImageBorderView.setCropSize(mCropWidth, mCropHeight); + } + } } diff --git a/library/src/main/java/com/github/crazyorr/zoomcropimage/FileUtils.java b/library/src/main/java/com/github/crazyorr/zoomcropimage/FileUtils.java index 455fd4d..0e44d5d 100644 --- a/library/src/main/java/com/github/crazyorr/zoomcropimage/FileUtils.java +++ b/library/src/main/java/com/github/crazyorr/zoomcropimage/FileUtils.java @@ -10,10 +10,27 @@ import android.provider.DocumentsContract; import android.provider.MediaStore; +import java.io.File; + /** * http://stackoverflow.com/questions/20067508/get-real-path-from-uri-android-kitkat-new-storage-access-framework */ public class FileUtils { + + public static File createFile(String dir, String name) { + File file = new File(dir, name); + File dirFile = file.getParentFile(); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + return file; + } + + public static boolean isSdCardMounted() { + return Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED); + } + /** * Get a file path from a Uri. This will get the the path for Storage Access * Framework Documents, as well as the _data field for the MediaStore and diff --git a/library/src/main/java/com/github/crazyorr/zoomcropimage/ZoomCropImageActivity.java b/library/src/main/java/com/github/crazyorr/zoomcropimage/ZoomCropImageActivity.java index 8f4688f..b4e25f3 100644 --- a/library/src/main/java/com/github/crazyorr/zoomcropimage/ZoomCropImageActivity.java +++ b/library/src/main/java/com/github/crazyorr/zoomcropimage/ZoomCropImageActivity.java @@ -1,7 +1,6 @@ package com.github.crazyorr.zoomcropimage; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; @@ -15,6 +14,9 @@ import java.io.File; import java.io.FileOutputStream; +import static com.github.crazyorr.zoomcropimage.FileUtils.createFile; +import static com.github.crazyorr.zoomcropimage.FileUtils.isSdCardMounted; + /** * http://blog.csdn.net/lmj623565791/article/details/39761281 * @@ -47,12 +49,14 @@ public class ZoomCropImageActivity extends Activity implements OnClickListener { * intent extra name : mFileName */ public static final String INTENT_EXTRA_FILE_NAME = "INTENT_EXTRA_FILE_NAME"; - + //crop status + public static final int CROP_SUCCEEDED = 0; + public static final int CROP_CANCELLED = 1; + public static final int CROP_FAILED = 2; /** * default cropped image name */ private static final String DEFAULT_CROPPED_IMAGE_NAME = "cropped_picture.png"; - /** * default cropped image width */ @@ -61,17 +65,27 @@ public class ZoomCropImageActivity extends Activity implements OnClickListener { * default cropped image height */ private static final int DEFAULT_OUTPUT_HEIGHT = 100; - - //crop status - public static final int CROP_SUCCEEDED = 0; - public static final int CROP_CANCELLED = 1; - public static final int CROP_FAILED = 2; - private CropImageLayout mCropImageLayout; private String mDir; private String mFileName; + /** + * get default directory to save cropped image + * + * @return + */ + private static String getDefaultSaveDir() { + String path; + if (isSdCardMounted()) { + path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + + File.separator + BuildConfig.APPLICATION_ID; + } else { + throw new RuntimeException("No SD card is mounted."); + } + return path; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -81,9 +95,9 @@ protected void onCreate(Bundle savedInstanceState) { // Image Uri Uri uri = getIntent().getParcelableExtra(INTENT_EXTRA_URI); - if(uri == null){ + if (uri == null) { throw new NullPointerException("uri == null"); - }else{ + } else { mCropImageLayout.setImageURI(uri); } @@ -104,13 +118,13 @@ protected void onCreate(Bundle savedInstanceState) { // directory mDir = getIntent().getStringExtra(INTENT_EXTRA_SAVE_DIR); - if(mDir == null){ - mDir = getDefaultSaveDir(this); + if (mDir == null) { + mDir = getDefaultSaveDir(); } // file name mFileName = getIntent().getStringExtra(INTENT_EXTRA_FILE_NAME); - if(mFileName == null){ + if (mFileName == null) { mFileName = DEFAULT_CROPPED_IMAGE_NAME; } @@ -119,7 +133,6 @@ protected void onCreate(Bundle savedInstanceState) { btnCancel.setOnClickListener(this); Button btnConfirm = (Button) findViewById(R.id.id_btn_confirm); btnConfirm.setOnClickListener(this); - } @Override @@ -158,34 +171,4 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { } return super.onKeyDown(keyCode, event); } - - public static File createFile(String dir, String name) { - File dirFile = new File(dir); - if (!dirFile.exists()) { - dirFile.mkdirs(); - } - - File file = new File(dirFile, name); - return file; - } - - public static boolean isSdCardMounted() { - return Environment.getExternalStorageState().equals( - Environment.MEDIA_MOUNTED); - } - - /** - * get default directory to save cropped image - * @param context - * @return - */ - public static String getDefaultSaveDir(Context context){ - String path; - if(isSdCardMounted()){ - path = Environment.getExternalStorageDirectory().getAbsolutePath(); - }else{ - path = context.getFilesDir().getAbsolutePath(); - } - return path + File.separator + context.getPackageName() + File.separator; - } } diff --git a/sample/build.gradle b/sample/build.gradle index f926368..22fc01c 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + compileSdkVersion 23 + buildToolsVersion "23.0.3" defaultConfig { applicationId "com.github.crazyorr.zoomcropimage.sample" minSdkVersion 14 - targetSdkVersion 22 - versionCode 1 + targetSdkVersion 23 + versionCode 2 versionName version } @@ -27,6 +27,6 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:22.1.1' + compile 'com.android.support:appcompat-v7:23.3.0' compile project(':library') } diff --git a/sample/src/main/java/com/github/crazyorr/zoomcropimage/sample/MainActivity.java b/sample/src/main/java/com/github/crazyorr/zoomcropimage/sample/MainActivity.java index bb31cb5..fe2192a 100644 --- a/sample/src/main/java/com/github/crazyorr/zoomcropimage/sample/MainActivity.java +++ b/sample/src/main/java/com/github/crazyorr/zoomcropimage/sample/MainActivity.java @@ -1,12 +1,16 @@ package com.github.crazyorr.zoomcropimage.sample; +import android.Manifest; import android.app.Activity; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; -import android.util.Log; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; @@ -16,9 +20,14 @@ import java.io.File; -public class MainActivity extends Activity { +public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); + + private static final String KEY_PICTURE_URI = "KEY_PICTURE_URI"; + + private static final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1; + private static final int REQUEST_CODE_SELECT_PICTURE = 0; private static final int REQUEST_CODE_CROP_PICTURE = 1; @@ -34,22 +43,16 @@ public static File createPictureFile(String fileName) { return null; } - File pictureStorageDir = new File(Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES), BuildConfig.APPLICATION_ID); - // This location works best if you want the created images to be shared - // between applications and persist after your app has been uninstalled. + File picture = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_PICTURES) + File.separator + BuildConfig.APPLICATION_ID, + fileName); - // Create the storage directory if it does not exist - if (!pictureStorageDir.exists()) { - if (!pictureStorageDir.mkdirs()) { - Log.d(TAG, "failed to create directory"); - return null; - } + File dirFile = picture.getParentFile(); + if (!dirFile.exists()) { + dirFile.mkdirs(); } - // Create a media file name - File pictureFile = new File(pictureStorageDir.getPath() + File.separator + fileName); - return pictureFile; + return picture; } @Override @@ -75,6 +78,21 @@ public void onClick(View v) { startActivityForResult(chooserIntent, REQUEST_CODE_SELECT_PICTURE); } }); + if (savedInstanceState != null) { + mPictureUri = savedInstanceState.getParcelable(KEY_PICTURE_URI); + } + } + + @Override + public void onResume() { + super.onResume(); + requestPermissionWriteExternalStorage(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable(KEY_PICTURE_URI, mPictureUri); } @Override @@ -98,9 +116,13 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_OUTPUT_WIDTH, PICTURE_WIDTH); intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_OUTPUT_HEIGHT, PICTURE_HEIGHT); intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_CROP_SHAPE, CropShape.SHAPE_OVAL); //optional - intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_SAVE_DIR, - Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + getPackageName()); //optional - intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_FILE_NAME, "cropped.png"); //optional + File croppedPicture = createPictureFile("cropped.png"); + if (croppedPicture != null) { + intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_SAVE_DIR, + croppedPicture.getParent()); //optional + intent.putExtra(ZoomCropImageActivity.INTENT_EXTRA_FILE_NAME, + croppedPicture.getName()); //optional + } startActivityForResult(intent, REQUEST_CODE_CROP_PICTURE); break; } @@ -123,6 +145,30 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } break; } + } + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: { + // If request is cancelled, the result arrays are empty. + if (!(grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { + finish(); + } + break; + } + } + } + + private void requestPermissionWriteExternalStorage() { + final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE; + final int requestCode = MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE; + + if (ContextCompat.checkSelfPermission(this, permission) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode); + } } } diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 7521c81..41c1430 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -22,6 +22,6 @@ android:layout_height="match_parent" android:layout_above="@id/id_btn" android:adjustViewBounds="true" - android:scaleType="centerInside" /> + android:scaleType="fitCenter" /> diff --git a/screenshots/demo.gif b/screenshots/demo.gif new file mode 100644 index 0000000..ae2bdad Binary files /dev/null and b/screenshots/demo.gif differ