android图像处理系列之三--图片色调饱和度、色相、亮度处理

原图:


处理后:


下面贴代码:

一、图片处理层:

package com.jacp.tone.view;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import com.jacp.tone.R;

/**
 * 图片调色处理
 * @author maylian7700@126.com
 *
 */
public class ToneLayer {
	
	/**
	 * 饱和度标识
	 */
	public static final int FLAG_SATURATION = 0x0;
	
	/**
	 * 亮度标识
	 */
	public static final int FLAG_LUM = 0x1;
	
	/**
	 * 色相标识
	 */
	public static final int FLAG_HUE = 0x2;
	
	/**
	 * 饱和度
	 */
	private TextView mSaturation;
	private SeekBar mSaturationBar;

	/**
	 * 色相
	 */
	private TextView mHue;
	private SeekBar mHueBar;

	/**
	 * 亮度
	 */
	private TextView mLum;
	private SeekBar mLumBar;

	private float mDensity;
	private static final int TEXT_WIDTH = 50;

	private LinearLayout mParent;

	private ColorMatrix mLightnessMatrix;
	private ColorMatrix mSaturationMatrix;
	private ColorMatrix mHueMatrix;
	private ColorMatrix mAllMatrix;

	/**
	 * 亮度
	 */
	private float mLumValue = 1F;

	/**
	 * 饱和度
	 */
	private float mSaturationValue = 0F;

	/**
	 * 色相
	 */
	private float mHueValue = 0F;
	
	/**
	 * SeekBar的中间值
	 */
	private static final int MIDDLE_VALUE = 127;
	
	/**
	 * SeekBar的最大值
	 */
	private static final int MAX_VALUE = 255;
	
	private ArrayList<SeekBar> mSeekBars = new ArrayList<SeekBar>();

	public ToneLayer(Context context) {
		init(context);
	}

	private void init(Context context) {
		mDensity = context.getResources().getDisplayMetrics().density;

		mSaturation = new TextView(context);
		mSaturation.setText(R.string.saturation);
		mHue = new TextView(context);
		mHue.setText(R.string.contrast);
		mLum = new TextView(context);
		mLum.setText(R.string.lightness);
		
		mSaturationBar = new SeekBar(context);
		mHueBar = new SeekBar(context);
		mLumBar = new SeekBar(context);
		
		mSeekBars.add(mSaturationBar);
		mSeekBars.add(mHueBar);
		mSeekBars.add(mLumBar);
		
		for (int i = 0, size = mSeekBars.size(); i < size; i++) {
			SeekBar seekBar = mSeekBars.get(i);
			seekBar.setMax(MAX_VALUE);
			seekBar.setProgress(MIDDLE_VALUE);
			seekBar.setTag(i);
		}

		LinearLayout saturation = new LinearLayout(context);
		saturation.setOrientation(LinearLayout.HORIZONTAL);
		saturation.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));

		LinearLayout.LayoutParams txtLayoutparams = new LinearLayout.LayoutParams((int) (TEXT_WIDTH * mDensity), LinearLayout.LayoutParams.MATCH_PARENT);
		mSaturation.setGravity(Gravity.CENTER);
		saturation.addView(mSaturation, txtLayoutparams);

		LinearLayout.LayoutParams seekLayoutparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
		saturation.addView(mSaturationBar, seekLayoutparams);

		LinearLayout hue = new LinearLayout(context);
		hue.setOrientation(LinearLayout.HORIZONTAL);
		hue.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));

		mHue.setGravity(Gravity.CENTER);
		hue.addView(mHue, txtLayoutparams);
		hue.addView(mHueBar, seekLayoutparams);

		LinearLayout lum = new LinearLayout(context);
		lum.setOrientation(LinearLayout.HORIZONTAL);
		lum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));

		mLum.setGravity(Gravity.CENTER);
		lum.addView(mLum, txtLayoutparams);
		lum.addView(mLumBar, seekLayoutparams);

		mParent = new LinearLayout(context);
		mParent.setOrientation(LinearLayout.VERTICAL);
		mParent.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
		mParent.addView(saturation);
		mParent.addView(hue);
		mParent.addView(lum);
	}

	public View getParentView() {
		return mParent;
	}

	/**
	 * 设置饱和度值
	 * @param saturation
	 */
	public void setSaturation(int saturation) {
		mSaturationValue = saturation * 1.0F / MIDDLE_VALUE;
	}

	/**
	 * 设置色相值
	 * @param hue
	 */
	public void setHue(int hue) {
		mHueValue = hue * 1.0F / MIDDLE_VALUE;
	}

	/**
	 * 设置亮度值
	 * @param lum
	 */
	public void setLum(int lum) {
		mLumValue = (lum - MIDDLE_VALUE) * 1.0F / MIDDLE_VALUE * 180;
	}

	public ArrayList<SeekBar> getSeekBars()
	{
		return mSeekBars;
	}

	/**
	 * 
	 * @param flag
	 *            比特位0 表示是否改变色相,比位1表示是否改变饱和度,比特位2表示是否改变明亮度
	 */
	public Bitmap handleImage(Bitmap bm, int flag) {
		Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
				Bitmap.Config.ARGB_8888);
		// 创建一个相同尺寸的可变的位图区,用于绘制调色后的图片
		Canvas canvas = new Canvas(bmp); // 得到画笔对象
		Paint paint = new Paint(); // 新建paint
		paint.setAntiAlias(true); // 设置抗锯齿,也即是边缘做平滑处理
		if (null == mAllMatrix) {
			mAllMatrix = new ColorMatrix();
		}

		if (null == mLightnessMatrix) {
			mLightnessMatrix = new ColorMatrix(); // 用于颜色变换的矩阵,android位图颜色变化处理主要是靠该对象完成
		}

		if (null == mSaturationMatrix) {
			mSaturationMatrix = new ColorMatrix();
		}

		if (null == mHueMatrix) {
			mHueMatrix = new ColorMatrix();
		}

		switch (flag) {
		case FLAG_HUE: // 需要改变色相
			mHueMatrix.reset();
			mHueMatrix.setScale(mHueValue, mHueValue, mHueValue, 1); // 红、绿、蓝三分量按相同的比例,最后一个参数1表示透明度不做变化,此函数详细说明参考
			// // android
			// doc
			break;
		case FLAG_SATURATION: // 需要改变饱和度
			// saturation 饱和度值,最小可设为0,此时对应的是灰度图(也就是俗话的“黑白图”),
			// 为1表示饱和度不变,设置大于1,就显示过饱和
			mSaturationMatrix.reset();
			mSaturationMatrix.setSaturation(mSaturationValue);
			break;
		case FLAG_LUM: // 亮度
			// hueColor就是色轮旋转的角度,正值表示顺时针旋转,负值表示逆时针旋转
			mLightnessMatrix.reset(); // 设为默认值
			mLightnessMatrix.setRotate(0, mLumValue); // 控制让红色区在色轮上旋转的角度
			mLightnessMatrix.setRotate(1, mLumValue); // 控制让绿红色区在色轮上旋转的角度
			mLightnessMatrix.setRotate(2, mLumValue); // 控制让蓝色区在色轮上旋转的角度
			// 这里相当于改变的是全图的色相
			break;
		}
		mAllMatrix.reset();
		mAllMatrix.postConcat(mHueMatrix);
		mAllMatrix.postConcat(mSaturationMatrix); // 效果叠加
		mAllMatrix.postConcat(mLightnessMatrix); // 效果叠加

		paint.setColorFilter(new ColorMatrixColorFilter(mAllMatrix));// 设置颜色变换效果
		canvas.drawBitmap(bm, 0, 0, paint); // 将颜色变化后的图片输出到新创建的位图区
		// 返回新的位图,也即调色处理后的图片
		return bmp;
	}

}


