您的位置:首页 > 理论基础 > 计算机网络

Android开发本地及网络Mp3音乐播放器(七)循环模式与专辑倒影

2016-04-25 18:17 661 查看
实现功能:

顺序播放

随机播放

单曲循环

PlayActivity(独立音乐播放界面)的专辑封面图片的倒影效果

截止到目前的源码下载:
http://download.csdn.net/detail/iwanghang/9502218
欢迎移动开发爱好者交流:我的微信是iwanghang

另外,我打算开始找工作,如果沈阳或周边城市公司有意,也请与我联系。

实现效果如图:











实现代码如下:

PlayService如下:

package com.iwanghang.drmplayer;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;

import com.iwanghang.drmplayer.utils.MediaUtils;
import com.iwanghang.drmplayer.vo.Mp3Info;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 音乐播放的服务组件
* 实现功能:
* 播放
* 暂停
* 下一首
* 上一首
* 获取当前歌曲的播放进度
*
* 需要在AndroidManifest.xml添加以下代码:
*<service
*android:name=".PlayService"
*android:enabled="true"
*android:exported="true">
*</service>
*
* 实现功能(播放模式play_mode):
* 顺序播放
* 随机播放
* 单曲循环
*/
public class PlayService extends Service implements OnCompletionListener,OnErrorListener{
private MediaPlayer mPlayer;
private int currentPosition;//当前正在播放的歌曲的位置
ArrayList<Mp3Info> mp3Infos;

private MusicUpdatrListener musicUpdatrListener;

//创建一个单实力的线程,用于更新音乐信息
private ExecutorService es = Executors.newSingleThreadExecutor();

//播放模式
public static final int ORDER_PLAY = 1;//顺序播放
public static final int RANDOM_PLAY = 2;//随机播放
public static final int SINGLE_PLAY = 3;//单曲循环
private int play_mode = ORDER_PLAY;//播放模式,默认为顺序播放

/**
* @param play_mode
* ORDER_PLAY = 1;//顺序播放
* RANDOM_PLAY = 2;//随机播放
* SINGLE_PLAY = 3;//单曲循环
*/
//set方法
public void setPlay_mode(int play_mode) {
this.play_mode = play_mode;
}

//get方法
public int getPlay_mode() {
return play_mode;
}

private boolean isPause = false;//歌曲播放中的暂停状态

public boolean isPause(){
return isPause;
}

public PlayService() {
}

public int getCurrentPosition(){
return currentPosition;
}

private Random random = new Random();//创建随机对象
//MediaPlayer.Completion 播放完成 实现播放下一首功能
//播放完成以后,判断播放模式(曲目循环方式)
//为了实现循环后,可以显示音乐信息,需要在PlayAcivity的change里添加对应代码
@Override
public void onCompletion(MediaPlayer mp) {
switch (play_mode){
case ORDER_PLAY://顺序播放
next();//下一首
break;
case RANDOM_PLAY://随机播放
//currentPosition = random.nextInt(mp3Infos.size());//随机下标为mp3Infos.size()
//play(currentPosition);
play(random.nextInt(mp3Infos.size()));
break;
case SINGLE_PLAY://单曲循环
play(currentPosition);
break;
default:
break;
}
}
//MediaPlayer.Error 播放错误 处理实现播放下一首功能出现的错误
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();//重启
return false;
}

//内部类PlayBinder实现Binder,得到当前PlayService对象
class PlayBinder extends Binder{
public PlayService getPlayService(){
System.out.println("PlayService #1 " + PlayService.this);
return PlayService.this;
}
}

@Override
public IBinder onBind(Intent intent) {
return new PlayBinder();//通过PlayBinder拿到PlayService,给Activity调用
}

@Override
public void onCreate() {
super.onCreate();
mPlayer = new MediaPlayer();
mPlayer.setOnCompletionListener(this);//注册播放完成事件
mPlayer.setOnErrorListener(this);//注册播放错误事件
mp3Infos = MediaUtils.getMp3Infos(this);//获取Mp3列表
es.execute(updateSteatusRunnable);//更新进度值
}

@Override
public void onDestroy() {
super.onDestroy();
//回收线程
if (es!=null && !es.isShutdown()){//当进度值等于空,并且,进度值没有关闭
es.shutdown();
es = null;
}
}

