自定义裁剪图像无法正常工作

时间:2013-07-10 06:25:11

标签: android

我使用以下代码在android中执行图像裁剪。

但我收到了错误的结果。我正在获得非常缩放的图片,我认为我的代码中存在错误

代码:

   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();
    }
}

我尝试裁剪的图像是

enter image description here

预期的图像是矩形框中的图像,但我得到的图像非常放大

结果图片

enter image description here

我如何解决这个问题,我试过改变一些代码,但没有找到任何结果。

另一个问题是,通过使用这个矩形框,我只能在矩形形状中裁剪图像,是否有可能裁剪任何我想要的形状的图像。

我在其中一个应用程序(文档扫描程序跟踪版本)中观察到这一点,用户可以使用相同的矩形框裁剪一些不规则形状的图像。

如何实现这一结果?

请建议

由于

1 个答案:

答案 0 :(得分:3)

我已经实施了 Android Crop Image 库。这对我很有帮助。它具有以下功能。

  1. 捏缩放以裁剪图像的非常小部分
  2. 可在图像上调整大小的矩形
  3. 高效的图像裁剪结果返回到您的活动
  4. 轮换设施
  5. 修改

    结果,

    @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");
    }
    

    再修改一次

    private void handleFace(FaceDetector.Face f)文件中搜索CropImage方法。将以下代码放在HighlightView hv = new HighlightView(mImageView);这一行之后的方法中。

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

    还在private void makeDefault()方法中添加上述代码。

     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
    }
    

    由于加速的某些原因,这是必要的。如果您在“GINGERBREAD”和“View.LAYOUT_TYPE_SOFTWARE”中收到任何错误,请将您的API版本更改为4.0及更高版本。

    确保您有如下活动注册

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

    注意

    此示例应用程序具有脏布局。你需要弄清楚自己。这是库项目,因此从项目属性中删除“is library”以运行该示例代码。