使用乘法和不透明度百分比将两个图像混合在一起

12

我正在尝试在Android上使用类似于Multiply的混合模式将两个图像混合在一起。

// Prepare -------------------------------

// Create source images
Bitmap img1 = ...
Bitmap img2 = ...

// Create result image
Bitmap result = ...
Canvas canvas = new Canvas();
canvas.setBitmap(result);

// Get proper display reference
BitmapDrawable drawable = new BitmapDrawable(getResources(), result);
ImageView imageView = (ImageView)findViewById(R.id.imageBlend1);
imageView.setImageDrawable(drawable);


// Apply -------------------------------

// Draw base
canvas.drawBitmap(img1, 0, 0, null);

// Draw overlay
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
paint.setShader(new BitmapShader(img2, TileMode.CLAMP, TileMode.CLAMP));

canvas.drawRect(0, 0, img2.getWidth(), img2.getHeight(), paint);
这个方法可行,但我无法控制乘法的“量” - 它总是进行完整的乘法转换。理想情况下,0%的乘法将与基本图像(img1)没有任何更改相同,但100%的乘法将是我使用上面代码得到的结果。 paint.setAlpha() 对此似乎无效。
是否还有其他方法来设置新“层”的透明度百分比?
附注:我猜可能有一些方法可以让这个乘法方法工作(使用LightingColorFilter),通过预先乘以白色并偏移颜色来实现,但这非常特定于乘法模式.. 我正在尝试找到一种方法来将透明度/%的事情应用于所有其他转换模式。
4个回答

3
我正在实现类似于我们的iOS应用程序的照片滤镜。他们使用以下方式:源位图+掩模位图+混合模式+alpha值。为了获得相同的效果,我只增加了掩模的alpha值。以下是我的代码最终版本:
public static Bitmap blend(Bitmap back, Bitmap front, BlendMethod method, float alpha) {
    if (alpha != 1.0F) {
        front = makeTransparent(front, Math.round(alpha * 255));
    }

    Bitmap.Config config = back.getConfig();
    int width = back.getWidth();
    int height = back.getHeight();

    if (width != front.getWidth() || height != front.getHeight()) {
        Log.e(TAG, "Arrays must be of identical size! Do bitmap scaling prior to blending.");
        return null;
    }

    int[] frontArr = new int[height * width], backArr = new int[height * width], resultArr;

    back.getPixels(backArr, 0, width, 0, 0, width, height);
    front.getPixels(frontArr, 0, width, 0, 0, width, height);

    resultArr = jniBlend(frontArr, backArr, alpha, method.toInt());
    return Bitmap.createBitmap(resultArr, width, height, config);
}

public static Bitmap blend(Bitmap back, Bitmap front, BlendMethod method) {
    return blend(back, front, method, 1F);
}

public static Bitmap makeTransparent(Bitmap src, int value) {
    int width = src.getWidth();
    int height = src.getHeight();
    Bitmap transBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(transBitmap);
    canvas.drawARGB(0, 0, 0, 0);
    // config paint
    final Paint paint = new Paint();
    paint.setAlpha(value);
    canvas.drawBitmap(src, 0, 0, paint);
    return transBitmap;
}

请注意,jniBlend是我自己编写的一种方法,其行为类似于Java中的标准PorterDuff模式。 makeTransparent方法不是我的 - 在这里找到它:(来自Ruban的答案)

2
什么是BlendMethod?请分享完整的内容,否则没什么用。 - Mohsin
@Mohsin 如果我没记错的话,这个问题现在已经在AndroidSDK中实现了。回到2015年时,它缺少一些混合模式。 - Den Drobiazko

3

1
谢谢,伙计。这篇文章很棒,但更多的是关于使用不同模式附加图层,而不是有一种方法来改变每种模式下输入值的百分比。它确实展示了从图像中读取像素后进行直接操作的一些方法,所以也许这是一种替代方案。我需要进一步调查。暂时先谢谢! - zeh
1
互联网档案馆链接:https://web.archive.org/web/20150310155646/http://kevindion.com/2011/01/android-bitmap-blending-color-channels/ - 1j01

0
我正在使用 @Den Drobiazko 的代码,这些代码可以完美地混合位图。请将您的位图和可见度百分比作为整数值传递进去。
    public static Bitmap makeTransparent(Bitmap src, int value) {
    int width = src.getWidth();
    int height = src.getHeight();
    Bitmap transBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(transBitmap);
    canvas.drawARGB(0, 0, 0, 0);
    // config paint
    Log.e("test","value "+value);
    final Paint paint = new Paint();
    paint.setAlpha(value);
    canvas.drawBitmap(src, 0, 0, paint);
    return transBitmap;
}

0

这段代码并不完整,只是为了让您了解如何使用渲染脚本来混合图像。

public Bitmap blend(Bitmap image)
{
    final float BLUR_RADIUS = 25f;
    Bitmap outbitmap = Bitmap.createBitmap(image);
    final RenderScript renderScript = RenderScript.create(this);

    Allocation tmpin = Allocation.createFromBitmap(renderScript,image);
    Allocation tmpout = Allocation.createFromBitmap(renderScript,outbitmap);
    ScriptIntrinsicBlend blend = ScriptIntrinsicBlend.create(renderScript,
    Element.U8_4(renderScript));

    blend.forEachMultiply(tmpin,tmpout);
    return outbitmap;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接