반응형


이미지에서 자유 영역을 지정한 부분을 자르는 예제입니다.


다음 링크에 있는 코드를 사용했습니다.

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





반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts