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 가 좋다.

댓글 없음:
댓글 쓰기