web-dev-qa-db-ja.com

カスタムAndroid画像の切り抜き

私が書いたこのコードを共有したいだけです。カスタムクロップアクティビティを検索しようとしましたが、カスタムクロップまたはフリーハンドクロップアクティビティの質問にもかかわらず、それらのほとんどはデフォルトの「com.Android.camera.action.CROP」につながります。とにかく、私は自分のために1つ作っただけで、うまくいけば皆さんの助けになるでしょう。

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

私がしたことは、ImageViewを拡張し、トリミング機能を追加したことです。とても使いやすいです。クラスが保存されたら、このようなレイアウトで使用します。

    <"your package name".CropView
        Android:id="@+id/image_preview"
        Android:layout_width="fill_parent"
        Android:layout_height="match_parent" />

それでおしまい!それが役に立てば幸い!問題が発生した場合は、お気軽にお問い合わせください:)

17
Seph Remotigue

試してみてください:

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);

    setContentView(R.layout.crop_layout);


    myCropView = new CropView(this);

    Uri imageUri = getIntent().getExtras().getParcelable("path");

    b = (BitmapDrawable) BitmapDrawable.createFromPath(imageUri.getPath()); 

    myCropView.setImageURI(imageUri);
}

(あなたの質問への編集から取られました。)

2
TheHippo

thehippoに感謝します...しかし、私はレイアウトによってビューを見つけることを解決しました

Uri imageUri = getIntent().getExtras().getParcelable("path");
    b = (BitmapDrawable) BitmapDrawable.createFromPath(getRealPathFromURI(imageUri));
    myCropView = (CropView) findViewById(R.id.image_preview);
    myCropView.setBackground(b);

しかし、今はタッチイベントを処理できません。画面に触れても長方形は静止します...

編集:わかりました、私はそれを機能させました。しかし現在、長方形は画像全体ではなく、より小さな領域内でのみ移動します。ここに何か問題があると思います

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(getBackground().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
    imageScaledHeight = Math.round(getBackground().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;
}

コードを動作させるために少し変更を加えました:getDrawableの代わりにgetBackground()

編集2:OK iveはそれを手に入れました、私はこれを間違った方法でやっていた。あなたのコードは良いです。画像を設定するには、view.setImageDrawable()の代わりにview.seBackground()...を使用していました。これですべてが機能します。たぶん、長方形のスケーリングを実行するより大きな領域を作成できるかどうかだけを確認します

0
Vahn84

これをサポートするライブラリを見つけました:SimpleCropView from https://Android-arsenal.com/details/1/2366 。一般的に、私はそれをお勧めしません、そのパフォーマンスはネイティブのAndroidトリミングアプリからはほど遠いです。

私はそれを使ってみました、そして私の考えは次のとおりです:

  • アプリに実装するのは本当に簡単で、既存のアプリで切り抜きと回転の機能を動作させるのに約5分かかりました

  • トリミング領域のサイズ変更は非常に遅いので、ユーザーに見られたくありません。

更新:実際、Githubでjdamcd/Android-cropとして本当に良い解決策を見つけました: https://github.com/jdamcd/Android-crop 要約:

  • アプリでの使用は非常に簡単です

  • ネイティブギャラリーアプリのコードを使用しているため、高速です

  • あなたがそれで遊んで時間を過ごしたいならば、カスタマイズ可能です。デフォルトでは、トリミングを行うアクティビティが提供されます。それをあなた自身の活動に統合したいのなら、それは少し時間がかかります。 (私のプロジェクトでは、それを統合したいと思っていましたが、将来的には統合する予定ですが、今のところ、別のアクティビティで十分です)。

これがいくつかの洞察を提供することを願っています!

0
MMagician