颜色的一些基本概念:
色调:物体颜色,色彩效果,如红/黄/蓝/绿等。
饱和度:颜色的鲜艳程度,从0%到100%。
亮度:颜色明暗程度
RGBA模型:Red+Green+Blue+Alpha。RGBA模型描述了一个图片的颜色+透明度。
矩阵乘法的基本概念:
比如,矩阵[ 1, 2 和 矩阵 [ 2
2, 3 ] 1 ]
相乘,结果是
[ 1*2 + 2*1 [4
2*2 + 3*1] = 7]
用公式表示:
矩阵A:
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t]
矩阵B:
[ R
G
B
A
1 ]
两矩阵相乘,AB = C, 矩阵C为:
G' = f*R + g*G + h*B + i*A + j;
B' = k*R + l*G + m*B + n*A + o;
A' = p*R + q*G + r*B + s*A + t;
即:
[ R'
G'
B'
A']
以上的算式中,如果用矩阵B的值描述一个图形的RGBA的话,则矩阵A的第一行abcde影响这个图形的R值,第二行fghij影响这个图形的G值,同理,第三第四行分别影响这个图形的B和A。
Android中,用ColorMatrix这个类来代表矩阵A,一个图形的颜色信息可以用ColorMatrix这个类来改变。ColorMatrix是一个5*4的矩阵,它被存放在一个数组中。以上面矩阵A举例,存放形式为: [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
ColorMatrix有一个方法 reset,这个方法使图形恢复原来的颜色水平,它将矩阵的值设置为:
[1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0 ]
这样,调用reset方法后,和[RGBA1]矩阵相乘,RGBA的分量保持不变。依然是RGBA
下面用一个例子说明以上内容:
创建一个Activity,布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_weight="2" />
<GridLayout
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:columnCount="5"
android:rowCount="4" >
</GridLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="btnChange"
android:text="Change" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="btnReset"
android:text="Reset" />
</LinearLayout>
</LinearLayout>
最上面是显示图片的ImageView,下方GridView中会通过代码增加5*4的EditText,用于控制Matrix的值。
Activity:
public class MainActivity extends ActionBarActivity {
private ImageView mImageView;
private GridLayout mGroup;
private int mEtWidth, mEtHeight;
private EditText[] mEts = new EditText[20];
private float[] mColorMatrix = new float[20];
private Bitmap originBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageview);
mGroup = (GridLayout) findViewById(R.id.group);
originBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.dragon);
mImageView.setImageBitmap(originBitmap);
// GridView的大小确定后,
// 计算其中每个EditText应有的大小(5*4),
// 并添加到GridView中。
mGroup.post(new Runnable() {
@Override
public void run() {
mEtWidth = mGroup.getWidth() / 5;
mEtHeight = mGroup.getHeight() / 4;
addEts();
}
});
}
public void btnChange(View view) {
getMatrix();
setImageMatrix();
}
public void btnReset(View view) {
initMatrix();
getMatrix();
setImageMatrix();
}
private void setImageMatrix() {
Bitmap bmp = Bitmap.createBitmap(originBitmap.getWidth(),
originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
// 设置新的ColorMatrix.
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.set(mColorMatrix);
// 使用新的ColorMatrix绘制Bitmap
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(originBitmap, 0, 0, paint);
mImageView.setImageBitmap(bmp);
}
private void addEts() {
for (int i = 0; i < 20; i++) {
EditText editText = new EditText(MainActivity.this);
editText.setBackground(getResources().getDrawable(
R.drawable.common_textfield_background));
editText.setInputType(InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_DECIMAL);
mEts[i] = editText;
mGroup.addView(editText, mEtWidth, mEtHeight);
}
}
private void getMatrix() {
for (int i = 0; i < 20; i++) {
String etNum = mEts[i].getText().toString();
if (TextUtils.isEmpty(etNum)) {
mEts[i].setText("0");
etNum = "0";
}
mColorMatrix[i] = Float.valueOf(etNum);
}
}
/**
* 初始化矩阵数组为: [ 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 ]
* */
private void initMatrix() {
for (int i = 0; i < 20; i++) {
if (i % 6 == 0) {
mEts[i].setText(String.valueOf(1));
} else {
mEts[i].setText(String.valueOf(0));
}
}
}
}
以上代码,setImageMatrix方法通过用户输入,改变ColorMatrix内部数组的值(用mColorMatrix),并用这个ColorMatrix绘制Bitmap,来改变图片的颜色效果。getMatrix方法用于把EditText里面的数字赋值到 mColorMatrix数组中。
界面初始效果:
现在试着改变第一行的值,第二,第三个EditText的值改为0.5,点击Change按钮,查看图片变化。
可以看到,由于改变了ColorMatrix数组的第一行数值,图片的R值被增加,所以图片偏红,同理,改变第二行图片颜色会偏绿,改变第三行图片颜色会偏蓝,改变第四行透明度 会改变。
ColorMatrix这个类为图片调色提供了便捷方法。
setScale:设置R,G,B颜色分量的色调
源码:
public void setScale(float rScale, float gScale, float bScale,
float aScale) {
final float[] a = mArray;
for (int i = 19; i > 0; --i) {
a[i] = 0;
}
a[0] = rScale;
a[6] = gScale;
a[12] = bScale;
a[18] = aScale;
}
setRotate:设置R,G,B颜色分量的亮度
源码:
public void setRotate(int axis, float degrees) {
reset();
float radians = degrees * (float)Math.PI / 180;
float cosine = FloatMath.cos(radians);
float sine = FloatMath.sin(radians);
switch (axis) {
// Rotation around the red color
case 0:
mArray[6] = mArray[12] = cosine;
mArray[7] = sine;
mArray[11] = -sine;
break;
// Rotation around the green color
case 1:
mArray[0] = mArray[12] = cosine;
mArray[2] = -sine;
mArray[10] = sine;
break;
// Rotation around the blue color
case 2:
mArray[0] = mArray[6] = cosine;
mArray[1] = sine;
mArray[5] = -sine;
break;
default:
throw new RuntimeException();
}
}
setSaturation:设置色彩饱和度
源码:
public void setSaturation(float sat) {
reset();
float[] m = mArray;
final float invSat = 1 - sat;
final float R = 0.213f * invSat;
final float G = 0.715f * invSat;
final float B = 0.072f * invSat;
m[0] = R + sat; m[1] = G; m[2] = B;
m[5] = R; m[6] = G + sat; m[7] = B;
m[10] = R; m[11] = G; m[12] = B + sat;
}
通过以上3段代码看出,这3个方法的本质还是去改变ColorMatrix矩阵的数组的值。
下面用一个例子说明:
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="10dp"
/>
<!-- saturation -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/et_saturation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="饱和度"
/>
<Button
android:id="@+id/btn_set_saturation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="setSaturation"
android:text="设置饱和度"
/>
</LinearLayout>
<!-- rotate -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/et_red"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="R"
/>
<EditText
android:id="@+id/et_green"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="G"
/>
<EditText
android:id="@+id/et_blue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="B"
/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:onClick="setHue"
android:text="设置色调"
/>
</LinearLayout>
<!-- scale -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/et_redlum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="R"
/>
<EditText
android:id="@+id/et_greenlum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="G"
/>
<EditText
android:id="@+id/et_bluelum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_weight="1"
android:hint="B"
/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:onClick="setLum"
android:text="设置亮度"
/>
</LinearLayout>
</LinearLayout>
Activity:
public class ChangeMatrix extends Activity {
private EditText saturation;
private EditText red;
private EditText green;
private EditText blue;
private EditText redLum;
private EditText greenLum;
private EditText blueLum;
private ImageView imageView;
private Bitmap originBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_change_matrix);
saturation = (EditText) findViewById(R.id.et_saturation);
imageView = (ImageView) findViewById(R.id.imageview);
red = (EditText) findViewById(R.id.et_red);
green = (EditText) findViewById(R.id.et_green);
blue = (EditText) findViewById(R.id.et_blue);
redLum = (EditText) findViewById(R.id.et_redlum);
greenLum = (EditText) findViewById(R.id.et_greenlum);
blueLum = (EditText) findViewById(R.id.et_bluelum);
originBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.dragon);
imageView.setImageBitmap(originBitmap);
}
public void setSaturation(View view) {
float satu = Float.valueOf(handleNullValue(saturation.getText()
.toString()));
Bitmap bm = getNewSatuBitmap(satu);
imageView.setImageBitmap(bm);
}
public void setHue(View view) {
float rHue = Float.valueOf(handleNullValue(red.getText().toString()));
float gHue = Float.valueOf(handleNullValue(green.getText().toString()));
float bHue = Float.valueOf(handleNullValue(blue.getText().toString()));
Bitmap bm = getNewHueBitmap(rHue, gHue, bHue);
imageView.setImageBitmap(bm);
}
public void setLum(View view) {
float rLum = Float
.valueOf(handleNullValue(redLum.getText().toString()));
float gLum = Float.valueOf(handleNullValue(greenLum.getText()
.toString()));
float bLum = Float
.valueOf(handleNullValue(blueLum.getText().toString()));
Bitmap bm = getNewLumBitmap(rLum, gLum, bLum);
imageView.setImageBitmap(bm);
}
/**
* @Description: 设置图片饱和度
* @param @param saturation
* @param @return
* @return Bitmap
* @throws
*/
private Bitmap getNewSatuBitmap(float saturation) {
reset();
Bitmap bmp = Bitmap.createBitmap(originBitmap.getWidth(),
originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
ColorMatrix saturationMatrix = new ColorMatrix();
saturationMatrix.setSaturation(saturation);
paint.setColorFilter(new ColorMatrixColorFilter(saturationMatrix));
canvas.drawBitmap(originBitmap, 0, 0, paint);
return bmp;
}
/**
* @Description: 设置图片色调
* @param @param rHue 红色色调
* @param @param gHue 绿色色调
* @param @param bHue 蓝色色调
* @param @return
* @return Bitmap
* @throws
*/
private Bitmap getNewLumBitmap(float rLum, float gLum, float bLum) {
reset();
Bitmap bmp = Bitmap.createBitmap(originBitmap.getWidth(),
originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
ColorMatrix rotateMatrix = new ColorMatrix();
rotateMatrix.setScale(rLum, gLum, bLum, 1);
paint.setColorFilter(new ColorMatrixColorFilter(rotateMatrix));
canvas.drawBitmap(originBitmap, 0, 0, paint);
return bmp;
}
/**
* @Description: 设置亮度
* @param @param rHue
* @param @param gHue
* @param @param bHue
* @param @return
* @return Bitmap
* @throws
*/
private Bitmap getNewHueBitmap(float rHue, float gHue, float bHue) {
reset();
Bitmap bmp = Bitmap.createBitmap(originBitmap.getWidth(),
originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
ColorMatrix rotateMatrix = new ColorMatrix();
// 红
rotateMatrix.setRotate(0, rHue);
// 绿
rotateMatrix.setRotate(1, gHue);
// 蓝
rotateMatrix.setRotate(2, bHue);
paint.setColorFilter(new ColorMatrixColorFilter(rotateMatrix));
canvas.drawBitmap(originBitmap, 0, 0, paint);
return bmp;
}
private void reset() {
Bitmap bmp = Bitmap.createBitmap(originBitmap.getWidth(),
originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
ColorMatrix rotateMatrix = new ColorMatrix();
paint.setColorFilter(new ColorMatrixColorFilter(rotateMatrix));
canvas.drawBitmap(originBitmap, 0, 0, paint);
}
private String handleNullValue(String value) {
if (TextUtils.isEmpty(value)) {
return "1";
}
return value;
}
}
点击按钮后的效果图: