Green Screen effect on ImageView - android

My goal is to have a "green screen" effect for an ImageView and a border. I have a png border with a somewhat thick solid outline, the shape is irregular, and is transparent both inside and outside the border. I want to use it as a border of another image, say a photo, and because the border shape is irregular, some parts of the photo may lie outside of the border.
All this contraption sits at the center of a layout with a complex gradient background, so I cannot just cheat the border imageview and fill the outside part with color similar to the underlying parent background.
My initial idea is to use some image editing tool to fill the inside and outside of the png with different colors (green inside, black outside), place the image behind it, and perform some pixel magic with the resulting bitmap such that all black pixels outside the border will "punch through" the whole canvas thus showing the parent background (the complex gradient background), and all green pixels inside the border will become transparent and reveal the photo behind it.
This sounds somewhat too complicated for a simple-looking goal so I'm postponing the implementation (not even sure if it's possible) until I'm convinced that:
A. There is no existing library I can use with the same effect
B. There is a better solution that results to the same effect, but is a lot less complex.

Got it to work using Bitmap.setPixel
public static Bitmap combine(Bitmap b1, Bitmap b2) {
try {
int maxWidth = b1.getWidth();
int maxHeight = b1.getHeight();
Bitmap bmOverlay = Bitmap.createBitmap(maxWidth, maxHeight, b1.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(b2, 0, 0, null);
canvas.drawBitmap(b1, 0, 0, null);
for (int index = 0; index < bmOverlay.getWidth(); index++) {
for (int index2 = 0; index2 < bmOverlay.getHeight(); index2++) {
if (bmOverlay.getPixel(index, index2) == Color.rgb(0, 255, 0)) { // or whatever outside color you set on your png
bmOverlay.setPixel(index, index2, Color.TRANSPARENT);
}
}
}
return bmOverlay;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
The trick is to leave the inside of the border as transparent, then fill the outside with a solid color (such as #00ff00) with a tolerance of 0. Won't work as well with shadowed or alpha gradient borders, but should be fine for solid colors.
Usage:
Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.profile_pic_border_alt);
Bitmap b2 = BitmapFactory.decodeResource(getResources(), R.drawable.panggap);
b2 = ThumbnailUtils.extractThumbnail(panggap, border.getWidth(), border.getHeight());
Bitmap b = combine(b1, b2);
imageView.setImageBitmap(b);

Try to using ColorFilter to do that: http://developer.android.com/intl/es/reference/android/graphics/ColorFilter.html
In this discussion you should find what you want: Applying ColorFilter to ImageView with ShapedDrawable

Related

How to put 2 imageViews, one on top of another, that will blend them both?

Background
I have 2 imageViews, one on top of another, that have an animation together . I need them to blend with each other, using the "Multiply" effect, during this animation.
Something similar to this question which is about colors, yet with images (VectorDrawable in my case, but I can use PNG instead if needed).
Here's a sketch to demonstrate what I'd like to do:
Notice that the part of the images that overlap is darker than the original color of the arrows.
The problem
So far I can't find a way to do it. I know of course how to put a view on top of another, but changing the color of a part of the bitmap, based on the other, is something I can't find.
What I've found
I tried to use :
imageView.getDrawable().setColorFilter(..., PorterDuff.Mode.MULTIPLY)
for both the ImageViews, but it doesn't seem to work. What it does is actually change the entire color of the imageView, merging with the color I provide as the parameter.
It makes sense, because it's just a colorFilter, similar to tint.
I also tried alpha for each of the ImageViews, but this also mean that a part of the ImageViews (the parts that don't overlap) will have a semi-transparent color.
I could theoretically get the bitmap of each of them, and then perform the filter on the result, but this is not practical as I need to show it during animation between the two.
The question
How can I blend the 2 imageViews ?
Since you're using VectorDrawable, Have you considered animating the drawable rather than the view?
https://developer.android.com/reference/android/graphics/drawable/AnimatedVectorDrawable.html
try this:
public Bitmap combineImages(Bitmap frame, Bitmap image) {
Bitmap cs = null;
Bitmap rs = null;
rs = Bitmap.createScaledBitmap(frame, image.getWidth(),
image.getHeight(), true);
cs = Bitmap.createBitmap(rs.getWidth(), rs.getHeight(),
Bitmap.Config.RGB_565);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(image, 0, 0, null);
comboImage.drawBitmap(rs, 0, 0, null);
if (rs != null) {
rs.recycle();
rs = null;
}
Runtime.getRuntime().gc();
return cs;
}
OK, it seems it's probably not possible using 2 views, because of the way they work on Android, so instead, I want to show how to do it with a LayerDrawable instead:
public class LD extends LayerDrawable {
private Paint p = new Paint();
public LD(Drawable[] layers) {
super(layers);
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
int count = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
for (int i = 0, numberOfLayers = getNumberOfLayers(); i < numberOfLayers; ++i) {
this.getDrawable(i).draw(canvas);
canvas.saveLayer(null, p, Canvas.ALL_SAVE_FLAG);
}
canvas.restoreToCount(count);
//original code:
//int count = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
//this.getDrawable(0).draw(canvas);
//canvas.saveLayer(null, p, Canvas.ALL_SAVE_FLAG);
//this.getDrawable(1).draw(canvas);
//canvas.restoreToCount(count);
}
}
Usage:
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Drawable drawable1 = AppCompatResources.getDrawable(this, R.drawable....);
Drawable drawable2 = AppCompatResources.getDrawable(this, R.drawable....);
Drawable drawable3 = AppCompatResources.getDrawable(this, R.drawable....);
LD layerDrawable = new LD(new Drawable[]{
drawable1,
drawable2,
drawable3
});
imageView.setImageDrawable(layerDrawable);

How to have a FAB with option of no padding, yet still have it elevation?

background
I have a small circular contact photo view that I need to show the user.
If the photo is available, I should show it, while the image gets rounded to a circle, and has an elevation.
If the photo isn't available, I show an icon inside with a background, while still it's rounded and has elevation.
The problem
I've managed to make the photo showing work only on Android 5 and above:
But, it has a bad color around the edges as it tries to show the background of the FAB, and on Android 4.x and below it it showing as a simple rectangular content, with nothing that's related to FAB, probably because padding is what's protecting it for the shadow to be shown.
I also need to be able to add a stroke (a thin line of specific color around the rounded image), but I'm not sure how to add it.
What I've tried
This is in the layout file:
<android.support.design.widget.FloatingActionButton
android:id="#+id/image"
android:layout_width="#dimen/test"
android:layout_height="#dimen/test"/>
"test" is 80dp.
And this is in the code:
FloatingActionButton floatingActionButton = (FloatingActionButton) view.findViewById(R.id.image);
floatingActionButton.setPadding(0, 0, 0, 0);
final Bitmap bitmap = ...
RoundedCornersDrawable roundedCornersDrawable = new RoundedCornersDrawable(getResources(), bitmap, bitmap.getWidth() / 2);
floatingActionButton.setImageDrawable(roundedCornersDrawable);
code of RoundedCornersDrawable:
public class RoundedCornersDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
final int w = b.getWidth(), h = b.getHeight();
rect = new RectF(0, 0, w, h);
this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
}
#Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
}
}
The question
How do I get the FAB to work this way? How can I disable the padding at will, for all Android versions, and yet still have a rounded image with shadow ?
How do I also add a stroke to the rounded FAB ?
I think I was too fast in writing this post, while it seems there is already one about it here:
How to add a shadow and a border on circular imageView android?
I will have a look at it and see if it matches the requirements of what I need.
EDIT: it doesn't look as well as FAB (especially the shadow), plus I don't see the ability to put the small content in the center, like in FAB. It always puts the content in center-crop way.
Of course, I could just put a smaller sized image in it....
EDIT: I think I've found the right library this time:
https://github.com/lopspower/CircularImageView
It allows a shadow, customize the shadow size and color, and also a border, and also how to scale the image.
It's not quite a FAB, and it doesn't have the ability to put the image at the center without cropping, but it's enough for me.

White bitmap in android

I want to set home wallpaper with white bitmap:
Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(0xfff);
WallpaperManager wall = WallpaperManager.getInstance(this);
try {
wall.setBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
And the wallpaper becomes black. What's wrong is here?
Just add bitmap.eraseColor(Color.WHITE);
as second line
My first guess would be your color choice, assuming this is the value in your actual code and not edited.
Color ints in java take the form ARGB, so Color.WHITE is 0xFFFFFFFF, Color.BLUE is 0xFF0000FF, etc.
The color in your code (0xFFF) would expand to 0x00000FFF which is Blue with a little green mixed in, but the alpha channel is zero, so the Canvas is basically written with a transparent color.
If you are using standard colors, I would stick to the constants in the Color class as parameters here, but if you want to define the color yourself, remember to place the full color or use Canvas.drawRGB() instead.

How to programmatically overlap alpha blended bitmaps in android?

I need to "compute" the resulting bitmap obtained from overlapping two different bitmaps that have an alpha value somewhere between 0 and 255. I need to do this in java code, not xml, because bitmaps are being loaded dinamically and not from resources.
Here is my first try (which always yields a black bitmap...):
private Drawable composeBitmaps(int alpha1, BitmapDrawable bm1,
int alpha2, BitmapDrawable bm2)
{
Canvas c = new Canvas();
Bitmap b1 = bm1.getBitmap();
BitmapDrawable draw1 = new BitmapDrawable(b1.copy(b1.getConfig(), true));
draw1.setAlpha(alpha1);
c.setBitmap(draw1.getBitmap());
Paint p = new Paint();
p.setAlpha(alpha2);
c.drawBitmap(bm2.getBitmap(), 0, 0, p);
return draw1;
}
...
View v = // whatever
v.setBackgroundDrawable(composeBitmaps(100, bdrawable1, 150, bdrawable2));
And the view goes black background. What am I doing wrong?
My code above is absolutely correct. The bug that made the bitmap go black was elsewhere. Found it, fixed it, now it works.
The only thing to note is that my code is slow as hell and it cannot be used to crossfade two fullscreen bitmaps at a reasonable fps rate.

How to reverse a bitmap color in android with colorfilter?

I have a white background image, it is not fit for my app's black background.
I want to make it have black background, or reverse all the colors in the bitmap image.
How can I do that?
Get the width and the height of the bitmap. Store the pixels in array, then iterate each pixel, test for white color (hex value) if it is true than swap it with value for black. This is not the best solution. Why dont you just load black bitmap?
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.r); //example,
int[] pixels = new int[bm.getWidth()*bm.getHeight()];
bm.getPixels(pixels, 0, bm.getWidth(),0, 0, bm.getWidth(), bm.getHeight()); //filling the array, this might throw some outofboundaryindex exception for the array, check again.
int i = 0;
while(i!=bm.getWidth()*bm.getHeight())
{
if(pixels[i]==hexforblack)
{
swap it with hex of white
}
i++;
}
Here you can find hex values of the colors
http://www.w3schools.com/html/html_colors.asp

Categories

Resources