实现功能:
顺序播放
随机播放
单曲循环
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; } }
时间: 2024-11-02 22:57:31