I am making an application with a coloring book. I found the byronsanchez / coloring-book-android library using which I can make dye. However, I need to implement scaling for the same. I used ScaleImageView for scaling purposes.
The problem that I am facing is that when I enlarge the image, I cannot paint in certain areas of the image. When the image does not scale, it detects a delicate touch for different areas, but after scaling it fills the color to another area when you touch the area.
I was looking for some solutions, but I cannot figure out how to implement it in my code. Here is one of the answers that I met when I was looking for a solution. I think I already have the scaling functions in my code, but still it does not work.
Please provide me some examples with a little explanation. I'm really stuck with this, hope to get help here, thanks !!!
Here is my code where I fill in the colors in a bitmap:
@Override public boolean onTouch(View paramView, MotionEvent event) { try { int action = event.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: //ScaleImageView img = (ScaleImageView) findViewById(R.id.iv_coloring_figure); BitmapDrawable drawable = (BitmapDrawable) mImage.getDrawable(); bmp = drawable.getBitmap(); Rect imageBounds = new Rect(); mImage.getDrawingRect(imageBounds); // original height and width of the bitmap int intrinsicHeight = drawable.getIntrinsicHeight(); int intrinsicWidth = drawable.getIntrinsicWidth(); // height and width of the visible (scaled) image int scaledHeight = imageBounds.height(); int scaledWidth = imageBounds.width(); // Find the ratio of the original image to the scaled image Should normally be equal unless a disproportionate scaling (eg fitXY) is used. float heightRatio = (float) intrinsicHeight / scaledHeight; float widthRatio = (float) intrinsicWidth / scaledWidth; // do whatever magic to get your touch point // MotionEvent event; // get the distance from the left and top of the image bounds float scaledImageOffsetX = event.getX() - imageBounds.left; float scaledImageOffsetY = event.getY() - imageBounds.top; // scale these distances according to the ratio of your scaling // For example, if the original image is 1.5x the size of the scaled image, and your offset is (10, 20), your original image offset values should be (15, 30). int originalImageOffsetX = Math.round(scaledImageOffsetX * widthRatio); int originalImageOffsetY = Math.round(scaledImageOffsetY * heightRatio); int oldColor = bmp.getPixel(originalImageOffsetX, originalImageOffsetY); arrX.add(originalImageOffsetX); arrY.add(originalImageOffsetY); Log.e("arrX", "originalImageOffsetX is " + arrX); Log.e("arrY", "originalImageOffsetY is " + arrY); index = arrX.size(); int newColor = 0; Log.e("sel", "sel color"+selColor); if(selColor == null) { Toast.makeText(getApplicationContext(), "Please select a color to fill!", Toast.LENGTH_LONG).show(); } newColor = Color.parseColor(selColor); if (oldColor != newColor && oldColor != Color.BLACK) { FloodFill floodfill = new FloodFill(bmp, oldColor, newColor); floodfill.fill(originalImageOffsetX, originalImageOffsetY); mImage.invalidate(); } break; default: break; } } catch (Exception e) { e.printStackTrace();; } return false; }
and here is the code that I use to increase.
public class ScaleImageView extends ImageView implements OnTouchListener { private Context mContext; private float MAX_SCALE = 2f; private Matrix mMatrix; private final float[] mMatrixValues = new float[9]; // display width height. private int mWidth; private int mHeight; private int mIntrinsicWidth; private int mIntrinsicHeight; private float mScale; private float mMinScale; private float mPrevDistance; private boolean isScaling; private int mPrevMoveX; private int mPrevMoveY; private GestureDetector mDetector; String TAG = "ScaleImageView"; public ScaleImageView(Context context, AttributeSet attr) { super(context, attr); this.mContext = context; initialize(); } public ScaleImageView(Context context) { super(context); this.mContext = context; initialize(); } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); this.initialize(); } @Override public void setImageResource(int resId) { super.setImageResource(resId); this.initialize(); } private void initialize() { this.setScaleType(ScaleType.MATRIX); this.mMatrix = new Matrix(); Drawable d = getDrawable(); if (d != null) { mIntrinsicWidth = d.getIntrinsicWidth(); mIntrinsicHeight = d.getIntrinsicHeight(); setOnTouchListener(this); } mDetector = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { maxZoomTo((int) e.getX(), (int) e.getY()); cutting(); return super.onDoubleTap(e); } }); } @Override protected boolean setFrame(int l, int t, int r, int b) { mWidth = r - l; mHeight = b - t; mMatrix.reset(); int r_norm = r - l; mScale = (float) r_norm / (float) mIntrinsicWidth; int paddingHeight = 0; int paddingWidth = 0; // scaling vertical if (mScale * mIntrinsicHeight > mHeight) { mScale = (float) mHeight / (float) mIntrinsicHeight; mMatrix.postScale(mScale, mScale); paddingWidth = (r - mWidth) / 2; paddingHeight = 0; // scaling horizontal } else { mMatrix.postScale(mScale, mScale); paddingHeight = (b - mHeight) / 2; paddingWidth = 0; } mMatrix.postTranslate(paddingWidth, paddingHeight); setImageMatrix(mMatrix); mMinScale = mScale; zoomTo(mScale, mWidth / 2, mHeight / 2); cutting(); return super.setFrame(l, t, r, b); } protected float getValue(Matrix matrix, int whichValue) { matrix.getValues(mMatrixValues); return mMatrixValues[whichValue]; } protected float getScale() { return getValue(mMatrix, Matrix.MSCALE_X); } public float getTranslateX() { return getValue(mMatrix, Matrix.MTRANS_X); } protected float getTranslateY() { return getValue(mMatrix, Matrix.MTRANS_Y); } protected void maxZoomTo(int x, int y) { if (mMinScale != getScale() && (getScale() - mMinScale) > 0.1f) { // threshold 0.1f float scale = mMinScale / getScale(); zoomTo(scale, x, y); } else { float scale = MAX_SCALE / getScale(); zoomTo(scale, x, y); } } public void zoomTo(float scale, int x, int y) { if (getScale() * scale < mMinScale) { return; } if (scale >= 1 && getScale() * scale > MAX_SCALE) { return; } mMatrix.postScale(scale, scale); // move to center mMatrix.postTranslate(-(mWidth * scale - mWidth) / 2, -(mHeight * scale - mHeight) / 2); // move x and y distance mMatrix.postTranslate(-(x - (mWidth / 2)) * scale, 0); mMatrix.postTranslate(0, -(y - (mHeight / 2)) * scale); setImageMatrix(mMatrix); } public void cutting() { int width = (int) (mIntrinsicWidth * getScale()); int height = (int) (mIntrinsicHeight * getScale()); if (getTranslateX() < -(width - mWidth)) { mMatrix.postTranslate(-(getTranslateX() + width - mWidth), 0); } if (getTranslateX() > 0) { mMatrix.postTranslate(-getTranslateX(), 0); } if (getTranslateY() < -(height - mHeight)) { mMatrix.postTranslate(0, -(getTranslateY() + height - mHeight)); } if (getTranslateY() > 0) { mMatrix.postTranslate(0, -getTranslateY()); } if (width < mWidth) { mMatrix.postTranslate((mWidth - width) / 2, 0); } if (height < mHeight) { mMatrix.postTranslate(0, (mHeight - height) / 2); } setImageMatrix(mMatrix); } private float distance(float x0, float x1, float y0, float y1) { float x = x0 - x1; float y = y0 - y1; return FloatMath.sqrt(x * x + y * y); } private float dispDistance() { return FloatMath.sqrt(mWidth * mWidth + mHeight * mHeight); } @Override public boolean onTouchEvent(MotionEvent event) { if (mDetector.onTouchEvent(event)) { return true; } int touchCount = event.getPointerCount(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_1_DOWN: case MotionEvent.ACTION_POINTER_2_DOWN: if (touchCount >= 2) { float distance = distance(event.getX(0), event.getX(1), event.getY(0), event.getY(1)); mPrevDistance = distance; isScaling = true; } else { mPrevMoveX = (int) event.getX(); mPrevMoveY = (int) event.getY(); } case MotionEvent.ACTION_MOVE: if (touchCount >= 2 && isScaling) { float dist = distance(event.getX(0), event.getX(1), event.getY(0), event.getY(1)); float scale = (dist - mPrevDistance) / dispDistance(); mPrevDistance = dist; scale += 1; scale = scale * scale; zoomTo(scale, mWidth / 2, mHeight / 2); cutting(); } else if (!isScaling) { int distanceX = mPrevMoveX - (int) event.getX(); int distanceY = mPrevMoveY - (int) event.getY(); mPrevMoveX = (int) event.getX(); mPrevMoveY = (int) event.getY(); mMatrix.postTranslate(-distanceX, -distanceY); cutting(); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_2_UP: if (event.getPointerCount() <= 1) { isScaling = false; } break; } return true; } @Override public boolean onTouch(View v, MotionEvent event) { return super.onTouchEvent(event); } }
I also draw a bitmap in onCreate in my activity, as shown below:
// Coloring Image mImage = (ScaleImageView) findViewById(R.id.iv_coloring_figure); BitmapDrawable drawable = (BitmapDrawable) mImage.getDrawable(); bmp = drawable.getBitmap(); _alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(_alteredBitmap); Paint paint = new Paint(); Matrix matrix = new Matrix(); canvas.drawBitmap(bmp, matrix, paint); mImage.setImageBitmap(_alteredBitmap); mImage.setOnTouchListener(this);
I also tried setting the coloring code inside the onTouch method in a custom imageView, which I use to scale, but still does not work. The only reason is that the original image below it does not scale, even when I enlarge the image from above. I really need a solution for this. I hope I get it. Thanks again!!!