uCrop 사용하기
uCrop 은 이미지 잘라내기(crop image) 를 구현해 놓은 library 이다. library 는 ref. 4 에 많이 볼 수 있는데 개인적으로 이녀석의 UI 가 가장 예뻐서 선택했다.여기서는 uCrop 의 github 의 example source 을 조금 간략하게 편집한 소스로 설명하려 한다.(소스다운로드)
gradle 설정
app gradleapply plugin: 'com.android.application'
android {
...
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.android.support:design:23.2.0'
compile 'com.yalantis:ucrop:1.3.+'
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.namh.ucropsample"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application ... <activity android:name="com.yalantis.ucrop.UCropActivity" android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Light.NoActionBar"/> </application> </manifest>
동작 설명
대략적인 동작은 아래와 같다.
- "PICK AND CROP" 이라는 버튼을 누르면,
- gallery 가 보여지고,
- 여기서 사진을 선택하면,
- edit 화면(uCrop) 이 나온다.
- edit 를 끝맞치면, 사진이 "PICK AND CROP" 버튼 아래에 보여지게 된다.
MainActivity
uCorp 의 예제에 보면 BaseActivity.java 를 사용하는데, 이 activity 에 Mashmellow 의 permission 을 물어보는 부분도 구현을 해 놓았다. 그러니 이녀석을 상속받아서 Activity 를 만들도록 하자.
그리고 아래처럼 code 를 추가해 주면 된다. 그러면 아래같은 화면이 된다. 코드가 길어서 일부만 적어놓는다. 자세한 코드는 링크를 참고하자.
MainActivity.java
gallery
requestPermission 은 BaseActivity.java 에 들어있다.
private void pickFromGallery() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN // Permission was added in API Level 16 && ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, getString(R.string.permission_read_storage_rationale), REQUEST_STORAGE_READ_ACCESS_PERMISSION); } else { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(Intent.createChooser(intent, getString(R.string.label_select_picture)), REQUEST_SELECT_PICTURE); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == REQUEST_SELECT_PICTURE) { final Uri selectedUri = data.getData(); if (selectedUri != null) { startCropActivity(data.getData()); } else { Toast.makeText(SampleActivity.this, R.string.toast_cannot_retrieve_selected_image, Toast.LENGTH_SHORT).show(); } } else if (requestCode == UCrop.REQUEST_CROP) { handleCropResult(data); } } if (resultCode == UCrop.RESULT_ERROR) { handleCropError(data); } }
crop
gallery 에서 사진 선택이 끝나면 아래 같은 순서로 실행된다.- startCropActivity ()
- --> uCrop.start(MainActivity.this);
- --> handleCropResult()
- --> mImageView.setImageURI(resultUri);
public class MainActivity extends BaseActivity { private static final String TAG = "MainActivity"; private static final int REQUEST_SELECT_PICTURE = 0x01; private static final String SAMPLE_CROPPED_IMAGE_NAME = "SampleCropImage.jpeg"; ... private Uri mDestinationUri; private ImageView mImageView; @Override protected void onCreate(Bundle savedInstanceState) { ... // setup crop mDestinationUri = Uri.fromFile(new File(getCacheDir(), SAMPLE_CROPPED_IMAGE_NAME)); _setupPickButton(); mImageView = ((ImageView) findViewById(R.id.image_view_preview)); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == REQUEST_SELECT_PICTURE) { final Uri selectedUri = data.getData(); if (selectedUri != null) { startCropActivity(data.getData()); } else { Toast.makeText(MainActivity.this, R.string.toast_cannot_retrieve_selected_image, Toast.LENGTH_SHORT).show(); } } else if (requestCode == UCrop.REQUEST_CROP) { handleCropResult(data); } } if (resultCode == UCrop.RESULT_ERROR) { handleCropError(data); } } private void startCropActivity(@NonNull Uri uri) { UCrop uCrop = UCrop.of(uri, mDestinationUri); uCrop = _setRatio(uCrop, RATIO_ORIGIN, 0, 0); uCrop = _setSize(uCrop, 0, 0); uCrop = _advancedConfig(uCrop, FORMAT_JPEG, 90); uCrop.start(MainActivity.this); } private void handleCropResult(@NonNull Intent result) { final Uri resultUri = UCrop.getOutput(result); if (resultUri != null) { // ResultActivity.startWithUri(MainActivity.this, resultUri); Toast.makeText(MainActivity.this, resultUri.toString(), Toast.LENGTH_SHORT).show(); mImageView.setImageURI(resultUri); } else { Toast.makeText(MainActivity.this, R.string.toast_cannot_retrieve_cropped_image, Toast.LENGTH_SHORT).show(); } } @SuppressWarnings("ThrowableResultOfMethodCallIgnored") private void handleCropError(@NonNull Intent result) { ... } private void _setupPickButton(){ ... } private void _pickFromGallery() { ... } /** * Callback received when a permissions request has been completed. */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { ... } private UCrop _setRatio(@NonNull UCrop uCrop, int choice, float xratio, float yratio){ ... } private UCrop _setSize(@NonNull UCrop uCrop, int maxWidth, int maxHeight){ ... } /** * Sometimes you want to adjust more options, it's done via {@link com.yalantis.ucrop.UCrop.Options} class. * * @param uCrop - ucrop builder instance * @return - ucrop builder instance */ private UCrop _advancedConfig(@NonNull UCrop uCrop, int format, int quality) { ... } }
mDestinationUri 의 path
참고로 edit 한 내용은 mDestinationUri 에 임시로 저장한다. mDestinationUri 의 경로는- /data/data/com.applicaton.com/cache
같다.
Save the Image
이미지를 저장하는 방법은 간단하다.cache 에 저장된 이미지를 Downloads 폴더로 copy 하는 작업을 수행하기만 하면 된다.
private void _setupSaveButton() { findViewById(R.id.button_save).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { _saveCroppedImage(); } }); } private void _saveCroppedImage() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, getString(R.string.permission_write_storage_rationale), REQUEST_STORAGE_WRITE_ACCESS_PERMISSION); } else { Uri imageUri = mResultUri; if (imageUri != null && imageUri.getScheme().equals("file")) { try { copyFileToDownloads(imageUri); } catch (Exception e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); Log.e(TAG, imageUri.toString(), e); } } else { Toast.makeText(MainActivity.this, getString(R.string.toast_unexpected_error), Toast.LENGTH_SHORT).show(); } } } private void copyFileToDownloads(Uri croppedFileUri) throws Exception { String downloadsDirectoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getAbsolutePath(); String filename = String.format( "%d_%s", Calendar.getInstance().getTimeInMillis(), croppedFileUri.getLastPathSegment()); File saveFile = new File(downloadsDirectoryPath, filename); FileInputStream inStream = new FileInputStream(new File(croppedFileUri.getPath())); FileOutputStream outStream = new FileOutputStream(saveFile); FileChannel inChannel = inStream.getChannel(); FileChannel outChannel = outStream.getChannel(); inChannel.transferTo(0, inChannel.size(), outChannel); inStream.close(); outStream.close(); // showNotification(saveFile); Toast.makeText(MainActivity.this, getString(R.string.toast_image_saved), Toast.LENGTH_SHORT).show(); }
Example Source
- android_uCrop_example source > 소스 다운로드
- https://github.com/Yalantis/uCrop 에 library source 와 example 소스가 같이 있다.
수정
gallery 를 부르고, 다시 crop activity 를 호출하는 부분을 BaseActivity.java 로 옮겼다. 이 녀석을 사용하면, 아래 정도만 구현해 주면된다. 편할대로 사용하자.
- protected Activity getActivity()
- protected void handleCropResult(Intent data)
- protected void handleCropError(Intent data)
- pickFromGallery() : 버튼의 click event handler 에서 pickFromGallery() 를 불러주면 된다.
source
- https://gist.github.com/i5on9i/9493bd1bd1923d87372c : gallery 부르는 부분을 BaseActivity.java 로 옮겼다.
Reference
- unable to find com.android.camera.CropImage activity in android, StackOverflow
- GitHub - lvillani/android-cropimage: CropImage Activity from Gallery.apk packaged as a reusable Android library (4.0 and up).
- GitHub - biokys/cropimage: Replacement for deprecated official Android crop image function : 이 crop image 소스를 ref. 2 에서 사용하는 듯 하다.
- The Android Arsenal - Image Croppers - A categorized directory of free libraries and tools for Android
- The Android Arsenal - Image Croppers - uCrop : 무료 library 인데 UI 가 좋다.
댓글 없음:
댓글 쓰기