package com.candc.findlookmanager; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.drawable.BitmapDrawable; import android.media.ExifInterface; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; /** * @author kein * */ public class ImageSelectHelperActivity extends Activity { /** Buttons for selector dialog */ private View mBtnGallery = null, mBtnCamera = null, mBtnCancel = null; private final int REQ_CODE_PICK_GALLERY = 900001; private final int REQ_CODE_PICK_CAMERA = 900002; private final int REQ_CODE_PICK_CROP = 900003; @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putBoolean("mCropRequested", mCropRequested); savedInstanceState.putInt("mCropAspectWidth", mCropAspectWidth); savedInstanceState.putInt("mCropAspectHeight", mCropAspectHeight); BitmapDrawable drawable = (BitmapDrawable) ((ImageView) findViewById(R.id.ivImageSelected)) .getDrawable(); if (drawable != null) { Bitmap bitmap = drawable.getBitmap(); savedInstanceState.putParcelable("bitmap", bitmap); } } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mCropRequested = savedInstanceState.getBoolean("mCropRequested"); mCropAspectWidth = savedInstanceState.getInt("mCropAspectWidth"); mCropAspectHeight = savedInstanceState.getInt("mCropAspectHeight"); Bitmap bm = (Bitmap) savedInstanceState.getParcelable("bitmap"); if (bm != null) { ((ImageView) findViewById(R.id.ivImageSelected)).setImageBitmap(bm); } } /** * Call this to start! */ public void startSelectImage() { if (!checkWriteExternalPermission()) { showAlert("we need android.permission.WRITE_EXTERNAL_STORAGE"); return; } if (!checkSDisAvailable()) { showAlert("Check External Storage."); return; } if (findViewById(R.id.ivImageSelected) == null) { showAlert("Your layout should have ImageView name as ivImageSelected."); return; } if (mBtnGallery == null) { setDefaultButtons(); } setButtonsClick(); showSelectDialog(); } public File getSelectedImageFile() { return getTempImageFile(); } private boolean mCropRequested = false; /** * crop 이 필요한 경우 설정함. 설정하지 않으면 crop 하지 않음. * * @param width * crop size width. * @param height * crop size height. */ private int mCropAspectWidth = 1, mCropAspectHeight = 1; public void setCropOption(int aspectX, int aspectY) { mCropRequested = true; mCropAspectWidth = aspectX; mCropAspectHeight = aspectY; } /** * 사용할 이미지의 최대 크기 설정. 가로, 세로 지정한 크기보다 작은 사이즈로 이미지 크기를 조절함. default size : * 500 * * @param sizePixel * 기본 500 */ private int mImageSizeBoundary = 500; public void setImageSizeBoundary(int sizePixel) { mImageSizeBoundary = sizePixel; } private boolean checkWriteExternalPermission() { String permission = "android.permission.WRITE_EXTERNAL_STORAGE"; int res = checkCallingOrSelfPermission(permission); return (res == PackageManager.PERMISSION_GRANTED); } private boolean checkSDisAvailable() { String state = Environment.getExternalStorageState(); return state.equals(Environment.MEDIA_MOUNTED); } /** * Set your own button views for selector dialog. */ public void setCustomButtons(View btnGallery, View btnCamera, View btnCancel) { if (btnGallery == null || btnCamera == null || btnCancel == null) { showAlert("All buttons should not null."); } else { mBtnGallery = btnGallery; mBtnCamera = btnCamera; mBtnCancel = btnCancel; } } /** * Set default buttons for selector dialog, unless you set. */ private void setDefaultButtons() { Button btn1 = new Button(this); Button btn2 = new Button(this); Button btn3 = new Button(this); btn1.setText("从相册选择"); btn2.setText("拍照"); btn3.setText("取消"); btn1.setBackgroundColor(Color.GREEN); btn2.setBackgroundColor(Color.YELLOW); btn3.setBackgroundColor(Color.RED); btn1.setTextColor(Color.WHITE); btn2.setTextColor(Color.WHITE); btn3.setTextColor(Color.WHITE); btn1.setMinHeight(30); btn2.setMinHeight(30); btn3.setMinHeight(30); mBtnGallery = btn1; mBtnCamera = btn2; mBtnCancel = btn3; } private File getTempImageFile() { File path = new File(Environment.getExternalStorageDirectory() + "/Android/data/" + getPackageName() + "/temp/"); if (!path.exists()) { path.mkdirs(); } File file = new File(path, "tempimage.png"); return file; } private void setButtonsClick() { mBtnGallery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mSelectDialog.dismiss(); Intent i = new Intent(Intent.ACTION_PICK); i.setType(android.provider.MediaStore.Images.Media.CONTENT_TYPE); i.setData(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, REQ_CODE_PICK_GALLERY); } }); mBtnCamera.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mSelectDialog.dismiss(); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempImageFile())); intent.putExtra("return-data", true); startActivityForResult(intent, REQ_CODE_PICK_CAMERA); } }); mBtnCancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mSelectDialog != null && mSelectDialog.isShowing()) { mSelectDialog.dismiss(); } } }); } private Dialog mSelectDialog; private void showSelectDialog() { if (mSelectDialog == null) { mSelectDialog = new Dialog(this); mSelectDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); LinearLayout linear = new LinearLayout(this); linear.setOrientation(LinearLayout.VERTICAL); linear.setPadding(30, 10, 30, 10); linear.setBackgroundColor(Color.WHITE); linear.addView(mBtnGallery); linear.addView(mBtnCamera); linear.addView(mBtnCancel); int dialogWidth = getResources().getDisplayMetrics().widthPixels / 2; if (dialogWidth / 2 > 700) { dialogWidth = 700; } mSelectDialog.setContentView(linear, new LayoutParams(dialogWidth, LayoutParams.WRAP_CONTENT)); } mSelectDialog.show(); } private void showAlert(String msg) { new AlertDialog.Builder(this).setTitle("Error").setMessage(msg) .setPositiveButton(android.R.string.ok, null).show(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQ_CODE_PICK_GALLERY && resultCode == Activity.RESULT_OK) { // 갤러리의 경우 곧바로 data 에 uri가 넘어옴. Uri uri = data.getData(); copyUriToFile(uri, getTempImageFile()); if (mCropRequested) { cropImage(); } else { doFinalProcess(); } } else if (requestCode == REQ_CODE_PICK_CAMERA && resultCode == Activity.RESULT_OK) { // 카메라의 경우 file 로 결과물이 돌아옴. // 카메라 회전 보정. correctCameraOrientation(getTempImageFile()); if (mCropRequested) { cropImage(); } else { doFinalProcess(); } } else if (requestCode == REQ_CODE_PICK_CROP && resultCode == Activity.RESULT_OK) { // crop 한 결과는 file로 돌아옴. doFinalProcess(); } else { super.onActivityResult(requestCode, resultCode, data); } } private void doFinalProcess() { // sample size 를 적용하여 bitmap load. Bitmap bitmap = loadImageWithSampleSize(getTempImageFile()); // image boundary size 에 맞도록 이미지 축소. bitmap = resizeImageWithinBoundary(bitmap); // 결과 file 을 얻어갈 수 있는 메서드 제공. saveBitmapToFile(bitmap); // show image on ImageView Bitmap bm = BitmapFactory.decodeFile(getTempImageFile() .getAbsolutePath()); ((ImageView) findViewById(R.id.ivImageSelected)).setImageBitmap(bm); } private void saveBitmapToFile(Bitmap bitmap) { File target = getTempImageFile(); try { FileOutputStream fos = new FileOutputStream(target, false); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** 이미지 사이즈 수정 후, 카메라 rotation 정보가 있으면 회전 보정함. */ private void correctCameraOrientation(File imgFile) { Bitmap bitmap = loadImageWithSampleSize(imgFile); try { ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath()); int exifOrientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); int exifRotateDegree = exifOrientationToDegrees(exifOrientation); bitmap = rotateImage(bitmap, exifRotateDegree); saveBitmapToFile(bitmap); } catch (IOException e) { e.printStackTrace(); } } private Bitmap rotateImage(Bitmap bitmap, int degrees) { if (degrees != 0 && bitmap != null) { Matrix m = new Matrix(); m.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); try { Bitmap converted = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); if (bitmap != converted) { bitmap.recycle(); bitmap = converted; } } catch (OutOfMemoryError ex) { } } return bitmap; } /** * EXIF정보를 회전각도로 변환하는 메서드 * * @param exifOrientation * EXIF 회전각 * @return 실제 각도 */ private int exifOrientationToDegrees(int exifOrientation) { if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) { return 180; } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) { return 270; } return 0; } /** 원하는 크기의 이미지로 options 설정. */ private Bitmap loadImageWithSampleSize(File file) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(file.getAbsolutePath(), options); int width = options.outWidth; int height = options.outHeight; int longSide = Math.max(width, height); int sampleSize = 1; if (longSide > mImageSizeBoundary) { sampleSize = longSide / mImageSizeBoundary; } options.inJustDecodeBounds = false; options.inSampleSize = sampleSize; options.inPurgeable = true; options.inDither = false; Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options); return bitmap; } /** * mImageSizeBoundary 크기로 이미지 크기 조정. mImageSizeBoundary 보다 작은 경우 resize하지 * 않음. */ private Bitmap resizeImageWithinBoundary(Bitmap bitmap) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); if (width > height) { if (width > mImageSizeBoundary) { bitmap = resizeBitmapWithWidth(bitmap, mImageSizeBoundary); } } else { if (height > mImageSizeBoundary) { bitmap = resizeBitmapWithHeight(bitmap, mImageSizeBoundary); } } return bitmap; } private Bitmap resizeBitmapWithHeight(Bitmap source, int wantedHeight) { if (source == null) return null; int width = source.getWidth(); int height = source.getHeight(); float resizeFactor = wantedHeight * 1f / height; int targetWidth, targetHeight; targetWidth = (int) (width * resizeFactor); targetHeight = (int) (height * resizeFactor); Bitmap resizedBitmap = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, true); return resizedBitmap; } private Bitmap resizeBitmapWithWidth(Bitmap source, int wantedWidth) { if (source == null) return null; int width = source.getWidth(); int height = source.getHeight(); float resizeFactor = wantedWidth * 1f / width; int targetWidth, targetHeight; targetWidth = (int) (width * resizeFactor); targetHeight = (int) (height * resizeFactor); Bitmap resizedBitmap = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, true); return resizedBitmap; } private void copyUriToFile(Uri srcUri, File target) { FileInputStream inputStream = null; FileOutputStream outputStream = null; FileChannel fcin = null; FileChannel fcout = null; try { // 스트림 생성 inputStream = (FileInputStream) getContentResolver() .openInputStream(srcUri); outputStream = new FileOutputStream(target); // 채널 생성 fcin = inputStream.getChannel(); fcout = outputStream.getChannel(); // 채널을 통한 스트림 전송 long size = fcin.size(); fcin.transferTo(0, size, fcout); } catch (Exception e) { e.printStackTrace(); } finally { try { fcout.close(); } catch (IOException ioe) { } try { fcin.close(); } catch (IOException ioe) { } try { outputStream.close(); } catch (IOException ioe) { } try { inputStream.close(); } catch (IOException ioe) { } } } private void cropImage() { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setType("image/*"); List<ResolveInfo> cropToolLists = getPackageManager() .queryIntentActivities(intent, 0); int size = cropToolLists.size(); if (size == 0) { // crop 을 처리할 앱이 없음. 곧바로 처리. doFinalProcess(); } else { intent.setData(Uri.fromFile(getTempImageFile())); intent.putExtra("aspectX", mCropAspectWidth); intent.putExtra("aspectY", mCropAspectHeight); intent.putExtra("output", Uri.fromFile(getTempImageFile())); Intent i = new Intent(intent); ResolveInfo res = cropToolLists.get(0); i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); startActivityForResult(i, REQ_CODE_PICK_CROP); } } }