How to set an Image's alpha in android - java

so I'm in a bit of a pickle. I know how to set the alpha value of a bitmap in android. What I don't know how to do is make is reversible. So, let's say someone wanted to set the alpha of an image to 50%, so they do. Now lets say they wanted to set it 75% (keep in mind, this is of the original image alpha value). Currently, what I have is a function that will set the alpha value of the current image, so it would be 75% of the 50% alpha value if that makes sense. How can I make it so that it accounts for the original image?
public Pixmap setAlpha(float newAlpha) { //integer between 0-100
if (newAlpha != alpha) { //to check if the current alpha value of the image is equal to your desired alpha. to avoid always halving you alpha value
float test = newAlpha/100.0f;
float test2 = test * 255;
alpha = test2;
Bitmap newBM = Bitmap.createBitmap(backupImg.getBitmap().getWidth(),backupImg.getBitmap().getHeight(), Bitmap.Config.ARGB_8888);
Canvas cc = new Canvas(newBM);
cc.drawARGB(0,0,0,0);
Paint newPaint = new Paint();
newPaint.setAlpha((int)test2);
cc.drawBitmap(backupImg.getBitmap(), 0, 0, newPaint);
img.setBitmap(newBM);
return img;
} else {
return img;
}
}
The Pixmap part is just a custom Bitmap class. backupImg is just a copy of img, created in the constructor of the object this function belongs to.
please keep in mind that this will be a canvas based bitmap. If I recall correctly imageView's aren't drawn on the canvas? So, as a further example. Imagine a sprite drawn to the canvas that you want to alter the alpha of. So you do it using the function I've posted. Now, let's say you want to undo the changes and restore it to the sprite's original alpha, of some other value. Well, you can't because the alpha value of the image has been changed permanently. What I want to do is store reference to the original image with another variable, and refer to that whenever I need to adjust the alpha value of the image. Hopefully that makes sense

Why don't you set alpha to the ImageView instead of setting it to a bitmap.
By setting alpha to the ImageView or say any view you can reverse it easily.
Refer to this answer in order to do it.

