简体   繁体   中英

Custom Cropping of image is not working correctly

I am using the following code to perform the cropping of image in android.

But I am getting the wrong results. I am getting very zoom pictures,i think there is something wrong in my code

code:

   package net.londatiga.android;

import java.io.ByteArrayOutputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

public class CropView extends ImageView {

    Paint paint = new Paint();
    private int initial_size = 300;
    private static Point leftTop, rightBottom, center, previous;

    private static final int DRAG= 0;
    private static final int LEFT= 1;
    private static final int TOP= 2;
    private static final int RIGHT= 3;
    private static final int BOTTOM= 4;

    private int imageScaledWidth,imageScaledHeight;
    // Adding parent class constructors   
    public CropView(Context context) {
        super(context);
        initCropView();
    }

    public CropView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        initCropView();
    }

    public CropView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initCropView();
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        if(leftTop.equals(0, 0))
            resetPoints();
        canvas.drawRect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y, paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int eventaction = event.getAction();
        switch (eventaction) { 
            case MotionEvent.ACTION_DOWN:
                previous.set((int)event.getX(), (int)event.getY());
                break; 
            case MotionEvent.ACTION_MOVE: 
                if(isActionInsideRectangle(event.getX(), event.getY())) {
                    adjustRectangle((int)event.getX(), (int)event.getY());
                    invalidate(); // redraw rectangle
                    previous.set((int)event.getX(), (int)event.getY());
                }
                break; 
            case MotionEvent.ACTION_UP: 
                previous = new Point();
                break;
        }         
        return true;
    }

    private void initCropView() {
        paint.setColor(Color.YELLOW);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(5);  
        leftTop = new Point();
        rightBottom = new Point();
        center = new Point();
        previous = new Point();
    }

    public void resetPoints() {
        center.set(getWidth()/2, getHeight()/2);
        leftTop.set((getWidth()-initial_size)/2,(getHeight()-initial_size)/2);
        rightBottom.set(leftTop.x+initial_size, leftTop.y+initial_size);
    }

    private static boolean isActionInsideRectangle(float x, float y) {
        int buffer = 10;
        return (x>=(leftTop.x-buffer)&&x<=(rightBottom.x+buffer)&& y>=(leftTop.y-buffer)&&y<=(rightBottom.y+buffer))?true:false;
    }

    private boolean isInImageRange(PointF point) {
        // Get image matrix values and place them in an array
        float[] f = new float[9];
        getImageMatrix().getValues(f);

        // Calculate the scaled dimensions
        imageScaledWidth = Math.round(getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
        imageScaledHeight = Math.round(getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]);

        return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false;
    }

    private void adjustRectangle(int x, int y) {
        int movement;
        switch(getAffectedSide(x,y)) {
            case LEFT:
                movement = x-leftTop.x;
                if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
                    leftTop.set(leftTop.x+movement,leftTop.y+movement);
                break;
            case TOP:
                movement = y-leftTop.y;
                if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
                    leftTop.set(leftTop.x+movement,leftTop.y+movement);
                break;
            case RIGHT:
                movement = x-rightBottom.x;
                if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
                    rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
                break;
            case BOTTOM:
                movement = y-rightBottom.y;
                if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
                    rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
                break;      
            case DRAG:
                movement = x-previous.x;
                int movementY = y-previous.y;
                if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movementY)) && isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movementY))) {
                    leftTop.set(leftTop.x+movement,leftTop.y+movementY);
                    rightBottom.set(rightBottom.x+movement,rightBottom.y+movementY);
                }
                break;
        }
    }

    private static int getAffectedSide(float x, float y) {
        int buffer = 10;
        if(x>=(leftTop.x-buffer)&&x<=(leftTop.x+buffer))
            return LEFT;
        else if(y>=(leftTop.y-buffer)&&y<=(leftTop.y+buffer))
            return TOP;
        else if(x>=(rightBottom.x-buffer)&&x<=(rightBottom.x+buffer))
            return RIGHT;
        else if(y>=(rightBottom.y-buffer)&&y<=(rightBottom.y+buffer))
            return BOTTOM;
        else
            return DRAG;
    }

    public byte[] getCroppedImage() {
        BitmapDrawable drawable = (BitmapDrawable)getDrawable();
        float x = leftTop.x-center.x+(drawable.getBitmap().getWidth()/2);
        float y = leftTop.y-center.y+(drawable.getBitmap().getHeight()/2);
        Bitmap cropped = Bitmap.createBitmap(drawable.getBitmap(),(int)x,(int)y,(int)rightBottom.x-(int)leftTop.x,(int)rightBottom.y-(int)leftTop.y);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        cropped.compress(Bitmap.CompressFormat.PNG, 100, stream);
        return stream.toByteArray();
    }
}

The image which I tried to do crop is

在此输入图像描述

The expected image is what is there in the rectangular box but I am getting very zoomed image

resulted image

在此输入图像描述

How can I solve this issue,I tried by changing some code but didnt find any results.

And Another issue is that by using this Rectangle box I can able to crop images only in Rectangle shapes, is there any possibility to crop image in any shape which I want.

I have observed this in one of the app ( Document Scanner trail version ),in which user can able to crop image in some irregular shapes using the same rectangle box.

How can I achieve this result?

Please suggest

Thanks

I have implemented Android Crop Image library. Which is very helpful to me. It has following features.

  1. Pinch zoom to crop very small portion of image
  2. Rectangle which is resizable over image
  3. Efficient Image Crop result back to your activity
  4. Rotation facility

Edit

For result,

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

     if (data != null) if (data.getParcelableExtra("data") != null)
     Bitmap bitmap = data.getParcelableExtra("data");
}

One more Edit

Search private void handleFace(FaceDetector.Face f) method in CropImage file. Put following code inside method after HighlightView hv = new HighlightView(mImageView); this line.

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
    mImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Also add above code in private void makeDefault() method.

 private void makeDefault(){
    HighlightView hv = new HighlightView(mImageView);

    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
        mImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }
     //rest of code
}

Due to some reason of acceleration, this is necessary. If you get any error in "GINGERBREAD" and "View.LAYOUT_TYPE_SOFTWARE", then change your API version to 4.0 and above.

Make sure you have activity registration like below,

<activity
        android:name="com.android.camera.CropImage"
        android:hardwareAccelerated="false" />

Note

This sample application has dirty layout. You need to make clear yourself. This is library project, so remove "is library" from project property to run that sample code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM