zoukankan      html  css  js  c++  java
  • [转]Android多媒体:实现图像的编辑和合成

    本文转自:http://jiahua8859-163-com.iteye.com/blog/1147947

    1. package demo.camera;   
    2. import java.io.FileNotFoundException;   
    3. import android.app.Activity;   
    4. import android.content.Intent;   
    5. import android.graphics.Bitmap;   
    6. import android.graphics.BitmapFactory;   
    7. import android.graphics.Canvas;   
    8. import android.graphics.ColorMatrix;   
    9. import android.graphics.ColorMatrixColorFilter;   
    10. import android.graphics.Matrix;   
    11. import android.graphics.Paint;   
    12. import android.graphics.PorterDuff;   
    13. import android.graphics.PorterDuffXfermode;   
    14. import android.net.Uri;   
    15. import android.os.Bundle;   
    16. import android.provider.MediaStore;   
    17. import android.util.Log;   
    18. import android.view.Menu;   
    19. import android.view.MenuItem;   
    20. import android.view.View;   
    21. import android.widget.Button;   
    22. import android.widget.ImageView;   
    23. /**  
    24.  * 在Android中我们可以对图像进行编辑处理等操作  
    25.  * 包括放大缩小,旋转,偏移,裁剪,以及更改亮度,饱和度等  
    26.  *   
    27.  * 1、首先,从SDCard中选择图片,采用Android自带的Callery应用获得  
    28.  * Gallery是Android自带的图片和视频管理应用  
    29.  * 使用Intent来启动Gallery应用,需要指定两个参数,一个是Action,另一个是多媒体存放的URI  
    30.  * Action是一个通用的Action叫ACTION_PICK,来告诉Gallery,我们想检索数据。  
    31.  * 第二个是Data,是一个URI,这里当然是MediaStore.Images.Media.EXTERNAL_CONTENT_URI  
    32.  * 当在Gallery中选择了一个图片的时候,返回的Intent中的Data域就是所选图片对应的URI  
    33.  *   
    34.  * @author Administrator  
    35.  *  
    36.  */  
    37. public class PhotoProcess extends Activity{   
    38.     public static final int FIRST_PIC = 0;   
    39.     public static final int SECOND_PIC = 1;   
    40.     public static final int MAX_WIDTH = 240;   
    41.     public static final int MAX_HEIGHT = 180;   
    42.     private Button btnSelect,btnSelect2;   
    43.     private ImageView srcImageView, dstImageView;   
    44.        
    45.     private Bitmap srcBitmap, dstBitmap;   
    46.     private Uri imageUri;   
    47.        
    48.        
    49.     public void onCreate(Bundle savedInstanceState){   
    50.         super.onCreate(savedInstanceState);   
    51.         this.setContentView(R.layout.process);   
    52.            
    53.         this.btnSelect = (Button)this.findViewById(R.id.btn_select);   
    54.         btnSelect.setOnClickListener(clickListener);   
    55.         this.btnSelect2 = (Button)this.findViewById(R.id.btn_select2);   
    56.         btnSelect2.setOnClickListener(clickListener2);   
    57.         srcImageView = (ImageView)this.findViewById(R.id.img_src);   
    58.         dstImageView = (ImageView)this.findViewById(R.id.img_dst);   
    59.     }   
    60.        
    61.     private View.OnClickListener clickListener = new View.OnClickListener() {   
    62.            
    63.         @Override  
    64.         public void onClick(View arg0) {   
    65.             // 启动Gallery应用   
    66.             Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);   
    67.             startActivityForResult(intent, FIRST_PIC);   
    68.         }   
    69.     };   
    70.     private View.OnClickListener clickListener2 = new View.OnClickListener() {   
    71.            
    72.         @Override  
    73.         public void onClick(View arg0) {   
    74.             // 启动Gallery应用   
    75.             Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);   
    76.             startActivityForResult(intent, SECOND_PIC);   
    77.                
    78.         }   
    79.     };     
    80.        
    81.     public boolean onCreateOptionsMenu(Menu menu){   
    82.         //super.onCreateOptionsMenu(menu);   
    83.         //MenuInflater menuInflater = new MenuInflater(this);   
    84.         //menuInflater.inflate(R.layout.image, menu)   
    85.         menu.add(Menu.NONE,1,Menu.NONE,"复制");   
    86.         menu.add(Menu.NONE,2,Menu.NONE,"变换");   
    87.         menu.add(Menu.NONE,3,Menu.NONE,"亮度");   
    88.         menu.add(Menu.NONE,4,Menu.NONE,"合成");   
    89.         return super.onCreateOptionsMenu(menu);   
    90.     }   
    91.        
    92.     public boolean onOptionsItemSelected(MenuItem item){   
    93.         int id = item.getItemId();   
    94.         switch(id){   
    95.         case 1:   
    96.             //复制一个图像   
    97.             if(srcBitmap != null){   
    98.                 dstBitmap = getDstImage(null);//这里没有变换   
    99.                 dstImageView.setImageBitmap(dstBitmap);   
    100.             }   
    101.             break;   
    102.         case 2:   
    103.             //对复制后的图像进行变换   
    104.             if(srcBitmap != null){   
    105.                 dstBitmap = transferImage();   
    106.                 dstImageView.setImageBitmap(dstBitmap);   
    107.             }   
    108.             break;   
    109.         case 3:   
    110.             //改变图像的色彩   
    111.             if(srcBitmap != null){   
    112.                 dstBitmap = ajustImage();   
    113.                 dstImageView.setImageBitmap(dstBitmap);   
    114.             }   
    115.             break;   
    116.         case 4:   
    117.             if(srcBitmap != null && dstBitmap != null){   
    118.                 dstBitmap = compositeImages();   
    119.                 dstImageView.setImageBitmap(dstBitmap);   
    120.             }   
    121.             break;   
    122.         }   
    123.         return true;   
    124.     }   
    125.        
    126.     /**  
    127.      * 为了创建一个图像的副本,我们可以在创建一个新的空的Bitmap,然后在这个Bitmap上绘制一个Bitmap  
    128.      * 这个空的Bitmap应该和已存在的Bitmap具有相同的尺寸和颜色深度  
    129.      *   
    130.      * 然后我们需要一个Canvas对象,一个Canvas简单说,就是一个画布,存放Bitmap,在构造时,就可以传入Bitmap对象  
    131.      * 同时,Canvas中定义了很多便捷的画图方法,方便我们绘制各种图形  
    132.      * 接下来,如果我们需要处理颜色和对比度,我们需要一个Paint对象,通过Paint我们可以设置画笔的各种特性。  
    133.      *   
    134.      * 最后,我们调用Canvas的drawBitmap就可以将原Bitmap绘制在dstBitmap上了  
    135.      *   
    136.      */  
    137.     private Bitmap getDstImage(Matrix matrix){   
    138.            
    139.         Bitmap bmp = null;   
    140.         //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap   
    141.         //返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了   
    142.         bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());   
    143.         //创建Canvas对象,   
    144.         Canvas canvas = new Canvas(bmp);    
    145.         //创建Paint对象,这里先不用   
    146.         Paint paint = new Paint();   
    147.         //在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了   
    148.            
    149.         if(matrix != null){   
    150.             //如果matrix存在,则采用变换   
    151.             canvas.drawBitmap(dstBitmap, matrix, paint);   
    152.         }else{   
    153.             canvas.drawBitmap(srcBitmap, 00, paint);   
    154.         }   
    155.            
    156.            
    157.         return bmp;   
    158.   
    159.     }   
    160.        
    161.        
    162.     /**  
    163.      * 重载getDstImage函数,传入定制的Paint对象  
    164.      * @param matrix  
    165.      * @param paint  
    166.      * @return  
    167.      */  
    168.     private Bitmap getDstImage(Matrix matrix, Paint paint){   
    169.            
    170.         Bitmap bmp = null;   
    171.         //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap   
    172.         //返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了   
    173.         bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());   
    174.         //创建Canvas对象,   
    175.         Canvas canvas = new Canvas(bmp);    
    176.            
    177.         //在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了   
    178.            
    179.         if(matrix != null){   
    180.             //如果matrix存在,则采用变换   
    181.             canvas.drawBitmap(dstBitmap, matrix, paint);   
    182.         }else{   
    183.             canvas.drawBitmap(srcBitmap, 00, paint);   
    184.         }   
    185.            
    186.            
    187.         return bmp;   
    188.   
    189.     }      
    190.        
    191.     /**  
    192.      * 为了放大缩小、旋转图像,我们要使用Matrix类。Matrix类是一个三维矩阵。  
    193.      * 在Android屏幕中,图像的每个像素对应都是一个坐标,一个坐标由x/y/z组成  
    194.      * ------------------------  
    195.      * cosX -sinX translateX  
    196.      * sinX cosX  translateY  
    197.      * 0    0     scale  
    198.      * ------------------------  
    199.      * 第一行的值,影响着x坐标。比如 1 0 0 =>x = 1*x + 0*y + 0*z  
    200.      * 第二行的值,影响着y坐标。比如0 1 0 => y = 0*x + 1*y + 0*z  
    201.      * 第三行的值,影响着z坐标。比如 0 0 1 => z = 0*x + 0*y + 1*z  
    202.      *   
    203.      * 我们自己计算一个矩阵然后通过Matrax.setValues设置。  
    204.      * 这样,在调用canvas的drawBitmap方法时,传入matrix  
    205.      *   
    206.      * Matrix类并不提倡我们使用这种方式来操作变换,Matrix针对不同的变换都相应的有pre,set,post三种方法  
    207.      * 可以使用。  
    208.      * pre是矩阵前乘  
    209.      * set是直接设置  
    210.      * post是矩阵后乘  
    211.      */  
    212.     private Bitmap transferImage(){   
    213.         Matrix matrix = new Matrix();   
    214.         matrix.setValues(new float[]{   
    215.             .5f,0,0,//这里只会影响到x轴,所以,图片的长度将是原来的一半   
    216.             0,1,0,   
    217.             0,0,1  
    218.         });   
    219.         return this.getDstImage(matrix);   
    220.     }   
    221.        
    222.     /**  
    223.      * 该方法中我们将对图像的颜色,亮度,对比度等进行设置  
    224.      * 需要用到ColorMatrix类。ColorMatrix类是一个四行五列的矩阵  
    225.      * 每一行影响着[R,G,B,A]中的一个  
    226.      * -------------------------  
    227.      * a1 b1 c1 d1 e1  
    228.      * a2 b2 c2 d2 e2  
    229.      * a3 b3 c3 d3 e3  
    230.      * a4 b4 c4 d4 e4  
    231.      * -------------------------  
    232.      * Rnew => a1*R+b1*G+c1*B+d1*A+e1  
    233.      * Gnew => a2*R+b2*G+c2*B+d2*A+e2  
    234.      * Bnew => a3*R+b3*G+c3*B+d3*A+e3  
    235.      * Gnew => a4*R+b4*G+c4*B+d4*A+e4  
    236.      * 其中R,G,B的值是128,A的值是0  
    237.      *   
    238.      * 最后将颜色的修改,通过Paint.setColorFilter应用到Paint对象中。  
    239.      * 主要对于ColorMatrix,需要将其包装成ColorMatrixColorFilter对象,再传给Paint对象  
    240.      *   
    241.      * 同样的,ColorMatrix提供给我们相应的方法,setSaturation()就可以设置一个饱和度  
    242.      */  
    243.     private Bitmap ajustImage(){   
    244.         ColorMatrix cMatrix = new ColorMatrix();   
    245. //      int brightIndex = -25;   
    246. //      int doubleColor = 2;   
    247. //      cMatrix.set(new float[]{   
    248. //              doubleColor,0,0,0,brightIndex, //这里将1改为2则我们让Red的值为原来的两倍   
    249. //              0,doubleColor,0,0,brightIndex,//改变最后一列的值,我们可以不改变RGB同道颜色的基础上,改变亮度   
    250. //              0,0,doubleColor,0,brightIndex,   
    251. //              0,0,0,doubleColor,0   
    252. //      });   
    253.         //cMatrix.setSaturation(2.0f);//设置饱和度   
    254.         cMatrix.setScale(2.0f, 2.0f, 2.0f, 2.0f);//设置颜色同道色彩缩放   
    255.         Paint paint = new Paint();   
    256.         paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));   
    257.         return this.getDstImage(null, paint);   
    258.     }   
    259.        
    260.     /**  
    261.      * 图像的合成,可以通过在同一个Canvas中绘制两张图片。  
    262.      * 只是在绘制第二章图片的时候,需要给Paint指定一个变幻模式TransferMode。  
    263.      * 在Android中有一个XFermode所有的变幻模式都是这个类的子类  
    264.      * 我们需要用到它的一个子类PorterDuffXfermode,关于这个类,其中用到PorterDuff类  
    265.      * 这个类很简单,就包含一个Enum是Mode,其中定义了一组规则,这组规则就是如何将  
    266.      * 一张图像和另一种图像进行合成  
    267.      * 关于图像合成有四种模式,LIGHTEN,DRAKEN,MULTIPLY,SCREEN  
    268.      */  
    269.     private Bitmap compositeImages(){   
    270.            
    271.         Bitmap bmp = null;   
    272.         //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap   
    273.         bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());   
    274.         Paint paint = new Paint();   
    275.         Canvas canvas = new Canvas(bmp);   
    276.         //首先绘制第一张图片,很简单,就是和方法中getDstImage一样   
    277.         canvas.drawBitmap(srcBitmap, 00, paint);         
    278.            
    279.         //在绘制第二张图片的时候,我们需要指定一个Xfermode   
    280.         //这里采用Multiply模式,这个模式是将两张图片的对应的点的像素相乘   
    281.         //,再除以255,然后以新的像素来重新绘制显示合成后的图像   
    282.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));   
    283.         canvas.drawBitmap(dstBitmap, 00, paint);   
    284.            
    285.         return bmp;   
    286.     }   
    287.     public void onActivityResult(int requestCode, int resultCode, Intent data){   
    288.         super.onActivityResult(requestCode, resultCode, data);   
    289.            
    290.         Log.v("Result OK Value:", resultCode+"");   
    291.         Log.v("RequestCode Value", requestCode+"");   
    292.            
    293.         if(resultCode == RESULT_OK){   
    294.             imageUri = data.getData();     
    295.             if(requestCode == FIRST_PIC){   
    296.                 //在Gallery中选中一个图片时,返回来的Intent中的Data就是选择图片的Uri   
    297.                 srcBitmap = getSrcImage(imageUri);   
    298.                 srcImageView.setImageBitmap(srcBitmap);                
    299.             }else if(requestCode == SECOND_PIC){   
    300.                 //这里处理用户选择的第二张图片   
    301.                    
    302.                 dstBitmap = getSrcImage(imageUri);   
    303.                 dstImageView.setImageBitmap(dstBitmap);   
    304.             }   
    305.         }   
    306.     }   
    307.        
    308.     /**  
    309.      * 需要加载的图片可能是大图,我们需要对其进行合适的缩小处理  
    310.      * @param imageUri  
    311.      */  
    312.     private Bitmap getSrcImage(Uri imageUri){   
    313.         //Display display = this.getWindowManager().getDefaultDisplay();   
    314.         try {   
    315.             BitmapFactory.Options ops = new BitmapFactory.Options();   
    316.             ops.inJustDecodeBounds = true;   
    317.             Bitmap bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);   
    318.             int wRatio = (int)Math.ceil(ops.outWidth/(float)MAX_WIDTH);   
    319.             int hRatio = (int)Math.ceil(ops.outHeight/(float)MAX_HEIGHT);   
    320.                
    321.             if(wRatio > 1 && hRatio > 1){   
    322.                 if(wRatio > hRatio){   
    323.                     ops.inSampleSize = wRatio;   
    324.                 }else{   
    325.                     ops.inSampleSize = hRatio;   
    326.                 }   
    327.             }   
    328.                
    329.             ops.inJustDecodeBounds = false;   
    330.             bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);   
    331.                
    332.             return bmp;   
    333.                
    334.         } catch (FileNotFoundException e) {   
    335.             // TODO Auto-generated catch block   
    336.             e.printStackTrace();   
    337.             Log.e(this.getClass().getName(), e.getMessage());   
    338.         }   
    339.            
    340.         return null;   
    341.     }   
    342. }  
  • 相关阅读:
    批量修改mp3文件播放速度
    尝试了一下alsa录音播放的编程。
    最快速获取天气的方法
    乒乓Buffer
    GCC编译选项和环境变量
    Linux发行版本
    memcpy 和 memmove
    自动定位android ndk的路径
    记一下,安装和使用Ubuntu过程中遇到的问题
    Android API 和Android 版本对照
  • 原文地址:https://www.cnblogs.com/freeliver54/p/2545089.html
Copyright © 2011-2022 走看看