28

I would like to Scale, Move, Resize Image. I would like to surround the image with Indicators which guide user what operation these indicators perform i.e. Moving, Rotating, Scaling.

enter image description here

I've tried

  • Scaling - but it only crops down. No chance to increase length and height of image.
  • Rotate - achieved but via inserting manual degrees. That's not a good option in here.
  • Moving - as I'm achieving drag on Api < 11. So little bit of difficult. Still no hope in here.

Is there any library which can do me simple image edit [Move, Scale, Rotate]?

halfer
  • 19,824
  • 17
  • 99
  • 186
Vikalp Patel
  • 10,669
  • 6
  • 61
  • 96
  • @Pragnani Nah not yet. Increasing the size of image is bugging me as we can't add more size than actual image size insite `matrix.postScale()` – Vikalp Patel Feb 13 '13 at 08:10

8 Answers8

6

You can use Matrix transaformation to achieve rotating, scaling, and moving....I hope this will help you....

for rotating

Matrix matrix = new Matrix();
    matrix.postRotate(90);

for scaling

 matrix.postScale(scaleWidth, scaleHeight);

create new bitmap without changing the original one...like this

Bitmap bmp2 = Bitmap.createBitmap(bmp1, 0, 0, pow2, pow2, matrix, true);
Pragnani
  • 20,075
  • 6
  • 49
  • 74
  • Yeah Surely I can use Matrix Transformation. I've tried on rotation by adding matrix. But what i need is input to matrix from the indicator. Any help of fetching input from indicator to Matrix would be most welcomes. – Vikalp Patel Feb 10 '13 at 16:59
  • @VikalpPatel you will get x and y co ordinates of the image when you set onTouchListener to it...based on the movement you can scale, rotate and move – Pragnani Feb 10 '13 at 17:04
  • 1
    yeah but in `matrix.postScale()` we can't add size more than image actual size. That'z the problem which bugs me out. – Vikalp Patel Feb 10 '13 at 17:14
4

Just check out this image cropping reference :

http://www.londatiga.net/featured-articles/how-to-select-and-crop-image-on-android/

For image rotation, just refer to this example; this sample code represents the rotation of image dynamically:

http://android-er.blogspot.in/2010/07/rotate-bitmap-image-using-matrix.html

This link is also useful for image crop, rotate and scale:

https://github.com/Yalantis/uCrop

halfer
  • 19,824
  • 17
  • 99
  • 186
Nipun Gogia
  • 1,846
  • 1
  • 11
  • 17
  • The first link uses a `crop intent` that is specific to `AOSP camera app`, which is not present in all devices, so using that method will crash. Use some library like https://github.com/lvillani/android-cropimage, which covers it all. – Darpan Jul 16 '15 at 12:12
4

Using Library : StickerView

Its a 3rd Party Library which gives exactly what i was looking for.

WorkAround :

Still these answer is half of what I've asked for in OP. Means It ain't surronded by some specific Indicator. I'm still searching how to wrap ImageView with indicators and use them for Translate & Resize.

Initilization of Variables inside Activity important for Translate & Resize ImageView

public static final int DRAG = 1;
public static final int NONE = 0;
private static final String TAG = "Touch";
public static final int ZOOM = 2;
public static PointF mid = new PointF();
public static int mode = 0;
float d = 0.0F;
Matrix savedMatrix = new Matrix();
Matrix matrix = new Matrix();
PointF start = new PointF();

Setting ImageView to scaleType - Matrix

iv = new ImageView(this);
iv.setPadding(10, 10, 25, 25);
iv.setScaleType(ImageView.ScaleType.MATRIX);

iv.setOnTouchListener(t);

Adding onTouch Listener to ImageView which uses

  • 1 Finger for Translate - Drag
  • 2 Finger for Zoom - Resize {Pinch To Zoom}

    View.OnTouchListener t = new View.OnTouchListener()
    {
    public boolean onTouch(View paramView, MotionEvent event)
    {
      ImageView view = (ImageView)paramView;
      switch (event.getAction() & MotionEvent.ACTION_MASK)
      {
      case MotionEvent.ACTION_DOWN:
    
          savedMatrix.set(matrix);
          start.set(event.getX(), event.getY());
          Log.d(TAG, "mode=DRAG" );
          mode = DRAG;
          break;
      case MotionEvent.ACTION_POINTER_DOWN:
    
          oldDist = spacing(event);
          Log.d(TAG, "oldDist=" + oldDist);
          if (oldDist > 10f) {
    
              savedMatrix.set(matrix);
              midPoint(mid, event);
              mode = ZOOM;
              Log.d(TAG, "mode=ZOOM" );
          }
          break;
    
      case MotionEvent.ACTION_MOVE:
    
          if (mode == DRAG) {
    
              matrix.set(savedMatrix);
              matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
          }
          else if (mode == ZOOM) {
    
              float newDist = spacing(event);
              Log.d(TAG, "newDist=" + newDist);
              if (newDist > 10f) {
    
                  matrix.set(savedMatrix);
                  float scale = newDist / oldDist;
                  matrix.postScale(scale, scale, mid.x, mid.y);
              }
          }
          break;
    
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_POINTER_UP:
    
          mode = NONE;
          Log.d(TAG, "mode=NONE" );
          break;
      }  
      view.setImageMatrix(matrix);
      return true;
    
    }
    
     private void midPoint(PointF point, MotionEvent event) {
    
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }
    
          private float spacing(MotionEvent event) {
          float x = event.getX(0) - event.getX(1);
          float y = event.getY(0) - event.getY(1);
          return FloatMath.sqrt(x * x + y * y);
          }
         };
    
