이미지에서 자유 영역을 지정한 부분을 자르는 예제입니다.
다음 링크에 있는 코드를 사용했습니다.
https://stackoverflow.com/questions/18439246/android-free-cropping-of-image
다음처럼 동작합니다.
1. 처음 실행하면 drawable 폴더에 있는 이미지를 이미지뷰에 보여줍니다.
2. 손가락으로 영역을 그린 후 떼면 다이얼로그가 보입니다.
NON-CROP을 선택하면 지정한 영역 바깥을 남기며, CROP을 선택하면 지정한 영역 내부만 남기게 됩니다.
테스트에선 CROP을 선택했습니다.
3. 지정한 영역 부분만 보여줍니다.
다음 코드를 사용하여 예제를 테스트 할 수 있습니다.
1. MainActivity.java
앱이 실행되면 먼저 실행되는 액티비티로 SomeView 클래스를 뷰로 사용하여 보여줍니다.
package com.tistory.webnautes.image_cropper;
import android.support.v7.app.AppCompatActivity; import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); }
@Override protected void onResume() { super.onResume(); setContentView(new SomeView(MainActivity.this)); } } |
2. SomeView.java
MainActivity에서 보여지는 뷰로써 사용자가 그린 경로와 이미지를 CropActivity로 넘겨줍니다.
package com.tistory.webnautes.image_cropper;
import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.MotionEvent; import android.view.View;
import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List;
public class SomeView extends View implements View.OnTouchListener { private Paint paint; public static List<Point> points; int DIST = 2; boolean flgPathDraw = true;
Point mfirstpoint = null; boolean bfirstpoint = false;
Point mlastpoint = null;
Bitmap bitmap; byte[] byteArray;
Context mContext; int height; int width;
public SomeView(Context c) { super(c);
mContext = c;
DisplayMetrics displayMetrics = new DisplayMetrics(); ((AppCompatActivity)mContext).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); height = displayMetrics.heightPixels; width = displayMetrics.widthPixels;
Bitmap original = BitmapFactory.decodeResource(getResources(), R.drawable.apple); float scale = (float) ((width/(float)original.getWidth()));
int image_w = (int) (original.getWidth()*scale); int image_h = (int) (original.getHeight()*scale);
bitmap = Bitmap.createScaledBitmap(original, image_w, image_h, true);
ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); byteArray = stream.toByteArray();
setFocusable(true); setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStyle(Paint.Style.STROKE); paint.setPathEffect(new DashPathEffect(new float[] { 10, 20 }, 0)); paint.setStrokeWidth(5); paint.setColor(Color.WHITE);
this.setOnTouchListener(this); points = new ArrayList<Point>();
bfirstpoint = false; }
public SomeView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; setFocusable(true); setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(2); paint.setColor(Color.WHITE);
this.setOnTouchListener(this); points = new ArrayList<Point>(); bfirstpoint = false;
}
public void onDraw(Canvas canvas) { canvas.drawBitmap(bitmap, 0, 0, null);
Path path = new Path(); boolean first = true;
for (int i = 0; i < points.size(); i += 2) { Point point = points.get(i); if (first) { first = false; path.moveTo(point.x, point.y); } else if (i < points.size() - 1) { Point next = points.get(i + 1); path.quadTo(point.x, point.y, next.x, next.y); } else { mlastpoint = points.get(i); path.lineTo(point.x, point.y); } } canvas.drawPath(path, paint); }
public boolean onTouch(View view, MotionEvent event) { // if(event.getAction() != MotionEvent.ACTION_DOWN) // return super.onTouchEvent(event);
Point point = new Point(); point.x = (int) event.getX(); point.y = (int) event.getY();
if (flgPathDraw) {
if (bfirstpoint) {
if (comparepoint(mfirstpoint, point)) { // points.add(point); points.add(mfirstpoint); flgPathDraw = false; showcropdialog(); } else { points.add(point); } } else { points.add(point); }
if (!(bfirstpoint)) {
mfirstpoint = point; bfirstpoint = true; } }
invalidate(); Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) { Log.d("Action up*******~~~>>>>", "called"); mlastpoint = point; if (flgPathDraw) { if (points.size() > 12) { if (!comparepoint(mfirstpoint, mlastpoint)) { flgPathDraw = false; points.add(mfirstpoint); showcropdialog(); } } } }
return true; }
private boolean comparepoint(Point first, Point current) { int left_range_x = (int) (current.x - 3); int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3); int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x) && (left_range_y < first.y && first.y < right_range_y)) { if (points.size() < 10) { return false; } else { return true; } } else { return false; }
}
public void fillinPartofPath() { Point point = new Point(); point.x = points.get(0).x; point.y = points.get(0).y;
points.add(point); invalidate(); }
public void resetView() { points.clear(); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.STROKE); flgPathDraw = true; invalidate(); }
private void showcropdialog() { DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent; switch (which) { case DialogInterface.BUTTON_POSITIVE: // Yes button clicked // bfirstpoint = false;
intent = new Intent(mContext, CropActivity.class); intent.putExtra("crop", true); intent.putExtra("image", byteArray); mContext.startActivity(intent); break;
case DialogInterface.BUTTON_NEGATIVE: // No button clicked
intent = new Intent(mContext, CropActivity.class); intent.putExtra("crop", false); intent.putExtra("image", byteArray); mContext.startActivity(intent);
bfirstpoint = false; // resetView();
break; } } };
AlertDialog.Builder builder = new AlertDialog.Builder(mContext); builder.setMessage("Do you Want to save Crop or Non-crop image?") .setPositiveButton("Crop", dialogClickListener) .setNegativeButton("Non-crop", dialogClickListener).show() .setCancelable(false); } }
class Point {
public float dy; public float dx; float x, y;
@Override public String toString() { return x + ", " + y; } } |
3. CropActivity.java
사용자가 지정한 영역을 잘라서 결과를 보여주는 역활을 합니다.
package com.tistory.webnautes.image_cropper;
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.widget.ImageView;
public class CropActivity extends AppCompatActivity {
ImageView compositeImageView; boolean crop;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.cropview);
Bundle extras = getIntent().getExtras(); if (extras != null) { crop = extras.getBoolean("crop"); }
byte[] byteArray = getIntent().getByteArrayExtra("image"); Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
int widthOfscreen = 0; int heightOfScreen = 0;
DisplayMetrics dm = new DisplayMetrics(); try { getWindowManager().getDefaultDisplay().getMetrics(dm); } catch (Exception ex) { } widthOfscreen = dm.widthPixels; heightOfScreen = dm.heightPixels;
compositeImageView = (ImageView) findViewById(R.id.imageview);
Bitmap resultingImage = Bitmap.createBitmap(widthOfscreen, heightOfScreen, bitmap.getConfig());
Canvas canvas = new Canvas(resultingImage); Paint paint = new Paint(); paint.setAntiAlias(true);
Path path = new Path(); for (int i = 0; i < SomeView.points.size(); i++) { path.lineTo(SomeView.points.get(i).x, SomeView.points.get(i).y); } canvas.drawPath(path, paint); if (crop) { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
} else { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); } canvas.drawBitmap(bitmap, 0, 0, paint); compositeImageView.setImageBitmap(resultingImage); } } |
4. cropview.xml
CropActivity 액티비티에서 결과를 보여주기 위해 사용하는 레이아웃입니다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="match_parent" android:layout_width="match_parent">
<ImageView android:id="@+id/imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout> |
5. AndroidManifest.xml 매니페스트 파일에 CropActivity 액티비티를 추가합니다.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.tistory.webnautes.image_cropper">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".CropActivity"></activity> </application>
</manifest> |
최초 작성 2019. 3. 5
문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.
제가 쓴 책도 한번 검토해보세요 ^^