//利用Runnable来实现多线程
/**
* Runnable
* Java中实现多线程有两种途径:继承Thread类或者实现Runnable接口.
* Runnable接口非常简单,就定义了一个方法run(),继承Runnable并实现这个
* 方法就可以实现多线程了,但是这个run()方法不能自己调用,必须由系统来调用,否则就和别的方法没有什么区别了.
* 好处:数据共享
*/
Runnable updateSteatusRunnable = new Runnable() {//更新状态
@Override
public void run() {
//不断更新进度值
while (true){
//音乐更新监听不为空,并且,媒体播放不为空,并且媒体播放为播放状态
if(musicUpdatrListener!=null && mPlayer!=null && mPlayer.isPlaying()){
musicUpdatrListener.onPublish(getCurrentProgress());//获取当前的进度值
}
try {
Thread.sleep(500);//500毫秒更新一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};

//播放
public void play(int position){
if (position>=0 && position<mp3Infos.size()){
Mp3Info mp3Info = mp3Infos.get(position);//获取mp3Info对象
//进行播放,播放前判断
try {
mPlayer.reset();//重启
mPlayer.setDataSource(this, Uri.parse(mp3Info.getUrl()));//资源解析,Mp3地址
mPlayer.prepare();//准备
mPlayer.start();//开始(播放)
currentPosition = position;//保存当前位置到currentPosition,比如第一首,currentPosition = 1
} catch (IOException e) {
e.printStackTrace();
}
if(musicUpdatrListener!=null){
musicUpdatrListener.onChange(currentPosition);//更新当前位置
}
}
}

//暂停
public void pause(){
if (mPlayer.isPlaying()){
mPlayer.pause();
isPause = true;
}
}

//下一首
public void next(){
if (currentPosition>=mp3Infos.size()-1){//如果超出最大值,(因为第一首是0),说明已经是最后一首
currentPosition = 0;//回到第一首
}else {
currentPosition++;//下一首
}
play(currentPosition);
}

//上一首 previous
public void prev(){
if (currentPosition-1<0){//如果上一首小于0,说明已经是第一首
currentPosition = mp3Infos.size()-1;//回到最后一首
}else {
currentPosition--;//上一首
}
play(currentPosition);
}

//默认开始播放的方法
public void start(){
if (mPlayer!=null && !mPlayer.isPlaying()){//判断当前歌曲不等于空,并且没有在播放的状态
mPlayer.start();

}
}

//获取当前是否为播放状态,提供给MyMusicListFragment的播放暂停按钮点击事件判断状态时调用
public boolean isPlaying(){
if (mPlayer!=null){
return mPlayer.isPlaying();
}
return false;
}

//获取当前的进度值
public int getCurrentProgress(){
if(mPlayer!=null && mPlayer.isPlaying()){//mPlayer不为空,并且,为播放状态
return mPlayer.getCurrentPosition();
}
return 0;
}
//getDuration 获取文件的持续时间
public int getDuration(){
return mPlayer.getDuration();
}
//seekTo 寻找指定的时间位置
public void seekTo(int msec){
mPlayer.seekTo(msec);
}

//更新状态的接口(PlayService的内部接口),并在BaseActivity中实现
public interface MusicUpdatrListener{//音乐更新监听器
public void onPublish(int progress);//发表进度事件(更新进度条)
public void onChange(int position); //更新歌曲位置.按钮的状态等信息
//声明MusicUpdatrListener后,添加set方法
}

//set方法
public void setMusicUpdatrListener(MusicUpdatrListener musicUpdatrListener) {
this.musicUpdatrListener = musicUpdatrListener;
}
}


PlayActivity如下:

package com.iwanghang.drmplayer;

import android.graphics.Bitmap;
import android.os.Bundle;

import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.iwanghang.drmplayer.utils.ImageUtils;
import com.iwanghang.drmplayer.utils.MediaUtils;
import com.iwanghang.drmplayer.vo.Mp3Info;

import java.util.ArrayList;

import static com.iwanghang.drmplayer.PlayService.ORDER_PLAY;
import static com.iwanghang.drmplayer.PlayService.RANDOM_PLAY;
import static com.iwanghang.drmplayer.PlayService.SINGLE_PLAY;

/**
*PlayActivity 点击MyMusicListFragment(本地音乐)底部UI中的专辑封面图片打开的Activity
*/
public class PlayActivity extends BaseActivity implements OnClickListener{
private TextView textView1_title;//歌名
private ImageView imageView1_ablum;//专辑封面图片
private SeekBar seekBar1;//进度条
private TextView textView1_start_time,textView1_end_time;//开始时间,结束时间
private ImageView imageView1_play_mode;//菜单
private ImageView imageView3_previous,imageView2_play_pause,imageView1_next;//上一首,播放暂停,下一首
private ImageView imageView1_ablum_reflection;//专辑封面图片倒影

private ArrayList<Mp3Info> mp3Infos;
//private int position;//当前播放的位置
private boolean isPause = false;//当前播放的是否为暂停状态
private static final int UPDATE_TIME = 0x1;//更新播放事件的标记

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_play);
//初始化界面信息
textView1_title = (TextView) findViewById(R.id.textView1_title);//歌名
imageView1_ablum = (ImageView) findViewById(R.id.imageView1_ablum);//专辑封面图片
seekBar1 = (SeekBar) findViewById(R.id.seekBar1);//进度条
textView1_start_time = (TextView) findViewById(R.id.textView1_start_time);//开始时间
textView1_end_time = (TextView) findViewById(R.id.textView1_end_time);//结束时间
imageView1_play_mode = (ImageView) findViewById(R.id.imageView1_play_mode);//菜单
imageView3_previous = (ImageView) findViewById(R.id.imageView3_previous);//上一首
imageView2_play_pause = (ImageView) findViewById(R.id.imageView2_play_pause);//播放暂停
imageView1_next = (ImageView) findViewById(R.id.imageView1_next);//下一首
imageView1_ablum_reflection = (ImageView) findViewById(R.id.imageView1_ablum_reflection);//专辑封面图片倒影
//注册按钮点击监听事件
imageView1_play_mode.setOnClickListener(this);
imageView2_play_pause.setOnClickListener(this);
imageView3_previous.setOnClickListener(this);
imageView1_next.setOnClickListener(this);

mp3Infos = MediaUtils.getMp3Infos(this);
//bindPlayService();//绑定服务,异步过程,绑定后需要取得相应的值,来更新界面
myHandler = new MyHandler(this);

//以下直接调用change()是不行的,因为异步问题,会发生NullPointerException空指针异常
//从MyMusicListFragment的专辑封面图片点击时间传过来的position(当前播放的位置)
//position = getIntent().getIntExtra("position",0);
//change(position);

//通过在BaseActivity中绑定Service,添加如下代码实现change()
//musicUpdatrListener.onChange(playService.getCurrentProgeress());

//从MyMusicListFragment的专辑封面图片点击时间传过来的isPause(当前播放的是否为暂停状态)
//isPause = getIntent().getBooleanExtra("isPause",false);
}

//把播放服务的绑定和解绑放在onResume,onPause里,好处是,每次回到当前Activity就获取一次播放状态
@Override
protected void onResume() {
super.onResume();
bindPlayService();
}

@Override
protected void onPause() {
super.onPause();
unbindPlayService();
}

@Override
protected void onDestroy() {
super.onDestroy();
unbindPlayService();//解绑服务
}

//Handler用于更新已经播放时间
private static MyHandler myHandler;
static class MyHandler extends Handler{
private PlayActivity playActivity;
public MyHandler(PlayActivity playActivity){
this.playActivity = playActivity;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (playActivity!=null){
switch (msg.what){
case UPDATE_TIME://更新时间(已经播放时间)
playActivity.textView1_start_time.setText(MediaUtils.formatTime(msg.arg1));
break;
}
}
}
}

@Override
public void publish(int progress) {
//以下是是直接调用线程,但是不能这样做,会报错,线程异常
//textView1_start_time.setText(MediaUtils.formatTime(progress));
//所以,我们需要使用Handler
Message msg = myHandler.obtainMessage(UPDATE_TIME);//用于更新已经播放时间
msg.arg1 = progress;//用于更新已经播放时间
myHandler.sendMessage(msg);//用于更新已经播放时间

seekBar1.setProgress(progress);
}

@Override
public void change(int position) {
//if (this.playService.isPlaying()) {//获取是否为播放状态
System.out.println("PlayActivity #100 position = " + position);
Mp3Info mp3Info = mp3Infos.get(position);
textView1_title.setText(mp3Info.getTitle());//设置歌名
//获取专辑封面图片
Bitmap albumBitmap = MediaUtils.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, false);
//改变播放界面专辑封面图片
imageView1_ablum.setImageBitmap(albumBitmap);
textView1_end_time.setText(MediaUtils.formatTime(mp3Info.getDuration()));//设置结束时间
imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//设置暂停图片
seekBar1.setProgress(0);//设置当前进度为0
seekBar1.setMax((int)mp3Info.getDuration());//设置进度条最大值为MP3总时间
if (playService.isPlaying()){
imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);
}else {
imageView2_play_pause.setImageResource(R.mipmap.app_music_play);
}

if(imageView1_ablum != null) {
imageView1_ablum_reflection.setImageBitmap(ImageUtils.createReflectionBitmapForSingle(albumBitmap));//显示倒影
}
switch (playService.getPlay_mode()){
case ORDER_PLAY://顺序播放
imageView1_play_mode.setImageResource(R.mipmap.app_mode_order);
//imageView2_play_pause.setTag(ORDER_PLAY);
break;
case PlayService.RANDOM_PLAY://随机播放
imageView1_play_mode.setImageResource(R.mipmap.app_mode_random);
//imageView2_play_pause.setTag(RANDOM_PLAY);
break;
case PlayService.SINGLE_PLAY://单曲循环
imageView1_play_mode.setImageResource(R.mipmap.app_mode_single);
//imageView2_play_pause.setTag(SINGLE_PLAY);
break;
default:
break;
}
}