Vikalp Patel
  • 10,669
  • 6
  • 61
  • 96
3

I recently tried the same thing but ended up using a library since it covered a lot more edge cases. This is a great, and pretty widely used library:

http://code.google.com/p/android-multitouch-controller/

Nick
  • 6,375
  • 5
  • 36
  • 53
2

I think I can help you with the rotation part. I recently made an android wheel menu library. It tracks user's hand motion and rotates the imageview accordingly. You can check out the source to see how I did it here:

https://github.com/anupcowkur/Android-Wheel-Menu

Anup Cowkur
  • 20,443
  • 6
  • 51
  • 84
  • Thanks brother for your rotation library. I'll check it out ASAP!! – Vikalp Patel Feb 18 '13 at 08:20
  • This library is nice.. But when i create an image view in java file and use this library to rotate the image, i am unable to see the rotation. Can you help me in this one? – G_S May 29 '13 at 17:47
  • @G_S If everything is set up according to the instructions provided, then it should work perfectly without any problems. – Anup Cowkur May 31 '13 at 05:26
  • I created an object and associated it with my imageview. But I am unable to rotate it. Can i know where are the instructions – G_S May 31 '13 at 08:40
  • This is what i tried but i am unable to rotate the image LinearLayout layout = (LinearLayout)findViewById(R.id.mainLayout); ImageView wheel_image = new ImageView(this); wheel_image.setImageResource(R.drawable.wheel); final WheelMenu wm = new WheelMenu(MainActivity.this, 12, R.drawable.wheel, wheel_image, true); layout.addView(wheel_image); – G_S Jun 01 '13 at 20:01
2

I know this is not an answer but it's worth mentioning.

Take a look at this project. I intend to put it on GitHub but it is not done yet (at all).

There is a button to rotate the image. I am still working on the "save". Many of the classes are taken from the Android source thanks to Lorenzo Villani's project

Add to your project's manifest:

    <activity
        android:name="mobi.sherif.camera.CropImage"
        android:hardwareAccelerated="false"
        android:screenOrientation="portrait" >

Call the activity using:

Intent intent = new Intent(mContext, CropImage.class);
intent.setData(uri);
startActivityForResult(intent, S.request.cropimage);

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
1

Bitmap rotation

Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight, config);
Canvas canvas = new Canvas(targetBitmap);
Matrix matrix = new Matrix();
matrix.setRotate(mRotation,source.getWidth()/2,source.getHeight()/2);
canvas.drawBitmap(source, matrix, new Paint());

Image Scaling Scaling

AssetManager assetManager = context.getAssets();
InputStream imageIn;
String imgPath = "test.png";
Bitmap image;
try {
    imageIn = assetManager.open(imgPath, AssetManager.ACCESS_BUFFER);
    image = BitmapFactory.decodeStream(imageIn);
} catch (IOException e) {

}
//TODO: calculate width and height to fill or fit screen
image = Bitmap.createScaledBitmap(image, width, height, true);

Image moving Image in Canvas with touch events

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

public class ImgView extends View {

private static final int INVALID_POINTER_ID = -1;

    private Drawable mImage;
    private float mPosX;
    private float mPosY;

    private float mLastTouchX;
    private float mLastTouchY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    public ImgView(Context context) {
        this(context, null, 0);
    mImage = getResources().getDrawable(R.drawable.imagename);

        mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
    }

    public ImgView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ImgView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
            final float x = ev.getX();
            final float y = ev.getY();

            mLastTouchX = x;
            mLastTouchY = y;
            mActivePointerId = ev.getPointerId(0);
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float y = ev.getY(pointerIndex);

            // Only move if the ScaleGestureDetector isn't processing a gesture.
            if (!mScaleDetector.isInProgress()) {
                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;

                invalidate();
            }

            mLastTouchX = x;
            mLastTouchY = y;

            break;
        }

        case MotionEvent.ACTION_UP: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_POINTER_UP: {
            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = ev.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mLastTouchX = ev.getX(newPointerIndex);
                mLastTouchY = ev.getY(newPointerIndex);
                mActivePointerId = ev.getPointerId(newPointerIndex);
            }
            break;
        }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        mImage.draw(canvas);
        canvas.restore();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));

            invalidate();
            return true;
        }
    }

}
Community
  • 1
  • 1
Rohit
  • 6,941
  • 17
  • 58
  • 102
1

You can https://github.com/siddhpuraamitr/MultitouchWithDynamicAddandRemove try this code in your project

Nirav Dhanani
  • 45
  • 1
  • 9