二、主界面:

package com.jacp.tone;

import java.util.ArrayList;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

import com.jacp.tone.view.ToneLayer;

/**
 * 启动的主界面
 * @author maylian7700@126.com
 *
 */
public class ImageToneActivity extends Activity implements OnSeekBarChangeListener {
	private ToneLayer mToneLayer;
	private ImageView mImageView;
	private Bitmap mBitmap;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        init();
    }
    
    private void init()
    {
    	mToneLayer = new ToneLayer(this);
        
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
        mImageView = (ImageView) findViewById(R.id.img_view);
        mImageView.setImageBitmap(mBitmap);
        ((LinearLayout) findViewById(R.id.tone_view)).addView(mToneLayer.getParentView());
        
        ArrayList<SeekBar> seekBars = mToneLayer.getSeekBars();
        for (int i = 0, size = seekBars.size(); i < size; i++)
        {
        	seekBars.get(i).setOnSeekBarChangeListener(this);
        }
    }

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		int flag = (Integer) seekBar.getTag();
		switch (flag)
		{
		case ToneLayer.FLAG_SATURATION:
			mToneLayer.setSaturation(progress);
			break;
		case ToneLayer.FLAG_LUM:
			mToneLayer.setLum(progress);
			break;
		case ToneLayer.FLAG_HUE:
			mToneLayer.setHue(progress);
			break;
		}
		
		mImageView.setImageBitmap(mToneLayer.handleImage(mBitmap, flag));
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
		
	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
		
	}
}


三、布局文件:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    
	<LinearLayout 
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
	    android:orientation="vertical" >
	
	    <ImageView
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:id="@+id/img_view"
	        android:layout_gravity="center"
	        />
	    <LinearLayout
	        android:layout_width="match_parent"
	        android:layout_height="wrap_content"
	        android:id="@+id/tone_view"
	        />
	</LinearLayout>
</ScrollView>


 

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值