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

发布于 2024-12-09 10:20:52 字数 1131 浏览 0 评论 0原文

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

// 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() 似乎不适用于此。

还有其他方法可以设置新“图层”的不透明度百分比吗?

PS 我猜有一些方法可以通过预乘并将颜色偏移为白色来使乘法工作(使用 LightingColorFilter),但它非常特定于乘法模式..我正在尝试找到一种方法将 opacity/% 也应用于所有其他传输模式。

I'm trying to blend two images together with Android, using a Multiply-like blending mode.

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

This works, but I don't have control over the "amount" of multiply that is done - it's always a complete multiply transfer. Ideally, a 0% multiply would be the same as the base image (img1) without any change, but a 100% multiply would be the result I get with the code above.

paint.setAlpha() doesn't seem to work for this.

Any other way to set the % opacity of the new 'layer'?

P.S. There are some methods to make multiply work with this I guess (using a LightingColorFilter) by pre-multiplying and offsetting the color to white, but it's very specific to the multiplymode .. I'm trying to find a way to apply the opacity/% thing to all other transfer modes too.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

逆蝶 2024-12-16 10:20:53

我正在实现类似于我们 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 的回答)

I was implementing photo filters similar to what iOS app of ours does. They do it something like source bitmap + mask bitmap + blend mode + alpha value. To achieve identical behaviour I just increased the alpha of mask. Here's what my code finally looks:

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

Note that jniBlend is some method I wrote on my own, it behaves like stock PorterDuff modes in Java.

Method makeTransparent is not mine - found it here: (answer from Ruban)

预谋 2024-12-16 10:20:53

不久前我需要做类似的事情,我发现这个关于颜色通道的帖子很有启发。
(但恐怕这与您在“PS”中描述的内容有关)

archive.org 中的链接,感谢 @1j01

I needed to do something like that a while ago, and I found this post about Color Channels a lot enlightening.
(But I'm afraid this is related to what you described in your "PS")

Link above in archive.org, thanks to @1j01

情场扛把子 2024-12-16 10:20:53

代码不完整。这只是为了给您一个想法,以便您可以使用渲染脚本来混合图像

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

The code is not complete. it is just to give you an idea so that you can use render script to blend an image

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;
}
一影成城 2024-12-16 10:20:53

我正在使用 @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;
}

I am using these lines of code from @Den Drobiazko answer and its working perfectly for blending bitmap

// pass your Bitmap and percentage of visibility as a integer value

    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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文