I want to apply a gradient to a bitmap. So far I'm using this technique.
here is my code in the onCreate method of MainActivity.class.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
double angle = Math.toRadians(135);
double length = 100;
int x = (int) (Math.cos(angle) * length);
int y = (int) (Math.sin(angle) * length);
int[] colors = new int[3];
colors[0] = Color.parseColor("#FF4081");
colors[1] = Color.parseColor("#3F51B5");
Bitmap bitmap = Bitmap.createBitmap(1080, 1080, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
LinearGradient linearGradient =
new LinearGradient(0, 0, x, y, colors[1], colors[0], Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setDither(true);
paint.setShader(linearGradient);
canvas.drawRect(new RectF(0, 0, 1080, 1080), paint);
ImageView imageView = findViewById(R.id.iv);
imageView.setImageBitmap(bitmap);
}
}
which results in this
but I want to get an effect like this
image 2 results were achieved by simply creating a drawable XML file with the following code
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="45"
android:endColor="#color/colorPrimary"
android:startColor="#color/colorAccent" />
</shape>
and setting it as a background for an ImageView, but I want this effect on the bitmap because I want to save that bitmap locally as an Image. I have tried creating a GradientDrawable instance in the MainActivity and calling onDraw(canvas) on the GradientDrawable as mentioned in the post
As I see, you calculated the angle incorrect.
Instead of this
LinearGradient linearGradient =
new LinearGradient(0, 0, x, y, colors[1], colors[0], Shader.TileMode.CLAMP);
Use this
LinearGradient linearGradient =
new LinearGradient(1080, 0, 0, 1080, colors[1], colors[0], Shader.TileMode.CLAMP);
x0 is gradient start X, y0 is gradient start Y, x1 is gradient end X and y1 is gradient end Y.
Hope I helped you.
Glow effect is working fine. my doubt is how to hide glow effect? if i click my imageview, that time only i wish to show my glow effect please how to hide and show glow effect while on click.
code:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// An added margin to the initial image
int margin = 24;
int halfMargin = margin / 2;
// the glow radius
int glowRadius = 16;
// the glow color
int glowColor = Color.rgb(0, 192, 255);
// The original image to use
Bitmap src = BitmapFactory.decodeResource(getResources(),
R.drawable.test);
// extract the alpha from the source image
Bitmap alpha = src.extractAlpha();
// The output bitmap (with the icon + glow)
Bitmap bmp = Bitmap.createBitmap(src.getWidth() + margin,
src.getHeight() + margin, Bitmap.Config.ARGB_8888);
// The canvas to paint on the image
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint();
paint.setColor(glowColor);
// outer glow
paint.setMaskFilter(new BlurMaskFilter(glowRadius, Blur.OUTER));
canvas.drawBitmap(alpha, halfMargin, halfMargin, paint);
// original icon
canvas.drawBitmap(src, halfMargin, halfMargin, null);
setContentView(R.layout.activity_main);
((ImageView) findViewById(R.id.bmpImg)).setImageBitmap(bmp);
}
}
present screen shot:
set onclicklistener and implement this code:
.setOnClickListener(clicklistener);
private OnClickListener backListener = new OnClickListener() {
public void onClick(View v) {
// An added margin to the initial image
int margin = 24;
int halfMargin = margin / 2;
// the glow radius
int glowRadius = 16;
// the glow color
int glowColor = Color.rgb(0, 192, 255);
// The original image to use
Bitmap src = BitmapFactory.decodeResource(getResources(),
R.drawable.test);
// extract the alpha from the source image
Bitmap alpha = src.extractAlpha();
// The output bitmap (with the icon + glow)
Bitmap bmp = Bitmap.createBitmap(src.getWidth() + margin,
src.getHeight() + margin, Bitmap.Config.ARGB_8888);
// The canvas to paint on the image
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint();
paint.setColor(glowColor);
// outer glow
paint.setMaskFilter(new BlurMaskFilter(glowRadius, Blur.OUTER));
canvas.drawBitmap(alpha, halfMargin, halfMargin, paint);
// original icon
canvas.drawBitmap(src, halfMargin, halfMargin, null);
}}
you can set null for setMaskFilter() like this way
paint.setMaskFilter(null);
and you need just set paint.setMaskFilter(new BlurMaskFilter(glowRadius, Blur.OUTER));
for this you need keep paint object for application scope so this paint object can accessing out in another class or activity wherever you want or you can set flag for true then show glow effect and false the flag set nothing (as default)
An easier way to do this would be to use StateListDrawable.
Create two images - one for normal state and one for pressed state (with glow). Use this in the res/drawable/button_drawable.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#drawable/image_normal"
android:state_enabled="true"/>
<item
android:drawable="#drawable/image_pressed"
android:state_pressed="true"/>
</selector>
and use it as the buttom drawable:
((ImageView) findViewById(R.id.bmpImg)).setImageDrawable(getResources().getDrawable(R.drawable.button_drawable));
I have an ImageView with bitmap in it. This bitmap has alpha channel and transparent pixels.
When i try to use ColorFiter with Mode.OVERLAY (since honeycomb) - provided color overlay the whole imageview (whole rect), but i want only to overlay non transparent pixels. How can i clip the imageview's canvas to perform filter where i want ?
UPDATED
I have grey image in png:
When i try to use MODE_ATOP i get:
When i use OVERLAY i get:
And what i want to get:
There's probably a more efficient way to do this (maybe by creating a ColorMatrixColorFilter to approximate it), but since Mode.OVERLAY appear to be hard to simplify otherwise, here's some sample code that should implement what you want:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ImageView imageView = new ImageView(this);
setContentView(imageView);
final Paint paint = new Paint();
Canvas c;
final Bitmap src = BitmapFactory.decodeResource(getResources(),
android.R.drawable.sym_def_app_icon);
final int overlayColor = Color.RED;
final Bitmap bm1 = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888);
c = new Canvas(bm1);
paint.setColorFilter(new PorterDuffColorFilter(overlayColor, PorterDuff.Mode.OVERLAY));
c.drawBitmap(src, 0, 0, paint);
final Bitmap bm2 = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888);
c = new Canvas(bm2);
paint.setColorFilter(new PorterDuffColorFilter(overlayColor, PorterDuff.Mode.SRC_ATOP));
c.drawBitmap(src, 0, 0, paint);
paint.setColorFilter(null);
paint.setXfermode(new AvoidXfermode(overlayColor, 0, Mode.TARGET));
c.drawBitmap(bm1, 0, 0, paint);
imageView.setImageBitmap(bm2);
}
}
In short, we draw the source bitmap and color using the OVERLAY mode, and then using a secondary bitmap (composited using SRC_ATOP mode), we combine it using AvoidXfermode to not draw over the transparent pixels.
Original image:
Result:
You can use the Overlay mode and then clip out the area that used to be transparent with the same bitmap using DST_ATOP xFerMode. https://developer.android.com/reference/android/graphics/PorterDuff.Mode
private fun applyFilterToImage() {
val bitmapCopy = Bitmap.createBitmap(originalImage.width, originalImage.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmapCopy)
val rnd = java.util.Random()
val randomColor = Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))
val paint = Paint()
val porterDuffMode = PorterDuff.Mode.OVERLAY
paint.colorFilter = PorterDuffColorFilter(randomColor, porterDuffMode)
val maskPaint = Paint()
maskPaint. xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)
canvas.drawBitmap(originalImage, 0f, 0f, paint)
canvas.drawBitmap(originalImage, 0f, 0f, maskPaint) //clips out the background that used to be transparent.
imageView.setImageBitmap(bitmapCopy)
}
MarkerColorChangeGIF
I am working in an android application and I want to place an ImageView in a particular position in my view. For that I applied the particular code and worked successfully :
ImageView image = (ImageView) findViewById(R.id.imageView1);
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.mrng);
Matrix mat = new Matrix();
mat.postRotate(350);
Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(),bMap.getHeight(), mat, true);
image.setImageBitmap(bMapRotate);
Now I want to set a border to this image. For that I made a an shape xml and I have set as the background of the image view.
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<stroke android:width="3dp" android:color="#000000" />
</shape>
But when I gave the background of the image view the shape it does not give the correct output.please help me.
I do not want a border around the ImageView, but rather border around the rotated image.
EDIT: I'm completely rewriting my answer based on the clarification of the question. Here's how I achieved what you want. The idea is to draw the frame and then rotate:
ImageView image = (ImageView) findViewById(R.id.TestImage);
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
final int BORDER_WIDTH = 3;
final int BORDER_COLOR = Color.BLACK;
Bitmap res = Bitmap.createBitmap(bMap.getWidth() + 2 * BORDER_WIDTH,
bMap.getHeight() + 2 * BORDER_WIDTH,
bMap.getConfig());
Canvas c = new Canvas(res);
Paint p = new Paint();
p.setColor(BORDER_COLOR);
c.drawRect(0, 0, res.getWidth(), res.getHeight(), p);
p = new Paint(Paint.FILTER_BITMAP_FLAG);
c.drawBitmap(bMap, BORDER_WIDTH, BORDER_WIDTH, p);
Matrix mat = new Matrix();
mat.postRotate(350);
Bitmap bMapRotate = Bitmap.createBitmap(res, 0, 0, res.getWidth(), res.getHeight(), mat, true);
image.setImageBitmap(bMapRotate);
And here's the screenshot of the result:
There is way to put border around ImageView even any view in android. In XML put Four simple <View>'s on each side of the imageview. And these view's can be assigned any type of style. You can use relative layout in which you can place four borders easily around image view.
Kinda lengthy process but works.
I am developing an android application in which I set an image to imageview. Now programmatic I want to change the bitmap image color. Suppose my image have red color initially and now I need to change it to orange color. How can I do that? Please help.
Here is my code. I managed to change the opacity but I do not know how to change the color.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView iv = (ImageView) findViewById(R.id.img);
Drawable d = getResources().getDrawable(R.drawable.pic1);
Bitmap mNewBitmap = ((BitmapDrawable)d).getBitmap();
Bitmap nNewBitmap = adjustOpacity(mNewBitmap);
iv.setImageBitmap(nNewBitmap);
}
private Bitmap adjustOpacity( Bitmap bitmap ) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap dest = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
dest.setPixels(pixels, 0, width, 0, 0, width, height);
return dest;
}
I tried Josip's answer but wouldn't work for me, regardless of whether the offset parameter was 1 or 0 - the drawn bitmap just appeared in original colour.
However, this did work:
// You have to copy the bitmap as any bitmaps loaded as drawables are immutable
Bitmap bm = ImageLoader.getInstance().loadImageSync("drawable://" + drawableId, o)
.copy(Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(ContextCompat.getColor(this, R.color.COLOR_1_DARK), PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
Canvas canvas = new Canvas(bm);
canvas.drawBitmap(bm, 0, 0, paint);
Update 1
Whilst the above works well and is useful in a lot of cases, if you just want to change the main colour of an ImageView drawable, which the op did, you can just use:
imgView.setColorFilter(ContextCompat.getColor(this, R.color.COLOR_1_DARK));
If you need more flexibility or this doesn't give the desired effect, there's an overload that allows you to change the PorterDuff Mode until you get what you're after:
imgView.setColorFilter(ContextCompat.getColor(this, R.color.COLOR_1_DARK), PorterDuff.Mode.SRC_ATOP);
Update 2
Another good use case I've had for this lately is customizing the appearance of a Google map v2 marker icon. In order to use 2 graphics to allow (for example) small/large icons on a marker, but also a range of colours on those 2 graphics by changing the colour of them dynamically. In my case I was doing this inside a ClusterRenderer as the markers were also clustered, but this can be used with a regular map marker the same way:
#Override
protected void onBeforeClusterItemRendered(MyClusterItem item, MarkerOptions markerOptions) {
try {
int markerColor = item.getColor();
Bitmap icon;
if (item.isFeatured()) {
// We must copy the bitmap or we get an exception "Immutable bitmap passed to Canvas constructor"
icon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.icon_marker_large).copy(Bitmap.Config.ARGB_8888, true);
} else {
// We must copy the bitmap or we get an exception "Immutable bitmap passed to Canvas constructor"
icon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.icon_marker_small).copy(Bitmap.Config.ARGB_8888, true);
}
Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(ContextCompat.getColor(context, markerColor), PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
Canvas canvas = new Canvas(icon);
canvas.drawBitmap(icon, 0, 0, paint);
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
} catch (Exception ex) {
ex.printStackTrace();
}
}
I got kind of solution.
Bitmap sourceBitmap = BitmapFactory.decodeFile(imgPath);
float[] colorTransform = {
0, 1f, 0, 0, 0,
0, 0, 0f, 0, 0,
0, 0, 0, 0f, 0,
0, 0, 0, 1f, 0};
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0f); //Remove Colour
colorMatrix.set(colorTransform); //Apply the Red
ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
Paint paint = new Paint();
paint.setColorFilter(colorFilter);
Display display = getWindowManager().getDefaultDisplay();
Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, (int)(display.getHeight() * 0.15), display.getWidth(), (int)(display.getHeight() * 0.75));
image.setImageBitmap(resultBitmap);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(resultBitmap, 0, 0, paint);
private void changeColor(){
ImageView image = (ImageView) findViewById(R.id.imageView1);
Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
changeBitmapColor(sourceBitmap, image, Color.BLUE);
}
private void changeBitmapColor(Bitmap sourceBitmap, ImageView image, int color) {
Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0,
sourceBitmap.getWidth() - 1, sourceBitmap.getHeight() - 1);
Paint p = new Paint();
ColorFilter filter = new LightingColorFilter(color, 1);
p.setColorFilter(filter);
image.setImageBitmap(resultBitmap);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(resultBitmap, 0, 0, p);
}
It's better obtain mutable bitmap by copy, without changing size:
public static Bitmap changeBitmapColor(Bitmap sourceBitmap, int color)
{
Bitmap resultBitmap = sourceBitmap.copy(sourceBitmap.getConfig(),true);
Paint paint = new Paint();
ColorFilter filter = new LightingColorFilter(color, 1);
paint.setColorFilter(filter);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(resultBitmap, 0, 0, paint);
return resultBitmap;
}
public Bitmap replaceColor(Bitmap src,int fromColor, int targetColor) {
if(src == null) {
return null;
}
// Source image size
int width = src.getWidth();
int height = src.getHeight();
int[] pixels = new int[width * height];
//get pixels
src.getPixels(pixels, 0, width, 0, 0, width, height);
for(int x = 0; x < pixels.length; ++x) {
pixels[x] = (pixels[x] == fromColor) ? targetColor : pixels[x];
}
// create result bitmap output
Bitmap result = Bitmap.createBitmap(width, height, src.getConfig());
//set pixels
result.setPixels(pixels, 0, width, 0, 0, width, height);
return result;
}
The simplest way to change the bitmaps color is with this method:
bitmap.eraseColor(ContextCompat.getColor(this, R.color.your_color));
If you want to overlay the ImageView with color use:
imageView.setColorFilter(ContextCompat.getColor(this, R.color.your_color));
A little off topic, but considering you only want to display in changed color here is my solution. Namely, the easiest and fast way is just applying a filter by using drawColor() method on Canvas, right after drawBitmap():
m_canvas.drawColor(Color.RED, PorterDuff.Mode.ADD);
Sources: https://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
Even if bitmap is immutable, it will work.
Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(ContextCompat.getColor(context, R.color.whatColorNeed), PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
canvas.drawBitmap(bitmapToModify, some_x, some_y, paint);
I have solved the problem by using the below code
public void changeColor(Bitmap srcImage) {
Bitmap bmpRedscale = Bitmap.createBitmap(srcImage.getWidth(),
srcImage.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpRedscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setRGB2YUV();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(srcImage, 0, 0, paint);
mImgEdited.setImageBitmap(bmpRedscale);
}
In Kotlin :
private fun changeBitmapColor(oldBitmap: Bitmap, newColor: Int): Bitmap {
val paint = Paint()
val filter: ColorFilter = PorterDuffColorFilter(
newColor,
PorterDuff.Mode.SRC_IN
)
paint.colorFilter = filter
val canvas = Canvas(oldBitmap)
canvas.drawBitmap(oldBitmap, 0f, 0f, paint)
return oldBitmap
}
This function PorterDuff.Mode.SRC_IN can change due to the Bitmap file, look this link https://developer.android.com/reference/android/graphics/PorterDuff.Mode