//点击事件
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.imageView2_play_pause: {//播放暂停按钮
if (playService.isPlaying()) {//如果是播放状态
imageView2_play_pause.setImageResource(R.mipmap.app_music_play);//设置播放图片
playService.pause();
} else {
if (playService.isPause()) {
imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//设置暂停图片
playService.start();//播放事件
} else {
//只有打开APP没有点击任何歌曲,同时,直接点击暂停播放按钮时.才会调用
playService.play(0);
}
}
break;
}
case R.id.imageView1_next:{//下一首按钮
playService.next();//下一首
break;
}
case R.id.imageView3_previous:{//上一首按钮
playService.prev();//上一首
break;
}
case R.id.imageView1_play_mode:{//循环模式按钮
//int mode = (int) imageView1_play_mode.getTag();
switch (playService.getPlay_mode()){
case ORDER_PLAY:
imageView1_play_mode.setImageResource(R.mipmap.app_mode_random);
//imageView1_play_mode.setTag(RANDOM_PLAY);
playService.setPlay_mode(RANDOM_PLAY);
Toast.makeText(getApplicationContext(),"随机播放",Toast.LENGTH_SHORT).show();
break;
case RANDOM_PLAY:
imageView1_play_mode.setImageResource(R.mipmap.app_mode_single);
//imageView1_play_mode.setTag(SINGLE_PLAY);
playService.setPlay_mode(SINGLE_PLAY);
Toast.makeText(getApplicationContext(),"单曲循环",Toast.LENGTH_SHORT).show();
break;
case SINGLE_PLAY:
imageView1_play_mode.setImageResource(R.mipmap.app_mode_order);
//imageView1_play_mode.setTag(ORDER_PLAY);
playService.setPlay_mode(ORDER_PLAY);
Toast.makeText(getApplicationContext(),"顺序播放",Toast.LENGTH_SHORT).show();
break;
}
break;
}
default:
break;
}
}
}


