package com.linseykate.findingfido; /** * Adapted from following sites: * http://android-er.blogspot.com/2013/09/detect-touch-and-draw-rect-on-bitmap.html * http://code.tutsplus.com/tutorials/capture-and-crop-an-image-with-the-device-camera--mobile-11458 * http://arthurhub.github.io/Android-Image-Cropper/ * * Allows user to take or upload picture * based on button pressed from previous activity; * Also takes care of cropping the picture; * Allows user to draw boxes on image; * Provides arrows to adjust box */ import android.content.ActivityNotFoundException; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.net.Uri; import android.provider.MediaStore; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; public class DrawingActivity extends AppCompatActivity { private static final String TAG = DrawingActivity.class.getSimpleName(); //for debugging purposes int squareCount = 1; //which square is the user drawing? Button btnSaveImage; Button btnUndoImage; TextView textSource; TextView helpText; ImageView imageResult, imageDrawingPane; //For drawing the squares Bitmap bitmap; Bitmap tempBitmap; Bitmap bitmapMaster; Canvas canvasMaster; Bitmap bitmapDrawingPane; Canvas canvasDrawingPane; projectPt startPt; //For algorithm coordinates int startX, startY, finishX, finishY; //keep track of camera capture intent final int CAMERA_CAPTURE = 1; //keep track of cropping intent final int PIC_CROP = 2; //captured picture uri private Uri picUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_drawing); btnSaveImage = (Button) findViewById(R.id.loadimage); btnUndoImage = (Button) findViewById(R.id.undoimage); textSource = (TextView) findViewById(R.id.sourceuri); helpText = (TextView) findViewById(R.id.helptext); imageResult = (ImageView) findViewById(R.id.result); imageDrawingPane = (ImageView) findViewById(R.id.drawingpane); //Arrow buttons in bottom right corner of screen FloatingActionButton fabLeft = (FloatingActionButton) findViewById(R.id.fabLeft); FloatingActionButton fabRight = (FloatingActionButton) findViewById(R.id.fabRight); FloatingActionButton fabUp = (FloatingActionButton) findViewById(R.id.fabUp); FloatingActionButton fabDown = (FloatingActionButton) findViewById(R.id.fabDown); btnSaveImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(squareCount < 4 ) { if(squareCount == 3) btnSaveImage.setText("Finish"); switch (squareCount){ //Head case 1: ((GlobalVariables) getApplication()).setHeadStartX(startX); ((GlobalVariables) getApplication()).setHeadStartY(startY); ((GlobalVariables) getApplication()).setHeadFinishX(finishX); ((GlobalVariables) getApplication()).setHeadFinishY(finishY); Log.d(TAG, "Head = "+startX+":"+startY+"/"+finishX+":"+finishY); break; //Left Eye case 2: ((GlobalVariables) getApplication()).setlEyeStartX(startX); ((GlobalVariables) getApplication()).setlEyeStartY(startY); ((GlobalVariables) getApplication()).setlEyeFinishX(finishX); ((GlobalVariables) getApplication()).setlEyeFinishY(finishY); Log.d(TAG, "lEye = " + startX + ":" + startY + "/" + finishX + ":" + finishY); break; //Right Eye case 3: ((GlobalVariables) getApplication()).setrEyeStartX(startX); ((GlobalVariables) getApplication()).setrEyeStartY(startY); ((GlobalVariables) getApplication()).setrEyeFinishX(finishX); ((GlobalVariables) getApplication()).setrEyeFinishY(finishY); Log.d(TAG, "rEye = " + startX + ":" + startY + "/" + finishX + ":" + finishY); break; } squareCount++; createDrawable(bitmap, squareCount);//clear the previous square } else{ RelativeLayout temp = ((GlobalVariables) getApplication()).getHiddenSection(); temp.setVisibility(View.VISIBLE); //show slider bar and radio buttons ImageView tempDog = ((GlobalVariables) getApplication()).getDogPic(); tempBitmap = Bitmap.createScaledBitmap(bitmap, 150, 150, true); //scale image down tempDog.setImageBitmap(tempBitmap); //set the image //Nose ((GlobalVariables) getApplication()).setNoseStartX(startX); ((GlobalVariables) getApplication()).setNoseStartY(startY); ((GlobalVariables) getApplication()).setNoseFinishX(finishX); ((GlobalVariables) getApplication()).setNoseFinishY(finishY); Log.d(TAG, "Nose = " + startX + ":" + startY + "/" + finishX + ":" + finishY); finish(); //return to MainActivity } } }); btnUndoImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { createDrawable(bitmap, squareCount); //erase square } }); //shift box left fabLeft.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { createDrawable(bitmap, squareCount); startX--;finishX--; //textSource.setText(startX + ":" + startY + "/" + finishX + " : " + finishY); drawFeatheredOnBitMap(); } }); //shift box right fabRight.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { createDrawable(bitmap, squareCount); startX++;finishX++; //textSource.setText(startX + ":" + startY + "/" + finishX + " : " + finishY); drawFeatheredOnBitMap(); } }); //shift box up fabUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { createDrawable(bitmap, squareCount); startY--;finishY--; //textSource.setText(startX + ":" + startY + "/" + finishX + " : " + finishY); drawFeatheredOnBitMap(); } }); //shift box down fabDown.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { createDrawable(bitmap, squareCount); startY++;finishY++; //textSource.setText(startX + ":" + startY + "/" + finishX + " : " + finishY); drawFeatheredOnBitMap(); } }); //did the user want to take or upload a photo? int id = getIntent().getIntExtra("button_id", 0); Intent intent; if(id == R.id.btnUpload){ //launch gallery intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent, CAMERA_CAPTURE); }else if(id == R.id.btnTake){ //launch camera intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, CAMERA_CAPTURE); } imageResult.setOnTouchListener(new View.OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { //draw the box on touch int action = event.getAction(); int x = (int) event.getX(); int y = (int) event.getY(); switch(action){ case MotionEvent.ACTION_DOWN: //textSource.setText("ACTION_DOWN- " + x + " : " + y); startPt = projectXY((ImageView)v, bitmapMaster, x, y); break; case MotionEvent.ACTION_MOVE: //textSource.setText("ACTION_MOVE- " + x + " : " + y); drawOnRectProjectedBitMap((ImageView)v, bitmapMaster, x, y); break; case MotionEvent.ACTION_UP: //textSource.setText("ACTION_UP- " + x + " : " + y); drawOnRectProjectedBitMap((ImageView)v, bitmapMaster, x, y); finalizeDrawing(); break; } /* * Return 'true' to indicate that the event have been consumed. * If auto-generated 'false', your code can detect ACTION_DOWN only, * cannot detect ACTION_MOVE and ACTION_UP. */ return true; }}); } class projectPt{ int x; int y; projectPt(int tx, int ty){ x = tx; y = ty; } } private projectPt projectXY(ImageView iv, Bitmap bm, int x, int y){ if(x<0 || y<0 || x > iv.getWidth() || y > iv.getHeight()){ //outside ImageView return null; }else{ int projectedX = (int)((double)x * ((double)bm.getWidth()/(double)iv.getWidth())); int projectedY = (int)((double)y * ((double)bm.getHeight()/(double)iv.getHeight())); return new projectPt(projectedX, projectedY); } } private void drawOnRectProjectedBitMap(ImageView iv, Bitmap bm, int x, int y){ if(x<0 || y<0 || x > iv.getWidth() || y > iv.getHeight()){ //outside ImageView return; }else{ int projectedX = (int)((double)x * ((double)bm.getWidth()/(double)iv.getWidth())); int projectedY = (int)((double)y * ((double)bm.getHeight()/(double)iv.getHeight())); //clear canvasDrawingPane canvasDrawingPane.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.WHITE); paint.setStrokeWidth(3); canvasDrawingPane.drawRect(startPt.x, startPt.y, projectedX, projectedY, paint); imageDrawingPane.invalidate(); startX = startPt.x; startY = startPt.y; finishX = projectedX; finishY = projectedY; //textSource.setText(startX + ":" + startY + "/" + finishX + " : " + finishY); } } //for shifting the box by one pixel on arrow tap private void drawFeatheredOnBitMap(){ Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.WHITE); paint.setStrokeWidth(3); canvasDrawingPane.drawRect(startX, startY, finishX, finishY, paint); imageDrawingPane.invalidate(); } private void finalizeDrawing(){ canvasMaster.drawBitmap(bitmapDrawingPane, 0, 0, null); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { //user is returning from capturing an image using the camera if(requestCode == CAMERA_CAPTURE){ //get the Uri for the captured image picUri = data.getData(); //carry out the crop operation performCrop(); } //user is returning from cropping the image else if(requestCode == PIC_CROP){ //get the returned data Bundle extras = data.getExtras(); //get the cropped bitmap bitmap = extras.getParcelable("data"); //this is the one I want to store createDrawable(bitmap, squareCount); } } } /** * Helper method to carry out crop operation */ private void performCrop(){ //take care of exceptions try { //call the standard crop action intent (the user device may not support it) Intent cropIntent = new Intent("com.android.camera.action.CROP"); //indicate image type and Uri cropIntent.setDataAndType(picUri, "image/*"); //set crop properties cropIntent.putExtra("crop", "true"); //indicate aspect of desired crop cropIntent.putExtra("aspectX", 1); cropIntent.putExtra("aspectY", 1); //indicate output X and Y cropIntent.putExtra("outputX", 256); cropIntent.putExtra("outputY", 256); //retrieve data on return cropIntent.putExtra("return-data", true); //start the activity - we handle returning in onActivityResult startActivityForResult(cropIntent, PIC_CROP); } //respond to users whose devices do not support the crop action catch(ActivityNotFoundException anfe){ //display an error message String errorMessage = "Whoops - your device doesn't support the crop action!"; Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT); toast.show(); } } private void createDrawable(Bitmap bitmap, int option){ switch (option) { case 1: helpText.setText("Draw a box around the head"); break; case 2: helpText.setText("Draw a box around the left eye"); break; case 3: helpText.setText("Draw a box around the right eye"); break; case 4: helpText.setText("Draw a box around the nose"); break; } tempBitmap = Bitmap.createScaledBitmap(bitmap, 800, 800, true); //enlarging for squares Bitmap.Config config = Bitmap.Config.ARGB_8888; //bitmapMaster is Mutable bitmap bitmapMaster = Bitmap.createBitmap( tempBitmap.getWidth(), tempBitmap.getHeight(), config); canvasMaster = new Canvas(bitmapMaster); canvasMaster.drawBitmap(tempBitmap, 0, 0, null); imageResult.setImageBitmap(bitmapMaster); //Create bitmap of same size for drawing bitmapDrawingPane = Bitmap.createBitmap( tempBitmap.getWidth(), tempBitmap.getHeight(), config); canvasDrawingPane = new Canvas(bitmapDrawingPane); imageDrawingPane.setImageBitmap(bitmapDrawingPane); } }