【问题标题】:Android - Masking a Bitmap using another BitmapAndroid - 使用另一个位图屏蔽位图
【发布时间】:2013-06-21 22:57:08
【问题描述】:

我有两个位图。这是位图 1:

这是位图 2:

最终结果应该是什么:

我会很欣赏代码,但是,我会更欣赏对文档或教程的引用。我想完全理解代码,我在 developer.android.com 上搜索了很长时间,但没有运气。谢谢。

【问题讨论】:

  • 这是可以做到的,我相信有人会有所了解。但是我能问一下为什么你不只使用你想要的最终结果的单个位图或 .png 吗?
  • @JadeByfield 也许那些是动态输入和输出,在这种情况下,你不能这样做
  • @fge 啊,好点子 :)
  • 正如@fge 所说:)
  • 无论如何——看PNG,你只有countour,其余的都是空的......我认为如果countour的周围是别的东西会更容易(黑色,for实例?)

标签: java android filter bitmap mask


【解决方案1】:

超过 3 年没有答案?我可以解决这个问题。

如 cmets 中所述,位图 2 的边缘和中间是透明的(只有轮廓在那里),所以第一步是用白色填充中心。有很多可用的洪水填充算法。我使用了https://stackoverflow.com/a/8925653/852795,因为它很简单,尽管还有其他的肯定更快。这是必要的,因为它支持下一步。

第二步是使用Porter/Duff Composting将填充的Bitmap 2与Bitmap 1结合起来。 PorterDuff.Mode.SRC_ATOP 将有效地将位图 1 绘制到位图 2 现在的白色区域,同时使轮廓之外的区域保持透明。

代码如下:

package test.testapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.graphics.Bitmap.Config;

import java.util.LinkedList;
import java.util.Queue;

public class MainActivity extends AppCompatActivity {

    Bitmap mask, background, filledMask, overlay;
    Canvas c;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mask = BitmapFactory.decodeResource(getResources(), R.drawable.mask);
        background = BitmapFactory.decodeResource(getResources(), R.drawable.background);

        // get the mask, copy it to filledMask and then flood from the center with CYAN
        filledMask = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888);
        c = new Canvas(filledMask);
        c.drawBitmap(mask, 0, 0, new Paint());
        Point center = new Point(filledMask.getWidth() / 2, filledMask.getHeight() / 2);
        floodFill(filledMask, center, Color.TRANSPARENT, Color.WHITE);


        // create new overlay Bitmap, draw the filledMask and then add the background using PorterDuff
        overlay = Bitmap.createBitmap(filledMask.getWidth(), filledMask.getHeight(), Config.ARGB_8888);
        c = new Canvas(overlay);
        Paint p = new Paint();
        p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        c.drawBitmap(filledMask, 0, 0, new Paint());
        c.drawBitmap(background, 0, 0, p);

        DrawView drawView = new DrawView(this);
        // set background to light blue in order to see transparent areas
        drawView.setBackgroundColor(0xffd2d7fe);
        setContentView(drawView);
        drawView.requestFocus();
    }

    public class DrawView extends View {
        Paint p = new Paint();
        int top = 0;

        public DrawView(Context context) {
            super(context);
        }

        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawBitmap(mask, 0, 0, p);
            top += mask.getHeight();

            canvas.drawBitmap(filledMask, 0, top, p);
            top += filledMask.getHeight();

            canvas.drawBitmap(background, 0, top, p);
            top += background.getHeight();

            canvas.drawBitmap(overlay, 0, top, p);
        }
    }

    // method from https://stackoverflow.com/a/8925653/852795
    public void floodFill(Bitmap bmp, Point pt, int targetColor, int replacementColor) {

        Queue<Point> q = new LinkedList<>();
        q.add(pt);
        while (q.size() > 0) {
            Point n = q.poll();
            if (bmp.getPixel(n.x, n.y) != targetColor) continue;

            Point w = n, e = new Point(n.x + 1, n.y);
            while ((w.x > 0) && (bmp.getPixel(w.x, w.y) == targetColor)) {
                bmp.setPixel(w.x, w.y, replacementColor);
                if ((w.y > 0) && (bmp.getPixel(w.x, w.y - 1) == targetColor)) q.add(new Point(w.x, w.y - 1));
                if ((w.y < bmp.getHeight() - 1) && (bmp.getPixel(w.x, w.y + 1) == targetColor)) q.add(new Point(w.x, w.y + 1));
                w.x--;
            }
            while ((e.x < bmp.getWidth() - 1) && (bmp.getPixel(e.x, e.y) == targetColor)) {
                bmp.setPixel(e.x, e.y, replacementColor);

                if ((e.y > 0) && (bmp.getPixel(e.x, e.y - 1) == targetColor)) q.add(new Point(e.x, e.y - 1));
                if ((e.y < bmp.getHeight() - 1) && (bmp.getPixel(e.x, e.y + 1) == targetColor)) q.add(new Point(e.x, e.y + 1));
                e.x++;
            }
        }
    }
}

运行时,输出(在背景中添加浅蓝色以“看到”图像的透明区域后)应如下所示,图像分别为位图 2、位图 2 填充,位图 1,最后是位图 2 填充和位图 1 的组合:

轮廓内部似乎有一点“模糊”,但这可能是洪水填充的伪影,或者可能是原始位图 2。玩弄这两者可能会清除这种情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多