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.
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)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With