Android - 使用Flood-Fill时的Canvas Black

时间:2014-12-17 15:14:50

标签: android bitmap imageview android-canvas flood-fill

当我实施flood-fill课程时,我的整个Bitmap会变黑。显然这不是预期的效果。我查看了以下主题:

从我所看到的,我做了他们在这些解决方案中提出的所有事情,但它并没有引导我解决我的问题。所以要切入追逐,这里的代码有一些简短的解释。

XML
我正在使用相对布局并将两个ImageViews直接定位(堆叠)在彼此之上。它们都具有相同的图像,这就产生了能够在图像上绘制的错觉。但是,您实际上只是在透明覆盖图上绘制。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    ....

    <ImageView
        android:id="@+id/drawContainer2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toRightOf="@id/imageMapperSurfaces"
        android:contentDescription="@string/image" />

    <ImageView
        android:id="@+id/drawContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toRightOf="@id/imageMapperSurfaces"
        android:contentDescription="@string/image" />

   ...
</RelativeLayout>

帆布
然后我使用此代码创建Canvas,并确保正确设置我的图层类型。

public void setCanvas() {
    if(mFile != null && mFile.exists()) {
        mPictureBitmap = BitmapFactory.decodeFile(mFile.getAbsolutePath());
        mBitmap = Bitmap.createScaledBitmap(mPictureBitmap, mImageView.getWidth(), mImageView.getHeight(), false);
        mPictureBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mBitmap = mPictureBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mSceneBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mBlurBitmap = blurImage(mPictureBitmap); 
        mCanvas = new Canvas(mBitmap);
        mImageView.setImageBitmap(mBitmap);
        mImageView2.setImageBitmap(mPictureBitmap);
        mBlur.setImageBitmap(mBlurBitmap);

        // failure to set these layer types correctly will result in a black canvas after drawing.
        mImageView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        mImageView2.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        mImageView.bringToFront();
        mAllowedToDraw = true;

        setImageViewOnTouch();
    }
}

洪水填充实施
我抓住颜色,将我的参数传递给flood-fill对象,使用flood-fill方法,返回bitmap,最后将新bitmap绘制到我的canvas }。

int targetColor = mSceneBitmap.getPixel((int) event.getX(), (int) event.getY());
FloodFill fill = new FloodFill(mBitmap, targetColor, Color.argb(100, 255, 0, 0));
fill.floodFill((int) event.getX(), (int) event.getY());
Bitmap bmp = fill.getImage();
mCanvas.drawBitmap(bmp, 0, 0, null);
mImageView.invalidate();

洪水填充类
锅炉板Flood-fill算法。

public class FloodFill {
    protected Bitmap mImage = null;
    protected int[] mTolerance = new int[] { 0, 0, 0, 0 };
    protected int mWidth = 0;
    protected int mHeight = 0;
    protected int[] mPixels = null;
    protected int mFillColor = 0;
    protected int[] mStartColor = new int[] { 0, 0, 0, 0 };
    protected boolean[] mPixelsChecked;
    protected Queue<FloodFillRange> mRanges;

    public FloodFill(Bitmap img) {
        copyImage(img);
    }

    public FloodFill(Bitmap img, int targetColor, int newColor) {
        useImage(img);

        setFillColor(newColor);
        setTargetColor(targetColor);
    }

    public void setTargetColor(int targetColor) {
        mStartColor[0] = Color.red(targetColor);
        Log.v("Red", "" + mStartColor[0]);
        mStartColor[1] = Color.green(targetColor);
        Log.v("Green", "" + mStartColor[1]);
        mStartColor[2] = Color.blue(targetColor);
        Log.v("Blue", "" + mStartColor[2]);
        mStartColor[3] = Color.alpha(targetColor);
        Log.v("Alpha", "" + mStartColor[3]);
    }

    public int getFillColor() {
        return mFillColor;
    }

    public void setFillColor(int value) {
        mFillColor = value;
    }

    public int[] getTolerance() {
        return mTolerance;
    }

    public void setTolerance(int[] value) {
        mTolerance = value;
    }

    public void setTolerance(int value) {
        mTolerance = new int[] { value, value, value, value };
    }

    public Bitmap getImage() {
        return mImage;
    }

    public void copyImage(Bitmap img) {
        mWidth = img.getWidth();
        mHeight = img.getHeight();

        mImage = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mImage);
        canvas.drawBitmap(img, 0, 0, null);

        mPixels = new int[mWidth * mHeight];