You can do it from xml. Just add the below line in the imageview tag:-
android:alpha="0.5"
You can set alpha between 0 to 1. Above line will set alpha to half that is 0.5.
For bitmap:
Bitmap newBitmap = Bitmap.createBitmap(originalBitmap.getWidth(),
originalBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
Paint alphaPaint = new Paint();
alphaPaint.setAlpha(75);
canvas.drawBitmap(originalBitmap, 0, 0, alphaPaint);

I've solved the problem myself. So, there is nothing wrong with the function I wrote. The problem instead lies within how Java uses pointers. because everything is passed via reference, I was actually referencing the same object, rather than creating two separate objects. So instead of:
Bitmap oldBM = new Bitmap();
Bitmap newBM = oldBM;
you would instead want to do
Bitmap oldBM = new Bitmap();
Bitmap newBM = new Bitmap(using old bitmap's value);

Related

How to set size, position, and color, of one RadialGradient, or set XferMode on GradientDrawable

This is my first question here on Stackoverflow, so go easy on me. I'm trying to draw a radial bloom effect around a point, and found RadialGradient, as well as GradientDrawable. However neither fully gives a solution.
Here is how I'm doing the drawing right now:
//global
PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
Paint mainP = new Paint();
Paint whiteP = new Paint();
whiteP.setColor(Color.WHITE);
RadialGradient gradient;
// in a drawing method with a canvas
gradient = new RadialGradient((int) x, (int) y, tempRadius, mainP.getColor(),
0x00000000, Shader.TileMode.CL
mainP.setShader(gradient);
mainP.setXfermode(xferMode);
canvas.drawCircle((int) x, (int) y, tempRadius, mainP);
gradient = new RadialGradient((int) x, (int) y, tempRadius/2, whiteP.getColor(),
0x00000000, Shader.TileMode.CLAMP);
whiteP.setXfermode(xferMode);
whiteP.setShader(gradient);
canvas.drawCircle((int) x, (int) y, tempRadius/2, whiteP);
This will give the expected result:
Screenshot
However the new RadialGradient builds up in memory every frame per dot. Which becomes a problem later obviously. The only public thing in that class is a constructor, so all you can do with RadialGradient is create a new one every time you need a new size, position or color. The reason I want to do it this way is because you assign the gradient to the Paint object your going to draw it with, which allows you to use it's setXferMode().
The other way, using the GradientDrawable, does allow you to just create one instance of itself, so you can change the size, position, and color, but the Paint object it uses to paint itself is private, so you can't set the XferMode on it. Which is necessary so that if you have more than one dot, they don't just paint over one another. It has a colorfilter, but it doesn't look like colorfilter worries about the destination, only a specified color and the source.
Since I am new, i can only post two links, and instead of posting just two pictures, I'll link back to the same question I wrote on reddit which has all the pictures for context. (and no answers yet, which is why I came here, ha ha)
https://www.reddit.com/r/learnandroid/comments/590uce/having_a_shader_issue_using_radialgradient_and/
So, how should this be done, I know I need one class or the other. From what I can tell, RadialGradient would be perfect if I didn't have to create a new one every time I needed a different size, position, or color. GradientDrawable would be equally great since you can just have one instance, but I need to be able to set the XferMode on the paint it uses. Is there another class, or am I missing something between the two of these?
Thanks!!
So, while I did find a solution, it still lead to more issues. The solution I found was partly here. The only thing it was missing was being able to change the color of the preallocated RadialGradient bitmap. So I came up with this:
// Global
int tempRadius;
Paint p = new Paint();
RadialGradient gradient;
Bitmap circleBitmap = Bitmap.createBitmap((int) (tempRadius * 2.0f), (int) (tempRadius * 2.0f),
Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(circleBitmap);
Rect gradBMPRect = new Rect(0,0,200,200);
Rect destRect = new Rect();
int[] hsv = {0,1,1};
PorterDuffColorFilter[] myColors = new PorterDuffColorFilter[360];
PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
// Initialize
gradient = new RadialGradient(tempRadius, tempRadius, tempRadius, Color.WHITE, 0x00000000, Shader.TileMode.CLAMP);
circleBitmap = Bitmap.createBitmap((int) (100 * 2.0f), (int) (100 * 2.0f),
Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(circleBitmap);
for(int i = 0; i < 360; i++){
hsv[0] = i;
myColors[i] = new PorterDuffColorFilter(Color.HSVtoColor(hsv), PorterDuff.Mode.MULTIPLY)
}
// update/draw
p.setDither(true);
p.setShader(gradient);
tempCanvas.drawCircle(100, 100, 100, p);
p.setXfermode(xferMode);
if(p.getColor() != mainP.getColor()) {
p.setColorFilter(myColors[hue]);
p.setColor(mainP.getColor());
destRect.set((int)x-tempRadius,(int)y-tempRadius,(int)x+tempRadius,(int)y+tempRadius);
canvas.drawBitmap(circleBitmap,gradBMPRect,destRect,p);
p.setColorFilter(null);
destRect.set((int)x-(tempRadius/2),(int)y-(tempRadius/2),(int)x+(tempRadius/2),(int)y+(tempRadius/2));
canvas.drawBitmap(circleBitmap,gradBMPRect,destRect,p);
With this the RadialGradient is used to create a greyscaled bitmap, then a pallette of 360 PorterDuffColorFilters is made using HSVtoColor. All 360 have their modes set to multiply. When drawing these the paint used to draw the bitmap is set use the ColorFilter specified by its hue. The colorfilter shades the greyscaled bitmap to whatever color the filter is. And no more memory leaks :)
This took longer to render the bitmap of a RadialGradient vs rendering a circle with a RadialGradient though. With 30 circles it took my Galaxy S5 15-20ms per frame draw, while the bitmaps took around 30-35ms. It could probably get worked out though with a little more work and adjustment.

Android - use bitmap as a gradient mask

I have implemented a flood fill algorithm in an android app. The way I have implemented the algorithm doesn't actually change the source bitmap, but instead creates a new bitmap of the fill area. I.E.
Flood filling this circle with red
Would produce this bitmap (where everything else in the bitmap is transparent)
Which I then combine again into a single bitmap. This works great for solid colors, but I want to be able to implement a gradient flood fill so that if a user fills the same circle, choosing red and blue, the resulting bitmap would look like this
My question is, is there a way that I can use the red circle as some sort of mask to make the desired gradient? or do I have to write a gradient generator myself?
Thanks to pskink's hint, I was able to find an answer.
The idea is that you create a canvas, draw the mask to it, create the gradient that you want, then draw the gradient on top of it using the SRC_IN PorterDuffXfermode. Here's the code:
public Bitmap addGradient(Bitmap src, int color1, int color2)
{
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0,0,0,h, color1, color2, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawRect(0,0,w,h,paint);
return result;
}
In this instance, the DST(destination) is the red circle and the SRC(source) is the gradient. The SRC_IN PorterDuff mode means draw the SRC everywhere that it intersects with the DST.
Note that it really doesn't matter what color the mask is, because the PorterDuff mode only pays attention to whether the DST pixel is transparent or not. The color of the resulting bitmap will be a gradient between color1 and color2.

Android Bitmap: Convert transparent pixels to a color

I have an Android app that loads an image as a bitmap and displays it in an ImageView. The problem is that the image appears to have a transparent background; this causes some of the black text on the image to disappear against the black background.
If I set the ImageView background to white, that sort of works, but I get ugly big borders on the image where it is stretched to fit the parent (the actual image is scaled in the middle).
So - I want to convert the transparent pixels in the Bitmap to a solid colour - but I cannot figure out how to do it!
Any help would be appreciate!
Thanks
Chris
If you are including the image as a resource, it is easiest to just edit the image yourself in a program like gimp. You can add your background there, and be sure of what it is going to look like and don't have use to processing power modifying the image each time it is loaded.
If you do not have control over the image yourself, you can modify it by doing something like, assuming your Bitmap is called image.
Bitmap imageWithBG = Bitmap.createBitmap(image.getWidth(), image.getHeight(),image.getConfig()); // Create another image the same size
imageWithBG.eraseColor(Color.WHITE); // set its background to white, or whatever color you want
Canvas canvas = new Canvas(imageWithBG); // create a canvas to draw on the new image
canvas.drawBitmap(image, 0f, 0f, null); // draw old image on the background
image.recycle(); // clear out old image
You can loop through each pixel and check if it is transparent.
Something like this. (Untested)
Bitmap b = ...;
for(int x = 0; x<b.getWidth(); x++){
for(int y = 0; y<b.getHeight(); y++){
if(b.getPixel(x, y) == Color.TRANSPARENT){
b.setPixel(x, y, Color.WHITE);
}
}
}

BufferedImage colour change

I have working on an application which captures screen shots and create video from captured images. But the problem is that when video is generated, colours in generated video is very pinkish. I think this is because I am manipulating captured images to show cursor using BufferedImage.TYPE_3BYTE_BGR type. Could someone tell me how to resolve this issue, I want to have the colour of video same as actual colour of screen.
For capturing screen image I am doing as follows:
Robot robot = new Robot();
Rectangle captureSize = new Rectangle(screenBounds);
return robot.createScreenCapture(captureSize);
For manipulating images I am doing as follows:
image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
if (true) {
int x = MouseInfo.getPointerInfo().getLocation().x - 25;
int y = MouseInfo.getPointerInfo().getLocation().y - 37;
Graphics2D graphics2D = sourceImage.createGraphics();`enter code here`
graphics2D.drawImage(SimpleWebBrowserExample.m_MouseIcon, x, y, 48, 48, null);
}
image.getGraphics().drawImage(sourceImage, 0, 0, null);
return image;
please tell me how to get the images with colour same as actual colour on screen.
Thanks.
Use BufferedImage.TYPE_INT_ARGB or BufferedImage.TYPE_INT_RGB, as shown in this example. If you need to change the colors, you can use a LookupOp with a four-component LookupTable that adjusts the alpha component as required for BufferedImage.TYPE_3BYTE_BGR: "When data with non-opaque alpha is stored in an image of this type, the color data must be adjusted to a non-premultiplied form and the alpha discarded." Examples may be found in Using the Java 2D LookupOp Filter Class to Process Images and Image processing with Java 2D.
See the the "pinkish" explanation here
Basically the image is saved as a ARGB and most viewers interpret it as a CMYK. Alpha is preserved when opening it back in Java, though.

Tint Bitmap with Paint?

I'm trying to create a function that tints a Bitmap,
this works...
imgPaint = new Paint();
imgPaint.setColorFilter(new LightingColorFilter(color,0));
//when image is being drawn
canvas.drawBitmap(img,matrix,imgPaint);
However, when the bitmap has to be drawn constantly (every frame) , I start to see screen lag, because this didn't occur before the color filter was set, I believe that it is applying the filter every time I need the canvas drawn.
Is there a way to apply the paint once to the bitmap and have it permanently changed?
Any help appreciated :)
Create a second bitmap and draw the first bitmap into it using the color filter. Then use the second bitmap for the high-volume rendering.
EDIT: Per request, here is code that would do this:
public Bitmap makeTintedBitmap(Bitmap src, int color) {
Bitmap result = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig());
Canvas c = new Canvas(result);
Paint paint = new Paint();
paint.setColorFilter(new LightingColorFilter(color,0));
c.drawBitmap(src, 0, 0, paint);
return result;
}
You would then call this method once to convert a bitmap to a tinted bitmap and save the result in an instance variable. You would then use the tinted bitmap directly (without a color filter) in your method that draws to canvas. (It would also be a good idea to pre-allocate the Paint object you will be using in the main draw method and save it in an instance variable as well, rather than allocating a new Paint on every draw.)

Categories

Resources