博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android多媒体学习
阅读量:7032 次
发布时间:2019-06-28

本文共 39181 字,大约阅读时间需要 130 分钟。

hot3.png

一、Image的获取可以通过调Android自带的Camera应用来完成。该应用含有一个Intent-Filter。通过使用

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);startActivityForResult(intent)就可以启动Camera应用了。
二、Image存储,Android系统中含有一个多媒体库,其中包括所有Image、Video、Audio的数据。通过MediaStore对象可以访问相关数据。
闲话少说,直接看例子,这是一本英文书上的,觉得写的很好,自己翻译了一下,并加入了很多注释。以备查询。

 package demo.camera;  import java.io.File;  import android.app.Activity;  import android.content.ContentValues;  import android.content.Intent;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.net.Uri;  import android.os.Bundle;  import android.os.Environment;  import android.provider.MediaStore;  import android.util.Log;  import android.view.Display;  import android.view.View;  import android.widget.Button;  import android.widget.ImageView;  /**  * 这里多媒体第一个示例,主要介绍Image的获取和存储  * Image的获取可以通过Android自带的Camera应用来获得,  * 图片的存储需要用到MediaStore对象。Android中的多媒体库。  *   * @author Administrator  *  */  public class MainActivity extends Activity {            private static final int RESULT_CODE = 1;      private Button btnCamera;      private ImageView imageView;            private Uri imageFilePath;            @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);                              imageView = (ImageView)this.findViewById(R.id.imageView);          btnCamera = (Button)this.findViewById(R.id.camera);          btnCamera.setOnClickListener(new View.OnClickListener() {                            @Override              public void onClick(View v) {                                                      /**                  * 由于Camara返回的是缩略图,我们可以传递给他一个参数EXTRA_OUTPUT,                  * 来将用Camera获取到的图片存储在一个指定的URI位置处。                  * 下面就指定image存储在SDCard上,并且文件名为123.jpg                  * imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"123.jpg";                  * File file = new File(imageFilePath); //创建一个文件                  * Uri imageUri = Uri.fromFile(file);                  * 然而Android已经提供了一个多媒体库,那里统一存放了设备上所有的多媒体数据。所以,                  * 我们可以将获取到的图片存放在那个多媒体库中。                  * Android提供了MediaStore类,该类是一个ContentProvider,管理着设备上自带的和外部的多媒体文件,                  * 同时包含着每一个多媒体文件的数据信息。                  * 为了将数据存储在多媒体库,使用ContentResolver对象来操纵MediaStore对象                  * 在MediaStore.Images.Media中有两个URI常量,一个是    EXTERNAL_CONTENT_URI,另一个是INTERNAL_CONTENT_URI                  * 第一个URI对应着外部设备(SDCard),第二个URI对应着系统设备内部存储位置。                  * 对于多媒体文件,一般比较大,我们选择外部存储方式                  * 通过使用ContentResolver对象的insert方法我们可以向MediaStore中插入一条数据                  * 这样在检索那张图片的时候,不再使用文件的路径,而是根据insert数据时返回的URI,获取一个InputStream                  * 并传给BitmapFactory                  */                  //在这里启动Camera。                   //Camera中定义了一个Intent-Filter,其中Action是android.media.action.IMAGE_CAPTURE                   //我们使用的时候,最好不要直接使用这个,而是用MediaStore中的常量ACTION_IMAGE_CAPTURE.                   //这个常量就是对应的上面的action                   Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                                //这里我们插入一条数据,ContentValues是我们希望这条记录被创建时包含的数据信息                   //这些数据的名称已经作为常量在MediaStore.Images.Media中,有的存储在MediaStore.MediaColumn中了                   //ContentValues values = new ContentValues();                   ContentValues values = new ContentValues(3);                  values.put(MediaStore.Images.Media.DISPLAY_NAME, "testing");                  values.put(MediaStore.Images.Media.DESCRIPTION, "this is description");                  values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");                  imageFilePath = MainActivity.this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);                  intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFilePath); //这样就将文件的存储方式和uri指定到了Camera应用中                                     //由于我们需要调用完Camera后,可以返回Camera获取到的图片,                   //所以,我们使用startActivityForResult来启动Camera                                       startActivityForResult(intent, RESULT_CODE);                                }          });      }      /**      * 为了获取Camera返回的图片信息,重写该方法。      */      @Override      public void onActivityResult(int requestCode, int resultCode, Intent data){          super.onActivityResult(requestCode, resultCode, data);          if(resultCode == RESULT_CODE){              //说明是由Camera返回的数据               //由Camera应用返回的图片数据是一个Camera对象,存储在一个名为data的extra域               //然后将获取到的图片存储显示在ImageView中                             try {                  Bundle extra = data.getExtras();                  /**                  * 然而为了节约内存的消耗,这里返回的图片是一个121*162的缩略图。                  * 那么如何返回我们需要的大图呢?看上面                  * 然而存储了图片。有了图片的存储位置,能不能直接将图片显示出来呢》                  * 这个问题就设计到对于图片的处理和显示,是非常消耗内存的,对于PC来说可能不算什么,但是对于手机来说                  * 很可能使你的应用因为内存耗尽而死亡。不过还好,Android为我们考虑到了这一点                  * Android中可以使用BitmapFactory类和他的一个内部类BitmapFactory.Options来实现图片的处理和显示                  * BitmapFactory是一个工具类,里面包含了很多种获取Bitmap的方法。BitmapFactory.Options类中有一个inSampleSize,比如设定他的值为8,则加载到内存中的图片的大小将                  * 是原图片的1/8大小。这样就远远降低了内存的消耗。                  * BitmapFactory.Options op = new BitmapFactory.Options();                  * op.inSampleSize = 8;                  * Bitmap pic = BitmapFactory.decodeFile(imageFilePath, op);                  * 这是一种快捷的方式来加载一张大图,因为他不用考虑整个显示屏幕的大小和图片的原始大小                  * 然而有时候,我需要根据我们的屏幕来做相应的缩放,如何操作呢?                  *                   */                  //首先取得屏幕对象                   Display display = this.getWindowManager().getDefaultDisplay();                  //获取屏幕的宽和高                   int dw = display.getWidth();                  int dh = display.getHeight();                  /**                  * 为了计算缩放的比例,我们需要获取整个图片的尺寸,而不是图片                  * BitmapFactory.Options类中有一个布尔型变量inJustDecodeBounds,将其设置为true                  * 这样,我们获取到的就是图片的尺寸,而不用加载图片了。                  * 当我们设置这个值的时候,我们接着就可以从BitmapFactory.Options的outWidth和outHeight中获取到值                  */                  BitmapFactory.Options op = new BitmapFactory.Options();                  //op.inSampleSize = 8;                   op.inJustDecodeBounds = true;                  //Bitmap pic = BitmapFactory.decodeFile(imageFilePath, op);//调用这个方法以后,op中的outWidth和outHeight就有值了                   //由于使用了MediaStore存储,这里根据URI获取输入流的形式                   Bitmap pic = BitmapFactory.decodeStream(this                          .getContentResolver().openInputStream(imageFilePath),                          null, op);                  int wRatio = (int) Math.ceil(op.outWidth / (float) dw); //计算宽度比例                   int hRatio = (int) Math.ceil(op.outHeight / (float) dh); //计算高度比例                   Log.v("Width Ratio:", wRatio + "");                  Log.v("Height Ratio:", hRatio + "");                  /**                  * 接下来,我们就需要判断是否需要缩放以及到底对宽还是高进行缩放。                  * 如果高和宽不是全都超出了屏幕,那么无需缩放。                  * 如果高和宽都超出了屏幕大小,则如何选择缩放呢》                  * 这需要判断wRatio和hRatio的大小                  * 大的一个将被缩放,因为缩放大的时,小的应该自动进行同比率缩放。                  * 缩放使用的还是inSampleSize变量                  */                  if (wRatio > 1 && hRatio > 1) {                      if (wRatio > hRatio) {                          op.inSampleSize = wRatio;                      } else {                          op.inSampleSize = hRatio;                      }                  }                  op.inJustDecodeBounds = false; //注意这里,一定要设置为false,因为上面我们将其设置为true来获取图片尺寸了                   pic = BitmapFactory.decodeStream(this.getContentResolver()                          .openInputStream(imageFilePath), null, op);                  imageView.setImageBitmap(pic);              } catch (Exception e) {                  e.printStackTrace();              }           }      }  }

检索并显示媒体库中的图片

如果你在模拟器已经启动的情况下,push了几张图片到SDCard中,建议将模拟器关了,再重新启动一下,否则,刚刚添加的图片,是没有办法获取到的。这是因为Android是在系统启动的时候来扫描模拟器上SDCard中多媒体文件的。

 package demo.camera;  import android.app.Activity;  import android.database.Cursor;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.os.Bundle;  import android.provider.MediaStore.Images.Media;  import android.util.Log;  import android.view.View;  import android.widget.ImageButton;  import android.widget.TextView;  /**  * 该类完成图片的检索,显示功能  * @author Administrator  *  */  public class PhotoManager extends Activity {            public static final float DISPLAY_WIDTH = 200;      public static final float DISPLAY_HEIGHT = 200;            //这里采用ImageButton的原因是有Button的作用       private ImageButton photoView;      private TextView nameView;            private Cursor cursor;            private String photoPath; //存放某张图片对应的位置信息       private Bitmap currPhoto;            //这三个变量主要用来保存Media.DATA,Media.TITLE,Media.DISPLAY_NAME的索引号,来获取每列的数据       private int photoIndex;      //private int titleIndex;       private int nameIndex;            public void onCreate(Bundle savedInstanceState){          super.onCreate(savedInstanceState);          setContentView(R.layout.photo_view);                    photoView = (ImageButton)this.findViewById(R.id.image_view);          photoView.setOnClickListener(clickListener);          nameView = (TextView)this.findViewById(R.id.view_name);                    //指定获取的列           String columns[] = new String[]{                  Media.DATA,Media._ID,Media.TITLE,Media.DISPLAY_NAME          };          //cursor = this.managedQuery(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);           cursor = this.getContentResolver().query(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);          photoIndex = cursor.getColumnIndexOrThrow(Media.DATA);          //titleIndex = cursor.getColumnIndexOrThrow(Media.TITLE);           nameIndex = cursor.getColumnIndexOrThrow(Media.DISPLAY_NAME);                    Log.v("HERE First:", "First Debug");          //显示第一张图片,但是首先要判断一下,Cursor是否有值           if(cursor.moveToFirst()){              showImage();          }      }            private View.OnClickListener clickListener = new View.OnClickListener() {                    @Override          public void onClick(View v) {                            if(cursor.moveToNext()){                  showImage();              }          }      };            /**      * 显示图像信息      */      private void showImage(){          photoPath = cursor.getString(photoIndex); //这里获取到的就是图片存储的位置信息           //这里怎样获取图片呢?看decodeBitmap           Log.v("Photo Path:", photoPath);          currPhoto = decodeBitmap(photoPath);          photoView.setImageBitmap(currPhoto);          nameView.setText(cursor.getString(nameIndex));            }            /**      * 从path中获取图片信息      * @param path      * @return      */      private Bitmap decodeBitmap(String path){          BitmapFactory.Options op = new BitmapFactory.Options();          op.inJustDecodeBounds = true;          Bitmap bmp = BitmapFactory.decodeFile(path, op); //获取尺寸信息           //获取比例大小           int wRatio = (int)Math.ceil(op.outWidth/DISPLAY_WIDTH);          int hRatio = (int)Math.ceil(op.outHeight/DISPLAY_HEIGHT);          //如果超出指定大小,则缩小相应的比例           if(wRatio > 1 && hRatio > 1){              if(wRatio > hRatio){                  op.inSampleSize = wRatio;              }else{                  op.inSampleSize = hRatio;              }          }          op.inJustDecodeBounds = false;          bmp = BitmapFactory.decodeFile(path, op);          return bmp;      }        }

Android自带的Camera应用虽然可以满足大多数情景,但是其灵活性上还有不足。但是Android允许我们定制自己的Camera。

在Android的hardware包中有一个Camera类。这个类就是获取Camera服务的,可以定制Camera等。

可以通过open()方法获取其实例。在使用这个类是需要在AndroidManifest.xml文件中加入相应的权限和特性 

如:  <uses-permission android:name = "android.permission.CAMERA" />

  <uses-feature android:name = "android.hardware.camera" />
  <uses-feature android:name = "android.hardware.camera.autofocus" /> 等。

package demo.camera;  import java.io.OutputStream;  import java.util.Iterator;  import java.util.List;  import android.app.Activity;  import android.content.ContentValues;  import android.content.res.Configuration;  import android.hardware.Camera;  import android.net.Uri;  import android.os.Bundle;  import android.provider.MediaStore;  import android.view.SurfaceHolder;  import android.view.SurfaceView;  import android.view.View;  import android.widget.LinearLayout;  /**  * Android自带的Camera应用程序可以完成很多功能。但是当其不能满足我们需要的时候  * 我们可以定制自己的Camera。Android提供了Camera类来辅助我们实现自己的Camera。  * 这个例子就来定义一个自己的Camera  * 首先,在Manifest中需要引入权限
  * 我们需要用来存放取景器的容器,这个容器就是SurfaceView。  * 使用SurfaceView的同时,我们还需要使用到SurfaceHolder,SurfaceHolder相当于一个监听器,可以监听  * Surface上的变化,通过其内部类CallBack来实现。  * 为了可以获取图片,我们需要使用Camera的takePicture方法同时我们需要实现Camera.PictureCallBack类,实现onPictureTaken方法  * @author Administrator  *  */  public class MyCamera extends Activity implements SurfaceHolder.Callback,Camera.PictureCallback{            public static final int MAX_WIDTH = 200;      public static final int MAX_HEIGHT = 200;            private SurfaceView surfaceView;            private Camera camera; //这个是hardare的Camera对象             public void onCreate(Bundle savedInstanceState){          super.onCreate(savedInstanceState);          this.setContentView(R.layout.camera);          surfaceView = (SurfaceView)this.findViewById(R.id.myCameraView);          surfaceView.setFocusable(true);           surfaceView.setFocusableInTouchMode(true);          surfaceView.setClickable(true);          surfaceView.setOnClickListener(new View.OnClickListener() {                            @Override              public void onClick(View v) {                                    camera.takePicture(null, null, null, MyCamera.this);                                }          });          //SurfaceView中的getHolder方法可以获取到一个SurfaceHolder实例           SurfaceHolder holder = surfaceView.getHolder();          //为了实现照片预览功能,需要将SurfaceHolder的类型设置为PUSH           //这样,画图缓存就由Camera类来管理,画图缓存是独立于Surface的           holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);          holder.addCallback(this);      }      @Override      public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {      }      @Override      public void surfaceCreated(SurfaceHolder holder) {          // 当Surface被创建的时候,该方法被调用,可以在这里实例化Camera对象           //同时可以对Camera进行定制           camera = Camera.open(); //获取Camera实例                           /**          * Camera对象中含有一个内部类Camera.Parameters.该类可以对Camera的特性进行定制          * 在Parameters中设置完成后,需要调用Camera.setParameters()方法,相应的设置才会生效          * 由于不同的设备,Camera的特性是不同的,所以在设置时,需要首先判断设备对应的特性,再加以设置          * 比如在调用setEffects之前最好先调用getSupportedColorEffects。如果设备不支持颜色特性,那么该方法将          * 返回一个null          */          try {                            Camera.Parameters param = camera.getParameters();              if(this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){                  //如果是竖屏                   param.set("orientation", "portrait");                  //在2.2以上可以使用                   //camera.setDisplayOrientation(90);               }else{                  param.set("orientation", "landscape");                  //在2.2以上可以使用                   //camera.setDisplayOrientation(0);                             }              //首先获取系统设备支持的所有颜色特效,有复合我们的,则设置;否则不设置               List
 colorEffects = param.getSupportedColorEffects();              Iterator
 colorItor = colorEffects.iterator();              while(colorItor.hasNext()){                  String currColor = colorItor.next();                  if(currColor.equals(Camera.Parameters.EFFECT_SOLARIZE)){                      param.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);                      break;                  }              }              //设置完成需要再次调用setParameter方法才能生效               camera.setParameters(param);                            camera.setPreviewDisplay(holder);                            /**              * 在显示了预览后,我们有时候希望限制预览的Size              * 我们并不是自己指定一个SIze而是指定一个Size,然后              * 获取系统支持的SIZE,然后选择一个比指定SIZE小且最接近所指定SIZE的一个              * Camera.Size对象就是该SIZE。              *               */              int bestWidth = 0;              int bestHeight = 0;                            List
 sizeList = param.getSupportedPreviewSizes();              //如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择               if(sizeList.size() > 1){                  Iterator
 itor = sizeList.iterator();                  while(itor.hasNext()){                      Camera.Size cur = itor.next();                      if(cur.width > bestWidth && cur.height>bestHeight && cur.width 
< MAX_HEIGHT){                          bestWidth = cur.width;                          bestHeight = cur.height;                      }                  }                  if(bestWidth != 0 && bestHeight != 0){                      param.setPreviewSize(bestWidth, bestHeight);                      //这里改变了SIze后,我们还要告诉SurfaceView,否则,Surface将不会改变大小,进入Camera的图像将质量很差                       surfaceView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth, bestHeight));                  }              }              camera.setParameters(param);          } catch (Exception e) {              // 如果出现异常,则释放Camera对象               camera.release();          }                    //启动预览功能           camera.startPreview();                }      @Override      public void surfaceDestroyed(SurfaceHolder holder) {          // 当Surface被销毁的时候,该方法被调用           //在这里需要释放Camera资源           camera.stopPreview();          camera.release();                }      @Override      public void onPictureTaken(byte[] data, Camera camera) {          // data是一个原始的JPEG图像数据,           //在这里我们可以存储图片,很显然可以采用MediaStore           //注意保存图片后,再次调用startPreview()回到预览           Uri imageUri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());          try {              OutputStream os = this.getContentResolver().openOutputStream(imageUri);              os.write(data);              os.flush();              os.close();          } catch (Exception e) {              // TODO: handle exception               e.printStackTrace();          }                    camera.startPreview();      }                    }

图像的编辑和合成

package demo.camera;  import java.io.FileNotFoundException;  import android.app.Activity;  import android.content.Intent;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.graphics.Canvas;  import android.graphics.ColorMatrix;  import android.graphics.ColorMatrixColorFilter;  import android.graphics.Matrix;  import android.graphics.Paint;  import android.graphics.PorterDuff;  import android.graphics.PorterDuffXfermode;  import android.net.Uri;  import android.os.Bundle;  import android.provider.MediaStore;  import android.util.Log;  import android.view.Menu;  import android.view.MenuItem;  import android.view.View;  import android.widget.Button;  import android.widget.ImageView;  /**  * 在Android中我们可以对图像进行编辑处理等操作  * 包括放大缩小,旋转,偏移,裁剪,以及更改亮度,饱和度等  *   * 1、首先,从SDCard中选择图片,采用Android自带的Callery应用获得  * Gallery是Android自带的图片和视频管理应用  * 使用Intent来启动Gallery应用,需要指定两个参数,一个是Action,另一个是多媒体存放的URI  * Action是一个通用的Action叫ACTION_PICK,来告诉Gallery,我们想检索数据。  * 第二个是Data,是一个URI,这里当然是MediaStore.Images.Media.EXTERNAL_CONTENT_URI  * 当在Gallery中选择了一个图片的时候,返回的Intent中的Data域就是所选图片对应的URI  *   * @author Administrator  *  */  public class PhotoProcess extends Activity{      public static final int FIRST_PIC = 0;      public static final int SECOND_PIC = 1;      public static final int MAX_WIDTH = 240;      public static final int MAX_HEIGHT = 180;      private Button btnSelect,btnSelect2;      private ImageView srcImageView, dstImageView;            private Bitmap srcBitmap, dstBitmap;      private Uri imageUri;                  public void onCreate(Bundle savedInstanceState){          super.onCreate(savedInstanceState);          this.setContentView(R.layout.process);                    this.btnSelect = (Button)this.findViewById(R.id.btn_select);          btnSelect.setOnClickListener(clickListener);          this.btnSelect2 = (Button)this.findViewById(R.id.btn_select2);          btnSelect2.setOnClickListener(clickListener2);          srcImageView = (ImageView)this.findViewById(R.id.img_src);          dstImageView = (ImageView)this.findViewById(R.id.img_dst);      }            private View.OnClickListener clickListener = new View.OnClickListener() {                    @Override          public void onClick(View arg0) {              // 启动Gallery应用               Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);              startActivityForResult(intent, FIRST_PIC);          }      };      private View.OnClickListener clickListener2 = new View.OnClickListener() {                    @Override          public void onClick(View arg0) {              // 启动Gallery应用               Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);              startActivityForResult(intent, SECOND_PIC);                        }      };              public boolean onCreateOptionsMenu(Menu menu){          //super.onCreateOptionsMenu(menu);           //MenuInflater menuInflater = new MenuInflater(this);           //menuInflater.inflate(R.layout.image, menu)           menu.add(Menu.NONE,1,Menu.NONE,"复制");          menu.add(Menu.NONE,2,Menu.NONE,"变换");          menu.add(Menu.NONE,3,Menu.NONE,"亮度");          menu.add(Menu.NONE,4,Menu.NONE,"合成");          return super.onCreateOptionsMenu(menu);      }            public boolean onOptionsItemSelected(MenuItem item){          int id = item.getItemId();          switch(id){          case 1:              //复制一个图像               if(srcBitmap != null){                  dstBitmap = getDstImage(null);//这里没有变换                   dstImageView.setImageBitmap(dstBitmap);              }              break;          case 2:              //对复制后的图像进行变换               if(srcBitmap != null){                  dstBitmap = transferImage();                  dstImageView.setImageBitmap(dstBitmap);              }              break;          case 3:              //改变图像的色彩               if(srcBitmap != null){                  dstBitmap = ajustImage();                  dstImageView.setImageBitmap(dstBitmap);              }              break;          case 4:              if(srcBitmap != null && dstBitmap != null){                  dstBitmap = compositeImages();                  dstImageView.setImageBitmap(dstBitmap);              }              break;          }          return true;      }            /**      * 为了创建一个图像的副本,我们可以在创建一个新的空的Bitmap,然后在这个Bitmap上绘制一个Bitmap      * 这个空的Bitmap应该和已存在的Bitmap具有相同的尺寸和颜色深度      *       * 然后我们需要一个Canvas对象,一个Canvas简单说,就是一个画布,存放Bitmap,在构造时,就可以传入Bitmap对象      * 同时,Canvas中定义了很多便捷的画图方法,方便我们绘制各种图形      * 接下来,如果我们需要处理颜色和对比度,我们需要一个Paint对象,通过Paint我们可以设置画笔的各种特性。      *       * 最后,我们调用Canvas的drawBitmap就可以将原Bitmap绘制在dstBitmap上了      *       */      private Bitmap getDstImage(Matrix matrix){                    Bitmap bmp = null;          //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap           //返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了           bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());          //创建Canvas对象,           Canvas canvas = new Canvas(bmp);           //创建Paint对象,这里先不用           Paint paint = new Paint();          //在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了                     if(matrix != null){              //如果matrix存在,则采用变换               canvas.drawBitmap(dstBitmap, matrix, paint);          }else{              canvas.drawBitmap(srcBitmap, 0, 0, paint);          }                              return bmp;        }                  /**      * 重载getDstImage函数,传入定制的Paint对象      * @param matrix      * @param paint      * @return      */      private Bitmap getDstImage(Matrix matrix, Paint paint){                    Bitmap bmp = null;          //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap           //返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了           bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());          //创建Canvas对象,           Canvas canvas = new Canvas(bmp);                     //在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了                     if(matrix != null){              //如果matrix存在,则采用变换               canvas.drawBitmap(dstBitmap, matrix, paint);          }else{              canvas.drawBitmap(srcBitmap, 0, 0, paint);          }                              return bmp;        }               /**      * 为了放大缩小、旋转图像,我们要使用Matrix类。Matrix类是一个三维矩阵。      * 在Android屏幕中,图像的每个像素对应都是一个坐标,一个坐标由x/y/z组成      * ------------------------      * cosX -sinX translateX      * sinX cosX  translateY      * 0    0     scale      * ------------------------      * 第一行的值,影响着x坐标。比如 1 0 0 =>x = 1*x + 0*y + 0*z      * 第二行的值,影响着y坐标。比如0 1 0 => y = 0*x + 1*y + 0*z      * 第三行的值,影响着z坐标。比如 0 0 1 => z = 0*x + 0*y + 1*z      *       * 我们自己计算一个矩阵然后通过Matrax.setValues设置。      * 这样,在调用canvas的drawBitmap方法时,传入matrix      *       * Matrix类并不提倡我们使用这种方式来操作变换,Matrix针对不同的变换都相应的有pre,set,post三种方法      * 可以使用。      * pre是矩阵前乘      * set是直接设置      * post是矩阵后乘      */      private Bitmap transferImage(){          Matrix matrix = new Matrix();          matrix.setValues(new float[]{              .5f,0,0,//这里只会影响到x轴,所以,图片的长度将是原来的一半               0,1,0,              0,0,1          });          return this.getDstImage(matrix);      }            /**      * 该方法中我们将对图像的颜色,亮度,对比度等进行设置      * 需要用到ColorMatrix类。ColorMatrix类是一个四行五列的矩阵      * 每一行影响着[R,G,B,A]中的一个      * -------------------------      * a1 b1 c1 d1 e1      * a2 b2 c2 d2 e2      * a3 b3 c3 d3 e3      * a4 b4 c4 d4 e4      * -------------------------      * Rnew => a1*R+b1*G+c1*B+d1*A+e1      * Gnew => a2*R+b2*G+c2*B+d2*A+e2      * Bnew => a3*R+b3*G+c3*B+d3*A+e3      * Gnew => a4*R+b4*G+c4*B+d4*A+e4      * 其中R,G,B的值是128,A的值是0      *       * 最后将颜色的修改,通过Paint.setColorFilter应用到Paint对象中。      * 主要对于ColorMatrix,需要将其包装成ColorMatrixColorFilter对象,再传给Paint对象      *       * 同样的,ColorMatrix提供给我们相应的方法,setSaturation()就可以设置一个饱和度      */      private Bitmap ajustImage(){          ColorMatrix cMatrix = new ColorMatrix();  //      int brightIndex = -25;   //      int doubleColor = 2;   //      cMatrix.set(new float[]{   //              doubleColor,0,0,0,brightIndex, //这里将1改为2则我们让Red的值为原来的两倍   //              0,doubleColor,0,0,brightIndex,//改变最后一列的值,我们可以不改变RGB同道颜色的基础上,改变亮度   //              0,0,doubleColor,0,brightIndex,   //              0,0,0,doubleColor,0   //      });           //cMatrix.setSaturation(2.0f);//设置饱和度           cMatrix.setScale(2.0f, 2.0f, 2.0f, 2.0f);//设置颜色同道色彩缩放           Paint paint = new Paint();          paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));          return this.getDstImage(null, paint);      }            /**      * 图像的合成,可以通过在同一个Canvas中绘制两张图片。      * 只是在绘制第二章图片的时候,需要给Paint指定一个变幻模式TransferMode。      * 在Android中有一个XFermode所有的变幻模式都是这个类的子类      * 我们需要用到它的一个子类PorterDuffXfermode,关于这个类,其中用到PorterDuff类      * 这个类很简单,就包含一个Enum是Mode,其中定义了一组规则,这组规则就是如何将      * 一张图像和另一种图像进行合成      * 关于图像合成有四种模式,LIGHTEN,DRAKEN,MULTIPLY,SCREEN      */      private Bitmap compositeImages(){                    Bitmap bmp = null;          //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap           bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());          Paint paint = new Paint();          Canvas canvas = new Canvas(bmp);          //首先绘制第一张图片,很简单,就是和方法中getDstImage一样           canvas.drawBitmap(srcBitmap, 0, 0, paint);                          //在绘制第二张图片的时候,我们需要指定一个Xfermode           //这里采用Multiply模式,这个模式是将两张图片的对应的点的像素相乘           //,再除以255,然后以新的像素来重新绘制显示合成后的图像           paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));          canvas.drawBitmap(dstBitmap, 0, 0, paint);                    return bmp;      }      public void onActivityResult(int requestCode, int resultCode, Intent data){          super.onActivityResult(requestCode, resultCode, data);                    Log.v("Result OK Value:", resultCode+"");          Log.v("RequestCode Value", requestCode+"");                    if(resultCode == RESULT_OK){              imageUri = data.getData();                if(requestCode == FIRST_PIC){                  //在Gallery中选中一个图片时,返回来的Intent中的Data就是选择图片的Uri                   srcBitmap = getSrcImage(imageUri);                  srcImageView.setImageBitmap(srcBitmap);                           }else if(requestCode == SECOND_PIC){                  //这里处理用户选择的第二张图片                                     dstBitmap = getSrcImage(imageUri);                  dstImageView.setImageBitmap(dstBitmap);              }          }      }            /**      * 需要加载的图片可能是大图,我们需要对其进行合适的缩小处理      * @param imageUri      */      private Bitmap getSrcImage(Uri imageUri){          //Display display = this.getWindowManager().getDefaultDisplay();           try {              BitmapFactory.Options ops = new BitmapFactory.Options();              ops.inJustDecodeBounds = true;              Bitmap bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);              int wRatio = (int)Math.ceil(ops.outWidth/(float)MAX_WIDTH);              int hRatio = (int)Math.ceil(ops.outHeight/(float)MAX_HEIGHT);                            if(wRatio > 1 && hRatio > 1){                  if(wRatio > hRatio){                      ops.inSampleSize = wRatio;                  }else{                      ops.inSampleSize = hRatio;                  }              }                            ops.inJustDecodeBounds = false;              bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);                            return bmp;                        } catch (FileNotFoundException e) {              // TODO Auto-generated catch block               e.printStackTrace();              Log.e(this.getClass().getName(), e.getMessage());          }                    return null;      }  }

调用Android自带的播放器播放audio

Android有其自带的播放器,我们可以使用隐式Intent来调用它:通过传入一个Action为ACTION_VIEW同时,指定Data为所要播放的Audio的Uri对象,并指定格式信息,则我们就可以调用播放器来播放该Audio了。

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setDataAndType(Uri, MimeType);

startActivity(intent);

本文我们需要访问MediaStore,来获取所有Audio信息,我们首先将获取所有的Album,然后当用户点击某个Album时,显示该Album下所有的Audio,然后当用户点击某个Audio时,调用系统自带的播放器播放该Audio。

package demo.camera;  import java.io.File;  import org.apache.http.client.utils.URIUtils;  import android.app.Activity;  import android.app.ListActivity;  import android.content.Intent;  import android.database.Cursor;  import android.net.Uri;  import android.os.Bundle;  import android.os.Environment;  import android.provider.MediaStore;  import android.provider.MediaStore.Audio;  import android.provider.MediaStore.Audio.Albums;  import android.view.View;  import android.widget.Button;  import android.widget.CursorAdapter;  import android.widget.ListView;  import android.widget.SimpleCursorAdapter;  /**  * 本示例演示如何利用Android自带的Music来播放程序  * 和Camera一样,可以通过Intent来启动它。  * 我们需要指定一个ACTION_VIEW的Action  * 同时一个Uri来指定我们要播放文件的路径  * 最后指定一个MIME类型,指定所要播放的文件类型  * 每种文件类型对应的都有一个MIME,他一般是类似于audio/mp3格式  * 前部分是一个较大的类型,后面是更具体的类型  *   * 同样的,对于Audio类型的多媒体,系统存储在MediaStore.Audio中  * 包括Media,Album,Genre等信息体  *   * 本文将以列表的形式列出所有的Album信息,供用户选择  * 当用户选择某个Album时,系统将打开这个ALbum下的所有Audio  * @author Administrator  *  */  public class AudioDemo extends ListActivity {            private Button btnMusic;            private boolean isAlbum = true; //true时,说明当前列表的内容是Album,false时,说明是Media             private Cursor cursor; //游标对象,             public void onCreate(Bundle savedInstanceState){          super.onCreate(savedInstanceState);          this.setContentView(R.layout.audio);          btnMusic = (Button)this.findViewById(R.id.btn_music);          btnMusic.setOnClickListener(new View.OnClickListener() {                            @Override              public void onClick(View v) {                    //              Intent intent = new Intent(Intent.ACTION_VIEW);   //              //这里我们先从SDCard文件中获取指定文件的URi   //              File sdcard = Environment.getExternalStorageDirectory(); //这个是获取SDCard路径   //              File audioFile = new File(sdcard.getPath()+"/music/tt.mp3");   //              //然后需要获取该文件的Uri   //              Uri audioUri = Uri.fromFile(audioFile);   //              //然后指定Uri和MIME   //              intent.setDataAndType(audioUri, "audio/mp3");   //              startActivity(intent);                                     //获取Album列表                   getAlbums();                  isAlbum = true;              }          });                }            public void onListItemClick(ListView l, View v, int position, long id){                    //判断当前是哪个列表           if(isAlbum){              //如果是Album,当用户点击某一个时,获取该Album下的所有media               //l.getChildAt(position);               if(cursor.moveToPosition(position)){                  getMedias(cursor.getInt(cursor.getColumnIndexOrThrow(Albums._ID)));                  isAlbum = false;              }          }else{              //如果是Media,则当用户点击某一个时,则播放该Media               //调用系统自带的MediaPlayer来播放               if(cursor.moveToPosition(position)){                  String mediaUri = cursor.getString(cursor.getColumnIndexOrThrow(Audio.Media.DATA));                  String type = cursor.getString(cursor.getColumnIndexOrThrow(Audio.Media.MIME_TYPE));                  Uri data = Uri.fromFile(new File(mediaUri));                  Intent intent = new Intent(Intent.ACTION_VIEW);                  intent.setDataAndType(data, type);                  startActivity(intent);              }          }                    //super.onListItemClick(l, v, position, id);       }                  //获取所有Albums       public void getAlbums(){          String[] columns = new String[]{                  Albums._ID,                  Albums.ALBUM          };          String[] from = new String[]{                  Albums.ALBUM          };          int[] to = new int[]{                  android.R.id.text1          };          cursor = this.managedQuery(Albums.EXTERNAL_CONTENT_URI, columns, null, null, Albums.DEFAULT_SORT_ORDER);          CursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, from, to);          this.setListAdapter(adapter);          //this.isAlbum = true;                 }            //获取某个Albums下对应的medias       public void getMedias(int albumId){          String[] columns = new String[]{                  Audio.Media._ID,                  Audio.Media.DATA,                  Audio.Media.DISPLAY_NAME,                  Audio.Media.MIME_TYPE          };          String selection = Audio.Media.ALBUM_ID + "=?";          String[] selectionArgs = new String[]{                  albumId+""          };                    String[] from = new String[]{                  Audio.Media.DISPLAY_NAME          };          int[] to = new int[]{                  android.R.id.text1          };                    cursor = this.managedQuery(Audio.Media.EXTERNAL_CONTENT_URI, columns, selection, selectionArgs, Audio.Media.TITLE);          CursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1,cursor,from,to);          this.setListAdapter(adapter);      }  }
利用Service实现背景音乐的播放

Activity类

package demo.camera;  import android.app.Activity;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent;  import android.content.ServiceConnection;  import android.os.Bundle;  import android.os.IBinder;  import android.view.View;  /**  * 演示Activity如何利用Service来完成后台Audio的播放功能  * 同时如何将Service和Activity进行绑定  * @author Administrator  *  */  public class BackgroundAudioDemo extends Activity {            private AudioService audioService;            //使用ServiceConnection来监听Service状态的变化       private ServiceConnection conn = new ServiceConnection() {                    @Override          public void onServiceDisconnected(ComponentName name) {              // TODO Auto-generated method stub               audioService = null;          }                    @Override          public void onServiceConnected(ComponentName name, IBinder binder) {              //这里我们实例化audioService,通过binder来实现               audioService = ((AudioService.AudioBinder)binder).getService();                        }      };            public void onCreate(Bundle savedInstanceState){          super.onCreate(savedInstanceState);          setContentView(R.layout.back_audio);      }                  public void onClick(View v){          int id = v.getId();          Intent intent = new Intent();          intent.setClass(this, AudioService.class);                if(id == R.id.btn_start){              //启动Service,然后绑定该Service,这样我们可以在同时销毁该Activity,看看歌曲是否还在播放               startService(intent);              bindService(intent, conn, Context.BIND_AUTO_CREATE);              finish();          }else if(id == R.id.btn_end){              //结束Service               unbindService(conn);              stopService(intent);              finish();          }else if(id == R.id.btn_fun){              audioService.haveFun();          }      }  }

Service类

 package demo.camera;  import android.app.Service;  import android.content.Intent;  import android.media.MediaPlayer;  import android.os.Binder;  import android.os.IBinder;  import android.widget.MediaController.MediaPlayerControl;  /**  * 为了可以使得在后台播放音乐,我们需要Service  * Service就是用来在后台完成一些不需要和用户交互的动作  * @author Administrator  *  */  public class AudioService extends Service implements MediaPlayer.OnCompletionListener{            MediaPlayer player;            private final IBinder binder = new AudioBinder();      @Override      public IBinder onBind(Intent arg0) {          // TODO Auto-generated method stub           return binder;      }      /**      * 当Audio播放完的时候触发该动作      */      @Override      public void onCompletion(MediaPlayer player) {          // TODO Auto-generated method stub           stopSelf();//结束了,则结束Service       }            //在这里我们需要实例化MediaPlayer对象       public void onCreate(){          super.onCreate();          //我们从raw文件夹中获取一个应用自带的mp3文件           player = MediaPlayer.create(this, R.raw.tt);          player.setOnCompletionListener(this);      }            /**      * 该方法在SDK2.0才开始有的,替代原来的onStart方法      */      public int onStartCommand(Intent intent, int flags, int startId){          if(!player.isPlaying()){              player.start();          }          return START_STICKY;      }            public void onDestroy(){          //super.onDestroy();           if(player.isPlaying()){              player.stop();          }          player.release();      }            //为了和Activity交互,我们需要定义一个Binder对象       class AudioBinder extends Binder{                    //返回Service对象           AudioService getService(){              return AudioService.this;          }      }            //后退播放进度       public void haveFun(){          if(player.isPlaying() && player.getCurrentPosition()>2500){              player.seekTo(player.getCurrentPosition()-2500);          }      }  }

在清单文件AndroidManifest.xml中配置Service

<service

            android:name=".AudioService" />

 

转载于:https://my.oschina.net/u/2409257/blog/475947

你可能感兴趣的文章
JavaScript中的delete操作符
查看>>
es7与es8其他知识
查看>>
使用 Hexo 创建项目文档网站
查看>>
typeof和instanceof的区别
查看>>
XAMPP Windows 安装中报错解决方法备忘
查看>>
sublime之利器使用篇
查看>>
每个类都应将所有能力以最小粒度提供给外部可配置,每个业务所需要的功能是这些能力的组合...
查看>>
使用cached的wrapper类读取请求响应内容
查看>>
[python][os]分离文件目录,文件名以及文件后缀
查看>>
解决Android Studio SDK无法下载问题
查看>>
雷军定AI+IoT为小米核心战略,牵手宜家推进生态布局
查看>>
书评:《All About Java 8 Lambdas》
查看>>
搜狗信息流推荐算法实践
查看>>
Visual Studio 2017 15.6发布
查看>>
2019年Java和JVM生态系统预测:OpenJDK将成为Java运行时市场领导者
查看>>
拥抱PostgreSQL,红帽再表态:SSPL的MongoDB坚决不用
查看>>
架构设计复杂度的6个来源
查看>>
360首席安全官谭晓生宣布离职
查看>>
在敏捷中应用测试驱动开发
查看>>
到底谁应该对软件开发的质量负责?
查看>>