        mImage.getPixels(mPixels, 0, mWidth, 0, 0, mWidth, mHeight);
    }

    public void useImage(Bitmap img) {
        mWidth = img.getWidth();
        mHeight = img.getHeight();
        mImage = img;

        mPixels = new int[mWidth * mHeight];

        mImage.getPixels(mPixels, 0, mWidth, 0, 0, mWidth, mHeight);
    }

    protected void prepare() {
        mPixelsChecked = new boolean[mPixels.length];
        mRanges = new LinkedList<FloodFillRange>();
    }

    public void floodFill(int x, int y) {
        // Setup
        prepare();

        if (mStartColor[0] == 0) {
            // ***Get starting color.
            int startPixel = mPixels[(mWidth * y) + x];
            mStartColor[0] = (startPixel >> 16) & 0xff;
            mStartColor[1] = (startPixel >> 8) & 0xff;
            mStartColor[2] = startPixel & 0xff;
        }

        LinearFill(x, y);
        FloodFillRange range;

        while (mRanges.size() > 0) {
            range = mRanges.remove();
            int downPxIdx = (mWidth * (range.Y + 1)) + range.startX;
            int upPxIdx = (mWidth * (range.Y - 1)) + range.startX;
            int upY = range.Y - 1;
            int downY = range.Y + 1;

            for (int i = range.startX; i <= range.endX; i++) {
                if (range.Y > 0 && (!mPixelsChecked[upPxIdx]) && CheckPixel(upPxIdx)) LinearFill(i, upY);
                if (range.Y < (mHeight - 1) && (!mPixelsChecked[downPxIdx]) && CheckPixel(downPxIdx)) LinearFill(i, downY);
                downPxIdx++;
                upPxIdx++;
            }
        }

        mImage.setPixels(mPixels, 0, mWidth, 0, 0, mWidth, mHeight);
    }

    protected void LinearFill(int x, int y) {
        int lFillLoc = x;
        int pxIdx = (mWidth * y) + x;

        while (true) {
            mPixels[pxIdx] = mFillColor;
            mPixelsChecked[pxIdx] = true;
            lFillLoc--;
            pxIdx--;

            if (lFillLoc < 0 || (mPixelsChecked[pxIdx]) || !CheckPixel(pxIdx)) {
                break;
            }
        }

        lFillLoc++;
        int rFillLoc = x; 

        pxIdx = (mWidth * y) + x;

        while (true) {
            mPixels[pxIdx] = mFillColor;
            mPixelsChecked[pxIdx] = true;

            rFillLoc++;
            pxIdx++;

            if (rFillLoc >= mWidth || mPixelsChecked[pxIdx] || !CheckPixel(pxIdx)) {
                break;
            }
        }

        rFillLoc--;

        FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);

        mRanges.offer(r);
    }

    protected boolean CheckPixel(int px) {
        int red = (mPixels[px] >>> 16) & 0xff;
        int green = (mPixels[px] >>> 8) & 0xff;
        int blue = mPixels[px] & 0xff;
        int alpha = (Color.alpha(mPixels[px]));

        return (red >= (mStartColor[0] - mTolerance[0]) && red <= (mStartColor[0] + mTolerance[0])
                && green >= (mStartColor[1] - mTolerance[1]) && green <= (mStartColor[1] + mTolerance[1])
                && blue >= (mStartColor[2] - mTolerance[2]) && blue <= (mStartColor[2] + mTolerance[2])
                && alpha >= (mStartColor[3] - mTolerance[3]) && alpha <= (mStartColor[3] + mTolerance[3]));
    }

    protected class FloodFillRange {
        public int startX;
        public int endX;
        public int Y;

        public FloodFillRange(int startX, int endX, int y) {
            this.startX = startX;
            this.endX = endX;
            this.Y = y;
        }
    }
}

因此,我们应该把所有的部分都拼凑到拼图中,但由于某些原因它们不起作用。我感到茫然,任何帮助都表示赞赏。谢谢!

2 个答案:

答案 0 :(得分:0)

我认为你排成一行:

mCanvas.drawBitmap(bmp, 0, 0, null);

可能需要更像

mPaint = new Paint();    
mCanvas.drawBitmap(bmp, 0, 0, mPaint);

答案 1 :(得分:0)

我不确定所有事情,但据我所知,我会尝试使用这些解决方案:

第一: 而不是使用decodeFile我宁愿使用decodeInputStream 第二: 有人已经有了你最好在显示视图时使用Paint() 第三: 我要问你为什么需要食物填充算法呢?我觉得它太迟了,使用时看起来有点乱,你为什么不创建一个新的缩放位图或类似opengl效果呢?因为这就是为什么有显卡的原因;