github地址
PrimaryColorDemo
效果
原始图片
就是一张普通的png图片
依据选择的主题色动态烘托。
思考
最近在思考怎么完成动态的设置图片的主题色。不是那种烘托透明iocn。而是把图片的明暗联系保存。而改动其间的主题色。总算花了半响的时刻研究出来了。和大家同享。
完成
思路很简单
- 将图片从RGB色彩空间转化为YUV色彩空间
- 使用ColorMatirx的setRotate(0, hue0);办法。将图片沿着Y轴旋转hue0的视点(视点从0到360度)
- 在家图片从YUV色彩空间转化RGB色彩空间
原理
YUV 空间
浅显的讲。YUV仅仅色彩的一种表达形式。Y中保存了图片的明暗度。UV保存了图片的色度信息。 下图所示,第一张是原图,依次是YUV重量。
setRotate办法
ColorMatirx的setRotate办法能够将色彩沿着一个轴旋转,沿着的这个轴的信息就不会改动。
/**
-
用于色彩的旋转运算
-
axis=0 表示色彩环绕赤色进行旋转
-
axis=1 表示色彩环绕绿色进行旋转
-
axis=2 表示色彩环绕蓝色进行旋转
*/
public void setRotate(int axis, float degrees)
1)环绕赤色轴旋转
咱们能够依据三原色来建立一个三维向量坐标系,当环绕赤色旋转时,咱们将赤色虚化为一个点,绿色为横坐标,蓝色为纵坐标,旋转。
偷梁换柱
如果咱们将色彩从RGB转换为YUV 那么这个时分调用setRotate(0,degrees)那么色彩就会以Y信息为轴,进行旋转degrees的视点。 由于没有改动Y信息,所以图片的明暗度不会发生改动。 代码如下
ColorMatrix cm = new ColorMatrix();
ColorMatrix tmp = new ColorMatrix();
cm.setRGB2YUV();
tmp.setRotate(0, hue0);
cm.postConcat(tmp);
tmp.setYUV2RGB();
cm.postConcat(tmp);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bitmap,0,0,paint);
难点计算这个转动视点
其实也很简单。咱们只需获取本来图片中的主题色
使用拾色器就能够搞定
然后依据方针色计算视点。
因为只转动UV信息
所以将原图中的UV信息组成一个二维向量,方针色的UV信息组成一个二维向量。
计算公式如下。
还需求注意一点 就是上面计算出来的视点是最小视点。 还要依据两个向量之间的叉积,来判别向量之间的位置联系。
叉乘公式
两个向量的叉乘,又叫向量积、外积、叉积,叉乘的运算成果是一个向量而不是一个标量。而且两个向量的叉积与这两个向量组成的坐标平面垂直。
一、二维向量叉乘公式:a(x1,y1),b(x2,y2),则ab=(x1y2-x2y1)
依据叉乘成果的正负,能够判别两个向量的位置联系
判别点P在向量AB的左侧还是右侧,则可依据向量ABxAP 的叉乘成果r 来判别,依据右手定则:
- 若r > 0,则点P在向量AB的左侧;
- 若r = 0,则点P在向量AB上;
- 若r < 0,则点P在向量AB的右侧。
代码完成
注意,主题色写死在代码里面。要扩展需求自行改动。
最终的代码如下:
package com.example.orderlayoutdemo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.util.Log;
/**
* <pre>
* Created by zhuguohui
* Date: 2023/4/21
* Time: 17:24
* Desc:
* </pre>
*/
public class ImageUtils {
public static Bitmap handleImageEffect(Bitmap bitmap,int targetColor){
//由于不能直接在原图上修正,所以创立一个图片,设定宽度高度与原图相同。为32位ARGB图片
Bitmap currentBitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);
//创立一个和原图相同巨细的画布
Canvas canvas = new Canvas(currentBitmap);
//创立笔刷并设置抗锯齿
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
float hue0=getHub(Color.parseColor("#61BCF8"),targetColor);
ColorMatrix cm = new ColorMatrix();
ColorMatrix tmp = new ColorMatrix();
cm.setRGB2YUV();
tmp.setRotate(0, hue0);
cm.postConcat(tmp);
tmp.setYUV2RGB();
cm.postConcat(tmp);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bitmap,0,0,paint);
return currentBitmap;
}
public static float getHub(int fromColor,int targetColor){
int[] yuv1 = convertRGB2YUV(fromColor);
int[] yuv2 = convertRGB2YUV(targetColor);
//计算两个色彩的uv重量组成的向量之间的夹角
return getDegreeBetweenVectors(new int[]{yuv1[1], yuv1[2]}, new int[]{yuv2[1], yuv2[2]});
}
/**
* 计算向量1,顺时针旋转多少度能够得到向量2
* 返回的度数为0到360度
* @param vs1
* @param vs2
* @return
*/
private static float getDegreeBetweenVectors(int[] vs1,int[] vs2 ){
double cosDegree=0;
//向量的内积
int nj = vs1[0] * vs2[0] + vs1[1] * vs2[1];
//叉积
int cj=vs1[0]*vs2[1]-vs1[1]*vs2[0];
double bl = Math.sqrt(vs1[0] * vs1[0] + vs1[1] * vs1[1]) *Math.sqrt(vs2[0] * vs2[0] + vs2[1] * vs2[1]);
cosDegree= (nj/bl);
double degree = Math.acos(cosDegree) / Math.PI * 180;
//叉积大于0,表示向量2 在向量1的左边
degree = (float) (cj > 0 ? 360- degree : degree);
return (float) degree;
}
private static int[] convertRGB2YUV(int color) {
ColorMatrix cm = new ColorMatrix();
cm.setRGB2YUV();
final float[] yuvArray = cm.getArray();
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
int[] result = new int[3];
result[0] = floatToByte(yuvArray[0] * r + yuvArray[1] * g + yuvArray[2] * b);
result[1] = floatToByte(yuvArray[5] * r + yuvArray[6] * g + yuvArray[7] * b) ;
result[2] = floatToByte(yuvArray[10] * r + yuvArray[11] * g + yuvArray[12] * b) ;
return result;
}
private static int floatToByte(float x) {
int n = java.lang.Math.round(x);
return n;
}
}