【问题标题】:Android : How to fill colors in a Bitmap after zooming?Android:缩放后如何在位图中填充颜色?
【发布时间】:2013-08-22 02:10:42
【问题描述】:

我正在制作一个带有图画书的应用程序。我找到了一个库byronsanchez/coloring-book-android,使用它我可以很好地进行着色。但是,我需要为此实现缩放。我使用ScaleImageView 进行缩放。

我面临的问题是,当我缩放图像时,我无法为图像的特定区域着色。当图像未缩放时,它会检测到不同区域的触摸精细,但缩放后,它会在触摸一个区域时将颜色填充到不同的区域。

我搜索了一些解决方案,但我无法理解如何在我的代码中实现它。 Here 是我在寻找解决方案时遇到的答案之一。我想我的代码中已经有了缩放功能,但它仍然无法正常工作。

请提供一些示例和一些解释。我真的陷入了困境,希望我能在这里得到一些帮助,谢谢!!!

这是我在位图中填充颜色的代码:

@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 (e.g. 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;
}

这是我用来缩放的代码。

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

我还在 Activity 的 onCreate 中绘制位图,如下所示:

// 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);

我还尝试在我用于缩放的自定义 imageView 中的 onTouch 方法中设置着色代码,但仍然无法正常工作。原因只是即使我在顶部缩放图像,原始图像也没有被缩放。我真的需要一个解决方案。希望我得到一个。再次感谢!!!

【问题讨论】:

  • 在你的 onTouch 中填充颜色(第一个代码),你需要翻译 event.getX() 和 Y。做 float fixedX = (event.getX - mImage.getTranslateX()) / mImage。缩放()。然后使用fixedX 代替event.getX。不确定是否需要 +-*/ 只需记录值以查看应如何修复它们
  • @talkol 好的,感谢您的回复。我会尝试你的建议,如果它成功了,我会告诉你!
  • @talkol 不行!
  • 我很确定这是大方向,我们只需要修正数学(加或减,除或乘)。如果您不想考虑正确的数学应该是什么样子,您可以随时尝试所有组合:加法而不是减法,乘法而不是除法,先除法然后减法而不是减法然后除法:)
  • 是的,但我的问题是我在这里有两个相互重叠的位图。下面的位图获取用于填充颜色的触摸事件,而上面的位图获取用于缩放的触摸事件。当我缩放图像时,下面的位图只是停留在其原始位置并根据原始图像上的触摸事件而不是缩放后的事件填充颜色。

标签: android touch image-scaling pinchzoom flood-fill


【解决方案1】:

您可以尝试获取顶层位图的矩阵并将其设置为底层位图。获取图片的矩阵可以参考这个answer

【讨论】:

  • 这是一个很好的参考示例,尽管我会尝试看看它是否适合我。谢谢!
  • 我还将尝试复制您的代码并使用它,看看我是否可以真正修复并为您提供已修复的代码。一旦我有足够的时间,我会这样做。
猜你喜欢
  • 2010-10-29
  • 2011-03-17
  • 2013-02-21
  • 2012-04-24
  • 2014-01-16
  • 2011-10-20
  • 1970-01-01
  • 2012-07-24
  • 2019-11-26
相关资源
最近更新 更多