ImageUtils如下:

package com.iwanghang.drmplayer.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

/**
* 图片工具类
* Created by iwanghang on 16/4/25.
*/
public class ImageUtils {
/**图片的八个位置**/
public static final int TOP = 0;			//上
public static final int BOTTOM = 1;			//下
public static final int LEFT = 2;			//左
public static final int RIGHT = 3;			//右
public static final int LEFT_TOP = 4;		//左上
public static final int LEFT_BOTTOM = 5;	//左下
public static final int RIGHT_TOP = 6;		//右上
public static final int RIGHT_BOTTOM = 7;	//右下

/**
* 图像的放大缩小方法
* @param src		源位图对象
* @param scaleX	宽度比例系数
* @param scaleY	高度比例系数
* @return 返回位图对象
*/
public static Bitmap zoomBitmap(Bitmap src, float scaleX, float scaleY) {
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
Bitmap t_bitmap = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
return t_bitmap;
}

/**
* 图像放大缩小--根据宽度和高度
* @param src
* @param width
* @param height
* @return
*/
public static Bitmap zoomBimtap(Bitmap src, int width, int height) {
return Bitmap.createScaledBitmap(src, width, height, true);
}

/**
* 将Drawable转为Bitmap对象
* @param drawable
* @return
*/
public static Bitmap drawableToBitmap(Drawable drawable) {
return ((BitmapDrawable)drawable).getBitmap();
}

/**
* 将Bitmap转换为Drawable对象
* @param bitmap
* @return
*/
public static Drawable bitmapToDrawable(Bitmap bitmap) {
Drawable drawable = new BitmapDrawable(bitmap);
return drawable;
}

/**
* Bitmap转byte[]
* @param bitmap
* @return
*/
public static byte[] bitmapToByte(Bitmap bitmap) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
return out.toByteArray();
}

/**
* byte[]转Bitmap
* @param data
* @return
*/
public static Bitmap byteToBitmap(byte[] data) {
if(data.length != 0) {
return BitmapFactory.decodeByteArray(data, 0, data.length);
}
return null;
}

/**
* 绘制带圆角的图像
* @param src
* @param radius
* @return
*/
public static Bitmap createRoundedCornerBitmap(Bitmap src, int radius) {
final int w = src.getWidth();
final int h = src.getHeight();
// 高清量32位图
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Paint paint = new Paint();
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(0xff424242);
// 防止边缘的锯齿
paint.setFilterBitmap(true);
Rect rect = new Rect(0, 0, w, h);
RectF rectf = new RectF(rect);
// 绘制带圆角的矩形
canvas.drawRoundRect(rectf, radius, radius, paint);

// 取两层绘制交集,显示上层
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// 绘制图像
canvas.drawBitmap(src, rect, rect, paint);
return bitmap;
}

/**
* 创建选中带提示图片
* @param context
* @param srcId
* @param tipId
* @return
*/
public static Drawable createSelectedTip(Context context, int srcId, int tipId) {
Bitmap src = BitmapFactory.decodeResource(context.getResources(), srcId);
Bitmap tip = BitmapFactory.decodeResource(context.getResources(), tipId);
final int w = src.getWidth();
final int h = src.getHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Paint paint = new Paint();
Canvas canvas = new Canvas(bitmap);
//绘制原图
canvas.drawBitmap(src, 0, 0, paint);
//绘制提示图片
canvas.drawBitmap(tip, (w - tip.getWidth()), 0, paint);
return bitmapToDrawable(bitmap);
}

/**
* 带倒影的图像
* @param src
* @return
*/
public static Bitmap createReflectionBitmap(Bitmap src) {
// 两个图像间的空隙
final int spacing = 4;
final int w = src.getWidth();
final int h = src.getHeight();
// 绘制高质量32位图
Bitmap bitmap = Bitmap.createBitmap(w, h + h / 2 + spacing, Config.ARGB_8888);
// 创建燕X轴的倒影图像
Matrix m = new Matrix();
m.setScale(1, -1);
Bitmap t_bitmap = Bitmap.createBitmap(src, 0, h / 2, w, h / 2, m, true);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
//	绘制原图像
canvas.drawBitmap(src, 0, 0, paint);
// 绘制倒影图像
canvas.drawBitmap(t_bitmap, 0, h + spacing, paint);
// 线性渲染-沿Y轴高到低渲染
Shader shader = new LinearGradient(0, h + spacing, 0, h + spacing + h / 2, 0x70ffffff, 0x00ffffff, Shader.TileMode.MIRROR);
paint.setShader(shader);
// 取两层绘制交集,显示下层。
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
// 绘制渲染倒影的矩形
canvas.drawRect(0, h + spacing, w, h + h / 2 + spacing, paint);
return bitmap;
}

/**
* 独立的倒影图像
* @param src
* @return
*/
public static Bitmap createReflectionBitmapForSingle(Bitmap src) {
final int w = src.getWidth();
final int h = src.getHeight();
// 绘制高质量32位图
Bitmap bitmap = Bitmap.createBitmap(w, h / 2, Config.ARGB_8888);
// 创建沿X轴的倒影图像
Matrix m = new Matrix();
m.setScale(1, -1);
Bitmap t_bitmap = Bitmap.createBitmap(src, 0, h / 2, w, h / 2, m, true);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
// 绘制倒影图像
canvas.drawBitmap(t_bitmap, 0, 0, paint);
// 线性渲染-沿Y轴高到低渲染
Shader shader = new LinearGradient(0, 0, 0, h / 2, 0x70ffffff,
0x00ffffff, Shader.TileMode.MIRROR);
paint.setShader(shader);
// 取两层绘制交集。显示下层。
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
// 绘制渲染倒影的矩形
canvas.drawRect(0, 0, w, h / 2, paint);
return bitmap;
}

public static Bitmap createGreyBitmap(Bitmap src) {
final int w = src.getWidth();
final int h = src.getHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
// 颜色变换的矩阵
ColorMatrix matrix = new ColorMatrix();
// saturation 饱和度值,最小可设为0,此时对应的是灰度图;为1表示饱和度不变,设置大于1,就显示过饱和
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
paint.setColorFilter(filter);
canvas.drawBitmap(src, 0, 0, paint);
return bitmap;
}

/**
* 保存图片
* @param src
* @param filepath
* @param format:[Bitmap.CompressFormat.PNG,Bitmap.CompressFormat.JPEG]
* @return
*/
public static boolean saveImage(Bitmap src, String filepath, CompressFormat format) {
boolean rs = false;
File file = new File(filepath);
try {
FileOutputStream out = new FileOutputStream(file);
if(src.compress(format, 100, out)) {
out.flush();	//写入流
}
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return rs;
}

/**
* 添加水印效果
* @param src		源位图
* @param watermark	水印
* @param direction	方向
* @param spacing 间距
* @return
*/
public static Bitmap createWatermark(Bitmap src, Bitmap watermark, int direction, int spacing) {
final int w = src.getWidth();
final int h = src.getHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(src, 0, 0, null);
if(direction == LEFT_TOP) {
canvas.drawBitmap(watermark, spacing, spacing, null);
} else if(direction == LEFT_BOTTOM){
canvas.drawBitmap(watermark, spacing, h - watermark.getHeight() - spacing, null);
} else if(direction == RIGHT_TOP) {
canvas.drawBitmap(watermark, w - watermark.getWidth() - spacing, spacing, null);
} else if(direction == RIGHT_BOTTOM) {
canvas.drawBitmap(watermark, w - watermark.getWidth() - spacing, h - watermark.getHeight() - spacing, null);
}
return bitmap;
}

/**
* 合成图像
* @param direction
* @param bitmaps
* @return
*/
public static Bitmap composeBitmap(int direction, Bitmap... bitmaps) {
if(bitmaps.length < 2) {
return null;
}
Bitmap firstBitmap = bitmaps[0];
for (int i = 0; i < bitmaps.length; i++) {
firstBitmap = composeBitmap(firstBitmap, bitmaps[i], direction);
}
return firstBitmap;
}

/**
* 合成两张图像
* @param firstBitmap
* @param secondBitmap
* @param direction
* @return
*/
private static Bitmap composeBitmap(Bitmap firstBitmap, Bitmap secondBitmap,
int direction) {
if(firstBitmap == null) {
return null;
}
if(secondBitmap == null) {
return firstBitmap;
}
final int fw = firstBitmap.getWidth();
final int fh = firstBitmap.getHeight();
final int sw = secondBitmap.getWidth();
final int sh = secondBitmap.getHeight();
Bitmap bitmap = null;
Canvas canvas = null;
if(direction == TOP) {
bitmap = Bitmap.createBitmap(sw > fw ? sw : fw, fh + sh, Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawBitmap(secondBitmap, 0, 0, null);
canvas.drawBitmap(firstBitmap, 0, sh, null);
} else if(direction == BOTTOM) {
bitmap = Bitmap.createBitmap(fw > sw ? fw : sw, fh + sh, Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawBitmap(firstBitmap, 0, 0, null);
canvas.drawBitmap(secondBitmap, 0, fh, null);
} else if(direction == LEFT) {
bitmap = Bitmap.createBitmap(fw + sw, sh > fh ? sh : fh, Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawBitmap(secondBitmap, 0, 0, null);
canvas.drawBitmap(firstBitmap, sw, 0, null);
} else if(direction == RIGHT) {
bitmap = Bitmap.createBitmap(fw + sw, fh > sh ? fh : sh,
Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawBitmap(firstBitmap, 0, 0, null);
canvas.drawBitmap(secondBitmap, fw, 0, null);
}
return bitmap;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: